diff options
26 files changed, 429 insertions, 101 deletions
diff --git a/core/java/android/animation/OWNERS b/core/java/android/animation/OWNERS index 822a35c348ed..f3b330a02116 100644 --- a/core/java/android/animation/OWNERS +++ b/core/java/android/animation/OWNERS @@ -2,5 +2,4 @@ romainguy@google.com tianliu@google.com -alanv@google.com adamp@google.com diff --git a/core/java/android/gesture/OWNERS b/core/java/android/gesture/OWNERS index b3b8775dc036..168630af6da4 100644 --- a/core/java/android/gesture/OWNERS +++ b/core/java/android/gesture/OWNERS @@ -1,7 +1,6 @@ # Bug component: 25700 romainguy@google.com -alanv@google.com adamp@google.com aurimas@google.com nduca@google.com diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS index 9f3364feda84..04d49708b6ef 100644 --- a/core/java/android/os/OWNERS +++ b/core/java/android/os/OWNERS @@ -107,4 +107,8 @@ per-file SystemConfigManager.java = file:/PACKAGE_MANAGER_OWNERS per-file ProfilingServiceManager.java = file:/PERFORMANCE_OWNERS # Memory -per-file OomKillRecord.java = file:/MEMORY_OWNERS
\ No newline at end of file +per-file OomKillRecord.java = file:/MEMORY_OWNERS + +# MessageQueue +per-file MessageQueue.java = mfasheh@google.com, shayba@google.com +per-file Message.java = mfasheh@google.com, shayba@google.com diff --git a/core/java/android/transition/OWNERS b/core/java/android/transition/OWNERS index eb5a58115a8f..2a8d9404dbbd 100644 --- a/core/java/android/transition/OWNERS +++ b/core/java/android/transition/OWNERS @@ -2,5 +2,4 @@ romainguy@google.com mount@google.com -alanv@google.com adamp@google.com diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS index 07d05a4ff1ea..31a8dfaaf86b 100644 --- a/core/java/android/view/OWNERS +++ b/core/java/android/view/OWNERS @@ -1,7 +1,6 @@ # Bug component: 25700 romainguy@google.com -alanv@google.com adamp@google.com aurimas@google.com nduca@google.com diff --git a/core/java/android/view/accessibility/OWNERS b/core/java/android/view/accessibility/OWNERS index b0943e9cff62..f62b33f1f753 100644 --- a/core/java/android/view/accessibility/OWNERS +++ b/core/java/android/view/accessibility/OWNERS @@ -5,7 +5,6 @@ include /services/accessibility/OWNERS # Android members outside of Accessibility adamp@google.com #{LAST_RESORT_SUGGESTION} -alanv@google.com #{LAST_RESORT_SUGGESTION} aurimas@google.com #{LAST_RESORT_SUGGESTION} jjaggi@google.com #{LAST_RESORT_SUGGESTION} ogunwale@google.com #{LAST_RESORT_SUGGESTION} diff --git a/core/java/android/view/animation/OWNERS b/core/java/android/view/animation/OWNERS index 9b8f4d995975..2fa01c36ea96 100644 --- a/core/java/android/view/animation/OWNERS +++ b/core/java/android/view/animation/OWNERS @@ -2,5 +2,4 @@ romainguy@google.com tianliu@google.com -alanv@google.com adamp@google.com diff --git a/core/java/android/widget/OWNERS b/core/java/android/widget/OWNERS index 1dc90edbd1e5..8b8090b67133 100644 --- a/core/java/android/widget/OWNERS +++ b/core/java/android/widget/OWNERS @@ -1,7 +1,6 @@ # Bug component: 25700 romainguy@google.com -alanv@google.com adamp@google.com aurimas@google.com siyamed@google.com diff --git a/core/res/OWNERS b/core/res/OWNERS index dce578afe3d4..22ea9dadab34 100644 --- a/core/res/OWNERS +++ b/core/res/OWNERS @@ -66,6 +66,11 @@ per-file res/values/symbols.xml = file:/PERFORMANCE_OWNERS per-file res/xml/power_profile.xml = file:/BATTERY_STATS_OWNERS per-file res/xml/power_profile_test.xml = file:/BATTERY_STATS_OWNERS +# RemoteView color resources +per-file remote_color_resources_res/symbols.xml = pbdr@google.com +per-file remote_color_resources_res/values/public.xml = pbdr@google.com +per-file remote_color_resources_res/values/colors.xml = pbdr@google.com + # Telephony per-file res/values/config_telephony.xml = file:/platform/frameworks/opt/telephony:/OWNERS per-file res/xml/sms_short_codes.xml = file:/platform/frameworks/opt/telephony:/OWNERS @@ -79,4 +84,4 @@ per-file res/values/attrs.xml = arteiro@google.com per-file res/values/styles.xml = arteiro@google.com per-file res/values/symbols.xml = arteiro@google.com per-file res/values/themes_device_defaults.xml = arteiro@google.com -per-file res/values/styles_material.xml = arteiro@google.com
\ No newline at end of file +per-file res/values/styles_material.xml = arteiro@google.com diff --git a/core/tests/coretests/src/android/os/BinderTest.java b/core/tests/coretests/src/android/os/BinderTest.java index 6c8b69fc9c5c..9767d677807d 100644 --- a/core/tests/coretests/src/android/os/BinderTest.java +++ b/core/tests/coretests/src/android/os/BinderTest.java @@ -20,6 +20,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; import static org.testng.Assert.assertThrows; import android.platform.test.annotations.IgnoreUnderRavenwood; @@ -27,6 +29,9 @@ import android.platform.test.ravenwood.RavenwoodRule; import androidx.test.filters.SmallTest; +import com.android.internal.os.BinderInternal; + + import org.junit.Rule; import org.junit.Test; @@ -81,4 +86,27 @@ public class BinderTest { binder.setExtension(null); assertNull(binder.getExtension()); } + + @SmallTest + @Test(expected = java.lang.SecurityException.class) + public void testServiceManagerNativeSecurityException() throws RemoteException { + // Find the service manager + IServiceManager sServiceManager = ServiceManagerNative + .asInterface(Binder.allowBlocking(BinderInternal.getContextObject())); + + Binder binder = new Binder(); + sServiceManager.addService("ValidName", binder, + anyBoolean(), anyInt()); + } + + @SmallTest + @Test(expected = java.lang.NullPointerException.class) + public void testServiceManagerNativeNullptrException() throws RemoteException { + // Find the service manager + IServiceManager sServiceManager = ServiceManagerNative + .asInterface(Binder.allowBlocking(BinderInternal.getContextObject())); + + sServiceManager.addService("ValidName", null, + anyBoolean(), anyInt()); + } } diff --git a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioPolicyDeathTest.java b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioPolicyDeathTest.java index 48c51af26d3a..61670e97ab3f 100644 --- a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioPolicyDeathTest.java +++ b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioPolicyDeathTest.java @@ -128,7 +128,7 @@ public class AudioPolicyDeathTest { res.getInt(mContext.getResources().getString(R.string.status_key))); }); - // Launch process registering a dynamic auido policy and dying after RECORD_TIME_MS ms + // Launch process registering a dynamic audio policy and dying after RECORD_TIME_MS ms // RECORD_TIME_MS must be shorter than PLAYBACK_TIME_MS Intent intent = new Intent(mContext, AudioPolicyDeathTestActivity.class); intent.putExtra(mContext.getResources().getString(R.string.capture_duration_key), diff --git a/packages/DynamicSystemInstallationService/Android.bp b/packages/DynamicSystemInstallationService/Android.bp index b8f54b3faf63..ae6901917630 100644 --- a/packages/DynamicSystemInstallationService/Android.bp +++ b/packages/DynamicSystemInstallationService/Android.bp @@ -30,10 +30,6 @@ android_app { certificate: "platform", privileged: true, platform_apis: true, - - optimize: { - enabled: false, - }, } java_library { diff --git a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java index 7fcef9c90812..c0b354cc69d9 100644 --- a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java +++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java @@ -2373,7 +2373,7 @@ public class CameraExtensionsProxyService extends Service { public Plane[] getPlanes() { throwISEIfImageIsInvalid(); if (mPlanes == null) { - int fenceFd = mParcelImage.fence != null ? mParcelImage.fence.getFd() : -1; + int fenceFd = mParcelImage.fence != null ? mParcelImage.fence.detachFd() : -1; mGraphicBuffer = GraphicBuffer.createFromHardwareBuffer(mParcelImage.buffer); mPlanes = ImageReader.initializeImagePlanes(mParcelImage.planeCount, mGraphicBuffer, fenceFd, mParcelImage.format, mParcelImage.timestamp, diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java index f69a521130ab..23cee9db2138 100644 --- a/services/core/java/com/android/server/BootReceiver.java +++ b/services/core/java/com/android/server/BootReceiver.java @@ -141,6 +141,10 @@ public class BootReceiver extends BroadcastReceiver { private static final int MAX_ERROR_REPORTS = 8; private static int sSentReports = 0; + // Max tombstone file size to add to dropbox. + private static final long MAX_TOMBSTONE_SIZE_BYTES = + DropBoxManagerService.DEFAULT_QUOTA_KB * 1024; + @Override public void onReceive(final Context context, Intent intent) { // Log boot events in the background to avoid blocking the main thread with I/O @@ -390,6 +394,12 @@ public class BootReceiver extends BroadcastReceiver { private static void addAugmentedProtoToDropbox( File tombstone, DropBoxManager db, DropboxRateLimiter.RateLimitResult rateLimitResult) throws IOException { + // Do not add proto files larger than 20Mb to DropBox as they can cause OOMs when + // processing large tombstones. The text tombstone is still added to DropBox. + if (tombstone.length() > MAX_TOMBSTONE_SIZE_BYTES) { + Slog.w(TAG, "Tombstone too large to add to DropBox: " + tombstone.toPath()); + return; + } // Read the proto tombstone file as bytes. final byte[] tombstoneBytes = Files.readAllBytes(tombstone.toPath()); diff --git a/services/core/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java index f82a6aabfefb..70b3bde746af 100644 --- a/services/core/java/com/android/server/DropBoxManagerService.java +++ b/services/core/java/com/android/server/DropBoxManagerService.java @@ -106,7 +106,7 @@ public final class DropBoxManagerService extends SystemService { private static final int DEFAULT_AGE_SECONDS = 3 * 86400; private static final int DEFAULT_MAX_FILES = 1000; private static final int DEFAULT_MAX_FILES_LOWRAM = 300; - private static final int DEFAULT_QUOTA_KB = 10 * 1024; + public static final int DEFAULT_QUOTA_KB = Build.IS_USERDEBUG ? 20 * 1024 : 10 * 1024; private static final int DEFAULT_QUOTA_PERCENT = 10; private static final int DEFAULT_RESERVE_PERCENT = 0; private static final int QUOTA_RESCAN_MILLIS = 5000; diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java index a61925732256..966478e33c73 100644 --- a/services/core/java/com/android/server/PackageWatchdog.java +++ b/services/core/java/com/android/server/PackageWatchdog.java @@ -138,6 +138,12 @@ public class PackageWatchdog { static final long DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS = TimeUnit.MINUTES.toMillis(10); + // Time needed to apply mitigation + private static final String MITIGATION_WINDOW_MS = + "persist.device_config.configuration.mitigation_window_ms"; + @VisibleForTesting + static final long DEFAULT_MITIGATION_WINDOW_MS = TimeUnit.SECONDS.toMillis(5); + // Threshold level at which or above user might experience significant disruption. private static final String MAJOR_USER_IMPACT_LEVEL_THRESHOLD = "persist.device_config.configuration.major_user_impact_level_threshold"; @@ -210,6 +216,9 @@ public class PackageWatchdog { @GuardedBy("mLock") private boolean mSyncRequired = false; + @GuardedBy("mLock") + private long mLastMitigation = -1000000; + @FunctionalInterface @VisibleForTesting interface SystemClock { @@ -400,6 +409,16 @@ public class PackageWatchdog { Slog.w(TAG, "Could not resolve a list of failing packages"); return; } + synchronized (mLock) { + final long now = mSystemClock.uptimeMillis(); + if (Flags.recoverabilityDetection()) { + if (now >= mLastMitigation + && (now - mLastMitigation) < getMitigationWindowMs()) { + Slog.i(TAG, "Skipping onPackageFailure mitigation"); + return; + } + } + } mLongTaskHandler.post(() -> { synchronized (mLock) { if (mAllObservers.isEmpty()) { @@ -500,10 +519,17 @@ public class PackageWatchdog { int currentObserverImpact, int mitigationCount) { if (currentObserverImpact < getUserImpactLevelLimit()) { + synchronized (mLock) { + mLastMitigation = mSystemClock.uptimeMillis(); + } currentObserverToNotify.execute(versionedPackage, failureReason, mitigationCount); } } + private long getMitigationWindowMs() { + return SystemProperties.getLong(MITIGATION_WINDOW_MS, DEFAULT_MITIGATION_WINDOW_MS); + } + /** * Called when the system server boots. If the system server is detected to be in a boot loop, diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 54fb65c4e799..1ad0abf45f55 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -581,7 +581,7 @@ public class LockSettingsService extends ILockSettings.Stub { public RebootEscrowManager getRebootEscrowManager(RebootEscrowManager.Callbacks callbacks, LockSettingsStorage storage) { return new RebootEscrowManager(mContext, callbacks, storage, - getHandler(getServiceThread())); + getHandler(getServiceThread()), getUserManagerInternal()); } public int binderGetCallingUid() { diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java index e1cd2c585146..d0b8990e37c4 100644 --- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java +++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java @@ -51,16 +51,20 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.widget.RebootEscrowListener; +import com.android.server.pm.UserManagerInternal; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Objects; +import java.util.Set; import javax.crypto.SecretKey; @@ -138,6 +142,7 @@ class RebootEscrowManager { ERROR_KEYSTORE_FAILURE, ERROR_NO_NETWORK, ERROR_TIMEOUT_EXHAUSTED, + ERROR_NO_REBOOT_ESCROW_DATA, }) @Retention(RetentionPolicy.SOURCE) @interface RebootEscrowErrorCode { @@ -153,6 +158,7 @@ class RebootEscrowManager { static final int ERROR_KEYSTORE_FAILURE = 7; static final int ERROR_NO_NETWORK = 8; static final int ERROR_TIMEOUT_EXHAUSTED = 9; + static final int ERROR_NO_REBOOT_ESCROW_DATA = 10; private @RebootEscrowErrorCode int mLoadEscrowDataErrorCode = ERROR_NONE; @@ -222,11 +228,16 @@ class RebootEscrowManager { private final RebootEscrowKeyStoreManager mKeyStoreManager; private final LockSettingsStorage mStorage; private RebootEscrowProviderInterface mRebootEscrowProvider; + private final UserManagerInternal mUserManagerInternal; - Injector(Context context, LockSettingsStorage storage) { + Injector( + Context context, + LockSettingsStorage storage, + UserManagerInternal userManagerInternal) { mContext = context; mStorage = storage; mKeyStoreManager = new RebootEscrowKeyStoreManager(); + mUserManagerInternal = userManagerInternal; } private RebootEscrowProviderInterface createRebootEscrowProvider() { @@ -326,6 +337,10 @@ class RebootEscrowManager { return (UserManager) mContext.getSystemService(Context.USER_SERVICE); } + public UserManagerInternal getUserManagerInternal() { + return mUserManagerInternal; + } + public RebootEscrowKeyStoreManager getKeyStoreManager() { return mKeyStoreManager; } @@ -402,8 +417,8 @@ class RebootEscrowManager { } RebootEscrowManager(Context context, Callbacks callbacks, LockSettingsStorage storage, - Handler handler) { - this(new Injector(context, storage), callbacks, storage, handler); + Handler handler, UserManagerInternal userManagerInternal) { + this(new Injector(context, storage, userManagerInternal), callbacks, storage, handler); } @VisibleForTesting @@ -451,18 +466,50 @@ class RebootEscrowManager { onEscrowRestoreComplete(false, attemptCount, retryHandler); } - void loadRebootEscrowDataIfAvailable(Handler retryHandler) { - List<UserInfo> users = mUserManager.getUsers(); + private List<UserInfo> getUsersToUnlock(List<UserInfo> users) { + // System user must be unlocked to unlock any other user + if (mCallbacks.isUserSecure(USER_SYSTEM) && !mStorage.hasRebootEscrow(USER_SYSTEM)) { + Slog.i(TAG, "No reboot escrow data found for system user"); + return Collections.emptyList(); + } + + Set<Integer> noEscrowDataUsers = new HashSet<>(); + for (UserInfo user : users) { + if (mCallbacks.isUserSecure(user.id) + && !mStorage.hasRebootEscrow(user.id)) { + Slog.d(TAG, "No reboot escrow data found for user " + user); + noEscrowDataUsers.add(user.id); + } + } + List<UserInfo> rebootEscrowUsers = new ArrayList<>(); for (UserInfo user : users) { - if (mCallbacks.isUserSecure(user.id) && mStorage.hasRebootEscrow(user.id)) { - rebootEscrowUsers.add(user); + // No lskf, no need to unlock. + if (!mCallbacks.isUserSecure(user.id)) { + continue; + } + // Don't unlock if user or user's parent does not have reboot data + int userId = user.id; + if (noEscrowDataUsers.contains(userId) + || noEscrowDataUsers.contains( + mInjector.getUserManagerInternal().getProfileParentId(userId))) { + continue; } + rebootEscrowUsers.add(user); } + return rebootEscrowUsers; + } + + void loadRebootEscrowDataIfAvailable(Handler retryHandler) { + List<UserInfo> users = mUserManager.getUsers(); + List<UserInfo> rebootEscrowUsers = getUsersToUnlock(users); if (rebootEscrowUsers.isEmpty()) { Slog.i(TAG, "No reboot escrow data found for users," + " skipping loading escrow data"); + setLoadEscrowDataErrorCode(ERROR_NO_REBOOT_ESCROW_DATA, retryHandler); + reportMetricOnRestoreComplete( + /* success= */ false, /* attemptCount= */ 1, retryHandler); clearMetricsStorage(); return; } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 4d05c36cff3a..4e029fde8bf5 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -2291,7 +2291,7 @@ public class NotificationManagerService extends SystemService { @VisibleForTesting void clearNotifications() { - synchronized (mNotificationList) { + synchronized (mNotificationLock) { mEnqueuedNotifications.clear(); mNotificationList.clear(); mNotificationsByKey.clear(); @@ -2301,21 +2301,27 @@ public class NotificationManagerService extends SystemService { @VisibleForTesting void addNotification(NotificationRecord r) { - mNotificationList.add(r); - mNotificationsByKey.put(r.getSbn().getKey(), r); - if (r.getSbn().isGroup()) { - mSummaryByGroupKey.put(r.getGroupKey(), r); + synchronized (mNotificationLock) { + mNotificationList.add(r); + mNotificationsByKey.put(r.getSbn().getKey(), r); + if (r.getSbn().isGroup()) { + mSummaryByGroupKey.put(r.getGroupKey(), r); + } } } @VisibleForTesting void addEnqueuedNotification(NotificationRecord r) { - mEnqueuedNotifications.add(r); + synchronized (mNotificationLock) { + mEnqueuedNotifications.add(r); + } } @VisibleForTesting NotificationRecord getNotificationRecord(String key) { - return mNotificationsByKey.get(key); + synchronized (mNotificationLock) { + return mNotificationsByKey.get(key); + } } diff --git a/services/core/java/com/android/server/os/NativeTombstoneManager.java b/services/core/java/com/android/server/os/NativeTombstoneManager.java index f6e7ef3d50e9..3bcaf58d0a13 100644 --- a/services/core/java/com/android/server/os/NativeTombstoneManager.java +++ b/services/core/java/com/android/server/os/NativeTombstoneManager.java @@ -56,6 +56,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; +import java.lang.ref.Reference; import java.util.ArrayList; import java.util.Collections; import java.util.Optional; @@ -73,6 +74,9 @@ public final class NativeTombstoneManager { private final Context mContext; private final Handler mHandler; + // TODO(b/339371242): The garbage collector is misbehaving, and we must have + // a reference to this member outside the constructor. More details in the + // corresponding comment elsewhere in this class. private final TombstoneWatcher mWatcher; private final ReentrantLock mTmpFileLock = new ReentrantLock(); @@ -139,6 +143,14 @@ public final class NativeTombstoneManager { processName = parsedTombstone.get().getProcessName(); } BootReceiver.addTombstoneToDropBox(mContext, path, isProtoFile, processName, mTmpFileLock); + + // TODO(b/339371242): An optimizer on WearOS is misbehaving and this member is being garbage + // collected as it's never referenced inside this class outside of the constructor. But, + // it's a file watcher, and needs to stay alive to do its job. So, add a cheap check here to + // force the GC to behave itself. From a technical perspective, it's possible that we need + // to add this trick to every single member function, but this seems to work correctly in + // practice and avoids polluting a lot more of this class. + Reference.reachabilityFence(mWatcher); } private Optional<TombstoneFile> handleProtoTombstone(File path, boolean addToList) { diff --git a/services/core/java/com/android/server/tracing/TracingServiceProxy.java b/services/core/java/com/android/server/tracing/TracingServiceProxy.java index c1d92cffe1a7..68eb8eb1deaf 100644 --- a/services/core/java/com/android/server/tracing/TracingServiceProxy.java +++ b/services/core/java/com/android/server/tracing/TracingServiceProxy.java @@ -93,6 +93,7 @@ public class TracingServiceProxy extends SystemService { private final Context mContext; private final PackageManager mPackageManager; private final LruCache<ComponentName, ServiceConnector<IMessenger>> mCachedReporterServices; + private boolean mServicePublished = false; private final ITracingServiceProxy.Stub mTracingServiceProxy = new ITracingServiceProxy.Stub() { /** @@ -122,9 +123,12 @@ public class TracingServiceProxy extends SystemService { public void onStart() {} @Override - public void onBootPhase(int phase) { - if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { + public void onUserUnlocking(@NonNull TargetUser user) { + // We need the device storage to be unlocked before we can accept and forward + // requests. + if (!mServicePublished) { publishBinderService(TRACING_SERVICE_PROXY_BINDER_NAME, mTracingServiceProxy); + mServicePublished = true; } } diff --git a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java index 3cf19ddbd89d..dd53d32c7d85 100644 --- a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java +++ b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java @@ -561,32 +561,35 @@ public final class AccessibilityWindowsPopulator extends WindowInfosListener { } void dump(PrintWriter pw, String prefix) { - pw.print(prefix); pw.println("AccessibilityWindowsPopulator"); - String prefix2 = prefix + " "; + synchronized (mLock) { + pw.print(prefix); pw.println("AccessibilityWindowsPopulator"); + String prefix2 = prefix + " "; - pw.print(prefix2); pw.print("mWindowsNotificationEnabled: "); - pw.println(mWindowsNotificationEnabled); + pw.print(prefix2); pw.print("mWindowsNotificationEnabled: "); + pw.println(mWindowsNotificationEnabled); - if (mVisibleWindows.isEmpty()) { - pw.print(prefix2); pw.println("No visible windows"); - } else { - pw.print(prefix2); pw.print(mVisibleWindows.size()); - pw.print(" visible windows: "); pw.println(mVisibleWindows); - } - KeyDumper noKeyDumper = (i, k) -> {}; // display id is already shown on value; - KeyDumper displayDumper = (i, d) -> pw.printf("%sDisplay #%d: ", prefix, d); - // Ideally magnificationSpecDumper should use spec.dump(pw), but there is no such method - ValueDumper<MagnificationSpec> magnificationSpecDumper = spec -> pw.print(spec); - - dumpSparseArray(pw, prefix2, mDisplayInfos, "display info", noKeyDumper, d -> pw.print(d)); - dumpSparseArray(pw, prefix2, mInputWindowHandlesOnDisplays, "window handles on display", - displayDumper, list -> pw.print(list)); - dumpSparseArray(pw, prefix2, mMagnificationSpecInverseMatrix, "magnification spec matrix", - noKeyDumper, matrix -> matrix.dump(pw)); - dumpSparseArray(pw, prefix2, mCurrentMagnificationSpec, "current magnification spec", - noKeyDumper, magnificationSpecDumper); - dumpSparseArray(pw, prefix2, mPreviousMagnificationSpec, "previous magnification spec", - noKeyDumper, magnificationSpecDumper); + if (mVisibleWindows.isEmpty()) { + pw.print(prefix2); pw.println("No visible windows"); + } else { + pw.print(prefix2); pw.print(mVisibleWindows.size()); + pw.print(" visible windows: "); pw.println(mVisibleWindows); + } + KeyDumper noKeyDumper = (i, k) -> {}; // display id is already shown on value; + KeyDumper displayDumper = (i, d) -> pw.printf("%sDisplay #%d: ", prefix, d); + // Ideally magnificationSpecDumper should use spec.dump(pw), but there is no such method + ValueDumper<MagnificationSpec> magnificationSpecDumper = spec -> pw.print(spec); + + dumpSparseArray(pw, prefix2, mDisplayInfos, + "display info", noKeyDumper, d -> pw.print(d)); + dumpSparseArray(pw, prefix2, mInputWindowHandlesOnDisplays, + "window handles on display", displayDumper, list -> pw.print(list)); + dumpSparseArray(pw, prefix2, mMagnificationSpecInverseMatrix, + "magnification spec matrix", noKeyDumper, matrix -> matrix.dump(pw)); + dumpSparseArray(pw, prefix2, mCurrentMagnificationSpec, + "current magnification spec", noKeyDumper, magnificationSpecDumper); + dumpSparseArray(pw, prefix2, mPreviousMagnificationSpec, + "previous magnification spec", noKeyDumper, magnificationSpecDumper); + } } @GuardedBy("mLock") diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 5d019122d52e..76be8aebb54e 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -1257,10 +1257,13 @@ class TaskFragment extends WindowContainer<WindowContainer> { // In a multi-resumed environment, like in a freeform device, the top // activity can be resumed, but it might not be the focused app. - // Set focused app when top activity is resumed - if (taskDisplayArea.inMultiWindowMode() && taskDisplayArea.mDisplayContent != null - && taskDisplayArea.mDisplayContent.mFocusedApp != next) { - taskDisplayArea.mDisplayContent.setFocusedApp(next); + // Set focused app when top activity is resumed. However, we shouldn't do it for a + // same task because it can break focused state. (e.g. activity embedding) + if (taskDisplayArea.inMultiWindowMode() && taskDisplayArea.mDisplayContent != null) { + final ActivityRecord focusedApp = taskDisplayArea.mDisplayContent.mFocusedApp; + if (focusedApp == null || focusedApp.getTask() != next.getTask()) { + taskDisplayArea.mDisplayContent.setFocusedApp(next); + } } ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Top activity " + "resumed %s", next); diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java index 9f9764853bef..33bf4bd1cc02 100644 --- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java +++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java @@ -58,7 +58,6 @@ import java.util.concurrent.TimeUnit; public final class ProfcollectForwardingService extends SystemService { public static final String LOG_TAG = "ProfcollectForwardingService"; - private static final boolean DEBUG = Log.isLoggable(LOG_TAG, Log.DEBUG); private static final String INTENT_UPLOAD_PROFILES = "com.android.server.profcollect.UPLOAD_PROFILES"; private static final long BG_PROCESS_INTERVAL = TimeUnit.HOURS.toMillis(4); // every 4 hours. @@ -120,9 +119,6 @@ public final class ProfcollectForwardingService extends SystemService { @Override public void onStart() { - if (DEBUG) { - Log.d(LOG_TAG, "Profcollect forwarding service start"); - } connectNativeService(); } @@ -245,9 +241,6 @@ public final class ProfcollectForwardingService extends SystemService { @Override public boolean onStartJob(JobParameters params) { - if (DEBUG) { - Log.d(LOG_TAG, "Starting background process job"); - } createAndUploadReport(sSelfService); jobFinished(params, false); return true; @@ -289,9 +282,6 @@ public final class ProfcollectForwardingService extends SystemService { "applaunch_trace_freq", 2); int randomNum = ThreadLocalRandom.current().nextInt(100); if (randomNum < traceFrequency) { - if (DEBUG) { - Log.d(LOG_TAG, "Tracing on app launch event: " + packageName); - } BackgroundThread.get().getThreadHandler().post(() -> { try { mIProfcollect.trace_once("applaunch"); @@ -331,9 +321,6 @@ public final class ProfcollectForwardingService extends SystemService { "dex2oat_trace_freq", 25); int randomNum = ThreadLocalRandom.current().nextInt(100); if (randomNum < traceFrequency) { - if (DEBUG) { - Log.d(LOG_TAG, "Tracing on dex2oat event"); - } BackgroundThread.get().getThreadHandler().post(() -> { try { // Dex2oat could take a while before it starts. Add a short delay before start @@ -352,11 +339,6 @@ public final class ProfcollectForwardingService extends SystemService { updateEngine.bind(new UpdateEngineCallback() { @Override public void onStatusUpdate(int status, float percent) { - if (DEBUG) { - Log.d(LOG_TAG, "Received OTA status update, status: " + status + ", percent: " - + percent); - } - if (status == UpdateEngine.UpdateStatusConstants.UPDATED_NEED_REBOOT) { createAndUploadReport(sSelfService); } @@ -388,8 +370,5 @@ public final class ProfcollectForwardingService extends SystemService { .putExtra("filename", reportName); pfs.getContext().sendBroadcast(intent); }); - if (DEBUG) { - Log.d(LOG_TAG, "Sent report for upload."); - } } } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java index 64e62369f955..17b499e112bc 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java @@ -19,6 +19,7 @@ package com.android.server.locksettings; import static android.content.pm.UserInfo.FLAG_FULL; import static android.content.pm.UserInfo.FLAG_PRIMARY; import static android.content.pm.UserInfo.FLAG_PROFILE; +import static android.content.pm.UserInfo.NO_PROFILE_GROUP_ID; import static android.os.UserHandle.USER_SYSTEM; import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_ESCROW_NOT_READY; @@ -32,6 +33,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyByte; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; @@ -65,6 +67,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.widget.RebootEscrowListener; import com.android.server.locksettings.ResumeOnRebootServiceProvider.ResumeOnRebootServiceConnection; +import com.android.server.pm.UserManagerInternal; import org.junit.Before; import org.junit.Test; @@ -107,6 +110,7 @@ public class RebootEscrowManagerTests { private Context mContext; private UserManager mUserManager; + private UserManagerInternal mUserManagerInternal; private RebootEscrowManager.Callbacks mCallbacks; private IRebootEscrow mRebootEscrow; private ResumeOnRebootServiceConnection mServiceConnection; @@ -126,13 +130,15 @@ public class RebootEscrowManagerTests { long getCurrentTimeMillis(); void reportMetric(boolean success, int errorCode, int serviceType, int attemptCount, - int escrowDurationInSeconds, int vbmetaDigestStatus, int durationSinceBootComplete); + int escrowDurationInSeconds, int vbmetaDigestStatus, + int durationSinceBootComplete); } static class MockInjector extends RebootEscrowManager.Injector { private final IRebootEscrow mRebootEscrow; private final RebootEscrowProviderInterface mDefaultRebootEscrowProvider; private final UserManager mUserManager; + private final UserManagerInternal mUserManagerInternal; private final MockableRebootEscrowInjected mInjected; private final RebootEscrowKeyStoreManager mKeyStoreManager; private boolean mServerBased; @@ -141,12 +147,16 @@ public class RebootEscrowManagerTests { private Consumer<ConnectivityManager.NetworkCallback> mNetworkConsumer; private boolean mWaitForInternet; - MockInjector(Context context, UserManager userManager, + MockInjector( + Context context, + UserManager userManager, + UserManagerInternal userManagerInternal, IRebootEscrow rebootEscrow, RebootEscrowKeyStoreManager keyStoreManager, LockSettingsStorageTestable storage, MockableRebootEscrowInjected injected) { - super(context, storage); + // TODO: change this + super(context, storage, userManagerInternal); mRebootEscrow = rebootEscrow; mServerBased = false; mWaitForInternet = false; @@ -159,16 +169,20 @@ public class RebootEscrowManagerTests { }; mDefaultRebootEscrowProvider = new RebootEscrowProviderHalImpl(halInjector); mUserManager = userManager; + mUserManagerInternal = userManagerInternal; mKeyStoreManager = keyStoreManager; mInjected = injected; } - MockInjector(Context context, UserManager userManager, + MockInjector( + Context context, + UserManager userManager, + UserManagerInternal userManagerInternal, ResumeOnRebootServiceConnection serviceConnection, RebootEscrowKeyStoreManager keyStoreManager, LockSettingsStorageTestable storage, MockableRebootEscrowInjected injected) { - super(context, storage); + super(context, storage, userManagerInternal); mRebootEscrow = null; mServerBased = true; mWaitForInternet = false; @@ -187,6 +201,7 @@ public class RebootEscrowManagerTests { mDefaultRebootEscrowProvider = new RebootEscrowProviderServerBasedImpl( storage, injector); mUserManager = userManager; + mUserManagerInternal = userManagerInternal; mKeyStoreManager = keyStoreManager; mInjected = injected; } @@ -202,6 +217,11 @@ public class RebootEscrowManagerTests { } @Override + public UserManagerInternal getUserManagerInternal() { + return mUserManagerInternal; + } + + @Override public boolean serverBasedResumeOnReboot() { return mServerBased; } @@ -289,8 +309,8 @@ public class RebootEscrowManagerTests { @Override public void reportMetric(boolean success, int errorCode, int serviceType, int attemptCount, - int escrowDurationInSeconds, int vbmetaDigestStatus, - int durationSinceBootComplete) { + int escrowDurationInSeconds, int vbmetaDigestStatus, + int durationSinceBootComplete) { mInjected.reportMetric(success, errorCode, serviceType, attemptCount, escrowDurationInSeconds, vbmetaDigestStatus, durationSinceBootComplete); @@ -301,6 +321,7 @@ public class RebootEscrowManagerTests { public void setUp_baseServices() throws Exception { mContext = new ContextWrapper(InstrumentationRegistry.getContext()); mUserManager = mock(UserManager.class); + mUserManagerInternal = mock(UserManagerInternal.class); mCallbacks = mock(RebootEscrowManager.Callbacks.class); mRebootEscrow = mock(IRebootEscrow.class); mServiceConnection = mock(ResumeOnRebootServiceConnection.class); @@ -314,28 +335,43 @@ public class RebootEscrowManagerTests { new File(InstrumentationRegistry.getContext().getFilesDir(), "locksettings")); ArrayList<UserInfo> users = new ArrayList<>(); - users.add(new UserInfo(PRIMARY_USER_ID, "primary", FLAG_PRIMARY)); - users.add(new UserInfo(WORK_PROFILE_USER_ID, "work", FLAG_PROFILE)); - users.add(new UserInfo(NONSECURE_SECONDARY_USER_ID, "non-secure", FLAG_FULL)); - users.add(new UserInfo(SECURE_SECONDARY_USER_ID, "secure", FLAG_FULL)); + users.add(createUser(PRIMARY_USER_ID, "primary", FLAG_PRIMARY, PRIMARY_USER_ID)); + users.add(createUser(WORK_PROFILE_USER_ID, "work", FLAG_PROFILE, PRIMARY_USER_ID)); + users.add( + createUser( + NONSECURE_SECONDARY_USER_ID, "non-secure", FLAG_FULL, NO_PROFILE_GROUP_ID)); + users.add(createUser(SECURE_SECONDARY_USER_ID, "secure", FLAG_FULL, NO_PROFILE_GROUP_ID)); when(mUserManager.getUsers()).thenReturn(users); when(mCallbacks.isUserSecure(PRIMARY_USER_ID)).thenReturn(true); when(mCallbacks.isUserSecure(WORK_PROFILE_USER_ID)).thenReturn(true); when(mCallbacks.isUserSecure(NONSECURE_SECONDARY_USER_ID)).thenReturn(false); when(mCallbacks.isUserSecure(SECURE_SECONDARY_USER_ID)).thenReturn(true); mInjected = mock(MockableRebootEscrowInjected.class); - mMockInjector = new MockInjector(mContext, mUserManager, mRebootEscrow, - mKeyStoreManager, mStorage, mInjected); + mMockInjector = + new MockInjector( + mContext, + mUserManager, + mUserManagerInternal, + mRebootEscrow, + mKeyStoreManager, + mStorage, + mInjected); HandlerThread thread = new HandlerThread("RebootEscrowManagerTest"); thread.start(); mHandler = new Handler(thread.getLooper()); mService = new RebootEscrowManager(mMockInjector, mCallbacks, mStorage, mHandler); - } private void setServerBasedRebootEscrowProvider() throws Exception { - mMockInjector = new MockInjector(mContext, mUserManager, mServiceConnection, - mKeyStoreManager, mStorage, mInjected); + mMockInjector = + new MockInjector( + mContext, + mUserManager, + mUserManagerInternal, + mServiceConnection, + mKeyStoreManager, + mStorage, + mInjected); mService = new RebootEscrowManager(mMockInjector, mCallbacks, mStorage, mHandler); } @@ -352,6 +388,12 @@ public class RebootEscrowManagerTests { waitForHandler(); } + private UserInfo createUser(int id, String name, int flag, int profileGroupId) { + UserInfo user = new UserInfo(id, name, flag); + when(mUserManagerInternal.getProfileParentId(eq(id))).thenReturn(profileGroupId); + return user; + } + @Test public void prepareRebootEscrow_Success() throws Exception { RebootEscrowListener mockListener = mock(RebootEscrowListener.class); @@ -559,6 +601,172 @@ public class RebootEscrowManagerTests { } @Test + public void loadRebootEscrowDataIfAvailable_noDataPrimaryUser_Failure() throws Exception { + setServerBasedRebootEscrowProvider(); + RebootEscrowListener mockListener = mock(RebootEscrowListener.class); + mService.setRebootEscrowListener(mockListener); + mService.prepareRebootEscrow(); + + clearInvocations(mServiceConnection); + + // escrow secondary user, don't escrow primary user + callToRebootEscrowIfNeededAndWait(SECURE_SECONDARY_USER_ID); + verify(mockListener).onPreparedForReboot(eq(true)); + verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong()); + + when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong())) + .thenAnswer(invocation -> invocation.getArgument(0)); + assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded()); + verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong()); + + assertTrue(mStorage.hasRebootEscrow(SECURE_SECONDARY_USER_ID)); + assertFalse(mStorage.hasRebootEscrow(PRIMARY_USER_ID)); + assertTrue(mStorage.hasRebootEscrowServerBlob()); + + // pretend reboot happens here + when(mInjected.getBootCount()).thenReturn(1); + ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class); + ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class); + doNothing() + .when(mInjected) + .reportMetric( + metricsSuccessCaptor.capture(), + metricsErrorCodeCaptor.capture(), + eq(2) /* Server based */, + eq(1) /* attempt count */, + anyInt(), + eq(0) /* vbmeta status */, + anyInt()); + mService.loadRebootEscrowDataIfAvailable(null); + verify(mServiceConnection, never()).unwrap(any(), anyLong()); + verify(mCallbacks, never()).onRebootEscrowRestored(anyByte(), any(), anyInt()); + assertFalse(metricsSuccessCaptor.getValue()); + assertEquals( + Integer.valueOf(RebootEscrowManager.ERROR_NO_REBOOT_ESCROW_DATA), + metricsErrorCodeCaptor.getValue()); + } + + @Test + public void loadRebootEscrowDataIfAvailable_noDataSecondaryUser_Success() throws Exception { + setServerBasedRebootEscrowProvider(); + RebootEscrowListener mockListener = mock(RebootEscrowListener.class); + mService.setRebootEscrowListener(mockListener); + mService.prepareRebootEscrow(); + + clearInvocations(mServiceConnection); + + // Setup work profile with secondary user as parent. + ArrayList<UserInfo> users = new ArrayList<>(); + users.add(createUser(PRIMARY_USER_ID, "primary", FLAG_PRIMARY, NO_PROFILE_GROUP_ID)); + users.add(createUser(WORK_PROFILE_USER_ID, "work", FLAG_PROFILE, SECURE_SECONDARY_USER_ID)); + users.add( + createUser( + SECURE_SECONDARY_USER_ID, "secure", FLAG_FULL, SECURE_SECONDARY_USER_ID)); + when(mUserManager.getUsers()).thenReturn(users); + + // escrow primary user and work profile, don't escrow secondary user + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); + verify(mockListener).onPreparedForReboot(eq(true)); + verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong()); + callToRebootEscrowIfNeededAndWait(WORK_PROFILE_USER_ID); + verify(mockListener).onPreparedForReboot(eq(true)); + verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong()); + + when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong())) + .thenAnswer(invocation -> invocation.getArgument(0)); + assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded()); + verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong()); + + assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID)); + assertFalse(mStorage.hasRebootEscrow(SECURE_SECONDARY_USER_ID)); + assertTrue(mStorage.hasRebootEscrow(WORK_PROFILE_USER_ID)); + assertTrue(mStorage.hasRebootEscrowServerBlob()); + + // pretend reboot happens here + when(mInjected.getBootCount()).thenReturn(1); + ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class); + doNothing() + .when(mInjected) + .reportMetric( + metricsSuccessCaptor.capture(), + eq(0) /* error code */, + eq(2) /* Server based */, + eq(1) /* attempt count */, + anyInt(), + eq(0) /* vbmeta status */, + anyInt()); + when(mServiceConnection.unwrap(any(), anyLong())) + .thenAnswer(invocation -> invocation.getArgument(0)); + + mService.loadRebootEscrowDataIfAvailable(null); + + verify(mServiceConnection).unwrap(any(), anyLong()); + verify(mCallbacks).onRebootEscrowRestored(anyByte(), any(), eq(PRIMARY_USER_ID)); + verify(mCallbacks, never()) + .onRebootEscrowRestored(anyByte(), any(), eq(SECURE_SECONDARY_USER_ID)); + verify(mCallbacks, never()) + .onRebootEscrowRestored(anyByte(), any(), eq(WORK_PROFILE_USER_ID)); + verify(mCallbacks, never()) + .onRebootEscrowRestored(anyByte(), any(), eq(NONSECURE_SECONDARY_USER_ID)); + assertTrue(metricsSuccessCaptor.getValue()); + } + + @Test + public void loadRebootEscrowDataIfAvailable_noDataWorkProfile_Success() throws Exception { + setServerBasedRebootEscrowProvider(); + RebootEscrowListener mockListener = mock(RebootEscrowListener.class); + mService.setRebootEscrowListener(mockListener); + mService.prepareRebootEscrow(); + + clearInvocations(mServiceConnection); + + // escrow primary user and secondary user, don't escrow work profile + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); + verify(mockListener).onPreparedForReboot(eq(true)); + verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong()); + callToRebootEscrowIfNeededAndWait(SECURE_SECONDARY_USER_ID); + verify(mockListener).onPreparedForReboot(eq(true)); + verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong()); + + when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong())) + .thenAnswer(invocation -> invocation.getArgument(0)); + assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded()); + verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong()); + + assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID)); + assertTrue(mStorage.hasRebootEscrow(SECURE_SECONDARY_USER_ID)); + assertFalse(mStorage.hasRebootEscrow(WORK_PROFILE_USER_ID)); + assertTrue(mStorage.hasRebootEscrowServerBlob()); + + // pretend reboot happens here + when(mInjected.getBootCount()).thenReturn(1); + ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class); + doNothing() + .when(mInjected) + .reportMetric( + metricsSuccessCaptor.capture(), + eq(0) /* error code */, + eq(2) /* Server based */, + eq(1) /* attempt count */, + anyInt(), + eq(0) /* vbmeta status */, + anyInt()); + when(mServiceConnection.unwrap(any(), anyLong())) + .thenAnswer(invocation -> invocation.getArgument(0)); + + mService.loadRebootEscrowDataIfAvailable(null); + + verify(mServiceConnection).unwrap(any(), anyLong()); + verify(mCallbacks).onRebootEscrowRestored(anyByte(), any(), eq(PRIMARY_USER_ID)); + verify(mCallbacks).onRebootEscrowRestored(anyByte(), any(), eq(SECURE_SECONDARY_USER_ID)); + verify(mCallbacks, never()) + .onRebootEscrowRestored(anyByte(), any(), eq(WORK_PROFILE_USER_ID)); + verify(mCallbacks, never()) + .onRebootEscrowRestored(anyByte(), any(), eq(NONSECURE_SECONDARY_USER_ID)); + assertTrue(metricsSuccessCaptor.getValue()); + } + + @Test public void loadRebootEscrowDataIfAvailable_ServerBased_Success() throws Exception { setServerBasedRebootEscrowProvider(); diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java index 093923f3ed53..a8b383cd4274 100644 --- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java +++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java @@ -101,8 +101,8 @@ public class PackageWatchdogTest { private static final String OBSERVER_NAME_2 = "observer2"; private static final String OBSERVER_NAME_3 = "observer3"; private static final String OBSERVER_NAME_4 = "observer4"; - private static final long SHORT_DURATION = TimeUnit.SECONDS.toMillis(1); - private static final long LONG_DURATION = TimeUnit.SECONDS.toMillis(5); + private static final long SHORT_DURATION = TimeUnit.SECONDS.toMillis(10); + private static final long LONG_DURATION = TimeUnit.SECONDS.toMillis(50); @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @@ -1453,7 +1453,8 @@ public class PackageWatchdogTest { raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN); - moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_DEESCALATION_WINDOW_MS); + moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_DEESCALATION_WINDOW_MS + - TimeUnit.MINUTES.toMillis(1)); // The first failure will be outside the threshold. raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A, @@ -1712,6 +1713,9 @@ public class PackageWatchdogTest { watchdog.onPackageFailure(packages, failureReason); } mTestLooper.dispatchAll(); + if (Flags.recoverabilityDetection()) { + moveTimeForwardAndDispatch(watchdog.DEFAULT_MITIGATION_WINDOW_MS); + } } private PackageWatchdog createWatchdog() { |