diff options
Diffstat (limited to 'services')
84 files changed, 1969 insertions, 885 deletions
diff --git a/services/accessibility/java/com/android/server/accessibility/GlobalActionPerformer.java b/services/accessibility/java/com/android/server/accessibility/GlobalActionPerformer.java index 672518cc17ed..b9b2654b93cc 100644 --- a/services/accessibility/java/com/android/server/accessibility/GlobalActionPerformer.java +++ b/services/accessibility/java/com/android/server/accessibility/GlobalActionPerformer.java @@ -24,10 +24,7 @@ import android.os.Binder; import android.os.Handler; import android.os.Looper; import android.os.PowerManager; -import android.os.RemoteException; -import android.os.ServiceManager; import android.os.SystemClock; -import android.view.IWindowManager; import android.view.InputDevice; import android.view.KeyCharacterMap; import android.view.KeyEvent; @@ -191,7 +188,7 @@ public class GlobalActionPerformer { ScreenshotHelper screenshotHelper = (mScreenshotHelperSupplier != null) ? mScreenshotHelperSupplier.get() : new ScreenshotHelper(mContext); screenshotHelper.takeScreenshot(android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN, - true, true, new Handler(Looper.getMainLooper())); + true, true, new Handler(Looper.getMainLooper()), null); return true; } } diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java index d7e68f896c6c..5844f9873001 100644 --- a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java +++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java @@ -23,6 +23,7 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.app.prediction.AppPredictionContext; import android.app.prediction.AppPredictionSessionId; import android.app.prediction.AppTargetEvent; @@ -61,7 +62,8 @@ public class AppPredictionManagerService extends public AppPredictionManagerService(Context context) { super(context, new FrameworkResourcesServiceNameResolver(context, - com.android.internal.R.string.config_defaultAppPredictionService), null); + com.android.internal.R.string.config_defaultAppPredictionService), null, + PACKAGE_UPDATE_POLICY_NO_REFRESH | PACKAGE_RESTART_POLICY_NO_REFRESH); mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class); } @@ -80,6 +82,22 @@ public class AppPredictionManagerService extends getContext().enforceCallingPermission(MANAGE_APP_PREDICTIONS, TAG); } + @Override // from AbstractMasterSystemService + protected void onServicePackageUpdatedLocked(@UserIdInt int userId) { + final AppPredictionPerUserService service = peekServiceForUserLocked(userId); + if (service != null) { + service.onPackageUpdatedLocked(); + } + } + + @Override // from AbstractMasterSystemService + protected void onServicePackageRestartedLocked(@UserIdInt int userId) { + final AppPredictionPerUserService service = peekServiceForUserLocked(userId); + if (service != null) { + service.onPackageRestartedLocked(); + } + } + @Override protected int getMaximumTemporaryServiceDurationMs() { return MAX_TEMP_SERVICE_DURATION_MS; diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java index 03c4542a50d4..4f49fb7578a1 100644 --- a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java +++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java @@ -251,6 +251,40 @@ public class AppPredictionPerUserService extends // Do nothing, eventually the system will bind to the remote service again... } + void onPackageUpdatedLocked() { + if (isDebug()) { + Slog.v(TAG, "onPackageUpdatedLocked()"); + } + destroyAndRebindRemoteService(); + } + + void onPackageRestartedLocked() { + if (isDebug()) { + Slog.v(TAG, "onPackageRestartedLocked()"); + } + destroyAndRebindRemoteService(); + } + + private void destroyAndRebindRemoteService() { + if (mRemoteService == null) { + return; + } + + if (isDebug()) { + Slog.d(TAG, "Destroying the old remote service."); + } + mRemoteService.destroy(); + mRemoteService = null; + + mRemoteService = getRemoteServiceLocked(); + if (mRemoteService != null) { + if (isDebug()) { + Slog.d(TAG, "Rebinding to the new remote service."); + } + mRemoteService.reconnect(); + } + } + /** * Called after the remote service connected, it's used to restore state from a 'zombie' * service (i.e., after it died). diff --git a/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java b/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java index c82e7a012fff..04e0e7f7102f 100644 --- a/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java +++ b/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java @@ -135,6 +135,13 @@ public class RemoteAppPredictionService extends } /** + * Schedules a request to bind to the remote service. + */ + public void reconnect() { + super.scheduleBind(); + } + + /** * Failure callback */ public interface RemoteAppPredictionServiceCallbacks diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index d260985190f7..87991beefcee 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -2407,7 +2407,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // Update the view states first... mCurrentViewId = viewState.id; - viewState.setCurrentValue(value); + if (value != null) { + viewState.setCurrentValue(value); + } if (mCompatMode && (viewState.getState() & ViewState.STATE_URL_BAR) != 0) { if (sDebug) Slog.d(TAG, "Ignoring VIEW_ENTERED on URL BAR (id=" + id + ")"); diff --git a/services/core/java/com/android/server/BluetoothService.java b/services/core/java/com/android/server/BluetoothService.java index 5c5b477352b1..6a6ddc84be49 100644 --- a/services/core/java/com/android/server/BluetoothService.java +++ b/services/core/java/com/android/server/BluetoothService.java @@ -54,8 +54,11 @@ class BluetoothService extends SystemService { @Override public void onSwitchUser(int userHandle) { - initialize(); - mBluetoothManagerService.handleOnSwitchUser(userHandle); + if (!mInitialized) { + initialize(); + } else { + mBluetoothManagerService.handleOnSwitchUser(userHandle); + } } @Override diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index 52a4218238e7..2ab46e65e77f 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -2737,7 +2737,9 @@ public class DeviceIdleController extends SystemService resetIdleManagementLocked(); // Wait a small amount of time in case something (eg: background service from // recently closed app) needs to finish running. - scheduleAlarmLocked(mConstants.QUICK_DOZE_DELAY_TIMEOUT, false); + // Use a non-wakeup alarm for going into quick doze in case an AlarmClock alarm + // is scheduled soon. The non-wakeup alarm will be delayed by at most 2 minutes. + scheduleAlarmLocked(mConstants.QUICK_DOZE_DELAY_TIMEOUT, false, false); EventLogTags.writeDeviceIdle(mState, "no activity"); } else if (mState == STATE_ACTIVE) { mState = STATE_INACTIVE; @@ -3362,6 +3364,10 @@ public class DeviceIdleController extends SystemService } void scheduleAlarmLocked(long delay, boolean idleUntil) { + scheduleAlarmLocked(delay, idleUntil, true); + } + + private void scheduleAlarmLocked(long delay, boolean idleUntil, boolean useWakeupAlarm) { if (DEBUG) Slog.d(TAG, "scheduleAlarmLocked(" + delay + ", " + idleUntil + ")"); if (mUseMotionSensor && mMotionSensor == null @@ -3377,12 +3383,14 @@ public class DeviceIdleController extends SystemService // can continue until the user interacts with the device. return; } + final int alarmType = useWakeupAlarm + ? AlarmManager.ELAPSED_REALTIME_WAKEUP : AlarmManager.ELAPSED_REALTIME; mNextAlarmTime = SystemClock.elapsedRealtime() + delay; if (idleUntil) { - mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP, + mAlarmManager.setIdleUntil(alarmType, mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler); } else { - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, + mAlarmManager.set(alarmType, mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler); } } diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags index 4d39f9ab8d78..bec08f45188f 100644 --- a/services/core/java/com/android/server/EventLogTags.logtags +++ b/services/core/java/com/android/server/EventLogTags.logtags @@ -39,6 +39,12 @@ option java_package com.android.server 27391 user_activity_timeout_override (override|2|3) 27392 battery_saver_setting (threshold|1) + +# --------------------------- +# ThermalManagerService.java +# --------------------------- +2737 thermal_changed (name|3),(type|1|5),(temperature|5),(sensor_status|1|5),(previous_system_status|1|5) + # # Leave IDs through 2740 for more power logs (2730 used by battery_discharge above) # diff --git a/services/core/java/com/android/server/MountServiceIdler.java b/services/core/java/com/android/server/MountServiceIdler.java index 1891ba9b1742..6bc1a570b7c0 100644 --- a/services/core/java/com/android/server/MountServiceIdler.java +++ b/services/core/java/com/android/server/MountServiceIdler.java @@ -27,6 +27,7 @@ import android.content.ComponentName; import android.content.Context; import android.os.RemoteException; import android.util.Slog; +import java.util.concurrent.TimeUnit; public class MountServiceIdler extends JobService { private static final String TAG = "MountServiceIdler"; @@ -48,7 +49,7 @@ public class MountServiceIdler extends JobService { mStarted = false; } } - // ... and try again tomorrow + // ... and try again right away or tomorrow scheduleIdlePass(MountServiceIdler.this); } }; @@ -98,24 +99,32 @@ public class MountServiceIdler extends JobService { public static void scheduleIdlePass(Context context) { JobScheduler tm = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); - Calendar calendar = tomorrowMidnight(); - final long timeToMidnight = calendar.getTimeInMillis() - System.currentTimeMillis(); + final long today3AM = offsetFromTodayMidnight(0, 3).getTimeInMillis(); + final long today4AM = offsetFromTodayMidnight(0, 4).getTimeInMillis(); + final long tomorrow3AM = offsetFromTodayMidnight(1, 3).getTimeInMillis(); + + long nextScheduleTime; + if (System.currentTimeMillis() > today3AM && System.currentTimeMillis() < today4AM) { + nextScheduleTime = TimeUnit.SECONDS.toMillis(10); + } else { + nextScheduleTime = tomorrow3AM - System.currentTimeMillis(); // 3AM tomorrow + } JobInfo.Builder builder = new JobInfo.Builder(MOUNT_JOB_ID, sIdleService); builder.setRequiresDeviceIdle(true); - builder.setRequiresCharging(true); - builder.setMinimumLatency(timeToMidnight); + builder.setRequiresBatteryNotLow(true); + builder.setMinimumLatency(nextScheduleTime); tm.schedule(builder.build()); } - private static Calendar tomorrowMidnight() { + private static Calendar offsetFromTodayMidnight(int nDays, int nHours) { Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); - calendar.set(Calendar.HOUR_OF_DAY, 3); + calendar.set(Calendar.HOUR_OF_DAY, nHours); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); - calendar.add(Calendar.DAY_OF_MONTH, 1); + calendar.add(Calendar.DAY_OF_MONTH, nDays); return calendar; } } diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java index 30a356325ada..6b038979a98d 100644 --- a/services/core/java/com/android/server/UiModeManagerService.java +++ b/services/core/java/com/android/server/UiModeManagerService.java @@ -48,7 +48,6 @@ import android.os.ShellCallback; import android.os.ShellCommand; import android.os.SystemProperties; import android.os.UserHandle; -import android.os.UserManager; import android.provider.Settings.Secure; import android.service.dreams.Sandman; import android.service.vr.IVrManager; @@ -218,6 +217,15 @@ final class UiModeManagerService extends SystemService { } }; + private final ContentObserver mDarkThemeObserver = new ContentObserver(mHandler) { + @Override + public void onChange(boolean selfChange, Uri uri) { + final int mode = Secure.getIntForUser(getContext().getContentResolver(), + Secure.UI_NIGHT_MODE, mNightMode, 0); + SystemProperties.set(SYSTEM_PROPERTY_DEVICE_THEME, Integer.toString(mode)); + } + }; + @Override public void onSwitchUser(int userHandle) { super.onSwitchUser(userHandle); @@ -293,6 +301,9 @@ final class UiModeManagerService extends SystemService { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_USER_SWITCHED); context.registerReceiver(new UserSwitchedReceiver(), filter, null, mHandler); + + context.getContentResolver().registerContentObserver(Secure.getUriFor(Secure.UI_NIGHT_MODE), + false, mDarkThemeObserver, 0); } // Records whether setup wizard has happened or not and adds an observer for this user if not. @@ -417,11 +428,6 @@ final class UiModeManagerService extends SystemService { if (!mCarModeEnabled) { Secure.putIntForUser(getContext().getContentResolver(), Secure.UI_NIGHT_MODE, mode, user); - - if (UserManager.get(getContext()).isPrimaryUser()) { - SystemProperties.set(SYSTEM_PROPERTY_DEVICE_THEME, - Integer.toString(mode)); - } } mNightMode = mode; diff --git a/services/core/java/com/android/server/accounts/AccountManagerServiceShellCommand.java b/services/core/java/com/android/server/accounts/AccountManagerServiceShellCommand.java index 9e5f7229d382..9bf0bd357f37 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerServiceShellCommand.java +++ b/services/core/java/com/android/server/accounts/AccountManagerServiceShellCommand.java @@ -17,6 +17,7 @@ package com.android.server.accounts; import android.annotation.NonNull; +import android.app.ActivityManager; import android.os.ShellCommand; import android.os.UserHandle; @@ -83,7 +84,7 @@ final class AccountManagerServiceShellCommand extends ShellCommand { return null; } } - return UserHandle.USER_SYSTEM; + return ActivityManager.getCurrentUser(); } @Override @@ -92,9 +93,11 @@ final class AccountManagerServiceShellCommand extends ShellCommand { pw.println("Account manager service commands:"); pw.println(" help"); pw.println(" Print this help text."); - pw.println(" set-bind-instant-service-allowed [--user <USER_ID>] true|false "); + pw.println(" set-bind-instant-service-allowed " + + "[--user <USER_ID> (current user if not specified)] true|false "); pw.println(" Set whether binding to services provided by instant apps is allowed."); - pw.println(" get-bind-instant-service-allowed [--user <USER_ID>]"); + pw.println(" get-bind-instant-service-allowed " + + "[--user <USER_ID> (current user if not specified)]"); pw.println(" Get whether binding to services provided by instant apps is allowed."); } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 5af1480af94b..5ffdf02ef11e 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -5276,6 +5276,9 @@ public class ActivityManagerService extends IActivityManager.Stub // Inform checkpointing systems of success try { + // This line is needed to CTS test for the correct exception handling + // See b/138952436#comment36 for context + Slog.i(TAG, "About to commit checkpoint"); IStorageManager storageManager = PackageHelper.getStorageManager(); storageManager.commitChanges(); } catch (Exception e) { @@ -9052,7 +9055,16 @@ public class ActivityManagerService extends IActivityManager.Stub Integer.toString(currentUserId), currentUserId); mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_FOREGROUND_START, Integer.toString(currentUserId), currentUserId); - mSystemServiceManager.startUser(currentUserId); + + // On Automotive, at this point the system user has already been started and unlocked, + // and some of the tasks we do here have already been done. So skip those in that case. + // TODO(b/132262830): this workdound shouldn't be necessary once we move the + // headless-user start logic to UserManager-land + final boolean bootingSystemUser = currentUserId == UserHandle.USER_SYSTEM; + + if (bootingSystemUser) { + mSystemServiceManager.startUser(currentUserId); + } synchronized (this) { // Only start up encryption-aware persistent apps; once user is @@ -9076,43 +9088,53 @@ public class ActivityManagerService extends IActivityManager.Stub throw e.rethrowAsRuntimeException(); } } - mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady"); + + if (bootingSystemUser) { + mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady"); + } mAtmInternal.showSystemReadyErrorDialogsIfNeeded(); - final int callingUid = Binder.getCallingUid(); - final int callingPid = Binder.getCallingPid(); - long ident = Binder.clearCallingIdentity(); - try { - Intent intent = new Intent(Intent.ACTION_USER_STARTED); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY - | Intent.FLAG_RECEIVER_FOREGROUND); - intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId); - broadcastIntentLocked(null, null, intent, - null, null, 0, null, null, null, OP_NONE, - null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid, - currentUserId); - intent = new Intent(Intent.ACTION_USER_STARTING); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId); - broadcastIntentLocked(null, null, intent, - null, new IIntentReceiver.Stub() { - @Override - public void performReceive(Intent intent, int resultCode, String data, - Bundle extras, boolean ordered, boolean sticky, int sendingUser) - throws RemoteException { - } - }, 0, null, null, - new String[] {INTERACT_ACROSS_USERS}, OP_NONE, - null, true, false, MY_PID, SYSTEM_UID, callingUid, callingPid, - UserHandle.USER_ALL); - } catch (Throwable t) { - Slog.wtf(TAG, "Failed sending first user broadcasts", t); - } finally { - Binder.restoreCallingIdentity(ident); + if (bootingSystemUser) { + final int callingUid = Binder.getCallingUid(); + final int callingPid = Binder.getCallingPid(); + long ident = Binder.clearCallingIdentity(); + try { + Intent intent = new Intent(Intent.ACTION_USER_STARTED); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY + | Intent.FLAG_RECEIVER_FOREGROUND); + intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId); + broadcastIntentLocked(null, null, intent, + null, null, 0, null, null, null, OP_NONE, + null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid, + currentUserId); + intent = new Intent(Intent.ACTION_USER_STARTING); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId); + broadcastIntentLocked(null, null, intent, + null, new IIntentReceiver.Stub() { + @Override + public void performReceive(Intent intent, int resultCode, String data, + Bundle extras, boolean ordered, boolean sticky, int sendingUser) + throws RemoteException { + } + }, 0, null, null, + new String[] {INTERACT_ACROSS_USERS}, OP_NONE, + null, true, false, MY_PID, SYSTEM_UID, callingUid, callingPid, + UserHandle.USER_ALL); + } catch (Throwable t) { + Slog.wtf(TAG, "Failed sending first user broadcasts", t); + } finally { + Binder.restoreCallingIdentity(ident); + } + } else { + Slog.i(TAG, "Not sending multi-user broadcasts for non-system user " + + currentUserId); } mAtmInternal.resumeTopActivities(false /* scheduleIdle */); - mUserController.sendUserSwitchBroadcasts(-1, currentUserId); + if (bootingSystemUser) { + mUserController.sendUserSwitchBroadcasts(-1, currentUserId); + } BinderInternal.nSetBinderProxyCountWatermarks(BINDER_PROXY_HIGH_WATERMARK, BINDER_PROXY_LOW_WATERMARK); @@ -15004,7 +15026,12 @@ public class ActivityManagerService extends IActivityManager.Stub final int uid = getUidFromIntent(intent); if (uid >= 0) { mBatteryStatsService.removeUid(uid); - mAppOpsService.uidRemoved(uid); + if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { + mAppOpsService.resetAllModes(UserHandle.getUserId(uid), + intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME)); + } else { + mAppOpsService.uidRemoved(uid); + } } break; case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE: diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index 567404697395..8c60d0c759dc 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -722,10 +722,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub } } - public void notePhoneDataConnectionState(int dataType, boolean hasData) { + public void notePhoneDataConnectionState(int dataType, boolean hasData, int serviceType) { enforceCallingPermission(); synchronized (mStats) { - mStats.notePhoneDataConnectionStateLocked(dataType, hasData); + mStats.notePhoneDataConnectionStateLocked(dataType, hasData, serviceType); } } @@ -756,7 +756,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub } public void noteStartAudio(int uid) { - enforceSelfOrCallingPermission(uid); + enforceCallingPermission(); synchronized (mStats) { mStats.noteAudioOnLocked(uid); StatsLog.write_non_chained(StatsLog.AUDIO_STATE_CHANGED, uid, null, @@ -765,7 +765,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub } public void noteStopAudio(int uid) { - enforceSelfOrCallingPermission(uid); + enforceCallingPermission(); synchronized (mStats) { mStats.noteAudioOffLocked(uid); StatsLog.write_non_chained(StatsLog.AUDIO_STATE_CHANGED, uid, null, @@ -774,7 +774,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub } public void noteStartVideo(int uid) { - enforceSelfOrCallingPermission(uid); + enforceCallingPermission(); synchronized (mStats) { mStats.noteVideoOnLocked(uid); StatsLog.write_non_chained(StatsLog.MEDIA_CODEC_STATE_CHANGED, uid, null, @@ -783,7 +783,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub } public void noteStopVideo(int uid) { - enforceSelfOrCallingPermission(uid); + enforceCallingPermission(); synchronized (mStats) { mStats.noteVideoOffLocked(uid); StatsLog.write_non_chained(StatsLog.MEDIA_CODEC_STATE_CHANGED, uid, @@ -1184,13 +1184,6 @@ public final class BatteryStatsService extends IBatteryStats.Stub Binder.getCallingPid(), Binder.getCallingUid(), null); } - private void enforceSelfOrCallingPermission(int uid) { - if (Binder.getCallingUid() == uid) { - return; - } - enforceCallingPermission(); - } - final class WakeupReasonThread extends Thread { private static final int MAX_REASON_SIZE = 512; private CharsetDecoder mDecoder; diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 4692fd4eeb2e..a2670d8dd424 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -2098,10 +2098,10 @@ public final class ProcessList { } } } - if (lrui <= mLruProcessActivityStart) { + if (lrui < mLruProcessActivityStart) { mLruProcessActivityStart--; } - if (lrui <= mLruProcessServiceStart) { + if (lrui < mLruProcessServiceStart) { mLruProcessServiceStart--; } mLruProcesses.remove(lrui); @@ -2633,7 +2633,7 @@ public final class ProcessList { if (!moved) { // Goes to the end of the group. mLruProcesses.remove(i); - mLruProcesses.add(endIndex - 1, subProc); + mLruProcesses.add(endIndex, subProc); if (DEBUG_LRU) Slog.d(TAG_LRU, "Moving " + subProc + " from position " + i + " to end of group @ " @@ -2878,15 +2878,6 @@ public final class ProcessList { pos--; } mLruProcesses.add(pos, app); - if (pos == mLruProcessActivityStart) { - mLruProcessActivityStart++; - } - if (pos == mLruProcessServiceStart) { - // Unless {@code #hasService} is implemented, currently the starting position - // for activity and service are the same, so the incoming position may equal to - // the starting position of service. - mLruProcessServiceStart++; - } // If this process is part of a group, need to pull up any other processes // in that group to be with it. int endIndex = pos - 1; diff --git a/services/core/java/com/android/server/am/TEST_MAPPING b/services/core/java/com/android/server/am/TEST_MAPPING index e9151d499706..21d4925722d0 100644 --- a/services/core/java/com/android/server/am/TEST_MAPPING +++ b/services/core/java/com/android/server/am/TEST_MAPPING @@ -14,9 +14,6 @@ }, { "exclude-annotation": "androidx.test.filters.FlakyTest" - }, - { - "exclude-filter": "android.app.cts.SystemFeaturesTest#testLocationFeatures" } ] }, diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index a35d2ee38641..314e04c8da32 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -18,9 +18,11 @@ package com.android.server.appop; import static android.app.AppOpsManager.MAX_PRIORITY_UID_STATE; import static android.app.AppOpsManager.MIN_PRIORITY_UID_STATE; +import static android.app.AppOpsManager.OP_CAMERA; import static android.app.AppOpsManager.OP_FLAGS_ALL; import static android.app.AppOpsManager.OP_NONE; import static android.app.AppOpsManager.OP_PLAY_AUDIO; +import static android.app.AppOpsManager.OP_RECORD_AUDIO; import static android.app.AppOpsManager.UID_STATE_BACKGROUND; import static android.app.AppOpsManager.UID_STATE_CACHED; import static android.app.AppOpsManager.UID_STATE_FOREGROUND; @@ -173,6 +175,12 @@ public class AppOpsService extends IAppOpsService.Stub { UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_NONEXISTENT }; + private static final int[] OPS_RESTRICTED_ON_SUSPEND = { + OP_PLAY_AUDIO, + OP_RECORD_AUDIO, + OP_CAMERA, + }; + Context mContext; final AtomicFile mFile; final Handler mHandler; @@ -510,6 +518,10 @@ public class AppOpsService extends IAppOpsService.Stub { private void updateProxyState(long key, int proxyUid, @Nullable String proxyPackageName) { + if (proxyUid == Process.INVALID_UID) { + return; + } + if (mProxyUids == null) { mProxyUids = new LongSparseLongArray(); } @@ -789,20 +801,22 @@ public class AppOpsService extends IAppOpsService.Stub { final int[] changedUids = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); final String[] changedPkgs = intent.getStringArrayExtra( Intent.EXTRA_CHANGED_PACKAGE_LIST); - ArraySet<ModeCallback> callbacks; - synchronized (AppOpsService.this) { - callbacks = mOpModeWatchers.get(OP_PLAY_AUDIO); - if (callbacks == null) { - return; + for (int code : OPS_RESTRICTED_ON_SUSPEND) { + ArraySet<ModeCallback> callbacks; + synchronized (AppOpsService.this) { + callbacks = mOpModeWatchers.get(code); + if (callbacks == null) { + continue; + } + callbacks = new ArraySet<>(callbacks); + } + for (int i = 0; i < changedUids.length; i++) { + final int changedUid = changedUids[i]; + final String changedPkg = changedPkgs[i]; + // We trust packagemanager to insert matching uid and packageNames in the + // extras + notifyOpChanged(callbacks, code, changedUid, changedPkg); } - callbacks = new ArraySet<>(callbacks); - } - for (int i = 0; i < changedUids.length; i++) { - final int changedUid = changedUids[i]; - final String changedPkg = changedPkgs[i]; - // We trust packagemanager to insert matching uid and packageNames in the - // extras - notifyOpChanged(callbacks, OP_PLAY_AUDIO, changedUid, changedPkg); } } }, packageSuspendFilter); @@ -1805,6 +1819,9 @@ public class AppOpsService extends IAppOpsService.Stub { */ private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName, boolean raw, boolean verify) { + if (isOpRestrictedDueToSuspend(code, packageName, uid)) { + return AppOpsManager.MODE_IGNORED; + } synchronized (this) { if (verify) { checkPackage(uid, packageName); @@ -2659,6 +2676,14 @@ public class AppOpsService extends IAppOpsService.Stub { return op; } + private boolean isOpRestrictedDueToSuspend(int code, String packageName, int uid) { + if (!ArrayUtils.contains(OPS_RESTRICTED_ON_SUSPEND, code)) { + return false; + } + final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class); + return pmi.isPackageSuspended(packageName, UserHandle.getUserId(uid)); + } + private boolean isOpRestrictedLocked(int uid, int code, String packageName) { int userHandle = UserHandle.getUserId(uid); final int restrictionSetCount = mOpUserRestrictions.size(); @@ -2984,17 +3009,40 @@ public class AppOpsService extends IAppOpsService.Stub { out.startTag(null, "app-ops"); out.attribute(null, "v", String.valueOf(CURRENT_VERSION)); - final int uidStateCount = mUidStates.size(); - for (int i = 0; i < uidStateCount; i++) { - UidState uidState = mUidStates.valueAt(i); - if (uidState.opModes != null && uidState.opModes.size() > 0) { + SparseArray<SparseIntArray> uidStatesClone; + synchronized (this) { + uidStatesClone = new SparseArray<>(mUidStates.size()); + + final int uidStateCount = mUidStates.size(); + for (int uidStateNum = 0; uidStateNum < uidStateCount; uidStateNum++) { + UidState uidState = mUidStates.valueAt(uidStateNum); + int uid = mUidStates.keyAt(uidStateNum); + + SparseIntArray opModes = uidState.opModes; + if (opModes != null && opModes.size() > 0) { + uidStatesClone.put(uid, new SparseIntArray(opModes.size())); + + final int opCount = opModes.size(); + for (int opCountNum = 0; opCountNum < opCount; opCountNum++) { + uidStatesClone.get(uid).put( + opModes.keyAt(opCountNum), + opModes.valueAt(opCountNum)); + } + } + } + } + + final int uidStateCount = uidStatesClone.size(); + for (int uidStateNum = 0; uidStateNum < uidStateCount; uidStateNum++) { + SparseIntArray opModes = uidStatesClone.valueAt(uidStateNum); + if (opModes != null && opModes.size() > 0) { out.startTag(null, "uid"); - out.attribute(null, "n", Integer.toString(uidState.uid)); - SparseIntArray uidOpModes = uidState.opModes; - final int opCount = uidOpModes.size(); - for (int j = 0; j < opCount; j++) { - final int op = uidOpModes.keyAt(j); - final int mode = uidOpModes.valueAt(j); + out.attribute(null, "n", + Integer.toString(uidStatesClone.keyAt(uidStateNum))); + final int opCount = opModes.size(); + for (int opCountNum = 0; opCountNum < opCount; opCountNum++) { + final int op = opModes.keyAt(opCountNum); + final int mode = opModes.valueAt(opCountNum); out.startTag(null, "op"); out.attribute(null, "n", Integer.toString(op)); out.attribute(null, "m", Integer.toString(mode)); diff --git a/services/core/java/com/android/server/audio/TEST_MAPPING b/services/core/java/com/android/server/audio/TEST_MAPPING index bf09eac1b422..0d34c5372914 100644 --- a/services/core/java/com/android/server/audio/TEST_MAPPING +++ b/services/core/java/com/android/server/audio/TEST_MAPPING @@ -8,9 +8,6 @@ }, { "include-filter": "android.media.cts.AudioFocusTest" - }, - { - "exclude-annotation": "androidx.test.filters.FlakyTest" } ] } diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java index ee49f5885e4a..387d7a85f4a8 100644 --- a/services/core/java/com/android/server/biometrics/face/FaceService.java +++ b/services/core/java/com/android/server/biometrics/face/FaceService.java @@ -53,6 +53,7 @@ import android.os.SELinux; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; +import android.provider.Settings; import android.util.Slog; import com.android.internal.R; @@ -926,7 +927,8 @@ public class FaceService extends BiometricServiceBase { final Face face = new Face("", 0 /* identifier */, deviceId); FaceService.super.handleRemoved(face, 0 /* remaining */); } - + Settings.Secure.putIntForUser(getContext().getContentResolver(), + Settings.Secure.FACE_UNLOCK_RE_ENROLL, 0, UserHandle.USER_CURRENT); }); } diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java index acb0207ff11f..85ca627e3b02 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java @@ -35,6 +35,8 @@ import android.hardware.broadcastradio.V2_0.Result; import android.hardware.broadcastradio.V2_0.VendorKeyValue; import android.hardware.radio.RadioManager; import android.os.DeadObjectException; +import android.os.Handler; +import android.os.Looper; import android.os.RemoteException; import android.util.MutableInt; import android.util.Slog; @@ -44,6 +46,7 @@ import com.android.internal.annotations.GuardedBy; import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @@ -55,6 +58,7 @@ class RadioModule { @NonNull public final RadioManager.ModuleProperties mProperties; private final Object mLock = new Object(); + @NonNull private final Handler mHandler; @GuardedBy("mLock") private ITunerSession mHalTunerSession; @@ -70,38 +74,46 @@ class RadioModule { private final ITunerCallback mHalTunerCallback = new ITunerCallback.Stub() { @Override public void onTuneFailed(int result, ProgramSelector programSelector) { - fanoutAidlCallback(cb -> cb.onTuneFailed(result, Convert.programSelectorFromHal( - programSelector))); + lockAndFireLater(() -> { + android.hardware.radio.ProgramSelector csel = + Convert.programSelectorFromHal(programSelector); + fanoutAidlCallbackLocked(cb -> cb.onTuneFailed(result, csel)); + }); } @Override public void onCurrentProgramInfoChanged(ProgramInfo halProgramInfo) { - RadioManager.ProgramInfo programInfo = Convert.programInfoFromHal(halProgramInfo); - synchronized (mLock) { - mProgramInfo = programInfo; - fanoutAidlCallbackLocked(cb -> cb.onCurrentProgramInfoChanged(programInfo)); - } + lockAndFireLater(() -> { + mProgramInfo = Convert.programInfoFromHal(halProgramInfo); + fanoutAidlCallbackLocked(cb -> cb.onCurrentProgramInfoChanged(mProgramInfo)); + }); } @Override public void onProgramListUpdated(ProgramListChunk programListChunk) { // TODO: Cache per-AIDL client filters, send union of filters to HAL, use filters to fan // back out to clients. - fanoutAidlCallback(cb -> cb.onProgramListUpdated(Convert.programListChunkFromHal( - programListChunk))); + lockAndFireLater(() -> { + android.hardware.radio.ProgramList.Chunk chunk = + Convert.programListChunkFromHal(programListChunk); + fanoutAidlCallbackLocked(cb -> cb.onProgramListUpdated(chunk)); + }); } @Override public void onAntennaStateChange(boolean connected) { - synchronized (mLock) { + lockAndFireLater(() -> { mAntennaConnected = connected; fanoutAidlCallbackLocked(cb -> cb.onAntennaState(connected)); - } + }); } @Override public void onParametersUpdated(ArrayList<VendorKeyValue> parameters) { - fanoutAidlCallback(cb -> cb.onParametersUpdated(Convert.vendorInfoFromHal(parameters))); + lockAndFireLater(() -> { + Map<String, String> cparam = Convert.vendorInfoFromHal(parameters); + fanoutAidlCallbackLocked(cb -> cb.onParametersUpdated(cparam)); + }); } }; @@ -113,6 +125,7 @@ class RadioModule { @NonNull RadioManager.ModuleProperties properties) throws RemoteException { mProperties = Objects.requireNonNull(properties); mService = Objects.requireNonNull(service); + mHandler = new Handler(Looper.getMainLooper()); } public static @Nullable RadioModule tryLoadingModule(int idx, @NonNull String fqName) { @@ -201,15 +214,22 @@ class RadioModule { } } + // add to mHandler queue, but ensure the runnable holds mLock when it gets executed + private void lockAndFireLater(Runnable r) { + mHandler.post(() -> { + synchronized (mLock) { + r.run(); + } + }); + } + interface AidlCallbackRunnable { void run(android.hardware.radio.ITunerCallback callback) throws RemoteException; } // Invokes runnable with each TunerSession currently open. void fanoutAidlCallback(AidlCallbackRunnable runnable) { - synchronized (mLock) { - fanoutAidlCallbackLocked(runnable); - } + lockAndFireLater(() -> fanoutAidlCallbackLocked(runnable)); } private void fanoutAidlCallbackLocked(AidlCallbackRunnable runnable) { diff --git a/services/core/java/com/android/server/connectivity/DataConnectionStats.java b/services/core/java/com/android/server/connectivity/DataConnectionStats.java index e6a4428ef219..27f11ffa60ce 100644 --- a/services/core/java/com/android/server/connectivity/DataConnectionStats.java +++ b/services/core/java/com/android/server/connectivity/DataConnectionStats.java @@ -97,7 +97,8 @@ public class DataConnectionStats extends BroadcastReceiver { if (DEBUG) Log.d(TAG, String.format("Noting data connection for network type %s: %svisible", networkType, visible ? "" : "not ")); try { - mBatteryStats.notePhoneDataConnectionState(networkType, visible); + mBatteryStats.notePhoneDataConnectionState(networkType, visible, + mServiceState.getState()); } catch (RemoteException e) { Log.w(TAG, "Error noting data connection state", e); } diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java index f61306405daa..c46fc20b3cc8 100644 --- a/services/core/java/com/android/server/display/ColorFade.java +++ b/services/core/java/com/android/server/display/ColorFade.java @@ -649,13 +649,8 @@ final class ColorFade { if (mSurfaceControl != null) { mSurfaceLayout.dispose(); mSurfaceLayout = null; - SurfaceControl.openTransaction(); - try { - mSurfaceControl.remove(); - mSurface.release(); - } finally { - SurfaceControl.closeTransaction(); - } + new Transaction().remove(mSurfaceControl).apply(); + mSurface.release(); mSurfaceControl = null; mSurfaceVisible = false; mSurfaceAlpha = 0f; diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java index 97fd02f53513..1fc0db3ff7cb 100644 --- a/services/core/java/com/android/server/display/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/DisplayModeDirector.java @@ -69,6 +69,7 @@ public class DisplayModeDirector { private static final int MSG_ALLOWED_MODES_CHANGED = 1; private static final int MSG_BRIGHTNESS_THRESHOLDS_CHANGED = 2; private static final int MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED = 3; + private static final int MSG_REFRESH_RATE_IN_ZONE_CHANGED = 4; // Special ID used to indicate that given vote is to be applied globally, rather than to a // specific display. @@ -440,23 +441,48 @@ public class DisplayModeDirector { mSettingsObserver.onDeviceConfigDefaultPeakRefreshRateChanged( defaultPeakRefreshRate); break; + + case MSG_REFRESH_RATE_IN_ZONE_CHANGED: + int refreshRateInZone = msg.arg1; + mBrightnessObserver.onDeviceConfigRefreshRateInZoneChanged( + refreshRateInZone); + break; } } } private static final class Vote { - // We split the app request into two priorities in case we can satisfy one desire without - // the other. - public static final int PRIORITY_APP_REQUEST_REFRESH_RATE = 0; - public static final int PRIORITY_APP_REQUEST_SIZE = 1; - public static final int PRIORITY_USER_SETTING_REFRESH_RATE = 2; - public static final int PRIORITY_LOW_BRIGHTNESS = 3; - public static final int PRIORITY_LOW_POWER_MODE = 4; + // LOW_BRIGHTNESS votes for a single refresh rate like [60,60], [90,90] or null. + // If the higher voters result is a range, it will fix the rate to a single choice. + // It's used to avoid rate switch in certain conditions. + public static final int PRIORITY_LOW_BRIGHTNESS = 0; + + // SETTING_MIN_REFRESH_RATE is used to propose a lower bound of display refresh rate. + // It votes [MIN_REFRESH_RATE, Float.POSITIVE_INFINITY] + public static final int PRIORITY_USER_SETTING_MIN_REFRESH_RATE = 1; + + // We split the app request into different priorities in case we can satisfy one desire + // without the other. + + // Application can specify preferred refresh rate with below attrs. + // @see android.view.WindowManager.LayoutParams#preferredRefreshRate + // @see android.view.WindowManager.LayoutParams#preferredDisplayModeId + // System also forces some apps like blacklisted app to run at a lower refresh rate. + // @see android.R.array#config_highRefreshRateBlacklist + public static final int PRIORITY_APP_REQUEST_REFRESH_RATE = 2; + public static final int PRIORITY_APP_REQUEST_SIZE = 3; + + // SETTING_PEAK_REFRESH_RATE has a high priority and will restrict the bounds of the rest + // of low priority voters. It votes [0, max(PEAK, MIN)] + public static final int PRIORITY_USER_SETTING_PEAK_REFRESH_RATE = 4; + + // LOW_POWER_MODE force display to [0, 60HZ] if Settings.Global.LOW_POWER_MODE is on. + public static final int PRIORITY_LOW_POWER_MODE = 5; // Whenever a new priority is added, remember to update MIN_PRIORITY and/or MAX_PRIORITY as // appropriate, as well as priorityToString. - public static final int MIN_PRIORITY = PRIORITY_APP_REQUEST_REFRESH_RATE; + public static final int MIN_PRIORITY = PRIORITY_LOW_BRIGHTNESS; public static final int MAX_PRIORITY = PRIORITY_LOW_POWER_MODE; /** @@ -500,12 +526,16 @@ public class DisplayModeDirector { public static String priorityToString(int priority) { switch (priority) { + case PRIORITY_LOW_BRIGHTNESS: + return "PRIORITY_LOW_BRIGHTNESS"; + case PRIORITY_USER_SETTING_MIN_REFRESH_RATE: + return "PRIORITY_USER_SETTING_MIN_REFRESH_RATE"; case PRIORITY_APP_REQUEST_REFRESH_RATE: return "PRIORITY_APP_REQUEST_REFRESH_RATE"; case PRIORITY_APP_REQUEST_SIZE: return "PRIORITY_APP_REQUEST_SIZE"; - case PRIORITY_USER_SETTING_REFRESH_RATE: - return "PRIORITY_USER_SETTING_REFRESH_RATE"; + case PRIORITY_USER_SETTING_PEAK_REFRESH_RATE: + return "PRIORITY_USER_SETTING_PEAK_REFRESH_RATE"; case PRIORITY_LOW_POWER_MODE: return "PRIORITY_LOW_POWER_MODE"; default: @@ -608,12 +638,11 @@ public class DisplayModeDirector { float peakRefreshRate = Settings.System.getFloat(mContext.getContentResolver(), Settings.System.PEAK_REFRESH_RATE, mDefaultPeakRefreshRate); - if (peakRefreshRate < minRefreshRate) { - peakRefreshRate = minRefreshRate; - } + updateVoteLocked(Vote.PRIORITY_USER_SETTING_PEAK_REFRESH_RATE, + Vote.forRefreshRates(0f, Math.max(minRefreshRate, peakRefreshRate))); + updateVoteLocked(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE, + Vote.forRefreshRates(minRefreshRate, Float.POSITIVE_INFINITY)); - Vote vote = Vote.forRefreshRates(minRefreshRate, peakRefreshRate); - updateVoteLocked(Vote.PRIORITY_USER_SETTING_REFRESH_RATE, vote); mBrightnessObserver.onRefreshRateSettingChangedLocked(minRefreshRate, peakRefreshRate); } @@ -655,6 +684,7 @@ public class DisplayModeDirector { refreshRateVote = null; sizeVote = null; } + updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, refreshRateVote); updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_SIZE, sizeVote); return; @@ -736,6 +766,7 @@ public class DisplayModeDirector { @Override public void onDisplayChanged(int displayId) { updateDisplayModes(displayId); + mBrightnessObserver.onDisplayChanged(displayId); } private void updateDisplayModes(int displayId) { @@ -790,7 +821,6 @@ public class DisplayModeDirector { private AmbientFilter mAmbientFilter; private final Context mContext; - private final ScreenStateReceiver mScreenStateReceiver; // Enable light sensor only when mShouldObserveAmbientChange is true, screen is on, peak // refresh rate changeable and low power mode off. After initialization, these states will @@ -799,10 +829,11 @@ public class DisplayModeDirector { private boolean mRefreshRateChangeable = false; private boolean mLowPowerModeEnabled = false; + private int mRefreshRateInZone; + BrightnessObserver(Context context, Handler handler) { super(handler); mContext = context; - mScreenStateReceiver = new ScreenStateReceiver(mContext); mDisplayBrightnessThresholds = context.getResources().getIntArray( R.array.config_brightnessThresholdsOfPeakRefreshRate); mAmbientBrightnessThresholds = context.getResources().getIntArray( @@ -816,6 +847,7 @@ public class DisplayModeDirector { public void observe(SensorManager sensorManager) { mSensorManager = sensorManager; + // DeviceConfig is accessible after system ready. int[] brightnessThresholds = mDeviceConfigDisplaySettings.getBrightnessThresholds(); int[] ambientThresholds = mDeviceConfigDisplaySettings.getAmbientThresholds(); @@ -825,6 +857,8 @@ public class DisplayModeDirector { mDisplayBrightnessThresholds = brightnessThresholds; mAmbientBrightnessThresholds = ambientThresholds; } + + mRefreshRateInZone = mDeviceConfigDisplaySettings.getRefreshRateInZone(); restartObserver(); mDeviceConfigDisplaySettings.startListening(); } @@ -864,8 +898,16 @@ public class DisplayModeDirector { restartObserver(); } + public void onDeviceConfigRefreshRateInZoneChanged(int refreshRate) { + if (refreshRate != mRefreshRateInZone) { + mRefreshRateInZone = refreshRate; + restartObserver(); + } + } + public void dumpLocked(PrintWriter pw) { pw.println(" BrightnessObserver"); + pw.println(" mRefreshRateInZone: " + mRefreshRateInZone); for (int d: mDisplayBrightnessThresholds) { pw.println(" mDisplayBrightnessThreshold: " + d); @@ -876,12 +918,16 @@ public class DisplayModeDirector { } } + public void onDisplayChanged(int displayId) { + if (displayId == Display.DEFAULT_DISPLAY) { + onScreenOn(isDefaultDisplayOn()); + } + } + @Override public void onChange(boolean selfChange, Uri uri, int userId) { synchronized (mLock) { - if (mRefreshRateChangeable) { - onBrightnessChangedLocked(); - } + onBrightnessChangedLocked(); } } @@ -927,16 +973,11 @@ public class DisplayModeDirector { mAmbientFilter = DisplayWhiteBalanceFactory.createBrightnessFilter(res); mLightSensor = lightSensor; - // Intent.ACTION_SCREEN_ON is not sticky. Check current screen status. - if (mContext.getSystemService(PowerManager.class).isInteractive()) { - onScreenOn(true); - } - mScreenStateReceiver.register(); + onScreenOn(isDefaultDisplayOn()); } } else { mAmbientFilter = null; mLightSensor = null; - mScreenStateReceiver.unregister(); } if (mRefreshRateChangeable) { @@ -952,6 +993,10 @@ public class DisplayModeDirector { * to value changes. */ private boolean checkShouldObserve(int[] a) { + if (mRefreshRateInZone <= 0) { + return false; + } + for (int d: a) { if (d >= 0) { return true; @@ -961,44 +1006,47 @@ public class DisplayModeDirector { return false; } - private void onBrightnessChangedLocked() { - int brightness = Settings.System.getInt(mContext.getContentResolver(), - Settings.System.SCREEN_BRIGHTNESS, -1); - - Vote vote = null; + private boolean isInsideZone(int brightness, float lux) { for (int i = 0; i < mDisplayBrightnessThresholds.length; i++) { int disp = mDisplayBrightnessThresholds[i]; int ambi = mAmbientBrightnessThresholds[i]; if (disp >= 0 && ambi >= 0) { if (brightness <= disp && mAmbientLux <= ambi) { - vote = Vote.forRefreshRates(0f, 60f); + return true; } } else if (disp >= 0) { if (brightness <= disp) { - vote = Vote.forRefreshRates(0f, 60f); + return true; } } else if (ambi >= 0) { if (mAmbientLux <= ambi) { - vote = Vote.forRefreshRates(0f, 60f); + return true; } } + } - if (vote != null) { - break; - } + return false; + } + + private void onBrightnessChangedLocked() { + int brightness = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS, -1); + + Vote vote = null; + boolean insideZone = isInsideZone(brightness, mAmbientLux); + if (insideZone) { + vote = Vote.forRefreshRates(mRefreshRateInZone, mRefreshRateInZone); } if (DEBUG) { Slog.d(TAG, "Display brightness " + brightness + ", ambient lux " + mAmbientLux + - (vote != null ? " 60hz only" : " no refresh rate limit")); + ", Vote " + vote); } updateVoteLocked(Vote.PRIORITY_LOW_BRIGHTNESS, vote); } private void onScreenOn(boolean on) { - // Not check mShouldObserveAmbientChange because Screen status receiver is registered - // only when it is true. if (mScreenOn != on) { mScreenOn = on; updateSensorStatus(); @@ -1020,6 +1068,13 @@ public class DisplayModeDirector { } } + private boolean isDefaultDisplayOn() { + final Display display = mContext.getSystemService(DisplayManager.class) + .getDisplay(Display.DEFAULT_DISPLAY); + return display.getState() != Display.STATE_OFF + && mContext.getSystemService(PowerManager.class).isInteractive(); + } + private final class LightSensorEventListener implements SensorEventListener { final private static int INJECT_EVENTS_INTERVAL_MS = LIGHT_SENSOR_RATE_MS; private float mLastSensorData; @@ -1097,43 +1152,10 @@ public class DisplayModeDirector { } } }; - }; - - private final class ScreenStateReceiver extends BroadcastReceiver { - final Context mContext; - boolean mRegistered; - - public ScreenStateReceiver(Context context) { - mContext = context; - } - - @Override - public void onReceive(Context context, Intent intent) { - onScreenOn(Intent.ACTION_SCREEN_ON.equals(intent.getAction())); - } - - public void register() { - if (!mRegistered) { - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_SCREEN_OFF); - filter.addAction(Intent.ACTION_SCREEN_ON); - filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); - mContext.registerReceiver(this, filter, null, mHandler); - mRegistered = true; - } - } - - public void unregister() { - if (mRegistered) { - mContext.unregisterReceiver(this); - mRegistered = false; - } - } } } private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener { - public DeviceConfigDisplaySettings() { } @@ -1147,7 +1169,8 @@ public class DisplayModeDirector { */ public int[] getBrightnessThresholds() { return getIntArrayProperty( - DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_BRIGHTNESS_THRESHOLDS); + DisplayManager.DeviceConfig. + KEY_PEAK_REFRESH_RATE_DISPLAY_BRIGHTNESS_THRESHOLDS); } /* @@ -1155,7 +1178,8 @@ public class DisplayModeDirector { */ public int[] getAmbientThresholds() { return getIntArrayProperty( - DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_AMBIENT_THRESHOLDS); + DisplayManager.DeviceConfig. + KEY_PEAK_REFRESH_RATE_AMBIENT_BRIGHTNESS_THRESHOLDS); } /* @@ -1172,17 +1196,32 @@ public class DisplayModeDirector { return defaultPeakRefreshRate; } + public int getRefreshRateInZone() { + int defaultRefreshRateInZone = mContext.getResources().getInteger( + R.integer.config_defaultRefreshRateInZone); + + int refreshRate = DeviceConfig.getInt( + DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_ZONE, + defaultRefreshRateInZone); + + return refreshRate; + } + @Override public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) { int[] brightnessThresholds = getBrightnessThresholds(); int[] ambientThresholds = getAmbientThresholds(); Float defaultPeakRefreshRate = getDefaultPeakRefreshRate(); + int refreshRateInZone = getRefreshRateInZone(); mHandler.obtainMessage(MSG_BRIGHTNESS_THRESHOLDS_CHANGED, new Pair<int[], int[]>(brightnessThresholds, ambientThresholds)) .sendToTarget(); mHandler.obtainMessage(MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED, defaultPeakRefreshRate).sendToTarget(); + mHandler.obtainMessage(MSG_REFRESH_RATE_IN_ZONE_CHANGED, refreshRateInZone, + 0).sendToTarget(); } private int[] getIntArrayProperty(String prop) { diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java index 7fb5b191a9b0..0bf43b6d1b9c 100644 --- a/services/core/java/com/android/server/display/color/ColorDisplayService.java +++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java @@ -609,6 +609,9 @@ public final class ColorDisplayService extends SystemService { @Override public void onAnimationEnd(Animator animator) { + Slog.d(TAG, tintController.getClass().getSimpleName() + + " Animation cancelled: " + mIsCancelled + + " to matrix: " + TintController.matrixToString(to, 16)); if (!mIsCancelled) { // Ensure final color matrix is set at the end of the animation. If the // animation is cancelled then don't set the final color matrix so the new @@ -1314,8 +1317,10 @@ public final class ColorDisplayService extends SystemService { * Reset the CCT value for the display white balance transform to its default value. */ public boolean resetDisplayWhiteBalanceColorTemperature() { - return setDisplayWhiteBalanceColorTemperature(getContext().getResources() - .getInteger(R.integer.config_displayWhiteBalanceColorTemperatureDefault)); + int temperatureDefault = getContext().getResources() + .getInteger(R.integer.config_displayWhiteBalanceColorTemperatureDefault); + Slog.d(TAG, "resetDisplayWhiteBalanceColorTemperature: " + temperatureDefault); + return setDisplayWhiteBalanceColorTemperature(temperatureDefault); } /** diff --git a/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java b/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java index d2c6cd9f1007..3f1c222ab520 100644 --- a/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java +++ b/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java @@ -149,8 +149,6 @@ final class DisplayWhiteBalanceTintController extends TintController { cct = mTemperatureMax; } - Slog.d(ColorDisplayService.TAG, "setDisplayWhiteBalanceTemperatureMatrix: cct = " + cct); - synchronized (mLock) { mCurrentColorTemperature = cct; @@ -185,6 +183,9 @@ final class DisplayWhiteBalanceTintController extends TintController { java.lang.System.arraycopy(result, 3, mMatrixDisplayWhiteBalance, 4, 3); java.lang.System.arraycopy(result, 6, mMatrixDisplayWhiteBalance, 8, 3); } + + Slog.d(ColorDisplayService.TAG, "setDisplayWhiteBalanceTemperatureMatrix: cct = " + cct + + " matrix = " + matrixToString(mMatrixDisplayWhiteBalance, 16)); } @Override @@ -225,28 +226,6 @@ final class DisplayWhiteBalanceTintController extends TintController { } } - /** - * Format a given matrix into a string. - * - * @param matrix the matrix to format - * @param columns number of columns in the matrix - */ - private String matrixToString(float[] matrix, int columns) { - if (matrix == null || columns <= 0) { - Slog.e(ColorDisplayService.TAG, "Invalid arguments when formatting matrix to string"); - return ""; - } - - final StringBuilder sb = new StringBuilder(""); - for (int i = 0; i < matrix.length; i++) { - if (i % columns == 0) { - sb.append("\n "); - } - sb.append(String.format("%9.6f", matrix[i])); - } - return sb.toString(); - } - private ColorSpace.Rgb makeRgbColorSpaceFromXYZ(float[] redGreenBlueXYZ, float[] whiteXYZ) { return new ColorSpace.Rgb( "Display Color Space", diff --git a/services/core/java/com/android/server/display/color/TintController.java b/services/core/java/com/android/server/display/color/TintController.java index b291c645027a..8d8b9b2af04e 100644 --- a/services/core/java/com/android/server/display/color/TintController.java +++ b/services/core/java/com/android/server/display/color/TintController.java @@ -18,6 +18,7 @@ package com.android.server.display.color; import android.animation.ValueAnimator; import android.content.Context; +import android.util.Slog; import java.io.PrintWriter; @@ -95,4 +96,29 @@ abstract class TintController { * Returns whether or not this transform type is available on this device. */ public abstract boolean isAvailable(Context context); + + /** + * Format a given matrix into a string. + * + * @param matrix the matrix to format + * @param columns number of columns in the matrix + */ + static String matrixToString(float[] matrix, int columns) { + if (matrix == null || columns <= 0) { + Slog.e(ColorDisplayService.TAG, "Invalid arguments when formatting matrix to string," + + " matrix is null: " + (matrix == null) + + " columns: " + columns); + return ""; + } + + final StringBuilder sb = new StringBuilder(""); + for (int i = 0; i < matrix.length; i++) { + if (i % columns == 0) { + sb.append("\n "); + } + sb.append(String.format("%9.6f", matrix[i])); + } + return sb.toString(); + } + } diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java index 02ec10e2d49d..7b1f4c3222f3 100644 --- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java +++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java @@ -95,6 +95,11 @@ public class DisplayWhiteBalanceController implements // A piecewise linear relationship between high light brightness and high light bias. private Spline.LinearSpline mHighLightAmbientBrightnessToBiasSpline; + private float mLatestAmbientColorTemperature; + private float mLatestAmbientBrightness; + private float mLatestLowLightBias; + private float mLatestHighLightBias; + /** * @param brightnessSensor * The sensor used to detect changes in the ambient brightness. @@ -348,6 +353,7 @@ public class DisplayWhiteBalanceController implements public void updateAmbientColorTemperature() { final long time = System.currentTimeMillis(); float ambientColorTemperature = mColorTemperatureFilter.getEstimate(time); + mLatestAmbientColorTemperature = ambientColorTemperature; if (mAmbientToDisplayColorTemperatureSpline != null && ambientColorTemperature != -1.0f) { ambientColorTemperature = @@ -355,6 +361,7 @@ public class DisplayWhiteBalanceController implements } float ambientBrightness = mBrightnessFilter.getEstimate(time); + mLatestAmbientBrightness = ambientBrightness; if (ambientColorTemperature != -1.0f && mLowLightAmbientBrightnessToBiasSpline != null) { @@ -362,6 +369,7 @@ public class DisplayWhiteBalanceController implements ambientColorTemperature = bias * ambientColorTemperature + (1.0f - bias) * mLowLightAmbientColorTemperature; + mLatestLowLightBias = bias; } if (ambientColorTemperature != -1.0f && mHighLightAmbientBrightnessToBiasSpline != null) { @@ -369,6 +377,7 @@ public class DisplayWhiteBalanceController implements ambientColorTemperature = (1.0f - bias) * ambientColorTemperature + bias * mHighLightAmbientColorTemperature; + mLatestHighLightBias = bias; } if (mAmbientColorTemperatureOverride != -1.0f) { @@ -426,6 +435,11 @@ public class DisplayWhiteBalanceController implements } mPendingAmbientColorTemperature = -1.0f; mAmbientColorTemperatureHistory.add(mAmbientColorTemperature); + Slog.d(TAG, "Display cct: " + mAmbientColorTemperature + + " Latest ambient cct: " + mLatestAmbientColorTemperature + + " Latest ambient lux: " + mLatestAmbientBrightness + + " Latest low light bias: " + mLatestLowLightBias + + " Latest high light bias: " + mLatestHighLightBias); mColorDisplayServiceInternal.setDisplayWhiteBalanceColorTemperature( (int) mAmbientColorTemperature); mLastAmbientColorTemperature = mAmbientColorTemperature; diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java index 9782f30d3074..259527a5f217 100644 --- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java +++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java @@ -79,7 +79,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem S extends AbstractPerUserSystemService<S, M>> extends SystemService { /** On a package update, does not refresh the per-user service in the cache. */ - public static final int PACKAGE_UPDATE_POLICY_NO_REFRESH = 0; + public static final int PACKAGE_UPDATE_POLICY_NO_REFRESH = 0x00000001; /** * On a package update, removes any existing per-user services in the cache. @@ -87,20 +87,40 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem * <p>This does not immediately recreate these services. It is assumed they will be recreated * for the next user request. */ - public static final int PACKAGE_UPDATE_POLICY_REFRESH_LAZY = 1; + public static final int PACKAGE_UPDATE_POLICY_REFRESH_LAZY = 0x00000002; /** * On a package update, removes and recreates any existing per-user services in the cache. */ - public static final int PACKAGE_UPDATE_POLICY_REFRESH_EAGER = 2; + public static final int PACKAGE_UPDATE_POLICY_REFRESH_EAGER = 0x00000004; - @IntDef(flag = true, prefix = { "PACKAGE_UPDATE_POLICY_" }, value = { + /** On a package restart, does not refresh the per-user service in the cache. */ + public static final int PACKAGE_RESTART_POLICY_NO_REFRESH = 0x00000010; + + /** + * On a package restart, removes any existing per-user services in the cache. + * + * <p>This does not immediately recreate these services. It is assumed they will be recreated + * for the next user request. + */ + public static final int PACKAGE_RESTART_POLICY_REFRESH_LAZY = 0x00000020; + + /** + * On a package restart, removes and recreates any existing per-user services in the cache. + */ + public static final int PACKAGE_RESTART_POLICY_REFRESH_EAGER = 0x00000040; + + @IntDef(flag = true, prefix = { "PACKAGE_" }, value = { PACKAGE_UPDATE_POLICY_NO_REFRESH, PACKAGE_UPDATE_POLICY_REFRESH_LAZY, - PACKAGE_UPDATE_POLICY_REFRESH_EAGER + PACKAGE_UPDATE_POLICY_REFRESH_EAGER, + PACKAGE_RESTART_POLICY_NO_REFRESH, + PACKAGE_RESTART_POLICY_REFRESH_LAZY, + PACKAGE_RESTART_POLICY_REFRESH_EAGER }) + @Retention(RetentionPolicy.SOURCE) - public @interface PackageUpdatePolicy {} + public @interface ServicePackagePolicyFlags {} /** * Log tag @@ -153,12 +173,10 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem private final SparseArray<S> mServicesCache = new SparseArray<>(); /** - * Whether the per-user service should be removed from the cache when its apk is updated. - * - * <p>One of {@link #PACKAGE_UPDATE_POLICY_NO_REFRESH}, - * {@link #PACKAGE_UPDATE_POLICY_REFRESH_LAZY} or {@link #PACKAGE_UPDATE_POLICY_REFRESH_EAGER}. + * Value that determines whether the per-user service should be removed from the cache when its + * apk is updated or restarted. */ - private final @PackageUpdatePolicy int mPackageUpdatePolicy; + private final @ServicePackagePolicyFlags int mServicePackagePolicyFlags; /** * Name of the service packages whose APK are being updated, keyed by user id. @@ -184,11 +202,11 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem @Nullable ServiceNameResolver serviceNameResolver, @Nullable String disallowProperty) { this(context, serviceNameResolver, disallowProperty, - /*packageUpdatePolicy=*/ PACKAGE_UPDATE_POLICY_REFRESH_LAZY); + PACKAGE_UPDATE_POLICY_REFRESH_LAZY | PACKAGE_RESTART_POLICY_REFRESH_LAZY); } /** - * Full constructor. + * Full Constructor. * * @param context system context. * @param serviceNameResolver resolver for @@ -197,19 +215,32 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem * @param disallowProperty when not {@code null}, defines a {@link UserManager} restriction that * disables the service. <b>NOTE: </b> you'll also need to add it to * {@code UserRestrictionsUtils.USER_RESTRICTIONS}. - * @param packageUpdatePolicy when {@link #PACKAGE_UPDATE_POLICY_REFRESH_LAZY}, the - * {@link AbstractPerUserSystemService} is removed from the cache when the service - * package is updated; when {@link #PACKAGE_UPDATE_POLICY_REFRESH_EAGER}, the - * {@link AbstractPerUserSystemService} is removed from the cache and immediately - * re-added when the service package is updated; when - * {@link #PACKAGE_UPDATE_POLICY_NO_REFRESH}, the service is untouched during the update. + * @param servicePackagePolicyFlags a combination of + * {@link #PACKAGE_UPDATE_POLICY_NO_REFRESH}, + * {@link #PACKAGE_UPDATE_POLICY_REFRESH_LAZY}, + * {@link #PACKAGE_UPDATE_POLICY_REFRESH_EAGER}, + * {@link #PACKAGE_RESTART_POLICY_NO_REFRESH}, + * {@link #PACKAGE_RESTART_POLICY_REFRESH_LAZY} or + * {@link #PACKAGE_RESTART_POLICY_REFRESH_EAGER} */ protected AbstractMasterSystemService(@NonNull Context context, - @Nullable ServiceNameResolver serviceNameResolver, - @Nullable String disallowProperty, @PackageUpdatePolicy int packageUpdatePolicy) { + @Nullable ServiceNameResolver serviceNameResolver, @Nullable String disallowProperty, + @ServicePackagePolicyFlags int servicePackagePolicyFlags) { super(context); - mPackageUpdatePolicy = packageUpdatePolicy; + final int updatePolicyMask = PACKAGE_UPDATE_POLICY_NO_REFRESH + | PACKAGE_UPDATE_POLICY_REFRESH_LAZY | PACKAGE_UPDATE_POLICY_REFRESH_EAGER; + if ((servicePackagePolicyFlags & updatePolicyMask) == 0) { + // If the package update policy is not set, add the default flag + servicePackagePolicyFlags |= PACKAGE_UPDATE_POLICY_REFRESH_LAZY; + } + final int restartPolicyMask = PACKAGE_RESTART_POLICY_NO_REFRESH + | PACKAGE_RESTART_POLICY_REFRESH_LAZY | PACKAGE_RESTART_POLICY_REFRESH_EAGER; + if ((servicePackagePolicyFlags & restartPolicyMask) == 0) { + // If the package restart policy is not set, add the default flag + servicePackagePolicyFlags |= PACKAGE_RESTART_POLICY_REFRESH_LAZY; + } + mServicePackagePolicyFlags = servicePackagePolicyFlags; mServiceNameResolver = serviceNameResolver; if (mServiceNameResolver != null) { @@ -606,6 +637,20 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem } /** + * Called after the package data that provides the service for the given user is cleared. + */ + protected void onServicePackageDataClearedLocked(@UserIdInt int userId) { + if (verbose) Slog.v(mTag, "onServicePackageDataCleared(" + userId + ")"); + } + + /** + * Called after the package that provides the service for the given user is restarted. + */ + protected void onServicePackageRestartedLocked(@UserIdInt int userId) { + if (verbose) Slog.v(mTag, "onServicePackageRestarted(" + userId + ")"); + } + + /** * Called after the service is removed from the cache. */ @SuppressWarnings("unused") @@ -677,7 +722,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem final int size = mServicesCache.size(); pw.print(prefix); pw.print("Debug: "); pw.print(realDebug); pw.print(" Verbose: "); pw.println(realVerbose); - pw.print("Refresh on package update: "); pw.println(mPackageUpdatePolicy); + pw.print("Package policy flags: "); pw.println(mServicePackagePolicyFlags); if (mUpdatingPackageNames != null) { pw.print("Packages being updated: "); pw.println(mUpdatingPackageNames); } @@ -733,7 +778,12 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem } mUpdatingPackageNames.put(userId, packageName); onServicePackageUpdatingLocked(userId); - if (mPackageUpdatePolicy != PACKAGE_UPDATE_POLICY_NO_REFRESH) { + if ((mServicePackagePolicyFlags & PACKAGE_UPDATE_POLICY_NO_REFRESH) != 0) { + if (debug) { + Slog.d(mTag, "Holding service for user " + userId + " while package " + + activePackageName + " is being updated"); + } + } else { if (debug) { Slog.d(mTag, "Removing service for user " + userId + " because package " + activePackageName @@ -741,18 +791,14 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem } removeCachedServiceLocked(userId); - if (mPackageUpdatePolicy == PACKAGE_UPDATE_POLICY_REFRESH_EAGER) { + if ((mServicePackagePolicyFlags & PACKAGE_UPDATE_POLICY_REFRESH_EAGER) + != 0) { if (debug) { Slog.d(mTag, "Eagerly recreating service for user " + userId); } getServiceForUserLocked(userId); } - } else { - if (debug) { - Slog.d(mTag, "Holding service for user " + userId + " while package " - + activePackageName + " is being updated"); - } } } } @@ -804,7 +850,13 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem if (!doit) { return true; } - removeCachedServiceLocked(getChangingUserId()); + final String action = intent.getAction(); + final int userId = getChangingUserId(); + if (Intent.ACTION_PACKAGE_RESTARTED.equals(action)) { + handleActiveServiceRestartedLocked(activePackageName, userId); + } else { + removeCachedServiceLocked(userId); + } } else { handlePackageUpdateLocked(pkg); } @@ -813,6 +865,23 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem return false; } + @Override + public void onPackageDataCleared(String packageName, int uid) { + if (verbose) Slog.v(mTag, "onPackageDataCleared(): " + packageName); + final int userId = getChangingUserId(); + synchronized (mLock) { + final S service = peekServiceForUserLocked(userId); + if (service != null) { + final ComponentName componentName = service.getServiceComponentName(); + if (componentName != null) { + if (packageName.equals(componentName.getPackageName())) { + onServicePackageDataClearedLocked(userId); + } + } + } + } + } + private void handleActiveServiceRemoved(@UserIdInt int userId) { synchronized (mLock) { removeCachedServiceLocked(userId); @@ -824,6 +893,31 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem } } + private void handleActiveServiceRestartedLocked(String activePackageName, + @UserIdInt int userId) { + if ((mServicePackagePolicyFlags & PACKAGE_RESTART_POLICY_NO_REFRESH) != 0) { + if (debug) { + Slog.d(mTag, "Holding service for user " + userId + " while package " + + activePackageName + " is being restarted"); + } + } else { + if (debug) { + Slog.d(mTag, "Removing service for user " + userId + + " because package " + activePackageName + + " is being restarted"); + } + removeCachedServiceLocked(userId); + + if ((mServicePackagePolicyFlags & PACKAGE_RESTART_POLICY_REFRESH_EAGER) != 0) { + if (debug) { + Slog.d(mTag, "Eagerly recreating service for user " + userId); + } + getServiceForUserLocked(userId); + } + } + onServicePackageRestartedLocked(userId); + } + private String getActiveServicePackageNameLocked() { final int userId = getChangingUserId(); final S service = peekServiceForUserLocked(userId); diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index c312b76cc463..181a43549313 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -1459,7 +1459,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements info.mSvCarrierFreqs); // Log CN0 as part of GNSS metrics - mGnssMetrics.logCn0(info.mCn0s, info.mSvCount); + mGnssMetrics.logCn0(info.mCn0s, info.mSvCount, info.mSvCarrierFreqs); if (VERBOSE) { Log.v(TAG, "SV count: " + info.mSvCount); @@ -1510,6 +1510,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements SystemClock.elapsedRealtime() - mLastFixTime > RECENT_FIX_TIMEOUT) { updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE); } + + mGnssMetrics.logSvStatus(info.mSvCount, info.mSvidWithFlags, info.mSvCarrierFreqs); } @NativeEntryPoint diff --git a/services/core/java/com/android/server/notification/BubbleExtractor.java b/services/core/java/com/android/server/notification/BubbleExtractor.java index 358bdb90f6d3..e59bf1642ba8 100644 --- a/services/core/java/com/android/server/notification/BubbleExtractor.java +++ b/services/core/java/com/android/server/notification/BubbleExtractor.java @@ -41,10 +41,9 @@ public class BubbleExtractor implements NotificationSignalExtractor { if (DBG) Slog.d(TAG, "missing config"); return null; } - boolean userWantsBubbles = mConfig.bubblesEnabled(record.sbn.getUser()); boolean appCanShowBubble = mConfig.areBubblesAllowed(record.sbn.getPackageName(), record.sbn.getUid()); - if (!userWantsBubbles || !appCanShowBubble) { + if (!mConfig.bubblesEnabled() || !appCanShowBubble) { record.setAllowBubble(false); } else { if (record.getChannel() != null) { diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index 4a6eb276bd02..4828bbfff676 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -196,18 +196,20 @@ abstract public class ManagedServices { public void dump(PrintWriter pw, DumpFilter filter) { pw.println(" Allowed " + getCaption() + "s:"); - final int N = mApproved.size(); - for (int i = 0 ; i < N; i++) { - final int userId = mApproved.keyAt(i); - final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i); - if (approvedByType != null) { - final int M = approvedByType.size(); - for (int j = 0; j < M; j++) { - final boolean isPrimary = approvedByType.keyAt(j); - final ArraySet<String> approved = approvedByType.valueAt(j); - if (approvedByType != null && approvedByType.size() > 0) { - pw.println(" " + String.join(ENABLED_SERVICES_SEPARATOR, approved) - + " (user: " + userId + " isPrimary: " + isPrimary + ")"); + synchronized (mApproved) { + final int N = mApproved.size(); + for (int i = 0; i < N; i++) { + final int userId = mApproved.keyAt(i); + final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i); + if (approvedByType != null) { + final int M = approvedByType.size(); + for (int j = 0; j < M; j++) { + final boolean isPrimary = approvedByType.keyAt(j); + final ArraySet<String> approved = approvedByType.valueAt(j); + if (approvedByType != null && approvedByType.size() > 0) { + pw.println(" " + String.join(ENABLED_SERVICES_SEPARATOR, approved) + + " (user: " + userId + " isPrimary: " + isPrimary + ")"); + } } } } @@ -240,23 +242,25 @@ abstract public class ManagedServices { public void dump(ProtoOutputStream proto, DumpFilter filter) { proto.write(ManagedServicesProto.CAPTION, getCaption()); - final int N = mApproved.size(); - for (int i = 0 ; i < N; i++) { - final int userId = mApproved.keyAt(i); - final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i); - if (approvedByType != null) { - final int M = approvedByType.size(); - for (int j = 0; j < M; j++) { - final boolean isPrimary = approvedByType.keyAt(j); - final ArraySet<String> approved = approvedByType.valueAt(j); - if (approvedByType != null && approvedByType.size() > 0) { - final long sToken = proto.start(ManagedServicesProto.APPROVED); - for (String s : approved) { - proto.write(ServiceProto.NAME, s); + synchronized (mApproved) { + final int N = mApproved.size(); + for (int i = 0; i < N; i++) { + final int userId = mApproved.keyAt(i); + final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i); + if (approvedByType != null) { + final int M = approvedByType.size(); + for (int j = 0; j < M; j++) { + final boolean isPrimary = approvedByType.keyAt(j); + final ArraySet<String> approved = approvedByType.valueAt(j); + if (approvedByType != null && approvedByType.size() > 0) { + final long sToken = proto.start(ManagedServicesProto.APPROVED); + for (String s : approved) { + proto.write(ServiceProto.NAME, s); + } + proto.write(ServiceProto.USER_ID, userId); + proto.write(ServiceProto.IS_PRIMARY, isPrimary); + proto.end(sToken); } - proto.write(ServiceProto.USER_ID, userId); - proto.write(ServiceProto.IS_PRIMARY, isPrimary); - proto.end(sToken); } } } @@ -315,33 +319,36 @@ abstract public class ManagedServices { trimApprovedListsAccordingToInstalledServices(userId); } - final int N = mApproved.size(); - for (int i = 0 ; i < N; i++) { - final int approvedUserId = mApproved.keyAt(i); - if (forBackup && approvedUserId != userId) { - continue; - } - final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i); - if (approvedByType != null) { - final int M = approvedByType.size(); - for (int j = 0; j < M; j++) { - final boolean isPrimary = approvedByType.keyAt(j); - final Set<String> approved = approvedByType.valueAt(j); - if (approved != null) { - String allowedItems = String.join(ENABLED_SERVICES_SEPARATOR, approved); - out.startTag(null, TAG_MANAGED_SERVICES); - out.attribute(null, ATT_APPROVED_LIST, allowedItems); - out.attribute(null, ATT_USER_ID, Integer.toString(approvedUserId)); - out.attribute(null, ATT_IS_PRIMARY, Boolean.toString(isPrimary)); - writeExtraAttributes(out, approvedUserId); - out.endTag(null, TAG_MANAGED_SERVICES); - - if (!forBackup && isPrimary) { - // Also write values to settings, for observers who haven't migrated yet - Settings.Secure.putStringForUser(mContext.getContentResolver(), - getConfig().secureSettingName, allowedItems, approvedUserId); - } + synchronized (mApproved) { + final int N = mApproved.size(); + for (int i = 0; i < N; i++) { + final int approvedUserId = mApproved.keyAt(i); + if (forBackup && approvedUserId != userId) { + continue; + } + final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i); + if (approvedByType != null) { + final int M = approvedByType.size(); + for (int j = 0; j < M; j++) { + final boolean isPrimary = approvedByType.keyAt(j); + final Set<String> approved = approvedByType.valueAt(j); + if (approved != null) { + String allowedItems = String.join(ENABLED_SERVICES_SEPARATOR, approved); + out.startTag(null, TAG_MANAGED_SERVICES); + out.attribute(null, ATT_APPROVED_LIST, allowedItems); + out.attribute(null, ATT_USER_ID, Integer.toString(approvedUserId)); + out.attribute(null, ATT_IS_PRIMARY, Boolean.toString(isPrimary)); + writeExtraAttributes(out, approvedUserId); + out.endTag(null, TAG_MANAGED_SERVICES); + + if (!forBackup && isPrimary) { + // Also write values to settings, for observers who haven't migrated yet + Settings.Secure.putStringForUser(mContext.getContentResolver(), + getConfig().secureSettingName, allowedItems, + approvedUserId); + } + } } } } @@ -440,23 +447,25 @@ abstract public class ManagedServices { if (TextUtils.isEmpty(approved)) { approved = ""; } - ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId); - if (approvedByType == null) { - approvedByType = new ArrayMap<>(); - mApproved.put(userId, approvedByType); - } + synchronized (mApproved) { + ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId); + if (approvedByType == null) { + approvedByType = new ArrayMap<>(); + mApproved.put(userId, approvedByType); + } - ArraySet<String> approvedList = approvedByType.get(isPrimary); - if (approvedList == null) { - approvedList = new ArraySet<>(); - approvedByType.put(isPrimary, approvedList); - } + ArraySet<String> approvedList = approvedByType.get(isPrimary); + if (approvedList == null) { + approvedList = new ArraySet<>(); + approvedByType.put(isPrimary, approvedList); + } - String[] approvedArray = approved.split(ENABLED_SERVICES_SEPARATOR); - for (String pkgOrComponent : approvedArray) { - String approvedItem = getApprovedValue(pkgOrComponent); - if (approvedItem != null) { - approvedList.add(approvedItem); + String[] approvedArray = approved.split(ENABLED_SERVICES_SEPARATOR); + for (String pkgOrComponent : approvedArray) { + String approvedItem = getApprovedValue(pkgOrComponent); + if (approvedItem != null) { + approvedList.add(approvedItem); + } } } } @@ -469,23 +478,25 @@ abstract public class ManagedServices { boolean isPrimary, boolean enabled) { Slog.i(TAG, (enabled ? " Allowing " : "Disallowing ") + mConfig.caption + " " + pkgOrComponent); - ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.get(userId); - if (allowedByType == null) { - allowedByType = new ArrayMap<>(); - mApproved.put(userId, allowedByType); - } - ArraySet<String> approved = allowedByType.get(isPrimary); - if (approved == null) { - approved = new ArraySet<>(); - allowedByType.put(isPrimary, approved); - } - String approvedItem = getApprovedValue(pkgOrComponent); - - if (approvedItem != null) { - if (enabled) { - approved.add(approvedItem); - } else { - approved.remove(approvedItem); + synchronized (mApproved) { + ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.get(userId); + if (allowedByType == null) { + allowedByType = new ArrayMap<>(); + mApproved.put(userId, allowedByType); + } + ArraySet<String> approved = allowedByType.get(isPrimary); + if (approved == null) { + approved = new ArraySet<>(); + allowedByType.put(isPrimary, approved); + } + String approvedItem = getApprovedValue(pkgOrComponent); + + if (approvedItem != null) { + if (enabled) { + approved.add(approvedItem); + } else { + approved.remove(approvedItem); + } } } @@ -504,22 +515,26 @@ abstract public class ManagedServices { } protected String getApproved(int userId, boolean primary) { - final ArrayMap<Boolean, ArraySet<String>> allowedByType = - mApproved.getOrDefault(userId, new ArrayMap<>()); - ArraySet<String> approved = allowedByType.getOrDefault(primary, new ArraySet<>()); - return String.join(ENABLED_SERVICES_SEPARATOR, approved); + synchronized (mApproved) { + final ArrayMap<Boolean, ArraySet<String>> allowedByType = + mApproved.getOrDefault(userId, new ArrayMap<>()); + ArraySet<String> approved = allowedByType.getOrDefault(primary, new ArraySet<>()); + return String.join(ENABLED_SERVICES_SEPARATOR, approved); + } } protected List<ComponentName> getAllowedComponents(int userId) { final List<ComponentName> allowedComponents = new ArrayList<>(); - final ArrayMap<Boolean, ArraySet<String>> allowedByType = - mApproved.getOrDefault(userId, new ArrayMap<>()); - for (int i = 0; i < allowedByType.size(); i++) { - final ArraySet<String> allowed = allowedByType.valueAt(i); - for (int j = 0; j < allowed.size(); j++) { - ComponentName cn = ComponentName.unflattenFromString(allowed.valueAt(j)); - if (cn != null) { - allowedComponents.add(cn); + synchronized (mApproved) { + final ArrayMap<Boolean, ArraySet<String>> allowedByType = + mApproved.getOrDefault(userId, new ArrayMap<>()); + for (int i = 0; i < allowedByType.size(); i++) { + final ArraySet<String> allowed = allowedByType.valueAt(i); + for (int j = 0; j < allowed.size(); j++) { + ComponentName cn = ComponentName.unflattenFromString(allowed.valueAt(j)); + if (cn != null) { + allowedComponents.add(cn); + } } } } @@ -528,14 +543,16 @@ abstract public class ManagedServices { protected List<String> getAllowedPackages(int userId) { final List<String> allowedPackages = new ArrayList<>(); - final ArrayMap<Boolean, ArraySet<String>> allowedByType = - mApproved.getOrDefault(userId, new ArrayMap<>()); - for (int i = 0; i < allowedByType.size(); i++) { - final ArraySet<String> allowed = allowedByType.valueAt(i); - for (int j = 0; j < allowed.size(); j++) { - String pkgName = getPackageName(allowed.valueAt(j)); - if (!TextUtils.isEmpty(pkgName)) { - allowedPackages.add(pkgName); + synchronized (mApproved) { + final ArrayMap<Boolean, ArraySet<String>> allowedByType = + mApproved.getOrDefault(userId, new ArrayMap<>()); + for (int i = 0; i < allowedByType.size(); i++) { + final ArraySet<String> allowed = allowedByType.valueAt(i); + for (int j = 0; j < allowed.size(); j++) { + String pkgName = getPackageName(allowed.valueAt(j)); + if (!TextUtils.isEmpty(pkgName)) { + allowedPackages.add(pkgName); + } } } } @@ -543,12 +560,14 @@ abstract public class ManagedServices { } protected boolean isPackageOrComponentAllowed(String pkgOrComponent, int userId) { - ArrayMap<Boolean, ArraySet<String>> allowedByType = - mApproved.getOrDefault(userId, new ArrayMap<>()); - for (int i = 0; i < allowedByType.size(); i++) { - ArraySet<String> allowed = allowedByType.valueAt(i); - if (allowed.contains(pkgOrComponent)) { - return true; + synchronized (mApproved) { + ArrayMap<Boolean, ArraySet<String>> allowedByType = + mApproved.getOrDefault(userId, new ArrayMap<>()); + for (int i = 0; i < allowedByType.size(); i++) { + ArraySet<String> allowed = allowedByType.valueAt(i); + if (allowed.contains(pkgOrComponent)) { + return true; + } } } return false; @@ -558,19 +577,21 @@ abstract public class ManagedServices { if (pkg == null) { return false; } - ArrayMap<Boolean, ArraySet<String>> allowedByType = - mApproved.getOrDefault(userId, new ArrayMap<>()); - for (int i = 0; i < allowedByType.size(); i++) { - ArraySet<String> allowed = allowedByType.valueAt(i); - for (String allowedEntry : allowed) { - ComponentName component = ComponentName.unflattenFromString(allowedEntry); - if (component != null) { - if (pkg.equals(component.getPackageName())) { - return true; - } - } else { - if (pkg.equals(allowedEntry)) { - return true; + synchronized (mApproved) { + ArrayMap<Boolean, ArraySet<String>> allowedByType = + mApproved.getOrDefault(userId, new ArrayMap<>()); + for (int i = 0; i < allowedByType.size(); i++) { + ArraySet<String> allowed = allowedByType.valueAt(i); + for (String allowedEntry : allowed) { + ComponentName component = ComponentName.unflattenFromString(allowedEntry); + if (component != null) { + if (pkg.equals(component.getPackageName())) { + return true; + } + } else { + if (pkg.equals(allowedEntry)) { + return true; + } } } } @@ -616,7 +637,9 @@ abstract public class ManagedServices { public void onUserRemoved(int user) { Slog.i(TAG, "Removing approved services for removed user " + user); - mApproved.remove(user); + synchronized (mApproved) { + mApproved.remove(user); + } rebindServices(true, user); } @@ -797,14 +820,16 @@ abstract public class ManagedServices { protected Set<String> getAllowedPackages() { final Set<String> allowedPackages = new ArraySet<>(); - for (int k = 0; k < mApproved.size(); k++) { - ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.valueAt(k); - for (int i = 0; i < allowedByType.size(); i++) { - final ArraySet<String> allowed = allowedByType.valueAt(i); - for (int j = 0; j < allowed.size(); j++) { - String pkgName = getPackageName(allowed.valueAt(j)); - if (!TextUtils.isEmpty(pkgName)) { - allowedPackages.add(pkgName); + synchronized (mApproved) { + for (int k = 0; k < mApproved.size(); k++) { + ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.valueAt(k); + for (int i = 0; i < allowedByType.size(); i++) { + final ArraySet<String> allowed = allowedByType.valueAt(i); + for (int j = 0; j < allowed.size(); j++) { + String pkgName = getPackageName(allowed.valueAt(j)); + if (!TextUtils.isEmpty(pkgName)) { + allowedPackages.add(pkgName); + } } } } @@ -813,22 +838,24 @@ abstract public class ManagedServices { } private void trimApprovedListsAccordingToInstalledServices(int userId) { - final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId); - if (approvedByType == null) { - return; - } - for (int i = 0; i < approvedByType.size(); i++) { - final ArraySet<String> approved = approvedByType.valueAt(i); - for (int j = approved.size() - 1; j >= 0; j--) { - final String approvedPackageOrComponent = approved.valueAt(j); - if (!isValidEntry(approvedPackageOrComponent, userId)){ - approved.removeAt(j); - Slog.v(TAG, "Removing " + approvedPackageOrComponent - + " from approved list; no matching services found"); - } else { - if (DEBUG) { - Slog.v(TAG, "Keeping " + approvedPackageOrComponent - + " on approved list; matching services found"); + synchronized (mApproved) { + final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId); + if (approvedByType == null) { + return; + } + for (int i = 0; i < approvedByType.size(); i++) { + final ArraySet<String> approved = approvedByType.valueAt(i); + for (int j = approved.size() - 1; j >= 0; j--) { + final String approvedPackageOrComponent = approved.valueAt(j); + if (!isValidEntry(approvedPackageOrComponent, userId)) { + approved.removeAt(j); + Slog.v(TAG, "Removing " + approvedPackageOrComponent + + " from approved list; no matching services found"); + } else { + if (DEBUG) { + Slog.v(TAG, "Keeping " + approvedPackageOrComponent + + " on approved list; matching services found"); + } } } } @@ -837,20 +864,23 @@ abstract public class ManagedServices { private boolean removeUninstalledItemsFromApprovedLists(int uninstalledUserId, String pkg) { boolean removed = false; - final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(uninstalledUserId); - if (approvedByType != null) { - int M = approvedByType.size(); - for (int j = 0; j < M; j++) { - final ArraySet<String> approved = approvedByType.valueAt(j); - int O = approved.size(); - for (int k = O - 1; k >= 0; k--) { - final String packageOrComponent = approved.valueAt(k); - final String packageName = getPackageName(packageOrComponent); - if (TextUtils.equals(pkg, packageName)) { - approved.removeAt(k); - if (DEBUG) { - Slog.v(TAG, "Removing " + packageOrComponent - + " from approved list; uninstalled"); + synchronized (mApproved) { + final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get( + uninstalledUserId); + if (approvedByType != null) { + int M = approvedByType.size(); + for (int j = 0; j < M; j++) { + final ArraySet<String> approved = approvedByType.valueAt(j); + int O = approved.size(); + for (int k = O - 1; k >= 0; k--) { + final String packageOrComponent = approved.valueAt(k); + final String packageName = getPackageName(packageOrComponent); + if (TextUtils.equals(pkg, packageName)) { + approved.removeAt(k); + if (DEBUG) { + Slog.v(TAG, "Removing " + packageOrComponent + + " from approved list; uninstalled"); + } } } } @@ -887,17 +917,19 @@ abstract public class ManagedServices { for (int i = 0; i < nUserIds; ++i) { final int userId = userIds.get(i); - final ArrayMap<Boolean, ArraySet<String>> approvedLists = mApproved.get(userId); - if (approvedLists != null) { - final int N = approvedLists.size(); - for (int j = 0; j < N; j++) { - ArraySet<ComponentName> approvedByUser = componentsByUser.get(userId); - if (approvedByUser == null) { - approvedByUser = new ArraySet<>(); - componentsByUser.put(userId, approvedByUser); + synchronized (mApproved) { + final ArrayMap<Boolean, ArraySet<String>> approvedLists = mApproved.get(userId); + if (approvedLists != null) { + final int N = approvedLists.size(); + for (int j = 0; j < N; j++) { + ArraySet<ComponentName> approvedByUser = componentsByUser.get(userId); + if (approvedByUser == null) { + approvedByUser = new ArraySet<>(); + componentsByUser.put(userId, approvedByUser); + } + approvedByUser.addAll( + loadComponentNamesFromValues(approvedLists.valueAt(j), userId)); } - approvedByUser.addAll( - loadComponentNamesFromValues(approvedLists.valueAt(j), userId)); } } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index faac78d68879..655b9ac10b84 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -91,6 +91,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER; import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER; import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER; +import static com.android.server.notification.PreferencesHelper.DEFAULT_ALLOW_BUBBLE; import static com.android.server.utils.PriorityDump.PRIORITY_ARG; import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL; import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL; @@ -466,6 +467,8 @@ public class NotificationManagerService extends SystemService { private MetricsLogger mMetricsLogger; private TriPredicate<String, Integer, String> mAllowedManagedServicePackages; + private final SavePolicyFileRunnable mSavePolicyFile = new SavePolicyFileRunnable(); + private static class Archive { final int mBufferSize; final ArrayDeque<StatusBarNotification> mBuffer; @@ -659,7 +662,14 @@ public class NotificationManagerService extends SystemService { @VisibleForTesting protected void handleSavePolicyFile() { - IoThread.getHandler().post(() -> { + if (!IoThread.getHandler().hasCallbacks(mSavePolicyFile)) { + IoThread.getHandler().post(mSavePolicyFile); + } + } + + private final class SavePolicyFileRunnable implements Runnable { + @Override + public void run() { if (DBG) Slog.d(TAG, "handleSavePolicyFile"); synchronized (mPolicyFile) { final FileOutputStream stream; @@ -679,7 +689,7 @@ public class NotificationManagerService extends SystemService { } } BackupManager.dataChanged(getContext().getPackageName()); - }); + } } private void writePolicyXml(OutputStream stream, boolean forBackup, int userId) @@ -1371,7 +1381,9 @@ public class NotificationManagerService extends SystemService { private final class SettingsObserver extends ContentObserver { private final Uri NOTIFICATION_BADGING_URI = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING); - private final Uri NOTIFICATION_BUBBLES_URI + private final Uri NOTIFICATION_BUBBLES_URI_GLOBAL + = Settings.Global.getUriFor(Settings.Global.NOTIFICATION_BUBBLES); + private final Uri NOTIFICATION_BUBBLES_URI_SECURE = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BUBBLES); private final Uri NOTIFICATION_LIGHT_PULSE_URI = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE); @@ -1390,7 +1402,9 @@ public class NotificationManagerService extends SystemService { false, this, UserHandle.USER_ALL); resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI, false, this, UserHandle.USER_ALL); - resolver.registerContentObserver(NOTIFICATION_BUBBLES_URI, + resolver.registerContentObserver(NOTIFICATION_BUBBLES_URI_GLOBAL, + false, this, UserHandle.USER_ALL); + resolver.registerContentObserver(NOTIFICATION_BUBBLES_URI_SECURE, false, this, UserHandle.USER_ALL); update(null); } @@ -1417,9 +1431,41 @@ public class NotificationManagerService extends SystemService { if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) { mPreferencesHelper.updateBadgingEnabled(); } - if (uri == null || NOTIFICATION_BUBBLES_URI.equals(uri)) { + // In QPR we moved the setting to Global rather than Secure so that the setting + // applied to work profiles. Unfortunately we need to maintain both to pass CTS without + // a change to CTS outside of a normal letter release. + if (uri == null || NOTIFICATION_BUBBLES_URI_GLOBAL.equals(uri)) { + syncBubbleSettings(resolver, NOTIFICATION_BUBBLES_URI_GLOBAL); mPreferencesHelper.updateBubblesEnabled(); } + if (NOTIFICATION_BUBBLES_URI_SECURE.equals(uri)) { + syncBubbleSettings(resolver, NOTIFICATION_BUBBLES_URI_SECURE); + } + } + + private void syncBubbleSettings(ContentResolver resolver, Uri settingToFollow) { + boolean followSecureSetting = settingToFollow.equals(NOTIFICATION_BUBBLES_URI_SECURE); + + int secureSettingValue = Settings.Secure.getInt(resolver, + Settings.Secure.NOTIFICATION_BUBBLES, DEFAULT_ALLOW_BUBBLE ? 1 : 0); + int globalSettingValue = Settings.Global.getInt(resolver, + Settings.Global.NOTIFICATION_BUBBLES, DEFAULT_ALLOW_BUBBLE ? 1 : 0); + + if (globalSettingValue == secureSettingValue) { + return; + } + + if (followSecureSetting) { + // Global => secure + Settings.Global.putInt(resolver, + Settings.Global.NOTIFICATION_BUBBLES, + secureSettingValue); + } else { + // Secure => Global + Settings.Secure.putInt(resolver, + Settings.Secure.NOTIFICATION_BADGING, + globalSettingValue); + } } } @@ -1837,6 +1883,7 @@ public class NotificationManagerService extends SystemService { } if (properties.getKeyset() .contains(SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE)) { + mAssistants.allowAdjustmentType(Adjustment.KEY_IMPORTANCE); mAssistants.resetDefaultAssistantsIfNecessary(); } }); @@ -2269,7 +2316,7 @@ public class NotificationManagerService extends SystemService { final int callingUid = Binder.getCallingUid(); final boolean isSystemToast = isCallerSystemOrPhone() || PackageManagerService.PLATFORM_PACKAGE_NAME.equals(pkg); - final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid); + final boolean isPackageSuspended = isPackagePaused(pkg); final boolean notificationsDisabledForPackage = !areNotificationsEnabledForPackage(pkg, callingUid); @@ -2418,9 +2465,25 @@ public class NotificationManagerService extends SystemService { } @Override + public void silenceNotificationSound() { + checkCallerIsSystem(); + + mNotificationDelegate.clearEffects(); + } + + @Override public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) { enforceSystemOrSystemUI("setNotificationsEnabledForPackage"); + synchronized (mNotificationLock) { + boolean wasEnabled = mPreferencesHelper.getImportance(pkg, uid) + != NotificationManager.IMPORTANCE_NONE; + + if (wasEnabled == enabled) { + return; + } + } + mPreferencesHelper.setEnabled(pkg, uid, enabled); mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_BAN_APP_NOTES) .setType(MetricsEvent.TYPE_ACTION) @@ -4107,17 +4170,7 @@ public class NotificationManagerService extends SystemService { Preconditions.checkNotNull(pkg); checkCallerIsSameApp(pkg); - boolean isPaused; - - final PackageManagerInternal pmi = LocalServices.getService( - PackageManagerInternal.class); - int flags = pmi.getDistractingPackageRestrictions( - pkg, Binder.getCallingUserHandle().getIdentifier()); - isPaused = ((flags & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0); - - isPaused |= isPackageSuspendedForUser(pkg, Binder.getCallingUid()); - - return isPaused; + return isPackagePausedOrSuspended(pkg, Binder.getCallingUid()); } private void verifyPrivilegedListener(INotificationListener token, UserHandle user, @@ -4830,47 +4883,112 @@ public class NotificationManagerService extends SystemService { } else { notification.flags &= ~FLAG_BUBBLE; } + // Is the app in the foreground? + final boolean appIsForeground = + mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND; + Notification.BubbleMetadata metadata = notification.getBubbleMetadata(); + if (!appIsForeground && metadata != null) { + // Remove any flags that only work when foregrounded + int flags = metadata.getFlags(); + flags &= ~Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE; + flags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; + metadata.setFlags(flags); + } } /** - * @return whether the provided notification record is allowed to be represented as a bubble. + * @return whether the provided notification record is allowed to be represented as a bubble, + * accounting for user choice & policy. */ private boolean isNotificationAppropriateToBubble(NotificationRecord r, String pkg, int userId, NotificationRecord oldRecord) { Notification notification = r.getNotification(); - Notification.BubbleMetadata metadata = notification.getBubbleMetadata(); - boolean intentCanBubble = metadata != null - && canLaunchInActivityView(getContext(), metadata.getIntent(), pkg); + if (!canBubble(r, pkg, userId)) { + // no log: canBubble has its own + return false; + } - // Does the app want to bubble & is able to bubble - boolean canBubble = intentCanBubble - && mPreferencesHelper.areBubblesAllowed(pkg, userId) - && mPreferencesHelper.bubblesEnabled(r.sbn.getUser()) - && r.getChannel().canBubble() - && !mActivityManager.isLowRamDevice(); + if (mActivityManager.isLowRamDevice()) { + logBubbleError(r.getKey(), "low ram device"); + return false; + } - // Is the app in the foreground? - final boolean appIsForeground = - mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND; + if (mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND) { + // If the app is foreground it always gets to bubble + return true; + } + + if (oldRecord != null && (oldRecord.getNotification().flags & FLAG_BUBBLE) != 0) { + // This is an update to an active bubble + return true; + } - // Is the notification something we'd allow to bubble? - // A call with a foreground service + person + // At this point the bubble must fulfill communication policy + + // Communication always needs a person ArrayList<Person> peopleList = notification.extras != null ? notification.extras.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST) : null; - boolean isForegroundCall = CATEGORY_CALL.equals(notification.category) - && (notification.flags & FLAG_FOREGROUND_SERVICE) != 0; - // OR message style (which always has a person) with any remote input - Class<? extends Notification.Style> style = notification.getNotificationStyle(); - boolean isMessageStyle = Notification.MessagingStyle.class.equals(style); - boolean notificationAppropriateToBubble = - (isMessageStyle && hasValidRemoteInput(notification)) - || (peopleList != null && !peopleList.isEmpty() && isForegroundCall); + // Message style requires a person & it's not included in the list + boolean isMessageStyle = Notification.MessagingStyle.class.equals( + notification.getNotificationStyle()); + if (!isMessageStyle && (peopleList == null || peopleList.isEmpty())) { + logBubbleError(r.getKey(), "if not foreground, must have a person and be " + + "Notification.MessageStyle or Notification.CATEGORY_CALL"); + return false; + } + + // Communication is a message or a call + boolean isCall = CATEGORY_CALL.equals(notification.category); + boolean hasForegroundService = (notification.flags & FLAG_FOREGROUND_SERVICE) != 0; + if (isMessageStyle) { + if (hasValidRemoteInput(notification)) { + return true; + } + logBubbleError(r.getKey(), "messages require valid remote input"); + return false; + } else if (isCall) { + if (hasForegroundService) { + return true; + } + logBubbleError(r.getKey(), "calls require foreground service"); + return false; + } + logBubbleError(r.getKey(), "if not foreground, must be " + + "Notification.MessageStyle or Notification.CATEGORY_CALL"); + return false; + } - // OR something that was previously a bubble & still exists - boolean bubbleUpdate = oldRecord != null - && (oldRecord.getNotification().flags & FLAG_BUBBLE) != 0; - return canBubble && (notificationAppropriateToBubble || appIsForeground || bubbleUpdate); + /** + * @return whether the user has enabled the provided notification to bubble, does not account + * for policy. + */ + private boolean canBubble(NotificationRecord r, String pkg, int userId) { + Notification notification = r.getNotification(); + Notification.BubbleMetadata metadata = notification.getBubbleMetadata(); + if (metadata == null) { + // no log: no need to inform dev if they didn't attach bubble metadata + return false; + } + if (!canLaunchInActivityView(getContext(), metadata.getIntent(), pkg)) { + // no log: method has the failure log + return false; + } + if (!mPreferencesHelper.bubblesEnabled()) { + logBubbleError(r.getKey(), "bubbles disabled for user: " + userId); + return false; + } + if (!mPreferencesHelper.areBubblesAllowed(pkg, userId)) { + logBubbleError(r.getKey(), + "bubbles for package: " + pkg + " disabled for user: " + userId); + return false; + } + if (!r.getChannel().canBubble()) { + logBubbleError(r.getKey(), + "bubbles for channel " + r.getChannel().getId() + " disabled"); + return false; + } + return true; } private boolean hasValidRemoteInput(Notification n) { @@ -4889,6 +5007,11 @@ public class NotificationManagerService extends SystemService { return false; } + private void logBubbleError(String key, String failureMessage) { + if (DBG) { + Log.w(TAG, "Bubble notification: " + key + " failed: " + failureMessage); + } + } /** * Whether an intent is properly configured to display in an {@link android.app.ActivityView}. * @@ -5251,12 +5374,26 @@ public class NotificationManagerService extends SystemService { return; } + // Bubbled children get to stick around if the summary was manually cancelled + // (user removed) from systemui. + FlagChecker childrenFlagChecker = null; + if (mReason == REASON_CANCEL + || mReason == REASON_CLICK + || mReason == REASON_CANCEL_ALL) { + childrenFlagChecker = (flags) -> { + if ((flags & FLAG_BUBBLE) != 0) { + return false; + } + return true; + }; + } + // Cancel the notification. boolean wasPosted = removeFromNotificationListsLocked(r); cancelNotificationLocked( r, mSendDelete, mReason, mRank, mCount, wasPosted, listenerName); cancelGroupChildrenLocked(r, mCallingUid, mCallingPid, listenerName, - mSendDelete, null); + mSendDelete, childrenFlagChecker); updateLightsLocked(); } else { // No notification was found, assume that it is snoozed and cancel it. @@ -5339,11 +5476,18 @@ public class NotificationManagerService extends SystemService { } @GuardedBy("mNotificationLock") - private boolean isPackageSuspendedLocked(NotificationRecord r) { - final String pkg = r.sbn.getPackageName(); - final int callingUid = r.sbn.getUid(); + boolean isPackagePausedOrSuspended(String pkg, int uid) { + boolean isPaused; + + final PackageManagerInternal pmi = LocalServices.getService( + PackageManagerInternal.class); + int flags = pmi.getDistractingPackageRestrictions( + pkg, Binder.getCallingUserHandle().getIdentifier()); + isPaused = ((flags & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0); + + isPaused |= isPackageSuspendedForUser(pkg, uid); - return isPackageSuspendedForUser(pkg, callingUid); + return isPaused; } protected class PostNotificationRunnable implements Runnable { @@ -5376,7 +5520,8 @@ public class NotificationManagerService extends SystemService { return; } - final boolean isPackageSuspended = isPackageSuspendedLocked(r); + final boolean isPackageSuspended = + isPackagePausedOrSuspended(r.sbn.getPackageName(), r.getUid()); r.setHidden(isPackageSuspended); if (isPackageSuspended) { mUsageStats.registerSuspendedByAdmin(r); diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index 7b45a1b1997c..4835c97f0bb7 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -73,6 +73,9 @@ public class PreferencesHelper implements RankingConfig { private static final String NON_BLOCKABLE_CHANNEL_DELIM = ":"; @VisibleForTesting + static final int NOTIFICATION_CHANNEL_COUNT_LIMIT = 50000; + + @VisibleForTesting static final String TAG_RANKING = "ranking"; private static final String TAG_PACKAGE = "package"; private static final String TAG_CHANNEL = "channel"; @@ -100,7 +103,7 @@ public class PreferencesHelper implements RankingConfig { @VisibleForTesting static final boolean DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS = false; private static final boolean DEFAULT_SHOW_BADGE = true; - private static final boolean DEFAULT_ALLOW_BUBBLE = true; + static final boolean DEFAULT_ALLOW_BUBBLE = true; private static final boolean DEFAULT_OEM_LOCKED_IMPORTANCE = false; private static final boolean DEFAULT_APP_LOCKED_IMPORTANCE = false; @@ -130,7 +133,7 @@ public class PreferencesHelper implements RankingConfig { private final ZenModeHelper mZenModeHelper; private SparseBooleanArray mBadgingEnabled; - private SparseBooleanArray mBubblesEnabled; + private boolean mBubblesEnabled = DEFAULT_ALLOW_BUBBLE; private boolean mAreChannelsBypassingDnd; private boolean mHideSilentStatusBarIcons = DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS; @@ -179,6 +182,7 @@ public class PreferencesHelper implements RankingConfig { // noop } } + boolean skipWarningLogged = false; PackagePreferences r = getOrCreatePackagePreferencesLocked(name, uid, XmlUtils.readIntAttribute( @@ -225,6 +229,14 @@ public class PreferencesHelper implements RankingConfig { } // Channels if (TAG_CHANNEL.equals(tagName)) { + if (r.channels.size() >= NOTIFICATION_CHANNEL_COUNT_LIMIT) { + if (!skipWarningLogged) { + Slog.w(TAG, "Skipping further channels for " + r.pkg + + "; app has too many"); + skipWarningLogged = true; + } + continue; + } String id = parser.getAttributeValue(null, ATT_ID); String channelName = parser.getAttributeValue(null, ATT_NAME); int channelImportance = XmlUtils.readIntAttribute( @@ -690,6 +702,10 @@ public class PreferencesHelper implements RankingConfig { return needsPolicyFileChange; } + if (r.channels.size() >= NOTIFICATION_CHANNEL_COUNT_LIMIT) { + throw new IllegalStateException("Limit exceed; cannot create more channels"); + } + needsPolicyFileChange = true; if (channel.getImportance() < IMPORTANCE_NONE @@ -1818,40 +1834,19 @@ public class PreferencesHelper implements RankingConfig { } public void updateBubblesEnabled() { - if (mBubblesEnabled == null) { - mBubblesEnabled = new SparseBooleanArray(); - } - boolean changed = false; - // update the cached values - for (int index = 0; index < mBubblesEnabled.size(); index++) { - int userId = mBubblesEnabled.keyAt(index); - final boolean oldValue = mBubblesEnabled.get(userId); - final boolean newValue = Settings.Secure.getIntForUser(mContext.getContentResolver(), - Settings.Secure.NOTIFICATION_BUBBLES, - DEFAULT_ALLOW_BUBBLE ? 1 : 0, userId) != 0; - mBubblesEnabled.put(userId, newValue); - changed |= oldValue != newValue; - } - if (changed) { + final boolean newValue = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.NOTIFICATION_BUBBLES, + DEFAULT_ALLOW_BUBBLE ? 1 : 0) == 1; + if (newValue != mBubblesEnabled) { + mBubblesEnabled = newValue; updateConfig(); } } - public boolean bubblesEnabled(UserHandle userHandle) { - int userId = userHandle.getIdentifier(); - if (userId == UserHandle.USER_ALL) { - return false; - } - if (mBubblesEnabled.indexOfKey(userId) < 0) { - mBubblesEnabled.put(userId, - Settings.Secure.getIntForUser(mContext.getContentResolver(), - Settings.Secure.NOTIFICATION_BUBBLES, - DEFAULT_ALLOW_BUBBLE ? 1 : 0, userId) != 0); - } - return mBubblesEnabled.get(userId, DEFAULT_ALLOW_BUBBLE); + public boolean bubblesEnabled() { + return mBubblesEnabled; } - public void updateBadgingEnabled() { if (mBadgingEnabled == null) { mBadgingEnabled = new SparseBooleanArray(); diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java index 5de00e43a05d..7816f3619023 100644 --- a/services/core/java/com/android/server/notification/RankingConfig.java +++ b/services/core/java/com/android/server/notification/RankingConfig.java @@ -30,7 +30,7 @@ public interface RankingConfig { boolean canShowBadge(String packageName, int uid); boolean badgingEnabled(UserHandle userHandle); boolean areBubblesAllowed(String packageName, int uid); - boolean bubblesEnabled(UserHandle userHandle); + boolean bubblesEnabled(); boolean isGroupBlocked(String packageName, int uid, String groupId); Collection<NotificationChannelGroup> getNotificationChannelGroups(String pkg, diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java index c6af7566a8bd..8f05636eed9c 100644 --- a/services/core/java/com/android/server/notification/ZenLog.java +++ b/services/core/java/com/android/server/notification/ZenLog.java @@ -179,6 +179,7 @@ public class ZenLog { case TYPE_SUPPRESSOR_CHANGED: return "suppressor_changed"; case TYPE_LISTENER_HINTS_CHANGED: return "listener_hints_changed"; case TYPE_SET_NOTIFICATION_POLICY: return "set_notification_policy"; + case TYPE_SET_CONSOLIDATED_ZEN_POLICY: return "set_consolidated_policy"; default: return "unknown"; } } diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index f81015dae468..ebc41916d034 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -942,12 +942,11 @@ public class ZenModeHelper { } private void applyCustomPolicy(ZenPolicy policy, ZenRule rule) { - if (rule.zenMode == NotificationManager.INTERRUPTION_FILTER_NONE) { + if (rule.zenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) { policy.apply(new ZenPolicy.Builder() .disallowAllSounds() .build()); - } else if (rule.zenMode - == NotificationManager.INTERRUPTION_FILTER_ALARMS) { + } else if (rule.zenMode == Global.ZEN_MODE_ALARMS) { policy.apply(new ZenPolicy.Builder() .disallowAllSounds() .allowAlarms(true) diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java index da69986cd59f..965ddc9f2782 100644 --- a/services/core/java/com/android/server/om/OverlayManagerService.java +++ b/services/core/java/com/android/server/om/OverlayManagerService.java @@ -751,7 +751,7 @@ public final class OverlayManagerService extends SystemService { @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { final DumpState dumpState = new DumpState(); - dumpState.setUserId(UserHandle.getUserId(Binder.getCallingUid())); + dumpState.setUserId(UserHandle.USER_ALL); int opti = 0; while (opti < args.length) { @@ -771,13 +771,13 @@ public final class OverlayManagerService extends SystemService { pw.println(" so the following are equivalent: mState, mstate, State, state."); return; } else if ("--user".equals(opt)) { - opti++; if (opti >= args.length) { pw.println("Error: user missing argument"); return; } try { dumpState.setUserId(Integer.parseInt(args[opti])); + opti++; } catch (NumberFormatException e) { pw.println("Error: user argument is not a number: " + args[opti]); return; diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 0032e9a8ea51..e75f545eafaa 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -505,6 +505,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements params.installFlags &= ~PackageManager.INSTALL_REQUEST_DOWNGRADE; } + if (callingUid != Process.SYSTEM_UID) { + // Only system_server can use INSTALL_DISABLE_VERIFICATION. + params.installFlags &= ~PackageManager.INSTALL_DISABLE_VERIFICATION; + } + boolean isApex = (params.installFlags & PackageManager.INSTALL_APEX) != 0; if (params.isStaged || isApex) { mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, TAG); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index d7d73451e74b..f36d512e38e3 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -198,6 +198,7 @@ import android.content.pm.VersionedPackage; import android.content.pm.dex.ArtManager; import android.content.pm.dex.DexMetadataHelper; import android.content.pm.dex.IArtManager; +import android.content.pm.permission.SplitPermissionInfoParcelable; import android.content.res.Resources; import android.content.rollback.IRollbackManager; import android.database.ContentObserver; @@ -238,6 +239,7 @@ import android.os.storage.StorageManager; import android.os.storage.StorageManagerInternal; import android.os.storage.VolumeInfo; import android.os.storage.VolumeRecord; +import android.permission.PermissionManager; import android.provider.DeviceConfig; import android.provider.MediaStore; import android.provider.Settings.Global; @@ -2024,6 +2026,14 @@ public class PackageManagerService extends IPackageManager.Stub pkgList.add(packageName); sendResourcesChangedBroadcast(true, true, pkgList, uidArray, null); } + } else if (!ArrayUtils.isEmpty(res.libraryConsumers)) { // if static shared lib + for (int i = 0; i < res.libraryConsumers.size(); i++) { + PackageParser.Package pkg = res.libraryConsumers.get(i); + // send broadcast that all consumers of the static shared library have changed + sendPackageChangedBroadcast(pkg.packageName, false /*killFlag*/, + new ArrayList<>(Collections.singletonList(pkg.packageName)), + pkg.applicationInfo.uid); + } } // Work that needs to happen on first install within each user @@ -2122,6 +2132,12 @@ public class PackageManagerService extends IPackageManager.Stub } } + @Override + public List<SplitPermissionInfoParcelable> getSplitPermissions() { + return PermissionManager.splitPermissionInfoListToParcelableList( + SystemConfig.getInstance().getSplitPermissions()); + } + private void notifyInstallObserver(String packageName) { Pair<PackageInstalledInfo, IPackageInstallObserver2> pair = mNoKillInstallObservers.remove(packageName); @@ -12207,6 +12223,9 @@ public class PackageManagerService extends IPackageManager.Stub } } } + if (reconciledPkg.installResult != null) { + reconciledPkg.installResult.libraryConsumers = clientLibPkgs; + } if ((scanFlags & SCAN_BOOTING) != 0) { // No apps can run during boot scan, so they don't need to be frozen @@ -16060,6 +16079,8 @@ public class PackageManagerService extends IPackageManager.Stub String installerPackageName; PackageRemovedInfo removedInfo; ArrayMap<String, PackageInstalledInfo> addedChildPackages; + // The set of packages consuming this shared library or null if no consumers exist. + ArrayList<PackageParser.Package> libraryConsumers; public void setError(int code, String msg) { setReturnCode(code); @@ -18814,8 +18835,14 @@ public class PackageManagerService extends IPackageManager.Stub } } if (removedAppId >= 0) { + // If a system app's updates are uninstalled the UID is not actually removed. Some + // services need to know the package name affected. + if (extras.getBoolean(Intent.EXTRA_REPLACING, false)) { + extras.putString(Intent.EXTRA_PACKAGE_NAME, removedPackage); + } + packageSender.sendPackageBroadcast(Intent.ACTION_UID_REMOVED, - null, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, + null, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, null, null, broadcastUsers, instantUserIds); } } @@ -18904,19 +18931,20 @@ public class PackageManagerService extends IPackageManager.Stub // or packages running under the shared user of the removed // package if revoking the permissions requested only by the removed // package is successful and this causes a change in gids. + boolean shouldKill = false; for (int userId : UserManagerService.getInstance().getUserIds()) { final int userIdToKill = mSettings.updateSharedUserPermsLPw(deletedPs, userId); - if (userIdToKill == UserHandle.USER_ALL - || userIdToKill >= UserHandle.USER_SYSTEM) { - // If gids changed for this user, kill all affected packages. - mHandler.post(() -> { - // This has to happen with no lock held. - killApplication(deletedPs.name, deletedPs.appId, - KILL_APP_REASON_GIDS_CHANGED); - }); - break; - } + shouldKill |= userIdToKill == UserHandle.USER_ALL + || userIdToKill >= UserHandle.USER_SYSTEM; + } + // If gids changed, kill all affected packages. + if (shouldKill) { + mHandler.post(() -> { + // This has to happen with no lock held. + killApplication(deletedPs.name, deletedPs.appId, + KILL_APP_REASON_GIDS_CHANGED); + }); } } clearPackagePreferredActivitiesLPw( @@ -20873,7 +20901,7 @@ public class PackageManagerService extends IPackageManager.Stub public void sendSessionCommitBroadcast(PackageInstaller.SessionInfo sessionInfo, int userId) { UserManagerService ums = UserManagerService.getInstance(); - if (ums != null) { + if (ums != null && !sessionInfo.isStaged()) { final UserInfo parent = ums.getProfileParent(userId); final int launcherUid = (parent != null) ? parent.id : userId; final ComponentName launcherComponent = getDefaultHomeActivity(launcherUid); diff --git a/services/core/java/com/android/server/pm/ProtectedPackages.java b/services/core/java/com/android/server/pm/ProtectedPackages.java index a374e1484b28..231168e9c660 100644 --- a/services/core/java/com/android/server/pm/ProtectedPackages.java +++ b/services/core/java/com/android/server/pm/ProtectedPackages.java @@ -92,6 +92,9 @@ public class ProtectedPackages { if (mDeviceOwnerUserId == userId) { return mDeviceOwnerPackage; } + if (mProfileOwnerPackages == null) { + return null; + } return mProfileOwnerPackages.get(userId); } diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index 5870986a264f..2eedf0c696e2 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -190,6 +190,7 @@ public final class DefaultPermissionGrantPolicy { static { STORAGE_PERMISSIONS.add(Manifest.permission.READ_EXTERNAL_STORAGE); STORAGE_PERMISSIONS.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); + STORAGE_PERMISSIONS.add(Manifest.permission.ACCESS_MEDIA_LOCATION); } private static final int MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS = 1; diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 6a7c622b7e33..6fced8acf1df 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -967,10 +967,12 @@ public class PermissionManagerService { // or has updated its target SDK and AR is no longer implicit to it. // This is a compatibility workaround for apps when AR permission was // split in Q. - int numSplitPerms = PermissionManager.SPLIT_PERMISSIONS.size(); + final List<PermissionManager.SplitPermissionInfo> permissionList = + getSplitPermissions(); + int numSplitPerms = permissionList.size(); for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) { PermissionManager.SplitPermissionInfo sp = - PermissionManager.SPLIT_PERMISSIONS.get(splitPermNum); + permissionList.get(splitPermNum); String splitPermName = sp.getSplitPermission(); if (sp.getNewPermissions().contains(permName) && origPermissions.hasInstallPermission(splitPermName)) { @@ -1537,10 +1539,10 @@ public class PermissionManagerService { String pkgName = pkg.packageName; ArrayMap<String, ArraySet<String>> newToSplitPerms = new ArrayMap<>(); - int numSplitPerms = PermissionManager.SPLIT_PERMISSIONS.size(); + final List<PermissionManager.SplitPermissionInfo> permissionList = getSplitPermissions(); + int numSplitPerms = permissionList.size(); for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) { - PermissionManager.SplitPermissionInfo spi = - PermissionManager.SPLIT_PERMISSIONS.get(splitPermNum); + PermissionManager.SplitPermissionInfo spi = permissionList.get(splitPermNum); List<String> newPerms = spi.getNewPermissions(); int numNewPerms = newPerms.size(); @@ -1595,8 +1597,6 @@ public class PermissionManagerService { Slog.i(TAG, newPerm + " does not inherit from " + sourcePerms + " for " + pkgName + " as split permission is also new"); } - - break; } else { // Inherit from new install or existing runtime permissions inheritPermissionStateToNewImplicitPermissionLocked(sourcePerms, @@ -1610,6 +1610,10 @@ public class PermissionManagerService { return updatedUserIds; } + private List<PermissionManager.SplitPermissionInfo> getSplitPermissions() { + return SystemConfig.getInstance().getSplitPermissions(); + } + private boolean isNewPlatformPermissionForPackage(String perm, PackageParser.Package pkg) { boolean allowed = false; final int NP = PackageParser.NEW_PERMISSIONS.length; @@ -2035,16 +2039,6 @@ public class PermissionManagerService { return whitelistedPermissions; } - private void setWhitelistedRestrictedPermissions(@NonNull PackageParser.Package pkg, - @NonNull int[] userIds, @Nullable List<String> permissions, int callingUid, - @PackageManager.PermissionWhitelistFlags int whitelistFlags, - @NonNull PermissionCallback callback) { - for (int userId : userIds) { - setWhitelistedRestrictedPermissionsForUser(pkg, userId, permissions, - callingUid, whitelistFlags, callback); - } - } - private void grantRequestedRuntimePermissionsForUser(PackageParser.Package pkg, int userId, String[] grantedPermissions, int callingUid, PermissionCallback callback) { PackageSetting ps = (PackageSetting) pkg.mExtras; @@ -2325,109 +2319,122 @@ public class PermissionManagerService { } } - private void setWhitelistedRestrictedPermissionsForUser(@NonNull PackageParser.Package pkg, - @UserIdInt int userId, @Nullable List<String> permissions, int callingUid, - @PermissionWhitelistFlags int whitelistFlags, PermissionCallback callback) { + private void setWhitelistedRestrictedPermissions(@NonNull PackageParser.Package pkg, + @NonNull int[] userIds, @Nullable List<String> permissions, int callingUid, + @PackageManager.PermissionWhitelistFlags int whitelistFlags, + @NonNull PermissionCallback callback) { + final PackageSetting ps = (PackageSetting) pkg.mExtras; if (ps == null) { return; } final PermissionsState permissionsState = ps.getPermissionsState(); - - ArraySet<String> oldGrantedRestrictedPermissions = null; + SparseArray<ArraySet<String>> oldGrantedRestrictedPermissionsByUser = new SparseArray<>(); boolean updatePermissions = false; final int permissionCount = pkg.requestedPermissions.size(); - for (int i = 0; i < permissionCount; i++) { - final String permissionName = pkg.requestedPermissions.get(i); - - final BasePermission bp = mSettings.getPermissionLocked(permissionName); - if (bp == null) { - Slog.w(TAG, "Cannot whitelist unknown permission: " + permissionName); - continue; - } + for (int userId : userIds) { + for (int i = 0; i < permissionCount; i++) { + final String permissionName = pkg.requestedPermissions.get(i); - if (!bp.isHardOrSoftRestricted()) { - continue; - } + final BasePermission bp = mSettings.getPermissionLocked(permissionName); + if (bp == null) { + Slog.w(TAG, "Cannot whitelist unknown permission: " + permissionName); + continue; + } - if (permissionsState.hasPermission(permissionName, userId)) { - if (oldGrantedRestrictedPermissions == null) { - oldGrantedRestrictedPermissions = new ArraySet<>(); + if (!bp.isHardOrSoftRestricted()) { + continue; } - oldGrantedRestrictedPermissions.add(permissionName); - } - final int oldFlags = permissionsState.getPermissionFlags(permissionName, userId); + if (permissionsState.hasPermission(permissionName, userId)) { + if (oldGrantedRestrictedPermissionsByUser.get(userId) == null) { + oldGrantedRestrictedPermissionsByUser.put(userId, new ArraySet<>()); + } + oldGrantedRestrictedPermissionsByUser.get(userId).add(permissionName); + } - int newFlags = oldFlags; - int mask = 0; - int whitelistFlagsCopy = whitelistFlags; - while (whitelistFlagsCopy != 0) { - final int flag = 1 << Integer.numberOfTrailingZeros(whitelistFlagsCopy); - whitelistFlagsCopy &= ~flag; - switch (flag) { - case FLAG_PERMISSION_WHITELIST_SYSTEM: { - mask |= PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT; - if (permissions != null && permissions.contains(permissionName)) { - newFlags |= PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT; - } else { - newFlags &= ~PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT; + final int oldFlags = permissionsState.getPermissionFlags(permissionName, userId); + + int newFlags = oldFlags; + int mask = 0; + int whitelistFlagsCopy = whitelistFlags; + while (whitelistFlagsCopy != 0) { + final int flag = 1 << Integer.numberOfTrailingZeros(whitelistFlagsCopy); + whitelistFlagsCopy &= ~flag; + switch (flag) { + case FLAG_PERMISSION_WHITELIST_SYSTEM: { + mask |= PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT; + if (permissions != null && permissions.contains(permissionName)) { + newFlags |= + PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT; + } else { + newFlags &= + ~PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT; + } } - } break; - case FLAG_PERMISSION_WHITELIST_UPGRADE: { - mask |= PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT; - if (permissions != null && permissions.contains(permissionName)) { - newFlags |= PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT; - } else { - newFlags &= ~PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT; + break; + case FLAG_PERMISSION_WHITELIST_UPGRADE: { + mask |= PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT; + if (permissions != null && permissions.contains(permissionName)) { + newFlags |= + PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT; + } else { + newFlags &= + ~PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT; + } } - } break; - case FLAG_PERMISSION_WHITELIST_INSTALLER: { - mask |= PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT; - if (permissions != null && permissions.contains(permissionName)) { - newFlags |= PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT; - } else { - newFlags &= ~PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT; + break; + case FLAG_PERMISSION_WHITELIST_INSTALLER: { + mask |= PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT; + if (permissions != null && permissions.contains(permissionName)) { + newFlags |= + PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT; + } else { + newFlags &= ~PackageManager + .FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT; + } } - } break; + break; + } } - } - - if (oldFlags == newFlags) { - continue; - } - updatePermissions = true; + if (oldFlags == newFlags) { + continue; + } - final boolean wasWhitelisted = (oldFlags - & (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0; - final boolean isWhitelisted = (newFlags - & (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0; + updatePermissions = true; + + final boolean wasWhitelisted = (oldFlags + & (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0; + final boolean isWhitelisted = (newFlags + & (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0; + + // If the permission is policy fixed as granted but it is no longer + // on any of the whitelists we need to clear the policy fixed flag + // as whitelisting trumps policy i.e. policy cannot grant a non + // grantable permission. + if ((oldFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) { + final boolean isGranted = permissionsState.hasPermission(permissionName, + userId); + if (!isWhitelisted && isGranted) { + mask |= PackageManager.FLAG_PERMISSION_POLICY_FIXED; + newFlags &= ~PackageManager.FLAG_PERMISSION_POLICY_FIXED; + } + } - // If the permission is policy fixed as granted but it is no longer - // on any of the whitelists we need to clear the policy fixed flag - // as whitelisting trumps policy i.e. policy cannot grant a non - // grantable permission. - if ((oldFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) { - final boolean isGranted = permissionsState.hasPermission(permissionName, userId); - if (!isWhitelisted && isGranted) { - mask |= PackageManager.FLAG_PERMISSION_POLICY_FIXED; - newFlags &= ~PackageManager.FLAG_PERMISSION_POLICY_FIXED; + // If we are whitelisting an app that does not support runtime permissions + // we need to make sure it goes through the permission review UI at launch. + if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M + && !wasWhitelisted && isWhitelisted) { + mask |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED; + newFlags |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED; } - } - // If we are whitelisting an app that does not support runtime permissions - // we need to make sure it goes through the permission review UI at launch. - if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M - && !wasWhitelisted && isWhitelisted) { - mask |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED; - newFlags |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED; + updatePermissionFlags(permissionName, pkg.packageName, mask, newFlags, + callingUid, userId, false, null /*callback*/); } - - updatePermissionFlags(permissionName, pkg.packageName, mask, newFlags, - callingUid, userId, false, null /*callback*/); } if (updatePermissions) { @@ -2435,7 +2442,12 @@ public class PermissionManagerService { restorePermissionState(pkg, false, pkg.packageName, callback); // If this resulted in losing a permission we need to kill the app. - if (oldGrantedRestrictedPermissions != null) { + int oldGrantedRestrictedPermissionsByUserCount = + oldGrantedRestrictedPermissionsByUser.size(); + for (int j = 0; j < oldGrantedRestrictedPermissionsByUserCount; j++) { + final int userId = oldGrantedRestrictedPermissionsByUser.keyAt(j); + final ArraySet<String> oldGrantedRestrictedPermissions = + oldGrantedRestrictedPermissionsByUser.valueAt(j); final int oldGrantedCount = oldGrantedRestrictedPermissions.size(); for (int i = 0; i < oldGrantedCount; i++) { final String permission = oldGrantedRestrictedPermissions.valueAt(i); diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 21b13fe234e0..48056b47e1bd 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -107,6 +107,7 @@ import android.app.ActivityManagerInternal; import android.app.ActivityTaskManager; import android.app.AppOpsManager; import android.app.IUiModeManager; +import android.app.NotificationManager; import android.app.ProgressDialog; import android.app.SearchManager; import android.app.UiModeManager; @@ -2572,6 +2573,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { return (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE); } + NotificationManager getNotificationService() { + return mContext.getSystemService(NotificationManager.class); + } + static IAudioService getAudioService() { IAudioService audioService = IAudioService.Stub.asInterface( ServiceManager.checkService(Context.AUDIO_SERVICE)); @@ -3806,6 +3811,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (down) { sendSystemKeyToStatusBarAsync(event.getKeyCode()); + NotificationManager nm = getNotificationService(); + if (nm != null && !mHandleVolumeKeysInWM) { + nm.silenceNotificationSound(); + } + TelecomManager telecomManager = getTelecommService(); if (telecomManager != null && !mHandleVolumeKeysInWM) { // When {@link #mHandleVolumeKeysInWM} is set, volume key events diff --git a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java index 77bf930fb4d7..712012d9e621 100644 --- a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java +++ b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java @@ -24,20 +24,17 @@ import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ResolveInfo; -import android.os.Debug; import android.provider.Settings; -import android.telecom.TelecomManager; import android.text.TextUtils; -import android.util.Log; import android.util.Slog; +import com.android.internal.R; import com.android.internal.telephony.SmsApplication; import com.android.internal.util.CollectionUtils; import com.android.server.LocalServices; import com.android.server.role.RoleManagerService; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.List; @@ -67,14 +64,25 @@ public class LegacyRoleResolutionPolicy implements RoleManagerService.RoleHolder public List<String> getRoleHolders(@NonNull String roleName, @UserIdInt int userId) { switch (roleName) { case RoleManager.ROLE_ASSISTANT: { - String legacyAssistant = Settings.Secure.getStringForUser( - mContext.getContentResolver(), Settings.Secure.ASSISTANT, userId); - if (legacyAssistant == null || legacyAssistant.isEmpty()) { - return Collections.emptyList(); + String packageName; + String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(), + Settings.Secure.ASSISTANT, userId); + // AssistUtils was using the default assistant app if Settings.Secure.ASSISTANT is + // null, while only an empty string means user selected "None". + if (setting != null) { + if (!setting.isEmpty()) { + ComponentName componentName = ComponentName.unflattenFromString(setting); + packageName = componentName != null ? componentName.getPackageName() : null; + } else { + packageName = null; + } + } else if (mContext.getPackageManager().isDeviceUpgrading()) { + String defaultAssistant = mContext.getString(R.string.config_defaultAssistant); + packageName = !TextUtils.isEmpty(defaultAssistant) ? defaultAssistant : null; } else { - return Collections.singletonList( - ComponentName.unflattenFromString(legacyAssistant).getPackageName()); + packageName = null; } + return CollectionUtils.singletonOrEmpty(packageName); } case RoleManager.ROLE_BROWSER: { PackageManagerInternal packageManagerInternal = LocalServices.getService( @@ -84,44 +92,36 @@ public class LegacyRoleResolutionPolicy implements RoleManagerService.RoleHolder return CollectionUtils.singletonOrEmpty(packageName); } case RoleManager.ROLE_DIALER: { - String setting = Settings.Secure.getStringForUser( - mContext.getContentResolver(), + String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(), Settings.Secure.DIALER_DEFAULT_APPLICATION, userId); - return CollectionUtils.singletonOrEmpty(!TextUtils.isEmpty(setting) - ? setting - : mContext.getSystemService(TelecomManager.class).getSystemDialerPackage()); + String packageName; + if (!TextUtils.isEmpty(setting)) { + packageName = setting; + } else if (mContext.getPackageManager().isDeviceUpgrading()) { + // DefaultDialerManager was using the default dialer app if + // Settings.Secure.DIALER_DEFAULT_APPLICATION is invalid. + // TelecomManager.getSystemDialerPackage() won't work because it might not + // be ready. + packageName = mContext.getString(R.string.config_defaultDialer); + } else { + packageName = null; + } + return CollectionUtils.singletonOrEmpty(packageName); } case RoleManager.ROLE_SMS: { - // Moved over from SmsApplication#getApplication - String result = Settings.Secure.getStringForUser( - mContext.getContentResolver(), + String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(), Settings.Secure.SMS_DEFAULT_APPLICATION, userId); - // TODO: STOPSHIP: Remove the following code once we read the value of - // config_defaultSms in RoleControllerService. - if (result == null) { - Collection<SmsApplication.SmsApplicationData> applications = - SmsApplication.getApplicationCollectionAsUser(mContext, userId); - SmsApplication.SmsApplicationData applicationData; - String defaultPackage = mContext.getResources() - .getString(com.android.internal.R.string.default_sms_application); - applicationData = - SmsApplication.getApplicationForPackage(applications, defaultPackage); - - if (applicationData == null) { - // Are there any applications? - if (applications.size() != 0) { - applicationData = - (SmsApplication.SmsApplicationData) applications.toArray()[0]; - } - } - if (DEBUG) { - Log.i(LOG_TAG, "Found default sms app: " + applicationData - + " among: " + applications + " from " + Debug.getCallers(4)); - } - SmsApplication.SmsApplicationData app = applicationData; - result = app == null ? null : app.mPackageName; + String packageName; + if (!TextUtils.isEmpty(setting)) { + packageName = setting; + } else if (mContext.getPackageManager().isDeviceUpgrading()) { + // SmsApplication was using the default SMS app if + // Settings.Secure.DIALER_DEFAULT_APPLICATION is invalid. + packageName = mContext.getString(R.string.config_defaultSms); + } else { + packageName = null; } - return CollectionUtils.singletonOrEmpty(result); + return CollectionUtils.singletonOrEmpty(packageName); } case RoleManager.ROLE_HOME: { PackageManager packageManager = mContext.getPackageManager(); diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index aa49ba62f48b..e1b3e4d6fbcf 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -542,6 +542,10 @@ public final class PowerManagerService extends SystemService // True if we in the process of performing a forceSuspend private boolean mForceSuspendActive; + // Transition to Doze is in progress. We have transitioned to WAKEFULNESS_DOZING, + // but the DreamService has not yet been told to start (it's an async process). + private boolean mDozeStartInProgress; + private final class ForegroundProfileObserver extends SynchronousUserSwitchObserver { @Override public void onUserSwitching(int newUserId) throws RemoteException {} @@ -1514,6 +1518,7 @@ public final class PowerManagerService extends SystemService mLastSleepTime = eventTime; mLastSleepReason = reason; mSandmanSummoned = true; + mDozeStartInProgress = true; setWakefulnessLocked(WAKEFULNESS_DOZING, reason, eventTime); // Report the number of wake locks that will be cleared by going to sleep. @@ -1601,6 +1606,10 @@ public final class PowerManagerService extends SystemService mWakefulness = wakefulness; mWakefulnessChanging = true; mDirty |= DIRTY_WAKEFULNESS; + + // This is only valid while we are in wakefulness dozing. Set to false otherwise. + mDozeStartInProgress &= (mWakefulness == WAKEFULNESS_DOZING); + if (mNotifier != null) { mNotifier.onWakefulnessChangeStarted(wakefulness, reason, eventTime); } @@ -1631,6 +1640,9 @@ public final class PowerManagerService extends SystemService if (mWakefulness == WAKEFULNESS_DOZING && (mWakeLockSummary & WAKE_LOCK_DOZE) == 0) { return; // wait until dream has enabled dozing + } else { + // Doze wakelock acquired (doze started) or device is no longer dozing. + mDozeStartInProgress = false; } if (mWakefulness == WAKEFULNESS_DOZING || mWakefulness == WAKEFULNESS_ASLEEP) { logSleepTimeoutRecapturedLocked(); @@ -2309,6 +2321,10 @@ public final class PowerManagerService extends SystemService isDreaming = false; } + // At this point, we either attempted to start the dream or no attempt will be made, + // so stop holding the display suspend blocker for Doze. + mDozeStartInProgress = false; + // Update dream state. synchronized (mLock) { // Remember the initial battery level when the dream started. @@ -2735,6 +2751,16 @@ public final class PowerManagerService extends SystemService if (mScreenBrightnessBoostInProgress) { return true; } + + // When we transition to DOZING, we have to keep the display suspend blocker + // up until the Doze service has a change to acquire the DOZE wakelock. + // Here we wait for mWakefulnessChanging to become false since the wakefulness + // transition to DOZING isn't considered "changed" until the doze wake lock is + // acquired. + if (mWakefulness == WAKEFULNESS_DOZING && mDozeStartInProgress) { + return true; + } + // Let the system suspend if the screen is off or dozing. return false; } diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java index 1552fd517d30..491c5ab2ac03 100644 --- a/services/core/java/com/android/server/power/ThermalManagerService.java +++ b/services/core/java/com/android/server/power/ThermalManagerService.java @@ -38,11 +38,13 @@ import android.os.ShellCallback; import android.os.ShellCommand; import android.os.Temperature; import android.util.ArrayMap; +import android.util.EventLog; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.DumpUtils; +import com.android.server.EventLogTags; import com.android.server.FgThread; import com.android.server.SystemService; @@ -250,6 +252,8 @@ public class ThermalManagerService extends SystemService { } finally { mThermalEventListeners.finishBroadcast(); } + EventLog.writeEvent(EventLogTags.THERMAL_CHANGED, temperature.getName(), + temperature.getType(), temperature.getValue(), temperature.getStatus(), mStatus); } private void shutdownIfNeeded(Temperature temperature) { @@ -860,10 +864,10 @@ public class ThermalManagerService extends SystemService { mThermalHal11.linkToDeath(new DeathRecipient(), THERMAL_HAL_DEATH_COOKIE); mThermalHal11.registerThermalCallback(mThermalCallback11); + Slog.i(TAG, "Thermal HAL 1.1 service connected, limited thermal functions " + + "due to legacy API."); } catch (NoSuchElementException | RemoteException e) { - Slog.e(TAG, - "Thermal HAL 1.1 service not connected, no thermal call back will be " - + "called."); + Slog.e(TAG, "Thermal HAL 1.1 service not connected."); mThermalHal11 = null; } return (mThermalHal11 != null); @@ -978,8 +982,9 @@ public class ThermalManagerService extends SystemService { mThermalHal20.linkToDeath(new DeathRecipient(), THERMAL_HAL_DEATH_COOKIE); mThermalHal20.registerThermalChangedCallback(mThermalCallback20, false, 0 /* not used */); + Slog.i(TAG, "Thermal HAL 2.0 service connected."); } catch (NoSuchElementException | RemoteException e) { - Slog.e(TAG, "Thermal HAL 2.0 service not connected, trying 1.1."); + Slog.e(TAG, "Thermal HAL 2.0 service not connected."); mThermalHal20 = null; } return (mThermalHal20 != null); diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index e107c9aedf38..08c1bb536211 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -86,9 +86,9 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { private static final String TAG = "RollbackManager"; - // Rollbacks expire after 48 hours. + // Rollbacks expire after 14 days. private static final long DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS = - TimeUnit.HOURS.toMillis(48); + TimeUnit.DAYS.toMillis(14); // Lock used to synchronize accesses to in-memory rollback data // structures. By convention, methods with the suffix "Locked" require @@ -1289,7 +1289,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { private boolean packageVersionsEqual(VersionedPackage a, VersionedPackage b) { - return a.getPackageName().equals(b.getPackageName()) + return a != null && b != null + && a.getPackageName().equals(b.getPackageName()) && a.getLongVersionCode() == b.getLongVersionCode(); } diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 9908b3657121..b0f1e5d69be4 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -1172,8 +1172,16 @@ public class WallpaperManagerService extends IWallpaperManager.Stub return false; } final int displayId = display.getDisplayId(); - return displayId == DEFAULT_DISPLAY - || mWindowManagerInternal.shouldShowSystemDecorOnDisplay(displayId); + if (displayId == DEFAULT_DISPLAY) { + return true; + } + + final long ident = Binder.clearCallingIdentity(); + try { + return mWindowManagerInternal.shouldShowSystemDecorOnDisplay(displayId); + } finally { + Binder.restoreCallingIdentity(ident); + } } void forEachDisplayConnector(Consumer<DisplayConnector> action) { diff --git a/services/core/java/com/android/server/webkit/WebViewUpdater.java b/services/core/java/com/android/server/webkit/WebViewUpdater.java index a460040d0a60..3b58af2a200f 100644 --- a/services/core/java/com/android/server/webkit/WebViewUpdater.java +++ b/services/core/java/com/android/server/webkit/WebViewUpdater.java @@ -87,19 +87,6 @@ class WebViewUpdater { newPackage = findPreferredWebViewPackage(); if (mCurrentWebViewPackage != null) { oldProviderName = mCurrentWebViewPackage.packageName; - if (changedState == WebViewUpdateService.PACKAGE_CHANGED - && newPackage.packageName.equals(oldProviderName)) { - // If we don't change package name we should only rerun the - // preparation phase if the current package has been replaced - // (not if it has been enabled/disabled). - return; - } - if (newPackage.packageName.equals(oldProviderName) - && (newPackage.lastUpdateTime - == mCurrentWebViewPackage.lastUpdateTime)) { - // If the chosen package hasn't been updated, then early-out - return; - } } // Only trigger update actions if the updated package is the one // that will be used, or the one that was in use before the diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index 4cfc1d1df2ae..afd6674edfa8 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -907,7 +907,7 @@ final class AccessibilityController { } public void releaseSurface() { - mSurfaceControl.remove(); + mService.mTransactionFactory.make().remove(mSurfaceControl).apply(); mSurface.release(); } diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index a18a53dfea92..242139cd2da7 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -5231,18 +5231,28 @@ class ActivityStack extends ConfigurationContainer { * then skip running tasks that match those types. */ void getRunningTasks(List<TaskRecord> tasksOut, @ActivityType int ignoreActivityType, - @WindowingMode int ignoreWindowingMode, int callingUid, boolean allowed) { + @WindowingMode int ignoreWindowingMode, int callingUid, boolean allowed, + boolean crossUser, ArraySet<Integer> profileIds) { boolean focusedStack = mRootActivityContainer.getTopDisplayFocusedStack() == this; boolean topTask = true; + int userId = UserHandle.getUserId(callingUid); for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { final TaskRecord task = mTaskHistory.get(taskNdx); if (task.getTopActivity() == null) { // Skip if there are no activities in the task continue; } - if (!allowed && !task.isActivityTypeHome() && task.effectiveUid != callingUid) { - // Skip if the caller can't fetch this task - continue; + if (task.effectiveUid != callingUid) { + if (task.userId != userId && !crossUser && !profileIds.contains(task.userId)) { + // Skip if the caller does not have cross user permission or cannot access + // the task's profile + continue; + } + if (!allowed && !task.isActivityTypeHome()) { + // Skip if the caller isn't allowed to fetch this task, except for the home + // task which we always return. + continue; + } } if (ignoreActivityType != ACTIVITY_TYPE_UNDEFINED && task.getActivityType() == ignoreActivityType) { @@ -5458,6 +5468,7 @@ class ActivityStack extends ConfigurationContainer { task.cleanUpResourcesForDestroy(); } + final ActivityDisplay display = getDisplay(); if (mTaskHistory.isEmpty()) { if (DEBUG_STACK) Slog.i(TAG_STACK, "removeTask: removing stack=" + this); // We only need to adjust focused stack if this stack is in focus and we are not in the @@ -5466,11 +5477,11 @@ class ActivityStack extends ConfigurationContainer { && mRootActivityContainer.isTopDisplayFocusedStack(this)) { String myReason = reason + " leftTaskHistoryEmpty"; if (!inMultiWindowMode() || adjustFocusToNextFocusableStack(myReason) == null) { - getDisplay().moveHomeStackToFront(myReason); + display.moveHomeStackToFront(myReason); } } if (isAttached()) { - getDisplay().positionChildAtBottom(this); + display.positionChildAtBottom(this); } if (!isActivityTypeHome() || !isAttached()) { remove(); @@ -5483,6 +5494,9 @@ class ActivityStack extends ConfigurationContainer { if (inPinnedWindowingMode()) { mService.getTaskChangeNotificationController().notifyActivityUnpinned(); } + if (display.isSingleTaskInstance()) { + mService.notifySingleTaskDisplayEmpty(display.mDisplayId); + } } TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent, diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 5a1eed8897b6..5b697ee89602 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -2700,7 +2700,8 @@ class ActivityStarter { || mPreferredDisplayId != DEFAULT_DISPLAY) { final boolean onTop = aOptions == null || !aOptions.getAvoidMoveToFront(); final ActivityStack stack = - mRootActivityContainer.getLaunchStack(r, aOptions, task, onTop, mLaunchParams); + mRootActivityContainer.getLaunchStack(r, aOptions, task, onTop, mLaunchParams, + mRequest.realCallingPid, mRequest.realCallingUid); return stack; } // Otherwise handle adjacent launch. @@ -2818,11 +2819,24 @@ class ActivityStarter { return this; } + /** + * Sets the pid of the caller who originally started the activity. + * + * Normally, the pid/uid would be the calling pid from the binder call. + * However, in case of a {@link PendingIntent}, the pid/uid pair of the caller is considered + * the original entity that created the pending intent, in contrast to setRealCallingPid/Uid, + * which represents the entity who invoked pending intent via {@link PendingIntent#send}. + */ ActivityStarter setCallingPid(int pid) { mRequest.callingPid = pid; return this; } + /** + * Sets the uid of the caller who originally started the activity. + * + * @see #setCallingPid + */ ActivityStarter setCallingUid(int uid) { mRequest.callingUid = uid; return this; @@ -2833,11 +2847,25 @@ class ActivityStarter { return this; } + /** + * Sets the pid of the caller who requested to launch the activity. + * + * The pid/uid represents the caller who launches the activity in this request. + * It will almost same as setCallingPid/Uid except when processing {@link PendingIntent}: + * the pid/uid will be the caller who called {@link PendingIntent#send()}. + * + * @see #setCallingPid + */ ActivityStarter setRealCallingPid(int pid) { mRequest.realCallingPid = pid; return this; } + /** + * Sets the uid of the caller who requested to launch the activity. + * + * @see #setRealCallingPid + */ ActivityStarter setRealCallingUid(int uid) { mRequest.realCallingUid = uid; return this; diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 747837bc933f..223205377bb9 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -19,6 +19,8 @@ package com.android.server.wm; import static android.Manifest.permission.BIND_VOICE_INTERACTION; import static android.Manifest.permission.CHANGE_CONFIGURATION; import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS; +import static android.Manifest.permission.INTERACT_ACROSS_USERS; +import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS; import static android.Manifest.permission.READ_FRAME_BUFFER; @@ -213,6 +215,7 @@ import android.telecom.TelecomManager; import android.text.TextUtils; import android.text.format.Time; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.EventLog; import android.util.Log; import android.util.Slog; @@ -2522,15 +2525,22 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @WindowConfiguration.ActivityType int ignoreActivityType, @WindowConfiguration.WindowingMode int ignoreWindowingMode) { final int callingUid = Binder.getCallingUid(); + final int callingPid = Binder.getCallingPid(); + final boolean crossUser = isCrossUserAllowed(callingPid, callingUid); + final int[] profileIds = getUserManager().getProfileIds( + UserHandle.getUserId(callingUid), true); + ArraySet<Integer> callingProfileIds = new ArraySet<>(); + for (int i = 0; i < profileIds.length; i++) { + callingProfileIds.add(profileIds[i]); + } ArrayList<ActivityManager.RunningTaskInfo> list = new ArrayList<>(); synchronized (mGlobalLock) { if (DEBUG_ALL) Slog.v(TAG, "getTasks: max=" + maxNum); - final boolean allowed = isGetTasksAllowed("getTasks", Binder.getCallingPid(), - callingUid); + final boolean allowed = isGetTasksAllowed("getTasks", callingPid, callingUid); mRootActivityContainer.getRunningTasks(maxNum, list, ignoreActivityType, - ignoreWindowingMode, callingUid, allowed); + ignoreWindowingMode, callingUid, allowed, crossUser, callingProfileIds); } return list; @@ -3587,6 +3597,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return allowed; } + boolean isCrossUserAllowed(int pid, int uid) { + return checkPermission(INTERACT_ACROSS_USERS, pid, uid) == PERMISSION_GRANTED + || checkPermission(INTERACT_ACROSS_USERS_FULL, pid, uid) == PERMISSION_GRANTED; + } + private PendingAssistExtras enqueueAssistContext(int requestType, Intent intent, String hint, IAssistDataReceiver receiver, Bundle receiverExtras, IBinder activityToken, boolean focused, boolean newSessionId, int userHandle, Bundle args, long timeout, @@ -6048,6 +6063,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return allUids.contains(uid); } + void notifySingleTaskDisplayEmpty(int displayId) { + mTaskChangeNotificationController.notifySingleTaskDisplayEmpty(displayId); + } + final class H extends Handler { static final int REPORT_TIME_TRACKER_MSG = 1; diff --git a/services/core/java/com/android/server/wm/BlackFrame.java b/services/core/java/com/android/server/wm/BlackFrame.java index 84ba5ca94f8c..7fc17e1e8462 100644 --- a/services/core/java/com/android/server/wm/BlackFrame.java +++ b/services/core/java/com/android/server/wm/BlackFrame.java @@ -97,6 +97,7 @@ public class BlackFrame { final BlackSurface[] mBlackSurfaces = new BlackSurface[4]; final boolean mForceDefaultOrientation; + private final TransactionFactory mTransactionFactory; public void printTo(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("Outer: "); mOuterRect.printShortString(pw); @@ -111,11 +112,12 @@ public class BlackFrame { } } - public BlackFrame(SurfaceControl.Transaction t, - Rect outer, Rect inner, int layer, DisplayContent dc, - boolean forceDefaultOrientation) throws OutOfResourcesException { + public BlackFrame(TransactionFactory factory, SurfaceControl.Transaction t, Rect outer, + Rect inner, int layer, DisplayContent dc, boolean forceDefaultOrientation) + throws OutOfResourcesException { boolean success = false; + mTransactionFactory = factory; mForceDefaultOrientation = forceDefaultOrientation; // TODO: Why do we use 4 surfaces instead of just one big one behind the screenshot? @@ -149,14 +151,16 @@ public class BlackFrame { public void kill() { if (mBlackSurfaces != null) { + SurfaceControl.Transaction t = mTransactionFactory.make(); for (int i=0; i<mBlackSurfaces.length; i++) { if (mBlackSurfaces[i] != null) { if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG_WM, " BLACK " + mBlackSurfaces[i].surface + ": DESTROY"); - mBlackSurfaces[i].surface.remove(); + t.remove(mBlackSurfaces[i].surface); mBlackSurfaces[i] = null; } } + t.apply(); } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index e099a4f0c91c..3e7fea2ac203 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -1072,9 +1072,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // removing from parent. token.getParent().removeChild(token); } - if (prevDc.mLastFocus == mCurrentFocus) { - // The window has become the focus of this display, so it should not be notified - // that it lost focus from the previous display. + if (token.hasChild(prevDc.mLastFocus)) { + // If the reparent window token contains previous display's last focus window, means + // it will end up to gain window focus on the target display, so it should not be + // notified that it lost focus from the previous display. prevDc.mLastFocus = null; } } @@ -4589,13 +4590,15 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo .show(mSplitScreenDividerAnchor); scheduleAnimation(); } else { - mAppAnimationLayer.remove(); + mWmService.mTransactionFactory.make() + .remove(mAppAnimationLayer) + .remove(mBoostedAppAnimationLayer) + .remove(mHomeAppAnimationLayer) + .remove(mSplitScreenDividerAnchor) + .apply(); mAppAnimationLayer = null; - mBoostedAppAnimationLayer.remove(); mBoostedAppAnimationLayer = null; - mHomeAppAnimationLayer.remove(); mHomeAppAnimationLayer = null; - mSplitScreenDividerAnchor.remove(); mSplitScreenDividerAnchor = null; } } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index ed7dbd05853a..99a9db316c63 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -3622,7 +3622,8 @@ public class DisplayPolicy { if (mScreenshotHelper != null) { mScreenshotHelper.takeScreenshot(screenshotType, mStatusBar != null && mStatusBar.isVisibleLw(), - mNavigationBar != null && mNavigationBar.isVisibleLw(), mHandler); + mNavigationBar != null && mNavigationBar.isVisibleLw(), + mHandler, null /* completionConsumer */); } } diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java index a46fa13adf4e..207e8ef728eb 100644 --- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java +++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java @@ -30,6 +30,7 @@ import android.annotation.IntDef; import android.annotation.Nullable; import android.app.WindowConfiguration; import android.os.Environment; +import android.os.FileUtils; import android.provider.Settings; import android.util.AtomicFile; import android.util.Slog; @@ -64,6 +65,11 @@ import java.util.HashMap; class DisplayWindowSettings { private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayWindowSettings" : TAG_WM; + private static final String SYSTEM_DIRECTORY = "system"; + private static final String DISPLAY_SETTINGS_FILE_NAME = "display_settings.xml"; + private static final String VENDOR_DISPLAY_SETTINGS_PATH = "etc/" + DISPLAY_SETTINGS_FILE_NAME; + private static final String WM_DISPLAY_COMMIT_TAG = "wm-displays"; + private static final int IDENTIFIER_UNIQUE_ID = 0; private static final int IDENTIFIER_PORT = 1; @IntDef(prefix = { "IDENTIFIER_" }, value = { @@ -688,8 +694,26 @@ class DisplayWindowSettings { private final AtomicFile mAtomicFile; AtomicFileStorage() { - final File folder = new File(Environment.getDataDirectory(), "system"); - mAtomicFile = new AtomicFile(new File(folder, "display_settings.xml"), "wm-displays"); + final File folder = new File(Environment.getDataDirectory(), SYSTEM_DIRECTORY); + final File settingsFile = new File(folder, DISPLAY_SETTINGS_FILE_NAME); + // If display_settings.xml doesn't exist, try to copy the vendor's one instead + // in order to provide the vendor specific initialization. + if (!settingsFile.exists()) { + copyVendorSettings(settingsFile); + } + mAtomicFile = new AtomicFile(settingsFile, WM_DISPLAY_COMMIT_TAG); + } + + private static void copyVendorSettings(File target) { + final File vendorFile = new File(Environment.getVendorDirectory(), + VENDOR_DISPLAY_SETTINGS_PATH); + if (vendorFile.canRead()) { + try { + FileUtils.copy(vendorFile, target); + } catch (IOException e) { + Slog.e(TAG, "Failed to copy vendor display_settings.xml"); + } + } } @Override diff --git a/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java b/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java index b33b68a7a5b2..271db2895eac 100644 --- a/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java +++ b/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java @@ -110,7 +110,9 @@ class HighRefreshRateBlacklist { private class OnPropertyChangedListener implements DeviceConfig.OnPropertyChangedListener { public void onPropertyChanged(@NonNull String namespace, @NonNull String name, @Nullable String value) { - updateBlacklist(value); + if (KEY_HIGH_REFRESH_RATE_BLACKLIST.equals(name)) { + updateBlacklist(value); + } } } } diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java index c3ea72f4c2fe..bb035d524f55 100644 --- a/services/core/java/com/android/server/wm/Letterbox.java +++ b/services/core/java/com/android/server/wm/Letterbox.java @@ -261,7 +261,7 @@ public class Letterbox { public void remove() { if (mSurface != null) { - mSurface.remove(); + new SurfaceControl.Transaction().remove(mSurface).apply(); mSurface = null; } if (mInputInterceptor != null) { diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java index d58c61368f9a..ffbf68813d35 100644 --- a/services/core/java/com/android/server/wm/RootActivityContainer.java +++ b/services/core/java/com/android/server/wm/RootActivityContainer.java @@ -1667,7 +1667,8 @@ class RootActivityContainer extends ConfigurationContainer <T extends ActivityStack> T getLaunchStack(@Nullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, boolean onTop) { - return getLaunchStack(r, options, candidateTask, onTop, null /* launchParams */); + return getLaunchStack(r, options, candidateTask, onTop, null /* launchParams */, + -1 /* no realCallingPid */, -1 /* no realCallingUid */); } /** @@ -1676,13 +1677,16 @@ class RootActivityContainer extends ConfigurationContainer * @param r The activity we are trying to launch. Can be null. * @param options The activity options used to the launch. Can be null. * @param candidateTask The possible task the activity might be launched in. Can be null. - * @params launchParams The resolved launch params to use. + * @param launchParams The resolved launch params to use. + * @param realCallingPid The pid from {@link ActivityStarter#setRealCallingPid} + * @param realCallingUid The uid from {@link ActivityStarter#setRealCallingUid} * * @return The stack to use for the launch or INVALID_STACK_ID. */ <T extends ActivityStack> T getLaunchStack(@Nullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, boolean onTop, - @Nullable LaunchParamsController.LaunchParams launchParams) { + @Nullable LaunchParamsController.LaunchParams launchParams, int realCallingPid, + int realCallingUid) { int taskId = INVALID_TASK_ID; int displayId = INVALID_DISPLAY; //Rect bounds = null; @@ -1713,7 +1717,14 @@ class RootActivityContainer extends ConfigurationContainer if (launchParams != null && launchParams.mPreferredDisplayId != INVALID_DISPLAY) { displayId = launchParams.mPreferredDisplayId; } - if (displayId != INVALID_DISPLAY && canLaunchOnDisplay(r, displayId)) { + final boolean canLaunchOnDisplayFromStartRequest = + realCallingPid != 0 && realCallingUid > 0 && r != null + && mStackSupervisor.canPlaceEntityOnDisplay(displayId, realCallingPid, + realCallingUid, r.info); + // Checking if the activity's launch caller, or the realCallerId of the activity from + // start request (i.e. PendingIntent caller) is allowed to launch on the display. + if (displayId != INVALID_DISPLAY && (canLaunchOnDisplay(r, displayId) + || canLaunchOnDisplayFromStartRequest)) { if (r != null) { stack = (T) getValidLaunchStackOnDisplay(displayId, r, candidateTask, options, launchParams); @@ -2266,9 +2277,9 @@ class RootActivityContainer extends ConfigurationContainer void getRunningTasks(int maxNum, List<ActivityManager.RunningTaskInfo> list, @WindowConfiguration.ActivityType int ignoreActivityType, @WindowConfiguration.WindowingMode int ignoreWindowingMode, int callingUid, - boolean allowed) { + boolean allowed, boolean crossUser, ArraySet<Integer> profileIds) { mStackSupervisor.mRunningTasks.getTasks(maxNum, list, ignoreActivityType, - ignoreWindowingMode, mActivityDisplays, callingUid, allowed); + ignoreWindowingMode, mActivityDisplays, callingUid, allowed, crossUser, profileIds); } void sendPowerHintForLaunchStartIfNeeded(boolean forceSend, ActivityRecord targetActivity) { diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java index 3bf437d38bcc..81a85476c53a 100644 --- a/services/core/java/com/android/server/wm/RunningTasks.java +++ b/services/core/java/com/android/server/wm/RunningTasks.java @@ -19,6 +19,7 @@ package com.android.server.wm; import android.app.ActivityManager.RunningTaskInfo; import android.app.WindowConfiguration.ActivityType; import android.app.WindowConfiguration.WindowingMode; +import android.util.ArraySet; import java.util.ArrayList; import java.util.Comparator; @@ -40,7 +41,7 @@ class RunningTasks { void getTasks(int maxNum, List<RunningTaskInfo> list, @ActivityType int ignoreActivityType, @WindowingMode int ignoreWindowingMode, ArrayList<ActivityDisplay> activityDisplays, - int callingUid, boolean allowed) { + int callingUid, boolean allowed, boolean crossUser, ArraySet<Integer> profileIds) { // Return early if there are no tasks to fetch if (maxNum <= 0) { return; @@ -55,7 +56,7 @@ class RunningTasks { final ActivityStack stack = display.getChildAt(stackNdx); mTmpStackTasks.clear(); stack.getRunningTasks(mTmpStackTasks, ignoreActivityType, ignoreWindowingMode, - callingUid, allowed); + callingUid, allowed, crossUser, profileIds); mTmpSortedSet.addAll(mTmpStackTasks); } } diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java index 0be9736e9d76..b94a7dc781e8 100644 --- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java @@ -558,7 +558,7 @@ class ScreenRotationAnimation { Rect outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1, mOriginalWidth*2, mOriginalHeight*2); Rect inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight); - mCustomBlackFrame = new BlackFrame(t, outer, inner, + mCustomBlackFrame = new BlackFrame(mService.mTransactionFactory, t, outer, inner, SCREEN_FREEZE_LAYER_CUSTOM, mDisplayContent, false); mCustomBlackFrame.setMatrix(t, mFrameInitialMatrix); } catch (OutOfResourcesException e) { @@ -589,7 +589,7 @@ class ScreenRotationAnimation { mOriginalWidth*2, mOriginalHeight*2); inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight); } - mExitingBlackFrame = new BlackFrame(t, outer, inner, + mExitingBlackFrame = new BlackFrame(mService.mTransactionFactory, t, outer, inner, SCREEN_FREEZE_LAYER_EXIT, mDisplayContent, mForceDefaultOrientation); mExitingBlackFrame.setMatrix(t, mFrameInitialMatrix); } catch (OutOfResourcesException e) { @@ -602,7 +602,7 @@ class ScreenRotationAnimation { Rect outer = new Rect(-finalWidth*1, -finalHeight*1, finalWidth*2, finalHeight*2); Rect inner = new Rect(0, 0, finalWidth, finalHeight); - mEnteringBlackFrame = new BlackFrame(t, outer, inner, + mEnteringBlackFrame = new BlackFrame(mService.mTransactionFactory, t, outer, inner, SCREEN_FREEZE_LAYER_ENTER, mDisplayContent, false); } catch (OutOfResourcesException e) { Slog.w(TAG, "Unable to allocate black surface", e); @@ -640,7 +640,7 @@ class ScreenRotationAnimation { if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG_WM, " FREEZE " + mSurfaceControl + ": DESTROY"); - mSurfaceControl.remove(); + mService.mTransactionFactory.make().remove(mSurfaceControl).apply(); mSurfaceControl = null; } if (mCustomBlackFrame != null) { diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java index f776062b31a1..4c50527dd67c 100644 --- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java +++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java @@ -55,7 +55,8 @@ class TaskChangeNotificationController { private static final int NOTIFY_SIZE_COMPAT_MODE_ACTIVITY_CHANGED_MSG = 20; private static final int NOTIFY_BACK_PRESSED_ON_TASK_ROOT = 21; private static final int NOTIFY_SINGLE_TASK_DISPLAY_DRAWN = 22; - private static final int NOTIFY_TASK_DISPLAY_CHANGED_LISTENERS_MSG = 23; + private static final int NOTIFY_SINGLE_TASK_DISPLAY_EMPTY = 23; + private static final int NOTIFY_TASK_DISPLAY_CHANGED_LISTENERS_MSG = 24; // Delay in notifying task stack change listeners (in millis) private static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100; @@ -160,6 +161,10 @@ class TaskChangeNotificationController { l.onSingleTaskDisplayDrawn(m.arg1); }; + private final TaskStackConsumer mNotifySingleTaskDisplayEmpty = (l, m) -> { + l.onSingleTaskDisplayEmpty(m.arg1); + }; + private final TaskStackConsumer mNotifyTaskDisplayChanged = (l, m) -> { l.onTaskDisplayChanged(m.arg1, m.arg2); }; @@ -246,6 +251,9 @@ class TaskChangeNotificationController { case NOTIFY_SINGLE_TASK_DISPLAY_DRAWN: forAllRemoteListeners(mNotifySingleTaskDisplayDrawn, msg); break; + case NOTIFY_SINGLE_TASK_DISPLAY_EMPTY: + forAllRemoteListeners(mNotifySingleTaskDisplayEmpty, msg); + break; case NOTIFY_TASK_DISPLAY_CHANGED_LISTENERS_MSG: forAllRemoteListeners(mNotifyTaskDisplayChanged, msg); break; @@ -505,6 +513,17 @@ class TaskChangeNotificationController { } /** + * Notify listeners that the last task is removed from a single task display. + */ + void notifySingleTaskDisplayEmpty(int displayId) { + final Message msg = mHandler.obtainMessage( + NOTIFY_SINGLE_TASK_DISPLAY_EMPTY, + displayId, 0 /* unused */); + forAllLocalListeners(mNotifySingleTaskDisplayEmpty, msg); + msg.sendToTarget(); + } + + /** * Notify listeners that a task is reparented to another display. */ void notifyTaskDisplayChanged(int taskId, int newDisplayId) { diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 114a56feaf73..343a972801dd 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -1012,7 +1012,7 @@ public class TaskStack extends WindowContainer<Task> implements EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId); if (mAnimationBackgroundSurface != null) { - mAnimationBackgroundSurface.remove(); + mWmService.mTransactionFactory.make().remove(mAnimationBackgroundSurface).apply(); mAnimationBackgroundSurface = null; } @@ -1747,6 +1747,11 @@ public class TaskStack extends WindowContainer<Task> implements if (toBounds.width() == fromBounds.width() && toBounds.height() == fromBounds.height()) { intendedAnimationType = BoundsAnimationController.BOUNDS; + } else if (!fromFullscreen && !toBounds.equals(fromBounds)) { + // intendedAnimationType may have been reset at the end of RecentsAnimation, + // force it to BOUNDS type if we know for certain we're animating to + // a different bounds, especially for expand and collapse of PiP window. + intendedAnimationType = BoundsAnimationController.BOUNDS; } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index ec970d2d3a5a..e1f85446de7b 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1167,7 +1167,8 @@ public class WindowManagerService extends IWindowManager.Stub new HandlerExecutor(mH), properties -> { synchronized (mGlobalLock) { final int exclusionLimitDp = Math.max(MIN_GESTURE_EXCLUSION_LIMIT_DP, - properties.getInt(KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, 0)); + DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER, + KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, 0)); final boolean excludedByPreQSticky = DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, false); diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index 4cb546f107c7..e0a9af543f99 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -23,7 +23,6 @@ import static android.view.Display.INVALID_DISPLAY; import static com.android.server.am.ActivityManagerService.MY_PID; import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED; import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING; -import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING; import static com.android.server.wm.ActivityStack.ActivityState.PAUSED; import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; @@ -553,14 +552,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio continue; } ActivityRecord topActivity = task.getTopActivity(); - if (topActivity == null) { - continue; - } - // If an activity has just been started it will not yet be visible, but - // is expected to be soon. We treat this as if it were already visible. - // This ensures a subsequent activity can be started even before this one - // becomes visible. - if (topActivity.visible || topActivity.isState(INITIALIZING)) { + if (topActivity != null && topActivity.visible) { return true; } } diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java index 53bbd7010b5d..f37209bc6467 100644 --- a/services/core/java/com/android/server/wm/WindowSurfaceController.java +++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java @@ -162,7 +162,7 @@ class WindowSurfaceController { } try { if (mSurfaceControl != null) { - mSurfaceControl.remove(); + mTmpTransaction.remove(mSurfaceControl).apply(); } } catch (RuntimeException e) { Slog.w(TAG, "Error destroying surface in: " + this, e); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 16c60ca3997a..80535e496fbc 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -23,6 +23,7 @@ import static android.os.IServiceManager.DUMP_FLAG_PROTO; import static android.view.Display.DEFAULT_DISPLAY; import android.annotation.NonNull; +import android.annotation.StringRes; import android.app.ActivityThread; import android.app.AppCompatCallbacks; import android.app.INotificationManager; @@ -39,6 +40,7 @@ import android.database.sqlite.SQLiteCompatibilityWalFlags; import android.database.sqlite.SQLiteGlobal; import android.hardware.display.DisplayManagerInternal; import android.net.ConnectivityModuleConnector; +import android.net.Network; import android.net.NetworkStackClient; import android.os.BaseBundle; import android.os.Binder; @@ -1266,14 +1268,22 @@ public final class SystemServer { startSystemCaptionsManagerService(context); // App prediction manager service - traceBeginAndSlog("StartAppPredictionService"); - mSystemServiceManager.startService(APP_PREDICTION_MANAGER_SERVICE_CLASS); - traceEnd(); + if (deviceHasConfigString(context, R.string.config_defaultAppPredictionService)) { + traceBeginAndSlog("StartAppPredictionService"); + mSystemServiceManager.startService(APP_PREDICTION_MANAGER_SERVICE_CLASS); + traceEnd(); + } else { + Slog.d(TAG, "AppPredictionService not defined by OEM"); + } // Content suggestions manager service - traceBeginAndSlog("StartContentSuggestionsService"); - mSystemServiceManager.startService(CONTENT_SUGGESTIONS_SERVICE_CLASS); - traceEnd(); + if (deviceHasConfigString(context, R.string.config_defaultContentSuggestionsService)) { + traceBeginAndSlog("StartContentSuggestionsService"); + mSystemServiceManager.startService(CONTENT_SUGGESTIONS_SERVICE_CLASS); + traceEnd(); + } else { + Slog.d(TAG, "ContentSuggestionsService not defined by OEM"); + } traceBeginAndSlog("InitConnectivityModuleConnector"); try { @@ -2264,10 +2274,13 @@ public final class SystemServer { }, BOOT_TIMINGS_TRACE_LOG); } + private boolean deviceHasConfigString(@NonNull Context context, @StringRes int resId) { + String serviceName = context.getString(resId); + return !TextUtils.isEmpty(serviceName); + } + private void startSystemCaptionsManagerService(@NonNull Context context) { - String serviceName = context.getString( - com.android.internal.R.string.config_defaultSystemCaptionsManagerService); - if (TextUtils.isEmpty(serviceName)) { + if (!deviceHasConfigString(context, R.string.config_defaultSystemCaptionsManagerService)) { Slog.d(TAG, "SystemCaptionsManagerService disabled because resource is not overlaid"); return; } @@ -2294,9 +2307,7 @@ public final class SystemServer { // Then check if OEM overlaid the resource that defines the service. if (!explicitlyEnabled) { - final String serviceName = context - .getString(com.android.internal.R.string.config_defaultContentCaptureService); - if (TextUtils.isEmpty(serviceName)) { + if (!deviceHasConfigString(context, R.string.config_defaultContentCaptureService)) { Slog.d(TAG, "ContentCaptureService disabled because resource is not overlaid"); return; } diff --git a/services/net/java/android/net/ConnectivityModuleConnector.java b/services/net/java/android/net/ConnectivityModuleConnector.java index 19ade3394de7..62f2c35f339b 100644 --- a/services/net/java/android/net/ConnectivityModuleConnector.java +++ b/services/net/java/android/net/ConnectivityModuleConnector.java @@ -32,7 +32,7 @@ import android.os.IBinder; import android.os.Process; import android.os.SystemClock; import android.os.UserHandle; -import android.provider.Settings; +import android.provider.DeviceConfig; import android.text.format.DateUtils; import android.util.ArraySet; import android.util.Slog; @@ -296,8 +296,6 @@ public class ConnectivityModuleConnector { private synchronized void maybeCrashWithTerribleFailure(@NonNull String message, @Nullable String packageName) { logWtf(message, null); - // Called DeviceConfig to minimize merge conflicts - final DeviceConfigStub DeviceConfig = new DeviceConfigStub(mContext); // uptime is monotonic even after a framework restart final long uptime = SystemClock.elapsedRealtime(); final long now = System.currentTimeMillis(); @@ -417,36 +415,4 @@ public class ConnectivityModuleConnector { // dump is thread-safe on SharedLog mLog.dump(null, pw, null); } - - /** - * Stub class to replicate DeviceConfig behavior with minimal merge conflicts. - */ - private class DeviceConfigStub { - private final Context mContext; - - // Namespace is actually unused, but is here to replicate the final API. - private static final String NAMESPACE_CONNECTIVITY = "connectivity"; - - private DeviceConfigStub(Context context) { - mContext = context; - } - - private long getLong( - @NonNull String namespace, @NonNull String key, long defaultVal) { - // Temporary solution until DeviceConfig is available - try { - return Settings.Global.getLong( - mContext.getContentResolver(), TAG + "_" + key, defaultVal); - } catch (Throwable e) { - logWtf("Could not obtain setting " + key, e); - return defaultVal; - } - } - - private boolean getBoolean( - @NonNull String namespace, @NonNull String key, boolean defaultVal) { - // Temporary solution until DeviceConfig is available - return getLong(namespace, key, defaultVal ? 1 : 0) != 0; - } - } } diff --git a/services/tests/servicestests/src/com/android/server/accessibility/GlobalActionPerformerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/GlobalActionPerformerTest.java index e72e4601bbe8..c73be6f100cd 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/GlobalActionPerformerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/GlobalActionPerformerTest.java @@ -35,6 +35,8 @@ import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.function.Consumer; + /** * Tests for GlobalActionPerformer */ @@ -84,6 +86,6 @@ public class GlobalActionPerformerTest { AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT); verify(mMockScreenshotHelper).takeScreenshot( eq(android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN), anyBoolean(), - anyBoolean(), any(Handler.class)); + anyBoolean(), any(Handler.class), any()); } } diff --git a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java index d5d32bdd00cc..376f5cd3ab47 100644 --- a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java @@ -18,7 +18,10 @@ package com.android.server.pm; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.MODE_IGNORED; +import static android.app.AppOpsManager.OP_CAMERA; import static android.app.AppOpsManager.OP_PLAY_AUDIO; +import static android.app.AppOpsManager.OP_RECORD_AUDIO; +import static android.app.AppOpsManager.opToName; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -39,7 +42,6 @@ import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.content.pm.SuspendDialogInfo; import android.content.res.Resources; -import android.media.AudioAttributes; import android.os.BaseBundle; import android.os.Bundle; import android.os.Handler; @@ -551,28 +553,42 @@ public class SuspendPackagesTest { } @Test - public void testAudioOpBlockedOnSuspend() throws Exception { + public void testCameraBlockedOnSuspend() throws Exception { + assertOpBlockedOnSuspend(OP_CAMERA); + } + + @Test + public void testPlayAudioBlockedOnSuspend() throws Exception { + assertOpBlockedOnSuspend(OP_PLAY_AUDIO); + } + + @Test + public void testRecordAudioBlockedOnSuspend() throws Exception { + assertOpBlockedOnSuspend(OP_RECORD_AUDIO); + } + + private void assertOpBlockedOnSuspend(int code) throws Exception { final IAppOpsService iAppOps = IAppOpsService.Stub.asInterface( ServiceManager.getService(Context.APP_OPS_SERVICE)); final CountDownLatch latch = new CountDownLatch(1); final IAppOpsCallback watcher = new IAppOpsCallback.Stub() { @Override public void opChanged(int op, int uid, String packageName) { - if (op == OP_PLAY_AUDIO && packageName.equals(TEST_APP_PACKAGE_NAME)) { + if (op == code && packageName.equals(TEST_APP_PACKAGE_NAME)) { latch.countDown(); } } }; - iAppOps.startWatchingMode(OP_PLAY_AUDIO, TEST_APP_PACKAGE_NAME, watcher); + iAppOps.startWatchingMode(code, TEST_APP_PACKAGE_NAME, watcher); final int testPackageUid = mPackageManager.getPackageUid(TEST_APP_PACKAGE_NAME, 0); - int audioOpMode = iAppOps.checkAudioOperation(OP_PLAY_AUDIO, - AudioAttributes.USAGE_UNKNOWN, testPackageUid, TEST_APP_PACKAGE_NAME); - assertEquals("Audio muted for unsuspended package", MODE_ALLOWED, audioOpMode); + int opMode = iAppOps.checkOperation(code, testPackageUid, TEST_APP_PACKAGE_NAME); + assertEquals("Op " + opToName(code) + " disallowed for unsuspended package", MODE_ALLOWED, + opMode); suspendTestPackage(null, null, null); assertTrue("AppOpsWatcher did not callback", latch.await(5, TimeUnit.SECONDS)); - audioOpMode = iAppOps.checkAudioOperation(OP_PLAY_AUDIO, - AudioAttributes.USAGE_UNKNOWN, testPackageUid, TEST_APP_PACKAGE_NAME); - assertEquals("Audio not muted for suspended package", MODE_IGNORED, audioOpMode); + opMode = iAppOps.checkOperation(code, testPackageUid, TEST_APP_PACKAGE_NAME); + assertEquals("Op " + opToName(code) + " allowed for suspended package", MODE_IGNORED, + opMode); iAppOps.stopWatchingMode(watcher); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java index 273a9e66e55b..7459c4b0610e 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java @@ -86,7 +86,7 @@ public class BubbleExtractorTest extends UiServiceTestCase { BubbleExtractor extractor = new BubbleExtractor(); extractor.setConfig(mConfig); - when(mConfig.bubblesEnabled(mUser)).thenReturn(true); + when(mConfig.bubblesEnabled()).thenReturn(true); when(mConfig.areBubblesAllowed(mPkg, mUid)).thenReturn(true); NotificationRecord r = getNotificationRecord(false, IMPORTANCE_UNSPECIFIED); @@ -100,7 +100,7 @@ public class BubbleExtractorTest extends UiServiceTestCase { BubbleExtractor extractor = new BubbleExtractor(); extractor.setConfig(mConfig); - when(mConfig.bubblesEnabled(mUser)).thenReturn(true); + when(mConfig.bubblesEnabled()).thenReturn(true); when(mConfig.areBubblesAllowed(mPkg, mUid)).thenReturn(false); NotificationRecord r = getNotificationRecord(true, IMPORTANCE_HIGH); @@ -114,7 +114,7 @@ public class BubbleExtractorTest extends UiServiceTestCase { BubbleExtractor extractor = new BubbleExtractor(); extractor.setConfig(mConfig); - when(mConfig.bubblesEnabled(mUser)).thenReturn(true); + when(mConfig.bubblesEnabled()).thenReturn(true); when(mConfig.areBubblesAllowed(mPkg, mUid)).thenReturn(true); NotificationRecord r = getNotificationRecord(true, IMPORTANCE_UNSPECIFIED); @@ -128,7 +128,7 @@ public class BubbleExtractorTest extends UiServiceTestCase { BubbleExtractor extractor = new BubbleExtractor(); extractor.setConfig(mConfig); - when(mConfig.bubblesEnabled(mUser)).thenReturn(true); + when(mConfig.bubblesEnabled()).thenReturn(true); when(mConfig.areBubblesAllowed(mPkg, mUid)).thenReturn(false); NotificationRecord r = getNotificationRecord(false, IMPORTANCE_UNSPECIFIED); @@ -142,7 +142,7 @@ public class BubbleExtractorTest extends UiServiceTestCase { BubbleExtractor extractor = new BubbleExtractor(); extractor.setConfig(mConfig); - when(mConfig.bubblesEnabled(mUser)).thenReturn(false); + when(mConfig.bubblesEnabled()).thenReturn(false); when(mConfig.areBubblesAllowed(mPkg, mUid)).thenReturn(true); NotificationRecord r = getNotificationRecord(true, IMPORTANCE_HIGH); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 0c31b143df57..389b68a7d4b7 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -20,6 +20,7 @@ import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREG import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE; import static android.app.Notification.CATEGORY_CALL; +import static android.app.Notification.FLAG_AUTO_CANCEL; import static android.app.Notification.FLAG_BUBBLE; import static android.app.Notification.FLAG_FOREGROUND_SERVICE; import static android.app.NotificationManager.EXTRA_BLOCKED_STATE; @@ -420,7 +421,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { private void setUpPrefsForBubbles(boolean globalEnabled, boolean pkgEnabled, boolean channelEnabled) { mService.setPreferencesHelper(mPreferencesHelper); - when(mPreferencesHelper.bubblesEnabled(any())).thenReturn(globalEnabled); + when(mPreferencesHelper.bubblesEnabled()).thenReturn(globalEnabled); when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(pkgEnabled); when(mPreferencesHelper.getNotificationChannel( anyString(), anyInt(), anyString(), anyBoolean())).thenReturn( @@ -439,14 +440,22 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { return sbn; } + private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id, String groupKey, boolean isSummary) { + return generateNotificationRecord(channel, id, groupKey, isSummary, false /* isBubble */); + } + + private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id, + String groupKey, boolean isSummary, boolean isBubble) { Notification.Builder nb = new Notification.Builder(mContext, channel.getId()) .setContentTitle("foo") .setSmallIcon(android.R.drawable.sym_def_app_icon) .setGroup(groupKey) .setGroupSummary(isSummary); - + if (isBubble) { + nb.setBubbleMetadata(getBasicBubbleMetadataBuilder().build()); + } StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, id, "tag", mUid, 0, nb.build(), new UserHandle(mUid), null, 0); return new NotificationRecord(mContext, sbn, channel); @@ -542,6 +551,52 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .setIcon(Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon)); } + private NotificationRecord addGroupWithBubblesAndValidateAdded(boolean summaryAutoCancel) + throws RemoteException { + + // Notification that has bubble metadata + NotificationRecord nrBubble = generateNotificationRecord(mTestNotificationChannel, 1, + "BUBBLE_GROUP", false /* isSummary */, true /* isBubble */); + + // Make the package foreground so that we're allowed to be a bubble + when(mActivityManager.getPackageImportance(nrBubble.sbn.getPackageName())).thenReturn( + IMPORTANCE_FOREGROUND); + + mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + nrBubble.sbn.getId(), nrBubble.sbn.getNotification(), nrBubble.sbn.getUserId()); + waitForIdle(); + + // Make sure we are a bubble + StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(PKG); + assertEquals(1, notifsAfter.length); + assertTrue((notifsAfter[0].getNotification().flags & FLAG_BUBBLE) != 0); + + // Plain notification without bubble metadata + NotificationRecord nrPlain = generateNotificationRecord(mTestNotificationChannel, 2, + "BUBBLE_GROUP", false /* isSummary */, false /* isBubble */); + mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + nrPlain.sbn.getId(), nrPlain.sbn.getNotification(), nrPlain.sbn.getUserId()); + waitForIdle(); + + notifsAfter = mBinderService.getActiveNotifications(PKG); + assertEquals(2, notifsAfter.length); + + // Summary notification for both of those + NotificationRecord nrSummary = generateNotificationRecord(mTestNotificationChannel, 3, + "BUBBLE_GROUP", true /* isSummary */, false /* isBubble */); + if (summaryAutoCancel) { + nrSummary.getNotification().flags |= FLAG_AUTO_CANCEL; + } + mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + nrSummary.sbn.getId(), nrSummary.sbn.getNotification(), nrSummary.sbn.getUserId()); + waitForIdle(); + + notifsAfter = mBinderService.getActiveNotifications(PKG); + assertEquals(3, notifsAfter.length); + + return nrSummary; + } + @Test public void testCreateNotificationChannels_SingleChannel() throws Exception { final NotificationChannel channel = @@ -1508,14 +1563,22 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void testUpdateAppNotifyCreatorBlock() throws Exception { mService.setPreferencesHelper(mPreferencesHelper); - mBinderService.setNotificationsEnabledForPackage(PKG, 0, false); + mBinderService.setNotificationsEnabledForPackage(PKG, 0, true); ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null)); assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED, captor.getValue().getAction()); assertEquals(PKG, captor.getValue().getPackage()); - assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false)); + assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true)); + } + + @Test + public void testUpdateAppNotifyCreatorBlock_notIfMatchesExistingSetting() throws Exception { + mService.setPreferencesHelper(mPreferencesHelper); + + mBinderService.setNotificationsEnabledForPackage(PKG, 0, false); + verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null)); } @Test @@ -5082,4 +5145,162 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertEquals(1, notifsAfter.length); assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0); } + + @Test + public void testNotificationBubbles_flagAutoExpandForeground_fails_notForeground() + throws Exception { + // Bubbles are allowed! + setUpPrefsForBubbles(true /* global */, true /* app */, true /* channel */); + + // Give it bubble metadata + Notification.BubbleMetadata data = getBasicBubbleMetadataBuilder() + .setSuppressNotification(true) + .setAutoExpandBubble(true).build(); + // Give it a person + Person person = new Person.Builder() + .setName("bubblebot") + .build(); + // It needs remote input to be bubble-able + RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build(); + PendingIntent inputIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0); + Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon); + Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply", + inputIntent).addRemoteInput(remoteInput) + .build(); + // Make it messaging style + Notification.Builder nb = new Notification.Builder(mContext, + mTestNotificationChannel.getId()) + .setContentTitle("foo") + .setBubbleMetadata(data) + .setStyle(new Notification.MessagingStyle(person) + .setConversationTitle("Bubble Chat") + .addMessage("Hello?", + SystemClock.currentThreadTimeMillis() - 300000, person) + .addMessage("Is it me you're looking for?", + SystemClock.currentThreadTimeMillis(), person) + ) + .setActions(replyAction) + .setSmallIcon(android.R.drawable.sym_def_app_icon); + + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, null, mUid, 0, + nb.build(), new UserHandle(mUid), null, 0); + NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + + // Ensure we're not foreground + when(mActivityManager.getPackageImportance(nr.sbn.getPackageName())).thenReturn( + IMPORTANCE_VISIBLE); + + mBinderService.enqueueNotificationWithTag(PKG, PKG, null, + nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId()); + waitForIdle(); + + // yes allowed, yes messaging, yes bubble + Notification notif = mService.getNotificationRecord(sbn.getKey()).getNotification(); + assertTrue(notif.isBubbleNotification()); + + // Our flags should have failed since we're not foreground + assertFalse(notif.getBubbleMetadata().getAutoExpandBubble()); + assertFalse(notif.getBubbleMetadata().isNotificationSuppressed()); + } + + @Test + public void testNotificationBubbles_flagAutoExpandForeground_succeeds_foreground() + throws RemoteException { + // Bubbles are allowed! + setUpPrefsForBubbles(true /* global */, true /* app */, true /* channel */); + + // Give it bubble metadata + Notification.BubbleMetadata data = getBasicBubbleMetadataBuilder() + .setSuppressNotification(true) + .setAutoExpandBubble(true).build(); + // Give it a person + Person person = new Person.Builder() + .setName("bubblebot") + .build(); + // It needs remote input to be bubble-able + RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build(); + PendingIntent inputIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0); + Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon); + Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply", + inputIntent).addRemoteInput(remoteInput) + .build(); + // Make it messaging style + Notification.Builder nb = new Notification.Builder(mContext, + mTestNotificationChannel.getId()) + .setContentTitle("foo") + .setBubbleMetadata(data) + .setStyle(new Notification.MessagingStyle(person) + .setConversationTitle("Bubble Chat") + .addMessage("Hello?", + SystemClock.currentThreadTimeMillis() - 300000, person) + .addMessage("Is it me you're looking for?", + SystemClock.currentThreadTimeMillis(), person) + ) + .setActions(replyAction) + .setSmallIcon(android.R.drawable.sym_def_app_icon); + + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, null, mUid, 0, + nb.build(), new UserHandle(mUid), null, 0); + NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + + // Ensure we are in the foreground + when(mActivityManager.getPackageImportance(nr.sbn.getPackageName())).thenReturn( + IMPORTANCE_FOREGROUND); + + mBinderService.enqueueNotificationWithTag(PKG, PKG, null, + nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId()); + waitForIdle(); + + // yes allowed, yes messaging, yes bubble + Notification notif = mService.getNotificationRecord(sbn.getKey()).getNotification(); + assertTrue(notif.isBubbleNotification()); + + // Our flags should have failed since we are foreground + assertTrue(notif.getBubbleMetadata().getAutoExpandBubble()); + assertTrue(notif.getBubbleMetadata().isNotificationSuppressed()); + } + + @Test + public void testNotificationBubbles_bubbleChildrenStay_whenGroupSummaryDismissed() + throws Exception { + // Bubbles are allowed! + setUpPrefsForBubbles(true /* global */, true /* app */, true /* channel */); + + NotificationRecord nrSummary = addGroupWithBubblesAndValidateAdded( + true /* summaryAutoCancel */); + + // Dismiss summary + final NotificationVisibility nv = NotificationVisibility.obtain(nrSummary.getKey(), 1, 2, + true); + mService.mNotificationDelegate.onNotificationClear(mUid, 0, PKG, nrSummary.sbn.getTag(), + nrSummary.sbn.getId(), nrSummary.getUserId(), nrSummary.getKey(), + NotificationStats.DISMISSAL_SHADE, + NotificationStats.DISMISS_SENTIMENT_NEUTRAL, nv); + waitForIdle(); + + // The bubble should still exist + StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(PKG); + assertEquals(1, notifsAfter.length); + } + + @Test + public void testNotificationBubbles_bubbleChildrenStay_whenGroupSummaryClicked() + throws Exception { + // Bubbles are allowed! + setUpPrefsForBubbles(true /* global */, true /* app */, true /* channel */); + + NotificationRecord nrSummary = addGroupWithBubblesAndValidateAdded( + true /* summaryAutoCancel */); + + // Click summary + final NotificationVisibility nv = NotificationVisibility.obtain(nrSummary.getKey(), 1, 2, + true); + mService.mNotificationDelegate.onNotificationClick(mUid, Binder.getCallingPid(), + nrSummary.getKey(), nv); + waitForIdle(); + + // The bubble should still exist + StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(PKG); + assertEquals(1, notifsAfter.length); + } } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java index 8f8b746b59d4..80439cf66387 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java @@ -22,6 +22,8 @@ import static android.app.NotificationManager.IMPORTANCE_MAX; import static android.app.NotificationManager.IMPORTANCE_NONE; import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; +import static com.android.server.notification.PreferencesHelper.NOTIFICATION_CHANNEL_COUNT_LIMIT; + import static junit.framework.Assert.assertNull; import static junit.framework.Assert.fail; @@ -58,7 +60,9 @@ import android.net.Uri; import android.os.Build; import android.os.UserHandle; import android.provider.Settings; +import android.provider.Settings.Global; import android.provider.Settings.Secure; + import android.test.suitebuilder.annotation.SmallTest; import android.testing.TestableContentResolver; import android.util.ArrayMap; @@ -152,8 +156,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { contentResolver.setFallbackToExisting(false); Secure.putIntForUser(contentResolver, Secure.NOTIFICATION_BADGING, 1, UserHandle.getUserId(UID_N_MR1)); - Secure.putIntForUser(contentResolver, - Secure.NOTIFICATION_BUBBLES, 1, UserHandle.getUserId(UID_N_MR1)); + Global.putInt(contentResolver, Global.NOTIFICATION_BUBBLES, 1); ContentProvider testContentProvider = mock(ContentProvider.class); when(testContentProvider.getIContentProvider()).thenReturn(mTestIContentProvider); @@ -1948,42 +1951,18 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testBubblesOverrideTrue() { - Secure.putIntForUser(getContext().getContentResolver(), - Secure.NOTIFICATION_BUBBLES, 1, - USER.getIdentifier()); + Global.putInt(getContext().getContentResolver(), + Global.NOTIFICATION_BUBBLES, 1); mHelper.updateBubblesEnabled(); // would be called by settings observer - assertTrue(mHelper.bubblesEnabled(USER)); + assertTrue(mHelper.bubblesEnabled()); } @Test public void testBubblesOverrideFalse() { - Secure.putIntForUser(getContext().getContentResolver(), - Secure.NOTIFICATION_BUBBLES, 0, - USER.getIdentifier()); - mHelper.updateBubblesEnabled(); // would be called by settings observer - assertFalse(mHelper.bubblesEnabled(USER)); - } - - @Test - public void testBubblesForUserAll() { - try { - mHelper.bubblesEnabled(UserHandle.ALL); - } catch (Exception e) { - fail("just don't throw"); - } - } - - @Test - public void testBubblesOverrideUserIsolation() { - Secure.putIntForUser(getContext().getContentResolver(), - Secure.NOTIFICATION_BUBBLES, 0, - USER.getIdentifier()); - Secure.putIntForUser(getContext().getContentResolver(), - Secure.NOTIFICATION_BUBBLES, 1, - USER2.getIdentifier()); + Global.putInt(getContext().getContentResolver(), + Global.NOTIFICATION_BUBBLES, 0); mHelper.updateBubblesEnabled(); // would be called by settings observer - assertFalse(mHelper.bubblesEnabled(USER)); - assertTrue(mHelper.bubblesEnabled(USER2)); + assertFalse(mHelper.bubblesEnabled()); } @Test @@ -2690,4 +2669,51 @@ public class PreferencesHelperTest extends UiServiceTestCase { assertFalse(mHelper.areBubblesAllowed(PKG_O, UID_O)); verify(mHandler, times(1)).requestSort(); } + + @Test + public void testTooManyChannels() { + for (int i = 0; i < NOTIFICATION_CHANNEL_COUNT_LIMIT; i++) { + NotificationChannel channel = new NotificationChannel(String.valueOf(i), + String.valueOf(i), NotificationManager.IMPORTANCE_HIGH); + mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, true); + } + try { + NotificationChannel channel = new NotificationChannel( + String.valueOf(NOTIFICATION_CHANNEL_COUNT_LIMIT), + String.valueOf(NOTIFICATION_CHANNEL_COUNT_LIMIT), + NotificationManager.IMPORTANCE_HIGH); + mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, true); + fail("Allowed to create too many notification channels"); + } catch (IllegalStateException e) { + // great + } + } + + @Test + public void testTooManyChannels_xml() throws Exception { + String extraChannel = "EXTRA"; + String extraChannel1 = "EXTRA1"; + + // create first... many... directly so we don't need a big xml blob in this test + for (int i = 0; i < NOTIFICATION_CHANNEL_COUNT_LIMIT; i++) { + NotificationChannel channel = new NotificationChannel(String.valueOf(i), + String.valueOf(i), NotificationManager.IMPORTANCE_HIGH); + mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, true); + } + + final String xml = "<ranking version=\"1\">\n" + + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n" + + "<channel id=\"" + extraChannel + "\" name=\"hi\" importance=\"3\"/>" + + "<channel id=\"" + extraChannel1 + "\" name=\"hi\" importance=\"3\"/>" + + "</package>" + + "</ranking>"; + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())), + null); + parser.nextTag(); + mHelper.readXml(parser, false, UserHandle.USER_ALL); + + assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, extraChannel, true)); + assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, extraChannel1, true)); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 3d944671ef25..07d9f803d9fa 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -341,7 +341,7 @@ public class ActivityStarterTests extends ActivityTestsBase { doReturn(stack).when(mRootActivityContainer) .getLaunchStack(any(), any(), any(), anyBoolean()); doReturn(stack).when(mRootActivityContainer) - .getLaunchStack(any(), any(), any(), anyBoolean(), any()); + .getLaunchStack(any(), any(), any(), anyBoolean(), any(), anyInt(), anyInt()); } // Set up mock package manager internal and make sure no unmocked methods are called diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index ecf3acd32d4f..84bdecb86826 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -40,6 +40,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; +import static org.mockito.ArgumentMatchers.eq; + import android.app.ActivityManagerInternal; import android.app.ActivityOptions; import android.app.AppOpsManager; @@ -72,6 +74,7 @@ import com.android.server.am.ActivityManagerService; import com.android.server.am.PendingIntentController; import com.android.server.appop.AppOpsService; import com.android.server.firewall.IntentFirewall; +import com.android.server.pm.UserManagerService; import com.android.server.policy.PermissionPolicyInternal; import com.android.server.uri.UriGrantsManagerInternal; import com.android.server.wm.TaskRecord.TaskRecordFactory; @@ -92,6 +95,7 @@ import java.util.function.Consumer; */ class ActivityTestsBase { private static int sNextDisplayId = DEFAULT_DISPLAY + 1; + private static final int[] TEST_USER_PROFILE_IDS = {}; @Rule public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule = @@ -204,6 +208,8 @@ class ActivityTestsBase { private ActivityStack mStack; private int mActivityFlags; private int mLaunchMode; + private int mLaunchedFromPid; + private int mLaunchedFromUid; ActivityBuilder(ActivityTaskManagerService service) { mService = service; @@ -254,6 +260,16 @@ class ActivityTestsBase { return this; } + ActivityBuilder setLaunchedFromPid(int pid) { + mLaunchedFromPid = pid; + return this; + } + + ActivityBuilder setLaunchedFromUid(int uid) { + mLaunchedFromUid = uid; + return this; + } + ActivityRecord build() { if (mComponent == null) { final int id = sCurrentActivityId++; @@ -281,10 +297,11 @@ class ActivityTestsBase { aInfo.launchMode = mLaunchMode; final ActivityRecord activity = new ActivityRecord(mService, null /* caller */, - 0 /* launchedFromPid */, 0, null, intent, null, - aInfo /*aInfo*/, new Configuration(), null /* resultTo */, null /* resultWho */, - 0 /* reqCode */, false /*componentSpecified*/, false /* rootVoiceInteraction */, - mService.mStackSupervisor, null /* options */, null /* sourceRecord */); + mLaunchedFromPid /* launchedFromPid */, mLaunchedFromUid /* launchedFromUid */, + null, intent, null, aInfo /*aInfo*/, new Configuration(), null /* resultTo */, + null /* resultWho */, 0 /* reqCode */, false /*componentSpecified*/, + false /* rootVoiceInteraction */, mService.mStackSupervisor, + null /* options */, null /* sourceRecord */); spyOn(activity); activity.mAppWindowToken = mock(AppWindowToken.class); doCallRealMethod().when(activity.mAppWindowToken).getOrientationIgnoreVisibility(); @@ -471,6 +488,11 @@ class ActivityTestsBase { // allow background activity starts by default doReturn(true).when(this).isBackgroundActivityStartsEnabled(); doNothing().when(this).updateCpuStats(); + + // UserManager + final UserManagerService ums = mock(UserManagerService.class); + doReturn(ums).when(this).getUserManager(); + doReturn(TEST_USER_PROFILE_IDS).when(ums).getProfileIds(anyInt(), eq(true)); } void setup(IntentFirewall intentFirewall, PendingIntentController intentController, diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java index 292a05bd966a..a98f79cb5369 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java @@ -169,7 +169,7 @@ public class DimmerTests extends WindowTestsBase { mDimmer.updateDims(mTransaction, new Rect()); verify(mTransaction).show(getDimLayer()); - verify(dimLayer, never()).remove(); + verify(mTransaction, never()).remove(dimLayer); } @Test @@ -231,7 +231,7 @@ public class DimmerTests extends WindowTestsBase { mDimmer.updateDims(mTransaction, new Rect()); verify(mTransaction).show(dimLayer); - verify(dimLayer, never()).remove(); + verify(mTransaction, never()).remove(dimLayer); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index a1999c901702..e4f614d38c82 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java @@ -62,6 +62,7 @@ import android.os.Looper; import android.os.RemoteException; import android.os.SystemClock; import android.platform.test.annotations.Presubmit; +import android.util.ArraySet; import android.util.MutableLong; import android.util.SparseBooleanArray; @@ -952,7 +953,6 @@ public class RecentTasksTest extends ActivityTestsBase { public void testRecentsComponent_allowApiAccessWithoutPermissions() { doReturn(PackageManager.PERMISSION_DENIED).when(mTestService) .checkGetTasksPermission(anyString(), anyInt(), anyInt()); - // Set the recents component and ensure that the following calls do not fail mRecentTasks.setIsCallerRecentsOverride(TestRecentTasks.GRANT); doTestRecentTasksApis(true /* expectNoSecurityException */); @@ -1301,10 +1301,10 @@ public class RecentTasksTest extends ActivityTestsBase { @Override void getTasks(int maxNum, List<RunningTaskInfo> list, int ignoreActivityType, int ignoreWindowingMode, ArrayList<ActivityDisplay> activityDisplays, - int callingUid, boolean allowed) { + int callingUid, boolean allowed, boolean crossUser, ArraySet<Integer> profileIds) { mLastAllowed = allowed; super.getTasks(maxNum, list, ignoreActivityType, ignoreWindowingMode, activityDisplays, - callingUid, allowed); + callingUid, allowed, crossUser, profileIds); } } } diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java index 8d2c3dd80538..baf1b0821982 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java @@ -25,6 +25,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.Display.TYPE_VIRTUAL; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; @@ -61,6 +62,7 @@ import android.content.res.Resources; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.util.Pair; +import android.view.DisplayInfo; import androidx.test.filters.MediumTest; @@ -817,6 +819,41 @@ public class RootActivityContainerTests extends ActivityTestsBase { } /** + * Test that {@link RootActivityContainer#getLaunchStack} with the real caller id will get the + * expected stack when requesting the activity launch on the secondary display. + */ + @Test + public void testGetLaunchStackWithRealCallerId() { + // Create a non-system owned virtual display. + final DisplayInfo info = new DisplayInfo(); + mSupervisor.mService.mContext.getDisplay().getDisplayInfo(info); + info.type = TYPE_VIRTUAL; + info.ownerUid = 100; + final TestActivityDisplay secondaryDisplay = createNewActivityDisplay(info); + mRootActivityContainer.addChild(secondaryDisplay, POSITION_TOP); + + // Create an activity with specify the original launch pid / uid. + final ActivityRecord r = new ActivityBuilder(mService).setLaunchedFromPid(200) + .setLaunchedFromUid(200).build(); + + // Simulate ActivityStarter to find a launch stack for requesting the activity to launch + // on the secondary display with realCallerId. + final ActivityOptions options = ActivityOptions.makeBasic(); + options.setLaunchDisplayId(secondaryDisplay.mDisplayId); + options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN); + doReturn(true).when(mSupervisor).canPlaceEntityOnDisplay(secondaryDisplay.mDisplayId, + 300 /* test realCallerPid */, 300 /* test realCallerUid */, r.info); + final ActivityStack result = mRootActivityContainer.getLaunchStack(r, options, + null /* task */, true /* onTop */, null, 300 /* test realCallerPid */, + 300 /* test realCallerUid */); + + // Assert that the stack is returned as expected. + assertNotNull(result); + assertEquals("The display ID of the stack should same as secondary display ", + secondaryDisplay.mDisplayId, result.mDisplayId); + } + + /** * Mock {@link RootActivityContainerTests#resolveHomeActivity} for returning consistent activity * info for test cases (the original implementation will resolve from the real package manager). */ diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java index dc964806b7a9..3e316f674dbf 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java @@ -29,6 +29,7 @@ import static org.junit.Assert.assertEquals; import android.app.ActivityManager.RunningTaskInfo; import android.content.ComponentName; import android.platform.test.annotations.Presubmit; +import android.util.ArraySet; import androidx.test.filters.MediumTest; @@ -45,6 +46,8 @@ import java.util.ArrayList; @Presubmit public class RunningTasksTest extends ActivityTestsBase { + private static final ArraySet<Integer> PROFILE_IDS = new ArraySet<>(); + private RunningTasks mRunningTasks; @Before @@ -77,7 +80,8 @@ public class RunningTasksTest extends ActivityTestsBase { final int numFetchTasks = 5; ArrayList<RunningTaskInfo> tasks = new ArrayList<>(); mRunningTasks.getTasks(5, tasks, ACTIVITY_TYPE_UNDEFINED, WINDOWING_MODE_UNDEFINED, - displays, -1 /* callingUid */, true /* allowed */); + displays, -1 /* callingUid */, true /* allowed */, true /*crossUser */, + PROFILE_IDS); assertThat(tasks).hasSize(numFetchTasks); for (int i = 0; i < numFetchTasks; i++) { assertEquals(numTasks - i - 1, tasks.get(i).id); @@ -87,7 +91,8 @@ public class RunningTasksTest extends ActivityTestsBase { // and does not crash tasks.clear(); mRunningTasks.getTasks(100, tasks, ACTIVITY_TYPE_UNDEFINED, WINDOWING_MODE_UNDEFINED, - displays, -1 /* callingUid */, true /* allowed */); + displays, -1 /* callingUid */, true /* allowed */, true /* crossUser */, + PROFILE_IDS); assertThat(tasks).hasSize(numTasks); for (int i = 0; i < numTasks; i++) { assertEquals(numTasks - i - 1, tasks.get(i).id); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java index 19fd93fee5f0..6e41118997ac 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java @@ -271,6 +271,54 @@ public class TaskStackChangedListenerTest { waitForCallback(singleTaskDisplayDrawnLatch); } + @Test + public void testSingleTaskDisplayEmpty() throws Exception { + final Instrumentation instrumentation = getInstrumentation(); + + final CountDownLatch activityViewReadyLatch = new CountDownLatch(1); + final CountDownLatch activityViewDestroyedLatch = new CountDownLatch(1); + final CountDownLatch singleTaskDisplayDrawnLatch = new CountDownLatch(1); + final CountDownLatch singleTaskDisplayEmptyLatch = new CountDownLatch(1); + + registerTaskStackChangedListener(new TaskStackListener() { + @Override + public void onSingleTaskDisplayDrawn(int displayId) throws RemoteException { + singleTaskDisplayDrawnLatch.countDown(); + } + @Override + public void onSingleTaskDisplayEmpty(int displayId) + throws RemoteException { + singleTaskDisplayEmptyLatch.countDown(); + } + }); + final ActivityViewTestActivity activity = + (ActivityViewTestActivity) startTestActivity(ActivityViewTestActivity.class); + final ActivityView activityView = activity.getActivityView(); + activityView.setCallback(new ActivityView.StateCallback() { + @Override + public void onActivityViewReady(ActivityView view) { + activityViewReadyLatch.countDown(); + } + + @Override + public void onActivityViewDestroyed(ActivityView view) { + activityViewDestroyedLatch.countDown(); + } + }); + waitForCallback(activityViewReadyLatch); + + final Context context = instrumentation.getContext(); + Intent intent = new Intent(context, ActivityInActivityView.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); + activityView.startActivity(intent); + waitForCallback(singleTaskDisplayDrawnLatch); + assertEquals(1, singleTaskDisplayEmptyLatch.getCount()); + + activityView.release(); + waitForCallback(activityViewDestroyedLatch); + waitForCallback(singleTaskDisplayEmptyLatch); + } + /** * Starts the provided activity and returns the started instance. */ diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java index b93c994f4d8f..acfc2ea3d402 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java @@ -114,16 +114,12 @@ public class WindowContainerTests extends WindowTestsBase { @Test public void testAddChildSetsSurfacePosition() { try (MockSurfaceBuildingContainer top = new MockSurfaceBuildingContainer(mWm)) { - - final SurfaceControl.Transaction transaction = mock(SurfaceControl.Transaction.class); - mWm.mTransactionFactory = () -> transaction; - WindowContainer child = new WindowContainer(mWm); child.setBounds(1, 1, 10, 10); - verify(transaction, never()).setPosition(any(), anyFloat(), anyFloat()); + verify(mTransaction, never()).setPosition(any(), anyFloat(), anyFloat()); top.addChild(child, 0); - verify(transaction, times(1)).setPosition(any(), eq(1.f), eq(1.f)); + verify(mTransaction, times(1)).setPosition(any(), eq(1.f), eq(1.f)); } } diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java index 99337565e128..735b9a1dcf2e 100644 --- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java +++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java @@ -325,9 +325,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { false /* Don't notify for synchronous calls */); // Initialize power save, call active state monitoring logic. - if (status == STATUS_OK && !mRecognitionRequested) { + if (status == STATUS_OK) { initializeTelephonyAndPowerStateListeners(); - mRecognitionRequested = true; } return status; @@ -481,6 +480,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { if (unloadModel && modelData.isModelLoaded()) { Slog.d(TAG, "Unloading previously loaded stale model."); + if (mModule == null) { + return STATUS_ERROR; + } status = mModule.unloadSoundModel(modelData.getHandle()); MetricsLogger.count(mContext, "sth_unloading_stale_model", 1); if (status != SoundTrigger.STATUS_OK) { @@ -550,6 +552,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { } } + if (mModule == null) { + return STATUS_ERROR; + } int status = mModule.unloadSoundModel(modelData.getHandle()); if (status != SoundTrigger.STATUS_OK) { Slog.w(TAG, "unloadGenericSoundModel() call failed with " + status); @@ -878,6 +883,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { mContext.unregisterReceiver(mPowerSaveModeListener); mPowerSaveModeListener = null; } + mRecognitionRequested = false; } // Clears state for all models (generic and keyphrase). @@ -924,6 +930,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { } private void initializeTelephonyAndPowerStateListeners() { + if (mRecognitionRequested) { + return; + } long token = Binder.clearCallingIdentity(); try { // Get the current call state synchronously for the first recognition. @@ -941,6 +950,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { } mIsPowerSaveMode = mPowerManager.getPowerSaveState(ServiceType.SOUND) .batterySaverEnabled; + + mRecognitionRequested = true; } finally { Binder.restoreCallingIdentity(token); } @@ -987,6 +998,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { if (exception != null) { Slog.e(TAG, "forceStopAndUnloadModel", exception); } + if (mModule == null) { + return; + } if (modelData.isModelStarted()) { Slog.d(TAG, "Stopping previously started dangling model " + modelData.getHandle()); if (mModule.stopRecognition(modelData.getHandle()) != STATUS_OK) { @@ -1093,6 +1107,13 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { // a recognition include: no active phone call or not being in a power save mode. Also, // the native service should be enabled. private boolean isRecognitionAllowed() { + // if mRecognitionRequested is false, call and power state listeners are not registered so + // we read current state directly from services + if (!mRecognitionRequested) { + mCallActive = mTelephonyManager.getCallState() == TelephonyManager.CALL_STATE_OFFHOOK; + mIsPowerSaveMode = + mPowerManager.getPowerSaveState(ServiceType.SOUND).batterySaverEnabled; + } return !mCallActive && !mServiceDisabled && !mIsPowerSaveMode; } @@ -1116,6 +1137,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { return STATUS_OK; } + if (mModule == null) { + return STATUS_ERROR; + } int status = mModule.startRecognition(handle, config); if (status != SoundTrigger.STATUS_OK) { Slog.w(TAG, "startRecognition failed with " + status); @@ -1152,8 +1176,11 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { } private int stopRecognitionLocked(ModelData modelData, boolean notify) { - IRecognitionStatusCallback callback = modelData.getCallback(); + if (mModule == null) { + return STATUS_ERROR; + } + IRecognitionStatusCallback callback = modelData.getCallback(); // Stop recognition. int status = STATUS_OK; diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index e1ffb0f179f8..46d7509b43ca 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -1281,9 +1281,12 @@ public class VoiceInteractionManagerService extends SystemService { RoleObserver(@NonNull @CallbackExecutor Executor executor) { mRm.addOnRoleHoldersChangedListenerAsUser(executor, this, UserHandle.ALL); - UserHandle currentUser = UserHandle.of(LocalServices.getService( - ActivityManagerInternal.class).getCurrentUserId()); - onRoleHoldersChanged(RoleManager.ROLE_ASSISTANT, currentUser); + // Sync only if assistant role has been initialized. + if (mRm.isRoleAvailable(RoleManager.ROLE_ASSISTANT)) { + UserHandle currentUser = UserHandle.of(LocalServices.getService( + ActivityManagerInternal.class).getCurrentUserId()); + onRoleHoldersChanged(RoleManager.ROLE_ASSISTANT, currentUser); + } } private @NonNull String getDefaultRecognizer(@NonNull UserHandle user) { diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java index f16dec6fb670..0ff92739f8b6 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java @@ -194,7 +194,7 @@ final class VoiceInteractionSessionConnection implements ServiceConnection, if (!mFullyBound) { mFullyBound = mContext.bindServiceAsUser(mBindIntent, mFullConnection, Context.BIND_AUTO_CREATE | Context.BIND_TREAT_LIKE_ACTIVITY - | Context.BIND_FOREGROUND_SERVICE + | Context.BIND_SCHEDULE_LIKE_TOP_APP | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS, new UserHandle(mUser)); } |