From d027dcb83a71fd5264086aa53a05066e9db4ff48 Mon Sep 17 00:00:00 2001 From: Grace Jia Date: Wed, 5 Feb 2020 18:05:30 -0800 Subject: [PATCH 01/21] Fix unexpected crashed phone app notification when use system dialer as default dialer. Test: Manually test with system dialer Bug: 148758211 Change-Id: I80985c666f8f7f824b1057a8fdbf27774bfe4974 (cherry picked from commit d5b8466e0bedc5506a28d3d06703ba1e3c4c5c86) --- src/com/android/server/telecom/InCallController.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java index f3a030eb4..6a9771a11 100644 --- a/src/com/android/server/telecom/InCallController.java +++ b/src/com/android/server/telecom/InCallController.java @@ -1312,10 +1312,13 @@ private void connectToNonUiInCallServices(Call call) { private InCallServiceInfo getDefaultDialerComponent() { String packageName = mDefaultDialerCache.getDefaultDialerApplication( mCallsManager.getCurrentUserHandle().getIdentifier()); + String systemPackageName = mDefaultDialerCache.getSystemDialerApplication(); Log.d(this, "Default Dialer package: " + packageName); - InCallServiceInfo defaultDialerComponent = getInCallServiceComponent(packageName, - IN_CALL_SERVICE_TYPE_DIALER_UI); + InCallServiceInfo defaultDialerComponent = + (systemPackageName != null && systemPackageName.equals(packageName)) + ? getInCallServiceComponent(packageName, IN_CALL_SERVICE_TYPE_SYSTEM_UI) + : getInCallServiceComponent(packageName, IN_CALL_SERVICE_TYPE_DIALER_UI); if (packageName != null && defaultDialerComponent == null) { // The in call service of default phone app is disabled, send notification. sendCrashedInCallServiceNotification(packageName); From 60728b4216ae2319148a0b4bd71a667a69e8b8e7 Mon Sep 17 00:00:00 2001 From: Daniel Chapin Date: Thu, 16 Apr 2020 17:21:28 +0000 Subject: [PATCH 02/21] Revert "Change Ringer#startRinging to work asynchronously." This reverts commit 529ec5d5af26ca340d9ffacb0bb8cbf0c4fb7349. Reason for revert: QA blocking issue for daily rvc-release build. Bug: 154183314 Bug: 154184130 Change-Id: Ia6ab73230cb7d3ed87a398ddfc94559900ae352d (cherry picked from commit 606027332f5f6d5e66e50a65b2020ad251f5584c) --- src/com/android/server/telecom/Ringer.java | 172 ++++++------------ .../server/telecom/RingerAttributes.java | 118 ------------ 2 files changed, 57 insertions(+), 233 deletions(-) delete mode 100644 src/com/android/server/telecom/RingerAttributes.java diff --git a/src/com/android/server/telecom/Ringer.java b/src/com/android/server/telecom/Ringer.java index 9954d8704..d02d940a3 100644 --- a/src/com/android/server/telecom/Ringer.java +++ b/src/com/android/server/telecom/Ringer.java @@ -20,27 +20,26 @@ import android.app.NotificationManager; import android.app.Person; import android.content.Context; +import android.os.VibrationEffect; +import android.telecom.Log; +import android.telecom.TelecomManager; import android.media.AudioAttributes; import android.media.AudioManager; import android.media.Ringtone; import android.media.VolumeShaper; import android.net.Uri; import android.os.Bundle; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.VibrationEffect; import android.os.Vibrator; -import android.telecom.Log; -import android.telecom.TelecomManager; import com.android.internal.annotations.VisibleForTesting; import com.android.server.telecom.LogUtils.EventTimer; import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; +import java.util.stream.Collectors; /** * Controls the ringtone player. @@ -115,8 +114,6 @@ public VibrationEffect get(Uri ringtoneUri, Context context) { private static final int REPEAT_SIMPLE_VIBRATION_AT = 1; - private static final long RINGER_ATTRIBUTES_TIMEOUT = 5000; // 5 seconds - private static final float EPSILON = 1e-6f; private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder() @@ -150,7 +147,6 @@ public VibrationEffect get(Uri ringtoneUri, Context context) { private InCallTonePlayer mCallWaitingPlayer; private RingtoneFactory mRingtoneFactory; - private AudioManager mAudioManager; /** * Call objects that are ringing, vibrating or call-waiting. These are used only for logging @@ -165,8 +161,6 @@ public VibrationEffect get(Uri ringtoneUri, Context context) { */ private boolean mIsVibrating = false; - private Handler mHandler = null; - /** Initializes the Ringer. */ @VisibleForTesting public Ringer( @@ -189,7 +183,6 @@ public Ringer( mRingtoneFactory = ringtoneFactory; mInCallController = inCallController; mVibrationEffectProxy = vibrationEffectProxy; - mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); if (mContext.getResources().getBoolean(R.bool.use_simple_vibration_pattern)) { mDefaultVibrationEffect = mVibrationEffectProxy.createWaveform(SIMPLE_VIBRATION_PATTERN, @@ -223,39 +216,58 @@ public boolean startRinging(Call foregroundCall, boolean isHfpDeviceAttached) { return false; } - // Use completable future to establish a timeout, not intent to make these work outside the - // main thread asynchronously - // TODO: moving these RingerAttributes calculation out of Telecom lock to avoid blocking. - CompletableFuture ringerAttributesFuture = CompletableFuture - .supplyAsync(() -> getRingerAttributes(foregroundCall, isHfpDeviceAttached), - new LoggedHandlerExecutor(getHandler(), "R.sR", null)); - - RingerAttributes attributes = null; - try { - attributes = ringerAttributesFuture.get( - RINGER_ATTRIBUTES_TIMEOUT, TimeUnit.MILLISECONDS); - } catch (ExecutionException | InterruptedException | TimeoutException e) { - // Keep attributs as null - Log.i(this, "getAttributes error: " + e); - } + AudioManager audioManager = + (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + LogUtils.EventTimer timer = new EventTimer(); + boolean isVolumeOverZero = audioManager.getStreamVolume(AudioManager.STREAM_RING) > 0; + timer.record("isVolumeOverZero"); + boolean shouldRingForContact = shouldRingForContact(foregroundCall.getContactUri()); + timer.record("shouldRingForContact"); + boolean isRingtonePresent = !(mRingtoneFactory.getRingtone(foregroundCall) == null); + timer.record("getRingtone"); + boolean isSelfManaged = foregroundCall.isSelfManaged(); + timer.record("isSelfManaged"); + boolean isSilentRingingRequested = foregroundCall.isSilentRingingRequested(); + timer.record("isSilentRingRequested"); - if (attributes == null) { - Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "RingerAttributes error"); - return false; - } + boolean isRingerAudible = isVolumeOverZero && shouldRingForContact && isRingtonePresent; + timer.record("isRingerAudible"); + boolean hasExternalRinger = hasExternalRinger(foregroundCall); + timer.record("hasExternalRinger"); + // Don't do call waiting operations or vibration unless these are false. + boolean isTheaterModeOn = mSystemSettingsUtil.isTheaterModeOn(mContext); + timer.record("isTheaterModeOn"); + boolean letDialerHandleRinging = mInCallController.doesConnectedDialerSupportRinging(); + timer.record("letDialerHandleRinging"); + + Log.i(this, "startRinging timings: " + timer); + boolean endEarly = isTheaterModeOn || letDialerHandleRinging || isSelfManaged || + hasExternalRinger || isSilentRingingRequested; + + // Acquire audio focus under any of the following conditions: + // 1. Should ring for contact and there's an HFP device attached + // 2. Volume is over zero, we should ring for the contact, and there's a audible ringtone + // present. + // 3. The call is self-managed. + boolean shouldAcquireAudioFocus = + isRingerAudible || (isHfpDeviceAttached && shouldRingForContact) || isSelfManaged; - if (attributes.isEndEarly()) { - if (attributes.letDialerHandleRinging()) { + if (endEarly) { + if (letDialerHandleRinging) { Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "Dialer handles"); } - if (attributes.isSilentRingingRequested()) { + if (isSilentRingingRequested) { Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "Silent ringing " + "requested"); } + Log.i(this, "Ending early -- isTheaterModeOn=%s, letDialerHandleRinging=%s, " + + "isSelfManaged=%s, hasExternalRinger=%s, silentRingingRequested=%s", + isTheaterModeOn, letDialerHandleRinging, isSelfManaged, hasExternalRinger, + isSilentRingingRequested); if (mBlockOnRingingFuture != null) { mBlockOnRingingFuture.complete(null); } - return attributes.shouldAcquireAudioFocus(); + return shouldAcquireAudioFocus; } stopCallWaiting(); @@ -264,7 +276,7 @@ public boolean startRinging(Call foregroundCall, boolean isHfpDeviceAttached) { CompletableFuture hapticsFuture = null; // Determine if the settings and DND mode indicate that the vibrator can be used right now. boolean isVibratorEnabled = isVibratorEnabled(mContext, foregroundCall); - if (attributes.isRingerAudible()) { + if (isRingerAudible) { mRingingCall = foregroundCall; Log.addEvent(foregroundCall, LogUtils.Events.START_RINGER); // Because we wait until a contact info query to complete before processing a @@ -297,14 +309,15 @@ public boolean startRinging(Call foregroundCall, boolean isHfpDeviceAttached) { effect = getVibrationEffectForCall(mRingtoneFactory, foregroundCall); } } else { - Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "Inaudible: " - + attributes.getInaudibleReason()); + String reason = String.format( + "isVolumeOverZero=%s, shouldRingForContact=%s, isRingtonePresent=%s", + isVolumeOverZero, shouldRingForContact, isRingtonePresent); + Log.i(this, "startRinging: skipping because ringer would not be audible. " + reason); + Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "Inaudible: " + reason); effect = mDefaultVibrationEffect; } if (hapticsFuture != null) { - final boolean shouldRingForContact = attributes.shouldRingForContact(); - final boolean isRingerAudible = attributes.isRingerAudible(); mVibrateFuture = hapticsFuture.thenAccept(isUsingAudioCoupledHaptics -> { if (!isUsingAudioCoupledHaptics || !mIsHapticPlaybackSupportedByDevice) { Log.i(this, "startRinging: fileHasHaptics=%b, hapticsSupported=%b", @@ -329,11 +342,11 @@ public boolean startRinging(Call foregroundCall, boolean isHfpDeviceAttached) { mBlockOnRingingFuture.complete(null); } Log.w(this, "startRinging: No haptics future; fallback to default behavior"); - maybeStartVibration(foregroundCall, attributes.shouldRingForContact(), effect, - isVibratorEnabled, attributes.isRingerAudible()); + maybeStartVibration(foregroundCall, shouldRingForContact, effect, isVibratorEnabled, + isRingerAudible); } - return attributes.shouldAcquireAudioFocus(); + return shouldAcquireAudioFocus; } private void maybeStartVibration(Call foregroundCall, boolean shouldRingForContact, @@ -500,75 +513,4 @@ private boolean getVibrateWhenRinging(Context context) { return mSystemSettingsUtil.canVibrateWhenRinging(context) || mSystemSettingsUtil.applyRampingRinger(context); } - - private RingerAttributes getRingerAttributes(Call call, boolean isHfpDeviceAttached) { - RingerAttributes.Builder builder = new RingerAttributes.Builder(); - - LogUtils.EventTimer timer = new EventTimer(); - - boolean isVolumeOverZero = mAudioManager.getStreamVolume(AudioManager.STREAM_RING) > 0; - timer.record("isVolumeOverZero"); - boolean shouldRingForContact = shouldRingForContact(call.getContactUri()); - timer.record("shouldRingForContact"); - boolean isRingtonePresent = !(mRingtoneFactory.getRingtone(call) == null); - timer.record("getRingtone"); - boolean isSelfManaged = call.isSelfManaged(); - timer.record("isSelfManaged"); - boolean isSilentRingingRequested = call.isSilentRingingRequested(); - timer.record("isSilentRingRequested"); - - boolean isRingerAudible = isVolumeOverZero && shouldRingForContact && isRingtonePresent; - timer.record("isRingerAudible"); - String inaudibleReason = ""; - if (!isRingerAudible) { - inaudibleReason = String.format( - "isVolumeOverZero=%s, shouldRingForContact=%s, isRingtonePresent=%s", - isVolumeOverZero, shouldRingForContact, isRingtonePresent); - } - - boolean hasExternalRinger = hasExternalRinger(call); - timer.record("hasExternalRinger"); - // Don't do call waiting operations or vibration unless these are false. - boolean isTheaterModeOn = mSystemSettingsUtil.isTheaterModeOn(mContext); - timer.record("isTheaterModeOn"); - boolean letDialerHandleRinging = mInCallController.doesConnectedDialerSupportRinging(); - timer.record("letDialerHandleRinging"); - - Log.i(this, "startRinging timings: " + timer); - boolean endEarly = isTheaterModeOn || letDialerHandleRinging || isSelfManaged || - hasExternalRinger || isSilentRingingRequested; - - if (endEarly) { - Log.i(this, "Ending early -- isTheaterModeOn=%s, letDialerHandleRinging=%s, " + - "isSelfManaged=%s, hasExternalRinger=%s, silentRingingRequested=%s", - isTheaterModeOn, letDialerHandleRinging, isSelfManaged, hasExternalRinger, - isSilentRingingRequested); - } - - // Acquire audio focus under any of the following conditions: - // 1. Should ring for contact and there's an HFP device attached - // 2. Volume is over zero, we should ring for the contact, and there's a audible ringtone - // present. - // 3. The call is self-managed. - boolean shouldAcquireAudioFocus = - isRingerAudible || (isHfpDeviceAttached && shouldRingForContact) || isSelfManaged; - - return builder.setEndEarly(endEarly) - .setLetDialerHandleRinging(letDialerHandleRinging) - .setAcquireAudioFocus(shouldAcquireAudioFocus) - .setRingerAudible(isRingerAudible) - .setInaudibleReason(inaudibleReason) - .setShouldRingForContact(shouldRingForContact) - .setSilentRingingRequested(isSilentRingingRequested) - .build(); - } - - private Handler getHandler() { - if (mHandler == null) { - HandlerThread handlerThread = new HandlerThread("Ringer"); - handlerThread.start(); - mHandler = handlerThread.getThreadHandler(); - } - return mHandler; - } } diff --git a/src/com/android/server/telecom/RingerAttributes.java b/src/com/android/server/telecom/RingerAttributes.java deleted file mode 100644 index 840d815d1..000000000 --- a/src/com/android/server/telecom/RingerAttributes.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.telecom; - -public class RingerAttributes { - public static class Builder { - private boolean mEndEarly; - private boolean mLetDialerHandleRinging; - private boolean mAcquireAudioFocus; - private boolean mRingerAudible; - private String mInaudibleReason; - private boolean mShouldRingForContact; - private boolean mSilentRingingRequested; - - public RingerAttributes.Builder setEndEarly(boolean endEarly) { - mEndEarly = endEarly; - return this; - } - - public RingerAttributes.Builder setLetDialerHandleRinging(boolean letDialerHandleRinging) { - mLetDialerHandleRinging = letDialerHandleRinging; - return this; - } - - public RingerAttributes.Builder setAcquireAudioFocus(boolean acquireAudioFocus) { - mAcquireAudioFocus = acquireAudioFocus; - return this; - } - - public RingerAttributes.Builder setRingerAudible(boolean ringerAudible) { - mRingerAudible = ringerAudible; - return this; - } - - public RingerAttributes.Builder setInaudibleReason(String inaudibleReason) { - mInaudibleReason = inaudibleReason; - return this; - } - - public RingerAttributes.Builder setShouldRingForContact(boolean shouldRingForContact) { - mShouldRingForContact = shouldRingForContact; - return this; - } - - public RingerAttributes.Builder setSilentRingingRequested(boolean silentRingingRequested) { - mSilentRingingRequested = silentRingingRequested; - return this; - } - - public RingerAttributes build() { - return new RingerAttributes(mEndEarly, mLetDialerHandleRinging, mAcquireAudioFocus, - mRingerAudible, mInaudibleReason, mShouldRingForContact, - mSilentRingingRequested); - } - } - - private boolean mEndEarly; - private boolean mLetDialerHandleRinging; - private boolean mAcquireAudioFocus; - private boolean mRingerAudible; - private String mInaudibleReason; - private boolean mShouldRingForContact; - private boolean mSilentRingingRequested; - - private RingerAttributes(boolean endEarly, boolean letDialerHandleRinging, - boolean acquireAudioFocus, boolean ringerAudible, String inaudibleReason, - boolean shouldRingForContact, boolean silentRingingRequested) { - mEndEarly = endEarly; - mLetDialerHandleRinging = letDialerHandleRinging; - mAcquireAudioFocus = acquireAudioFocus; - mRingerAudible = ringerAudible; - mInaudibleReason = inaudibleReason; - mShouldRingForContact = shouldRingForContact; - mSilentRingingRequested = silentRingingRequested; - } - - public boolean isEndEarly() { - return mEndEarly; - } - - public boolean letDialerHandleRinging() { - return mLetDialerHandleRinging; - } - - public boolean shouldAcquireAudioFocus() { - return mAcquireAudioFocus; - } - - public boolean isRingerAudible() { - return mRingerAudible; - } - - public String getInaudibleReason() { - return mInaudibleReason; - } - - public boolean shouldRingForContact() { - return mShouldRingForContact; - } - - public boolean isSilentRingingRequested() { - return mSilentRingingRequested; - } -} From 9e4480d4062781c7ea46f8ebaef6ae834be7cc44 Mon Sep 17 00:00:00 2001 From: Grace Jia Date: Thu, 18 Jun 2020 14:12:56 -0700 Subject: [PATCH 03/21] Fix security vulnerability of TelecomManager#getPhoneAccountsForPackage Check calling package and READ_PRIVILEGED_PHONE_STATE to avoid potential PII expotion. Bug: 153995334 Test: atest TelecomUnitTests:TelecomServiceImpl Change-Id: Ie834633dc4031d19af90e922ef0f111c3c8d7cb2 (cherry picked from commit 9d8d0cf3dcf741afe7ed50e60da513a47b0e8d59) (cherry picked from commit f3f2d7c2dcb558081f02e282078c0c42c5c3e1b1) --- .../server/telecom/TelecomServiceImpl.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java index 62e0f3fe1..9ccae9a37 100644 --- a/src/com/android/server/telecom/TelecomServiceImpl.java +++ b/src/com/android/server/telecom/TelecomServiceImpl.java @@ -279,6 +279,23 @@ public List getPhoneAccountsSupportingScheme(String uriSchem @Override public List getPhoneAccountsForPackage(String packageName) { + //TODO: Deprecate this in S + try { + enforceCallingPackage(packageName); + } catch (SecurityException se1) { + EventLog.writeEvent(0x534e4554, "153995334", Binder.getCallingUid(), + "getPhoneAccountsForPackage: invalid calling package"); + throw se1; + } + + try { + enforcePermission(READ_PRIVILEGED_PHONE_STATE); + } catch (SecurityException se2) { + EventLog.writeEvent(0x534e4554, "153995334", Binder.getCallingUid(), + "getPhoneAccountsForPackage: no permission"); + throw se2; + } + synchronized (mLock) { final UserHandle callingUserHandle = Binder.getCallingUserHandle(); long token = Binder.clearCallingIdentity(); From d8959b6a7174b3e828cd0761c74fabaef642e558 Mon Sep 17 00:00:00 2001 From: Michael Bestas Date: Sun, 28 Feb 2021 02:43:24 +0200 Subject: [PATCH 04/21] Automatic translation import Change-Id: I4261bacad05699626b962764eeca1c295cb03655 --- res/values-ast-rES/strings.xml | 88 ++++++++++++++++++++++++ res/values-cy/strings.xml | 118 +++++++++++++++++++++++++++++++++ res/values-eo/strings.xml | 30 +++++++++ res/values-gd/strings.xml | 93 ++++++++++++++++++++++++++ res/values-ku/strings.xml | 41 ++++++++++++ res/values-lb/strings.xml | 43 ++++++++++++ res/values-ug/strings.xml | 27 ++++++++ 7 files changed, 440 insertions(+) create mode 100644 res/values-ast-rES/strings.xml create mode 100644 res/values-cy/strings.xml create mode 100644 res/values-eo/strings.xml create mode 100644 res/values-gd/strings.xml create mode 100644 res/values-ku/strings.xml create mode 100644 res/values-lb/strings.xml create mode 100644 res/values-ug/strings.xml diff --git a/res/values-ast-rES/strings.xml b/res/values-ast-rES/strings.xml new file mode 100644 index 000000000..c84820dd0 --- /dev/null +++ b/res/values-ast-rES/strings.xml @@ -0,0 +1,88 @@ + + + + Xestión de llamaes + Teléfonu + Desconocíu + Llamada perdida + Perdióse la llamada\'l trabayu + Llamaes perdíes + %s llamaes perdíes + Llamada perdida de %s + Llamar + Mensaxe + Llamada silenciada. + Altavoz habilitáu. + Nun puedo falar. ¿Ye importante? + Llámote namái pueda. + Llámote dempués. + Nun puedo falar. Llámesme llueu? + Rempuestes rápides + Editar rempuestes rápides + Rempuesta rápida + Mensaxe unviáu a %s. + Cuentes de llamaes + Namái s\'almiten llames d\'emerxencia. + Esta aplicación nun pue facer llamaes salientes ensin el permisu de Teléfonu. + Pa facer una llamada, teclexa un númberu válidu. + La llamada nun pue amestase nesti momentu. + Falta\'l númberu del buzón de voz + Nun s\'almacenó nengún númberu de buzón de voz na tarxeta SIM. + Amestar númberu + ¿Predeterminar la to aplicación de teléfonu %s? + Predeterminar + Encaboxar + %s sedrá a allugar y controlar tolos aspeutos de les llamaes. Namái deberíen predeterminase como aplicación de teléfonu les aplicaciones nes que t\'enfotes. + Predeterminar + Encaboxar + Númberos bloquiaos + Nun recibirás llames o mensaxes de númberos bloquiaos. + Amestar un númberu + ¿Desbloquiar %1$s? + Desbloquiar + Bloquiar llamaes y mensaxes de + Númberu telefónicu + Bloquiar + Namái\'l dueñu\'l teléfonu pue ver y xestionar númberos bloquiaos. + Desbloquiar + Bloquéu desactiváu temporalmente + Dempués que marques o unvies un mensaxe a un númberu d\'emerxencies, desactivaráse\'l bloquéu p\'asegurar qu\'esos servicios puean contautate. + Reactivar agora + %1$s bloquiáu + %1$s desbloquiáu + Nun pue bloquiase\'l númberu d\'emerxencies. + %1$s yá ta bloquiáu. + Q Mobile + Market Wireless + Sonoma Circles Talk Plus + Bay Voice Chat Pro + Account with Q Mobile + Account with Market Wireless + Talk to everyone in your Circles! + Chat with Chat Network users + RESTRICTED + Usando\'l marcador personal pa llamar + Llamaes perdíes + Bloquéu de Llamaes + Bloquéu de Llamaes + Los númberos nun tán en Contautos + Priváu + Teléfonu públicu + Torgar llamaes de teléfonos de pagu + Desconocíu + Torgar llamaes de contautos ensin identificar + Bloquéu de Llamaes + diff --git a/res/values-cy/strings.xml b/res/values-cy/strings.xml new file mode 100644 index 000000000..f90c868a3 --- /dev/null +++ b/res/values-cy/strings.xml @@ -0,0 +1,118 @@ + + + + Rheolaeth Galwadau + Ffôn + Anhysybys + Galwad wedi ei methu + Galwad gwaith wedi\'i methu + Galwadau wedi eu methu + %s galwad wedi eu methu + Wedi methu galwad gan %s + Galw nôl + Neges + Galwad wedi\'i distewi. + Seinydd uchel wedi\'i alluogi. + Methu siarad nawr. Be sy\'? + Mi alwa\'i nôl yn fuan. + Mi alwa\'i nôl yn hwyrach. + Methu siarad nawr. Galw fi\'n hwyrach? + Atebion cyflym + Golygu atebion cyflym + Ateb cyflym + Anfonwyd neges at %s. + Methwyd ag anfon y neges at %s. + Cyfrifon galw + Dim ond galwadau brys sydd yn bosib. + Ni all yr ap hwn wneud galwadau allan heb ganiatâd y Ffôn. + I wneud galwad, rho rif dilys. + Methu ag ychwanegu\'r alwad ar hyn o bryd. + Rhif lleisbost ar goll + Does dim rhif ar gyfer lleisbost wedi ei gadw ar y cerdyn SIM. + Ychwanegu rhif + Gosod %s fel dy ap Ffôn arferol? + Gosod fel Rhagosodiad + Diddymu + Bydd %s yn medru gwneud a rheoli pob agwedd o alwadau. Dylid ond osod ap wyt ti\'n ymddiried ynddo fel dy ap Ffôn diofyn. + Gosod %s fel dy ap arferol i sgrinio galwadau? + Ni fydd %s bellach yn medru sgrinio galwadau. + Bydd %s yn medru gweld gwybodaeth am alwadau na sydd yn dy gysylltiadau ac yn medru rhwystro\u2019r galwadau hyn. Dylid ond defnyddio ap rwyt yn ymddiried ynddynt fel dy ap sgrinio galwadau. + Gosod fel Rhagosodiad + Diddymu + Rhifau wedi eu rhwystro + Ni fyddi\'n derbyn galwadau na negesuon testun oddi wrth rifau wedi\'u rhwystro. + Ychwanegu rhif + Dadrwystro %1$s? + Dadrwystro + Rhwystro galwadau a negesuon testun oddi wrth + Rhif ffôn + Rhwystro + Dim ond perchennog y ddyfais gall gweld a rheoli rhifau wedi eu rhwystro. + Dadrwystro + Rhwystro wedi ei diffodd dros dro + Ar ôl deialu neu anfon neges at rif argyfwng, mae rhwystro yn cael ei diffodd i sicrhau bod modd i\'r gwasanaethau brys cysylltu â thi. + Ail-alluogi nawr + %1$s wedi\'i rwystro + %1$s wedi\'i dadrwystro + Amhosib rhwystro rhif argyfwng. + Mae %1$s eisoes wedi ei rwystro. + Q Mobile + Market Wireless + Sonoma Circles Talk Plus + Bay Voice Chat Pro + Account with Q Mobile + Account with Market Wireless + Talk to everyone in your Circles! + Chat with Chat Network users + CYFYNGEDIG + Defnyddio\'r deialydd personol i wneud yr alwad + Galwad %1$s oddi wrth %2$s + Galwad fideo %1$s oddi wrth %2$s + Bydd ateb yn dod a dy alwad %1$s i ben. + Bydd ateb yn dod a dy alwadau %1$s i ben. + Bydd ateb yn dod a dy alwad fideo %1$s i ben. + Bydd ateb yn dod a dy alwad presennol i ben. + Bydd ateb yn dod a dy alwadau presennol i ben. + Bydd ateb yn dod a dy alwad fideo presennol i ben. + Ateb + Gwrthod + Ni ellir gwneud y galwad am nad oes unrhyw gyfrifon galw sy\u2019n cefnogi\u2019r math hwn o alwad. + Ni ellir wneud yr alwad oherwydd dy alwad %1$s. + Ni ellir wneud yr alwad oherwydd dy alwadau %1$s. + Ni ellir gwneud galwad tra bod galwad ar y gweill mewn ap arall. + Galwadau i mewn + Galwadau wedi eu methu + Rhwystro Galwadau + Bydd gwneud yr alwad hon yn dod a dy alwad %1$s i ben. + Dewisa sut i wneud yr alwad hon + Ailgyfierio\u2019r alwad gan ddefnyddio %1$s + Galw gan ddefnyddio fy rhif ffôn + Ni ellir gwneud y galwad gyda %1$s. Rho gynnig ar ap arall sy\u2019n ailgyfeirio galwadau neu cysyllta â\'r datblygwr am gymorth. + Rhwystro Galwadau + Rhifau dim yng Nghysylltiadau + Rhwystro rhifau na sydd yn dy Gysylltiadau + Preifat + Rhwystro galwyr na sy\'n datgelu eu rhif + Ffôn cyhoeddus + Rhwystro galwadau o ffonau cyhoeddus + Anhysybys + Rhwystro galwadau gan bobol anhysbys + Rhwystro Galwadau + Analluogwyd Rhwystro Galwadau + Wedi gwneud galwad brys + Mae Rhwystro Galwadau wedi ei analluogi i ganiatáu’r gwasanaethau brys i gysylltu â thi. + Dewislen Datblygwr Telathrebu + diff --git a/res/values-eo/strings.xml b/res/values-eo/strings.xml new file mode 100644 index 000000000..bd11e3733 --- /dev/null +++ b/res/values-eo/strings.xml @@ -0,0 +1,30 @@ + + + + Telefono + Nekonata + Mesaĝo + Q Mobile + Market Wireless + Sonoma Circles Talk Plus + Bay Voice Chat Pro + Account with Q Mobile + Account with Market Wireless + Talk to everyone in your Circles! + Chat with Chat Network users + RESTRICTED + Nekonata + diff --git a/res/values-gd/strings.xml b/res/values-gd/strings.xml new file mode 100644 index 000000000..d2b54da45 --- /dev/null +++ b/res/values-gd/strings.xml @@ -0,0 +1,93 @@ + + + + Stiùireadh nan gairmean + Fòn + Neo-aithnichte + Gairm a dh’fhalbh ort + Gairm na h-obrach a dh’fhalbh ort + Gairmean a dh’fhalbh ort + Dh’fhalbh gairmean ort (%s) + Dh’fhalbh gairm o %s ort + Fònaig air ais + Cuir teachdaireachd + Chaidh a’ ghairm a mhùchadh. + Tha glaodhaire an fhòn an comas. + Chan urrainn dhomh bruidhinn riut an-dràsta. Dè tha dol? + Cuiridh mi fòn thugad an ceartair. + Cuiridh mi fòn thugad an ceann tamaill. + Chan urrainn dhomh bruidhinn riut an-dràsta. An cuir thu fòn thugam an ceann tamaill? + Grad-fhreagairtean + Deasaich na grad-fhreagairtean + Grad-fhreagairt + Chaidh an teachdaireachd a chur gu %s. + Cunntasan ghairmean + Chan eil ach gairmean èiginn ceadaichte. + Chan urrainn dhan aplacaid seo gairm a-mach a chur gun chead air an fhòn. + Airson gairm a chur, cuir a-steach àireamh dhligheach. + Cha ghabh a’ ghairm a chur ris aig an àm seo. + Tha àireamh a’ phuist-ghutha a dhìth + Chan eil àireamh puist-ghutha air a’ chairt SIM. + Cuir àireamh ris + An dèan thu aplacaid thùsail an fhònaidh dhe %s? + Suidhich mar a’ bhun-roghainn + Sguir dheth + ’S urrainn dha %s gairmean a chur is gach nì mun dèidhinn a stiùireadh. Cha bu chòir dhut aplacaid a shuidheachadh mar tè thùsail an fhònaidh ach ma bhios earbsa agad innte. + Suidhich mar a’ bhun-roghainn + Sguir dheth + Àireamhan bacte + Chan fhaigh thu gairm no teachdaireachd on a h-àireamhan bacte. + Cuir àireamh ris + An dì-bhac thu %1$s? + Dì-bhac + Bac gairmean is teacsaichean o + Àireamh fòn + Bac + Cha sheall no stiùir ach seilbheadair an uidheim na h-àireamhan bacte. + Dì-bhac + Tha am bacadh dheth rè seal + Nuair a chuireas tu gairm no teacsa gu àireamh-èiginn, thèid am bacadh a chur dheth a dhèanamh cinnteach gun ruig na seirbheisean-èiginn thu. + Cuir an comas a-rithist an-dràsta + Chaidh %1$s a bhacadh + Chaidh %1$s a dhì-bhacadh + Cha ghabh àireamh-èiginn a bhacadh. + Chaidh %1$s a bhacadh cheana. + Q Mobile + Market Wireless + Sonoma Circles Talk Plus + Bay Voice Chat Pro + Account with Q Mobile + Account with Market Wireless + Talk to everyone in your Circles! + Chat with Chat Network users + RESTRICTED + A’ cleachdadh an daithealair pearsanta airson na gairm + Gairmean a dh’fhalbh ort + Bacadh ghairmean + Bacadh ghairmean + Àireamhan nach eil ’nan luchd-aithne + Bac àireamhan nach deach a chlàradh san luchd-aithne agad + Prìobhaideach + Bac luchd-gairm nach nochd an àireamh + Bothan-fòn + Bac gairmean o bhothain-fhòn + Neo-aithnichte + Bac gairmean o luchd-ghairm gun aithneachadh + Bacadh ghairmean + Chaidh bacadh ghairmean a chur à comas + Chaidh gairm-èiginn a dhèanamh + Chaidh bacadh ghairmean a chur à comas ach am faigh an luchd-cobharach grèim ort. + diff --git a/res/values-ku/strings.xml b/res/values-ku/strings.xml new file mode 100644 index 000000000..5c83edcaa --- /dev/null +++ b/res/values-ku/strings.xml @@ -0,0 +1,41 @@ + + + + مۆبایل + نەزانراو + پەیوەندیی لەدەستچوو + پەیوەندییە لەدەستچووەکان + %s پەیوەندیی لەدەستچوو + پەیوەندیی لەدەستچوو لەلایەن %s + پەیوەندی کردنەوە + نامه‌ + په‌یوه‌ندی کپ کراوه‌. + بەرزەبێژ تواناپێدراوە. + ئێستا ناتوانم قسە بکه‌م.چی بووه‌؟ + هەر ئێستا پەیوەندیت بۆ ئەکەمەوە. + دواتر پەیوەندیت بۆ ئەکەمەوە. + ئێستا ناتوانم قسە بکه‌م. دواتر پەیوەندیم پێوە بکه‌؟ + وەڵامە خێراکان + ده‌ستکاریکردنی وه‌ڵامه‌ خێراکان + وه‌ڵامە خێراکان + نامه‌ نێردرا بۆ %s. + ژمارەی دەنگەپۆست نییە + هیچ ژمارەیەکی دەنگەپۆستی لەسەر سیمکارت کۆگا نەکراوە. + زیاکردنی ژمارە + سنووردارە + پەیوەندییە لەدەستچووەکان + نەزانراو + diff --git a/res/values-lb/strings.xml b/res/values-lb/strings.xml new file mode 100644 index 000000000..b33c3787d --- /dev/null +++ b/res/values-lb/strings.xml @@ -0,0 +1,43 @@ + + + + Telefon + Onbekannt + Verpassten Uruff + Verpasst Uriff + %s verpasst Uriff + Verpassten Uruff vum %s + Zréckruffen + Message schécken + Uruff roueg geschalt. + Lautsprecher aktivéiert. + Kann elo net schwätzen. Ëm wat geet et? + Ech ruffe geschwënn zréck. + Ech ruffe méi spéit zréck. + Kann elo net schwätzen. Telefonéiere mer méi spéit? + Séier Äntwerten + Séier Äntwerten änneren + Séier Äntwert + Message geschéckt un %s. + Uruff gouf net gesat, gëff eng gëlteg Nummer an. + Den Uruff ka momentan net dobäigesat ginn. + Mailbox-Nummer feelt + Op der SIM-Kaart ass keng Mailbox-Nummer gespäichert. + Nummer dobäisetzen + AGESCHRÄNKT + Verpasst Uriff + Onbekannt + diff --git a/res/values-ug/strings.xml b/res/values-ug/strings.xml new file mode 100644 index 000000000..ed66e86a6 --- /dev/null +++ b/res/values-ug/strings.xml @@ -0,0 +1,27 @@ + + + + تېلېفون + يوچۇن + سۆزلەشمىگەن چاقىرىش + سۆزلەشمىگەن چاقىرىشلار + سۆزلەشمىگەن چاقىرىش %s + %s دىن كەلگەن جاۋابسىز چاقىرىش + قايتۇرۇپ ئۇرۇڭ + ئۇچۇر + سۆزلەشمىگەن چاقىرىشلار + يوچۇن + From 617d40d54e4e2df066707d179dadffebd31b731a Mon Sep 17 00:00:00 2001 From: Michael Bestas Date: Sat, 21 Aug 2021 04:08:47 +0300 Subject: [PATCH 05/21] Automatic translation import Change-Id: I13901c934f6c593132061755bf77a0203d0abb5c --- res/values-gd/strings.xml | 45 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/res/values-gd/strings.xml b/res/values-gd/strings.xml index d2b54da45..db844a1bf 100644 --- a/res/values-gd/strings.xml +++ b/res/values-gd/strings.xml @@ -24,6 +24,18 @@ Dh’fhalbh gairm o %s ort Fònaig air ais Cuir teachdaireachd + Chaidh crìoch a chur air a’ ghairm + Chaidh crìoch a chur air a’ ghairm gu %s on a chaidh gairm-èiginn a chur. + Chaidh crìoch a chur air a’ ghairm agad on a chaidh gairm-èiginn a chur. + + Gairm sa chùlaibh + Chuir %s gairm + dhan chùlaibh. Dh’fhaoidte gu bheil an aplacaid seo ag inntrigeadh ’s a’ cluich fuaim thar na gairme. + + Chan eil %s a’ freagairt tuilleadh + + Chleachd a’ ghairm agad aplacaid an fhòn a thàining am broinn an uidheim agad + Chaidh a’ ghairm a mhùchadh. Tha glaodhaire an fhòn an comas. Chan urrainn dhomh bruidhinn riut an-dràsta. Dè tha dol? @@ -34,6 +46,7 @@ Deasaich na grad-fhreagairtean Grad-fhreagairt Chaidh an teachdaireachd a chur gu %s. + Cha deach an teachdaireachd a chur gu %s. Cunntasan ghairmean Chan eil ach gairmean èiginn ceadaichte. Chan urrainn dhan aplacaid seo gairm a-mach a chur gun chead air an fhòn. @@ -42,10 +55,13 @@ Tha àireamh a’ phuist-ghutha a dhìth Chan eil àireamh puist-ghutha air a’ chairt SIM. Cuir àireamh ris - An dèan thu aplacaid thùsail an fhònaidh dhe %s? + An dèan thu aplacaid bhunaiteach an fhòn dhe %s? Suidhich mar a’ bhun-roghainn Sguir dheth - ’S urrainn dha %s gairmean a chur is gach nì mun dèidhinn a stiùireadh. Cha bu chòir dhut aplacaid a shuidheachadh mar tè thùsail an fhònaidh ach ma bhios earbsa agad innte. + ’S urrainn dha %s gairmean a chur is gach nì mun dèidhinn a stiùireadh. Cha bu chòir dhut aplacaid a shuidheachadh mar tè bhunaiteach an fhòn ach ma bhios earbsa agad innte. + An dèan thu aplacaid bhunaiteach an sgrìnidh ghairmean dhe %s? + Chan urrainn dha %s gairmean a sgrìneadh tuilleadh an uairsin. + Chì %s fiosrachadh mu ghairmearan nach eil am measg an luchd-aithne agad agus ’s urrainn dha na gairmean sin a bhacadh. Cha bu chòir dhut aplacaid a shuidheachadh mar tè bhunaiteach an sgrìnidh ghairmean ach ma bhios earbsa agad innte. Suidhich mar a’ bhun-roghainn Sguir dheth Àireamhan bacte @@ -75,8 +91,31 @@ Chat with Chat Network users RESTRICTED A’ cleachdadh an daithealair pearsanta airson na gairm + Gairm %1$s o %2$s + Gairm video %1$s o %2$s + Ma fhreagras tu, thèid crìoch a chur air a’ ghairm %1$s agad + Ma fhreagras tu, thèid crìoch a chur air na gairmean %1$s agad + Ma fhreagras tu, thèid crìoch a chur air a’ ghairm video %1$s agad + Ma fhreagras tu, thèid crìoch a chur air gairm a tha a’ dol air adhart + Ma fhreagras tu, thèid crìoch a chur air gairmean a tha a’ dol air adhart + Ma fhreagras tu, thèid crìoch a chur air gairm video a tha a’ dol air adhart + Freagair + Diùlt + Chan urrainn dhuinn a’ ghairm a chur o nach eil cunntas gairmeir ann a chuireas taic ris an t-seòrsa seo de ghairm. + Cha ghabh a’ ghairm a chur air sàilleibh na gairme %1$s agad. + Cha ghabh a’ ghairm a chur air sàilleibh nan gairmean %1$s agad. + Cha ghabh a’ ghairm a chur air sàilleibh gairme am broinn aplacaid eile. + Gairmean a-steach Gairmean a dh’fhalbh ort Bacadh ghairmean + Gairmean sa chùlaibh + Gairmean a chaidh crìoch a chur orra + Aplacaidean fòn a thuislich + Ma chuireas tu a’ ghairm seo, thèid crìoch a chur air a’ ghairm %1$s agad. + Tagh mar a thèid a’ ghairm seo a chur + Sìn a’ ghairm air adhart le %1$s + Dèan gairm leis an àireamh fòn agam + Chan urrainn dha %1$s a’ ghairm seo a chur. Feuch aplacaid sìnidh air adhart eile no cuir fios dhan luchd-leasachaidh airson taic. Bacadh ghairmean Àireamhan nach eil ’nan luchd-aithne Bac àireamhan nach deach a chlàradh san luchd-aithne agad @@ -90,4 +129,6 @@ Chaidh bacadh ghairmean a chur à comas Chaidh gairm-èiginn a dhèanamh Chaidh bacadh ghairmean a chur à comas ach am faigh an luchd-cobharach grèim ort. + Clàr-taice luchd-leasachaidh telecom + Chan urrainn dhut gairm a thogail fhad ’s a bhios tu ann an gairm-èiginn. From 2419172d2fb856ddefcedd0ca259b6dcdbda00d3 Mon Sep 17 00:00:00 2001 From: Deepak Sharma Date: Thu, 25 Nov 2021 23:21:40 +0000 Subject: [PATCH 06/21] Fix sorting issue during emergency call attempt. Fix the integer overflow/underflow caused by sorting of duplicate phoneaccounts during emergency call attempt. Bug: 208267659 Original change: https://android-review.googlesource.com/c/platform/packages/services/Telecomm/+/1903050 Merged-In: I3529e4f86ba5690a8c2e72d6103a84c00bf3f358 Change-Id: I3529e4f86ba5690a8c2e72d6103a84c00bf3f358 Test: Added unit test (see https://googleplex-android-review.git.corp.google.com/c/platform/packages/services/Telecomm/+/16372187) Test: Manual testing performed to confirm that this corrects repro. (cherry picked from commit e20b83ec9b3dc2bc5a49a666bd057cf45ce99f15) (cherry picked from commit 4f64285184fbad85a0a554f3cefa821846be8002) Merged-In:I3529e4f86ba5690a8c2e72d6103a84c00bf3f358 --- src/com/android/server/telecom/CreateConnectionProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/server/telecom/CreateConnectionProcessor.java b/src/com/android/server/telecom/CreateConnectionProcessor.java index 700dac73c..0a8a6c427 100644 --- a/src/com/android/server/telecom/CreateConnectionProcessor.java +++ b/src/com/android/server/telecom/CreateConnectionProcessor.java @@ -657,7 +657,7 @@ public void sortSimPhoneAccountsForEmergency(List accounts, } // then by hashcode - return account1.hashCode() - account2.hashCode(); + return Integer.compare(account1.hashCode(), account2.hashCode()); }); } From 12fba80c3f7eff816b2457f80aa7324d924b74f8 Mon Sep 17 00:00:00 2001 From: Michael Bestas Date: Sun, 13 Feb 2022 03:12:12 +0200 Subject: [PATCH 07/21] Automatic translation import Change-Id: Ic73baf31a06400b368f836e52599b6a1e9b99972 --- res/values-ast-rES/strings.xml | 56 +++++----------------------------- res/values-cy/strings.xml | 16 ++++++++++ 2 files changed, 24 insertions(+), 48 deletions(-) diff --git a/res/values-ast-rES/strings.xml b/res/values-ast-rES/strings.xml index c84820dd0..7b74af0f1 100644 --- a/res/values-ast-rES/strings.xml +++ b/res/values-ast-rES/strings.xml @@ -16,55 +16,25 @@ Xestión de llamaes Teléfonu - Desconocíu Llamada perdida - Perdióse la llamada\'l trabayu Llamaes perdíes - %s llamaes perdíes - Llamada perdida de %s - Llamar - Mensaxe - Llamada silenciada. + Llamada col audiu desactiváu. Altavoz habilitáu. - Nun puedo falar. ¿Ye importante? - Llámote namái pueda. + Nun puedo falar. ¿Qué pasó? + Llámote de siguío. Llámote dempués. - Nun puedo falar. Llámesme llueu? + Nun puedo falar. ¿Llámesme dempués? Rempuestes rápides - Editar rempuestes rápides - Rempuesta rápida - Mensaxe unviáu a %s. - Cuentes de llamaes - Namái s\'almiten llames d\'emerxencia. - Esta aplicación nun pue facer llamaes salientes ensin el permisu de Teléfonu. - Pa facer una llamada, teclexa un númberu válidu. - La llamada nun pue amestase nesti momentu. - Falta\'l númberu del buzón de voz - Nun s\'almacenó nengún númberu de buzón de voz na tarxeta SIM. - Amestar númberu - ¿Predeterminar la to aplicación de teléfonu %s? + Pa facer una llamada, introduz un númberu válidu. + Nesti momentu nun se pue amestar la llamada. + Nun s\'atroxó nengún númberu de buzón de voz na tarxeta SIM. Predeterminar Encaboxar - %s sedrá a allugar y controlar tolos aspeutos de les llamaes. Namái deberíen predeterminase como aplicación de teléfonu les aplicaciones nes que t\'enfotes. Predeterminar Encaboxar - Númberos bloquiaos - Nun recibirás llames o mensaxes de númberos bloquiaos. - Amestar un númberu - ¿Desbloquiar %1$s? Desbloquiar - Bloquiar llamaes y mensaxes de - Númberu telefónicu Bloquiar - Namái\'l dueñu\'l teléfonu pue ver y xestionar númberos bloquiaos. - Desbloquiar - Bloquéu desactiváu temporalmente - Dempués que marques o unvies un mensaxe a un númberu d\'emerxencies, desactivaráse\'l bloquéu p\'asegurar qu\'esos servicios puean contautate. - Reactivar agora - %1$s bloquiáu - %1$s desbloquiáu - Nun pue bloquiase\'l númberu d\'emerxencies. - %1$s yá ta bloquiáu. + Nun ye posible bloquiar el númberu d\'emerxencia. Q Mobile Market Wireless Sonoma Circles Talk Plus @@ -74,15 +44,5 @@ Talk to everyone in your Circles! Chat with Chat Network users RESTRICTED - Usando\'l marcador personal pa llamar Llamaes perdíes - Bloquéu de Llamaes - Bloquéu de Llamaes - Los númberos nun tán en Contautos - Priváu - Teléfonu públicu - Torgar llamaes de teléfonos de pagu - Desconocíu - Torgar llamaes de contautos ensin identificar - Bloquéu de Llamaes diff --git a/res/values-cy/strings.xml b/res/values-cy/strings.xml index f90c868a3..d689c6cf5 100644 --- a/res/values-cy/strings.xml +++ b/res/values-cy/strings.xml @@ -24,6 +24,18 @@ Wedi methu galwad gan %s Galw nôl Neges + Galwad wedi\'i datgysylltu + Datgysylltwyd yr alwad â %s am fod galwad brys wedi ei gwneud. + Cafodd dy alwad ei datgysylltu am fod galwad brys wedi ei gwneud. + + Galwad yn y cefndir + Mae %s wedi gosod galwad yn + y cefndir. Gall fod yr ap hwn yn cael at ac yn chwarae sain dros yr alwad. + + Stopiodd %s ymateb + + Defnyddiodd dy alwad yr ap ffôn daeth gyda dy ddyfais + Galwad wedi\'i distewi. Seinydd uchel wedi\'i alluogi. Methu siarad nawr. Be sy\'? @@ -96,6 +108,9 @@ Galwadau i mewn Galwadau wedi eu methu Rhwystro Galwadau + Galwadau yn y cefndir + Galwadau wedi\'u datgysylltu + Apiau ffôn wedi chwalu Bydd gwneud yr alwad hon yn dod a dy alwad %1$s i ben. Dewisa sut i wneud yr alwad hon Ailgyfierio\u2019r alwad gan ddefnyddio %1$s @@ -115,4 +130,5 @@ Wedi gwneud galwad brys Mae Rhwystro Galwadau wedi ei analluogi i ganiatáu’r gwasanaethau brys i gysylltu â thi. Dewislen Datblygwr Telathrebu + Ni ellir gwneud galwadau tra bo galwad brys ar y gweill. From e18fc07621dedb7ea59a4424e4ad9036108b6a15 Mon Sep 17 00:00:00 2001 From: Tyler Gunn Date: Mon, 7 Mar 2022 09:32:42 -0800 Subject: [PATCH 08/21] Handle null bindings returned from ConnectionService. When a ConnectionService returns a null binding, immediately unbind from the ConnectionService and cancel any ongoing calls related to it. Bug: 211114016 Test: Added new CTS test to verify auto unbind from null binding ConnectionService. Test: Manually tested using test app which implements null binding ConnectionService and verified via telecom log inspection that the service is unbound and the call is terminated. Change-Id: I0757557e66725dddfd871cd9857071a8749bd7ba (cherry picked from commit 410ce026004bb485c39afcc7d86e89d26ff1af94) Merged-In: I0757557e66725dddfd871cd9857071a8749bd7ba --- .../android/server/telecom/ServiceBinder.java | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/com/android/server/telecom/ServiceBinder.java b/src/com/android/server/telecom/ServiceBinder.java index aa2e2a247..7274993e7 100644 --- a/src/com/android/server/telecom/ServiceBinder.java +++ b/src/com/android/server/telecom/ServiceBinder.java @@ -150,7 +150,6 @@ public void onServiceConnected(ComponentName componentName, IBinder binder) { Log.i(this, "Service bound %s", componentName); Log.addEvent(mCall, LogUtils.Events.CS_BOUND, componentName); - mCall = null; // Unbind request was queued so unbind immediately. if (mIsBindingAborted) { @@ -192,6 +191,30 @@ public void onServiceDisconnected(ComponentName componentName) { Log.endSession(); } } + + /** + * Handles the case where the {@link ConnectionService} we bound to returned a null binding. + * We want to unbind from the service and cleanup and call resources at this time. + * @param componentName The component of the {@link ConnectionService}. + */ + @Override + public void onNullBinding(ComponentName componentName) { + try { + Log.startSession("SBC.oNB"); + synchronized (mLock) { + Log.w(this, "Null binding %s", componentName); + Log.addEvent(mCall, "NULL_BINDING", componentName); + String componentStr = componentName == null ? "null" : componentName.toString(); + android.util.EventLog.writeEvent(0x534e4554, "211114016", -1, componentStr); + logServiceDisconnected("onNullBinding"); + mContext.unbindService(this); + clearAbort(); + handleFailedConnection(); + } + } finally { + Log.endSession(); + } + } } private void handleDisconnect() { From 81776a14761c986694560d6fb0fa1a36967164e5 Mon Sep 17 00:00:00 2001 From: Thomas Stuart Date: Sat, 15 Jan 2022 01:15:29 +0000 Subject: [PATCH 09/21] limit TelecomManager#registerPhoneAccount to 10 bug: 209814693 Bug: 217934478 Test: CTS Change-Id: I3042a3973dd0dcc8d2fdc96c23d6d41522dc00af Merged-In: I3042a3973dd0dcc8d2fdc96c23d6d41522dc00af (cherry picked from commit eb3394e3a8e21cd07c4f7a7ad43494ba14a8cbf4) Merged-In: I3042a3973dd0dcc8d2fdc96c23d6d41522dc00af --- .../server/telecom/PhoneAccountRegistrar.java | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/com/android/server/telecom/PhoneAccountRegistrar.java b/src/com/android/server/telecom/PhoneAccountRegistrar.java index ef2840aca..0e06fbaf6 100644 --- a/src/com/android/server/telecom/PhoneAccountRegistrar.java +++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java @@ -133,6 +133,7 @@ public void onPhoneAccountChanged(PhoneAccountRegistrar registrar, public static final String FILE_NAME = "phone-account-registrar-state.xml"; @VisibleForTesting public static final int EXPECTED_STATE_VERSION = 9; + public static final int MAX_PHONE_ACCOUNT_REGISTRATIONS = 10; /** Keep in sync with the same in SipSettings.java */ private static final String SIP_SHARED_PREFERENCES = "SIP_PREFERENCES"; @@ -764,8 +765,13 @@ public boolean isSelfManagedPhoneAccount(@NonNull PhoneAccountHandle handle) { return account.isSelfManaged(); } - // TODO: Should we implement an artificial limit for # of accounts associated with a single - // ComponentName? + /** + * Performs checks before calling addOrReplacePhoneAccount(PhoneAccount) + * + * @param account The {@code PhoneAccount} to add or replace. + * @throws SecurityException if package does not have BIND_TELECOM_CONNECTION_SERVICE permission + * @throws IllegalArgumentException if MAX_PHONE_ACCOUNT_REGISTRATIONS are reached + */ public void registerPhoneAccount(PhoneAccount account) { // Enforce the requirement that a connection service for a phone account has the correct // permission. @@ -776,6 +782,19 @@ public void registerPhoneAccount(PhoneAccount account) { throw new SecurityException("PhoneAccount connection service requires " + "BIND_TELECOM_CONNECTION_SERVICE permission."); } + //Enforce an upper bound on the number of PhoneAccount's a package can register. + // Most apps should only require 1-2. + if (getPhoneAccountsForPackage( + account.getAccountHandle().getComponentName().getPackageName(), + account.getAccountHandle().getUserHandle()).size() + >= MAX_PHONE_ACCOUNT_REGISTRATIONS) { + Log.w(this, "Phone account %s reached max registration limit for package", + account.getAccountHandle()); + throw new IllegalArgumentException( + "Error, cannot register phone account " + account.getAccountHandle() + + " because the limit, " + MAX_PHONE_ACCOUNT_REGISTRATIONS + + ", has been reached"); + } addOrReplacePhoneAccount(account); } From c043f35481689c02ca252f405f12d26b32ceb923 Mon Sep 17 00:00:00 2001 From: Thomas Stuart Date: Thu, 23 Jun 2022 14:20:30 -0700 Subject: [PATCH 10/21] switch TelecomManager List getters to ParceledListSlice It was shown that given a large phoneAccountHandles that are over 1 mb, a TransactionTooLarge exception can be silently thrown causing an empty list to be returned. In order to prevent this behavior, all Lists that return a PhoneAccountHandle or PhoneAccount have been switched to ParceledListSlice. bug: 236263294 Test: atest android.telecom.cts.PhoneAccountRegistrarTest #testRegisterPhoneAccountHandleWithFieldOverLimit Change-Id: Ibc3814dabd59cf9f0f9505b88f2146a4c3c5e015 Merged-In: Ibc3814dabd59cf9f0f9505b88f2146a4c3c5e015 (cherry picked from commit 9f8c7709457c8c898760f556049aefafc62cf907) Merged-In: Ibc3814dabd59cf9f0f9505b88f2146a4c3c5e015 --- .../server/telecom/TelecomServiceImpl.java | 50 +++++++++++-------- .../telecom/tests/TelecomServiceImplTest.java | 18 ++++--- 2 files changed, 39 insertions(+), 29 deletions(-) diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java index 9ccae9a37..f286f2fd8 100644 --- a/src/com/android/server/telecom/TelecomServiceImpl.java +++ b/src/com/android/server/telecom/TelecomServiceImpl.java @@ -36,6 +36,7 @@ import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.net.Uri; import android.os.Binder; @@ -187,25 +188,26 @@ public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle } @Override - public List getCallCapablePhoneAccounts( + public ParceledListSlice getCallCapablePhoneAccounts( boolean includeDisabledAccounts, String callingPackage, String callingFeatureId) { try { Log.startSession("TSI.gCCPA"); if (includeDisabledAccounts && !canReadPrivilegedPhoneState( callingPackage, "getCallCapablePhoneAccounts")) { - return Collections.emptyList(); + return ParceledListSlice.emptyList(); } if (!canReadPhoneState(callingPackage, callingFeatureId, "getCallCapablePhoneAccounts")) { - return Collections.emptyList(); + return ParceledListSlice.emptyList(); } synchronized (mLock) { final UserHandle callingUserHandle = Binder.getCallingUserHandle(); long token = Binder.clearCallingIdentity(); try { - return mPhoneAccountRegistrar.getCallCapablePhoneAccounts(null, - includeDisabledAccounts, callingUserHandle); + return new ParceledListSlice<>( + mPhoneAccountRegistrar.getCallCapablePhoneAccounts(null, + includeDisabledAccounts, callingUserHandle)); } catch (Exception e) { Log.e(this, e, "getCallCapablePhoneAccounts"); throw e; @@ -219,8 +221,8 @@ public List getCallCapablePhoneAccounts( } @Override - public List getSelfManagedPhoneAccounts(String callingPackage, - String callingFeatureId) { + public ParceledListSlice getSelfManagedPhoneAccounts( + String callingPackage, String callingFeatureId) { try { Log.startSession("TSI.gSMPA"); if (!canReadPhoneState(callingPackage, callingFeatureId, @@ -231,8 +233,8 @@ public List getSelfManagedPhoneAccounts(String callingPackag final UserHandle callingUserHandle = Binder.getCallingUserHandle(); long token = Binder.clearCallingIdentity(); try { - return mPhoneAccountRegistrar.getSelfManagedPhoneAccounts( - callingUserHandle); + return new ParceledListSlice<>(mPhoneAccountRegistrar + .getSelfManagedPhoneAccounts(callingUserHandle)); } catch (Exception e) { Log.e(this, e, "getSelfManagedPhoneAccounts"); throw e; @@ -246,8 +248,8 @@ public List getSelfManagedPhoneAccounts(String callingPackag } @Override - public List getPhoneAccountsSupportingScheme(String uriScheme, - String callingPackage) { + public ParceledListSlice getPhoneAccountsSupportingScheme( + String uriScheme, String callingPackage) { try { Log.startSession("TSI.gPASS"); try { @@ -256,15 +258,16 @@ public List getPhoneAccountsSupportingScheme(String uriSchem } catch (SecurityException e) { EventLog.writeEvent(0x534e4554, "62347125", Binder.getCallingUid(), "getPhoneAccountsSupportingScheme: " + callingPackage); - return Collections.emptyList(); + return ParceledListSlice.emptyList(); } synchronized (mLock) { final UserHandle callingUserHandle = Binder.getCallingUserHandle(); long token = Binder.clearCallingIdentity(); try { - return mPhoneAccountRegistrar.getCallCapablePhoneAccounts(uriScheme, false, - callingUserHandle); + return new ParceledListSlice<>(mPhoneAccountRegistrar + .getCallCapablePhoneAccounts(uriScheme, false, + callingUserHandle)); } catch (Exception e) { Log.e(this, e, "getPhoneAccountsSupportingScheme %s", uriScheme); throw e; @@ -278,7 +281,8 @@ public List getPhoneAccountsSupportingScheme(String uriSchem } @Override - public List getPhoneAccountsForPackage(String packageName) { + public ParceledListSlice getPhoneAccountsForPackage( + String packageName) { //TODO: Deprecate this in S try { enforceCallingPackage(packageName); @@ -301,8 +305,8 @@ public List getPhoneAccountsForPackage(String packageName) { long token = Binder.clearCallingIdentity(); try { Log.startSession("TSI.gPAFP"); - return mPhoneAccountRegistrar.getPhoneAccountsForPackage(packageName, - callingUserHandle); + return new ParceledListSlice<>(mPhoneAccountRegistrar + .getPhoneAccountsForPackage(packageName, callingUserHandle)); } catch (Exception e) { Log.e(this, e, "getPhoneAccountsForPackage %s", packageName); throw e; @@ -353,7 +357,7 @@ public int getAllPhoneAccountsCount() { synchronized (mLock) { try { // This list is pre-filtered for the calling user. - return getAllPhoneAccounts().size(); + return getAllPhoneAccounts().getList().size(); } catch (Exception e) { Log.e(this, e, "getAllPhoneAccountsCount"); throw e; @@ -366,7 +370,7 @@ public int getAllPhoneAccountsCount() { } @Override - public List getAllPhoneAccounts() { + public ParceledListSlice getAllPhoneAccounts() { synchronized (mLock) { try { Log.startSession("TSI.gAPA"); @@ -382,7 +386,8 @@ public List getAllPhoneAccounts() { final UserHandle callingUserHandle = Binder.getCallingUserHandle(); long token = Binder.clearCallingIdentity(); try { - return mPhoneAccountRegistrar.getAllPhoneAccounts(callingUserHandle); + return new ParceledListSlice<>(mPhoneAccountRegistrar + .getAllPhoneAccounts(callingUserHandle)); } catch (Exception e) { Log.e(this, e, "getAllPhoneAccounts"); throw e; @@ -396,7 +401,7 @@ public List getAllPhoneAccounts() { } @Override - public List getAllPhoneAccountHandles() { + public ParceledListSlice getAllPhoneAccountHandles() { try { Log.startSession("TSI.gAPAH"); try { @@ -412,7 +417,8 @@ public List getAllPhoneAccountHandles() { final UserHandle callingUserHandle = Binder.getCallingUserHandle(); long token = Binder.clearCallingIdentity(); try { - return mPhoneAccountRegistrar.getAllPhoneAccountHandles(callingUserHandle); + return new ParceledListSlice<>(mPhoneAccountRegistrar + .getAllPhoneAccountHandles(callingUserHandle)); } catch (Exception e) { Log.e(this, e, "getAllPhoneAccounts"); throw e; diff --git a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java index 0dfe29a08..126c0c062 100644 --- a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java +++ b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java @@ -390,9 +390,11 @@ public void testGetCallCapablePhoneAccounts() throws RemoteException { makeAccountsVisibleToAllUsers(TEL_PA_HANDLE_16, SIP_PA_HANDLE_17); assertEquals(fullPHList, - mTSIBinder.getCallCapablePhoneAccounts(true, DEFAULT_DIALER_PACKAGE, null)); + mTSIBinder.getCallCapablePhoneAccounts( + true, DEFAULT_DIALER_PACKAGE, null).getList()); assertEquals(smallPHList, - mTSIBinder.getCallCapablePhoneAccounts(false, DEFAULT_DIALER_PACKAGE, null)); + mTSIBinder.getCallCapablePhoneAccounts( + false, DEFAULT_DIALER_PACKAGE, null).getList()); } @SmallTest @@ -407,7 +409,7 @@ public void testGetCallCapablePhoneAccountsFailure() throws RemoteException { List result = null; try { - result = mTSIBinder.getCallCapablePhoneAccounts(true, "", null); + result = mTSIBinder.getCallCapablePhoneAccounts(true, "", null).getList(); } catch (SecurityException e) { // intended behavior } @@ -435,9 +437,11 @@ public void testGetPhoneAccountsSupportingScheme() throws RemoteException { makeAccountsVisibleToAllUsers(TEL_PA_HANDLE_16, SIP_PA_HANDLE_17); assertEquals(telPHList, - mTSIBinder.getPhoneAccountsSupportingScheme("tel", DEFAULT_DIALER_PACKAGE)); + mTSIBinder.getPhoneAccountsSupportingScheme( + "tel", DEFAULT_DIALER_PACKAGE).getList()); assertEquals(sipPHList, - mTSIBinder.getPhoneAccountsSupportingScheme("sip", DEFAULT_DIALER_PACKAGE)); + mTSIBinder.getPhoneAccountsSupportingScheme( + "sip", DEFAULT_DIALER_PACKAGE).getList()); } @SmallTest @@ -453,7 +457,7 @@ public void testGetPhoneAccountsForPackage() throws RemoteException { makeAccountsVisibleToAllUsers(TEL_PA_HANDLE_16, SIP_PA_HANDLE_17); assertEquals(phoneAccountHandleList, mTSIBinder.getPhoneAccountsForPackage( - TEL_PA_HANDLE_16.getComponentName().getPackageName())); + TEL_PA_HANDLE_16.getComponentName().getPackageName()).getList()); } @SmallTest @@ -476,7 +480,7 @@ public void testGetAllPhoneAccounts() throws RemoteException { when(mFakePhoneAccountRegistrar.getAllPhoneAccounts(any(UserHandle.class))) .thenReturn(phoneAccountList); - assertEquals(2, mTSIBinder.getAllPhoneAccounts().size()); + assertEquals(2, mTSIBinder.getAllPhoneAccounts().getList().size()); } @SmallTest From de386395c84d97cbabf38e711bd994b5059ab1bb Mon Sep 17 00:00:00 2001 From: Grace Jia Date: Thu, 25 Aug 2022 14:47:19 -0700 Subject: [PATCH 11/21] DO NOT MERGE Fix security vulnerability issue for multi user call redirections. Currently we won't check if the PhoneAccountHandle provided by a CallRedirectionService has multi-user capability or belong to the same user as the current user. Add the check and disconnect the call if this is an unexpected cross-user call redirection. Bug: 235098883 Test: CallsManagerTest, manual test with test app provided in b/235098883. Change-Id: Ia8b9468aa2bb8e3157c227e2617ff6a52e0af119 Merged-In: Ia8b9468aa2bb8e3157c227e2617ff6a52e0af119 (cherry picked from commit f29ab7e1ec0e480e2d39d289d5aa3fc95aed2142) (cherry picked from commit 256ef21f54f70e5b3d32058806ceeff546d7e07a) Merged-In: Ia8b9468aa2bb8e3157c227e2617ff6a52e0af119 --- .../android/server/telecom/CallsManager.java | 19 +++++++++++--- .../telecom/tests/CallsManagerTest.java | 25 +++++++++++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-) mode change 100755 => 100644 src/com/android/server/telecom/CallsManager.java diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java old mode 100755 new mode 100644 index 1c46209cd..5273675eb --- a/src/com/android/server/telecom/CallsManager.java +++ b/src/com/android/server/telecom/CallsManager.java @@ -1956,6 +1956,16 @@ public void onCallRedirectionComplete(Call call, Uri handle, boolean endEarly = false; String disconnectReason = ""; String callRedirectionApp = mRoleManagerAdapter.getDefaultCallRedirectionApp(); + PhoneAccount phoneAccount = mPhoneAccountRegistrar + .getPhoneAccountUnchecked(phoneAccountHandle); + if (phoneAccount != null + && !phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) { + // Check if the phoneAccountHandle belongs to the current user + if (phoneAccountHandle != null && + !phoneAccountHandle.getUserHandle().equals(mCurrentUserHandle)) { + phoneAccountHandle = null; + } + } boolean isPotentialEmergencyNumber; try { @@ -1988,9 +1998,9 @@ public void onCallRedirectionComplete(Call call, Uri handle, endEarly = true; disconnectReason = "Null handle from Call Redirection Service"; } else if (phoneAccountHandle == null) { - Log.w(this, "onCallRedirectionComplete: phoneAccountHandle is null"); + Log.w(this, "onCallRedirectionComplete: phoneAccountHandle is unavailable"); endEarly = true; - disconnectReason = "Null phoneAccountHandle from Call Redirection Service"; + disconnectReason = "Unavailable phoneAccountHandle from Call Redirection Service"; } else if (isPotentialEmergencyNumber) { Log.w(this, "onCallRedirectionComplete: emergency number %s is redirected from Call" + " Redirection Service", handle.getSchemeSpecificPart()); @@ -2011,6 +2021,7 @@ public void onCallRedirectionComplete(Call call, Uri handle, return; } + final PhoneAccountHandle finalPhoneAccountHandle = phoneAccountHandle; if (uiAction.equals(CallRedirectionProcessor.UI_TYPE_USER_DEFINED_ASK_FOR_CONFIRM)) { Log.addEvent(call, LogUtils.Events.REDIRECTION_USER_CONFIRMATION); mPendingRedirectedOutgoingCall = call; @@ -2020,7 +2031,7 @@ public void onCallRedirectionComplete(Call call, Uri handle, @Override public void loggedRun() { Log.addEvent(call, LogUtils.Events.REDIRECTION_USER_CONFIRMED); - call.setTargetPhoneAccount(phoneAccountHandle); + call.setTargetPhoneAccount(finalPhoneAccountHandle); placeOutgoingCall(call, handle, gatewayInfo, speakerphoneOn, videoState); } @@ -2030,7 +2041,7 @@ public void loggedRun() { new Runnable("CM.oCRC", mLock) { @Override public void loggedRun() { - call.setTargetPhoneAccount(phoneAccountHandle); + call.setTargetPhoneAccount(finalPhoneAccountHandle); placeOutgoingCall(call, handle, null, speakerphoneOn, videoState); } diff --git a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java index 4dffe596a..d16430298 100644 --- a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java +++ b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java @@ -36,6 +36,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -49,6 +50,9 @@ import android.os.UserHandle; import android.telecom.CallerInfo; import android.telecom.Connection; +import android.telecom.Log; +import android.telecom.DisconnectCause; +import android.telecom.GatewayInfo; import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; @@ -122,8 +126,12 @@ @RunWith(JUnit4.class) public class CallsManagerTest extends TelecomTestCase { private static final int TEST_TIMEOUT = 5000; // milliseconds + private static final int SECONDARY_USER_ID = 12; private static final PhoneAccountHandle SIM_1_HANDLE = new PhoneAccountHandle( ComponentName.unflattenFromString("com.foo/.Blah"), "Sim1"); + private static final PhoneAccountHandle SIM_1_HANDLE_SECONDARY = new PhoneAccountHandle( + ComponentName.unflattenFromString("com.foo/.Blah"), "Sim1", + new UserHandle(SECONDARY_USER_ID)); private static final PhoneAccountHandle SIM_2_HANDLE = new PhoneAccountHandle( ComponentName.unflattenFromString("com.foo/.Blah"), "Sim2"); private static final PhoneAccountHandle CONNECTION_MGR_1_HANDLE = new PhoneAccountHandle( @@ -1431,6 +1439,23 @@ public void testRequestDisconnect() throws Exception { eq(CallState.ACTIVE)); } + @SmallTest + @Test + public void testCrossUserCallRedirectionEndEarlyForIncapablePhoneAccount() { + when(mPhoneAccountRegistrar.getPhoneAccountUnchecked(eq(SIM_1_HANDLE_SECONDARY))) + .thenReturn(SIM_1_ACCOUNT); + mCallsManager.onUserSwitch(UserHandle.SYSTEM); + + Call callSpy = addSpyCall(CallState.NEW); + mCallsManager.onCallRedirectionComplete(callSpy, TEST_ADDRESS, SIM_1_HANDLE_SECONDARY, + new GatewayInfo("foo", TEST_ADDRESS2, TEST_ADDRESS), true /* speakerphoneOn */, + VideoProfile.STATE_AUDIO_ONLY, false /* shouldCancelCall */, "" /* uiAction */); + + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(String.class); + verify(callSpy).disconnect(argumentCaptor.capture()); + assertTrue(argumentCaptor.getValue().contains("Unavailable phoneAccountHandle")); + } + private Call addSpyCall() { return addSpyCall(SIM_2_HANDLE, CallState.ACTIVE); } From 71516aabfc5f27022cfe10a3716498893ff3590a Mon Sep 17 00:00:00 2001 From: Tyler Gunn Date: Tue, 27 Sep 2022 15:19:05 -0700 Subject: [PATCH 12/21] Hide overlay windows when showing phone account enable/disable screen. Hide any system alert window overlays when the screen that lets the user enable/disable phone accounts is shown. Test: Manual test with overlay shown from test app; verify that the overlay is hidden when the phone account selection screen is opened. Bug: 246933359 Change-Id: Ia0209d57ee9a672cde4196076845d77941dc3f68 (cherry picked from commit a7d57ace5819c4eef340aaf6744ad441d0369035) Merged-In: Ia0209d57ee9a672cde4196076845d77941dc3f68 --- AndroidManifest.xml | 1 + .../telecom/settings/EnableAccountPreferenceActivity.java | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 7c57599aa..eb0ac9e95 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -23,6 +23,7 @@ + + + Tiliɣri + Arussin + Asiwel yettwazgalen + Izen + Rnu uṭṭun + Semmet + Semmet + Eks asewḥel + Uṭṭun n tiliγri + Sewḥel + Eks asewḥel + Tiririt + Agwi + Uslig + Arussin + From 5223d86731cd51e5b7e39439071fde5b804b9a17 Mon Sep 17 00:00:00 2001 From: Pranav Madapurmath Date: Tue, 21 Mar 2023 23:28:56 +0000 Subject: [PATCH 18/21] Call Redirection: unbind service when onBind returns null The call redirection service does not handle the corner case of onNullBinding (occurs when onBind returns null). This vulnerability would give the app that has the call redirection role unintentional access to launch background activities outside the scope of a call lifecycle. Fixes: 273260090 Test: Unit test to ensure we unbind the service on null onBind Test: CTS for similar assertion (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:c3580d96071a7232ce11ad83848d6394b93121d8) Merged-In: Ib9d44d239833131eb055e83801cb635e8efe0b81 Change-Id: Ib9d44d239833131eb055e83801cb635e8efe0b81 --- .../CallRedirectionProcessor.java | 13 ++++++++++ .../tests/CallRedirectionProcessorTest.java | 24 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java b/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java index e93ef2243..da64b3769 100644 --- a/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java +++ b/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java @@ -151,6 +151,19 @@ public void onServiceDisconnected(ComponentName componentName) { Log.endSession(); } } + + @Override + public void onNullBinding(ComponentName componentName) { + // Make sure we unbind the service if onBind returns null + Log.startSession("CRSC.oNB"); + try { + synchronized (mTelecomLock) { + finishCallRedirection(); + } + } finally { + Log.endSession(); + } + } } private class CallRedirectionAdapter extends ICallRedirectionAdapter.Stub { diff --git a/tests/src/com/android/server/telecom/tests/CallRedirectionProcessorTest.java b/tests/src/com/android/server/telecom/tests/CallRedirectionProcessorTest.java index ff16880cc..ba2a248d2 100644 --- a/tests/src/com/android/server/telecom/tests/CallRedirectionProcessorTest.java +++ b/tests/src/com/android/server/telecom/tests/CallRedirectionProcessorTest.java @@ -354,4 +354,28 @@ public void testStripPostDialDigits() throws Exception { assertEquals(REDIRECTED_GATEWAY_NUMBER_WITH_POST_DIAL, gatewayInfoArgumentCaptor.getValue().getGatewayAddress()); } + + @Test + public void testUnbindOnNullBind() throws Exception { + startProcessWithNoGateWayInfo(); + // To make sure tests are not flaky, clean all the previous handler messages + waitForHandlerAction(mProcessor.getHandler(), HANDLER_TIMEOUT_DELAY); + enableUserDefinedCallRedirectionService(); + disableCarrierCallRedirectionService(); + + mProcessor.performCallRedirection(); + + // Capture the binder + ArgumentCaptor serviceConnectionCaptor = ArgumentCaptor.forClass( + ServiceConnection.class); + // Verify binding occurred + verify(mContext, times(1)).bindServiceAsUser(any(Intent.class), + serviceConnectionCaptor.capture(), anyInt(), eq(UserHandle.CURRENT)); + // Simulate null return from onBind + serviceConnectionCaptor.getValue().onNullBinding(USER_DEFINED_SERVICE_TEST_COMPONENT_NAME); + + // Verify service was unbound + verify(mContext, times(1)). + unbindService(any(ServiceConnection.class)); + } } From e084d4c6a70802cd32fe4dcbabbaee27785f6393 Mon Sep 17 00:00:00 2001 From: Pranav Madapurmath Date: Thu, 25 May 2023 20:49:21 +0000 Subject: [PATCH 19/21] Resolve StatusHints image exploit across user. Because of the INTERACT_ACROSS_USERS permission, an app that implements a ConnectionService can upload an image icon belonging to another user by setting it in the StatusHints. Validating the construction of the StatusHints on the calling user would prevent a malicious app from registering a connection service with the embedded image icon from a different user. From additional feedback, this CL also addresses potential vulnerabilities in an app being able to directly invoke the binder for a means to manipulate the contents of the bundle that are passed with it. The targeted points of entry are in ConnectionServiceWrapper for the following APIs: handleCreateConnectionComplete, setStatusHints, addConferenceCall, and addExistingConnection. Fixes: 280797684 Test: Manual (verified that original exploit is no longer an issue). Test: Unit test for validating image in StatusHints constructor. Test: Unit tests to address vulnerabilities via the binder. (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:49d19dd265bee669b230efa29bf98c83650efea6) Merged-In: Ie1f6a8866d31d5f1099dd0630cf8e9ee782d389c Change-Id: Ie1f6a8866d31d5f1099dd0630cf8e9ee782d389c --- .../telecom/ConnectionServiceWrapper.java | 31 ++++ .../server/telecom/tests/BasicCallTests.java | 166 +++++++++++++++++- .../server/telecom/tests/CallExtrasTest.java | 6 +- .../tests/ConnectionServiceFixture.java | 21 ++- .../telecom/tests/TelecomSystemTest.java | 66 ++++--- .../server/telecom/tests/VideoCallTests.java | 16 +- 6 files changed, 266 insertions(+), 40 deletions(-) mode change 100755 => 100644 src/com/android/server/telecom/ConnectionServiceWrapper.java diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java old mode 100755 new mode 100644 index 01acdd185..64fdd8833 --- a/src/com/android/server/telecom/ConnectionServiceWrapper.java +++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java @@ -22,6 +22,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; +import android.graphics.drawable.Icon; import android.net.Uri; import android.os.Binder; import android.os.Bundle; @@ -78,10 +79,17 @@ public void handleCreateConnectionComplete(String callId, ConnectionRequest requ ParcelableConnection connection, Session.Info sessionInfo) { Log.startSession(sessionInfo, LogUtils.Sessions.CSW_HANDLE_CREATE_CONNECTION_COMPLETE, mPackageAbbreviation); + UserHandle callingUserHandle = Binder.getCallingUserHandle(); long token = Binder.clearCallingIdentity(); try { synchronized (mLock) { logIncoming("handleCreateConnectionComplete %s", callId); + // Check status hints image for cross user access + if (connection.getStatusHints() != null) { + Icon icon = connection.getStatusHints().getIcon(); + connection.getStatusHints().setIcon(StatusHints. + validateAccountIconUserBoundary(icon, callingUserHandle)); + } ConnectionServiceWrapper.this .handleCreateConnectionComplete(callId, request, connection); @@ -476,6 +484,14 @@ public void addConferenceCall(String callId, ParcelableConference parcelableConf Log.startSession(sessionInfo, LogUtils.Sessions.CSW_ADD_CONFERENCE_CALL, mPackageAbbreviation); + UserHandle callingUserHandle = Binder.getCallingUserHandle(); + // Check status hints image for cross user access + if (parcelableConference.getStatusHints() != null) { + Icon icon = parcelableConference.getStatusHints().getIcon(); + parcelableConference.getStatusHints().setIcon(StatusHints. + validateAccountIconUserBoundary(icon, callingUserHandle)); + } + if (parcelableConference.getConnectElapsedTimeMillis() != 0 && mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) { @@ -721,10 +737,17 @@ public void setAudioRoute(String callId, int audioRoute, public void setStatusHints(String callId, StatusHints statusHints, Session.Info sessionInfo) { Log.startSession(sessionInfo, "CSW.sSH", mPackageAbbreviation); + UserHandle callingUserHandle = Binder.getCallingUserHandle(); long token = Binder.clearCallingIdentity(); try { synchronized (mLock) { logIncoming("setStatusHints %s %s", callId, statusHints); + // Check status hints image for cross user access + if (statusHints != null) { + Icon icon = statusHints.getIcon(); + statusHints.setIcon(StatusHints.validateAccountIconUserBoundary( + icon, callingUserHandle)); + } Call call = mCallIdMapper.getCall(callId); if (call != null) { call.setStatusHints(statusHints); @@ -917,6 +940,14 @@ public void addExistingConnection(String callId, ParcelableConnection connection } else { connectIdToCheck = callId; } + + // Check status hints image for cross user access + if (connection.getStatusHints() != null) { + Icon icon = connection.getStatusHints().getIcon(); + connection.getStatusHints().setIcon(StatusHints. + validateAccountIconUserBoundary(icon, userHandle)); + } + // Check to see if this Connection has already been added. Call alreadyAddedConnection = mCallsManager .getAlreadyAddedConnection(connectIdToCheck); diff --git a/tests/src/com/android/server/telecom/tests/BasicCallTests.java b/tests/src/com/android/server/telecom/tests/BasicCallTests.java index 6fd53ebba..382e0b710 100644 --- a/tests/src/com/android/server/telecom/tests/BasicCallTests.java +++ b/tests/src/com/android/server/telecom/tests/BasicCallTests.java @@ -16,8 +16,11 @@ package com.android.server.telecom.tests; +import static com.android.server.telecom.tests.ConnectionServiceFixture.STATUS_HINTS_EXTRA; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.nullable; @@ -35,9 +38,13 @@ import android.content.Context; import android.content.IContentProvider; +import android.content.Intent; +import android.graphics.drawable.Icon; import android.media.AudioManager; import android.net.Uri; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; import android.os.Process; import android.provider.BlockedNumberContract; import android.telecom.Call; @@ -49,12 +56,14 @@ import android.telecom.ParcelableCall; import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; +import android.telecom.StatusHints; import android.telecom.TelecomManager; import android.telecom.VideoProfile; import android.test.suitebuilder.annotation.LargeTest; import android.test.suitebuilder.annotation.MediumTest; import androidx.test.filters.FlakyTest; +import androidx.test.filters.SmallTest; import com.android.internal.telecom.IInCallAdapter; import android.telecom.CallerInfo; @@ -180,7 +189,7 @@ public void testTelecomManagerAcceptRingingCall() throws Exception { @Test public void testTelecomManagerAcceptRingingVideoCall() throws Exception { IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), - VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA); + VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA, null); assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); @@ -209,7 +218,7 @@ public void testTelecomManagerAcceptRingingVideoCall() throws Exception { @Test public void testTelecomManagerAcceptRingingVideoCallAsAudio() throws Exception { IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), - VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA); + VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA, null); assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); @@ -237,7 +246,7 @@ public void testTelecomManagerAcceptRingingVideoCallAsAudio() throws Exception { @Test public void testTelecomManagerAcceptRingingInvalidVideoState() throws Exception { IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), - VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA); + VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA, null); assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); @@ -661,13 +670,13 @@ public void run() { @MediumTest @Test public void testBasicConferenceCall() throws Exception { - makeConferenceCall(); + makeConferenceCall(null, null); } @MediumTest @Test public void testAddCallToConference1() throws Exception { - ParcelableCall conferenceCall = makeConferenceCall(); + ParcelableCall conferenceCall = makeConferenceCall(null, null); IdPair callId3 = startAndMakeActiveOutgoingCall("650-555-1214", mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); // testAddCallToConference{1,2} differ in the order of arguments to InCallAdapter#conference @@ -685,7 +694,7 @@ public void testAddCallToConference1() throws Exception { @MediumTest @Test public void testAddCallToConference2() throws Exception { - ParcelableCall conferenceCall = makeConferenceCall(); + ParcelableCall conferenceCall = makeConferenceCall(null, null); IdPair callId3 = startAndMakeActiveOutgoingCall("650-555-1214", mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); mInCallServiceFixtureX.getInCallAdapter() @@ -944,7 +953,7 @@ public void testPullNonPullableExternalCall() throws Exception { public void testOutgoingCallSelectPhoneAccountVideo() throws Exception { startOutgoingPhoneCallPendingCreateConnection("650-555-1212", null, mConnectionServiceFixtureA, - Process.myUserHandle(), VideoProfile.STATE_BIDIRECTIONAL); + Process.myUserHandle(), VideoProfile.STATE_BIDIRECTIONAL, null); com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls() .iterator().next(); assert(call.isVideoCallingSupportedByPhoneAccount()); @@ -967,7 +976,7 @@ public void testOutgoingCallSelectPhoneAccountVideo() throws Exception { public void testOutgoingCallSelectPhoneAccountNoVideo() throws Exception { startOutgoingPhoneCallPendingCreateConnection("650-555-1212", null, mConnectionServiceFixtureA, - Process.myUserHandle(), VideoProfile.STATE_BIDIRECTIONAL); + Process.myUserHandle(), VideoProfile.STATE_BIDIRECTIONAL, null); com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls() .iterator().next(); assert(call.isVideoCallingSupportedByPhoneAccount()); @@ -1176,4 +1185,145 @@ public void testUnmuteDuringEmergencyCall() throws Exception { assertTrue(muteValues.get(0)); assertFalse(muteValues.get(1)); } + + /** + * Verifies that StatusHints image is validated in ConnectionServiceWrapper#addConferenceCall + * when the image doesn't belong to the calling user. Simulates a scenario where an app + * could manipulate the contents of the bundle and send it via the binder to upload an image + * from another user. + * + * @throws Exception + */ + @SmallTest + @Test + public void testValidateStatusHintsImage_addConferenceCall() throws Exception { + Intent callIntent1 = new Intent(); + // Stub intent for call2 + Intent callIntent2 = new Intent(); + Bundle callExtras1 = new Bundle(); + Icon icon = Icon.createWithContentUri("content://10@media/external/images/media/"); + // Load StatusHints extra into TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS to be processed + // as the call extras. This will be leveraged in ConnectionServiceFixture to set the + // StatusHints for the given connection. + StatusHints statusHints = new StatusHints(icon); + assertNotNull(statusHints.getIcon()); + callExtras1.putParcelable(STATUS_HINTS_EXTRA, statusHints); + callIntent1.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, callExtras1); + + // Start conference call to invoke ConnectionServiceWrapper#addConferenceCall. + // Note that the calling user would be User 0. + ParcelableCall conferenceCall = makeConferenceCall(callIntent1, callIntent2); + + // Ensure that StatusHints was set. + assertNotNull(mInCallServiceFixtureX.getCall(mInCallServiceFixtureX.mLatestCallId) + .getStatusHints()); + // Ensure that the StatusHints image icon was disregarded. + assertNull(mInCallServiceFixtureX.getCall(mInCallServiceFixtureX.mLatestCallId) + .getStatusHints().getIcon()); + } + + /** + * Verifies that StatusHints image is validated in + * ConnectionServiceWrapper#handleCreateConnectionComplete when the image doesn't belong to the + * calling user. Simulates a scenario where an app could manipulate the contents of the + * bundle and send it via the binder to upload an image from another user. + * + * @throws Exception + */ + @SmallTest + @Test + public void testValidateStatusHintsImage_handleCreateConnectionComplete() throws Exception { + Bundle extras = new Bundle(); + Icon icon = Icon.createWithContentUri("content://10@media/external/images/media/"); + // Load the bundle with the test extra in order to simulate an app directly invoking the + // binder on ConnectionServiceWrapper#handleCreateConnectionComplete. + StatusHints statusHints = new StatusHints(icon); + assertNotNull(statusHints.getIcon()); + extras.putParcelable(STATUS_HINTS_EXTRA, statusHints); + + // Start incoming call with StatusHints extras + // Note that the calling user in ConnectionServiceWrapper#handleCreateConnectionComplete + // would be User 0. + IdPair ids = startIncomingPhoneCallWithExtras("650-555-1212", + mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA, extras); + + // Ensure that StatusHints was set. + assertNotNull(mInCallServiceFixtureX.getCall(ids.mCallId).getStatusHints()); + // Ensure that the StatusHints image icon was disregarded. + assertNull(mInCallServiceFixtureX.getCall(ids.mCallId).getStatusHints().getIcon()); + } + + /** + * Verifies that StatusHints image is validated in ConnectionServiceWrapper#setStatusHints + * when the image doesn't belong to the calling user. Simulates a scenario where an app + * could manipulate the contents of the bundle and send it via the binder to upload an image + * from another user. + * + * @throws Exception + */ + @SmallTest + @Test + public void testValidateStatusHintsImage_setStatusHints() throws Exception { + IdPair outgoing = startAndMakeActiveOutgoingCall("650-555-1214", + mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); + + // Modify existing connection with StatusHints image exploit + Icon icon = Icon.createWithContentUri("content://10@media/external/images/media/"); + StatusHints statusHints = new StatusHints(icon); + assertNotNull(statusHints.getIcon()); + ConnectionServiceFixture.ConnectionInfo connectionInfo = mConnectionServiceFixtureA + .mConnectionById.get(outgoing.mConnectionId); + connectionInfo.statusHints = statusHints; + + // Invoke ConnectionServiceWrapper#setStatusHints. + // Note that the calling user would be User 0. + mConnectionServiceFixtureA.sendSetStatusHints(outgoing.mConnectionId); + waitForHandlerAction(mConnectionServiceFixtureA.mConnectionServiceDelegate.getHandler(), + TEST_TIMEOUT); + + // Ensure that StatusHints was set. + assertNotNull(mInCallServiceFixtureX.getCall(outgoing.mCallId).getStatusHints()); + // Ensure that the StatusHints image icon was disregarded. + assertNull(mInCallServiceFixtureX.getCall(outgoing.mCallId) + .getStatusHints().getIcon()); + } + + /** + * Verifies that StatusHints image is validated in + * ConnectionServiceWrapper#addExistingConnection when the image doesn't belong to the calling + * user. Simulates a scenario where an app could manipulate the contents of the bundle and + * send it via the binder to upload an image from another user. + * + * @throws Exception + */ + @SmallTest + @Test + public void testValidateStatusHintsImage_addExistingConnection() throws Exception { + IdPair outgoing = startAndMakeActiveOutgoingCall("650-555-1214", + mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); + Connection existingConnection = mConnectionServiceFixtureA.mLatestConnection; + + // Modify existing connection with StatusHints image exploit + Icon icon = Icon.createWithContentUri("content://10@media/external/images/media/"); + StatusHints modifiedStatusHints = new StatusHints(icon); + assertNotNull(modifiedStatusHints.getIcon()); + ConnectionServiceFixture.ConnectionInfo connectionInfo = mConnectionServiceFixtureA + .mConnectionById.get(outgoing.mConnectionId); + connectionInfo.statusHints = modifiedStatusHints; + + // Invoke ConnectionServiceWrapper#addExistingConnection. + // Note that the calling user would be User 0. + mConnectionServiceFixtureA.sendAddExistingConnection(outgoing.mConnectionId); + waitForHandlerAction(mConnectionServiceFixtureA.mConnectionServiceDelegate.getHandler(), + TEST_TIMEOUT); + + // Ensure that StatusHints was set. Due to test setup, the ParcelableConnection object that + // is passed into sendAddExistingConnection is instantiated on invocation. The call's + // StatusHints are not updated at the time of completion, so instead, we can verify that + // the ParcelableConnection object was modified. + assertNotNull(mConnectionServiceFixtureA.mLatestParcelableConnection.getStatusHints()); + // Ensure that the StatusHints image icon was disregarded. + assertNull(mConnectionServiceFixtureA.mLatestParcelableConnection + .getStatusHints().getIcon()); + } } diff --git a/tests/src/com/android/server/telecom/tests/CallExtrasTest.java b/tests/src/com/android/server/telecom/tests/CallExtrasTest.java index 926d74078..cf44cfeff 100644 --- a/tests/src/com/android/server/telecom/tests/CallExtrasTest.java +++ b/tests/src/com/android/server/telecom/tests/CallExtrasTest.java @@ -370,7 +370,7 @@ public void testExtrasBidirectional() throws Exception { @LargeTest @Test public void testConferenceSetExtras() throws Exception { - ParcelableCall call = makeConferenceCall(); + ParcelableCall call = makeConferenceCall(null, null); String conferenceId = call.getId(); Conference conference = mConnectionServiceFixtureA.mLatestConference; @@ -414,7 +414,7 @@ public void testConferenceSetExtras() throws Exception { @FlakyTest(bugId = 117751305) @Test public void testConferenceExtraOperations() throws Exception { - ParcelableCall call = makeConferenceCall(); + ParcelableCall call = makeConferenceCall(null, null); String conferenceId = call.getId(); Conference conference = mConnectionServiceFixtureA.mLatestConference; assertNotNull(conference); @@ -450,7 +450,7 @@ public void testConferenceExtraOperations() throws Exception { @LargeTest @Test public void testConferenceICS() throws Exception { - ParcelableCall call = makeConferenceCall(); + ParcelableCall call = makeConferenceCall(null, null); String conferenceId = call.getId(); Conference conference = mConnectionServiceFixtureA.mLatestConference; diff --git a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java index 46b1522df..eaba9ca54 100755 --- a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java +++ b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java @@ -67,6 +67,7 @@ public class ConnectionServiceFixture implements TestFixture static int INVALID_VIDEO_STATE = -1; public CountDownLatch mExtrasLock = new CountDownLatch(1); static int NOT_SPECIFIED = 0; + public static final String STATUS_HINTS_EXTRA = "updateStatusHints"; /** * Implementation of ConnectionService that performs no-ops for tasks normally meant for @@ -101,6 +102,11 @@ public Connection onCreateIncomingConnection( if (mProperties != NOT_SPECIFIED) { fakeConnection.setConnectionProperties(mProperties); } + // Testing for StatusHints image icon cross user access + if (request.getExtras() != null) { + fakeConnection.setStatusHints( + request.getExtras().getParcelable(STATUS_HINTS_EXTRA)); + } return fakeConnection; } @@ -117,6 +123,11 @@ public Connection onCreateOutgoingConnection( if (mProperties != NOT_SPECIFIED) { fakeConnection.setConnectionProperties(mProperties); } + // Testing for StatusHints image icon cross user access + if (request.getExtras() != null) { + fakeConnection.setStatusHints( + request.getExtras().getParcelable(STATUS_HINTS_EXTRA)); + } return fakeConnection; } @@ -133,6 +144,12 @@ public void onConference(Connection cxn1, Connection cxn2) { Conference fakeConference = new FakeConference(); fakeConference.addConnection(cxn1); fakeConference.addConnection(cxn2); + if (cxn1.getStatusHints() != null || cxn2.getStatusHints() != null) { + // For testing purposes, pick one of the status hints that isn't null. + StatusHints statusHints = cxn1.getStatusHints() != null + ? cxn1.getStatusHints() : cxn2.getStatusHints(); + fakeConference.setStatusHints(statusHints); + } mLatestConference = fakeConference; addConference(fakeConference); } else { @@ -480,6 +497,7 @@ public class ConferenceInfo { public String mLatestConnectionId; public Connection mLatestConnection; + public ParcelableConnection mLatestParcelableConnection; public Conference mLatestConference; public final Set mConnectionServiceAdapters = new HashSet<>(); public final Map mConnectionById = new HashMap<>(); @@ -724,7 +742,7 @@ private ParcelableConference parcelable(ConferenceInfo c) { } private ParcelableConnection parcelable(ConnectionInfo c) { - return new ParcelableConnection( + mLatestParcelableConnection = new ParcelableConnection( c.request.getAccountHandle(), c.state, c.capabilities, @@ -745,5 +763,6 @@ private ParcelableConnection parcelable(ConnectionInfo c) { c.conferenceableConnectionIds, c.extras, c.callerNumberVerificationStatus); + return mLatestParcelableConnection; } } diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java index 68b10c6f8..94b4860ee 100644 --- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java +++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java @@ -415,12 +415,13 @@ public void tearDown() throws Exception { super.tearDown(); } - protected ParcelableCall makeConferenceCall() throws Exception { - IdPair callId1 = startAndMakeActiveOutgoingCall("650-555-1212", - mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); + protected ParcelableCall makeConferenceCall( + Intent callIntentExtras1, Intent callIntentExtras2) throws Exception { + IdPair callId1 = startAndMakeActiveOutgoingCallWithExtras("650-555-1212", + mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA, callIntentExtras1); - IdPair callId2 = startAndMakeActiveOutgoingCall("650-555-1213", - mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); + IdPair callId2 = startAndMakeActiveOutgoingCallWithExtras("650-555-1213", + mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA, callIntentExtras2); IInCallAdapter inCallAdapter = mInCallServiceFixtureX.getInCallAdapter(); inCallAdapter.conference(callId1.mCallId, callId2.mCallId); @@ -636,7 +637,7 @@ protected String startOutgoingPhoneCallWithNoPhoneAccount(String number, startOutgoingPhoneCallWaitForBroadcaster(number, null, connectionServiceFixture, Process.myUserHandle(), VideoProfile.STATE_AUDIO_ONLY, - false /*isEmergency*/); + false /*isEmergency*/, null); return mInCallServiceFixtureX.mLatestCallId; } @@ -666,17 +667,17 @@ protected IdPair startOutgoingPhoneCall(String number, PhoneAccountHandle phoneA throws Exception { return startOutgoingPhoneCall(number, phoneAccountHandle, connectionServiceFixture, - initiatingUser, VideoProfile.STATE_AUDIO_ONLY); + initiatingUser, VideoProfile.STATE_AUDIO_ONLY, null); } protected IdPair startOutgoingPhoneCall(String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser, - int videoState) throws Exception { + int videoState, Intent callIntentExtras) throws Exception { int startingNumConnections = connectionServiceFixture.mConnectionById.size(); int startingNumCalls = mInCallServiceFixtureX.mCallById.size(); startOutgoingPhoneCallPendingCreateConnection(number, phoneAccountHandle, - connectionServiceFixture, initiatingUser, videoState); + connectionServiceFixture, initiatingUser, videoState, callIntentExtras); verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT)) .createConnectionComplete(anyString(), any()); @@ -719,7 +720,7 @@ protected IdPair startOutgoingEmergencyCall(String number, // Call will not use the ordered broadcaster, since it is an Emergency Call startOutgoingPhoneCallWaitForBroadcaster(number, phoneAccountHandle, - connectionServiceFixture, initiatingUser, videoState, true /*isEmergency*/); + connectionServiceFixture, initiatingUser, videoState, true /*isEmergency*/, null); return outgoingCallCreateConnectionComplete(startingNumConnections, startingNumCalls, phoneAccountHandle, connectionServiceFixture); @@ -728,7 +729,7 @@ protected IdPair startOutgoingEmergencyCall(String number, protected void startOutgoingPhoneCallWaitForBroadcaster(String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser, - int videoState, boolean isEmergency) throws Exception { + int videoState, boolean isEmergency, Intent actionCallIntent) throws Exception { reset(connectionServiceFixture.getTestDouble(), mInCallServiceFixtureX.getTestDouble(), mInCallServiceFixtureY.getTestDouble()); @@ -741,7 +742,9 @@ protected void startOutgoingPhoneCallWaitForBroadcaster(String number, boolean hasInCallAdapter = mInCallServiceFixtureX.mInCallAdapter != null; - Intent actionCallIntent = new Intent(); + if (actionCallIntent == null) { + actionCallIntent = new Intent(); + } actionCallIntent.setData(Uri.parse("tel:" + number)); actionCallIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number); if(isEmergency) { @@ -786,9 +789,10 @@ protected void startOutgoingPhoneCallWaitForBroadcaster(String number, protected String startOutgoingPhoneCallPendingCreateConnection(String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser, - int videoState) throws Exception { + int videoState, Intent callIntentExtras) throws Exception { startOutgoingPhoneCallWaitForBroadcaster(number,phoneAccountHandle, - connectionServiceFixture, initiatingUser, videoState, false /*isEmergency*/); + connectionServiceFixture, initiatingUser, + videoState, false /*isEmergency*/, callIntentExtras); waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT); verifyAndProcessOutgoingCallBroadcast(phoneAccountHandle); @@ -893,14 +897,24 @@ protected IdPair startIncomingPhoneCall( PhoneAccountHandle phoneAccountHandle, final ConnectionServiceFixture connectionServiceFixture) throws Exception { return startIncomingPhoneCall(number, phoneAccountHandle, VideoProfile.STATE_AUDIO_ONLY, - connectionServiceFixture); + connectionServiceFixture, null); + } + + protected IdPair startIncomingPhoneCallWithExtras( + String number, + PhoneAccountHandle phoneAccountHandle, + final ConnectionServiceFixture connectionServiceFixture, + Bundle extras) throws Exception { + return startIncomingPhoneCall(number, phoneAccountHandle, VideoProfile.STATE_AUDIO_ONLY, + connectionServiceFixture, extras); } protected IdPair startIncomingPhoneCall( String number, PhoneAccountHandle phoneAccountHandle, int videoState, - final ConnectionServiceFixture connectionServiceFixture) throws Exception { + final ConnectionServiceFixture connectionServiceFixture, + Bundle extras) throws Exception { reset(connectionServiceFixture.getTestDouble(), mInCallServiceFixtureX.getTestDouble(), mInCallServiceFixtureY.getTestDouble()); @@ -917,7 +931,9 @@ protected IdPair startIncomingPhoneCall( new IncomingCallAddedListener(incomingCallAddedLatch); mTelecomSystem.getCallsManager().addListener(callAddedListener); - Bundle extras = new Bundle(); + if (extras == null) { + extras = new Bundle(); + } extras.putParcelable( TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null)); @@ -1003,7 +1019,16 @@ protected IdPair startAndMakeActiveOutgoingCall( PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture) throws Exception { return startAndMakeActiveOutgoingCall(number, phoneAccountHandle, connectionServiceFixture, - VideoProfile.STATE_AUDIO_ONLY); + VideoProfile.STATE_AUDIO_ONLY, null); + } + + protected IdPair startAndMakeActiveOutgoingCallWithExtras( + String number, + PhoneAccountHandle phoneAccountHandle, + ConnectionServiceFixture connectionServiceFixture, + Intent callIntentExtras) throws Exception { + return startAndMakeActiveOutgoingCall(number, phoneAccountHandle, connectionServiceFixture, + VideoProfile.STATE_AUDIO_ONLY, callIntentExtras); } // A simple outgoing call, verifying that the appropriate connection service is contacted, @@ -1011,9 +1036,10 @@ protected IdPair startAndMakeActiveOutgoingCall( protected IdPair startAndMakeActiveOutgoingCall( String number, PhoneAccountHandle phoneAccountHandle, - ConnectionServiceFixture connectionServiceFixture, int videoState) throws Exception { + ConnectionServiceFixture connectionServiceFixture, int videoState, + Intent callIntentExtras) throws Exception { IdPair ids = startOutgoingPhoneCall(number, phoneAccountHandle, connectionServiceFixture, - Process.myUserHandle(), videoState); + Process.myUserHandle(), videoState, callIntentExtras); connectionServiceFixture.sendSetDialing(ids.mConnectionId); if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) { diff --git a/tests/src/com/android/server/telecom/tests/VideoCallTests.java b/tests/src/com/android/server/telecom/tests/VideoCallTests.java index 97e71d18b..84beedc0f 100644 --- a/tests/src/com/android/server/telecom/tests/VideoCallTests.java +++ b/tests/src/com/android/server/telecom/tests/VideoCallTests.java @@ -105,7 +105,7 @@ public void testAutoSpeakerphoneOutgoingBidirectional() throws Exception { // Start an incoming video call. IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA, - VideoProfile.STATE_BIDIRECTIONAL); + VideoProfile.STATE_BIDIRECTIONAL, null); verifyAudioRoute(CallAudioState.ROUTE_SPEAKER); } @@ -121,7 +121,7 @@ public void testAutoSpeakerphoneOutgoingTransmitOnly() throws Exception { // Start an incoming video call. IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA, - VideoProfile.STATE_TX_ENABLED); + VideoProfile.STATE_TX_ENABLED, null); verifyAudioRoute(CallAudioState.ROUTE_SPEAKER); } @@ -137,7 +137,7 @@ public void testNoAutoSpeakerphoneOnOutgoing() throws Exception { // Start an incoming video call. IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA, - VideoProfile.STATE_AUDIO_ONLY); + VideoProfile.STATE_AUDIO_ONLY, null); verifyAudioRoute(CallAudioState.ROUTE_EARPIECE); } @@ -165,7 +165,7 @@ public void testNoAutoSpeakerphoneOnIncoming() throws Exception { @Test public void testIncomingVideoCallMissedCheckVideoHistory() throws Exception { IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), - VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA); + VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA, null); com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls() .iterator().next(); @@ -182,7 +182,7 @@ public void testIncomingVideoCallMissedCheckVideoHistory() throws Exception { @Test public void testIncomingVideoCallRejectedCheckVideoHistory() throws Exception { IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), - VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA); + VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA, null); com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls() .iterator().next(); @@ -201,7 +201,7 @@ public void testIncomingVideoCallRejectedCheckVideoHistory() throws Exception { public void testOutgoingVideoCallCanceledCheckVideoHistory() throws Exception { IdPair ids = startOutgoingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA, Process.myUserHandle(), - VideoProfile.STATE_BIDIRECTIONAL); + VideoProfile.STATE_BIDIRECTIONAL, null); com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls() .iterator().next(); @@ -219,7 +219,7 @@ public void testOutgoingVideoCallCanceledCheckVideoHistory() throws Exception { public void testOutgoingVideoCallRejectedCheckVideoHistory() throws Exception { IdPair ids = startOutgoingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA, Process.myUserHandle(), - VideoProfile.STATE_BIDIRECTIONAL); + VideoProfile.STATE_BIDIRECTIONAL, null); com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls() .iterator().next(); @@ -237,7 +237,7 @@ public void testOutgoingVideoCallRejectedCheckVideoHistory() throws Exception { public void testOutgoingVideoCallAnsweredAsAudio() throws Exception { IdPair ids = startOutgoingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA, Process.myUserHandle(), - VideoProfile.STATE_BIDIRECTIONAL); + VideoProfile.STATE_BIDIRECTIONAL, null); com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls() .iterator().next(); From 50f10d0b3a5149f33d5036b7dae9059260163235 Mon Sep 17 00:00:00 2001 From: Grace Jia Date: Thu, 20 Jul 2023 13:42:50 -0700 Subject: [PATCH 20/21] Fix vulnerability in CallRedirectionService. Currently when the CallRedirectionService binding died, we didn't do anything, which cause malicious app start activities even not run in the background by implementing a CallRedirectionService and overriding the onPlaceCall method to schedule a activity start job in an independent process and then kill itself. In that way, the activity can still start after the CallRedirectionService died. Fix this by unbinding the service when the binding died. Bug: b/289809991 Test: Using testapp provided in bug to make sure the test activity can't be started (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:29b52e3cd027da2d8644450a4dee3a7d95dc0043) Merged-In: I065d361b83700474a1efab2a75928427ee0a14ba Change-Id: I065d361b83700474a1efab2a75928427ee0a14ba --- .../callredirection/CallRedirectionProcessor.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java b/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java index da64b3769..879b26603 100644 --- a/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java +++ b/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java @@ -164,6 +164,20 @@ public void onNullBinding(ComponentName componentName) { Log.endSession(); } } + + @Override + public void onBindingDied(ComponentName componentName) { + // Make sure we unbind the service if binding died to avoid background stating + // activity leaks + Log.startSession("CRSC.oBD"); + try { + synchronized (mTelecomLock) { + finishCallRedirection(); + } + } finally { + Log.endSession(); + } + } } private class CallRedirectionAdapter extends ICallRedirectionAdapter.Stub { From a86f3b8cd1c63f2e89a6c55bead045cccb8eaace Mon Sep 17 00:00:00 2001 From: Pranav Madapurmath Date: Wed, 5 Apr 2023 21:36:12 +0000 Subject: [PATCH 21/21] Resolve account image icon profile boundary exploit. Because Telecom grants the INTERACT_ACROSS_USERS permission, an exploit is possible where the user can upload an image icon (belonging to another user) via registering a phone account. This CL provides a lightweight solution for parsing the image URI to detect profile exploitation. Fixes: 273502295 Fixes: 296915211 Test: Unit test to enforce successful/failure path (cherry picked from commit d0d1d38e37de54e58a7532a0020582fbd7d476b7) (cherry picked from commit e7d0ca3fe5be6e393f643f565792ea5e7ed05f48) (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:a604311f86ea8136ca2ac9f9ff0af7fa57ee3f42) Merged-In: I2b6418f019a373ee9f02ba8683e5b694e7ab80a5 Change-Id: I2b6418f019a373ee9f02ba8683e5b694e7ab80a5 --- .../server/telecom/TelecomServiceImpl.java | 22 +++++++++++++++++++ .../telecom/tests/TelecomServiceImplTest.java | 21 ++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java index 6d8a2f356..9b609af49 100644 --- a/src/com/android/server/telecom/TelecomServiceImpl.java +++ b/src/com/android/server/telecom/TelecomServiceImpl.java @@ -38,6 +38,7 @@ import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; +import android.graphics.drawable.Icon; import android.net.Uri; import android.os.Binder; import android.os.Build; @@ -539,6 +540,9 @@ public void registerPhoneAccount(PhoneAccount account) { .build(); } + // Validate the profile boundary of the given image URI. + validateAccountIconUserBoundary(account.getIcon()); + final long token = Binder.clearCallingIdentity(); try { mPhoneAccountRegistrar.registerPhoneAccount(account); @@ -2361,4 +2365,22 @@ private void broadcastCallScreeningAppChangedIntent(String componentName, mContext.sendBroadcast(intent); } } + + private void validateAccountIconUserBoundary(Icon icon) { + // Refer to Icon#getUriString for context. The URI string is invalid for icons of + // incompatible types. + if (icon != null && (icon.getType() == Icon.TYPE_URI + || icon.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP)) { + String encodedUser = icon.getUri().getEncodedUserInfo(); + // If there is no encoded user, the URI is calling into the calling user space + if (encodedUser != null) { + int userId = Integer.parseInt(encodedUser); + if (userId != UserHandle.getUserId(Binder.getCallingUid())) { + // If we are transcending the profile boundary, throw an error. + throw new IllegalArgumentException("Attempting to register a phone account with" + + " an image icon belonging to another user."); + } + } + } + } } diff --git a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java index c2d97e6ed..664b31efe 100644 --- a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java +++ b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java @@ -31,6 +31,7 @@ import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.graphics.drawable.Icon; import android.net.Uri; import android.os.Binder; import android.os.Build; @@ -591,6 +592,26 @@ private void registerPhoneAccountTestHelper(PhoneAccount testPhoneAccount, } } + @SmallTest + @Test + public void testRegisterPhoneAccountImageIconCrossUser() throws RemoteException { + String packageNameToUse = "com.android.officialpackage"; + PhoneAccountHandle phHandle = new PhoneAccountHandle(new ComponentName( + packageNameToUse, "cs"), "test", Binder.getCallingUserHandle()); + Icon icon = Icon.createWithContentUri("content://10@media/external/images/media/"); + PhoneAccount phoneAccount = makePhoneAccount(phHandle).setIcon(icon).build(); + doReturn(PackageManager.PERMISSION_GRANTED) + .when(mContext).checkCallingOrSelfPermission(MODIFY_PHONE_STATE); + + // This should fail; security exception will be thrown. + registerPhoneAccountTestHelper(phoneAccount, false); + + icon = Icon.createWithContentUri("content://0@media/external/images/media/"); + phoneAccount = makePhoneAccount(phHandle).setIcon(icon).build(); + // This should succeed. + registerPhoneAccountTestHelper(phoneAccount, true); + } + @SmallTest @Test public void testUnregisterPhoneAccount() throws RemoteException {