diff options
132 files changed, 4510 insertions, 2491 deletions
diff --git a/Android.bp b/Android.bp index 30b38d302a2d..c0a70b99827e 100644 --- a/Android.bp +++ b/Android.bp @@ -255,7 +255,10 @@ filegroup { java_defaults { name: "framework-minus-apex-defaults", - defaults: ["framework-aidl-export-defaults"], + defaults: [ + "framework-aidl-export-defaults", + "latest_android_hardware_soundtrigger3_java_static", + ], srcs: [ ":framework-non-updatable-sources", "core/java/**/*.logtags", @@ -365,8 +368,6 @@ java_defaults { sdk_version: "core_platform", static_libs: [ "android.hardware.common.fmq-V1-java", - // TODO(b/184162091) - "android.hardware.soundtrigger3-V1-java", "bouncycastle-repackaged-unbundled", "framework-internal-utils", // If MimeMap ever becomes its own APEX, then this dependency would need to be removed diff --git a/apct-tests/perftests/rubidium/src/android/rubidium/js/JSScriptEnginePerfTests.java b/apct-tests/perftests/rubidium/src/android/rubidium/js/JSScriptEnginePerfTests.java index 81685cbbd594..33b2bea1da66 100644 --- a/apct-tests/perftests/rubidium/src/android/rubidium/js/JSScriptEnginePerfTests.java +++ b/apct-tests/perftests/rubidium/src/android/rubidium/js/JSScriptEnginePerfTests.java @@ -37,6 +37,7 @@ import androidx.test.core.app.ApplicationProvider; import androidx.test.filters.MediumTest; import androidx.test.runner.AndroidJUnit4; +import com.android.adservices.service.js.IsolateSettings; import com.android.adservices.service.js.JSScriptArgument; import com.android.adservices.service.js.JSScriptArrayArgument; import com.android.adservices.service.js.JSScriptEngine; @@ -314,7 +315,11 @@ public class JSScriptEnginePerfTests { @NonNull CountDownLatch resultLatch) { Objects.requireNonNull(engine); Objects.requireNonNull(resultLatch); - ListenableFuture<String> result = engine.evaluate(jsScript, args, functionName); + ListenableFuture<String> result = engine.evaluate( + jsScript, + args, + functionName, + IsolateSettings.forMaxHeapSizeEnforcementDisabled()); result.addListener(resultLatch::countDown, sExecutorService); return result; } @@ -328,7 +333,12 @@ public class JSScriptEnginePerfTests { @NonNull CountDownLatch resultLatch) { Objects.requireNonNull(engine); Objects.requireNonNull(resultLatch); - ListenableFuture<String> result = engine.evaluate(jsScript, wasmScript, args, functionName); + ListenableFuture<String> result = engine.evaluate( + jsScript, + wasmScript, + args, + functionName, + IsolateSettings.forMaxHeapSizeEnforcementDisabled()); result.addListener(resultLatch::countDown, sExecutorService); return result; } diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java index d4a1cd234c39..4fe021a35f98 100644 --- a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java +++ b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java @@ -721,25 +721,28 @@ class Agent { @GuardedBy("mLock") void distributeBasicIncomeLocked(int batteryLevel) { - final List<InstalledPackageInfo> pkgs = mIrs.getInstalledPackages(); + final SparseArrayMap<String, InstalledPackageInfo> pkgs = mIrs.getInstalledPackages(); final long now = getCurrentTimeMillis(); - for (int i = 0; i < pkgs.size(); ++i) { - final InstalledPackageInfo pkgInfo = pkgs.get(i); - if (!shouldGiveCredits(pkgInfo)) { - continue; - } - final int userId = UserHandle.getUserId(pkgInfo.uid); - final String pkgName = pkgInfo.packageName; - final Ledger ledger = mScribe.getLedgerLocked(userId, pkgName); - final long minBalance = mIrs.getMinBalanceLocked(userId, pkgName); - final double perc = batteryLevel / 100d; - // TODO: maybe don't give credits to bankrupt apps until battery level >= 50% - final long shortfall = minBalance - ledger.getCurrentBalance(); - if (shortfall > 0) { - recordTransactionLocked(userId, pkgName, ledger, - new Ledger.Transaction(now, now, REGULATION_BASIC_INCOME, - null, (long) (perc * shortfall), 0), true); + for (int uIdx = pkgs.numMaps() - 1; uIdx >= 0; --uIdx) { + final int userId = pkgs.keyAt(uIdx); + + for (int pIdx = pkgs.numElementsForKeyAt(uIdx) - 1; pIdx >= 0; --pIdx) { + final InstalledPackageInfo pkgInfo = pkgs.valueAt(uIdx, pIdx); + if (!shouldGiveCredits(pkgInfo)) { + continue; + } + final String pkgName = pkgInfo.packageName; + final Ledger ledger = mScribe.getLedgerLocked(userId, pkgName); + final long minBalance = mIrs.getMinBalanceLocked(userId, pkgName); + final double perc = batteryLevel / 100d; + // TODO: maybe don't give credits to bankrupt apps until battery level >= 50% + final long shortfall = minBalance - ledger.getCurrentBalance(); + if (shortfall > 0) { + recordTransactionLocked(userId, pkgName, ledger, + new Ledger.Transaction(now, now, REGULATION_BASIC_INCOME, + null, (long) (perc * shortfall), 0), true); + } } } } @@ -1325,7 +1328,6 @@ class Agent { @GuardedBy("mLock") void dumpLocked(IndentingPrintWriter pw) { - pw.println(); mBalanceThresholdAlarmQueue.dump(pw); pw.println(); diff --git a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java index 2fb0c1a36e07..22a2f5163538 100644 --- a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java +++ b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java @@ -405,6 +405,10 @@ public abstract class EconomicPolicy { return "PROMOTION"; case REGULATION_DEMOTION: return "DEMOTION"; + case REGULATION_BG_RESTRICTED: + return "BG_RESTRICTED"; + case REGULATION_BG_UNRESTRICTED: + return "BG_UNRESTRICTED"; } return "UNKNOWN_REGULATION:" + Integer.toHexString(eventId); } diff --git a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java index 2b8272208c3e..448a808ff52f 100644 --- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java +++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java @@ -136,7 +136,7 @@ public class InternalResourceService extends SystemService { @NonNull @GuardedBy("mLock") - private final List<InstalledPackageInfo> mPkgCache = new ArrayList<>(); + private final SparseArrayMap<String, InstalledPackageInfo> mPkgCache = new SparseArrayMap<>(); /** Cached mapping of UIDs (for all users) to a list of packages in the UID. */ @GuardedBy("mLock") @@ -343,7 +343,7 @@ public class InternalResourceService extends SystemService { } @NonNull - List<InstalledPackageInfo> getInstalledPackages() { + SparseArrayMap<String, InstalledPackageInfo> getInstalledPackages() { synchronized (mLock) { return mPkgCache; } @@ -354,11 +354,13 @@ public class InternalResourceService extends SystemService { List<InstalledPackageInfo> getInstalledPackages(final int userId) { final List<InstalledPackageInfo> userPkgs = new ArrayList<>(); synchronized (mLock) { - for (int i = 0; i < mPkgCache.size(); ++i) { - final InstalledPackageInfo packageInfo = mPkgCache.get(i); - if (UserHandle.getUserId(packageInfo.uid) == userId) { - userPkgs.add(packageInfo); - } + final int uIdx = mPkgCache.indexOfKey(userId); + if (uIdx < 0) { + return userPkgs; + } + for (int p = mPkgCache.numElementsForKeyAt(uIdx) - 1; p >= 0; --p) { + final InstalledPackageInfo packageInfo = mPkgCache.valueAt(uIdx, p); + userPkgs.add(packageInfo); } } return userPkgs; @@ -511,7 +513,7 @@ public class InternalResourceService extends SystemService { mPackageToUidCache.add(userId, pkgName, uid); } synchronized (mLock) { - mPkgCache.add(new InstalledPackageInfo(packageInfo)); + mPkgCache.add(userId, pkgName, new InstalledPackageInfo(packageInfo)); mUidToPackageCache.add(uid, pkgName); // TODO: only do this when the user first launches the app (app leaves stopped state) mAgent.grantBirthrightLocked(userId, pkgName); @@ -532,14 +534,7 @@ public class InternalResourceService extends SystemService { synchronized (mLock) { mUidToPackageCache.remove(uid, pkgName); mVipOverrides.delete(userId, pkgName); - for (int i = 0; i < mPkgCache.size(); ++i) { - final InstalledPackageInfo pkgInfo = mPkgCache.get(i); - if (UserHandle.getUserId(pkgInfo.uid) == userId - && pkgName.equals(pkgInfo.packageName)) { - mPkgCache.remove(i); - break; - } - } + mPkgCache.delete(userId, pkgName); mAgent.onPackageRemovedLocked(userId, pkgName); } } @@ -560,7 +555,8 @@ public class InternalResourceService extends SystemService { final List<PackageInfo> pkgs = mPackageManager.getInstalledPackagesAsUser(PACKAGE_QUERY_FLAGS, userId); for (int i = pkgs.size() - 1; i >= 0; --i) { - mPkgCache.add(new InstalledPackageInfo(pkgs.get(i))); + final InstalledPackageInfo ipo = new InstalledPackageInfo(pkgs.get(i)); + mPkgCache.add(userId, ipo.packageName, ipo); } mAgent.grantBirthrightsLocked(userId); } @@ -570,15 +566,15 @@ public class InternalResourceService extends SystemService { synchronized (mLock) { mVipOverrides.delete(userId); ArrayList<String> removedPkgs = new ArrayList<>(); - for (int i = mPkgCache.size() - 1; i >= 0; --i) { - final InstalledPackageInfo pkgInfo = mPkgCache.get(i); - if (UserHandle.getUserId(pkgInfo.uid) == userId) { + final int uIdx = mPkgCache.indexOfKey(userId); + if (uIdx >= 0) { + for (int p = mPkgCache.numElementsForKeyAt(uIdx) - 1; p >= 0; --p) { + final InstalledPackageInfo pkgInfo = mPkgCache.valueAt(uIdx, p); removedPkgs.add(pkgInfo.packageName); mUidToPackageCache.remove(pkgInfo.uid); - mPkgCache.remove(i); - break; } } + mPkgCache.delete(userId); mAgent.onUserRemovedLocked(userId, removedPkgs); } } @@ -727,7 +723,8 @@ public class InternalResourceService extends SystemService { final List<PackageInfo> pkgs = mPackageManager.getInstalledPackagesAsUser(PACKAGE_QUERY_FLAGS, userId); for (int i = pkgs.size() - 1; i >= 0; --i) { - mPkgCache.add(new InstalledPackageInfo(pkgs.get(i))); + final InstalledPackageInfo ipo = new InstalledPackageInfo(pkgs.get(i)); + mPkgCache.add(userId, ipo.packageName, ipo); } } } @@ -1185,7 +1182,6 @@ public class InternalResourceService extends SystemService { // User setting should override DeviceConfig setting. // NOTE: There's currently no way for a user to reset the value (via UI), so if a user // manually toggles TARE via UI, we'll always defer to the user's current setting - // TODO: add a "reset" value if the user toggle is an issue final boolean isTareEnabledDC = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TARE, KEY_DC_ENABLE_TARE, Settings.Global.DEFAULT_ENABLE_TARE == 1); final boolean isTareEnabled = Settings.Global.getInt(mContentResolver, diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Ledger.java b/apex/jobscheduler/service/java/com/android/server/tare/Ledger.java index e91ed1287e1b..620d1a0da76f 100644 --- a/apex/jobscheduler/service/java/com/android/server/tare/Ledger.java +++ b/apex/jobscheduler/service/java/com/android/server/tare/Ledger.java @@ -247,7 +247,7 @@ class Ledger { boolean printedTransactionTitle = false; for (int t = 0; t < Math.min(MAX_TRANSACTION_COUNT, numRecentTransactions); ++t) { - final int idx = (mTransactionIndex - t + MAX_TRANSACTION_COUNT) % MAX_TRANSACTION_COUNT; + final int idx = (mTransactionIndex + t) % MAX_TRANSACTION_COUNT; final Transaction transaction = mTransactions[idx]; if (transaction == null) { continue; diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java b/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java index 2cae83f4aad5..29478d05e066 100644 --- a/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java +++ b/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java @@ -216,17 +216,21 @@ public class Scribe { mRemainingConsumableCakes = 0; final SparseArray<ArraySet<String>> installedPackagesPerUser = new SparseArray<>(); - final List<InstalledPackageInfo> installedPackages = mIrs.getInstalledPackages(); - for (int i = 0; i < installedPackages.size(); ++i) { - final InstalledPackageInfo packageInfo = installedPackages.get(i); - if (packageInfo.uid != InstalledPackageInfo.NO_UID) { - final int userId = UserHandle.getUserId(packageInfo.uid); - ArraySet<String> pkgsForUser = installedPackagesPerUser.get(userId); - if (pkgsForUser == null) { - pkgsForUser = new ArraySet<>(); - installedPackagesPerUser.put(userId, pkgsForUser); + final SparseArrayMap<String, InstalledPackageInfo> installedPackages = + mIrs.getInstalledPackages(); + for (int uIdx = installedPackages.numMaps() - 1; uIdx >= 0; --uIdx) { + final int userId = installedPackages.keyAt(uIdx); + + for (int pIdx = installedPackages.numElementsForKeyAt(uIdx) - 1; pIdx >= 0; --pIdx) { + final InstalledPackageInfo packageInfo = installedPackages.valueAt(uIdx, pIdx); + if (packageInfo.uid != InstalledPackageInfo.NO_UID) { + ArraySet<String> pkgsForUser = installedPackagesPerUser.get(userId); + if (pkgsForUser == null) { + pkgsForUser = new ArraySet<>(); + installedPackagesPerUser.put(userId, pkgsForUser); + } + pkgsForUser.add(packageInfo.packageName); } - pkgsForUser.add(packageInfo.packageName); } } diff --git a/core/api/current.txt b/core/api/current.txt index 317f8eb5c6b5..eace67b79cd5 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -49972,6 +49972,7 @@ package android.view { method public void invalidate(); method public void invalidateDrawable(@NonNull android.graphics.drawable.Drawable); method public void invalidateOutline(); + method public boolean isAccessibilityDataPrivate(); method public boolean isAccessibilityFocused(); method public boolean isAccessibilityHeading(); method public boolean isActivated(); @@ -50149,6 +50150,7 @@ package android.view { method public void scrollTo(int, int); method public void sendAccessibilityEvent(int); method public void sendAccessibilityEventUnchecked(android.view.accessibility.AccessibilityEvent); + method public void setAccessibilityDataPrivate(int); method public void setAccessibilityDelegate(@Nullable android.view.View.AccessibilityDelegate); method public void setAccessibilityHeading(boolean); method public void setAccessibilityLiveRegion(int); @@ -50329,6 +50331,9 @@ package android.view { method @CallSuper protected boolean verifyDrawable(@NonNull android.graphics.drawable.Drawable); method @Deprecated public boolean willNotCacheDrawing(); method public boolean willNotDraw(); + field public static final int ACCESSIBILITY_DATA_PRIVATE_AUTO = 0; // 0x0 + field public static final int ACCESSIBILITY_DATA_PRIVATE_NO = 2; // 0x2 + field public static final int ACCESSIBILITY_DATA_PRIVATE_YES = 1; // 0x1 field public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 2; // 0x2 field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0 field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1 @@ -51781,9 +51786,11 @@ package android.view.accessibility { method public int getSpeechStateChangeTypes(); method public int getWindowChanges(); method public void initFromParcel(android.os.Parcel); + method public boolean isAccessibilityDataPrivate(); method @Deprecated public static android.view.accessibility.AccessibilityEvent obtain(int); method @Deprecated public static android.view.accessibility.AccessibilityEvent obtain(android.view.accessibility.AccessibilityEvent); method @Deprecated public static android.view.accessibility.AccessibilityEvent obtain(); + method public void setAccessibilityDataPrivate(boolean); method public void setAction(int); method public void setContentChangeTypes(int); method public void setEventTime(long); @@ -51874,6 +51881,7 @@ package android.view.accessibility { method public static boolean isAccessibilityButtonSupported(); method public boolean isAudioDescriptionRequested(); method public boolean isEnabled(); + method public boolean isRequestFromAccessibilityTool(); method public boolean isTouchExplorationEnabled(); method public void removeAccessibilityRequestPreparer(android.view.accessibility.AccessibilityRequestPreparer); method public boolean removeAccessibilityServicesStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener); diff --git a/core/api/test-current.txt b/core/api/test-current.txt index f45298a630cd..4e594c1741fe 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -89,6 +89,7 @@ package android.accessibilityservice { public class AccessibilityServiceInfo implements android.os.Parcelable { method @NonNull public android.content.ComponentName getComponentName(); + method public void setAccessibilityTool(boolean); } } diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java index 2e89ce83cd36..8f6bfd3b13db 100644 --- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java +++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java @@ -784,6 +784,7 @@ public class AccessibilityServiceInfo implements Parcelable { mNonInteractiveUiTimeout = other.mNonInteractiveUiTimeout; mInteractiveUiTimeout = other.mInteractiveUiTimeout; flags = other.flags; + mIsAccessibilityTool = other.mIsAccessibilityTool; } private boolean isRequestAccessibilityButtonChangeEnabled(IPlatformCompat platformCompat) { @@ -1112,6 +1113,26 @@ public class AccessibilityServiceInfo implements Parcelable { } /** + * Sets whether the service is used to assist users with disabilities. + * + * <p> + * This property is normally provided in the service's {@link #mResolveInfo ResolveInfo}. + * </p> + * + * <p> + * This method is helpful for unit testing. However, this property is not dynamically + * configurable by a standard {@link AccessibilityService} so it's not possible to update the + * copy held by the system with this method. + * </p> + * + * @hide + */ + @TestApi + public void setAccessibilityTool(boolean isAccessibilityTool) { + mIsAccessibilityTool = isAccessibilityTool; + } + + /** * Indicates if the service is used to assist users with disabilities. * * @return {@code true} if the property is set to true. diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java index a045157e02db..8d57e32a763c 100644 --- a/core/java/android/app/UiAutomationConnection.java +++ b/core/java/android/app/UiAutomationConnection.java @@ -550,6 +550,7 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { info.setCapabilities(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT | AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION | AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS); + info.setAccessibilityTool(true); try { // Calling out with a lock held is fine since if the system // process is gone the client calling in will be killed. diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 09a52e452f9a..da206268917e 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -2326,11 +2326,6 @@ public abstract class BatteryStats { public abstract void finishIteratingHistoryLocked(); /** - * Return the base time offset for the battery history. - */ - public abstract long getHistoryBaseTime(); - - /** * Returns the number of times the device has been started. */ public abstract int getStartCount(); @@ -7615,8 +7610,6 @@ public abstract class BatteryStats { CHECKIN_VERSION, getParcelVersion(), getStartPlatformVersion(), getEndPlatformVersion()); - long now = getHistoryBaseTime() + SystemClock.elapsedRealtime(); - if ((flags & (DUMP_INCLUDE_HISTORY | DUMP_HISTORY_ONLY)) != 0) { if (startIteratingHistoryLocked()) { try { diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index 0338cebf75c6..bca100a1d81e 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -52,13 +52,6 @@ public class FeatureFlagUtils { public static final String SETTINGS_SUPPORT_LARGE_SCREEN = "settings_support_large_screen"; /** - * Support per app's language selection - * @hide - */ - public static final String SETTINGS_APP_LANGUAGE_SELECTION = "settings_app_language_selection"; - - - /** * Feature flag to allow/restrict intent redirection from/to clone profile. * Default value is false,this is to ensure that framework is not impacted by intent redirection * till we are ready to launch. @@ -139,7 +132,6 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put(SETTINGS_ENABLE_SECURITY_HUB, "true"); DEFAULT_FLAGS.put(SETTINGS_SUPPORT_LARGE_SCREEN, "true"); DEFAULT_FLAGS.put("settings_search_always_expand", "true"); - DEFAULT_FLAGS.put(SETTINGS_APP_LANGUAGE_SELECTION, "true"); DEFAULT_FLAGS.put(SETTINGS_ALLOW_INTENT_REDIRECTION_FOR_CLONE_PROFILE, "false"); DEFAULT_FLAGS.put(SETTINGS_APP_LOCALE_OPT_IN_ENABLED, "true"); DEFAULT_FLAGS.put(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS, "true"); @@ -154,7 +146,6 @@ public class FeatureFlagUtils { private static final Set<String> PERSISTENT_FLAGS; static { PERSISTENT_FLAGS = new HashSet<>(); - PERSISTENT_FLAGS.add(SETTINGS_APP_LANGUAGE_SELECTION); PERSISTENT_FLAGS.add(SETTINGS_ALLOW_INTENT_REDIRECTION_FOR_CLONE_PROFILE); PERSISTENT_FLAGS.add(SETTINGS_APP_LOCALE_OPT_IN_ENABLED); PERSISTENT_FLAGS.add(SETTINGS_SUPPORT_LARGE_SCREEN); diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java index a6f63e859049..510bde1deb5d 100644 --- a/core/java/android/view/AccessibilityInteractionController.java +++ b/core/java/android/view/AccessibilityInteractionController.java @@ -89,9 +89,7 @@ public final class AccessibilityInteractionController { // Callbacks should have the same configuration of the flags below to allow satisfying a pending // node request on prefetch - private static final int FLAGS_AFFECTING_REPORTED_DATA = - AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS - | AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS; + private static final int FLAGS_AFFECTING_REPORTED_DATA = AccessibilityNodeInfo.FLAG_REPORT_MASK; private final ArrayList<AccessibilityNodeInfo> mTempAccessibilityNodeInfoList = new ArrayList<AccessibilityNodeInfo>(); @@ -167,6 +165,11 @@ public final class AccessibilityInteractionController { return (view != null) && (view.getWindowVisibility() == View.VISIBLE && view.isShown()); } + private boolean isVisibleToAccessibilityService(View view) { + return view != null && (mA11yManager.isRequestFromAccessibilityTool() + || !view.isAccessibilityDataPrivate()); + } + public void findAccessibilityNodeInfoByAccessibilityIdClientThread( long accessibilityNodeId, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, @@ -358,7 +361,7 @@ public final class AccessibilityInteractionController { if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) { return; } - mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags; + setAccessibilityFetchFlags(flags); requestedView = findViewByAccessibilityId(accessibilityViewId); if (requestedView != null && isShown(requestedView)) { requestedNode = populateAccessibilityNodeInfoForView( @@ -371,7 +374,7 @@ public final class AccessibilityInteractionController { mPrefetcher.prefetchAccessibilityNodeInfos(requestedView, requestedNode == null ? null : new AccessibilityNodeInfo(requestedNode), infos); - mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; + resetAccessibilityFetchFlags(); } } } finally { @@ -396,7 +399,7 @@ public final class AccessibilityInteractionController { } mPrefetcher.prefetchAccessibilityNodeInfos(requestedView, requestedNode == null ? null : new AccessibilityNodeInfo(requestedNode), infos); - mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; + resetAccessibilityFetchFlags(); updateInfosForViewPort(infos, spec, matrixValues, interactiveRegion); final SatisfiedFindAccessibilityNodeByAccessibilityIdRequest satisfiedRequest = getSatisfiedRequestInPrefetch(requestedNode == null ? null : requestedNode, infos, @@ -478,7 +481,7 @@ public final class AccessibilityInteractionController { || viewId == null) { return; } - mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags; + setAccessibilityFetchFlags(flags); final View root = findViewByAccessibilityId(accessibilityViewId); if (root != null) { final int resolvedViewId = root.getContext().getResources() @@ -494,7 +497,7 @@ public final class AccessibilityInteractionController { mAddNodeInfosForViewId.reset(); } } finally { - mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; + resetAccessibilityFetchFlags(); updateInfosForViewportAndReturnFindNodeResult( infos, callback, interactionId, spec, matrixValues, interactiveRegion); } @@ -542,7 +545,7 @@ public final class AccessibilityInteractionController { if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) { return; } - mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags; + setAccessibilityFetchFlags(flags); final View root = findViewByAccessibilityId(accessibilityViewId); if (root != null && isShown(root)) { AccessibilityNodeProvider provider = root.getAccessibilityNodeProvider(); @@ -561,7 +564,7 @@ public final class AccessibilityInteractionController { final int viewCount = foundViews.size(); for (int i = 0; i < viewCount; i++) { View foundView = foundViews.get(i); - if (isShown(foundView)) { + if (isShown(foundView) && isVisibleToAccessibilityService(foundView)) { provider = foundView.getAccessibilityNodeProvider(); if (provider != null) { List<AccessibilityNodeInfo> infosFromProvider = @@ -579,7 +582,7 @@ public final class AccessibilityInteractionController { } } } finally { - mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; + resetAccessibilityFetchFlags(); updateInfosForViewportAndReturnFindNodeResult( infos, callback, interactionId, spec, matrixValues, interactiveRegion); } @@ -627,7 +630,7 @@ public final class AccessibilityInteractionController { if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) { return; } - mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags; + setAccessibilityFetchFlags(flags); final View root = findViewByAccessibilityId(accessibilityViewId); if (root != null && isShown(root)) { switch (focusType) { @@ -642,6 +645,9 @@ public final class AccessibilityInteractionController { if (!isShown(host)) { break; } + if (!isVisibleToAccessibilityService(host)) { + break; + } // If the host has a provider ask this provider to search for the // focus instead fetching all provider nodes to do the search here. AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider(); @@ -662,6 +668,9 @@ public final class AccessibilityInteractionController { if (!isShown(target)) { break; } + if (!isVisibleToAccessibilityService(target)) { + break; + } AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider(); if (provider != null) { focused = provider.findFocus(focusType); @@ -675,7 +684,7 @@ public final class AccessibilityInteractionController { } } } finally { - mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; + resetAccessibilityFetchFlags(); updateInfoForViewportAndReturnFindNodeResult( focused, callback, interactionId, spec, matrixValues, interactiveRegion); } @@ -722,7 +731,7 @@ public final class AccessibilityInteractionController { if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) { return; } - mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags; + setAccessibilityFetchFlags(flags); final View root = findViewByAccessibilityId(accessibilityViewId); if (root != null && isShown(root)) { View nextView = root.focusSearch(direction); @@ -731,7 +740,7 @@ public final class AccessibilityInteractionController { } } } finally { - mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; + resetAccessibilityFetchFlags(); updateInfoForViewportAndReturnFindNodeResult( next, callback, interactionId, spec, matrixValues, interactiveRegion); } @@ -778,9 +787,9 @@ public final class AccessibilityInteractionController { mViewRootImpl.mStopped || mViewRootImpl.mPausedForTransition) { return; } - mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags; + setAccessibilityFetchFlags(flags); final View target = findViewByAccessibilityId(accessibilityViewId); - if (target != null && isShown(target)) { + if (target != null && isShown(target) && isVisibleToAccessibilityService(target)) { mA11yManager.notifyPerformingAction(action); if (action == R.id.accessibilityActionClickOnClickableSpan) { // Handle this hidden action separately @@ -799,7 +808,7 @@ public final class AccessibilityInteractionController { } } finally { try { - mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; + resetAccessibilityFetchFlags(); callback.setPerformAccessibilityActionResult(succeeded, interactionId); } catch (RemoteException re) { /* ignore - the other side will time out */ @@ -823,9 +832,9 @@ public final class AccessibilityInteractionController { return; } try { - mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = - AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; - final View root = mViewRootImpl.mView; + setAccessibilityFetchFlags( + AccessibilityNodeInfo.FLAG_SERVICE_REQUESTS_INCLUDE_NOT_IMPORTANT_VIEWS); + final View root = getRootView(); if (root != null && isShown(root)) { final View host = mViewRootImpl.mAccessibilityFocusedHost; // If there is no accessibility focus host or it is not a descendant @@ -849,7 +858,7 @@ public final class AccessibilityInteractionController { } } } finally { - mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; + resetAccessibilityFetchFlags(); } } @@ -869,7 +878,7 @@ public final class AccessibilityInteractionController { || mViewRootImpl.mStopped || mViewRootImpl.mPausedForTransition) { return; } - final View root = mViewRootImpl.mView; + final View root = getRootView(); if (root != null && isShown(root)) { // trigger ACTION_OUTSIDE to notify windows final long now = SystemClock.uptimeMillis(); @@ -882,12 +891,30 @@ public final class AccessibilityInteractionController { private View findViewByAccessibilityId(int accessibilityId) { if (accessibilityId == AccessibilityNodeInfo.ROOT_ITEM_ID) { - return mViewRootImpl.mView; + return getRootView(); } else { return AccessibilityNodeIdManager.getInstance().findView(accessibilityId); } } + private View getRootView() { + if (!isVisibleToAccessibilityService(mViewRootImpl.mView)) { + return null; + } + return mViewRootImpl.mView; + } + + private void setAccessibilityFetchFlags(int flags) { + mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags; + mA11yManager.setRequestFromAccessibilityTool( + (flags & AccessibilityNodeInfo.FLAG_SERVICE_IS_ACCESSIBILITY_TOOL) != 0); + } + + private void resetAccessibilityFetchFlags() { + mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; + mA11yManager.setRequestFromAccessibilityTool(false); + } + // The boundInScreen includes magnification effect, so we need to normalize it before // determine the visibility. private void adjustIsVisibleToUserIfNeeded(AccessibilityNodeInfo info, @@ -1706,7 +1733,7 @@ public final class AccessibilityInteractionController { @Override public boolean test(View view) { - if (view.getId() == mViewId && isShown(view)) { + if (view.getId() == mViewId && isShown(view) && isVisibleToAccessibilityService(view)) { mInfos.add(view.createAccessibilityNodeInfo()); } return false; diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java index addbab07c478..2a0246b200eb 100644 --- a/core/java/android/view/InputDevice.java +++ b/core/java/android/view/InputDevice.java @@ -25,6 +25,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.hardware.BatteryState; import android.hardware.SensorManager; +import android.hardware.input.InputDeviceCountryCode; import android.hardware.input.InputDeviceIdentifier; import android.hardware.input.InputManager; import android.hardware.lights.LightsManager; @@ -72,6 +73,8 @@ public final class InputDevice implements Parcelable { private final int mSources; private final int mKeyboardType; private final KeyCharacterMap mKeyCharacterMap; + @InputDeviceCountryCode + private final int mCountryCode; private final boolean mHasVibrator; private final boolean mHasMicrophone; private final boolean mHasButtonUnderPad; @@ -462,8 +465,9 @@ public final class InputDevice implements Parcelable { @VisibleForTesting public InputDevice(int id, int generation, int controllerNumber, String name, int vendorId, int productId, String descriptor, boolean isExternal, int sources, int keyboardType, - KeyCharacterMap keyCharacterMap, boolean hasVibrator, boolean hasMicrophone, - boolean hasButtonUnderPad, boolean hasSensor, boolean hasBattery) { + KeyCharacterMap keyCharacterMap, @InputDeviceCountryCode int countryCode, + boolean hasVibrator, boolean hasMicrophone, boolean hasButtonUnderPad, + boolean hasSensor, boolean hasBattery) { mId = id; mGeneration = generation; mControllerNumber = controllerNumber; @@ -475,6 +479,7 @@ public final class InputDevice implements Parcelable { mSources = sources; mKeyboardType = keyboardType; mKeyCharacterMap = keyCharacterMap; + mCountryCode = countryCode; mHasVibrator = hasVibrator; mHasMicrophone = hasMicrophone; mHasButtonUnderPad = hasButtonUnderPad; @@ -495,6 +500,7 @@ public final class InputDevice implements Parcelable { mIsExternal = in.readInt() != 0; mSources = in.readInt(); mKeyboardType = in.readInt(); + mCountryCode = in.readInt(); mHasVibrator = in.readInt() != 0; mHasMicrophone = in.readInt() != 0; mHasButtonUnderPad = in.readInt() != 0; @@ -729,6 +735,16 @@ public final class InputDevice implements Parcelable { } /** + * Gets Country code associated with the device + * + * @hide + */ + @InputDeviceCountryCode + public int getCountryCode() { + return mCountryCode; + } + + /** * Gets whether the device is capable of producing the list of keycodes. * @param keys The list of android keycodes to check for. * @return An array of booleans where each member specifies whether the device is capable of @@ -1147,6 +1163,7 @@ public final class InputDevice implements Parcelable { out.writeInt(mIsExternal ? 1 : 0); out.writeInt(mSources); out.writeInt(mKeyboardType); + out.writeInt(mCountryCode); out.writeInt(mHasVibrator ? 1 : 0); out.writeInt(mHasMicrophone ? 1 : 0); out.writeInt(mHasButtonUnderPad ? 1 : 0); @@ -1178,7 +1195,8 @@ public final class InputDevice implements Parcelable { description.append("Input Device ").append(mId).append(": ").append(mName).append("\n"); description.append(" Descriptor: ").append(mDescriptor).append("\n"); description.append(" Generation: ").append(mGeneration).append("\n"); - description.append(" Location: ").append(mIsExternal ? "external" : "built-in").append("\n"); + description.append(" Location: ").append(mIsExternal ? "external" : "built-in").append( + "\n"); description.append(" Keyboard Type: "); switch (mKeyboardType) { @@ -1194,6 +1212,8 @@ public final class InputDevice implements Parcelable { } description.append("\n"); + description.append(" Country Code: ").append(mCountryCode).append("\n"); + description.append(" Has Vibrator: ").append(mHasVibrator).append("\n"); description.append(" Has Sensor: ").append(mHasSensor).append("\n"); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 48937770eddb..996dee0cd2da 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -3085,6 +3085,45 @@ public class View implements Drawable.Callback, KeyEvent.Callback, static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO; /** + * Automatically determine whether the view should only allow interactions from + * {@link android.accessibilityservice.AccessibilityService}s with the + * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property + * set to true. + * + * <p> + * Accessibility interactions from services without {@code isAccessibilityTool} set to true are + * disallowed for any of the following conditions: + * <li>this view's window sets {@link WindowManager.LayoutParams#FLAG_SECURE}.</li> + * <li>this view sets {@link #getFilterTouchesWhenObscured()}.</li> + * <li>any parent of this view returns true from {@link #isAccessibilityDataPrivate()}.</li> + * </p> + */ + public static final int ACCESSIBILITY_DATA_PRIVATE_AUTO = 0x00000000; + + /** + * Only allow interactions from {@link android.accessibilityservice.AccessibilityService}s + * with the {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} + * property set to true. + */ + public static final int ACCESSIBILITY_DATA_PRIVATE_YES = 0x00000001; + + /** + * Allow interactions from all {@link android.accessibilityservice.AccessibilityService}s, + * regardless of their + * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property. + */ + public static final int ACCESSIBILITY_DATA_PRIVATE_NO = 0x00000002; + + /** @hide */ + @IntDef(prefix = { "ACCESSIBILITY_DATA_PRIVATE_" }, value = { + ACCESSIBILITY_DATA_PRIVATE_AUTO, + ACCESSIBILITY_DATA_PRIVATE_YES, + ACCESSIBILITY_DATA_PRIVATE_NO, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface AccessibilityDataPrivate {} + + /** * Mask for obtaining the bits which specify how to determine * whether a view is important for accessibility. */ @@ -4527,6 +4566,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private CharSequence mAccessibilityPaneTitle; /** + * Describes whether this view should only allow interactions from + * {@link android.accessibilityservice.AccessibilityService}s with the + * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property + * set to true. + */ + private int mExplicitAccessibilityDataPrivate = ACCESSIBILITY_DATA_PRIVATE_AUTO; + /** Used to calculate and cache {@link #isAccessibilityDataPrivate()}. */ + private int mInferredAccessibilityDataPrivate = ACCESSIBILITY_DATA_PRIVATE_AUTO; + + /** * Specifies the id of a view for which this view serves as a label for * accessibility purposes. */ @@ -5919,6 +5968,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, setImportantForAccessibility(a.getInt(attr, IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); break; + case R.styleable.View_accessibilityDataPrivate: + setAccessibilityDataPrivate(a.getInt(attr, + ACCESSIBILITY_DATA_PRIVATE_AUTO)); + break; case R.styleable.View_accessibilityLiveRegion: setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT)); break; @@ -8518,6 +8571,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * is responsible for handling this call. * </p> * <p> + * If this view sets {@link #isAccessibilityDataPrivate()} then this view should only append + * sensitive information to an event that also sets + * {@link AccessibilityEvent#isAccessibilityDataPrivate()}. + * </p> + * <p> * <em>Note:</em> Accessibility events of certain types are not dispatched for * populating the event text via this method. For details refer to {@link AccessibilityEvent}. * </p> @@ -10419,7 +10477,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } if ((mAttachInfo.mAccessibilityFetchFlags - & AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS) != 0 + & AccessibilityNodeInfo.FLAG_SERVICE_REQUESTS_REPORT_VIEW_IDS) != 0 && Resources.resourceHasPackage(mID)) { try { String viewId = getResources().getResourceName(mID); @@ -13200,6 +13258,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, public void setFilterTouchesWhenObscured(boolean enabled) { setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, FILTER_TOUCHES_WHEN_OBSCURED); + calculateAccessibilityDataPrivate(); } /** @@ -14402,14 +14461,80 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @UnsupportedAppUsage public boolean includeForAccessibility() { if (mAttachInfo != null) { + if (!AccessibilityManager.getInstance(mContext).isRequestFromAccessibilityTool() + && isAccessibilityDataPrivate()) { + return false; + } + return (mAttachInfo.mAccessibilityFetchFlags - & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 + & AccessibilityNodeInfo.FLAG_SERVICE_REQUESTS_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 || isImportantForAccessibility(); } return false; } /** + * Whether this view should restrict accessibility service access only to services that have the + * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property + * set to true. + * + * <p> + * See default behavior provided by {@link #ACCESSIBILITY_DATA_PRIVATE_AUTO}. Otherwise, + * returns true for {@link #ACCESSIBILITY_DATA_PRIVATE_YES} or false for {@link + * #ACCESSIBILITY_DATA_PRIVATE_NO}. + * </p> + * + * @return True if this view should restrict accessibility service access to services that have + * the isAccessibilityTool property. + */ + @ViewDebug.ExportedProperty(category = "accessibility") + public boolean isAccessibilityDataPrivate() { + if (mInferredAccessibilityDataPrivate == ACCESSIBILITY_DATA_PRIVATE_AUTO) { + calculateAccessibilityDataPrivate(); + } + return mInferredAccessibilityDataPrivate == ACCESSIBILITY_DATA_PRIVATE_YES; + } + + /** + * Calculate and cache the inferred value for {@link #isAccessibilityDataPrivate()}. + * + * <p> + * <strong>Note:</strong> This method needs to be called any time one of the below conditions + * changes, to recalculate the new value. + * </p> + */ + void calculateAccessibilityDataPrivate() { + // Use the explicit value if set. + if (mExplicitAccessibilityDataPrivate != ACCESSIBILITY_DATA_PRIVATE_AUTO) { + mInferredAccessibilityDataPrivate = mExplicitAccessibilityDataPrivate; + } else if (mAttachInfo != null && mAttachInfo.mWindowSecure) { + // Views inside FLAG_SECURE windows default to accessibilityDataPrivate. + mInferredAccessibilityDataPrivate = ACCESSIBILITY_DATA_PRIVATE_YES; + } else if (getFilterTouchesWhenObscured()) { + // Views that set filterTouchesWhenObscured default to accessibilityDataPrivate. + mInferredAccessibilityDataPrivate = ACCESSIBILITY_DATA_PRIVATE_YES; + } else if (mParent instanceof View && ((View) mParent).isAccessibilityDataPrivate()) { + // Descendants of an accessibilityDataPrivate View are also accessibilityDataPrivate. + mInferredAccessibilityDataPrivate = ACCESSIBILITY_DATA_PRIVATE_YES; + } else { + // Otherwise, default to not accessibilityDataPrivate. + mInferredAccessibilityDataPrivate = ACCESSIBILITY_DATA_PRIVATE_NO; + } + } + + /** + * Specifies whether this view should only allow interactions from + * {@link android.accessibilityservice.AccessibilityService}s with the + * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property + * set to true. + */ + public void setAccessibilityDataPrivate( + @AccessibilityDataPrivate int accessibilityDataPrivate) { + mExplicitAccessibilityDataPrivate = accessibilityDataPrivate; + calculateAccessibilityDataPrivate(); + } + + /** * Returns whether the View is considered actionable from * accessibility perspective. Such view are important for * accessibility. @@ -30096,6 +30221,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, int mWindowVisibility; /** + * Indicates whether the view's window sets {@link WindowManager.LayoutParams#FLAG_SECURE}. + */ + boolean mWindowSecure; + + /** * Indicates the time at which drawing started to occur. */ @UnsupportedAppUsage @@ -30272,8 +30402,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * Flags related to accessibility processing. * - * @see AccessibilityNodeInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS - * @see AccessibilityNodeInfo#FLAG_REPORT_VIEW_IDS + * @see AccessibilityNodeInfo#FLAG_SERVICE_REQUESTS_INCLUDE_NOT_IMPORTANT_VIEWS + * @see AccessibilityNodeInfo#FLAG_SERVICE_REQUESTS_REPORT_VIEW_IDS */ int mAccessibilityFetchFlags; diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 9f0ad1169a8e..c4f20dc25904 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -3919,6 +3919,14 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } @Override + void calculateAccessibilityDataPrivate() { + super.calculateAccessibilityDataPrivate(); + for (int i = 0; i < mChildrenCount; i++) { + mChildren[i].calculateAccessibilityDataPrivate(); + } + } + + @Override @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) void dispatchDetachedFromWindow() { // If we still have a touch target, we are still in the process of diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 59bc061f54aa..ba250b0e247e 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -2836,6 +2836,7 @@ public final class ViewRootImpl implements ViewParent, // However, windows are now always 32 bits by default, so choose 32 bits mAttachInfo.mUse32BitDrawingCache = true; mAttachInfo.mWindowVisibility = viewVisibility; + mAttachInfo.mWindowSecure = (lp.flags & WindowManager.LayoutParams.FLAG_SECURE) != 0; mAttachInfo.mRecomputeGlobalAttributes = false; mLastConfigurationFromResources.setTo(config); mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility; diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java index cd0dd1df1249..2db0dcbce45e 100644 --- a/core/java/android/view/accessibility/AccessibilityEvent.java +++ b/core/java/android/view/accessibility/AccessibilityEvent.java @@ -46,15 +46,17 @@ import java.util.List; * </p> * <p> * The main purpose of an accessibility event is to communicate changes in the UI to an - * {@link android.accessibilityservice.AccessibilityService}. The service may then inspect, - * if needed the user interface by examining the View hierarchy, as represented by a tree of - * {@link AccessibilityNodeInfo}s (snapshot of a View state) - * which can be used for exploring the window content. Note that the privilege for accessing - * an event's source, thus the window content, has to be explicitly requested. For more + * {@link android.accessibilityservice.AccessibilityService}. If needed, the service may then + * inspect the user interface by examining the View hierarchy through the event's + * {@link #getSource() source}, as represented by a tree of {@link AccessibilityNodeInfo}s (snapshot + * of a View state) which can be used for exploring the window content. Note that the privilege for + * accessing an event's source, thus the window content, has to be explicitly requested. For more * details refer to {@link android.accessibilityservice.AccessibilityService}. If an * accessibility service has not requested to retrieve the window content the event will - * not contain reference to its source. Also for events of type - * {@link #TYPE_NOTIFICATION_STATE_CHANGED} the source is never available. + * not contain reference to its source. <strong>Note: </strong> for events of type + * {@link #TYPE_NOTIFICATION_STATE_CHANGED} the source is never available, and Views that set + * {@link android.view.View#isAccessibilityDataPrivate()} may not populate all event properties on + * events sent from higher up in the view hierarchy. * </p> * <p> * This class represents various semantically different accessibility event @@ -1092,6 +1094,47 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par } /** + * Whether the event should only be delivered to an + * {@link android.accessibilityservice.AccessibilityService} with the + * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property + * set to true. + * + * <p> + * Initial value matches the {@link android.view.View#isAccessibilityDataPrivate} property from + * the event's source node, if present, or false by default. + * </p> + * + * @return True if the event should be delivered only to isAccessibilityTool services, false + * otherwise. + * @see #setAccessibilityDataPrivate + */ + @Override + public boolean isAccessibilityDataPrivate() { + return super.isAccessibilityDataPrivate(); + } + + /** + * Sets whether the event should only be delivered to an + * {@link android.accessibilityservice.AccessibilityService} with the + * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property + * set to true. + * + * <p> + * This will be set automatically based on the event's source (if present). If creating and + * sending an event directly through {@link AccessibilityManager} (where an event may have + * no source) then this method must be called explicitly if you want non-default behavior. + * </p> + * + * @param accessibilityDataPrivate True if the event should be delivered only to + * isAccessibilityTool services, false otherwise. + * @throws IllegalStateException If called from an AccessibilityService. + */ + @Override + public void setAccessibilityDataPrivate(boolean accessibilityDataPrivate) { + super.setAccessibilityDataPrivate(accessibilityDataPrivate); + } + + /** * Gets the bit mask of the speech state signaled by a {@link #TYPE_SPEECH_STATE_CHANGE} event * * @see #SPEECH_STATE_SPEAKING_START diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java index 9e3195aec8a6..e89f836aaac1 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -276,6 +276,8 @@ public final class AccessibilityManager { private final ArrayMap<AudioDescriptionRequestedChangeListener, Executor> mAudioDescriptionRequestedChangeListeners = new ArrayMap<>(); + private boolean mRequestFromAccessibilityTool; + /** * Map from a view's accessibility id to the list of request preparers set for that view */ @@ -983,6 +985,39 @@ public final class AccessibilityManager { } /** + * Whether the current accessibility request comes from an + * {@link AccessibilityService} with the {@link AccessibilityServiceInfo#isAccessibilityTool} + * property set to true. + * + * <p> + * You can use this method inside {@link AccessibilityNodeProvider} to decide how to populate + * your nodes. + * </p> + * + * <p> + * <strong>Note:</strong> The return value is valid only when an {@link AccessibilityNodeInfo} + * request is in progress, can change from one request to another, and has no meaning when a + * request is not in progress. + * </p> + * + * @return True if the current request is from a tool that sets isAccessibilityTool. + */ + public boolean isRequestFromAccessibilityTool() { + return mRequestFromAccessibilityTool; + } + + /** + * Specifies whether the current accessibility request comes from an + * {@link AccessibilityService} with the {@link AccessibilityServiceInfo#isAccessibilityTool} + * property set to true. + * + * @hide + */ + public void setRequestFromAccessibilityTool(boolean requestFromAccessibilityTool) { + mRequestFromAccessibilityTool = requestFromAccessibilityTool; + } + + /** * Registers a {@link AccessibilityRequestPreparer}. */ public void addAccessibilityRequestPreparer(AccessibilityRequestPreparer preparer) { diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index 5d527500ff7b..6ae59bf0c8fc 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -220,14 +220,29 @@ public class AccessibilityNodeInfo implements Parcelable { @Retention(RetentionPolicy.SOURCE) public @interface PrefetchingStrategy {} - /** @hide */ - public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x00000080; + /** + * @see AccessibilityServiceInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS + * @hide + */ + public static final int FLAG_SERVICE_REQUESTS_INCLUDE_NOT_IMPORTANT_VIEWS = 0x00000080; - /** @hide */ - public static final int FLAG_REPORT_VIEW_IDS = 0x00000100; + /** + * @see AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS + * @hide + */ + public static final int FLAG_SERVICE_REQUESTS_REPORT_VIEW_IDS = 0x00000100; + + /** + * @see AccessibilityServiceInfo#isAccessibilityTool() + * @hide + */ + public static final int FLAG_SERVICE_IS_ACCESSIBILITY_TOOL = 0x00000200; /** @hide */ - public static final int FLAG_REPORT_MASK = 0x00000180; + public static final int FLAG_REPORT_MASK = + FLAG_SERVICE_REQUESTS_INCLUDE_NOT_IMPORTANT_VIEWS + | FLAG_SERVICE_REQUESTS_REPORT_VIEW_IDS + | FLAG_SERVICE_IS_ACCESSIBILITY_TOOL; // Actions. diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java index 036316e15cb9..789c740bbba2 100644 --- a/core/java/android/view/accessibility/AccessibilityRecord.java +++ b/core/java/android/view/accessibility/AccessibilityRecord.java @@ -72,6 +72,7 @@ public class AccessibilityRecord { private static final int PROPERTY_FULL_SCREEN = 0x00000080; private static final int PROPERTY_SCROLLABLE = 0x00000100; private static final int PROPERTY_IMPORTANT_FOR_ACCESSIBILITY = 0x00000200; + private static final int PROPERTY_ACCESSIBILITY_DATA_PRIVATE = 0x00000400; private static final int GET_SOURCE_PREFETCH_FLAGS = AccessibilityNodeInfo.FLAG_PREFETCH_ANCESTORS @@ -159,6 +160,8 @@ public class AccessibilityRecord { important = root.isImportantForAccessibility(); rootViewId = root.getAccessibilityViewId(); mSourceWindowId = root.getAccessibilityWindowId(); + setBooleanProperty(PROPERTY_ACCESSIBILITY_DATA_PRIVATE, + root.isAccessibilityDataPrivate()); } setBooleanProperty(PROPERTY_IMPORTANT_FOR_ACCESSIBILITY, important); mSourceNodeId = AccessibilityNodeInfo.makeNodeId(rootViewId, virtualDescendantId); @@ -388,6 +391,23 @@ public class AccessibilityRecord { } /** + * @see AccessibilityEvent#isAccessibilityDataPrivate + * @hide + */ + boolean isAccessibilityDataPrivate() { + return getBooleanProperty(PROPERTY_ACCESSIBILITY_DATA_PRIVATE); + } + + /** + * @see AccessibilityEvent#setAccessibilityDataPrivate + * @hide + */ + void setAccessibilityDataPrivate(boolean accessibilityDataPrivate) { + enforceNotSealed(); + setBooleanProperty(PROPERTY_ACCESSIBILITY_DATA_PRIVATE, accessibilityDataPrivate); + } + + /** * Gets the number of items that can be visited. * * @return The number of items. @@ -941,6 +961,8 @@ public class AccessibilityRecord { appendUnless(false, PROPERTY_CHECKED, builder); appendUnless(false, PROPERTY_FULL_SCREEN, builder); appendUnless(false, PROPERTY_SCROLLABLE, builder); + appendUnless(false, PROPERTY_IMPORTANT_FOR_ACCESSIBILITY, builder); + appendUnless(false, PROPERTY_ACCESSIBILITY_DATA_PRIVATE, builder); append(builder, "BeforeText", mBeforeText); append(builder, "FromIndex", mFromIndex); @@ -974,6 +996,8 @@ public class AccessibilityRecord { case PROPERTY_SCROLLABLE: return "Scrollable"; case PROPERTY_IMPORTANT_FOR_ACCESSIBILITY: return "ImportantForAccessibility"; + case PROPERTY_ACCESSIBILITY_DATA_PRIVATE: + return "AccessibilityDataPrivate"; default: return Integer.toHexString(prop); } } diff --git a/core/java/android/view/accessibility/DirectAccessibilityConnection.java b/core/java/android/view/accessibility/DirectAccessibilityConnection.java index 71746ee5dbab..dcc5660a64d6 100644 --- a/core/java/android/view/accessibility/DirectAccessibilityConnection.java +++ b/core/java/android/view/accessibility/DirectAccessibilityConnection.java @@ -55,8 +55,8 @@ class DirectAccessibilityConnection extends IAccessibilityServiceConnection.Defa // Fetch all views, but do not use prefetching/cache since this "connection" does not // receive cache invalidation events (as it is not linked to an AccessibilityService). private static final int FETCH_FLAGS = - AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS - | AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; + AccessibilityNodeInfo.FLAG_SERVICE_REQUESTS_REPORT_VIEW_IDS + | AccessibilityNodeInfo.FLAG_SERVICE_REQUESTS_INCLUDE_NOT_IMPORTANT_VIEWS; private static final MagnificationSpec MAGNIFICATION_SPEC = new MagnificationSpec(); private static final int PID = Process.myPid(); private static final Region INTERACTIVE_REGION = null; diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java index e31eabb083e5..0b63c179d042 100644 --- a/core/java/android/view/textservice/TextServicesManager.java +++ b/core/java/android/view/textservice/TextServicesManager.java @@ -303,6 +303,10 @@ public final class TextServicesManager { /** * Retrieve the list of currently enabled spell checkers. * + * <p> Note: The results are filtered by the rules of + * <a href="/training/basics/intents/package-visibility">package visibility</a>, except for + * the currently active spell checker. + * * @return The list of currently enabled spell checkers. */ @UserHandleAware diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index cd1c23cdc75f..6a572c530a1e 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -12089,6 +12089,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) { super.onPopulateAccessibilityEventInternal(event); + if (this.isAccessibilityDataPrivate() && !event.isAccessibilityDataPrivate()) { + // This view's accessibility data is private, but another view that generated this event + // is not, so don't append this view's text to the event in order to prevent sharing + // this view's contents with non-accessibility-tool services. + return; + } + final CharSequence text = getTextForAccessibility(); if (!TextUtils.isEmpty(text)) { event.getText().add(text); diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java index 962870e733f7..6909965edcd8 100644 --- a/core/java/com/android/internal/os/BatteryStatsHistory.java +++ b/core/java/com/android/internal/os/BatteryStatsHistory.java @@ -17,25 +17,35 @@ package com.android.internal.os; import android.annotation.Nullable; -import android.os.BatteryStats; +import android.os.BatteryManager; +import android.os.BatteryStats.HistoryItem; +import android.os.BatteryStats.HistoryStepDetails; +import android.os.BatteryStats.HistoryTag; import android.os.Parcel; +import android.os.ParcelFormatException; +import android.os.Process; import android.os.StatFs; import android.os.SystemClock; import android.util.ArraySet; import android.util.AtomicFile; import android.util.Slog; +import android.util.SparseArray; +import android.util.TimeUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ParseUtils; import java.io.File; +import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; -import java.util.function.Supplier; +import java.util.concurrent.locks.ReentrantLock; /** * BatteryStatsHistory encapsulates battery history files. @@ -56,57 +66,62 @@ import java.util.function.Supplier; * All interfaces in BatteryStatsHistory should only be called by BatteryStatsImpl and protected by * locks on BatteryStatsImpl object. */ -@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public class BatteryStatsHistory { private static final boolean DEBUG = false; private static final String TAG = "BatteryStatsHistory"; // Current on-disk Parcel version. Must be updated when the format of the parcelable changes - public static final int VERSION = 208; + private static final int VERSION = 208; - public static final String HISTORY_DIR = "battery-history"; - public static final String FILE_SUFFIX = ".bin"; + private static final String HISTORY_DIR = "battery-history"; + private static final String FILE_SUFFIX = ".bin"; private static final int MIN_FREE_SPACE = 100 * 1024 * 1024; + // Part of initial delta int that specifies the time delta. - public static final int DELTA_TIME_MASK = 0x7ffff; - public static final int DELTA_TIME_LONG = 0x7ffff; // The delta is a following long - public static final int DELTA_TIME_INT = 0x7fffe; // The delta is a following int - public static final int DELTA_TIME_ABS = 0x7fffd; // Following is an entire abs update. + static final int DELTA_TIME_MASK = 0x7ffff; + static final int DELTA_TIME_LONG = 0x7ffff; // The delta is a following long + static final int DELTA_TIME_INT = 0x7fffe; // The delta is a following int + static final int DELTA_TIME_ABS = 0x7fffd; // Following is an entire abs update. // Flag in delta int: a new battery level int follows. - public static final int DELTA_BATTERY_LEVEL_FLAG = 0x00080000; + static final int DELTA_BATTERY_LEVEL_FLAG = 0x00080000; // Flag in delta int: a new full state and battery status int follows. - public static final int DELTA_STATE_FLAG = 0x00100000; + static final int DELTA_STATE_FLAG = 0x00100000; // Flag in delta int: a new full state2 int follows. - public static final int DELTA_STATE2_FLAG = 0x00200000; + static final int DELTA_STATE2_FLAG = 0x00200000; // Flag in delta int: contains a wakelock or wakeReason tag. - public static final int DELTA_WAKELOCK_FLAG = 0x00400000; + static final int DELTA_WAKELOCK_FLAG = 0x00400000; // Flag in delta int: contains an event description. - public static final int DELTA_EVENT_FLAG = 0x00800000; + static final int DELTA_EVENT_FLAG = 0x00800000; // Flag in delta int: contains the battery charge count in uAh. - public static final int DELTA_BATTERY_CHARGE_FLAG = 0x01000000; + static final int DELTA_BATTERY_CHARGE_FLAG = 0x01000000; // These upper bits are the frequently changing state bits. - public static final int DELTA_STATE_MASK = 0xfe000000; + static final int DELTA_STATE_MASK = 0xfe000000; // These are the pieces of battery state that are packed in to the upper bits of // the state int that have been packed in to the first delta int. They must fit // in STATE_BATTERY_MASK. - public static final int STATE_BATTERY_MASK = 0xff000000; - public static final int STATE_BATTERY_STATUS_MASK = 0x00000007; - public static final int STATE_BATTERY_STATUS_SHIFT = 29; - public static final int STATE_BATTERY_HEALTH_MASK = 0x00000007; - public static final int STATE_BATTERY_HEALTH_SHIFT = 26; - public static final int STATE_BATTERY_PLUG_MASK = 0x00000003; - public static final int STATE_BATTERY_PLUG_SHIFT = 24; + static final int STATE_BATTERY_MASK = 0xff000000; + static final int STATE_BATTERY_STATUS_MASK = 0x00000007; + static final int STATE_BATTERY_STATUS_SHIFT = 29; + static final int STATE_BATTERY_HEALTH_MASK = 0x00000007; + static final int STATE_BATTERY_HEALTH_SHIFT = 26; + static final int STATE_BATTERY_PLUG_MASK = 0x00000003; + static final int STATE_BATTERY_PLUG_SHIFT = 24; // We use the low bit of the battery state int to indicate that we have full details // from a battery level change. - public static final int BATTERY_DELTA_LEVEL_FLAG = 0x00000001; + static final int BATTERY_DELTA_LEVEL_FLAG = 0x00000001; // Flag in history tag index: indicates that this is the first occurrence of this tag, // therefore the tag value is written in the parcel - public static final int TAG_FIRST_OCCURRENCE_FLAG = 0x8000; + static final int TAG_FIRST_OCCURRENCE_FLAG = 0x8000; - @Nullable - private final Supplier<Integer> mMaxHistoryFiles; private final Parcel mHistoryBuffer; + private final File mSystemDir; + private final HistoryStepDetailsCalculator mStepDetailsCalculator; private final File mHistoryDir; + private final Clock mClock; + + private int mMaxHistoryFiles; + private int mMaxHistoryBufferSize; + /** * The active history file that the history buffer is backed up into. */ @@ -144,19 +159,77 @@ public class BatteryStatsHistory { */ private int mParcelIndex = 0; + private final ReentrantLock mWriteLock = new ReentrantLock(); + + private final HistoryItem mHistoryCur = new HistoryItem(); + + private boolean mHaveBatteryLevel; + private boolean mRecordingHistory; + + private static final int HISTORY_TAG_INDEX_LIMIT = 0x7ffe; + private static final int MAX_HISTORY_TAG_STRING_LENGTH = 1024; + + private final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap<>(); + private SparseArray<HistoryTag> mHistoryTags; + private final HistoryItem mHistoryLastWritten = new HistoryItem(); + private final HistoryItem mHistoryLastLastWritten = new HistoryItem(); + private final HistoryItem mHistoryAddTmp = new HistoryItem(); + private int mNextHistoryTagIdx = 0; + private int mNumHistoryTagChars = 0; + private int mHistoryBufferLastPos = -1; + private int mActiveHistoryStates = 0xffffffff; + private int mActiveHistoryStates2 = 0xffffffff; + private long mLastHistoryElapsedRealtimeMs = 0; + private long mTrackRunningHistoryElapsedRealtimeMs = 0; + private long mTrackRunningHistoryUptimeMs = 0; + private long mHistoryBaseTimeMs; + + private byte mLastHistoryStepLevel = 0; + + private BatteryStatsHistoryIterator mBatteryStatsHistoryIterator; + + /** + * A delegate responsible for computing additional details for a step in battery history. + */ + public interface HistoryStepDetailsCalculator { + /** + * Returns additional details for the current history step or null. + */ + @Nullable + HistoryStepDetails getHistoryStepDetails(); + + /** + * Resets the calculator to get ready for a new battery session + */ + void clear(); + } + /** * Constructor * - * @param historyBuffer The in-memory history buffer. - * @param systemDir typically /data/system - * @param maxHistoryFiles the largest number of history buffer files to keep + * @param systemDir typically /data/system + * @param maxHistoryFiles the largest number of history buffer files to keep + * @param maxHistoryBufferSize the most amount of RAM to used for buffering of history steps */ + public BatteryStatsHistory(File systemDir, int maxHistoryFiles, int maxHistoryBufferSize, + HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) { + this(Parcel.obtain(), systemDir, maxHistoryFiles, maxHistoryBufferSize, + stepDetailsCalculator, clock); + initHistoryBuffer(); + } + + @VisibleForTesting public BatteryStatsHistory(Parcel historyBuffer, File systemDir, - Supplier<Integer> maxHistoryFiles) { + int maxHistoryFiles, int maxHistoryBufferSize, + HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) { mHistoryBuffer = historyBuffer; - mHistoryDir = new File(systemDir, HISTORY_DIR); + mSystemDir = systemDir; mMaxHistoryFiles = maxHistoryFiles; + mMaxHistoryBufferSize = maxHistoryBufferSize; + mStepDetailsCalculator = stepDetailsCalculator; + mClock = clock; + mHistoryDir = new File(systemDir, HISTORY_DIR); mHistoryDir.mkdirs(); if (!mHistoryDir.exists()) { Slog.wtf(TAG, "HistoryDir does not exist:" + mHistoryDir.getPath()); @@ -192,19 +265,81 @@ public class BatteryStatsHistory { } } + public BatteryStatsHistory(HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) { + mStepDetailsCalculator = stepDetailsCalculator; + mClock = clock; + + mHistoryBuffer = Parcel.obtain(); + mSystemDir = null; + mHistoryDir = null; + initHistoryBuffer(); + } + /** * Used when BatteryStatsImpl object is created from deserialization of a parcel, - * such as Settings app or checkin file. - * @param historyBuffer the history buffer + * such as a checkin file. */ - public BatteryStatsHistory(Parcel historyBuffer) { - mHistoryDir = null; + private BatteryStatsHistory(Parcel historyBuffer, + HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) { mHistoryBuffer = historyBuffer; - mMaxHistoryFiles = null; + mClock = clock; + mSystemDir = null; + mHistoryDir = null; + mStepDetailsCalculator = stepDetailsCalculator; + } + + private void initHistoryBuffer() { + mHistoryBaseTimeMs = 0; + mLastHistoryElapsedRealtimeMs = 0; + mTrackRunningHistoryElapsedRealtimeMs = 0; + mTrackRunningHistoryUptimeMs = 0; + + mHistoryBuffer.setDataSize(0); + mHistoryBuffer.setDataPosition(0); + mHistoryBuffer.setDataCapacity(mMaxHistoryBufferSize / 2); + mHistoryLastLastWritten.clear(); + mHistoryLastWritten.clear(); + mHistoryTagPool.clear(); + mNextHistoryTagIdx = 0; + mNumHistoryTagChars = 0; + mHistoryBufferLastPos = -1; + mActiveHistoryStates = 0xffffffff; + mActiveHistoryStates2 = 0xffffffff; + if (mStepDetailsCalculator != null) { + mStepDetailsCalculator.clear(); + } + } + + /** + * Changes the maximum number of history files to be kept. + */ + public void setMaxHistoryFiles(int maxHistoryFiles) { + mMaxHistoryFiles = maxHistoryFiles; + } + + /** + * Changes the maximum size of the history buffer, in bytes. + */ + public void setMaxHistoryBufferSize(int maxHistoryBufferSize) { + mMaxHistoryBufferSize = maxHistoryBufferSize; } - public File getHistoryDirectory() { - return mHistoryDir; + /** + * Creates a read-only copy of the battery history. Does not copy the files stored + * in the system directory, so it is not safe while actively writing history. + */ + public BatteryStatsHistory copy() { + // Make a copy of battery history to avoid concurrent modification. + Parcel historyBuffer = Parcel.obtain(); + historyBuffer.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize()); + return new BatteryStatsHistory(historyBuffer, mSystemDir, 0, 0, null, null); + } + + /** + * Returns true if this instance only supports reading history. + */ + public boolean isReadOnly() { + return mActiveFile == null; } /** @@ -221,12 +356,13 @@ public class BatteryStatsHistory { /** * Create history AtomicFile from file number. + * * @param num file number. * @return AtomicFile object. */ private AtomicFile getFile(int num) { return new AtomicFile( - new File(mHistoryDir, num + FILE_SUFFIX)); + new File(mHistoryDir, num + FILE_SUFFIX)); } /** @@ -234,7 +370,7 @@ public class BatteryStatsHistory { * create next history file. */ public void startNextFile() { - if (mMaxHistoryFiles == null) { + if (mMaxHistoryFiles == 0) { Slog.wtf(TAG, "mMaxHistoryFiles should not be zero when writing history"); return; } @@ -264,7 +400,7 @@ public class BatteryStatsHistory { // if there are more history files than allowed, delete oldest history files. // mMaxHistoryFiles comes from Constants.MAX_HISTORY_FILES and can be updated by GService // config at run time. - while (mFileNumbers.size() > mMaxHistoryFiles.get()) { + while (mFileNumbers.size() > mMaxHistoryFiles) { int oldest = mFileNumbers.get(0); getFile(oldest).delete(); mFileNumbers.remove(0); @@ -272,36 +408,43 @@ public class BatteryStatsHistory { } /** - * Delete all existing history files. Active history file start from number 0 again. + * Clear history buffer and delete all existing history files. Active history file start from + * number 0 again. */ - public void resetAllFiles() { + public void reset() { + if (DEBUG) Slog.i(TAG, "********** CLEARING HISTORY!"); for (Integer i : mFileNumbers) { getFile(i).delete(); } mFileNumbers.clear(); mFileNumbers.add(0); setActiveFile(0); + + initHistoryBuffer(); } /** * Start iterating history files and history buffer. + * * @return always return true. */ - public boolean startIteratingHistory() { + public BatteryStatsHistoryIterator iterate() { mRecordCount = 0; mCurrentFileIndex = 0; mCurrentParcel = null; mCurrentParcelEnd = 0; mParcelIndex = 0; - return true; + mBatteryStatsHistoryIterator = new BatteryStatsHistoryIterator(this); + return mBatteryStatsHistoryIterator; } /** * Finish iterating history files and history buffer. */ - public void finishIteratingHistory() { + void finishIteratingHistory() { // setDataPosition so mHistoryBuffer Parcel can be written. mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize()); + mBatteryStatsHistoryIterator = null; if (DEBUG) { Slog.d(TAG, "Battery history records iterated: " + mRecordCount); } @@ -311,11 +454,12 @@ public class BatteryStatsHistory { * When iterating history files and history buffer, always start from the lowest numbered * history file, when reached the mActiveFile (highest numbered history file), do not read from * mActiveFile, read from history buffer instead because the buffer has more updated data. + * * @param out a history item. * @return The parcel that has next record. null if finished all history files and history - * buffer + * buffer */ - public Parcel getNextParcel(BatteryStats.HistoryItem out) { + public Parcel getNextParcel(HistoryItem out) { if (mRecordCount == 0) { // reset out if it is the first record. out.clear(); @@ -323,8 +467,7 @@ public class BatteryStatsHistory { ++mRecordCount; // First iterate through all records in current parcel. - if (mCurrentParcel != null) - { + if (mCurrentParcel != null) { if (mCurrentParcel.dataPosition() < mCurrentParcelEnd) { // There are more records in current parcel. return mCurrentParcel; @@ -389,7 +532,8 @@ public class BatteryStatsHistory { /** * Read history file into a parcel. - * @param out the Parcel read into. + * + * @param out the Parcel read into. * @param file the File to read from. * @return true if success, false otherwise. */ @@ -402,8 +546,8 @@ public class BatteryStatsHistory { Slog.d(TAG, "readFileToParcel:" + file.getBaseFile().getPath() + " duration ms:" + (SystemClock.uptimeMillis() - start)); } - } catch(Exception e) { - Slog.e(TAG, "Error reading file "+ file.getBaseFile().getPath(), e); + } catch (Exception e) { + Slog.e(TAG, "Error reading file " + file.getBaseFile().getPath(), e); return false; } out.unmarshall(raw, 0, raw.length); @@ -413,6 +557,7 @@ public class BatteryStatsHistory { /** * Skip the header part of history parcel. + * * @param p history parcel to skip head. * @return true if version match, false if not. */ @@ -428,18 +573,68 @@ public class BatteryStatsHistory { } /** + * Writes the battery history contents for persistence. + */ + public void writeSummaryToParcel(Parcel out, boolean inclHistory) { + out.writeBoolean(inclHistory); + if (inclHistory) { + writeToParcel(out); + } + + out.writeInt(mHistoryTagPool.size()); + for (Map.Entry<HistoryTag, Integer> ent : mHistoryTagPool.entrySet()) { + HistoryTag tag = ent.getKey(); + out.writeInt(ent.getValue()); + out.writeString(tag.string); + out.writeInt(tag.uid); + } + } + + /** + * Reads battery history contents from a persisted parcel. + */ + public void readSummaryFromParcel(Parcel in) { + boolean inclHistory = in.readBoolean(); + if (inclHistory) { + readFromParcel(in); + } + + mHistoryTagPool.clear(); + mNextHistoryTagIdx = 0; + mNumHistoryTagChars = 0; + + int numTags = in.readInt(); + for (int i = 0; i < numTags; i++) { + int idx = in.readInt(); + String str = in.readString(); + int uid = in.readInt(); + HistoryTag tag = new HistoryTag(); + tag.string = str; + tag.uid = uid; + tag.poolIdx = idx; + mHistoryTagPool.put(tag, idx); + if (idx >= mNextHistoryTagIdx) { + mNextHistoryTagIdx = idx + 1; + } + mNumHistoryTagChars += tag.string.length() + 1; + } + } + + /** * Read all history files and serialize into a big Parcel. * Checkin file calls this method. * * @param out the output parcel */ public void writeToParcel(Parcel out) { + writeHistoryBuffer(out); writeToParcel(out, false /* useBlobs */); } /** * This is for Settings app, when Settings app receives big history parcel, it call * this method to parse it into list of parcels. + * * @param out the output parcel */ public void writeToBatteryUsageStatsParcel(Parcel out) { @@ -450,13 +645,13 @@ public class BatteryStatsHistory { private void writeToParcel(Parcel out, boolean useBlobs) { final long start = SystemClock.uptimeMillis(); out.writeInt(mFileNumbers.size() - 1); - for(int i = 0; i < mFileNumbers.size() - 1; i++) { + for (int i = 0; i < mFileNumbers.size() - 1; i++) { AtomicFile file = getFile(mFileNumbers.get(i)); byte[] raw = new byte[0]; try { raw = file.readFully(); - } catch(Exception e) { - Slog.e(TAG, "Error reading file "+ file.getBaseFile().getPath(), e); + } catch (Exception e) { + Slog.e(TAG, "Error reading file " + file.getBaseFile().getPath(), e); } if (useBlobs) { out.writeBlob(raw); @@ -480,17 +675,55 @@ public class BatteryStatsHistory { Parcel historyBuffer = Parcel.obtain(); historyBuffer.unmarshall(historyBlob, 0, historyBlob.length); - BatteryStatsHistory history = new BatteryStatsHistory(historyBuffer); + BatteryStatsHistory history = new BatteryStatsHistory(historyBuffer, null, + Clock.SYSTEM_CLOCK); history.readFromParcel(in, true /* useBlobs */); return history; } /** + * Read history from a check-in file. + */ + public boolean readSummary() { + if (mActiveFile == null) { + Slog.w(TAG, "readSummary: no history file associated with this instance"); + return false; + } + + Parcel parcel = Parcel.obtain(); + try { + final long start = SystemClock.uptimeMillis(); + if (mActiveFile.exists()) { + byte[] raw = mActiveFile.readFully(); + if (raw.length > 0) { + parcel.unmarshall(raw, 0, raw.length); + parcel.setDataPosition(0); + readHistoryBuffer(parcel); + } + if (DEBUG) { + Slog.d(TAG, "read history file::" + + mActiveFile.getBaseFile().getPath() + + " bytes:" + raw.length + " took ms:" + (SystemClock.uptimeMillis() + - start)); + } + } + } catch (Exception e) { + Slog.e(TAG, "Error reading battery history", e); + reset(); + return false; + } finally { + parcel.recycle(); + } + return true; + } + + /** * This is for the check-in file, which has all history files embedded. * * @param in the input parcel. */ public void readFromParcel(Parcel in) { + readHistoryBuffer(in); readFromParcel(in, false /* useBlobs */); } @@ -498,7 +731,7 @@ public class BatteryStatsHistory { final long start = SystemClock.uptimeMillis(); mHistoryParcels = new ArrayList<>(); final int count = in.readInt(); - for(int i = 0; i < count; i++) { + for (int i = 0; i < count; i++) { byte[] temp = useBlobs ? in.readBlob() : in.createByteArray(); if (temp == null || temp.length == 0) { continue; @@ -521,10 +754,12 @@ public class BatteryStatsHistory { return stats.getAvailableBytes() > MIN_FREE_SPACE; } + @VisibleForTesting public List<Integer> getFilesNumbers() { return mFileNumbers; } + @VisibleForTesting public AtomicFile getActiveFile() { return mActiveFile; } @@ -534,15 +769,972 @@ public class BatteryStatsHistory { */ public int getHistoryUsedSize() { int ret = 0; - for(int i = 0; i < mFileNumbers.size() - 1; i++) { + for (int i = 0; i < mFileNumbers.size() - 1; i++) { ret += getFile(mFileNumbers.get(i)).getBaseFile().length(); } ret += mHistoryBuffer.dataSize(); if (mHistoryParcels != null) { - for(int i = 0; i < mHistoryParcels.size(); i++) { + for (int i = 0; i < mHistoryParcels.size(); i++) { ret += mHistoryParcels.get(i).dataSize(); } } return ret; } + + /** + * Enables/disables recording of history. When disabled, all "record*" calls are a no-op. + */ + public void setHistoryRecordingEnabled(boolean enabled) { + mRecordingHistory = enabled; + } + + /** + * Returns true if history recording is enabled. + */ + public boolean isRecordingHistory() { + return mRecordingHistory; + } + + /** + * Forces history recording regardless of charging state. + */ + @VisibleForTesting + public void forceRecordAllHistory() { + mHaveBatteryLevel = true; + mRecordingHistory = true; + } + + /** + * Starts a history buffer by recording the current wall-clock time. + */ + public void startRecordingHistory(final long elapsedRealtimeMs, final long uptimeMs, + boolean reset) { + mRecordingHistory = true; + mHistoryCur.currentTime = mClock.currentTimeMillis(); + writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur, + reset ? HistoryItem.CMD_RESET : HistoryItem.CMD_CURRENT_TIME); + mHistoryCur.currentTime = 0; + } + + /** + * Prepares to continue recording after restoring previous history from persistent storage. + */ + public void continueRecordingHistory() { + if (mHistoryBuffer.dataPosition() <= 0 && mFileNumbers.size() <= 1) { + return; + } + + mRecordingHistory = true; + final long elapsedRealtimeMs = mClock.elapsedRealtime(); + final long uptimeMs = mClock.uptimeMillis(); + writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur, HistoryItem.CMD_START); + startRecordingHistory(elapsedRealtimeMs, uptimeMs, false); + } + + /** + * Notes the current battery state to be reflected in the next written history item. + */ + public void setBatteryState(boolean charging, int status, int level, int chargeUah) { + mHaveBatteryLevel = true; + setChargingState(charging); + mHistoryCur.batteryStatus = (byte) status; + mHistoryCur.batteryLevel = (byte) level; + mHistoryCur.batteryChargeUah = chargeUah; + } + + /** + * Notes the current battery state to be reflected in the next written history item. + */ + public void setBatteryState(int status, int level, int health, int plugType, int temperature, + int voltageMv, int chargeUah) { + mHaveBatteryLevel = true; + mHistoryCur.batteryStatus = (byte) status; + mHistoryCur.batteryLevel = (byte) level; + mHistoryCur.batteryHealth = (byte) health; + mHistoryCur.batteryPlugType = (byte) plugType; + mHistoryCur.batteryTemperature = (short) temperature; + mHistoryCur.batteryVoltage = (char) voltageMv; + mHistoryCur.batteryChargeUah = chargeUah; + } + + /** + * Notes the current power plugged-in state to be reflected in the next written history item. + */ + public void setPluggedInState(boolean pluggedIn) { + if (pluggedIn) { + mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG; + } else { + mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG; + } + } + + /** + * Notes the current battery charging state to be reflected in the next written history item. + */ + public void setChargingState(boolean charging) { + if (charging) { + mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG; + } else { + mHistoryCur.states2 &= ~HistoryItem.STATE2_CHARGING_FLAG; + } + } + + /** + * Records a history event with the given code, name and UID. + */ + public void recordEvent(long elapsedRealtimeMs, long uptimeMs, int code, String name, + int uid) { + mHistoryCur.eventCode = code; + mHistoryCur.eventTag = mHistoryCur.localEventTag; + mHistoryCur.eventTag.string = name; + mHistoryCur.eventTag.uid = uid; + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records a time change event. + */ + public void recordCurrentTimeChange(long elapsedRealtimeMs, long uptimeMs, long currentTimeMs) { + if (!mRecordingHistory) { + return; + } + + mHistoryCur.currentTime = currentTimeMs; + writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur, + HistoryItem.CMD_CURRENT_TIME); + mHistoryCur.currentTime = 0; + } + + /** + * Records a system shutdown event. + */ + public void recordShutdownEvent(long elapsedRealtimeMs, long uptimeMs, long currentTimeMs) { + if (!mRecordingHistory) { + return; + } + + mHistoryCur.currentTime = currentTimeMs; + writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur, HistoryItem.CMD_SHUTDOWN); + mHistoryCur.currentTime = 0; + } + + /** + * Records a battery state change event. + */ + public void recordBatteryState(long elapsedRealtimeMs, long uptimeMs, int batteryLevel, + boolean isPlugged) { + mHistoryCur.batteryLevel = (byte) batteryLevel; + setPluggedInState(isPlugged); + if (DEBUG) { + Slog.v(TAG, "Battery unplugged to: " + + Integer.toHexString(mHistoryCur.states)); + } + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records a history item with the amount of charge consumed by WiFi. Used on certain devices + * equipped with on-device power metering. + */ + public void recordWifiConsumedCharge(long elapsedRealtimeMs, long uptimeMs, + double monitoredRailChargeMah) { + mHistoryCur.wifiRailChargeMah += monitoredRailChargeMah; + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records a wakelock start event. + */ + public void recordWakelockStartEvent(long elapsedRealtimeMs, long uptimeMs, String historyName, + int uid) { + mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag; + mHistoryCur.wakelockTag.string = historyName; + mHistoryCur.wakelockTag.uid = uid; + recordStateStartEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.STATE_WAKE_LOCK_FLAG); + } + + /** + * Updates the previous history event with a wakelock name and UID. + */ + public boolean maybeUpdateWakelockTag(long elapsedRealtimeMs, long uptimeMs, String historyName, + int uid) { + if (mHistoryLastWritten.cmd != HistoryItem.CMD_UPDATE) { + return false; + } + if (mHistoryLastWritten.wakelockTag != null) { + // We'll try to update the last tag. + mHistoryLastWritten.wakelockTag = null; + mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag; + mHistoryCur.wakelockTag.string = historyName; + mHistoryCur.wakelockTag.uid = uid; + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + return true; + } + + /** + * Records an event when some state flag changes to true. + */ + public void recordStateStartEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) { + mHistoryCur.states |= stateFlags; + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records an event when some state flag changes to false. + */ + public void recordStateStopEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) { + mHistoryCur.states &= ~stateFlags; + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records an event when some state flags change to true and some to false. + */ + public void recordStateChangeEvent(long elapsedRealtimeMs, long uptimeMs, int stateStartFlags, + int stateStopFlags) { + mHistoryCur.states = (mHistoryCur.states | stateStartFlags) & ~stateStopFlags; + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records an event when some state2 flag changes to true. + */ + public void recordState2StartEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) { + mHistoryCur.states2 |= stateFlags; + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records an event when some state2 flag changes to false. + */ + public void recordState2StopEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) { + mHistoryCur.states2 &= ~stateFlags; + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records an wakeup event. + */ + public void recordWakeupEvent(long elapsedRealtimeMs, long uptimeMs, String reason) { + mHistoryCur.wakeReasonTag = mHistoryCur.localWakeReasonTag; + mHistoryCur.wakeReasonTag.string = reason; + mHistoryCur.wakeReasonTag.uid = 0; + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records a screen brightness change event. + */ + public void recordScreenBrightnessEvent(long elapsedRealtimeMs, long uptimeMs, + int brightnessBin) { + mHistoryCur.states = (mHistoryCur.states & ~HistoryItem.STATE_BRIGHTNESS_MASK) + | (brightnessBin << HistoryItem.STATE_BRIGHTNESS_SHIFT); + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records a GNSS signal level change event. + */ + public void recordGpsSignalQualityEvent(long elapsedRealtimeMs, long uptimeMs, + int signalLevel) { + mHistoryCur.states2 = (mHistoryCur.states2 & ~HistoryItem.STATE2_GPS_SIGNAL_QUALITY_MASK) + | (signalLevel << HistoryItem.STATE2_GPS_SIGNAL_QUALITY_SHIFT); + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records a device idle mode change event. + */ + public void recordDeviceIdleEvent(long elapsedRealtimeMs, long uptimeMs, int mode) { + mHistoryCur.states2 = (mHistoryCur.states2 & ~HistoryItem.STATE2_DEVICE_IDLE_MASK) + | (mode << HistoryItem.STATE2_DEVICE_IDLE_SHIFT); + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records a telephony state change event. + */ + public void recordPhoneStateChangeEvent(long elapsedRealtimeMs, long uptimeMs, int addStateFlag, + int removeStateFlag, int state, int signalStrength) { + mHistoryCur.states = (mHistoryCur.states | addStateFlag) & ~removeStateFlag; + if (state != -1) { + mHistoryCur.states = + (mHistoryCur.states & ~HistoryItem.STATE_PHONE_STATE_MASK) + | (state << HistoryItem.STATE_PHONE_STATE_SHIFT); + } + if (signalStrength != -1) { + mHistoryCur.states = + (mHistoryCur.states & ~HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_MASK) + | (signalStrength << HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_SHIFT); + } + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records a data connection type change event. + */ + public void recordDataConnectionTypeChangeEvent(long elapsedRealtimeMs, long uptimeMs, + int dataConnectionType) { + mHistoryCur.states = (mHistoryCur.states & ~HistoryItem.STATE_DATA_CONNECTION_MASK) + | (dataConnectionType << HistoryItem.STATE_DATA_CONNECTION_SHIFT); + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records a WiFi supplicant state change event. + */ + public void recordWifiSupplicantStateChangeEvent(long elapsedRealtimeMs, long uptimeMs, + int supplState) { + mHistoryCur.states2 = + (mHistoryCur.states2 & ~HistoryItem.STATE2_WIFI_SUPPL_STATE_MASK) + | (supplState << HistoryItem.STATE2_WIFI_SUPPL_STATE_SHIFT); + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Records a WiFi signal strength change event. + */ + public void recordWifiSignalStrengthChangeEvent(long elapsedRealtimeMs, long uptimeMs, + int strengthBin) { + mHistoryCur.states2 = + (mHistoryCur.states2 & ~HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_MASK) + | (strengthBin << HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_SHIFT); + writeHistoryItem(elapsedRealtimeMs, uptimeMs); + } + + /** + * Writes the current history item to history. + */ + public void writeHistoryItem(long elapsedRealtimeMs, long uptimeMs) { + if (mTrackRunningHistoryElapsedRealtimeMs != 0) { + final long diffElapsedMs = elapsedRealtimeMs - mTrackRunningHistoryElapsedRealtimeMs; + final long diffUptimeMs = uptimeMs - mTrackRunningHistoryUptimeMs; + if (diffUptimeMs < (diffElapsedMs - 20)) { + final long wakeElapsedTimeMs = elapsedRealtimeMs - (diffElapsedMs - diffUptimeMs); + mHistoryAddTmp.setTo(mHistoryLastWritten); + mHistoryAddTmp.wakelockTag = null; + mHistoryAddTmp.wakeReasonTag = null; + mHistoryAddTmp.eventCode = HistoryItem.EVENT_NONE; + mHistoryAddTmp.states &= ~HistoryItem.STATE_CPU_RUNNING_FLAG; + writeHistoryItem(wakeElapsedTimeMs, uptimeMs, mHistoryAddTmp); + } + } + mHistoryCur.states |= HistoryItem.STATE_CPU_RUNNING_FLAG; + mTrackRunningHistoryElapsedRealtimeMs = elapsedRealtimeMs; + mTrackRunningHistoryUptimeMs = uptimeMs; + writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur); + } + + private void writeHistoryItem(long elapsedRealtimeMs, long uptimeMs, HistoryItem cur) { + if (!mHaveBatteryLevel || !mRecordingHistory) { + return; + } + + final long timeDiffMs = (mHistoryBaseTimeMs + elapsedRealtimeMs) - mHistoryLastWritten.time; + final int diffStates = mHistoryLastWritten.states ^ (cur.states & mActiveHistoryStates); + final int diffStates2 = mHistoryLastWritten.states2 ^ (cur.states2 & mActiveHistoryStates2); + final int lastDiffStates = mHistoryLastWritten.states ^ mHistoryLastLastWritten.states; + final int lastDiffStates2 = mHistoryLastWritten.states2 ^ mHistoryLastLastWritten.states2; + if (DEBUG) { + Slog.i(TAG, "ADD: tdelta=" + timeDiffMs + " diff=" + + Integer.toHexString(diffStates) + " lastDiff=" + + Integer.toHexString(lastDiffStates) + " diff2=" + + Integer.toHexString(diffStates2) + " lastDiff2=" + + Integer.toHexString(lastDiffStates2)); + } + if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE + && timeDiffMs < 1000 && (diffStates & lastDiffStates) == 0 + && (diffStates2 & lastDiffStates2) == 0 + && (!mHistoryLastWritten.tagsFirstOccurrence && !cur.tagsFirstOccurrence) + && (mHistoryLastWritten.wakelockTag == null || cur.wakelockTag == null) + && (mHistoryLastWritten.wakeReasonTag == null || cur.wakeReasonTag == null) + && mHistoryLastWritten.stepDetails == null + && (mHistoryLastWritten.eventCode == HistoryItem.EVENT_NONE + || cur.eventCode == HistoryItem.EVENT_NONE) + && mHistoryLastWritten.batteryLevel == cur.batteryLevel + && mHistoryLastWritten.batteryStatus == cur.batteryStatus + && mHistoryLastWritten.batteryHealth == cur.batteryHealth + && mHistoryLastWritten.batteryPlugType == cur.batteryPlugType + && mHistoryLastWritten.batteryTemperature == cur.batteryTemperature + && mHistoryLastWritten.batteryVoltage == cur.batteryVoltage) { + // We can merge this new change in with the last one. Merging is + // allowed as long as only the states have changed, and within those states + // as long as no bit has changed both between now and the last entry, as + // well as the last entry and the one before it (so we capture any toggles). + if (DEBUG) Slog.i(TAG, "ADD: rewinding back to " + mHistoryBufferLastPos); + mHistoryBuffer.setDataSize(mHistoryBufferLastPos); + mHistoryBuffer.setDataPosition(mHistoryBufferLastPos); + mHistoryBufferLastPos = -1; + elapsedRealtimeMs = mHistoryLastWritten.time - mHistoryBaseTimeMs; + // If the last written history had a wakelock tag, we need to retain it. + // Note that the condition above made sure that we aren't in a case where + // both it and the current history item have a wakelock tag. + if (mHistoryLastWritten.wakelockTag != null) { + cur.wakelockTag = cur.localWakelockTag; + cur.wakelockTag.setTo(mHistoryLastWritten.wakelockTag); + } + // If the last written history had a wake reason tag, we need to retain it. + // Note that the condition above made sure that we aren't in a case where + // both it and the current history item have a wakelock tag. + if (mHistoryLastWritten.wakeReasonTag != null) { + cur.wakeReasonTag = cur.localWakeReasonTag; + cur.wakeReasonTag.setTo(mHistoryLastWritten.wakeReasonTag); + } + // If the last written history had an event, we need to retain it. + // Note that the condition above made sure that we aren't in a case where + // both it and the current history item have an event. + if (mHistoryLastWritten.eventCode != HistoryItem.EVENT_NONE) { + cur.eventCode = mHistoryLastWritten.eventCode; + cur.eventTag = cur.localEventTag; + cur.eventTag.setTo(mHistoryLastWritten.eventTag); + } + mHistoryLastWritten.setTo(mHistoryLastLastWritten); + } + final int dataSize = mHistoryBuffer.dataSize(); + + if (dataSize >= mMaxHistoryBufferSize) { + if (mMaxHistoryBufferSize == 0) { + Slog.wtf(TAG, "mMaxHistoryBufferSize should not be zero when writing history"); + mMaxHistoryBufferSize = 1024; + } + + //open a new history file. + final long start = SystemClock.uptimeMillis(); + writeHistory(); + if (DEBUG) { + Slog.d(TAG, "addHistoryBufferLocked writeHistory took ms:" + + (SystemClock.uptimeMillis() - start)); + } + startNextFile(); + mHistoryBuffer.setDataSize(0); + mHistoryBuffer.setDataPosition(0); + mHistoryBuffer.setDataCapacity(mMaxHistoryBufferSize / 2); + mHistoryBufferLastPos = -1; + mHistoryLastWritten.clear(); + mHistoryLastLastWritten.clear(); + + // Mark every entry in the pool with a flag indicating that the tag + // has not yet been encountered while writing the current history buffer. + for (Map.Entry<HistoryTag, Integer> entry : mHistoryTagPool.entrySet()) { + entry.setValue(entry.getValue() | BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG); + } + // Make a copy of mHistoryCur. + HistoryItem copy = new HistoryItem(); + copy.setTo(cur); + // startRecordingHistory will reset mHistoryCur. + startRecordingHistory(elapsedRealtimeMs, uptimeMs, false); + // Add the copy into history buffer. + writeHistoryItem(elapsedRealtimeMs, uptimeMs, copy, HistoryItem.CMD_UPDATE); + return; + } + + if (dataSize == 0) { + // The history is currently empty; we need it to start with a time stamp. + cur.currentTime = mClock.currentTimeMillis(); + writeHistoryItem(elapsedRealtimeMs, uptimeMs, cur, HistoryItem.CMD_RESET); + } + writeHistoryItem(elapsedRealtimeMs, uptimeMs, cur, HistoryItem.CMD_UPDATE); + } + + private void writeHistoryItem(long elapsedRealtimeMs, + @SuppressWarnings("UnusedVariable") long uptimeMs, HistoryItem cur, byte cmd) { + if (mBatteryStatsHistoryIterator != null) { + throw new IllegalStateException("Can't do this while iterating history!"); + } + mHistoryBufferLastPos = mHistoryBuffer.dataPosition(); + mHistoryLastLastWritten.setTo(mHistoryLastWritten); + final boolean hasTags = mHistoryLastWritten.tagsFirstOccurrence || cur.tagsFirstOccurrence; + mHistoryLastWritten.setTo(mHistoryBaseTimeMs + elapsedRealtimeMs, cmd, cur); + mHistoryLastWritten.tagsFirstOccurrence = hasTags; + mHistoryLastWritten.states &= mActiveHistoryStates; + mHistoryLastWritten.states2 &= mActiveHistoryStates2; + writeHistoryDelta(mHistoryBuffer, mHistoryLastWritten, mHistoryLastLastWritten); + mLastHistoryElapsedRealtimeMs = elapsedRealtimeMs; + cur.wakelockTag = null; + cur.wakeReasonTag = null; + cur.eventCode = HistoryItem.EVENT_NONE; + cur.eventTag = null; + cur.tagsFirstOccurrence = false; + if (DEBUG) { + Slog.i(TAG, "Writing history buffer: was " + mHistoryBufferLastPos + + " now " + mHistoryBuffer.dataPosition() + + " size is now " + mHistoryBuffer.dataSize()); + } + } + + /* + The history delta format uses flags to denote further data in subsequent ints in the parcel. + + There is always the first token, which may contain the delta time, or an indicator of + the length of the time (int or long) following this token. + + First token: always present, + 31 23 15 7 0 + â–ˆM|L|K|J|I|H|G|Fâ–ˆE|D|C|B|A|T|T|Tâ–ˆT|T|T|T|T|T|T|Tâ–ˆT|T|T|T|T|T|T|Tâ–ˆ + + T: the delta time if it is <= 0x7fffd. Otherwise 0x7fffe indicates an int immediately + follows containing the time, and 0x7ffff indicates a long immediately follows with the + delta time. + A: battery level changed and an int follows with battery data. + B: state changed and an int follows with state change data. + C: state2 has changed and an int follows with state2 change data. + D: wakelock/wakereason has changed and an wakelock/wakereason struct follows. + E: event data has changed and an event struct follows. + F: battery charge in coulombs has changed and an int with the charge follows. + G: state flag denoting that the mobile radio was active. + H: state flag denoting that the wifi radio was active. + I: state flag denoting that a wifi scan occurred. + J: state flag denoting that a wifi full lock was held. + K: state flag denoting that the gps was on. + L: state flag denoting that a wakelock was held. + M: state flag denoting that the cpu was running. + + Time int/long: if T in the first token is 0x7ffff or 0x7fffe, then an int or long follows + with the time delta. + + Battery level int: if A in the first token is set, + 31 23 15 7 0 + â–ˆL|L|L|L|L|L|L|Tâ–ˆT|T|T|T|T|T|T|Tâ–ˆT|V|V|V|V|V|V|Vâ–ˆV|V|V|V|V|V|V|Dâ–ˆ + + D: indicates that extra history details follow. + V: the battery voltage. + T: the battery temperature. + L: the battery level (out of 100). + + State change int: if B in the first token is set, + 31 23 15 7 0 + â–ˆS|S|S|H|H|H|P|Pâ–ˆF|E|D|C|B| | |Aâ–ˆ | | | | | | | â–ˆ | | | | | | | â–ˆ + + A: wifi multicast was on. + B: battery was plugged in. + C: screen was on. + D: phone was scanning for signal. + E: audio was on. + F: a sensor was active. + + State2 change int: if C in the first token is set, + 31 23 15 7 0 + â–ˆM|L|K|J|I|H|H|Gâ–ˆF|E|D|C| | | | â–ˆ | | | | | | | â–ˆ |B|B|B|A|A|A|Aâ–ˆ + + A: 4 bits indicating the wifi supplicant state: {@link BatteryStats#WIFI_SUPPL_STATE_NAMES}. + B: 3 bits indicating the wifi signal strength: 0, 1, 2, 3, 4. + C: a bluetooth scan was active. + D: the camera was active. + E: bluetooth was on. + F: a phone call was active. + G: the device was charging. + H: 2 bits indicating the device-idle (doze) state: off, light, full + I: the flashlight was on. + J: wifi was on. + K: wifi was running. + L: video was playing. + M: power save mode was on. + + Wakelock/wakereason struct: if D in the first token is set, + Event struct: if E in the first token is set, + History step details struct: if D in the battery level int is set, + + Battery charge int: if F in the first token is set, an int representing the battery charge + in coulombs follows. + */ + /** + * Writes the delta between the previous and current history items into history buffer. + */ + public void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) { + if (last == null || cur.cmd != HistoryItem.CMD_UPDATE) { + dest.writeInt(BatteryStatsHistory.DELTA_TIME_ABS); + cur.writeToParcel(dest, 0); + return; + } + + final long deltaTime = cur.time - last.time; + final int lastBatteryLevelInt = buildBatteryLevelInt(last); + final int lastStateInt = buildStateInt(last); + + int deltaTimeToken; + if (deltaTime < 0 || deltaTime > Integer.MAX_VALUE) { + deltaTimeToken = BatteryStatsHistory.DELTA_TIME_LONG; + } else if (deltaTime >= BatteryStatsHistory.DELTA_TIME_ABS) { + deltaTimeToken = BatteryStatsHistory.DELTA_TIME_INT; + } else { + deltaTimeToken = (int) deltaTime; + } + int firstToken = deltaTimeToken | (cur.states & BatteryStatsHistory.DELTA_STATE_MASK); + final int includeStepDetails = mLastHistoryStepLevel > cur.batteryLevel + ? BatteryStatsHistory.BATTERY_DELTA_LEVEL_FLAG : 0; + mLastHistoryStepLevel = cur.batteryLevel; + final int batteryLevelInt = buildBatteryLevelInt(cur) | includeStepDetails; + final boolean batteryLevelIntChanged = batteryLevelInt != lastBatteryLevelInt; + if (batteryLevelIntChanged) { + firstToken |= BatteryStatsHistory.DELTA_BATTERY_LEVEL_FLAG; + } + final int stateInt = buildStateInt(cur); + final boolean stateIntChanged = stateInt != lastStateInt; + if (stateIntChanged) { + firstToken |= BatteryStatsHistory.DELTA_STATE_FLAG; + } + final boolean state2IntChanged = cur.states2 != last.states2; + if (state2IntChanged) { + firstToken |= BatteryStatsHistory.DELTA_STATE2_FLAG; + } + if (cur.wakelockTag != null || cur.wakeReasonTag != null) { + firstToken |= BatteryStatsHistory.DELTA_WAKELOCK_FLAG; + } + if (cur.eventCode != HistoryItem.EVENT_NONE) { + firstToken |= BatteryStatsHistory.DELTA_EVENT_FLAG; + } + + final boolean batteryChargeChanged = cur.batteryChargeUah != last.batteryChargeUah; + if (batteryChargeChanged) { + firstToken |= BatteryStatsHistory.DELTA_BATTERY_CHARGE_FLAG; + } + dest.writeInt(firstToken); + if (DEBUG) { + Slog.i(TAG, "WRITE DELTA: firstToken=0x" + Integer.toHexString(firstToken) + + " deltaTime=" + deltaTime); + } + + if (deltaTimeToken >= BatteryStatsHistory.DELTA_TIME_INT) { + if (deltaTimeToken == BatteryStatsHistory.DELTA_TIME_INT) { + if (DEBUG) Slog.i(TAG, "WRITE DELTA: int deltaTime=" + (int) deltaTime); + dest.writeInt((int) deltaTime); + } else { + if (DEBUG) Slog.i(TAG, "WRITE DELTA: long deltaTime=" + deltaTime); + dest.writeLong(deltaTime); + } + } + if (batteryLevelIntChanged) { + dest.writeInt(batteryLevelInt); + if (DEBUG) { + Slog.i(TAG, "WRITE DELTA: batteryToken=0x" + + Integer.toHexString(batteryLevelInt) + + " batteryLevel=" + cur.batteryLevel + + " batteryTemp=" + cur.batteryTemperature + + " batteryVolt=" + (int) cur.batteryVoltage); + } + } + if (stateIntChanged) { + dest.writeInt(stateInt); + if (DEBUG) { + Slog.i(TAG, "WRITE DELTA: stateToken=0x" + + Integer.toHexString(stateInt) + + " batteryStatus=" + cur.batteryStatus + + " batteryHealth=" + cur.batteryHealth + + " batteryPlugType=" + cur.batteryPlugType + + " states=0x" + Integer.toHexString(cur.states)); + } + } + if (state2IntChanged) { + dest.writeInt(cur.states2); + if (DEBUG) { + Slog.i(TAG, "WRITE DELTA: states2=0x" + + Integer.toHexString(cur.states2)); + } + } + if (cur.wakelockTag != null || cur.wakeReasonTag != null) { + int wakeLockIndex; + int wakeReasonIndex; + if (cur.wakelockTag != null) { + wakeLockIndex = writeHistoryTag(cur.wakelockTag); + if (DEBUG) { + Slog.i(TAG, "WRITE DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx + + " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string); + } + } else { + wakeLockIndex = 0xffff; + } + if (cur.wakeReasonTag != null) { + wakeReasonIndex = writeHistoryTag(cur.wakeReasonTag); + if (DEBUG) { + Slog.i(TAG, "WRITE DELTA: wakeReasonTag=#" + cur.wakeReasonTag.poolIdx + + " " + cur.wakeReasonTag.uid + ":" + cur.wakeReasonTag.string); + } + } else { + wakeReasonIndex = 0xffff; + } + dest.writeInt((wakeReasonIndex << 16) | wakeLockIndex); + if (cur.wakelockTag != null + && (wakeLockIndex & BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG) != 0) { + cur.wakelockTag.writeToParcel(dest, 0); + cur.tagsFirstOccurrence = true; + } + if (cur.wakeReasonTag != null + && (wakeReasonIndex & BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG) != 0) { + cur.wakeReasonTag.writeToParcel(dest, 0); + cur.tagsFirstOccurrence = true; + } + } + if (cur.eventCode != HistoryItem.EVENT_NONE) { + final int index = writeHistoryTag(cur.eventTag); + final int codeAndIndex = (cur.eventCode & 0xffff) | (index << 16); + dest.writeInt(codeAndIndex); + if ((index & BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG) != 0) { + cur.eventTag.writeToParcel(dest, 0); + cur.tagsFirstOccurrence = true; + } + if (DEBUG) { + Slog.i(TAG, "WRITE DELTA: event=" + cur.eventCode + " tag=#" + + cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":" + + cur.eventTag.string); + } + } + + cur.stepDetails = mStepDetailsCalculator.getHistoryStepDetails(); + if (includeStepDetails != 0) { + cur.stepDetails.writeToParcel(dest); + } + + if (batteryChargeChanged) { + if (DEBUG) Slog.i(TAG, "WRITE DELTA: batteryChargeUah=" + cur.batteryChargeUah); + dest.writeInt(cur.batteryChargeUah); + } + dest.writeDouble(cur.modemRailChargeMah); + dest.writeDouble(cur.wifiRailChargeMah); + } + + private int buildBatteryLevelInt(HistoryItem h) { + return ((((int) h.batteryLevel) << 25) & 0xfe000000) + | ((((int) h.batteryTemperature) << 15) & 0x01ff8000) + | ((((int) h.batteryVoltage) << 1) & 0x00007ffe); + } + + private int buildStateInt(HistoryItem h) { + int plugType = 0; + if ((h.batteryPlugType & BatteryManager.BATTERY_PLUGGED_AC) != 0) { + plugType = 1; + } else if ((h.batteryPlugType & BatteryManager.BATTERY_PLUGGED_USB) != 0) { + plugType = 2; + } else if ((h.batteryPlugType & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0) { + plugType = 3; + } + return ((h.batteryStatus & BatteryStatsHistory.STATE_BATTERY_STATUS_MASK) + << BatteryStatsHistory.STATE_BATTERY_STATUS_SHIFT) + | ((h.batteryHealth & BatteryStatsHistory.STATE_BATTERY_HEALTH_MASK) + << BatteryStatsHistory.STATE_BATTERY_HEALTH_SHIFT) + | ((plugType & BatteryStatsHistory.STATE_BATTERY_PLUG_MASK) + << BatteryStatsHistory.STATE_BATTERY_PLUG_SHIFT) + | (h.states & (~BatteryStatsHistory.STATE_BATTERY_MASK)); + } + + /** + * Returns the index for the specified tag. If this is the first time the tag is encountered + * while writing the current history buffer, the method returns + * <code>(index | TAG_FIRST_OCCURRENCE_FLAG)</code> + */ + private int writeHistoryTag(HistoryTag tag) { + if (tag.string == null) { + Slog.wtfStack(TAG, "writeHistoryTag called with null name"); + } + + final int stringLength = tag.string.length(); + if (stringLength > MAX_HISTORY_TAG_STRING_LENGTH) { + Slog.e(TAG, "Long battery history tag: " + tag.string); + tag.string = tag.string.substring(0, MAX_HISTORY_TAG_STRING_LENGTH); + } + + Integer idxObj = mHistoryTagPool.get(tag); + int idx; + if (idxObj != null) { + idx = idxObj; + if ((idx & BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG) != 0) { + mHistoryTagPool.put(tag, idx & ~BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG); + } + return idx; + } else if (mNextHistoryTagIdx < HISTORY_TAG_INDEX_LIMIT) { + idx = mNextHistoryTagIdx; + HistoryTag key = new HistoryTag(); + key.setTo(tag); + tag.poolIdx = idx; + mHistoryTagPool.put(key, idx); + mNextHistoryTagIdx++; + + mNumHistoryTagChars += stringLength + 1; + if (mHistoryTags != null) { + mHistoryTags.put(idx, key); + } + return idx | BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG; + } else { + // Tag pool overflow: include the tag itself in the parcel + return HISTORY_TAG_INDEX_LIMIT | BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG; + } + } + + /** + * Don't allow any more batching in to the current history event. + */ + public void commitCurrentHistoryBatchLocked() { + mHistoryLastWritten.cmd = HistoryItem.CMD_NULL; + } + + /** + * Saves the accumulated history buffer in the active file, see {@link #getActiveFile()} . + */ + public void writeHistory() { + if (mActiveFile == null) { + Slog.w(TAG, "writeHistory: no history file associated with this instance"); + return; + } + + Parcel p = Parcel.obtain(); + try { + final long start = SystemClock.uptimeMillis(); + writeHistoryBuffer(p); + if (DEBUG) { + Slog.d(TAG, "writeHistoryBuffer duration ms:" + + (SystemClock.uptimeMillis() - start) + " bytes:" + p.dataSize()); + } + writeParcelToFileLocked(p, mActiveFile); + } finally { + p.recycle(); + } + } + + /** + * Reads history buffer from a persisted Parcel. + */ + public void readHistoryBuffer(Parcel in) throws ParcelFormatException { + final int version = in.readInt(); + if (version != BatteryStatsHistory.VERSION) { + Slog.w("BatteryStats", "readHistoryBuffer: version got " + version + + ", expected " + BatteryStatsHistory.VERSION + "; erasing old stats"); + return; + } + + final long historyBaseTime = in.readLong(); + + mHistoryBuffer.setDataSize(0); + mHistoryBuffer.setDataPosition(0); + + int bufSize = in.readInt(); + int curPos = in.dataPosition(); + if (bufSize >= (mMaxHistoryBufferSize * 100)) { + throw new ParcelFormatException( + "File corrupt: history data buffer too large " + bufSize); + } else if ((bufSize & ~3) != bufSize) { + throw new ParcelFormatException( + "File corrupt: history data buffer not aligned " + bufSize); + } else { + if (DEBUG) { + Slog.i(TAG, "***************** READING NEW HISTORY: " + bufSize + + " bytes at " + curPos); + } + mHistoryBuffer.appendFrom(in, curPos, bufSize); + in.setDataPosition(curPos + bufSize); + } + + if (DEBUG) { + StringBuilder sb = new StringBuilder(128); + sb.append("****************** OLD mHistoryBaseTimeMs: "); + TimeUtils.formatDuration(mHistoryBaseTimeMs, sb); + Slog.i(TAG, sb.toString()); + } + mHistoryBaseTimeMs = historyBaseTime; + if (DEBUG) { + StringBuilder sb = new StringBuilder(128); + sb.append("****************** NEW mHistoryBaseTimeMs: "); + TimeUtils.formatDuration(mHistoryBaseTimeMs, sb); + Slog.i(TAG, sb.toString()); + } + + // We are just arbitrarily going to insert 1 minute from the sample of + // the last run until samples in this run. + if (mHistoryBaseTimeMs > 0) { + long oldnow = mClock.elapsedRealtime(); + mHistoryBaseTimeMs = mHistoryBaseTimeMs - oldnow + 1; + if (DEBUG) { + StringBuilder sb = new StringBuilder(128); + sb.append("****************** ADJUSTED mHistoryBaseTimeMs: "); + TimeUtils.formatDuration(mHistoryBaseTimeMs, sb); + Slog.i(TAG, sb.toString()); + } + } + } + + private void writeHistoryBuffer(Parcel out) { + if (DEBUG) { + StringBuilder sb = new StringBuilder(128); + sb.append("****************** WRITING mHistoryBaseTimeMs: "); + TimeUtils.formatDuration(mHistoryBaseTimeMs, sb); + sb.append(" mLastHistoryElapsedRealtimeMs: "); + TimeUtils.formatDuration(mLastHistoryElapsedRealtimeMs, sb); + Slog.i(TAG, sb.toString()); + } + out.writeInt(BatteryStatsHistory.VERSION); + out.writeLong(mHistoryBaseTimeMs + mLastHistoryElapsedRealtimeMs); + out.writeInt(mHistoryBuffer.dataSize()); + if (DEBUG) { + Slog.i(TAG, "***************** WRITING HISTORY: " + + mHistoryBuffer.dataSize() + " bytes at " + out.dataPosition()); + } + out.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize()); + } + + private void writeParcelToFileLocked(Parcel p, AtomicFile file) { + FileOutputStream fos = null; + mWriteLock.lock(); + try { + final long startTimeMs = SystemClock.uptimeMillis(); + fos = file.startWrite(); + fos.write(p.marshall()); + fos.flush(); + file.finishWrite(fos); + if (DEBUG) { + Slog.d(TAG, "writeParcelToFileLocked file:" + file.getBaseFile().getPath() + + " duration ms:" + (SystemClock.uptimeMillis() - startTimeMs) + + " bytes:" + p.dataSize()); + } + com.android.internal.logging.EventLogTags.writeCommitSysConfigFile( + "batterystats", SystemClock.uptimeMillis() - startTimeMs); + } catch (IOException e) { + Slog.w(TAG, "Error writing battery statistics", e); + file.failWrite(fos); + } finally { + mWriteLock.unlock(); + } + } + + /** + * Returns the total number of history tags in the tag pool. + */ + public int getHistoryStringPoolSize() { + return mHistoryTagPool.size(); + } + + /** + * Returns the total number of bytes occupied by the history tag pool. + */ + public int getHistoryStringPoolBytes() { + return mNumHistoryTagChars; + } + + /** + * Returns the string held by the requested history tag. + */ + public String getHistoryTagPoolString(int index) { + ensureHistoryTagArray(); + HistoryTag historyTag = mHistoryTags.get(index); + return historyTag != null ? historyTag.string : null; + } + + /** + * Returns the UID held by the requested history tag. + */ + public int getHistoryTagPoolUid(int index) { + ensureHistoryTagArray(); + HistoryTag historyTag = mHistoryTags.get(index); + return historyTag != null ? historyTag.uid : Process.INVALID_UID; + } + + private void ensureHistoryTagArray() { + if (mHistoryTags != null) { + return; + } + + mHistoryTags = new SparseArray<>(mHistoryTagPool.size()); + for (Map.Entry<HistoryTag, Integer> entry : mHistoryTagPool.entrySet()) { + mHistoryTags.put(entry.getValue() & ~BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG, + entry.getKey()); + } + } } diff --git a/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java index de8b414c4b78..1bf878cb9119 100644 --- a/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java +++ b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java @@ -36,7 +36,6 @@ public class BatteryStatsHistoryIterator { public BatteryStatsHistoryIterator(@NonNull BatteryStatsHistory history) { mBatteryStatsHistory = history; - mBatteryStatsHistory.startIteratingHistory(); } /** @@ -231,4 +230,11 @@ public class BatteryStatsHistoryIterator { out.batteryTemperature = (short) ((batteryLevelInt & 0x01ff8000) >>> 15); out.batteryVoltage = (char) ((batteryLevelInt & 0x00007ffe) >>> 1); } + + /** + * Should be called when iteration is complete. + */ + public void close() { + mBatteryStatsHistory.finishIteratingHistory(); + } } diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 4bc946e17d04..5498769fcf8f 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -80,6 +80,10 @@ cc_library_shared { "include", ], + defaults: [ + "latest_android_media_audio_common_types_cpp_target_shared", + ], + target: { android: { srcs: [ @@ -243,7 +247,6 @@ cc_library_shared { ], shared_libs: [ - "android.media.audio.common.types-V1-cpp", "audioclient-types-aidl-cpp", "audioflinger-aidl-cpp", "audiopolicy-types-aidl-cpp", diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp index 9cc72437a023..aece8c35a9e6 100644 --- a/core/jni/android_view_InputDevice.cpp +++ b/core/jni/android_view_InputDevice.cpp @@ -69,9 +69,9 @@ jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& devi static_cast<int32_t>(ident.product), descriptorObj.get(), deviceInfo.isExternal(), deviceInfo.getSources(), deviceInfo.getKeyboardType(), kcmObj.get(), - deviceInfo.hasVibrator(), hasMic, - deviceInfo.hasButtonUnderPad(), deviceInfo.hasSensor(), - deviceInfo.hasBattery())); + deviceInfo.getCountryCode(), deviceInfo.hasVibrator(), + hasMic, deviceInfo.hasButtonUnderPad(), + deviceInfo.hasSensor(), deviceInfo.hasBattery())); const std::vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges(); for (const InputDeviceInfo::MotionRange& range: ranges) { @@ -94,7 +94,7 @@ int register_android_view_InputDevice(JNIEnv* env) gInputDeviceClassInfo.ctor = GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz, "<init>", "(IIILjava/lang/String;IILjava/lang/" - "String;ZIILandroid/view/KeyCharacterMap;ZZZZZ)V"); + "String;ZIILandroid/view/KeyCharacterMap;IZZZZZ)V"); gInputDeviceClassInfo.addMotionRange = GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz, "addMotionRange", "(IIFFFFF)V"); diff --git a/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java b/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java index 3e1db364cd82..e13a3323d31a 100644 --- a/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java +++ b/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java @@ -23,7 +23,6 @@ import static com.google.common.truth.Truth.assertThat; import static junit.framework.TestCase.assertEquals; import static junit.framework.TestCase.assertNotNull; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; @@ -114,8 +113,8 @@ public class InputDeviceLightsManagerTest { return new InputDevice(id, 0 /* generation */, 0 /* controllerNumber */, "name", 0 /* vendorId */, 0 /* productId */, "descriptor", true /* isExternal */, 0 /* sources */, 0 /* keyboardType */, null /* keyCharacterMap */, - false /* hasVibrator */, false /* hasMicrophone */, false /* hasButtonUnderpad */, - false /* hasSensor */, false /* hasBattery */); + InputDeviceCountryCode.INVALID, false /* hasVibrator */, false /* hasMicrophone */, + false /* hasButtonUnderpad */, false /* hasSensor */, false /* hasBattery */); } private void mockLights(Light[] lights) throws Exception { diff --git a/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java b/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java index 341ee37aee39..54ee4349c3e1 100644 --- a/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java +++ b/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java @@ -148,8 +148,8 @@ public class InputDeviceSensorManagerTest { InputDevice d = new InputDevice(id, 0 /* generation */, 0 /* controllerNumber */, "name", 0 /* vendorId */, 0 /* productId */, "descriptor", true /* isExternal */, 0 /* sources */, 0 /* keyboardType */, null /* keyCharacterMap */, - false /* hasVibrator */, false /* hasMicrophone */, false /* hasButtonUnderpad */, - true /* hasSensor */, false /* hasBattery */); + InputDeviceCountryCode.INVALID, false /* hasVibrator */, false /* hasMicrophone */, + false /* hasButtonUnderpad */, true /* hasSensor */, false /* hasBattery */); assertTrue(d.hasSensor()); return d; } diff --git a/media/Android.bp b/media/Android.bp index ec243bf2370a..7118afad975a 100644 --- a/media/Android.bp +++ b/media/Android.bp @@ -35,8 +35,8 @@ aidl_interface { "aidl/android/media/soundtrigger_middleware/SoundTriggerModuleDescriptor.aidl", ], imports: [ - "android.media.audio.common.types-V1", - "android.media.soundtrigger.types-V1", + "android.media.audio.common.types", + "android.media.soundtrigger.types", "media_permission-aidl", ], } @@ -52,6 +52,7 @@ aidl_interface { ], local_include_dir: "aidl", srcs: [ + "aidl/android/media/audio/common/AudioAttributes.aidl", "aidl/android/media/audio/common/AudioChannelLayout.aidl", "aidl/android/media/audio/common/AudioConfig.aidl", "aidl/android/media/audio/common/AudioConfigBase.aidl", @@ -63,6 +64,7 @@ aidl_interface { "aidl/android/media/audio/common/AudioEncapsulationMetadataType.aidl", "aidl/android/media/audio/common/AudioEncapsulationMode.aidl", "aidl/android/media/audio/common/AudioEncapsulationType.aidl", + "aidl/android/media/audio/common/AudioFlag.aidl", "aidl/android/media/audio/common/AudioFormatDescription.aidl", "aidl/android/media/audio/common/AudioFormatType.aidl", "aidl/android/media/audio/common/AudioGain.aidl", @@ -122,8 +124,75 @@ aidl_interface { version: "1", imports: [], }, + // IMPORTANT: Update latest_android_media_audio_common_types every time + // you add the latest frozen version to versions_with_info + ], + +} + +// Note: This should always be one version ahead of the last frozen version +latest_android_media_audio_common_types = "android.media.audio.common.types-V2" + +// Modules that depend on android.media.audio.common.types directly can include +// the following cc_defaults to avoid explicitly managing dependency versions +// across many scattered files. +cc_defaults { + name: "latest_android_media_audio_common_types_cpp_shared", + shared_libs: [ + latest_android_media_audio_common_types + "-cpp", + ], +} + +cc_defaults { + name: "latest_android_media_audio_common_types_cpp_export_shared", + defaults: [ + "latest_android_media_audio_common_types_cpp_shared", ], + export_shared_lib_headers: [ + latest_android_media_audio_common_types + "-cpp", + ], +} + +cc_defaults { + name: "latest_android_media_audio_common_types_cpp_static", + static_libs: [ + latest_android_media_audio_common_types + "-cpp", + ], +} +cc_defaults { + name: "latest_android_media_audio_common_types_cpp_export_static", + defaults: [ + "latest_android_media_audio_common_types_cpp_static", + ], + export_static_lib_headers: [ + latest_android_media_audio_common_types + "-cpp", + ], +} + +cc_defaults { + name: "latest_android_media_audio_common_types_ndk_shared", + shared_libs: [ + latest_android_media_audio_common_types + "-ndk", + ], +} + +cc_defaults { + name: "latest_android_media_audio_common_types_ndk_static", + static_libs: [ + latest_android_media_audio_common_types + "-ndk", + ], +} + +cc_defaults { + name: "latest_android_media_audio_common_types_cpp_target_shared", + target: { + android: { + shared_libs: [ + latest_android_media_audio_common_types + "-cpp", + ], + }, + }, } aidl_interface { diff --git a/media/aidl/android/media/audio/common/AudioAttributes.aidl b/media/aidl/android/media/audio/common/AudioAttributes.aidl new file mode 100644 index 000000000000..eb29e10ab3a5 --- /dev/null +++ b/media/aidl/android/media/audio/common/AudioAttributes.aidl @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media.audio.common; + +import android.media.audio.common.AudioContentType; +import android.media.audio.common.AudioFlag; +import android.media.audio.common.AudioSource; +import android.media.audio.common.AudioUsage; + +/** + * AudioAttributes give information about an audio stream that is more + * descriptive than stream type alone. + */ +@JavaDerive(equals=true, toString=true) +@VintfStability +parcelable AudioAttributes { + /** + * Classifies the content of the audio signal using categories such as + * speech or music + */ + AudioContentType contentType = AudioContentType.UNKNOWN; + /** + * Classifies the intended use of the audio signal using categories such as + * alarm or ringtone + */ + AudioUsage usage = AudioUsage.UNKNOWN; + /** + * Classifies the audio source using categories such as voice uplink or + * remote submix + */ + AudioSource source = AudioSource.DEFAULT; + /** + * Bitmask describing how playback is to be affected. + */ + int flags = AudioFlag.NONE; + /** + * Tag is an additional use case qualifier complementing AudioUsage and + * AudioContentType. Tags are set by vendor-specific applications and must + * be prefixed by "VX_". Vendors must namespace their tag names using the + * name of their company to avoid conflicts. The namespace must use at least + * three characters, and must go directly after the "VX_" prefix. + * For example: "VX_MYCOMPANY_VR". + */ + @utf8InCpp String[] tags; +}
\ No newline at end of file diff --git a/media/aidl/android/media/audio/common/AudioFlag.aidl b/media/aidl/android/media/audio/common/AudioFlag.aidl new file mode 100644 index 000000000000..b9d493e620ab --- /dev/null +++ b/media/aidl/android/media/audio/common/AudioFlag.aidl @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media.audio.common; + +/** + * Defines the audio flags that are used in AudioAttributes + */ +@Backing(type="int") +@VintfStability +enum AudioFlag { + NONE = 0x0, + /** + * Flag defining a behavior where the audibility of the sound will be + * ensured by the system. To ensure sound audibility, the system only uses + * built-in speakers or wired headphones and specifically excludes wireless + * audio devices. Note this flag should only be used for sounds subject to + * regulatory behaviors in some countries, such as for camera shutter sound, + * and not for routing behaviors. + */ + AUDIBILITY_ENFORCED = 0x1 << 0, + /** + * Skipping 0x1 << 1. This was previously used for SECURE flag, but because + * the security feature was never implemented using this flag, and the flag + * was never made public, this value may be used for another flag. + */ + /** + * Flag to enable when the stream is associated with SCO usage. + * Internal use only for dealing with legacy STREAM_BLUETOOTH_SCO + */ + SCO = 0x1 << 2, + /** + * Flag defining a behavior where the system ensures that the playback of + * the sound will be compatible with its use as a broadcast for surrounding + * people and/or devices. Ensures audibility with no or minimal + * post-processing applied. + */ + BEACON = 0x1 << 3, + /** + * Flag requesting the use of an output stream supporting hardware A/V + * synchronization. + */ + HW_AV_SYNC = 0x1 << 4, + /** + * Flag requesting capture from the source used for hardware hotword + * detection. To be used with capture preset MediaRecorder.AudioSource + * HOTWORD or MediaRecorder.AudioSource.VOICE_RECOGNITION. + */ + HW_HOTWORD = 0x1 << 5, + /** + * Flag requesting audible playback even under limited interruptions. + */ + BYPASS_INTERRUPTION_POLICY = 0x1 << 6, + /** + * Flag requesting audible playback even when the underlying stream is muted + */ + BYPASS_MUTE = 0x1 << 7, + /** + * Flag requesting a low latency path when creating an AudioTrack. + * When using this flag, the sample rate must match the native sample rate + * of the device. Effects processing is also unavailable. + */ + LOW_LATENCY = 0x1 << 8, + /** + * Flag requesting a deep buffer path when creating an AudioTrack. + * + * A deep buffer path, if available, may consume less power and is + * suitable for media playback where latency is not a concern. + */ + DEEP_BUFFER = 0x1 << 9, + /** + * Flag specifying that the audio shall not be captured by third-party apps + * with a MediaProjection. + */ + NO_MEDIA_PROJECTION = 0x1 << 10, + /** + * Flag indicating force muting haptic channels. + */ + MUTE_HAPTIC = 0x1 << 11, + /** + * Flag specifying that the audio shall not be captured by any apps, not + * even system apps. + */ + NO_SYSTEM_CAPTURE = 0x1 << 12, + /** + * Flag requesting private audio capture. + */ + CAPTURE_PRIVATE = 0x1 << 13, + /** + * Flag indicating the audio content has been processed to provide a virtual + * multichannel audio experience. + */ + CONTENT_SPATIALIZED = 0x1 << 14, + /** + * Flag indicating the audio content is never to be spatialized. + */ + NEVER_SPATIALIZE = 0x1 << 15, + /** + * Flag indicating the audio is part of a call redirection. + * Valid for playback and capture. + */ + CALL_REDIRECTION = 0x1 << 16, +}
\ No newline at end of file diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioAttributes.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioAttributes.aidl new file mode 100644 index 000000000000..6d5e234af08e --- /dev/null +++ b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioAttributes.aidl @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.media.audio.common; +@JavaDerive(equals=true, toString=true) @VintfStability +parcelable AudioAttributes { + android.media.audio.common.AudioContentType contentType = android.media.audio.common.AudioContentType.UNKNOWN; + android.media.audio.common.AudioUsage usage = android.media.audio.common.AudioUsage.UNKNOWN; + android.media.audio.common.AudioSource source = android.media.audio.common.AudioSource.DEFAULT; + int flags = 0; + @utf8InCpp String[] tags; +} diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioFlag.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioFlag.aidl new file mode 100644 index 000000000000..3138531d6545 --- /dev/null +++ b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioFlag.aidl @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.media.audio.common; +@Backing(type="int") @VintfStability +enum AudioFlag { + NONE = 0, + AUDIBILITY_ENFORCED = 1, + SCO = 4, + BEACON = 8, + HW_AV_SYNC = 16, + HW_HOTWORD = 32, + BYPASS_INTERRUPTION_POLICY = 64, + BYPASS_MUTE = 128, + LOW_LATENCY = 256, + DEEP_BUFFER = 512, + NO_MEDIA_PROJECTION = 1024, + MUTE_HAPTIC = 2048, + NO_SYSTEM_CAPTURE = 4096, + CAPTURE_PRIVATE = 8192, + CONTENT_SPATIALIZED = 16384, + NEVER_SPATIALIZE = 32768, + CALL_REDIRECTION = 65536, +} diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 6922637350d9..2547a963eb31 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -2812,9 +2812,7 @@ public class AudioManager { } /** - * @param on set <var>true</var> to route A2DP audio to/from Bluetooth - * headset; <var>false</var> disable A2DP audio - * @deprecated Do not use. + * @deprecated Use {@link MediaRouter#selectRoute} instead. */ @Deprecated public void setBluetoothA2dpOn(boolean on){ } diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java index bb086d6839eb..dc093595b6a4 100644 --- a/media/java/android/media/SoundPool.java +++ b/media/java/android/media/SoundPool.java @@ -311,7 +311,7 @@ public class SoundPool extends PlayerBase { int priority, int loop, float rate) { // FIXME: b/174876164 implement device id for soundpool baseStart(0); - return _play(soundID, leftVolume, rightVolume, priority, loop, rate); + return _play(soundID, leftVolume, rightVolume, priority, loop, rate, getPlayerIId()); } /** @@ -512,7 +512,7 @@ public class SoundPool extends PlayerBase { @NonNull Object/*AudioAttributes*/ attributes, @NonNull String opPackageName); private native final int _play(int soundID, float leftVolume, float rightVolume, - int priority, int loop, float rate); + int priority, int loop, float rate, int playerIId); private native final void _setVolume(int streamID, float leftVolume, float rightVolume); diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java index bbb4d1fa76bc..b1c97300d08a 100644 --- a/media/java/android/media/tv/tuner/Tuner.java +++ b/media/java/android/media/tv/tuner/Tuner.java @@ -344,6 +344,16 @@ public class Tuner implements AutoCloseable { @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public Tuner(@NonNull Context context, @Nullable String tvInputSessionId, @TvInputService.PriorityHintUseCaseType int useCase) { + mContext = context; + mTunerResourceManager = mContext.getSystemService(TunerResourceManager.class); + + // The Tuner Resource Manager is only started when the device has the tuner feature. + if (mTunerResourceManager == null) { + throw new IllegalStateException( + "Tuner instance is created, but the device doesn't have tuner feature"); + } + + // This code will start tuner server if the device is running on the lazy tuner HAL. nativeSetup(); sTunerVersion = nativeGetTunerVersion(); if (sTunerVersion == TunerVersionChecker.TUNER_VERSION_UNKNOWN) { @@ -353,9 +363,6 @@ public class Tuner implements AutoCloseable { + TunerVersionChecker.getMajorVersion(sTunerVersion) + "." + TunerVersionChecker.getMinorVersion(sTunerVersion) + "."); } - mContext = context; - mTunerResourceManager = (TunerResourceManager) - context.getSystemService(Context.TV_TUNER_RESOURCE_MGR_SERVICE); if (mHandler == null) { mHandler = createEventHandler(); } diff --git a/media/jni/Android.bp b/media/jni/Android.bp index e3e200fcd754..96a3781af3a8 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -160,7 +160,7 @@ cc_library_shared { cc_library_shared { name: "libmedia_tv_tuner", - + min_sdk_version: "", srcs: [ "android_media_tv_Tuner.cpp", "tuner/DemuxClient.cpp", diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp index 397c70485d5b..244730b76df2 100644 --- a/media/jni/android_media_tv_Tuner.cpp +++ b/media/jni/android_media_tv_Tuner.cpp @@ -1238,7 +1238,8 @@ FrontendClientCallbackImpl::~FrontendClientCallbackImpl() { } /////////////// Tuner /////////////////////// -sp<TunerClient> JTuner::mTunerClient; +sp<TunerClient> JTuner::sTunerClient = nullptr; +std::mutex JTuner::sTunerClientMutex; JTuner::JTuner(JNIEnv *env, jobject thiz) : mClass(nullptr) { jclass clazz = env->GetObjectClass(thiz); @@ -1246,10 +1247,15 @@ JTuner::JTuner(JNIEnv *env, jobject thiz) : mClass(nullptr) { mClass = (jclass)env->NewGlobalRef(clazz); mObject = env->NewWeakGlobalRef(thiz); - if (mTunerClient == nullptr) { - mTunerClient = new TunerClient(); + { + std::scoped_lock<std::mutex> lock(sTunerClientMutex); + if (sTunerClient == nullptr) { + sTunerClient = new TunerClient(); + } else { + sTunerClient->incStrong(this); + } + ALOGV("JTuner refs count: %d", sTunerClient->getStrongCount()); } - mSharedFeId = (int)Constant::INVALID_FRONTEND_ID; } @@ -1271,18 +1277,28 @@ JTuner::~JTuner() { mFeClient = nullptr; mFeClientCb = nullptr; mDemuxClient = nullptr; + { + std::scoped_lock<std::mutex> lock(sTunerClientMutex); + int32_t refCnt = sTunerClient->getStrongCount(); + ALOGV("~JTuner refs count: %d", refCnt); + if (refCnt == 1) { + sTunerClient = nullptr; + } else { + sTunerClient->decStrong(this); + } + } mClass = nullptr; mObject = nullptr; } jint JTuner::getTunerVersion() { ALOGV("JTuner::getTunerVersion()"); - return (jint)mTunerClient->getHalTunerVersion(); + return (jint)sTunerClient->getHalTunerVersion(); } jobject JTuner::getFrontendIds() { ALOGV("JTuner::getFrontendIds()"); - vector<int32_t> ids = mTunerClient->getFrontendIds(); + vector<int32_t> ids = sTunerClient->getFrontendIds(); if (ids.size() == 0) { ALOGW("Frontend isn't available"); return nullptr; @@ -1305,7 +1321,7 @@ jobject JTuner::getFrontendIds() { jobject JTuner::openFrontendByHandle(int feHandle) { // TODO: Handle reopening frontend with different handle - sp<FrontendClient> feClient = mTunerClient->openFrontend(feHandle); + sp<FrontendClient> feClient = sTunerClient->openFrontend(feHandle); if (feClient == nullptr) { ALOGE("Failed to open frontend"); return nullptr; @@ -1511,7 +1527,7 @@ jobject JTuner::getDtmbFrontendCaps(JNIEnv *env, FrontendCapabilities &caps) { jobject JTuner::getFrontendInfo(int id) { shared_ptr<FrontendInfo> feInfo; - feInfo = mTunerClient->getFrontendInfo(id); + feInfo = sTunerClient->getFrontendInfo(id); if (feInfo == nullptr) { return nullptr; } @@ -1605,21 +1621,21 @@ Result JTuner::getFrontendHardwareInfo(string &info) { } jint JTuner::setMaxNumberOfFrontends(int32_t type, int32_t maxNumber) { - if (mTunerClient == nullptr) { + if (sTunerClient == nullptr) { ALOGE("tuner is not initialized"); return (jint)Result::INVALID_STATE; } - return (jint)mTunerClient->setMaxNumberOfFrontends(static_cast<FrontendType>(type), maxNumber); + return (jint)sTunerClient->setMaxNumberOfFrontends(static_cast<FrontendType>(type), maxNumber); } int32_t JTuner::getMaxNumberOfFrontends(int32_t type) { - if (mTunerClient == nullptr) { + if (sTunerClient == nullptr) { ALOGE("tuner is not initialized"); return -1; } - return mTunerClient->getMaxNumberOfFrontends(static_cast<FrontendType>(type)); + return sTunerClient->getMaxNumberOfFrontends(static_cast<FrontendType>(type)); } jint JTuner::removeOutputPid(int32_t pid) { @@ -1662,13 +1678,13 @@ jobjectArray JTuner::getFrontendStatusReadiness(jintArray types) { } jobject JTuner::openLnbByHandle(int handle) { - if (mTunerClient == nullptr) { + if (sTunerClient == nullptr) { return nullptr; } sp<LnbClient> lnbClient; sp<LnbClientCallbackImpl> callback = new LnbClientCallbackImpl(); - lnbClient = mTunerClient->openLnb(handle); + lnbClient = sTunerClient->openLnb(handle); if (lnbClient == nullptr) { ALOGD("Failed to open lnb, handle = %d", handle); return nullptr; @@ -1692,7 +1708,7 @@ jobject JTuner::openLnbByHandle(int handle) { } jobject JTuner::openLnbByName(jstring name) { - if (mTunerClient == nullptr) { + if (sTunerClient == nullptr) { return nullptr; } @@ -1700,7 +1716,7 @@ jobject JTuner::openLnbByName(jstring name) { std::string lnbName(env->GetStringUTFChars(name, nullptr)); sp<LnbClient> lnbClient; sp<LnbClientCallbackImpl> callback = new LnbClientCallbackImpl(); - lnbClient = mTunerClient->openLnbByName(lnbName); + lnbClient = sTunerClient->openLnbByName(lnbName); if (lnbClient == nullptr) { ALOGD("Failed to open lnb by name, name = %s", lnbName.c_str()); return nullptr; @@ -1770,20 +1786,20 @@ int JTuner::setLnb(sp<LnbClient> lnbClient) { } int JTuner::setLna(bool enable) { - if (mTunerClient == nullptr) { + if (sTunerClient == nullptr) { return (int)Result::NOT_INITIALIZED; } - Result result = mTunerClient->setLna(enable); + Result result = sTunerClient->setLna(enable); return (int)result; } Result JTuner::openDemux(int handle) { - if (mTunerClient == nullptr) { + if (sTunerClient == nullptr) { return Result::NOT_INITIALIZED; } if (mDemuxClient == nullptr) { - mDemuxClient = mTunerClient->openDemux(handle); + mDemuxClient = sTunerClient->openDemux(handle); if (mDemuxClient == nullptr) { ALOGE("Failed to open demux"); return Result::UNKNOWN_ERROR; @@ -1881,10 +1897,10 @@ int JTuner::unlinkCiCam(int id) { jobject JTuner::openDescrambler() { ALOGV("JTuner::openDescrambler"); - if (mTunerClient == nullptr || mDemuxClient == nullptr) { + if (sTunerClient == nullptr || mDemuxClient == nullptr) { return nullptr; } - sp<DescramblerClient> descramblerClient = mTunerClient->openDescrambler(0/*unused*/); + sp<DescramblerClient> descramblerClient = sTunerClient->openDescrambler(0 /*unused*/); if (descramblerClient == nullptr) { ALOGD("Failed to open descrambler"); @@ -1995,12 +2011,12 @@ jobject JTuner::openDvr(DvrType type, jlong bufferSize) { } jobject JTuner::getDemuxCaps() { - if (mTunerClient == nullptr) { + if (sTunerClient == nullptr) { return nullptr; } shared_ptr<DemuxCapabilities> caps; - caps = mTunerClient->getDemuxCaps(); + caps = sTunerClient->getDemuxCaps(); if (caps == nullptr) { return nullptr; } diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h index 03e7fa91653d..c74b2df6c178 100644 --- a/media/jni/android_media_tv_Tuner.h +++ b/media/jni/android_media_tv_Tuner.h @@ -216,7 +216,8 @@ protected: private: jclass mClass; jweak mObject; - static sp<TunerClient> mTunerClient; + static sp<TunerClient> sTunerClient; + static std::mutex sTunerClientMutex; sp<FrontendClient> mFeClient; sp<FrontendClientCallbackImpl> mFeClientCb; int mFeId; diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp index a2826cb58ccf..9f32a83ad5be 100644 --- a/media/jni/soundpool/SoundPool.cpp +++ b/media/jni/soundpool/SoundPool.cpp @@ -115,7 +115,7 @@ bool SoundPool::unload(int32_t soundID) } int32_t SoundPool::play(int32_t soundID, float leftVolume, float rightVolume, - int32_t priority, int32_t loop, float rate) + int32_t priority, int32_t loop, float rate, int32_t playerIId) { ALOGV("%s(soundID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f)", __func__, soundID, leftVolume, rightVolume, priority, loop, rate); @@ -136,8 +136,9 @@ int32_t SoundPool::play(int32_t soundID, float leftVolume, float rightVolume, } const int32_t streamID = mStreamManager.queueForPlay( - sound, soundID, leftVolume, rightVolume, priority, loop, rate); + sound, soundID, leftVolume, rightVolume, priority, loop, rate, playerIId); ALOGV("%s returned %d", __func__, streamID); + return streamID; } diff --git a/media/jni/soundpool/SoundPool.h b/media/jni/soundpool/SoundPool.h index 6bb971b07e43..efc358ddf3b2 100644 --- a/media/jni/soundpool/SoundPool.h +++ b/media/jni/soundpool/SoundPool.h @@ -39,7 +39,7 @@ public: int32_t load(int fd, int64_t offset, int64_t length, int32_t priority); bool unload(int32_t soundID); int32_t play(int32_t soundID, float leftVolume, float rightVolume, int32_t priority, - int32_t loop, float rate); + int32_t loop, float rate, int32_t playerIId = PLAYER_PIID_INVALID); void pause(int32_t streamID); void autoPause(); void resume(int32_t streamID); diff --git a/media/jni/soundpool/Stream.cpp b/media/jni/soundpool/Stream.cpp index 9ed8770a455c..4194a22bfb67 100644 --- a/media/jni/soundpool/Stream.cpp +++ b/media/jni/soundpool/Stream.cpp @@ -229,7 +229,7 @@ Stream* Stream::getPairStream() const return mStreamManager->getPairStream(this); } -Stream* Stream::playPairStream(std::vector<std::any>& garbage) { +Stream* Stream::playPairStream(std::vector<std::any>& garbage, int32_t playerIId) { Stream* pairStream = getPairStream(); LOG_ALWAYS_FATAL_IF(pairStream == nullptr, "No pair stream!"); { @@ -260,7 +260,7 @@ Stream* Stream::playPairStream(std::vector<std::any>& garbage) { const int pairState = pairStream->mState; pairStream->play_l(pairStream->mSound, pairStream->mStreamID, pairStream->mLeftVolume, pairStream->mRightVolume, pairStream->mPriority, - pairStream->mLoop, pairStream->mRate, garbage); + pairStream->mLoop, pairStream->mRate, garbage, playerIId); if (pairStream->mState == IDLE) { return nullptr; // AudioTrack error } @@ -274,12 +274,12 @@ Stream* Stream::playPairStream(std::vector<std::any>& garbage) { void Stream::play_l(const std::shared_ptr<Sound>& sound, int32_t nextStreamID, float leftVolume, float rightVolume, int32_t priority, int32_t loop, float rate, - std::vector<std::any>& garbage) + std::vector<std::any>& garbage, int32_t playerIId) { ALOGV("%s(%p)(soundID=%d, streamID=%d, leftVolume=%f, rightVolume=%f," - " priority=%d, loop=%d, rate=%f)", + " priority=%d, loop=%d, rate=%f, playerIId=%d)", __func__, this, sound->getSoundID(), nextStreamID, leftVolume, rightVolume, - priority, loop, rate); + priority, loop, rate, playerIId); // initialize track const audio_stream_type_t streamType = @@ -340,6 +340,10 @@ void Stream::play_l(const std::shared_ptr<Sound>& sound, int32_t nextStreamID, // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_SOUNDPOOL mAudioTrack->setCallerName("soundpool"); + if (playerIId != PLAYER_PIID_INVALID) { + mAudioTrack->setPlayerIId(playerIId); + } + if (status_t status = mAudioTrack->initCheck(); status != NO_ERROR) { ALOGE("%s: error %d creating AudioTrack", __func__, status); @@ -379,6 +383,7 @@ int Stream::getCorrespondingStreamID() { std::lock_guard lock(mLock); return static_cast<int>(mAudioTrack ? mStreamID : getPairStream()->mStreamID); } + size_t Stream::StreamCallback::onMoreData(const AudioTrack::Buffer&) { ALOGW("%s streamID %d Unexpected EVENT_MORE_DATA for static track", __func__, mStream->getCorrespondingStreamID()); diff --git a/media/jni/soundpool/Stream.h b/media/jni/soundpool/Stream.h index 0054eeca529a..6c9ef2e087f8 100644 --- a/media/jni/soundpool/Stream.h +++ b/media/jni/soundpool/Stream.h @@ -93,7 +93,8 @@ public: // returns the pair stream if successful, nullptr otherwise. // garbage is used to release tracks and data outside of any lock. - Stream* playPairStream(std::vector<std::any>& garbage); + Stream* playPairStream(std::vector<std::any>& garbage, + int32_t playerIId = PLAYER_PIID_INVALID); // These parameters are explicitly checked in the SoundPool class // so never deviate from the Java API specified values. @@ -157,7 +158,7 @@ private: // garbage is used to release tracks and data outside of any lock. void play_l(const std::shared_ptr<Sound>& sound, int streamID, float leftVolume, float rightVolume, int priority, int loop, float rate, - std::vector<std::any>& garbage) REQUIRES(mLock); + std::vector<std::any>& garbage, int playerIId) REQUIRES(mLock); void stop_l() REQUIRES(mLock); void setVolume_l(float leftVolume, float rightVolume) REQUIRES(mLock); diff --git a/media/jni/soundpool/StreamManager.cpp b/media/jni/soundpool/StreamManager.cpp index 487a696d8765..acd4badad9b0 100644 --- a/media/jni/soundpool/StreamManager.cpp +++ b/media/jni/soundpool/StreamManager.cpp @@ -151,10 +151,13 @@ StreamManager::~StreamManager() int32_t StreamManager::queueForPlay(const std::shared_ptr<Sound> &sound, int32_t soundID, float leftVolume, float rightVolume, - int32_t priority, int32_t loop, float rate) + int32_t priority, int32_t loop, float rate, int32_t playerIId) { - ALOGV("%s(sound=%p, soundID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f)", - __func__, sound.get(), soundID, leftVolume, rightVolume, priority, loop, rate); + ALOGV( + "%s(sound=%p, soundID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f," + " playerIId=%d)", __func__, sound.get(), soundID, leftVolume, rightVolume, priority, + loop, rate, playerIId); + bool launchThread = false; int32_t streamID = 0; std::vector<std::any> garbage; @@ -244,7 +247,7 @@ int32_t StreamManager::queueForPlay(const std::shared_ptr<Sound> &sound, removeFromQueues_l(newStream); mProcessingStreams.emplace(newStream); lock.unlock(); - if (Stream* nextStream = newStream->playPairStream(garbage)) { + if (Stream* nextStream = newStream->playPairStream(garbage, playerIId)) { lock.lock(); ALOGV("%s: starting streamID:%d", __func__, nextStream->getStreamID()); addToActiveQueue_l(nextStream); diff --git a/media/jni/soundpool/StreamManager.h b/media/jni/soundpool/StreamManager.h index ec65b0c49dc4..adbab4b0f9d9 100644 --- a/media/jni/soundpool/StreamManager.h +++ b/media/jni/soundpool/StreamManager.h @@ -394,7 +394,7 @@ public: // Returns positive streamID on success, 0 on failure. This is locked. int32_t queueForPlay(const std::shared_ptr<Sound> &sound, int32_t soundID, float leftVolume, float rightVolume, - int32_t priority, int32_t loop, float rate) + int32_t priority, int32_t loop, float rate, int32_t playerIId) NO_THREAD_SAFETY_ANALYSIS; // uses unique_lock /////////////////////////////////////////////////////////////////////// diff --git a/media/jni/soundpool/android_media_SoundPool.cpp b/media/jni/soundpool/android_media_SoundPool.cpp index 5264772be7c3..25040a942061 100644 --- a/media/jni/soundpool/android_media_SoundPool.cpp +++ b/media/jni/soundpool/android_media_SoundPool.cpp @@ -364,12 +364,19 @@ android_media_SoundPool_unload(JNIEnv *env, jobject thiz, jint sampleID) { static jint android_media_SoundPool_play(JNIEnv *env, jobject thiz, jint sampleID, jfloat leftVolume, jfloat rightVolume, jint priority, jint loop, - jfloat rate) + jfloat rate, jint playerIId) { ALOGV("android_media_SoundPool_play\n"); auto soundPool = getSoundPool(env, thiz); if (soundPool == nullptr) return 0; - return (jint) soundPool->play(sampleID, leftVolume, rightVolume, priority, loop, rate); + + return (jint) soundPool->play(sampleID, + leftVolume, + rightVolume, + priority, + loop, + rate, + playerIId); } static void @@ -563,7 +570,7 @@ static JNINativeMethod gMethods[] = { (void *)android_media_SoundPool_unload }, { "_play", - "(IFFIIF)I", + "(IFFIIFI)I", (void *)android_media_SoundPool_play }, { "pause", diff --git a/media/jni/tuner/TunerClient.cpp b/media/jni/tuner/TunerClient.cpp index 3c8fdfe682af..8515874c022f 100644 --- a/media/jni/tuner/TunerClient.cpp +++ b/media/jni/tuner/TunerClient.cpp @@ -27,16 +27,13 @@ using ::aidl::android::hardware::tv::tuner::FrontendType; namespace android { -shared_ptr<ITunerService> TunerClient::mTunerService; int32_t TunerClient::mTunerVersion; /////////////// TunerClient /////////////////////// TunerClient::TunerClient() { - if (mTunerService == nullptr) { - ::ndk::SpAIBinder binder(AServiceManager_getService("media.tuner")); - mTunerService = ITunerService::fromBinder(binder); - } + ::ndk::SpAIBinder binder(AServiceManager_waitForService("media.tuner")); + mTunerService = ITunerService::fromBinder(binder); if (mTunerService == nullptr) { ALOGE("Failed to get tuner service"); } else { diff --git a/media/jni/tuner/TunerClient.h b/media/jni/tuner/TunerClient.h index a9f37e6df3aa..5410c1b185f5 100644 --- a/media/jni/tuner/TunerClient.h +++ b/media/jni/tuner/TunerClient.h @@ -150,10 +150,11 @@ public: private: /** - * An AIDL Tuner Service Singleton assigned at the first time the Tuner Client - * connects with the Tuner Service. Default null when the service does not exist. + * An AIDL Tuner Service assigned at the first time the Tuner Client connects with + * the Tuner Service. null when the service does not exist. The tuner client in JNI + * will be singleton, so this Tuner Service client will be singleton too. */ - static shared_ptr<ITunerService> mTunerService; + shared_ptr<ITunerService> mTunerService; // An integer that carries the Tuner version. The high 16 bits are the major version number // while the low 16 bits are the minor version. Default value is unknown version 0. diff --git a/packages/SettingsLib/Spa/gallery/AndroidManifest.xml b/packages/SettingsLib/Spa/gallery/AndroidManifest.xml index b5be7cd45688..22299861e0e3 100644 --- a/packages/SettingsLib/Spa/gallery/AndroidManifest.xml +++ b/packages/SettingsLib/Spa/gallery/AndroidManifest.xml @@ -22,7 +22,7 @@ android:label="@string/app_label" android:supportsRtl="true"> <activity - android:name="com.android.settingslib.spa.gallery.MainActivity" + android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/SpaActivity.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/SpaActivity.kt index 51d3714ce5ee..12be0702b3ee 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/SpaActivity.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/SpaActivity.kt @@ -36,24 +36,28 @@ open class SpaActivity( override fun onCreate(savedInstanceState: Bundle?) { setTheme(R.style.Theme_SpaLib_DayNight) super.onCreate(savedInstanceState) + setContent { - MainContent() + SettingsTheme { + MainContent() + } } } @Composable private fun MainContent() { - SettingsTheme { - val navController = rememberNavController() - CompositionLocalProvider(navController.localNavController()) { - NavHost(navController, settingsPageRepository.startDestination) { - for (page in settingsPageRepository.allPages) { - composable( - route = page.route, - arguments = page.arguments, - ) { navBackStackEntry -> - page.Page(navBackStackEntry.arguments) - } + val startDestination = + intent?.getStringExtra(KEY_START_DESTINATION) ?: settingsPageRepository.startDestination + + val navController = rememberNavController() + CompositionLocalProvider(navController.localNavController()) { + NavHost(navController, startDestination) { + for (page in settingsPageRepository.allPages) { + composable( + route = page.route, + arguments = page.arguments, + ) { navBackStackEntry -> + page.Page(navBackStackEntry.arguments) } } } @@ -62,4 +66,8 @@ open class SpaActivity( private val SettingsPageProvider.route: String get() = name + arguments.joinToString("") { argument -> "/{${argument.name}}" } + + companion object { + const val KEY_START_DESTINATION = "spa:SpaActivity:startDestination" + } } diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING index 26feaf979b20..234ef241f538 100644 --- a/packages/SystemUI/TEST_MAPPING +++ b/packages/SystemUI/TEST_MAPPING @@ -52,17 +52,6 @@ ] }, { - "name": "SystemUIGoogleScreenshotTests", - "options": [ - { - "exclude-annotation": "org.junit.Ignore" - }, - { - "exclude-annotation": "androidx.test.filters.FlakyTest" - } - ] - }, - { // Permission indicators "name": "CtsPermission4TestCases", "options": [ diff --git a/packages/SystemUI/res/raw/fingerprint_dialogue_error_to_success_lottie.json b/packages/SystemUI/res/raw/fingerprint_dialogue_error_to_success_lottie.json new file mode 100644 index 000000000000..c5ed827de0d1 --- /dev/null +++ b/packages/SystemUI/res/raw/fingerprint_dialogue_error_to_success_lottie.json @@ -0,0 +1 @@ +{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":80,"h":80,"nm":"RearFPS_error_to_success","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".green200","cl":"green200","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[28,47,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-10.556,-9.889],[7.444,6.555],[34.597,-20.486]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.658823529412,0.854901960784,0.709803921569,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":10,"s":[0]},{"t":20,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":10,"op":910,"st":10,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".red200","cl":"red200","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[39.95,40,0],"ix":2,"l":2},"a":{"a":0,"k":[30,30,0],"ix":1,"l":2},"s":{"a":0,"k":[120,120,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1.721,-7.982],[1.721,-7.982],[1.721,7.5],[-1.721,7.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.949019607843,0.721568627451,0.709803921569,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[30.002,32.488],"ix":2},"a":{"a":0,"k":[0.002,7.488],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.659,0.6],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":0,"s":[100,100]},{"i":{"x":[0.6,0.92],"y":[1,1.096]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":4,"s":[100,110]},{"t":10,"s":[100,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Top!","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1.681,-1.25],[1.681,-1.25],[1.681,2.213],[-1.681,2.213]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.949019607843,0.721568627451,0.709803921569,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[30,38.75],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.6,0.6],"y":[1,1]},"o":{"x":[0.853,0.853],"y":[0,0]},"t":0,"s":[100,100]},{"i":{"x":[0.92,0.92],"y":[1.06,1.06]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":4,"s":[110,110]},{"t":10,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Bottom!","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":86,"st":-30,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green200","cl":"green200","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[0]},{"t":15,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,40,0],"ix":2,"l":2},"a":{"a":0,"k":[40.25,40.25,0],"ix":1,"l":2},"s":{"a":0,"k":[93.5,93.5,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.12,0],[0,-22.08],[-22.08,0],[0,22.08]],"o":[[-22.08,0],[0,22.08],[22.12,0],[0,-22.08]],"v":[[-0.04,-40],[-40,0],[-0.04,40],[40,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[40.25,40.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.658823529412,0.854901960784,0.709803921569,1],"ix":3},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[0]},{"t":15,"s":[100]}],"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":10,"s":[0]},{"t":20,"s":[4]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":10,"op":21,"st":10,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".red200","cl":"red200","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":5,"s":[100]},{"t":10,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,40,0],"ix":2,"l":2},"a":{"a":0,"k":[40.25,40.25,0],"ix":1,"l":2},"s":{"a":0,"k":[93.5,93.5,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.12,0],[0,-22.08],[-22.08,0],[0,22.08]],"o":[[-22.08,0],[0,22.08],[22.12,0],[0,-22.08]],"v":[[-0.04,-40],[-40,0],[-0.04,40],[40,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[40.25,40.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":5,"s":[100]},{"t":10,"s":[0]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.949019607843,0.721568627451,0.709803921569,1],"ix":3},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":5,"s":[100]},{"t":10,"s":[0]}],"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[4]},{"t":10,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":0,"op":10,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file diff --git a/packages/SystemUI/res/raw/fingerprint_dialogue_fingerprint_to_success_lottie.json b/packages/SystemUI/res/raw/fingerprint_dialogue_fingerprint_to_success_lottie.json new file mode 100644 index 000000000000..3eb95ef1a718 --- /dev/null +++ b/packages/SystemUI/res/raw/fingerprint_dialogue_fingerprint_to_success_lottie.json @@ -0,0 +1 @@ +{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":80,"h":80,"nm":"RearFPS_fingerprint_to_success","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".green200","cl":"green200","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[28,47,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-10.556,-9.889],[7.444,6.555],[34.597,-20.486]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.658823529412,0.854901960784,0.709803921569,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":10,"s":[0]},{"t":20,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":10,"op":910,"st":10,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".green200","cl":"green200","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[0]},{"t":15,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,40,0],"ix":2,"l":2},"a":{"a":0,"k":[40.25,40.25,0],"ix":1,"l":2},"s":{"a":0,"k":[93.5,93.5,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.12,0],[0,-22.08],[-22.08,0],[0,22.08]],"o":[[-22.08,0],[0,22.08],[22.12,0],[0,-22.08]],"v":[[-0.04,-40],[-40,0],[-0.04,40],[40,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[40.25,40.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.658823529412,0.854901960784,0.709803921569,1],"ix":3},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[0]},{"t":15,"s":[100]}],"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":10,"s":[0]},{"t":20,"s":[4]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":10,"op":21,"st":10,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".colorAccentPrimary","cl":"colorAccentPrimary","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[100]},{"t":10,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40.091,40,0],"ix":2,"l":2},"a":{"a":0,"k":[19.341,24.25,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.701,0.42],[-1.757,0],[-1.577,-0.381],[-1.485,-0.816]],"o":[[1.455,-0.799],[1.608,-0.397],[1.719,0],[1.739,0.42],[0,0]],"v":[[-9.818,1.227],[-5.064,-0.618],[0,-1.227],[4.96,-0.643],[9.818,1.227]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.827450980392,0.890196078431,0.992156862745,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,7.477],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Top","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-2.446,1.161],[-1.168,0.275],[-1.439,0],[-1.301,-0.304],[-1.225,-0.66],[-1.11,-1.844]],"o":[[1.23,-2.044],[1.024,-0.486],[1.312,-0.31],[1.425,0],[1.454,0.34],[2.122,1.143],[0,0]],"v":[[-13.091,3.273],[-7.438,-1.646],[-4.14,-2.797],[0,-3.273],[4.104,-2.805],[8.141,-1.29],[13.091,3.273]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.827450980392,0.890196078431,0.992156862745,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,16.069],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Mid Top","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-6.53,0],[0,-5.793],[0,0],[2.159,0],[0.59,1.489],[0,0],[1.587,0],[0,-2.16],[-0.81,-1.363],[-0.844,-0.674],[0,0]],"o":[[-0.753,-2.095],[0,-5.793],[6.529,0],[0,0],[0,2.16],[-1.604,0],[0,0],[-0.589,-1.489],[-2.161,0],[0,1.62],[0.54,0.909],[0,0],[0,0]],"v":[[-10.702,5.728],[-11.454,1.506],[0.001,-9],[11.454,1.506],[11.454,1.817],[7.544,5.728],[3.926,3.273],[2.618,0],[-0.997,-2.454],[-4.91,1.457],[-3.657,6.014],[-1.57,8.412],[-0.818,9]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.827450980392,0.890196078431,0.992156862745,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,28.341],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Inside to dot ","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.307,-0.561],[0.894,-0.16],[0.706,0],[0.844,0.193],[0.728,0.334],[0.967,0.901]],"o":[[-1.038,0.967],[-0.817,0.351],[-0.673,0.12],[-0.9,0],[-0.794,-0.182],[-1.203,-0.551],[0,0]],"v":[[8.182,-0.386],[4.642,1.931],[2.07,2.703],[-0.001,2.886],[-2.621,2.591],[-4.909,1.813],[-8.182,-0.386]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.827450980392,0.890196078431,0.992156862745,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,40.614],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Bottom","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".grey700","cl":"grey700","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,40,0],"ix":2,"l":2},"a":{"a":0,"k":[40.25,40.25,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.12,0],[0,-22.08],[-22.08,0],[0,22.08]],"o":[[-22.08,0],[0,22.08],[22.12,0],[0,-22.08]],"v":[[-0.04,-40],[-40,0],[-0.04,40],[40,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.278431385756,0.278431385756,0.278431385756,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[100]},{"t":20,"s":[0]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[40.25,40.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt index d718a240bbfd..6c452bd97ff6 100644 --- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt +++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt @@ -45,7 +45,7 @@ class KeyguardUpdateMonitorLogger @Inject constructor( fun e(@CompileTimeConstant msg: String) = log(msg, ERROR) - fun v(@CompileTimeConstant msg: String) = log(msg, ERROR) + fun v(@CompileTimeConstant msg: String) = log(msg, VERBOSE) fun w(@CompileTimeConstant msg: String) = log(msg, WARNING) diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardViewMediatorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardViewMediatorLogger.kt new file mode 100644 index 000000000000..f54bf026a686 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardViewMediatorLogger.kt @@ -0,0 +1,690 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.keyguard.logging + +import android.os.RemoteException +import android.view.WindowManagerPolicyConstants +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.log.LogBuffer +import com.android.systemui.log.LogLevel.DEBUG +import com.android.systemui.log.LogLevel.ERROR +import com.android.systemui.log.LogLevel.INFO +import com.android.systemui.log.LogLevel.WARNING +import com.android.systemui.log.LogLevel.WTF +import com.android.systemui.log.dagger.KeyguardViewMediatorLog +import javax.inject.Inject + +private const val TAG = "KeyguardViewMediatorLog" + +@SysUISingleton +class KeyguardViewMediatorLogger @Inject constructor( + @KeyguardViewMediatorLog private val logBuffer: LogBuffer, +) { + + fun logFailedLoadLockSound(soundPath: String) { + logBuffer.log( + TAG, + WARNING, + { str1 = soundPath }, + { "failed to load lock sound from $str1" } + ) + } + + fun logFailedLoadUnlockSound(soundPath: String) { + logBuffer.log( + TAG, + WARNING, + { str1 = soundPath }, + { "failed to load unlock sound from $str1" } + ) + } + + fun logFailedLoadTrustedSound(soundPath: String) { + logBuffer.log( + TAG, + WARNING, + { str1 = soundPath }, + { "failed to load trusted sound from $str1" } + ) + } + + fun logOnSystemReady() { + logBuffer.log(TAG, DEBUG, "onSystemReady") + } + + fun logOnStartedGoingToSleep(offReason: Int) { + val offReasonString = WindowManagerPolicyConstants.offReasonToString(offReason) + logBuffer.log( + TAG, + DEBUG, + { str1 = offReasonString }, + { "onStartedGoingToSleep($str1)" } + ) + } + + fun logPendingExitSecureCallbackCancelled() { + logBuffer.log(TAG, DEBUG, "pending exit secure callback cancelled") + } + + fun logFailedOnKeyguardExitResultFalse(remoteException: RemoteException) { + logBuffer.log( + TAG, + WARNING, + "Failed to call onKeyguardExitResult(false)", + remoteException + ) + } + + fun logOnFinishedGoingToSleep(offReason: Int) { + val offReasonString = WindowManagerPolicyConstants.offReasonToString(offReason) + logBuffer.log( + TAG, + DEBUG, + { str1 = offReasonString }, + { "onFinishedGoingToSleep($str1)" } + ) + } + + fun logPinLockRequestedStartingKeyguard() { + logBuffer.log(TAG, INFO, "PIN lock requested, starting keyguard") + } + + fun logUserSwitching(userId: Int) { + logBuffer.log( + TAG, + DEBUG, + { int1 = userId }, + { "onUserSwitching $int1" } + ) + } + + fun logOnUserSwitchComplete(userId: Int) { + logBuffer.log( + TAG, + DEBUG, + { int1 = userId }, + { "onUserSwitchComplete $int1" } + ) + } + + fun logOnSimStateChanged(subId: Int, slotId: Int, simState: String) { + logBuffer.log( + TAG, + DEBUG, + { + int1 = subId + int2 = slotId + str1 = simState + }, + { "onSimStateChanged(subId=$int1, slotId=$int2, state=$str1)" } + ) + } + + fun logFailedToCallOnSimSecureStateChanged(remoteException: RemoteException) { + logBuffer.log( + TAG, + WARNING, + "Failed to call onSimSecureStateChanged", + remoteException + ) + } + + fun logIccAbsentIsNotShowing() { + logBuffer.log(TAG, DEBUG, "ICC_ABSENT isn't showing, we need to show the " + + "keyguard since the device isn't provisioned yet.") + } + + fun logSimMovedToAbsent() { + logBuffer.log(TAG, DEBUG, "SIM moved to ABSENT when the " + + "previous state was locked. Reset the state.") + } + + fun logIntentValueIccLocked() { + logBuffer.log(TAG, DEBUG, "INTENT_VALUE_ICC_LOCKED and keyguard isn't " + + "showing; need to show keyguard so user can enter sim pin") + } + + fun logPermDisabledKeyguardNotShowing() { + logBuffer.log(TAG, DEBUG, "PERM_DISABLED and keyguard isn't showing.") + } + + fun logPermDisabledResetStateLocked() { + logBuffer.log(TAG, DEBUG, "PERM_DISABLED, resetStateLocked to show permanently " + + "disabled message in lockscreen.") + } + + fun logReadyResetState(showing: Boolean) { + logBuffer.log( + TAG, + DEBUG, + { bool1 = showing }, + { "READY, reset state? $bool1"} + ) + } + + fun logSimMovedToReady() { + logBuffer.log(TAG, DEBUG, "SIM moved to READY when the previously was locked. " + + "Reset the state.") + } + + fun logUnspecifiedSimState(simState: Int) { + logBuffer.log( + TAG, + DEBUG, + { int1 = simState }, + { "Unspecific state: $int1" } + ) + } + + fun logOccludeLaunchAnimationCancelled(occluded: Boolean) { + logBuffer.log( + TAG, + DEBUG, + { bool1 = occluded }, + { "Occlude launch animation cancelled. Occluded state is now: $bool1"} + ) + } + + fun logActivityLaunchAnimatorLaunchContainerChanged() { + logBuffer.log(TAG, WTF, "Someone tried to change the launch container for the " + + "ActivityLaunchAnimator, which should never happen.") + } + + fun logVerifyUnlock() { + logBuffer.log(TAG, DEBUG, "verifyUnlock") + } + + fun logIgnoreUnlockDeviceNotProvisioned() { + logBuffer.log(TAG, DEBUG, "ignoring because device isn't provisioned") + } + + fun logFailedToCallOnKeyguardExitResultFalse(remoteException: RemoteException) { + logBuffer.log( + TAG, + WARNING, + "Failed to call onKeyguardExitResult(false)", + remoteException + ) + } + + fun logVerifyUnlockCalledNotExternallyDisabled() { + logBuffer.log(TAG, WARNING, "verifyUnlock called when not externally disabled") + } + + fun logSetOccluded(isOccluded: Boolean) { + logBuffer.log( + TAG, + DEBUG, + { bool1 = isOccluded }, + { "setOccluded($bool1)" } + ) + } + + fun logHandleSetOccluded(isOccluded: Boolean) { + logBuffer.log( + TAG, + DEBUG, + { bool1 = isOccluded }, + { "handleSetOccluded($bool1)" } + ) + } + + fun logIgnoreHandleShow() { + logBuffer.log(TAG, DEBUG, "ignoring handleShow because system is not ready.") + } + + fun logHandleShow() { + logBuffer.log(TAG, DEBUG, "handleShow") + } + + fun logHandleHide() { + logBuffer.log(TAG, DEBUG, "handleHide") + } + + fun logSplitSystemUserQuitUnlocking() { + logBuffer.log(TAG, DEBUG, "Split system user, quit unlocking.") + } + + fun logHandleStartKeyguardExitAnimation(startTime: Long, fadeoutDuration: Long) { + logBuffer.log( + TAG, + DEBUG, + { + long1 = startTime + long2 = fadeoutDuration + }, + { "handleStartKeyguardExitAnimation startTime=$long1 fadeoutDuration=$long2" } + ) + } + + fun logHandleVerifyUnlock() { + logBuffer.log(TAG, DEBUG, "handleVerifyUnlock") + } + + fun logHandleNotifyStartedGoingToSleep() { + logBuffer.log(TAG, DEBUG, "handleNotifyStartedGoingToSleep") + } + + fun logHandleNotifyFinishedGoingToSleep() { + logBuffer.log(TAG, DEBUG, "handleNotifyFinishedGoingToSleep") + } + + fun logHandleNotifyWakingUp() { + logBuffer.log(TAG, DEBUG, "handleNotifyWakingUp") + } + + fun logHandleReset() { + logBuffer.log(TAG, DEBUG, "handleReset") + } + + fun logKeyguardDone() { + logBuffer.log(TAG, DEBUG, "keyguardDone") + } + + fun logKeyguardDonePending() { + logBuffer.log(TAG, DEBUG, "keyguardDonePending") + } + + fun logKeyguardGone() { + logBuffer.log(TAG, DEBUG, "keyguardGone") + } + + fun logUnoccludeAnimationCancelled(isOccluded: Boolean) { + logBuffer.log( + TAG, + DEBUG, + { bool1 = isOccluded }, + { "Unocclude animation cancelled. Occluded state is now: $bool1" } + ) + } + + fun logShowLocked() { + logBuffer.log(TAG, DEBUG, "showLocked") + } + + fun logHideLocked() { + logBuffer.log(TAG, DEBUG, "hideLocked") + } + + fun logResetStateLocked() { + logBuffer.log(TAG, DEBUG, "resetStateLocked") + } + + fun logNotifyStartedGoingToSleep() { + logBuffer.log(TAG, DEBUG, "notifyStartedGoingToSleep") + } + + fun logNotifyFinishedGoingToSleep() { + logBuffer.log(TAG, DEBUG, "notifyFinishedGoingToSleep") + } + + fun logNotifyStartedWakingUp() { + logBuffer.log(TAG, DEBUG, "notifyStartedWakingUp") + } + + fun logDoKeyguardShowingLockScreen() { + logBuffer.log(TAG, DEBUG, "doKeyguard: showing the lock screen") + } + + fun logDoKeyguardNotShowingLockScreenOff() { + logBuffer.log(TAG, DEBUG, "doKeyguard: not showing because lockscreen is off") + } + + fun logDoKeyguardNotShowingDeviceNotProvisioned() { + logBuffer.log(TAG, DEBUG, "doKeyguard: not showing because device isn't " + + "provisioned and the sim is not locked or missing") + } + + fun logDoKeyguardNotShowingAlreadyShowing() { + logBuffer.log(TAG, DEBUG, "doKeyguard: not showing because it is already showing") + } + + fun logDoKeyguardNotShowingBootingCryptkeeper() { + logBuffer.log(TAG, DEBUG, "doKeyguard: not showing because booting to cryptkeeper") + } + + fun logDoKeyguardNotShowingExternallyDisabled() { + logBuffer.log(TAG, DEBUG, "doKeyguard: not showing because externally disabled") + } + + fun logFailedToCallOnDeviceProvisioned(remoteException: RemoteException) { + logBuffer.log( + TAG, + WARNING, + "Failed to call onDeviceProvisioned", + remoteException + ) + } + + fun logMaybeHandlePendingLockNotHandling() { + logBuffer.log(TAG, DEBUG, "#maybeHandlePendingLock: not handling because the " + + "screen off animation's isKeyguardShowDelayed() returned true. This should be " + + "handled soon by #onStartedWakingUp, or by the end actions of the " + + "screen off animation.") + } + + fun logMaybeHandlePendingLockKeyguardGoingAway() { + logBuffer.log(TAG, DEBUG, "#maybeHandlePendingLock: not handling because the " + + "keyguard is going away. This should be handled shortly by " + + "StatusBar#finishKeyguardFadingAway.") + } + + fun logMaybeHandlePendingLockHandling() { + logBuffer.log(TAG, DEBUG, "#maybeHandlePendingLock: handling pending lock; " + + "locking keyguard.") + } + + fun logSetAlarmToTurnOffKeyguard(delayedShowingSequence: Int) { + logBuffer.log( + TAG, + DEBUG, + { int1 = delayedShowingSequence }, + { "setting alarm to turn off keyguard, seq = $int1" } + ) + } + + fun logOnStartedWakingUp(delayedShowingSequence: Int) { + logBuffer.log( + TAG, + DEBUG, + { int1 = delayedShowingSequence }, + { "onStartedWakingUp, seq = $int1" } + ) + } + + fun logSetKeyguardEnabled(enabled: Boolean) { + logBuffer.log( + TAG, + DEBUG, + { bool1 = enabled }, + { "setKeyguardEnabled($bool1)" } + ) + } + + fun logIgnoreVerifyUnlockRequest() { + logBuffer.log(TAG, DEBUG, "in process of verifyUnlock request, ignoring") + } + + fun logRememberToReshowLater() { + logBuffer.log(TAG, DEBUG, "remembering to reshow, hiding keyguard, disabling " + + "status bar expansion") + } + + fun logPreviouslyHiddenReshow() { + logBuffer.log(TAG, DEBUG, "previously hidden, reshowing, reenabling status " + + "bar expansion") + } + + fun logOnKeyguardExitResultFalseResetting() { + logBuffer.log(TAG, DEBUG, "onKeyguardExitResult(false), resetting") + } + + fun logWaitingUntilKeyguardVisibleIsFalse() { + logBuffer.log(TAG, DEBUG, "waiting until mWaitingUntilKeyguardVisible is false") + } + + fun logDoneWaitingUntilKeyguardVisible() { + logBuffer.log(TAG, DEBUG, "done waiting for mWaitingUntilKeyguardVisible") + } + + fun logUnoccludeAnimatorOnAnimationStart() { + logBuffer.log(TAG, DEBUG, "UnoccludeAnimator#onAnimationStart. " + + "Set occluded = false.") + } + + fun logNoAppsProvidedToUnoccludeRunner() { + logBuffer.log(TAG, DEBUG, "No apps provided to unocclude runner; " + + "skipping animation and unoccluding.") + } + + fun logReceivedDelayedKeyguardAction(sequence: Int, delayedShowingSequence: Int) { + logBuffer.log( + TAG, + DEBUG, + { + int1 = sequence + int2 = delayedShowingSequence + }, + { + "received DELAYED_KEYGUARD_ACTION with seq = $int1 " + + "mDelayedShowingSequence = $int2" + } + ) + } + + fun logTimeoutWhileActivityDrawn() { + logBuffer.log(TAG, WARNING, "Timeout while waiting for activity drawn") + } + + fun logTryKeyguardDonePending( + keyguardDonePending: Boolean, + hideAnimationRun: Boolean, + hideAnimationRunning: Boolean + ) { + logBuffer.log(TAG, DEBUG, + { + bool1 = keyguardDonePending + bool2 = hideAnimationRun + bool3 = hideAnimationRunning + }, + { "tryKeyguardDone: pending - $bool1, animRan - $bool2 animRunning - $bool3" } + ) + } + + fun logTryKeyguardDonePreHideAnimation() { + logBuffer.log(TAG, DEBUG, "tryKeyguardDone: starting pre-hide animation") + } + + fun logHandleKeyguardDone() { + logBuffer.log(TAG, DEBUG, "handleKeyguardDone") + } + + fun logDeviceGoingToSleep() { + logBuffer.log(TAG, INFO, "Device is going to sleep, aborting keyguardDone") + } + + fun logFailedToCallOnKeyguardExitResultTrue(remoteException: RemoteException) { + logBuffer.log( + TAG, + WARNING, + "Failed to call onKeyguardExitResult(true)", + remoteException + ) + } + + fun logHandleKeyguardDoneDrawing() { + logBuffer.log(TAG, DEBUG, "handleKeyguardDoneDrawing") + } + + fun logHandleKeyguardDoneDrawingNotifyingKeyguardVisible() { + logBuffer.log(TAG, DEBUG, "handleKeyguardDoneDrawing: notifying " + + "mWaitingUntilKeyguardVisible") + } + + fun logUpdateActivityLockScreenState(showing: Boolean, aodShowing: Boolean) { + logBuffer.log( + TAG, + DEBUG, + { + bool1 = showing + bool2 = aodShowing + }, + { "updateActivityLockScreenState($bool1, $bool2)" } + ) + } + + fun logFailedToCallSetLockScreenShown(remoteException: RemoteException) { + logBuffer.log( + TAG, + WARNING, + "Failed to call setLockScreenShown", + remoteException + ) + } + + fun logKeyguardGoingAway() { + logBuffer.log(TAG, DEBUG, "keyguardGoingAway") + } + + fun logFailedToCallKeyguardGoingAway(keyguardFlag: Int, remoteException: RemoteException) { + logBuffer.log( + TAG, + ERROR, + { int1 = keyguardFlag }, + { "Failed to call keyguardGoingAway($int1)" }, + remoteException + ) + } + + fun logHideAnimationFinishedRunnable() { + logBuffer.log(TAG, WARNING, "mHideAnimationFinishedRunnable#run") + } + + fun logFailedToCallOnAnimationFinished(remoteException: RemoteException) { + logBuffer.log( + TAG, + WARNING, + "Failed to call onAnimationFinished", + remoteException + ) + } + + fun logFailedToCallOnAnimationStart(remoteException: RemoteException) { + logBuffer.log( + TAG, + WARNING, + "Failed to call onAnimationStart", + remoteException + ) + } + + fun logOnKeyguardExitRemoteAnimationFinished() { + logBuffer.log(TAG, DEBUG, "onKeyguardExitRemoteAnimationFinished") + } + + fun logSkipOnKeyguardExitRemoteAnimationFinished( + cancelled: Boolean, + surfaceBehindRemoteAnimationRunning: Boolean, + surfaceBehindRemoteAnimationRequested: Boolean + ) { + logBuffer.log( + TAG, + DEBUG, + { + bool1 = cancelled + bool2 = surfaceBehindRemoteAnimationRunning + bool3 = surfaceBehindRemoteAnimationRequested + }, + { + "skip onKeyguardExitRemoteAnimationFinished cancelled=$bool1 " + + "surfaceAnimationRunning=$bool2 " + + "surfaceAnimationRequested=$bool3" + } + ) + } + + fun logOnKeyguardExitRemoteAnimationFinishedHideKeyguardView() { + logBuffer.log(TAG, DEBUG, "onKeyguardExitRemoteAnimationFinished" + + "#hideKeyguardViewAfterRemoteAnimation") + } + + fun logSkipHideKeyguardViewAfterRemoteAnimation( + dismissingFromSwipe: Boolean, + wasShowing: Boolean + ) { + logBuffer.log( + TAG, + DEBUG, + { + bool1 = dismissingFromSwipe + bool2 = wasShowing + }, + { + "skip hideKeyguardViewAfterRemoteAnimation dismissFromSwipe=$bool1 " + + "wasShowing=$bool2" + } + ) + } + + fun logCouldNotGetStatusBarManager() { + logBuffer.log(TAG, WARNING, "Could not get status bar manager") + } + + fun logAdjustStatusBarLocked( + showing: Boolean, + occluded: Boolean, + secure: Boolean, + forceHideHomeRecentsButtons: Boolean, + flags: String + ) { + logBuffer.log( + TAG, + DEBUG, + { + bool1 = showing + bool2 = occluded + bool3 = secure + bool4 = forceHideHomeRecentsButtons + str3 = flags + }, + { + "adjustStatusBarLocked: mShowing=$bool1 mOccluded=$bool2 isSecure=$bool3 " + + "force=$bool4 --> flags=0x$str3" + } + ) + } + + fun logFailedToCallOnShowingStateChanged(remoteException: RemoteException) { + logBuffer.log( + TAG, + WARNING, + "Failed to call onShowingStateChanged", + remoteException + ) + } + + fun logFailedToCallNotifyTrustedChangedLocked(remoteException: RemoteException) { + logBuffer.log( + TAG, + WARNING, + "Failed to call notifyTrustedChangedLocked", + remoteException + ) + } + + fun logFailedToCallIKeyguardStateCallback(remoteException: RemoteException) { + logBuffer.log( + TAG, + WARNING, + "Failed to call to IKeyguardStateCallback", + remoteException + ) + } + + fun logOccludeAnimatorOnAnimationStart() { + logBuffer.log(TAG, DEBUG, "OccludeAnimator#onAnimationStart. Set occluded = true.") + } + + fun logOccludeAnimationCancelledByWm(isKeyguardOccluded: Boolean) { + logBuffer.log( + TAG, + DEBUG, + { bool1 = isKeyguardOccluded }, + { "Occlude animation cancelled by WM. Setting occluded state to: $bool1" } + ) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt index 589ec0e72b3b..9b5f54a0a91d 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt @@ -92,7 +92,7 @@ open class AuthBiometricFingerprintIconController( STATE_ERROR -> true STATE_AUTHENTICATING_ANIMATING_IN, STATE_AUTHENTICATING -> oldState == STATE_ERROR || oldState == STATE_HELP - STATE_AUTHENTICATED -> false + STATE_AUTHENTICATED -> true else -> false } @@ -114,7 +114,13 @@ open class AuthBiometricFingerprintIconController( R.raw.fingerprint_dialogue_fingerprint_to_error_lottie } } - STATE_AUTHENTICATED -> R.raw.fingerprint_dialogue_fingerprint_to_error_lottie + STATE_AUTHENTICATED -> { + if (oldState == STATE_ERROR || oldState == STATE_HELP) { + R.raw.fingerprint_dialogue_error_to_success_lottie + } else { + R.raw.fingerprint_dialogue_fingerprint_to_success_lottie + } + } else -> return null } return if (id != null) return id else null diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt index 31baa0ff1154..9cce066afe9d 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt @@ -75,7 +75,7 @@ open class AuthBiometricFingerprintView( } } - override fun getDelayAfterAuthenticatedDurationMs() = 0 + override fun getDelayAfterAuthenticatedDurationMs() = 500 override fun getStateForAfterError() = STATE_AUTHENTICATING diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java index e866b9c0bb25..fc5cf9f005ed 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java @@ -468,6 +468,7 @@ public abstract class AuthBiometricView extends LinearLayout { break; case STATE_AUTHENTICATED: + removePendingAnimations(); if (mSize != AuthDialog.SIZE_SMALL) { mConfirmButton.setVisibility(View.GONE); mNegativeButton.setVisibility(View.GONE); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java index 6dfbd426ef30..898959e6eb58 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java @@ -53,7 +53,6 @@ import android.os.IBinder; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; -import android.os.SystemProperties; import android.os.Trace; import android.util.ArrayMap; import android.util.Log; @@ -89,34 +88,6 @@ public class KeyguardService extends Service { static final String TAG = "KeyguardService"; static final String PERMISSION = android.Manifest.permission.CONTROL_KEYGUARD; - /** - * Run Keyguard animation as remote animation in System UI instead of local animation in - * the server process. - * - * 0: Runs all keyguard animation as local animation - * 1: Only runs keyguard going away animation as remote animation - * 2: Runs all keyguard animation as remote animation - * - * Note: Must be consistent with WindowManagerService. - */ - private static final String ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY = - "persist.wm.enable_remote_keyguard_animation"; - - private static final int sEnableRemoteKeyguardAnimation = - SystemProperties.getInt(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, 2); - - /** - * @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY - */ - public static boolean sEnableRemoteKeyguardGoingAwayAnimation = - sEnableRemoteKeyguardAnimation >= 1; - - /** - * @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY - */ - public static boolean sEnableRemoteKeyguardOccludeAnimation = - sEnableRemoteKeyguardAnimation >= 2; - private final KeyguardViewMediator mKeyguardViewMediator; private final KeyguardLifecyclesDispatcher mKeyguardLifecyclesDispatcher; private final ShellTransitions mShellTransitions; @@ -288,97 +259,90 @@ public class KeyguardService extends Service { if (mShellTransitions == null || !Transitions.ENABLE_SHELL_TRANSITIONS) { RemoteAnimationDefinition definition = new RemoteAnimationDefinition(); - if (sEnableRemoteKeyguardGoingAwayAnimation) { - final RemoteAnimationAdapter exitAnimationAdapter = - new RemoteAnimationAdapter(mExitAnimationRunner, 0, 0); - definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_GOING_AWAY, - exitAnimationAdapter); - definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER, - exitAnimationAdapter); - } - if (sEnableRemoteKeyguardOccludeAnimation) { - final RemoteAnimationAdapter occludeAnimationAdapter = - new RemoteAnimationAdapter( - mKeyguardViewMediator.getOccludeAnimationRunner(), 0, 0); - definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_OCCLUDE, - occludeAnimationAdapter); - - final RemoteAnimationAdapter unoccludeAnimationAdapter = - new RemoteAnimationAdapter( - mKeyguardViewMediator.getUnoccludeAnimationRunner(), 0, 0); - definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_UNOCCLUDE, - unoccludeAnimationAdapter); - } + final RemoteAnimationAdapter exitAnimationAdapter = + new RemoteAnimationAdapter(mExitAnimationRunner, 0, 0); + definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_GOING_AWAY, + exitAnimationAdapter); + definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER, + exitAnimationAdapter); + final RemoteAnimationAdapter occludeAnimationAdapter = + new RemoteAnimationAdapter( + mKeyguardViewMediator.getOccludeAnimationRunner(), 0, 0); + definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_OCCLUDE, + occludeAnimationAdapter); + + final RemoteAnimationAdapter unoccludeAnimationAdapter = + new RemoteAnimationAdapter( + mKeyguardViewMediator.getUnoccludeAnimationRunner(), 0, 0); + definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_UNOCCLUDE, + unoccludeAnimationAdapter); ActivityTaskManager.getInstance().registerRemoteAnimationsForDisplay( DEFAULT_DISPLAY, definition); return; } - if (sEnableRemoteKeyguardGoingAwayAnimation) { - Slog.d(TAG, "KeyguardService registerRemote: TRANSIT_KEYGUARD_GOING_AWAY"); - TransitionFilter f = new TransitionFilter(); - f.mFlags = TRANSIT_FLAG_KEYGUARD_GOING_AWAY; - mShellTransitions.registerRemote(f, - new RemoteTransition(wrap(mExitAnimationRunner), getIApplicationThread())); - } - if (sEnableRemoteKeyguardOccludeAnimation) { - Slog.d(TAG, "KeyguardService registerRemote: TRANSIT_KEYGUARD_(UN)OCCLUDE"); - // Register for occluding - final RemoteTransition occludeTransition = new RemoteTransition( - mOccludeAnimation, getIApplicationThread()); - TransitionFilter f = new TransitionFilter(); - f.mFlags = TRANSIT_FLAG_KEYGUARD_LOCKED; - f.mRequirements = new TransitionFilter.Requirement[]{ - new TransitionFilter.Requirement(), new TransitionFilter.Requirement()}; - // First require at-least one app showing that occludes. - f.mRequirements[0].mMustBeIndependent = false; - f.mRequirements[0].mFlags = FLAG_OCCLUDES_KEYGUARD; - f.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT}; - // Then require that we aren't closing any occludes (because this would mean a - // regular task->task or activity->activity animation not involving keyguard). - f.mRequirements[1].mNot = true; - f.mRequirements[1].mMustBeIndependent = false; - f.mRequirements[1].mFlags = FLAG_OCCLUDES_KEYGUARD; - f.mRequirements[1].mModes = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK}; - mShellTransitions.registerRemote(f, occludeTransition); - - // Now register for un-occlude. - final RemoteTransition unoccludeTransition = new RemoteTransition( - mUnoccludeAnimation, getIApplicationThread()); - f = new TransitionFilter(); - f.mFlags = TRANSIT_FLAG_KEYGUARD_LOCKED; - f.mRequirements = new TransitionFilter.Requirement[]{ - new TransitionFilter.Requirement(), new TransitionFilter.Requirement()}; - // First require at-least one app going-away (doesn't need occlude flag - // as that is implicit by it having been visible and we don't want to exclude - // cases where we are un-occluding because the app removed its showWhenLocked - // capability at runtime). - f.mRequirements[1].mMustBeIndependent = false; - f.mRequirements[1].mModes = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK}; - f.mRequirements[1].mMustBeTask = true; - // Then require that we aren't opening any occludes (otherwise we'd remain - // occluded). - f.mRequirements[0].mNot = true; - f.mRequirements[0].mMustBeIndependent = false; - f.mRequirements[0].mFlags = FLAG_OCCLUDES_KEYGUARD; - f.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT}; - mShellTransitions.registerRemote(f, unoccludeTransition); - - // Register for specific transition type. - // Above filter cannot fulfill all conditions. - // E.g. close top activity while screen off but next activity is occluded, this should - // an occluded transition, but since the activity is invisible, the condition would - // match unoccluded transition. - // But on the contrary, if we add above condition in occluded transition, then when user - // trying to dismiss occluded activity when unlock keyguard, the condition would match - // occluded transition. - f = new TransitionFilter(); - f.mTypeSet = new int[]{TRANSIT_KEYGUARD_OCCLUDE}; - mShellTransitions.registerRemote(f, occludeTransition); - - f = new TransitionFilter(); - f.mTypeSet = new int[]{TRANSIT_KEYGUARD_UNOCCLUDE}; - mShellTransitions.registerRemote(f, unoccludeTransition); - } + Slog.d(TAG, "KeyguardService registerRemote: TRANSIT_KEYGUARD_GOING_AWAY"); + TransitionFilter f = new TransitionFilter(); + f.mFlags = TRANSIT_FLAG_KEYGUARD_GOING_AWAY; + mShellTransitions.registerRemote(f, + new RemoteTransition(wrap(mExitAnimationRunner), getIApplicationThread())); + + Slog.d(TAG, "KeyguardService registerRemote: TRANSIT_KEYGUARD_(UN)OCCLUDE"); + // Register for occluding + final RemoteTransition occludeTransition = new RemoteTransition( + mOccludeAnimation, getIApplicationThread()); + f = new TransitionFilter(); + f.mFlags = TRANSIT_FLAG_KEYGUARD_LOCKED; + f.mRequirements = new TransitionFilter.Requirement[]{ + new TransitionFilter.Requirement(), new TransitionFilter.Requirement()}; + // First require at-least one app showing that occludes. + f.mRequirements[0].mMustBeIndependent = false; + f.mRequirements[0].mFlags = FLAG_OCCLUDES_KEYGUARD; + f.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT}; + // Then require that we aren't closing any occludes (because this would mean a + // regular task->task or activity->activity animation not involving keyguard). + f.mRequirements[1].mNot = true; + f.mRequirements[1].mMustBeIndependent = false; + f.mRequirements[1].mFlags = FLAG_OCCLUDES_KEYGUARD; + f.mRequirements[1].mModes = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK}; + mShellTransitions.registerRemote(f, occludeTransition); + + // Now register for un-occlude. + final RemoteTransition unoccludeTransition = new RemoteTransition( + mUnoccludeAnimation, getIApplicationThread()); + f = new TransitionFilter(); + f.mFlags = TRANSIT_FLAG_KEYGUARD_LOCKED; + f.mRequirements = new TransitionFilter.Requirement[]{ + new TransitionFilter.Requirement(), new TransitionFilter.Requirement()}; + // First require at-least one app going-away (doesn't need occlude flag + // as that is implicit by it having been visible and we don't want to exclude + // cases where we are un-occluding because the app removed its showWhenLocked + // capability at runtime). + f.mRequirements[1].mMustBeIndependent = false; + f.mRequirements[1].mModes = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK}; + f.mRequirements[1].mMustBeTask = true; + // Then require that we aren't opening any occludes (otherwise we'd remain + // occluded). + f.mRequirements[0].mNot = true; + f.mRequirements[0].mMustBeIndependent = false; + f.mRequirements[0].mFlags = FLAG_OCCLUDES_KEYGUARD; + f.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT}; + mShellTransitions.registerRemote(f, unoccludeTransition); + + // Register for specific transition type. + // Above filter cannot fulfill all conditions. + // E.g. close top activity while screen off but next activity is occluded, this should + // an occluded transition, but since the activity is invisible, the condition would + // match unoccluded transition. + // But on the contrary, if we add above condition in occluded transition, then when user + // trying to dismiss occluded activity when unlock keyguard, the condition would match + // occluded transition. + f = new TransitionFilter(); + f.mTypeSet = new int[]{TRANSIT_KEYGUARD_OCCLUDE}; + mShellTransitions.registerRemote(f, occludeTransition); + + f = new TransitionFilter(); + f.mTypeSet = new int[]{TRANSIT_KEYGUARD_UNOCCLUDE}; + mShellTransitions.registerRemote(f, unoccludeTransition); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt index c944e509c5f1..9ecfb7521151 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt @@ -484,8 +484,8 @@ class KeyguardUnlockAnimationController @Inject constructor( // surface behind the keyguard to finish unlocking. if (keyguardStateController.isFlingingToDismissKeyguard) { playCannedUnlockAnimation() - } else if (keyguardStateController.isDismissingFromSwipe - && willUnlockWithInWindowLauncherAnimations) { + } else if (keyguardStateController.isDismissingFromSwipe && + willUnlockWithInWindowLauncherAnimations) { // If we're swiping to unlock to the Launcher, and can play in-window animations, // make the launcher surface fully visible and play the in-window unlock animation // on the launcher icons. System UI will remain locked, using the swipe-to-unlock @@ -622,10 +622,6 @@ class KeyguardUnlockAnimationController @Inject constructor( } override fun onKeyguardDismissAmountChanged() { - if (!willHandleUnlockAnimation()) { - return - } - if (keyguardViewController.isShowing && !playingCannedUnlockAnimation) { showOrHideSurfaceIfDismissAmountThresholdsReached() @@ -685,8 +681,7 @@ class KeyguardUnlockAnimationController @Inject constructor( */ private fun finishKeyguardExitRemoteAnimationIfReachThreshold() { // no-op if keyguard is not showing or animation is not enabled. - if (!KeyguardService.sEnableRemoteKeyguardGoingAwayAnimation || - !keyguardViewController.isShowing) { + if (!keyguardViewController.isShowing) { return } @@ -727,8 +722,8 @@ class KeyguardUnlockAnimationController @Inject constructor( // If we're dismissing via swipe to the Launcher, we'll play in-window scale animations, so // don't also scale the window. - if (keyguardStateController.isDismissingFromSwipe - && willUnlockWithInWindowLauncherAnimations) { + if (keyguardStateController.isDismissingFromSwipe && + willUnlockWithInWindowLauncherAnimations) { scaleFactor = 1f } @@ -920,17 +915,6 @@ class KeyguardUnlockAnimationController @Inject constructor( } /** - * Whether this animation controller will be handling the unlock. We require remote animations - * to be enabled to do this. - * - * If this is not true, nothing in this class is relevant, and the unlock will be handled in - * [KeyguardViewMediator]. - */ - fun willHandleUnlockAnimation(): Boolean { - return KeyguardService.sEnableRemoteKeyguardGoingAwayAnimation - } - - /** * Whether the RemoteAnimation on the app/launcher surface behind the keyguard is 'running'. */ fun isAnimatingBetweenKeyguardAndSurfaceBehind(): Boolean { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 4a7346ee2901..70e0d5fa9ba7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -73,8 +73,6 @@ import android.provider.Settings; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.EventLog; -import android.util.Log; -import android.util.Slog; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.view.IRemoteAnimationFinishedCallback; @@ -106,6 +104,7 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.keyguard.KeyguardViewController; import com.android.keyguard.ViewMediatorCallback; +import com.android.keyguard.logging.KeyguardViewMediatorLogger; import com.android.keyguard.mediator.ScreenOnCoordinator; import com.android.systemui.CoreStartable; import com.android.systemui.DejankUtils; @@ -513,8 +512,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, public void onKeyguardVisibilityChanged(boolean showing) { synchronized (KeyguardViewMediator.this) { if (!showing && mPendingPinLock) { - Log.i(TAG, "PIN lock requested, starting keyguard"); - + mLogger.logPinLockRequestedStartingKeyguard(); // Bring the keyguard back in order to show the PIN lock mPendingPinLock = false; doKeyguardLocked(null); @@ -524,7 +522,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, @Override public void onUserSwitching(int userId) { - if (DEBUG) Log.d(TAG, String.format("onUserSwitching %d", userId)); + mLogger.logUserSwitching(userId); // Note that the mLockPatternUtils user has already been updated from setCurrentUser. // We need to force a reset of the views, since lockNow (called by // ActivityManagerService) will not reconstruct the keyguard if it is already showing. @@ -542,7 +540,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, @Override public void onUserSwitchComplete(int userId) { - if (DEBUG) Log.d(TAG, String.format("onUserSwitchComplete %d", userId)); + mLogger.logOnUserSwitchComplete(userId); if (userId != UserHandle.USER_SYSTEM) { UserInfo info = UserManager.get(mContext).getUserInfo(userId); // Don't try to dismiss if the user has Pin/Pattern/Password set @@ -570,8 +568,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, public void onSimStateChanged(int subId, int slotId, int simState) { if (DEBUG_SIM_STATES) { - Log.d(TAG, "onSimStateChanged(subId=" + subId + ", slotId=" + slotId - + ",state=" + simState + ")"); + mLogger.logOnSimStateChanged(subId, slotId, String.valueOf(simState)); } int size = mKeyguardStateCallbacks.size(); @@ -580,7 +577,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, try { mKeyguardStateCallbacks.get(i).onSimSecureStateChanged(simPinSecure); } catch (RemoteException e) { - Slog.w(TAG, "Failed to call onSimSecureStateChanged", e); + mLogger.logFailedToCallOnSimSecureStateChanged(e); if (e instanceof DeadObjectException) { mKeyguardStateCallbacks.remove(i); } @@ -603,9 +600,9 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, synchronized (KeyguardViewMediator.this) { if (shouldWaitForProvisioning()) { if (!mShowing) { - if (DEBUG_SIM_STATES) Log.d(TAG, "ICC_ABSENT isn't showing," - + " we need to show the keyguard since the " - + "device isn't provisioned yet."); + if (DEBUG_SIM_STATES) { + mLogger.logIccAbsentIsNotShowing(); + } doKeyguardLocked(null); } else { resetStateLocked(); @@ -615,8 +612,9 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, // MVNO SIMs can become transiently NOT_READY when switching networks, // so we should only lock when they are ABSENT. if (lastSimStateWasLocked) { - if (DEBUG_SIM_STATES) Log.d(TAG, "SIM moved to ABSENT when the " - + "previous state was locked. Reset the state."); + if (DEBUG_SIM_STATES) { + mLogger.logSimMovedToAbsent(); + } resetStateLocked(); } mSimWasLocked.append(slotId, false); @@ -629,9 +627,9 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, mSimWasLocked.append(slotId, true); mPendingPinLock = true; if (!mShowing) { - if (DEBUG_SIM_STATES) Log.d(TAG, - "INTENT_VALUE_ICC_LOCKED and keygaurd isn't " - + "showing; need to show keyguard so user can enter sim pin"); + if (DEBUG_SIM_STATES) { + mLogger.logIntentValueIccLocked(); + } doKeyguardLocked(null); } else { resetStateLocked(); @@ -641,29 +639,36 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, case TelephonyManager.SIM_STATE_PERM_DISABLED: synchronized (KeyguardViewMediator.this) { if (!mShowing) { - if (DEBUG_SIM_STATES) Log.d(TAG, "PERM_DISABLED and " - + "keygaurd isn't showing."); + if (DEBUG_SIM_STATES) { + mLogger.logPermDisabledKeyguardNotShowing(); + } doKeyguardLocked(null); } else { - if (DEBUG_SIM_STATES) Log.d(TAG, "PERM_DISABLED, resetStateLocked to" - + "show permanently disabled message in lockscreen."); + if (DEBUG_SIM_STATES) { + mLogger.logPermDisabledResetStateLocked(); + } resetStateLocked(); } } break; case TelephonyManager.SIM_STATE_READY: synchronized (KeyguardViewMediator.this) { - if (DEBUG_SIM_STATES) Log.d(TAG, "READY, reset state? " + mShowing); + if (DEBUG_SIM_STATES) { + mLogger.logReadyResetState(mShowing); + } if (mShowing && mSimWasLocked.get(slotId, false)) { - if (DEBUG_SIM_STATES) Log.d(TAG, "SIM moved to READY when the " - + "previously was locked. Reset the state."); + if (DEBUG_SIM_STATES) { + mLogger.logSimMovedToReady(); + } mSimWasLocked.append(slotId, false); resetStateLocked(); } } break; default: - if (DEBUG_SIM_STATES) Log.v(TAG, "Unspecific state: " + simState); + if (DEBUG_SIM_STATES) { + mLogger.logUnspecifiedSimState(simState); + } break; } } @@ -708,7 +713,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, if (targetUserId != ActivityManager.getCurrentUser()) { return; } - if (DEBUG) Log.d(TAG, "keyguardDone"); + mLogger.logKeyguardDone(); tryKeyguardDone(); } @@ -727,7 +732,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, @Override public void keyguardDonePending(boolean strongAuth, int targetUserId) { Trace.beginSection("KeyguardViewMediator.mViewMediatorCallback#keyguardDonePending"); - if (DEBUG) Log.d(TAG, "keyguardDonePending"); + mLogger.logKeyguardDonePending(); if (targetUserId != ActivityManager.getCurrentUser()) { Trace.endSection(); return; @@ -746,7 +751,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, @Override public void keyguardGone() { Trace.beginSection("KeyguardViewMediator.mViewMediatorCallback#keyguardGone"); - if (DEBUG) Log.d(TAG, "keyguardGone"); + mLogger.logKeyguardGone(); mKeyguardViewControllerLazy.get().setKeyguardGoingAwayState(false); mKeyguardDisplayManager.hide(); Trace.endSection(); @@ -832,8 +837,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, @Override public void onLaunchAnimationCancelled() { - Log.d(TAG, "Occlude launch animation cancelled. Occluded state is now: " - + mOccluded); + mLogger.logOccludeLaunchAnimationCancelled(mOccluded); } @Override @@ -853,8 +857,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, @Override public void setLaunchContainer(@NonNull ViewGroup launchContainer) { // No-op, launch container is always the shade. - Log.wtf(TAG, "Someone tried to change the launch container for the " - + "ActivityLaunchAnimator, which should never happen."); + mLogger.logActivityLaunchAnimatorLaunchContainerChanged(); } @NonNull @@ -905,8 +908,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, } setOccluded(isKeyguardOccluded /* isOccluded */, false /* animate */); - Log.d(TAG, "Unocclude animation cancelled. Occluded state is now: " - + mOccluded); + mLogger.logUnoccludeAnimationCancelled(mOccluded); } @Override @@ -914,12 +916,11 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException { - Log.d(TAG, "UnoccludeAnimator#onAnimationStart. Set occluded = false."); + mLogger.logUnoccludeAnimatorOnAnimationStart(); setOccluded(false /* isOccluded */, true /* animate */); if (apps == null || apps.length == 0 || apps[0] == null) { - Log.d(TAG, "No apps provided to unocclude runner; " - + "skipping animation and unoccluding."); + mLogger.logNoAppsProvidedToUnoccludeRunner(); finishedCallback.onAnimationFinished(); return; } @@ -1007,6 +1008,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, private ScreenOnCoordinator mScreenOnCoordinator; private Lazy<ActivityLaunchAnimator> mActivityLaunchAnimator; + private KeyguardViewMediatorLogger mLogger; /** * Injected constructor. See {@link KeyguardModule}. @@ -1035,7 +1037,8 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, InteractionJankMonitor interactionJankMonitor, DreamOverlayStateController dreamOverlayStateController, Lazy<NotificationShadeWindowController> notificationShadeWindowControllerLazy, - Lazy<ActivityLaunchAnimator> activityLaunchAnimator) { + Lazy<ActivityLaunchAnimator> activityLaunchAnimator, + KeyguardViewMediatorLogger logger) { super(context); mFalsingCollector = falsingCollector; mLockPatternUtils = lockPatternUtils; @@ -1078,6 +1081,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, mDreamOverlayStateController = dreamOverlayStateController; mActivityLaunchAnimator = activityLaunchAnimator; + mLogger = logger; mPowerButtonY = context.getResources().getDimensionPixelSize( R.dimen.physical_power_button_center_screen_location_y); @@ -1141,21 +1145,21 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, mLockSoundId = mLockSounds.load(soundPath, 1); } if (soundPath == null || mLockSoundId == 0) { - Log.w(TAG, "failed to load lock sound from " + soundPath); + mLogger.logFailedLoadLockSound(soundPath); } soundPath = Settings.Global.getString(cr, Settings.Global.UNLOCK_SOUND); if (soundPath != null) { mUnlockSoundId = mLockSounds.load(soundPath, 1); } if (soundPath == null || mUnlockSoundId == 0) { - Log.w(TAG, "failed to load unlock sound from " + soundPath); + mLogger.logFailedLoadUnlockSound(soundPath); } soundPath = Settings.Global.getString(cr, Settings.Global.TRUSTED_SOUND); if (soundPath != null) { mTrustedSoundId = mLockSounds.load(soundPath, 1); } if (soundPath == null || mTrustedSoundId == 0) { - Log.w(TAG, "failed to load trusted sound from " + soundPath); + mLogger.logFailedLoadTrustedSound(soundPath); } int lockSoundDefaultAttenuation = mContext.getResources().getInteger( @@ -1184,7 +1188,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, private void handleSystemReady() { synchronized (this) { - if (DEBUG) Log.d(TAG, "onSystemReady"); + mLogger.logOnSystemReady(); mSystemReady = true; doKeyguardLocked(null); mUpdateMonitor.registerCallback(mUpdateCallback); @@ -1202,7 +1206,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, * {@link WindowManagerPolicyConstants#OFF_BECAUSE_OF_TIMEOUT}. */ public void onStartedGoingToSleep(@WindowManagerPolicyConstants.OffReason int offReason) { - if (DEBUG) Log.d(TAG, "onStartedGoingToSleep(" + offReason + ")"); + mLogger.logOnStartedGoingToSleep(offReason); synchronized (this) { mDeviceInteractive = false; mPowerGestureIntercepted = false; @@ -1218,11 +1222,11 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, long timeout = getLockTimeout(KeyguardUpdateMonitor.getCurrentUser()); mLockLater = false; if (mExitSecureCallback != null) { - if (DEBUG) Log.d(TAG, "pending exit secure callback cancelled"); + mLogger.logPendingExitSecureCallbackCancelled(); try { mExitSecureCallback.onKeyguardExitResult(false); } catch (RemoteException e) { - Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e); + mLogger.logFailedOnKeyguardExitResultFalse(e); } mExitSecureCallback = null; if (!mExternallyEnabled) { @@ -1267,7 +1271,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, */ public void onFinishedGoingToSleep( @WindowManagerPolicyConstants.OffReason int offReason, boolean cameraGestureTriggered) { - if (DEBUG) Log.d(TAG, "onFinishedGoingToSleep(" + offReason + ")"); + mLogger.logOnFinishedGoingToSleep(offReason); synchronized (this) { mDeviceInteractive = false; mGoingToSleep = false; @@ -1325,13 +1329,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, // - The screen off animation is cancelled by the device waking back up. We will call // maybeHandlePendingLock from KeyguardViewMediator#onStartedWakingUp. if (mScreenOffAnimationController.isKeyguardShowDelayed()) { - if (DEBUG) { - Log.d(TAG, "#maybeHandlePendingLock: not handling because the screen off " - + "animation's isKeyguardShowDelayed() returned true. This should be " - + "handled soon by #onStartedWakingUp, or by the end actions of the " - + "screen off animation."); - } - + mLogger.logMaybeHandlePendingLockNotHandling(); return; } @@ -1341,18 +1339,11 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, // StatusBar#finishKeyguardFadingAway, which is always responsible for setting // isKeyguardGoingAway to false. if (mKeyguardStateController.isKeyguardGoingAway()) { - if (DEBUG) { - Log.d(TAG, "#maybeHandlePendingLock: not handling because the keyguard is " - + "going away. This should be handled shortly by " - + "StatusBar#finishKeyguardFadingAway."); - } - + mLogger.logMaybeHandlePendingLockKeyguardGoingAway(); return; } - if (DEBUG) { - Log.d(TAG, "#maybeHandlePendingLock: handling pending lock; locking keyguard."); - } + mLogger.logMaybeHandlePendingLockHandling(); doKeyguardLocked(null); setPendingLock(false); @@ -1421,8 +1412,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, PendingIntent sender = PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE); mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, sender); - if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = " - + mDelayedShowingSequence); + mLogger.logSetAlarmToTurnOffKeyguard(mDelayedShowingSequence); doKeyguardLaterForChildProfilesLocked(); } @@ -1482,7 +1472,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, mAnimatingScreenOff = false; cancelDoKeyguardLaterLocked(); cancelDoKeyguardForChildProfilesLocked(); - if (DEBUG) Log.d(TAG, "onStartedWakingUp, seq = " + mDelayedShowingSequence); + mLogger.logOnStartedWakingUp(mDelayedShowingSequence); notifyStartedWakingUp(); } mUpdateMonitor.dispatchStartedWakingUp(); @@ -1542,37 +1532,35 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, */ public void setKeyguardEnabled(boolean enabled) { synchronized (this) { - if (DEBUG) Log.d(TAG, "setKeyguardEnabled(" + enabled + ")"); + mLogger.logSetKeyguardEnabled(enabled); mExternallyEnabled = enabled; if (!enabled && mShowing) { if (mExitSecureCallback != null) { - if (DEBUG) Log.d(TAG, "in process of verifyUnlock request, ignoring"); + mLogger.logIgnoreVerifyUnlockRequest(); // we're in the process of handling a request to verify the user // can get past the keyguard. ignore extraneous requests to disable / re-enable return; } // hiding keyguard that is showing, remember to reshow later - if (DEBUG) Log.d(TAG, "remembering to reshow, hiding keyguard, " - + "disabling status bar expansion"); + mLogger.logRememberToReshowLater(); mNeedToReshowWhenReenabled = true; updateInputRestrictedLocked(); hideLocked(); } else if (enabled && mNeedToReshowWhenReenabled) { // re-enabled after previously hidden, reshow - if (DEBUG) Log.d(TAG, "previously hidden, reshowing, reenabling " - + "status bar expansion"); + mLogger.logPreviouslyHiddenReshow(); mNeedToReshowWhenReenabled = false; updateInputRestrictedLocked(); if (mExitSecureCallback != null) { - if (DEBUG) Log.d(TAG, "onKeyguardExitResult(false), resetting"); + mLogger.logOnKeyguardExitResultFalseResetting(); try { mExitSecureCallback.onKeyguardExitResult(false); } catch (RemoteException e) { - Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e); + mLogger.logFailedToCallOnKeyguardExitResultFalse(e); } mExitSecureCallback = null; resetStateLocked(); @@ -1584,7 +1572,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, // and causing an ANR). mWaitingUntilKeyguardVisible = true; mHandler.sendEmptyMessageDelayed(KEYGUARD_DONE_DRAWING, KEYGUARD_DONE_DRAWING_TIMEOUT_MS); - if (DEBUG) Log.d(TAG, "waiting until mWaitingUntilKeyguardVisible is false"); + mLogger.logWaitingUntilKeyguardVisibleIsFalse(); while (mWaitingUntilKeyguardVisible) { try { wait(); @@ -1592,7 +1580,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, Thread.currentThread().interrupt(); } } - if (DEBUG) Log.d(TAG, "done waiting for mWaitingUntilKeyguardVisible"); + mLogger.logDoneWaitingUntilKeyguardVisible(); } } } @@ -1604,31 +1592,31 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, public void verifyUnlock(IKeyguardExitCallback callback) { Trace.beginSection("KeyguardViewMediator#verifyUnlock"); synchronized (this) { - if (DEBUG) Log.d(TAG, "verifyUnlock"); + mLogger.logVerifyUnlock(); if (shouldWaitForProvisioning()) { // don't allow this api when the device isn't provisioned - if (DEBUG) Log.d(TAG, "ignoring because device isn't provisioned"); + mLogger.logIgnoreUnlockDeviceNotProvisioned(); try { callback.onKeyguardExitResult(false); } catch (RemoteException e) { - Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e); + mLogger.logFailedToCallOnKeyguardExitResultFalse(e); } } else if (mExternallyEnabled) { // this only applies when the user has externally disabled the // keyguard. this is unexpected and means the user is not // using the api properly. - Log.w(TAG, "verifyUnlock called when not externally disabled"); + mLogger.logVerifyUnlockCalledNotExternallyDisabled(); try { callback.onKeyguardExitResult(false); } catch (RemoteException e) { - Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e); + mLogger.logFailedToCallOnKeyguardExitResultFalse(e); } } else if (mExitSecureCallback != null) { // already in progress with someone else try { callback.onKeyguardExitResult(false); } catch (RemoteException e) { - Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e); + mLogger.logFailedToCallOnKeyguardExitResultFalse(e); } } else if (!isSecure()) { @@ -1640,7 +1628,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, try { callback.onKeyguardExitResult(true); } catch (RemoteException e) { - Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e); + mLogger.logFailedToCallOnKeyguardExitResultFalse(e); } } else { @@ -1649,7 +1637,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, try { callback.onKeyguardExitResult(false); } catch (RemoteException e) { - Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e); + mLogger.logFailedToCallOnKeyguardExitResultFalse(e); } } } @@ -1667,10 +1655,8 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, * Notify us when the keyguard is occluded by another window */ public void setOccluded(boolean isOccluded, boolean animate) { - Log.d(TAG, "setOccluded(" + isOccluded + ")"); - Trace.beginSection("KeyguardViewMediator#setOccluded"); - if (DEBUG) Log.d(TAG, "setOccluded " + isOccluded); + mLogger.logSetOccluded(isOccluded); mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_TRANSITION_FROM_AOD); mHandler.removeMessages(SET_OCCLUDED); Message msg = mHandler.obtainMessage(SET_OCCLUDED, isOccluded ? 1 : 0, animate ? 1 : 0); @@ -1699,7 +1685,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, */ private void handleSetOccluded(boolean isOccluded, boolean animate) { Trace.beginSection("KeyguardViewMediator#handleSetOccluded"); - Log.d(TAG, "handleSetOccluded(" + isOccluded + ")"); + mLogger.logHandleSetOccluded(isOccluded); synchronized (KeyguardViewMediator.this) { if (mHiding && isOccluded) { // We're in the process of going away but WindowManager wants to show a @@ -1756,7 +1742,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, try { callback.onInputRestrictedStateChanged(inputRestricted); } catch (RemoteException e) { - Slog.w(TAG, "Failed to call onDeviceProvisioned", e); + mLogger.logFailedToCallOnDeviceProvisioned(e); if (e instanceof DeadObjectException) { mKeyguardStateCallbacks.remove(callback); } @@ -1771,8 +1757,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, private void doKeyguardLocked(Bundle options) { // if another app is disabling us, don't show if (!mExternallyEnabled) { - if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled"); - + mLogger.logDoKeyguardNotShowingExternallyDisabled(); mNeedToReshowWhenReenabled = true; return; } @@ -1781,7 +1766,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, // to account for the hiding animation which results in a delay and discrepancy // between flags if (mShowing && mKeyguardViewControllerLazy.get().isShowing()) { - if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing"); + mLogger.logDoKeyguardNotShowingAlreadyShowing(); resetStateLocked(); return; } @@ -1800,20 +1785,19 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, || ((absent || disabled) && requireSim); if (!lockedOrMissing && shouldWaitForProvisioning()) { - if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned" - + " and the sim is not locked or missing"); + mLogger.logDoKeyguardNotShowingDeviceNotProvisioned(); return; } boolean forceShow = options != null && options.getBoolean(OPTION_FORCE_SHOW, false); if (mLockPatternUtils.isLockScreenDisabled(KeyguardUpdateMonitor.getCurrentUser()) && !lockedOrMissing && !forceShow) { - if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off"); + mLogger.logDoKeyguardNotShowingLockScreenOff(); return; } } - if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen"); + mLogger.logDoKeyguardShowingLockScreen(); showLocked(options); } @@ -1851,32 +1835,23 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, * @see #handleReset */ private void resetStateLocked() { - if (DEBUG) Log.e(TAG, "resetStateLocked"); + mLogger.logResetStateLocked(); Message msg = mHandler.obtainMessage(RESET); mHandler.sendMessage(msg); } - /** - * Send message to keyguard telling it to verify unlock - * @see #handleVerifyUnlock() - */ - private void verifyUnlockLocked() { - if (DEBUG) Log.d(TAG, "verifyUnlockLocked"); - mHandler.sendEmptyMessage(VERIFY_UNLOCK); - } - private void notifyStartedGoingToSleep() { - if (DEBUG) Log.d(TAG, "notifyStartedGoingToSleep"); + mLogger.logNotifyStartedGoingToSleep(); mHandler.sendEmptyMessage(NOTIFY_STARTED_GOING_TO_SLEEP); } private void notifyFinishedGoingToSleep() { - if (DEBUG) Log.d(TAG, "notifyFinishedGoingToSleep"); + mLogger.logNotifyFinishedGoingToSleep(); mHandler.sendEmptyMessage(NOTIFY_FINISHED_GOING_TO_SLEEP); } private void notifyStartedWakingUp() { - if (DEBUG) Log.d(TAG, "notifyStartedWakingUp"); + mLogger.logNotifyStartedWakingUp(); mHandler.sendEmptyMessage(NOTIFY_STARTED_WAKING_UP); } @@ -1886,7 +1861,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, */ private void showLocked(Bundle options) { Trace.beginSection("KeyguardViewMediator#showLocked acquiring mShowKeyguardWakeLock"); - if (DEBUG) Log.d(TAG, "showLocked"); + mLogger.logShowLocked(); // ensure we stay awake until we are finished displaying the keyguard mShowKeyguardWakeLock.acquire(); Message msg = mHandler.obtainMessage(SHOW, options); @@ -1903,7 +1878,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, */ private void hideLocked() { Trace.beginSection("KeyguardViewMediator#hideLocked"); - if (DEBUG) Log.d(TAG, "hideLocked"); + mLogger.logHideLocked(); Message msg = mHandler.obtainMessage(HIDE); mHandler.sendMessage(msg); Trace.endSection(); @@ -1982,8 +1957,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, public void onReceive(Context context, Intent intent) { if (DELAYED_KEYGUARD_ACTION.equals(intent.getAction())) { final int sequence = intent.getIntExtra("seq", 0); - if (DEBUG) Log.d(TAG, "received DELAYED_KEYGUARD_ACTION with seq = " - + sequence + ", mDelayedShowingSequence = " + mDelayedShowingSequence); + mLogger.logReceivedDelayedKeyguardAction(sequence, mDelayedShowingSequence); synchronized (KeyguardViewMediator.this) { if (mDelayedShowingSequence == sequence) { doKeyguardLocked(null); @@ -2016,7 +1990,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, private void keyguardDone() { Trace.beginSection("KeyguardViewMediator#keyguardDone"); - if (DEBUG) Log.d(TAG, "keyguardDone()"); + mLogger.logKeyguardDone(); userActivity(); EventLog.writeEvent(70000, 2); Message msg = mHandler.obtainMessage(KEYGUARD_DONE); @@ -2108,7 +2082,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, case KEYGUARD_DONE_PENDING_TIMEOUT: Trace.beginSection("KeyguardViewMediator#handleMessage" + " KEYGUARD_DONE_PENDING_TIMEOUT"); - Log.w(TAG, "Timeout while waiting for activity drawn!"); + mLogger.logTimeoutWhileActivityDrawn(); Trace.endSection(); break; case SYSTEM_READY: @@ -2119,14 +2093,15 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, }; private void tryKeyguardDone() { - if (DEBUG) { - Log.d(TAG, "tryKeyguardDone: pending - " + mKeyguardDonePending + ", animRan - " - + mHideAnimationRun + " animRunning - " + mHideAnimationRunning); - } + mLogger.logTryKeyguardDonePending( + mKeyguardDonePending, + mHideAnimationRun, + mHideAnimationRunning + ); if (!mKeyguardDonePending && mHideAnimationRun && !mHideAnimationRunning) { handleKeyguardDone(); } else if (!mHideAnimationRun) { - if (DEBUG) Log.d(TAG, "tryKeyguardDone: starting pre-hide animation"); + mLogger.logTryKeyguardDonePreHideAnimation(); mHideAnimationRun = true; mHideAnimationRunning = true; mKeyguardViewControllerLazy.get() @@ -2146,14 +2121,14 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, mLockPatternUtils.getDevicePolicyManager().reportKeyguardDismissed(currentUser); } }); - if (DEBUG) Log.d(TAG, "handleKeyguardDone"); + mLogger.logHandleKeyguardDone(); synchronized (this) { resetKeyguardDonePendingLocked(); } if (mGoingToSleep) { mUpdateMonitor.clearBiometricRecognizedWhenKeyguardDone(currentUser); - Log.i(TAG, "Device is going to sleep, aborting keyguardDone"); + mLogger.logDeviceGoingToSleep(); return; } setPendingLock(false); // user may have authenticated during the screen off animation @@ -2161,7 +2136,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, try { mExitSecureCallback.onKeyguardExitResult(true /* authenciated */); } catch (RemoteException e) { - Slog.w(TAG, "Failed to call onKeyguardExitResult()", e); + mLogger.logFailedToCallOnKeyguardExitResultTrue(e); } mExitSecureCallback = null; @@ -2204,9 +2179,9 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, private void handleKeyguardDoneDrawing() { Trace.beginSection("KeyguardViewMediator#handleKeyguardDoneDrawing"); synchronized(this) { - if (DEBUG) Log.d(TAG, "handleKeyguardDoneDrawing"); + mLogger.logHandleKeyguardDoneDrawing(); if (mWaitingUntilKeyguardVisible) { - if (DEBUG) Log.d(TAG, "handleKeyguardDoneDrawing: notifying mWaitingUntilKeyguardVisible"); + mLogger.logHandleKeyguardDoneDrawingNotifyingKeyguardVisible(); mWaitingUntilKeyguardVisible = false; notifyAll(); @@ -2256,12 +2231,11 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, private void updateActivityLockScreenState(boolean showing, boolean aodShowing) { mUiBgExecutor.execute(() -> { - if (DEBUG) { - Log.d(TAG, "updateActivityLockScreenState(" + showing + ", " + aodShowing + ")"); - } + mLogger.logUpdateActivityLockScreenState(showing, aodShowing); try { ActivityTaskManager.getService().setLockScreenShown(showing, aodShowing); } catch (RemoteException e) { + mLogger.logFailedToCallSetLockScreenShown(e); } }); } @@ -2278,10 +2252,10 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, } synchronized (KeyguardViewMediator.this) { if (!mSystemReady) { - if (DEBUG) Log.d(TAG, "ignoring handleShow because system is not ready."); + mLogger.logIgnoreHandleShow(); return; } else { - if (DEBUG) Log.d(TAG, "handleShow"); + mLogger.logHandleShow(); } mHiding = false; @@ -2313,7 +2287,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, @Override public void run() { Trace.beginSection("KeyguardViewMediator.mKeyGuardGoingAwayRunnable"); - if (DEBUG) Log.d(TAG, "keyguardGoingAway"); + mLogger.logKeyguardGoingAway(); mKeyguardViewControllerLazy.get().keyguardGoingAway(); int flags = 0; @@ -2357,7 +2331,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, try { ActivityTaskManager.getService().keyguardGoingAway(keyguardFlag); } catch (RemoteException e) { - Log.e(TAG, "Error while calling WindowManager", e); + mLogger.logFailedToCallKeyguardGoingAway(keyguardFlag, e); } }); Trace.endSection(); @@ -2365,7 +2339,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, }; private final Runnable mHideAnimationFinishedRunnable = () -> { - Log.e(TAG, "mHideAnimationFinishedRunnable#run"); + mLogger.logHideAnimationFinishedRunnable(); mHideAnimationRunning = false; tryKeyguardDone(); }; @@ -2385,14 +2359,14 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, } synchronized (KeyguardViewMediator.this) { - if (DEBUG) Log.d(TAG, "handleHide"); + mLogger.logHandleHide(); if (mustNotUnlockCurrentUser()) { // In split system user mode, we never unlock system user. The end user has to // switch to another user. // TODO: We should stop it early by disabling the swipe up flow. Right now swipe up // still completes and makes the screen blank. - if (DEBUG) Log.d(TAG, "Split system user, quit unlocking."); + mLogger.logSplitSystemUserQuitUnlocking(); mKeyguardExitAnimationRunner = null; return; } @@ -2424,8 +2398,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback) { Trace.beginSection("KeyguardViewMediator#handleStartKeyguardExitAnimation"); - Log.d(TAG, "handleStartKeyguardExitAnimation startTime=" + startTime - + " fadeoutDuration=" + fadeoutDuration); + mLogger.logHandleStartKeyguardExitAnimation(startTime, fadeoutDuration); synchronized (KeyguardViewMediator.this) { // Tell ActivityManager that we canceled the keyguard animation if @@ -2441,7 +2414,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, try { finishedCallback.onAnimationFinished(); } catch (RemoteException e) { - Slog.w(TAG, "Failed to call onAnimationFinished", e); + mLogger.logFailedToCallOnAnimationFinished(e); } } setShowingLocked(mShowing, true /* force */); @@ -2454,7 +2427,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, LatencyTracker.getInstance(mContext) .onActionEnd(LatencyTracker.ACTION_LOCKSCREEN_UNLOCK); - if (KeyguardService.sEnableRemoteKeyguardGoingAwayAnimation && runner != null + if (runner != null && finishedCallback != null) { // Wrap finishedCallback to clean up the keyguard state once the animation is done. IRemoteAnimationFinishedCallback callback = @@ -2464,7 +2437,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, try { finishedCallback.onAnimationFinished(); } catch (RemoteException e) { - Slog.w(TAG, "Failed to call onAnimationFinished", e); + mLogger.logFailedToCallOnAnimationFinished(e); } onKeyguardExitFinished(); mKeyguardViewControllerLazy.get().hide(0 /* startTime */, @@ -2483,13 +2456,12 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, runner.onAnimationStart(WindowManager.TRANSIT_KEYGUARD_GOING_AWAY, apps, wallpapers, nonApps, callback); } catch (RemoteException e) { - Slog.w(TAG, "Failed to call onAnimationStart", e); + mLogger.logFailedToCallOnAnimationStart(e); } // When remaining on the shade, there's no need to do a fancy remote animation, // it will dismiss the panel in that case. - } else if (KeyguardService.sEnableRemoteKeyguardGoingAwayAnimation - && !mStatusBarStateController.leaveOpenOnKeyguardHide() + } else if (!mStatusBarStateController.leaveOpenOnKeyguardHide() && apps != null && apps.length > 0) { mSurfaceBehindRemoteAnimationFinishedCallback = finishedCallback; mSurfaceBehindRemoteAnimationRunning = true; @@ -2548,7 +2520,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, try { finishedCallback.onAnimationFinished(); } catch (RemoteException e) { - Slog.e(TAG, "RemoteException"); + mLogger.logFailedToCallOnAnimationFinished(e); } finally { mInteractionJankMonitor.end(CUJ_LOCKSCREEN_UNLOCK_ANIMATION); } @@ -2559,7 +2531,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, try { finishedCallback.onAnimationFinished(); } catch (RemoteException e) { - Slog.e(TAG, "RemoteException"); + mLogger.logFailedToCallOnAnimationFinished(e); } finally { mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_UNLOCK_ANIMATION); } @@ -2628,11 +2600,9 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, * @param cancelled {@code true} if the animation was cancelled before it finishes. */ public void onKeyguardExitRemoteAnimationFinished(boolean cancelled) { - Log.d(TAG, "onKeyguardExitRemoteAnimationFinished"); + mLogger.logOnKeyguardExitRemoteAnimationFinished(); if (!mSurfaceBehindRemoteAnimationRunning && !mSurfaceBehindRemoteAnimationRequested) { - Log.d(TAG, "skip onKeyguardExitRemoteAnimationFinished cancelled=" + cancelled - + " surfaceAnimationRunning=" + mSurfaceBehindRemoteAnimationRunning - + " surfaceAnimationRequested=" + mSurfaceBehindRemoteAnimationRequested); + mLogger.logSkipOnKeyguardExitRemoteAnimationFinished(cancelled, false, false); return; } @@ -2646,13 +2616,13 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, onKeyguardExitFinished(); if (mKeyguardStateController.isDismissingFromSwipe() || wasShowing) { - Log.d(TAG, "onKeyguardExitRemoteAnimationFinished" - + "#hideKeyguardViewAfterRemoteAnimation"); + mLogger.logOnKeyguardExitRemoteAnimationFinishedHideKeyguardView(); mKeyguardUnlockAnimationControllerLazy.get().hideKeyguardViewAfterRemoteAnimation(); } else { - Log.d(TAG, "skip hideKeyguardViewAfterRemoteAnimation" - + " dismissFromSwipe=" + mKeyguardStateController.isDismissingFromSwipe() - + " wasShowing=" + wasShowing); + mLogger.logSkipHideKeyguardViewAfterRemoteAnimation( + mKeyguardStateController.isDismissingFromSwipe(), + wasShowing + ); } finishSurfaceBehindRemoteAnimation(cancelled); @@ -2749,7 +2719,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, } if (mStatusBarManager == null) { - Log.w(TAG, "Could not get status bar manager"); + mLogger.logCouldNotGetStatusBarManager(); } else { // Disable aspects of the system/status/navigation bars that must not be re-enabled by // windows that appear on top, ever @@ -2767,12 +2737,13 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, } flags |= StatusBarManager.DISABLE_RECENT; } - - if (DEBUG) { - Log.d(TAG, "adjustStatusBarLocked: mShowing=" + mShowing + " mOccluded=" + mOccluded - + " isSecure=" + isSecure() + " force=" + forceHideHomeRecentsButtons - + " --> flags=0x" + Integer.toHexString(flags)); - } + mLogger.logAdjustStatusBarLocked( + mShowing, + mOccluded, + isSecure(), + forceHideHomeRecentsButtons, + Integer.toHexString(flags) + ); mStatusBarManager.disable(flags); } @@ -2784,7 +2755,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, */ private void handleReset() { synchronized (KeyguardViewMediator.this) { - if (DEBUG) Log.d(TAG, "handleReset"); + mLogger.logHandleReset(); mKeyguardViewControllerLazy.get().reset(true /* hideBouncerWhenShowing */); } } @@ -2796,7 +2767,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, private void handleVerifyUnlock() { Trace.beginSection("KeyguardViewMediator#handleVerifyUnlock"); synchronized (KeyguardViewMediator.this) { - if (DEBUG) Log.d(TAG, "handleVerifyUnlock"); + mLogger.logHandleVerifyUnlock(); setShowingLocked(true); mKeyguardViewControllerLazy.get().dismissAndCollapse(); } @@ -2805,7 +2776,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, private void handleNotifyStartedGoingToSleep() { synchronized (KeyguardViewMediator.this) { - if (DEBUG) Log.d(TAG, "handleNotifyStartedGoingToSleep"); + mLogger.logHandleNotifyStartedGoingToSleep(); mKeyguardViewControllerLazy.get().onStartedGoingToSleep(); } } @@ -2816,7 +2787,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, */ private void handleNotifyFinishedGoingToSleep() { synchronized (KeyguardViewMediator.this) { - if (DEBUG) Log.d(TAG, "handleNotifyFinishedGoingToSleep"); + mLogger.logHandleNotifyFinishedGoingToSleep(); mKeyguardViewControllerLazy.get().onFinishedGoingToSleep(); } } @@ -2824,7 +2795,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, private void handleNotifyStartedWakingUp() { Trace.beginSection("KeyguardViewMediator#handleMotifyStartedWakingUp"); synchronized (KeyguardViewMediator.this) { - if (DEBUG) Log.d(TAG, "handleNotifyWakingUp"); + mLogger.logHandleNotifyWakingUp(); mKeyguardViewControllerLazy.get().onStartedWakingUp(); } Trace.endSection(); @@ -3090,7 +3061,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, try { callback.onShowingStateChanged(showing, KeyguardUpdateMonitor.getCurrentUser()); } catch (RemoteException e) { - Slog.w(TAG, "Failed to call onShowingStateChanged", e); + mLogger.logFailedToCallOnShowingStateChanged(e); if (e instanceof DeadObjectException) { mKeyguardStateCallbacks.remove(callback); } @@ -3109,7 +3080,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, try { mKeyguardStateCallbacks.get(i).onTrustedChanged(trusted); } catch (RemoteException e) { - Slog.w(TAG, "Failed to call notifyTrustedChangedLocked", e); + mLogger.logFailedToCallNotifyTrustedChangedLocked(e); if (e instanceof DeadObjectException) { mKeyguardStateCallbacks.remove(i); } @@ -3132,7 +3103,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, callback.onTrustedChanged(mUpdateMonitor.getUserHasTrust( KeyguardUpdateMonitor.getCurrentUser())); } catch (RemoteException e) { - Slog.w(TAG, "Failed to call to IKeyguardStateCallback", e); + mLogger.logFailedToCallIKeyguardStateCallback(e); } } } @@ -3209,7 +3180,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, // internal state to reflect that immediately, vs. waiting for the launch animator to // begin. Otherwise, calls to setShowingLocked, etc. will not know that we're about to // be occluded and might re-show the keyguard. - Log.d(TAG, "OccludeAnimator#onAnimationStart. Set occluded = true."); + mLogger.logOccludeAnimatorOnAnimationStart(); setOccluded(true /* isOccluded */, false /* animate */); } @@ -3217,8 +3188,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, public void onAnimationCancelled(boolean isKeyguardOccluded) throws RemoteException { super.onAnimationCancelled(isKeyguardOccluded); - Log.d(TAG, "Occlude animation cancelled by WM. " - + "Setting occluded state to: " + isKeyguardOccluded); + mLogger.logOccludeAnimationCancelledByWm(isKeyguardOccluded); setOccluded(isKeyguardOccluded /* occluded */, false /* animate */); } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java index 56f1ac46a875..fdea62dc0cbe 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -30,6 +30,7 @@ import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent; import com.android.keyguard.dagger.KeyguardStatusBarViewComponent; import com.android.keyguard.dagger.KeyguardStatusViewComponent; import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; +import com.android.keyguard.logging.KeyguardViewMediatorLogger; import com.android.keyguard.mediator.ScreenOnCoordinator; import com.android.systemui.animation.ActivityLaunchAnimator; import com.android.systemui.broadcast.BroadcastDispatcher; @@ -105,7 +106,8 @@ public class KeyguardModule { InteractionJankMonitor interactionJankMonitor, DreamOverlayStateController dreamOverlayStateController, Lazy<NotificationShadeWindowController> notificationShadeWindowController, - Lazy<ActivityLaunchAnimator> activityLaunchAnimator) { + Lazy<ActivityLaunchAnimator> activityLaunchAnimator, + KeyguardViewMediatorLogger logger) { return new KeyguardViewMediator( context, falsingCollector, @@ -132,7 +134,8 @@ public class KeyguardModule { interactionJankMonitor, dreamOverlayStateController, notificationShadeWindowController, - activityLaunchAnimator); + activityLaunchAnimator, + logger); } /** */ diff --git a/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt b/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt index 6124e10144f2..77ad8069f273 100644 --- a/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt +++ b/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt @@ -158,8 +158,13 @@ class LogBuffer @JvmOverloads constructor( * add more detail to every log may do more to improve overall logging than adding more logs * with this method. */ - fun log(tag: String, level: LogLevel, @CompileTimeConstant message: String) = - log(tag, level, {str1 = message}, { str1!! }) + fun log( + tag: String, + level: LogLevel, + @CompileTimeConstant message: String, + exception: Throwable? = null + ) = + log(tag, level, {str1 = message}, { str1!! }, exception) /** * You should call [log] instead of this method. diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardUpdateMonitorLog.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardUpdateMonitorLog.kt index 323ee21953ea..684839f2b124 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardUpdateMonitorLog.kt +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardUpdateMonitorLog.kt @@ -1,4 +1,7 @@ package com.android.systemui.log.dagger +import javax.inject.Qualifier + /** A [com.android.systemui.log.LogBuffer] for KeyguardUpdateMonitor. */ +@Qualifier annotation class KeyguardUpdateMonitorLog diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt new file mode 100644 index 000000000000..88e227b8ae35 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.log.dagger + +import javax.inject.Qualifier + +/** A [com.android.systemui.log.LogBuffer] for KeyguardViewMediator. */ +@Qualifier +annotation class KeyguardViewMediatorLog
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java index c2a87649adef..9af42f825e00 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java @@ -305,4 +305,15 @@ public class LogModule { public static LogBuffer provideKeyguardUpdateMonitorLogBuffer(LogBufferFactory factory) { return factory.create("KeyguardUpdateMonitorLog", 200); } + + /** + * Provides a {@link LogBuffer} for use by + * {@link com.android.systemui.keyguard.KeyguardViewMediator}. + */ + @Provides + @SysUISingleton + @KeyguardViewMediatorLog + public static LogBuffer provideKeyguardViewMediatorLogBuffer(LogBufferFactory factory) { + return factory.create("KeyguardViewMediatorLog", 100); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java index e754d5db4186..33c1f99c6f4c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java @@ -477,15 +477,6 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp if (!wasDeviceInteractive) { mPendingShowBouncer = true; } else { - // If the keyguard unlock controller is going to handle the unlock animation, it - // will fling the panel collapsed when it's ready. - if (!mKeyguardUnlockAnimationController.willHandleUnlockAnimation()) { - mShadeController.animateCollapsePanels( - CommandQueue.FLAG_EXCLUDE_NONE, - true /* force */, - false /* delayed */, - BIOMETRIC_COLLAPSE_SPEEDUP_FACTOR); - } mPendingShowBouncer = false; mKeyguardViewController.notifyKeyguardAuthenticated( false /* strongAuth */); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index e444e0a1e2c5..a1904859cd4c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -152,7 +152,6 @@ import com.android.systemui.flags.Flags; import com.android.systemui.fragments.ExtensionFragmentListener; import com.android.systemui.fragments.FragmentHostManager; import com.android.systemui.fragments.FragmentService; -import com.android.systemui.keyguard.KeyguardService; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.ScreenLifecycle; @@ -1875,11 +1874,9 @@ public class CentralSurfacesImpl extends CoreStartable implements return true; } - // If we are locked and have to dismiss the keyguard, only animate if remote unlock - // animations are enabled. We also don't animate non-activity launches as they can break the - // animation. + // We don't animate non-activity launches as they can break the animation. // TODO(b/184121838): Support non activity launches on the lockscreen. - return isActivityIntent && KeyguardService.sEnableRemoteKeyguardGoingAwayAnimation; + return isActivityIntent; } /** Whether we should animate an activity launch. */ diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt index 328ad39cddd5..58d906907488 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt @@ -41,11 +41,13 @@ import org.mockito.junit.MockitoJUnit @SmallTest class AuthBiometricFingerprintAndFaceViewTest : SysuiTestCase() { - @JvmField @Rule + @JvmField + @Rule var mockitoRule = MockitoJUnit.rule() @Mock private lateinit var callback: AuthBiometricView.Callback + @Mock private lateinit var panelController: AuthPanelController @@ -67,6 +69,7 @@ class AuthBiometricFingerprintAndFaceViewTest : SysuiTestCase() { fun fingerprintSuccessDoesNotRequireExplicitConfirmation() { biometricView.onDialogAnimatedIn() biometricView.onAuthenticationSucceeded(TYPE_FINGERPRINT) + TestableLooper.get(this).moveTimeForward(1000) waitForIdleSync() assertThat(biometricView.isAuthenticated).isTrue() @@ -86,6 +89,7 @@ class AuthBiometricFingerprintAndFaceViewTest : SysuiTestCase() { // icon acts as confirm button biometricView.mIconView.performClick() + TestableLooper.get(this).moveTimeForward(1000) waitForIdleSync() assertThat(biometricView.isAuthenticated).isTrue() @@ -102,6 +106,7 @@ class AuthBiometricFingerprintAndFaceViewTest : SysuiTestCase() { verify(callback, never()).onAction(AuthBiometricView.Callback.ACTION_ERROR) biometricView.onError(TYPE_FINGERPRINT, "that's a nope") + TestableLooper.get(this).moveTimeForward(1000) waitForIdleSync() verify(callback).onAction(AuthBiometricView.Callback.ACTION_ERROR) diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt index 687cb517b2f4..bce98cf116d4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt @@ -42,20 +42,23 @@ import org.mockito.junit.MockitoJUnit @SmallTest class AuthBiometricFingerprintViewTest : SysuiTestCase() { - @JvmField @Rule + @JvmField + @Rule val mockitoRule = MockitoJUnit.rule() @Mock private lateinit var callback: AuthBiometricView.Callback + @Mock private lateinit var panelController: AuthPanelController private lateinit var biometricView: AuthBiometricView private fun createView(allowDeviceCredential: Boolean = false): AuthBiometricFingerprintView { - val view = R.layout.auth_biometric_fingerprint_view.asTestAuthBiometricView( + val view: AuthBiometricFingerprintView = + R.layout.auth_biometric_fingerprint_view.asTestAuthBiometricView( mContext, callback, panelController, allowDeviceCredential = allowDeviceCredential - ) as AuthBiometricFingerprintView + ) waitForIdleSync() return view } @@ -73,6 +76,7 @@ class AuthBiometricFingerprintViewTest : SysuiTestCase() { @Test fun testOnAuthenticationSucceeded_noConfirmationRequired_sendsActionAuthenticated() { biometricView.onAuthenticationSucceeded(BiometricAuthenticator.TYPE_FINGERPRINT) + TestableLooper.get(this).moveTimeForward(1000) waitForIdleSync() assertThat(biometricView.isAuthenticated).isTrue() @@ -83,6 +87,7 @@ class AuthBiometricFingerprintViewTest : SysuiTestCase() { fun testOnAuthenticationSucceeded_confirmationRequired_updatesDialogContents() { biometricView.setRequireConfirmation(true) biometricView.onAuthenticationSucceeded(BiometricAuthenticator.TYPE_FINGERPRINT) + TestableLooper.get(this).moveTimeForward(1000) waitForIdleSync() // TODO: this should be tested in the subclasses @@ -104,6 +109,7 @@ class AuthBiometricFingerprintViewTest : SysuiTestCase() { @Test fun testPositiveButton_sendsActionAuthenticated() { biometricView.mConfirmButton.performClick() + TestableLooper.get(this).moveTimeForward(1000) waitForIdleSync() verify(callback).onAction(AuthBiometricView.Callback.ACTION_AUTHENTICATED) @@ -114,6 +120,7 @@ class AuthBiometricFingerprintViewTest : SysuiTestCase() { fun testNegativeButton_beforeAuthentication_sendsActionButtonNegative() { biometricView.onDialogAnimatedIn() biometricView.mNegativeButton.performClick() + TestableLooper.get(this).moveTimeForward(1000) waitForIdleSync() verify(callback).onAction(AuthBiometricView.Callback.ACTION_BUTTON_NEGATIVE) @@ -126,6 +133,7 @@ class AuthBiometricFingerprintViewTest : SysuiTestCase() { assertThat(biometricView.mNegativeButton.visibility).isEqualTo(View.GONE) biometricView.mCancelButton.performClick() + TestableLooper.get(this).moveTimeForward(1000) waitForIdleSync() verify(callback).onAction(AuthBiometricView.Callback.ACTION_USER_CANCELED) @@ -134,6 +142,7 @@ class AuthBiometricFingerprintViewTest : SysuiTestCase() { @Test fun testTryAgainButton_sendsActionTryAgain() { biometricView.mTryAgainButton.performClick() + TestableLooper.get(this).moveTimeForward(1000) waitForIdleSync() verify(callback).onAction(AuthBiometricView.Callback.ACTION_BUTTON_TRY_AGAIN) @@ -144,6 +153,7 @@ class AuthBiometricFingerprintViewTest : SysuiTestCase() { @Test fun testOnErrorSendsActionError() { biometricView.onError(BiometricAuthenticator.TYPE_FACE, "testError") + TestableLooper.get(this).moveTimeForward(1000) waitForIdleSync() verify(callback).onAction(eq(AuthBiometricView.Callback.ACTION_ERROR)) @@ -156,6 +166,7 @@ class AuthBiometricFingerprintViewTest : SysuiTestCase() { val message = "another error" biometricView.onError(BiometricAuthenticator.TYPE_FACE, message) + TestableLooper.get(this).moveTimeForward(1000) waitForIdleSync() assertThat(biometricView.isAuthenticating).isFalse() @@ -178,6 +189,7 @@ class AuthBiometricFingerprintViewTest : SysuiTestCase() { val view = View(mContext) biometricView.setBackgroundView(view) biometricView.onAuthenticationSucceeded(BiometricAuthenticator.TYPE_FINGERPRINT) + waitForIdleSync() view.performClick() verify(callback, never()) @@ -225,14 +237,14 @@ class AuthBiometricFingerprintViewTest : SysuiTestCase() { biometricView.onSaveState(state) assertThat(biometricView.mTryAgainButton.visibility).isEqualTo(View.GONE) assertThat(state.getInt(AuthDialog.KEY_BIOMETRIC_TRY_AGAIN_VISIBILITY)) - .isEqualTo(View.GONE) + .isEqualTo(View.GONE) assertThat(state.getInt(AuthDialog.KEY_BIOMETRIC_STATE)) - .isEqualTo(AuthBiometricView.STATE_ERROR) + .isEqualTo(AuthBiometricView.STATE_ERROR) assertThat(biometricView.mIndicatorView.visibility).isEqualTo(View.VISIBLE) assertThat(state.getBoolean(AuthDialog.KEY_BIOMETRIC_INDICATOR_ERROR_SHOWING)).isTrue() assertThat(biometricView.mIndicatorView.text).isEqualTo(failureMessage) assertThat(state.getString(AuthDialog.KEY_BIOMETRIC_INDICATOR_STRING)) - .isEqualTo(failureMessage) + .isEqualTo(failureMessage) // TODO: Test dialog size. Should move requireConfirmation to buildBiometricPromptBundle diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java index 21c018a0419d..6e89bb90e558 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -48,6 +48,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardDisplayManager; import com.android.keyguard.KeyguardSecurityView; import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.keyguard.logging.KeyguardViewMediatorLogger; import com.android.keyguard.mediator.ScreenOnCoordinator; import com.android.systemui.SysuiTestCase; import com.android.systemui.animation.ActivityLaunchAnimator; @@ -106,6 +107,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { private @Mock Lazy<NotificationShadeWindowController> mNotificationShadeWindowControllerLazy; private @Mock DreamOverlayStateController mDreamOverlayStateController; private @Mock ActivityLaunchAnimator mActivityLaunchAnimator; + private @Mock KeyguardViewMediatorLogger mLogger; private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake(); private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); @@ -262,7 +264,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { mInteractionJankMonitor, mDreamOverlayStateController, mNotificationShadeWindowControllerLazy, - () -> mActivityLaunchAnimator); + () -> mActivityLaunchAnimator, + mLogger); mViewMediator.start(); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/LogBufferTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/LogBufferTest.kt index 56aff3c2fc8b..7b12eb75e841 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/log/LogBufferTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/log/LogBufferTest.kt @@ -41,6 +41,18 @@ class LogBufferTest : SysuiTestCase() { } @Test + fun log_shouldSaveLogToBufferWithException() { + val exception = createTestException("Some exception test message", "SomeExceptionTestClass") + buffer.log("Test", LogLevel.INFO, "Some test message", exception) + + val dumpedString = dumpBuffer() + + assertThat(dumpedString).contains("Some test message") + assertThat(dumpedString).contains("Some exception test message") + assertThat(dumpedString).contains("SomeExceptionTestClass") + } + + @Test fun log_shouldRotateIfLogBufferIsFull() { buffer.log("Test", LogLevel.INFO, "This should be rotated") buffer.log("Test", LogLevel.INFO, "New test message") diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index b34482f0964f..3324c526ecc2 100644 --- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java @@ -354,16 +354,24 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ if (supportsFlagForNotImportantViews(info)) { if ((info.flags & AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0) { - mFetchFlags |= AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; + mFetchFlags |= + AccessibilityNodeInfo.FLAG_SERVICE_REQUESTS_INCLUDE_NOT_IMPORTANT_VIEWS; } else { - mFetchFlags &= ~AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; + mFetchFlags &= + ~AccessibilityNodeInfo.FLAG_SERVICE_REQUESTS_INCLUDE_NOT_IMPORTANT_VIEWS; } } if ((info.flags & AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS) != 0) { - mFetchFlags |= AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS; + mFetchFlags |= AccessibilityNodeInfo.FLAG_SERVICE_REQUESTS_REPORT_VIEW_IDS; } else { - mFetchFlags &= ~AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS; + mFetchFlags &= ~AccessibilityNodeInfo.FLAG_SERVICE_REQUESTS_REPORT_VIEW_IDS; + } + + if (mAccessibilityServiceInfo.isAccessibilityTool()) { + mFetchFlags |= AccessibilityNodeInfo.FLAG_SERVICE_IS_ACCESSIBILITY_TOOL; + } else { + mFetchFlags &= ~AccessibilityNodeInfo.FLAG_SERVICE_IS_ACCESSIBILITY_TOOL; } mRequestTouchExplorationMode = (info.flags @@ -1522,9 +1530,16 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ return false; } + final boolean includeNotImportantViews = (mFetchFlags + & AccessibilityNodeInfo.FLAG_SERVICE_REQUESTS_INCLUDE_NOT_IMPORTANT_VIEWS) != 0; if ((event.getWindowId() != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) && !event.isImportantForAccessibility() - && (mFetchFlags & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) { + && !includeNotImportantViews) { + return false; + } + + if (event.isAccessibilityDataPrivate() + && (mFetchFlags & AccessibilityNodeInfo.FLAG_SERVICE_IS_ACCESSIBILITY_TOOL) == 0) { return false; } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 6eabc981e9fe..6a6d2bb44d48 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -3693,6 +3693,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub info.setCapabilities(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT); info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS; info.flags |= AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; + info.setAccessibilityTool(true); final AccessibilityUserState userState; synchronized (mLock) { userState = getCurrentUserStateLocked(); diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index 265fbc510259..448d70c6b9a4 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -607,10 +607,8 @@ public class CompanionDeviceManagerService extends SystemService { @Override public void legacyDisassociate(String deviceMacAddress, String packageName, int userId) { - if (DEBUG) { - Log.i(TAG, "legacyDisassociate() pkg=u" + userId + "/" + packageName - + ", macAddress=" + deviceMacAddress); - } + Log.i(TAG, "legacyDisassociate() pkg=u" + userId + "/" + packageName + + ", macAddress=" + deviceMacAddress); requireNonNull(deviceMacAddress); requireNonNull(packageName); @@ -622,7 +620,7 @@ public class CompanionDeviceManagerService extends SystemService { @Override public void disassociate(int associationId) { - if (DEBUG) Log.i(TAG, "disassociate() associationId=" + associationId); + Log.i(TAG, "disassociate() associationId=" + associationId); final AssociationInfo association = getAssociationWithCallerChecks(associationId); diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 5cb25d36d94b..36908ce8c7b3 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -49,10 +49,12 @@ import android.app.BroadcastOptions; import android.app.IActivityController; import android.app.IActivityManager; import android.app.IActivityTaskManager; +import android.app.IProcessObserver; import android.app.IStopUserCallback; import android.app.IUidObserver; import android.app.IUserSwitchObserver; import android.app.KeyguardManager; +import android.app.ProcessStateEnum; import android.app.ProfilerInfo; import android.app.RemoteServiceException.CrashedByAdbException; import android.app.UserSwitchObserver; @@ -359,6 +361,8 @@ final class ActivityManagerShellCommand extends ShellCommand { return runSetBgRestrictionLevel(pw); case "get-bg-restriction-level": return runGetBgRestrictionLevel(pw); + case "observe-foreground-process": + return runGetCurrentForegroundProcess(pw, mInternal, mTaskInterface); default: return handleDefaultCommands(cmd); } @@ -3230,6 +3234,82 @@ final class ActivityManagerShellCommand extends ShellCommand { return -1; } + private int runGetCurrentForegroundProcess(PrintWriter pw, + IActivityManager iam, IActivityTaskManager iatm) + throws RemoteException { + + ProcessObserver observer = new ProcessObserver(pw, iam, iatm, mInternal); + iam.registerProcessObserver(observer); + + final InputStream mInput = getRawInputStream(); + InputStreamReader converter = new InputStreamReader(mInput); + BufferedReader in = new BufferedReader(converter); + String line; + try { + while ((line = in.readLine()) != null) { + boolean addNewline = true; + if (line.length() <= 0) { + addNewline = false; + } else if ("q".equals(line) || "quit".equals(line)) { + break; + } else { + pw.println("Invalid command: " + line); + } + if (addNewline) { + pw.println(""); + } + pw.flush(); + } + } catch (IOException e) { + e.printStackTrace(); + pw.flush(); + } finally { + iam.unregisterProcessObserver(observer); + } + return 0; + } + + static final class ProcessObserver extends IProcessObserver.Stub { + + private PrintWriter mPw; + private IActivityManager mIam; + private IActivityTaskManager mIatm; + private ActivityManagerService mInternal; + + ProcessObserver(PrintWriter mPw, IActivityManager mIam, + IActivityTaskManager mIatm, ActivityManagerService ams) { + this.mPw = mPw; + this.mIam = mIam; + this.mIatm = mIatm; + this.mInternal = ams; + } + + @Override + public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) { + if (foregroundActivities) { + try { + int prcState = mIam.getUidProcessState(uid, "android"); + int topPid = mInternal.getTopApp().getPid(); + if (prcState == ProcessStateEnum.TOP && topPid == pid) { + mPw.println("New foreground process: " + pid); + } + mPw.flush(); + } catch (RemoteException e) { + mPw.println("Error occurred in binder call"); + mPw.flush(); + } + } + } + + @Override + public void onForegroundServicesChanged(int pid, int uid, int serviceTypes) { + } + + @Override + public void onProcessDied(int pid, int uid) { + } + } + private int runSetMemoryFactor(PrintWriter pw) throws RemoteException { final String levelArg = getNextArgRequired(); @MemFactor int level = ADJ_MEM_FACTOR_NOTHING; diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 12aa66b84d85..de28be009c24 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -17,7 +17,6 @@ package com.android.server.am; import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL; -import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL_IMPLICIT; import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA; import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION; import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE; @@ -2566,16 +2565,10 @@ public class OomAdjuster { case PROCESS_STATE_BOUND_TOP: return PROCESS_CAPABILITY_NETWORK; case PROCESS_STATE_FOREGROUND_SERVICE: - if (psr.hasForegroundServices()) { - // Capability from FGS are conditional depending on foreground service type in - // manifest file and the mAllowWhileInUsePermissionInFgs flag. - return PROCESS_CAPABILITY_NETWORK; - } else { - // process has no FGS, the PROCESS_STATE_FOREGROUND_SERVICE is from client. - // the implicit capability could be removed in the future, client should use - // BIND_INCLUDE_CAPABILITY flag. - return PROCESS_CAPABILITY_ALL_IMPLICIT | PROCESS_CAPABILITY_NETWORK; - } + // Capability from foreground service is conditional depending on + // foregroundServiceType in the manifest file and the + // mAllowWhileInUsePermissionInFgs flag. + return PROCESS_CAPABILITY_NETWORK; case PROCESS_STATE_BOUND_FOREGROUND_SERVICE: return PROCESS_CAPABILITY_NETWORK; default: diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java index 134e2061c090..1302e226eba3 100644 --- a/services/core/java/com/android/server/app/GameManagerService.java +++ b/services/core/java/com/android/server/app/GameManagerService.java @@ -502,14 +502,6 @@ public final class GameManagerService extends IGameManagerService.Stub { GamePackageConfiguration(PackageManager packageManager, String packageName, int userId) { mPackageName = packageName; - - // set flag default values - mPerfModeOptedIn = false; - mBatteryModeOptedIn = false; - mAllowDownscale = true; - mAllowAngle = true; - mAllowFpsOverride = true; - try { final ApplicationInfo ai = packageManager.getApplicationInfoAsUser(packageName, PackageManager.GET_META_DATA, userId); @@ -519,6 +511,12 @@ public final class GameManagerService extends IGameManagerService.Stub { mBatteryModeOptedIn = ai.metaData.getBoolean(METADATA_BATTERY_MODE_ENABLE); mAllowDownscale = ai.metaData.getBoolean(METADATA_WM_ALLOW_DOWNSCALE, true); mAllowAngle = ai.metaData.getBoolean(METADATA_ANGLE_ALLOW_ANGLE, true); + } else { + mPerfModeOptedIn = false; + mBatteryModeOptedIn = false; + mAllowDownscale = true; + mAllowAngle = true; + mAllowFpsOverride = true; } } } catch (NameNotFoundException e) { diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index 61e2419e2d14..9db9837ffc45 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -899,7 +899,7 @@ final class InstallPackageHelper { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages"); reconciledPackages = ReconcilePackageUtils.reconcilePackages( reconcileRequest, mSharedLibraries, - mPm.mSettings.getKeySetManagerService(), mPm.mSettings, mContext); + mPm.mSettings.getKeySetManagerService(), mPm.mSettings); } catch (ReconcileFailure e) { for (InstallRequest request : requests) { request.mInstallResult.setError("Reconciliation failed...", e); @@ -3669,7 +3669,7 @@ final class InstallPackageHelper { final Map<String, ReconciledPackage> reconcileResult = ReconcilePackageUtils.reconcilePackages(reconcileRequest, mSharedLibraries, mPm.mSettings.getKeySetManagerService(), - mPm.mSettings, mContext); + mPm.mSettings); if ((scanFlags & SCAN_AS_APEX) == 0) { appIdCreated = optimisticallyRegisterAppId(scanResult); } else { diff --git a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java index 3c4780171ee5..d6a133e43789 100644 --- a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java +++ b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java @@ -16,7 +16,6 @@ package com.android.server.pm; -import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK; import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; import static android.content.pm.SigningDetails.CapabilityMergeRule.MERGE_RESTRICTED_CAPABILITY; @@ -24,31 +23,25 @@ import static android.content.pm.SigningDetails.CapabilityMergeRule.MERGE_RESTRI import static com.android.server.pm.PackageManagerService.SCAN_BOOTING; import static com.android.server.pm.PackageManagerService.SCAN_DONT_KILL_APP; -import android.content.Context; import android.content.pm.PackageManager; -import android.content.pm.PermissionInfo; import android.content.pm.SharedLibraryInfo; import android.content.pm.SigningDetails; import android.os.SystemProperties; -import android.permission.PermissionManager; import android.util.ArrayMap; import android.util.Log; import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.parsing.pkg.ParsedPackage; -import com.android.server.pm.pkg.component.ParsedUsesPermission; import com.android.server.pm.pkg.parsing.ParsingPackageUtils; import com.android.server.utils.WatchedLongSparseArray; -import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Map; final class ReconcilePackageUtils { public static Map<String, ReconciledPackage> reconcilePackages( final ReconcileRequest request, SharedLibrariesImpl sharedLibraries, - KeySetManagerService ksms, Settings settings, Context context) + KeySetManagerService ksms, Settings settings) throws ReconcileFailure { final Map<String, ScanResult> scannedPackages = request.mScannedPackages; @@ -168,43 +161,11 @@ final class ReconcilePackageUtils { // over the latest parsed certs. signingDetails = parsedPackage.getSigningDetails(); - // if this is a sharedUser, check to see if the new package is signed by a - // newer signing certificate than the existing one, and if so, copy over the new + // if this is is a sharedUser, check to see if the new package is signed by a + // newer + // signing certificate than the existing one, and if so, copy over the new // details if (sharedUserSetting != null) { - if (prepareResult != null && !prepareResult.mPackageToScan.isTestOnly() - && sharedUserSetting.isPrivileged() - && !signatureCheckPs.isSystem()) { - final List<ParsedUsesPermission> usesPermissions = - parsedPackage.getUsesPermissions(); - final List<String> usesPrivilegedPermissions = new ArrayList<>(); - final PermissionManager permissionManager = context.getSystemService( - PermissionManager.class); - // Check if the app requests any privileged permissions because that - // violates the privapp-permissions allowlist check during boot. - if (permissionManager != null) { - for (int i = 0; i < usesPermissions.size(); i++) { - final String permissionName = usesPermissions.get(i).getName(); - final PermissionInfo permissionInfo = - permissionManager.getPermissionInfo(permissionName, 0); - if (permissionInfo != null - && (permissionInfo.getProtectionFlags() - & PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0) { - usesPrivilegedPermissions.add(permissionName); - } - } - } - - if (!usesPrivilegedPermissions.isEmpty()) { - throw new ReconcileFailure(INSTALL_FAILED_INVALID_APK, - "Non-system package: " + parsedPackage.getPackageName() - + " shares signature and sharedUserId with" - + " a privileged package but requests" - + " privileged permissions that are not" - + " allowed: " + Arrays.toString( - usesPrivilegedPermissions.toArray())); - } - } // Attempt to merge the existing lineage for the shared SigningDetails with // the lineage of the new package; if the shared SigningDetails are not // returned this indicates the new package added new signers to the lineage diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 672c13c2dbf9..b31402cc935b 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -54,6 +54,7 @@ import android.content.pm.ShortcutServiceInternal; import android.content.pm.UserInfo; import android.content.pm.UserInfo.UserInfoFlag; import android.content.pm.UserProperties; +import android.content.pm.parsing.FrameworkParsingPackageUtils; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; @@ -5368,6 +5369,11 @@ public class UserManagerService extends IUserManager.Stub { public void setApplicationRestrictions(String packageName, Bundle restrictions, @UserIdInt int userId) { checkSystemOrRoot("set application restrictions"); + String validationResult = + FrameworkParsingPackageUtils.validateName(packageName, false, false); + if (validationResult != null) { + throw new IllegalArgumentException("Invalid package name: " + validationResult); + } if (restrictions != null) { restrictions.setDefusable(true); } diff --git a/services/core/java/com/android/server/pm/parsing/PackageCacher.java b/services/core/java/com/android/server/pm/parsing/PackageCacher.java index f7a6eef29dee..d3a64bb0b9ac 100644 --- a/services/core/java/com/android/server/pm/parsing/PackageCacher.java +++ b/services/core/java/com/android/server/pm/parsing/PackageCacher.java @@ -62,6 +62,8 @@ public class PackageCacher { StringBuilder sb = new StringBuilder(packageFile.getName()); sb.append('-'); sb.append(flags); + sb.append('-'); + sb.append(packageFile.getAbsolutePath().hashCode()); return sb.toString(); } @@ -171,7 +173,12 @@ public class PackageCacher { } final byte[] bytes = IoUtils.readFileAsByteArray(cacheFile.getAbsolutePath()); - return fromCacheEntry(bytes); + ParsedPackage parsed = fromCacheEntry(bytes); + if (!packageFile.getAbsolutePath().equals(parsed.getPath())) { + // Don't use this cache if the path doesn't match + return null; + } + return parsed; } catch (Throwable e) { Slog.w(TAG, "Error reading package cache: ", e); diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 937a7891a849..1a1de0341aa0 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -215,7 +215,6 @@ import com.android.server.wm.DisplayPolicy; import com.android.server.wm.DisplayRotation; import com.android.server.wm.WindowManagerInternal; import com.android.server.wm.WindowManagerInternal.AppTransitionListener; -import com.android.server.wm.WindowManagerService; import java.io.File; import java.io.FileNotFoundException; @@ -2082,22 +2081,19 @@ public class PhoneWindowManager implements WindowManagerPolicy { mWindowManagerInternal.registerAppTransitionListener(new AppTransitionListener() { @Override - public int onAppTransitionStartingLocked(boolean keyguardGoingAway, - boolean keyguardOccluding, long duration, long statusBarAnimationStartTime, + public int onAppTransitionStartingLocked(long statusBarAnimationStartTime, long statusBarAnimationDuration) { - // When remote animation is enabled for KEYGUARD_GOING_AWAY transition, SysUI - // receives IRemoteAnimationRunner#onAnimationStart to start animation, so we don't - // need to call IKeyguardService#keyguardGoingAway here. - return handleStartTransitionForKeyguardLw(keyguardGoingAway - && !WindowManagerService.sEnableRemoteKeyguardGoingAwayAnimation, - keyguardOccluding, duration); + return handleTransitionForKeyguardLw(false /* startKeyguardExitAnimation */, + false /* notifyOccluded */); } @Override - public void onAppTransitionCancelledLocked(boolean keyguardGoingAway) { - handleStartTransitionForKeyguardLw( - keyguardGoingAway, false /* keyguardOccludingStarted */, - 0 /* duration */); + public void onAppTransitionCancelledLocked(boolean keyguardGoingAwayCancelled) { + // When KEYGUARD_GOING_AWAY app transition is canceled, we need to trigger relevant + // IKeyguardService calls to sync keyguard status in WindowManagerService and SysUI. + handleTransitionForKeyguardLw( + keyguardGoingAwayCancelled /* startKeyguardExitAnimation */, + true /* notifyOccluded */); } }); @@ -3262,31 +3258,39 @@ public class PhoneWindowManager implements WindowManagerPolicy { mPendingKeyguardOccluded = occluded; mKeyguardOccludedChanged = true; } else { - setKeyguardOccludedLw(occluded, false /* force */, - false /* transitionStarted */); + setKeyguardOccludedLw(occluded, true /* notify */); } } @Override - public int applyKeyguardOcclusionChange(boolean transitionStarted) { + public int applyKeyguardOcclusionChange(boolean notify) { if (mKeyguardOccludedChanged) { if (DEBUG_KEYGUARD) Slog.d(TAG, "transition/occluded changed occluded=" + mPendingKeyguardOccluded); - if (setKeyguardOccludedLw(mPendingKeyguardOccluded, false /* force */, - transitionStarted)) { + if (setKeyguardOccludedLw(mPendingKeyguardOccluded, notify)) { return FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_WALLPAPER; } } return 0; } - private int handleStartTransitionForKeyguardLw(boolean keyguardGoingAway, - boolean keyguardOccluding, long duration) { - final int redoLayout = applyKeyguardOcclusionChange(keyguardOccluding); + /** + * Called when keyguard related app transition starts, or cancelled. + * + * @param startKeyguardExitAnimation Trigger IKeyguardService#startKeyguardExitAnimation to + * start keyguard exit animation. + * @param notifyOccluded Trigger IKeyguardService#setOccluded binder call to notify whether + * the top activity can occlude the keyguard or not. + * + * @return Whether the flags have changed and we have to redo the layout. + */ + private int handleTransitionForKeyguardLw(boolean startKeyguardExitAnimation, + boolean notifyOccluded) { + final int redoLayout = applyKeyguardOcclusionChange(notifyOccluded); if (redoLayout != 0) return redoLayout; - if (keyguardGoingAway) { + if (startKeyguardExitAnimation) { if (DEBUG_KEYGUARD) Slog.d(TAG, "Starting keyguard exit animation"); - startKeyguardExitAnimation(SystemClock.uptimeMillis(), duration); + startKeyguardExitAnimation(SystemClock.uptimeMillis()); } return 0; } @@ -3518,28 +3522,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { * Updates the occluded state of the Keyguard. * * @param isOccluded Whether the Keyguard is occluded by another window. - * @param force notify the occluded status to KeyguardService and update flags even though - * occlude status doesn't change. - * @param transitionStarted {@code true} if keyguard (un)occluded transition started. + * @param notify Notify keyguard occlude status change immediately via + * {@link com.android.internal.policy.IKeyguardService}. * @return Whether the flags have changed and we have to redo the layout. */ - private boolean setKeyguardOccludedLw(boolean isOccluded, boolean force, - boolean transitionStarted) { + private boolean setKeyguardOccludedLw(boolean isOccluded, boolean notify) { if (DEBUG_KEYGUARD) Slog.d(TAG, "setKeyguardOccluded occluded=" + isOccluded); mKeyguardOccludedChanged = false; - if (isKeyguardOccluded() == isOccluded && !force) { + if (isKeyguardOccluded() == isOccluded) { return false; } - - final boolean showing = mKeyguardDelegate.isShowing(); - final boolean animate = showing && !isOccluded; - // When remote animation is enabled for keyguard (un)occlude transition, KeyguardService - // uses remote animation start as a signal to update its occlusion status ,so we don't need - // to notify here. - final boolean notify = !WindowManagerService.sEnableRemoteKeyguardOccludeAnimation - || !transitionStarted; - mKeyguardDelegate.setOccluded(isOccluded, animate, notify); - return showing; + mKeyguardDelegate.setOccluded(isOccluded, notify); + return mKeyguardDelegate.isShowing(); } /** {@inheritDoc} */ @@ -4935,10 +4929,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override - public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) { + public void startKeyguardExitAnimation(long startTime) { if (mKeyguardDelegate != null) { if (DEBUG_KEYGUARD) Slog.d(TAG, "PWM.startKeyguardExitAnimation"); - mKeyguardDelegate.startKeyguardExitAnimation(startTime, fadeoutDuration); + mKeyguardDelegate.startKeyguardExitAnimation(startTime); } } diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index 4f00992c713e..2b0405073323 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -171,10 +171,10 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { void onKeyguardOccludedChangedLw(boolean occluded); /** - * Applies a keyguard occlusion change if one happened. - * @param transitionStarted Whether keyguard (un)occlude transition is starting or not. + * @param notify {@code true} if the status change should be immediately notified via + * {@link com.android.internal.policy.IKeyguardService} */ - int applyKeyguardOcclusionChange(boolean transitionStarted); + int applyKeyguardOcclusionChange(boolean notify); /** * Interface to the Window Manager state associated with a particular @@ -1129,11 +1129,10 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { /** * Notifies the keyguard to start fading out. + * @param startTime the start time of the animation in uptime milliseconds * - * @param startTime the start time of the animation in uptime milliseconds - * @param fadeoutDuration the duration of the exit animation, in milliseconds */ - void startKeyguardExitAnimation(long startTime, long fadeoutDuration); + void startKeyguardExitAnimation(long startTime); /** * Called when System UI has been started. diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java index b79ac6f68be2..7737421654ee 100644 --- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java +++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java @@ -249,10 +249,10 @@ public class KeyguardServiceDelegate { } } - public void setOccluded(boolean isOccluded, boolean animate, boolean notify) { + public void setOccluded(boolean isOccluded, boolean notify) { if (mKeyguardService != null && notify) { - if (DEBUG) Log.v(TAG, "setOccluded(" + isOccluded + ") animate=" + animate); - mKeyguardService.setOccluded(isOccluded, animate); + if (DEBUG) Log.v(TAG, "setOccluded(" + isOccluded + ")"); + mKeyguardService.setOccluded(isOccluded, false /* animate */); } mKeyguardState.occluded = isOccluded; } @@ -394,9 +394,9 @@ public class KeyguardServiceDelegate { } } - public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) { + public void startKeyguardExitAnimation(long startTime) { if (mKeyguardService != null) { - mKeyguardService.startKeyguardExitAnimation(startTime, fadeoutDuration); + mKeyguardService.startKeyguardExitAnimation(startTime, 0); } } diff --git a/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java index fe4aa534df6f..df902c2916ba 100644 --- a/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java +++ b/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java @@ -657,7 +657,7 @@ public class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStat // Now that we have finally received all the data, we can tell mStats about it. synchronized (mStats) { - mStats.addHistoryEventLocked( + mStats.recordHistoryEventLocked( elapsedRealtime, uptime, BatteryStats.HistoryItem.EVENT_COLLECT_EXTERNAL_STATS, diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java index 0c9ada8fa6db..968f9161b3c1 100644 --- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java +++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java @@ -108,6 +108,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.BackgroundThread; import com.android.internal.os.BatteryStatsHistory; +import com.android.internal.os.BatteryStatsHistory.HistoryStepDetailsCalculator; import com.android.internal.os.BatteryStatsHistoryIterator; import com.android.internal.os.BinderCallsStats; import com.android.internal.os.BinderTransactionNameResolver; @@ -173,7 +174,6 @@ public class BatteryStatsImpl extends BatteryStats { private static final boolean DEBUG_ENERGY_CPU = DEBUG_ENERGY; private static final boolean DEBUG_BINDER_STATS = false; private static final boolean DEBUG_MEMORY = false; - private static final boolean DEBUG_HISTORY = false; // TODO: remove "tcp" from network methods, since we measure total stats. @@ -322,6 +322,11 @@ public class BatteryStatsImpl extends BatteryStats { @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) protected Queue<UidToRemove> mPendingRemovedUids = new LinkedList<>(); + @NonNull + BatteryStatsHistory copyHistory() { + return mHistory.copy(); + } + @VisibleForTesting public final class UidToRemove { private final int mStartUid; @@ -413,7 +418,7 @@ public class BatteryStatsImpl extends BatteryStats { if (changed) { final long uptimeMs = mClock.uptimeMillis(); final long elapsedRealtimeMs = mClock.elapsedRealtime(); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.writeHistoryItem(elapsedRealtimeMs, uptimeMs); } } } @@ -668,16 +673,16 @@ public class BatteryStatsImpl extends BatteryStats { /** * Mapping isolated uids to the actual owning app uid. */ - final SparseIntArray mIsolatedUids = new SparseIntArray(); + private final SparseIntArray mIsolatedUids = new SparseIntArray(); /** * Internal reference count of isolated uids. */ - final SparseIntArray mIsolatedUidRefCounts = new SparseIntArray(); + private final SparseIntArray mIsolatedUidRefCounts = new SparseIntArray(); /** * The statistics we have collected organized by uids. */ - final SparseArray<BatteryStatsImpl.Uid> mUidStats = new SparseArray<>(); + private final SparseArray<BatteryStatsImpl.Uid> mUidStats = new SparseArray<>(); // A set of pools of currently active timers. When a timer is queried, we will divide the // elapsed time by the number of active timers to arrive at that timer's share of the time. @@ -685,20 +690,21 @@ public class BatteryStatsImpl extends BatteryStats { // changes. @VisibleForTesting protected ArrayList<StopwatchTimer> mPartialTimers = new ArrayList<>(); - final ArrayList<StopwatchTimer> mFullTimers = new ArrayList<>(); - final ArrayList<StopwatchTimer> mWindowTimers = new ArrayList<>(); - final ArrayList<StopwatchTimer> mDrawTimers = new ArrayList<>(); - final SparseArray<ArrayList<StopwatchTimer>> mSensorTimers = new SparseArray<>(); - final ArrayList<StopwatchTimer> mWifiRunningTimers = new ArrayList<>(); - final ArrayList<StopwatchTimer> mFullWifiLockTimers = new ArrayList<>(); - final ArrayList<StopwatchTimer> mWifiMulticastTimers = new ArrayList<>(); - final ArrayList<StopwatchTimer> mWifiScanTimers = new ArrayList<>(); - final SparseArray<ArrayList<StopwatchTimer>> mWifiBatchedScanTimers = new SparseArray<>(); - final ArrayList<StopwatchTimer> mAudioTurnedOnTimers = new ArrayList<>(); - final ArrayList<StopwatchTimer> mVideoTurnedOnTimers = new ArrayList<>(); - final ArrayList<StopwatchTimer> mFlashlightTurnedOnTimers = new ArrayList<>(); - final ArrayList<StopwatchTimer> mCameraTurnedOnTimers = new ArrayList<>(); - final ArrayList<StopwatchTimer> mBluetoothScanOnTimers = new ArrayList<>(); + private final ArrayList<StopwatchTimer> mFullTimers = new ArrayList<>(); + private final ArrayList<StopwatchTimer> mWindowTimers = new ArrayList<>(); + private final ArrayList<StopwatchTimer> mDrawTimers = new ArrayList<>(); + private final SparseArray<ArrayList<StopwatchTimer>> mSensorTimers = new SparseArray<>(); + private final ArrayList<StopwatchTimer> mWifiRunningTimers = new ArrayList<>(); + private final ArrayList<StopwatchTimer> mFullWifiLockTimers = new ArrayList<>(); + private final ArrayList<StopwatchTimer> mWifiMulticastTimers = new ArrayList<>(); + private final ArrayList<StopwatchTimer> mWifiScanTimers = new ArrayList<>(); + private final SparseArray<ArrayList<StopwatchTimer>> mWifiBatchedScanTimers = + new SparseArray<>(); + private final ArrayList<StopwatchTimer> mAudioTurnedOnTimers = new ArrayList<>(); + private final ArrayList<StopwatchTimer> mVideoTurnedOnTimers = new ArrayList<>(); + private final ArrayList<StopwatchTimer> mFlashlightTurnedOnTimers = new ArrayList<>(); + private final ArrayList<StopwatchTimer> mCameraTurnedOnTimers = new ArrayList<>(); + private final ArrayList<StopwatchTimer> mBluetoothScanOnTimers = new ArrayList<>(); // Last partial timers we use for distributing CPU usage. @VisibleForTesting @@ -713,69 +719,24 @@ public class BatteryStatsImpl extends BatteryStats { protected final TimeBase mOnBatteryScreenOffTimeBase = new TimeBase(true); private boolean mSystemReady; - boolean mShuttingDown; - - final HistoryEventTracker mActiveEvents = new HistoryEventTracker(); - - long mHistoryBaseTimeMs; - protected boolean mHaveBatteryLevel = false; - protected boolean mRecordingHistory = false; - int mNumHistoryItems; - - private static final int HISTORY_TAG_INDEX_LIMIT = 0x7ffe; - private static final int MAX_HISTORY_TAG_STRING_LENGTH = 1024; - - final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap<>(); - private SparseArray<HistoryTag> mHistoryTags; - final Parcel mHistoryBuffer = Parcel.obtain(); - final HistoryItem mHistoryLastWritten = new HistoryItem(); - final HistoryItem mHistoryLastLastWritten = new HistoryItem(); - final HistoryItem mHistoryAddTmp = new HistoryItem(); - int mNextHistoryTagIdx = 0; - int mNumHistoryTagChars = 0; - int mHistoryBufferLastPos = -1; - int mActiveHistoryStates = 0xffffffff; - int mActiveHistoryStates2 = 0xffffffff; - long mLastHistoryElapsedRealtimeMs = 0; - long mTrackRunningHistoryElapsedRealtimeMs = 0; - long mTrackRunningHistoryUptimeMs = 0; + private boolean mShuttingDown; + + private final HistoryEventTracker mActiveEvents = new HistoryEventTracker(); + private final HistoryStepDetailsCalculatorImpl mStepDetailsCalculator = + new HistoryStepDetailsCalculatorImpl(); + + private boolean mHaveBatteryLevel = false; + private boolean mBatteryPluggedIn; + private int mBatteryStatus; + private int mBatteryLevel; + private int mBatteryPlugType; + private int mBatteryChargeUah; + private int mBatteryHealth; + private int mBatteryTemperature; + private int mBatteryVoltageMv = -1; @NonNull - final BatteryStatsHistory mBatteryStatsHistory; - - final HistoryItem mHistoryCur = new HistoryItem(); - - // Used by computeHistoryStepDetails - HistoryStepDetails mLastHistoryStepDetails = null; - byte mLastHistoryStepLevel = 0; - final HistoryStepDetails mCurHistoryStepDetails = new HistoryStepDetails(); - final HistoryStepDetails mTmpHistoryStepDetails = new HistoryStepDetails(); - - /** - * Total time (in milliseconds) spent executing in user code. - */ - long mLastStepCpuUserTimeMs; - long mCurStepCpuUserTimeMs; - /** - * Total time (in milliseconds) spent executing in kernel code. - */ - long mLastStepCpuSystemTimeMs; - long mCurStepCpuSystemTimeMs; - /** - * Times from /proc/stat (but measured in milliseconds). - */ - long mLastStepStatUserTimeMs; - long mLastStepStatSystemTimeMs; - long mLastStepStatIOWaitTimeMs; - long mLastStepStatIrqTimeMs; - long mLastStepStatSoftIrqTimeMs; - long mLastStepStatIdleTimeMs; - long mCurStepStatUserTimeMs; - long mCurStepStatSystemTimeMs; - long mCurStepStatIOWaitTimeMs; - long mCurStepStatIrqTimeMs; - long mCurStepStatSoftIrqTimeMs; - long mCurStepStatIdleTimeMs; + private final BatteryStatsHistory mHistory; private BatteryStatsHistoryIterator mBatteryStatsHistoryIterator; @@ -1391,7 +1352,6 @@ public class BatteryStatsImpl extends BatteryStats { int mDischargeUnplugLevel; int mDischargePlugLevel; int mDischargeCurrentLevel; - int mCurrentBatteryLevel; int mLowDischargeAmountSinceCharge; int mHighDischargeAmountSinceCharge; int mDischargeScreenOnUnplugLevel; @@ -1443,7 +1403,6 @@ public class BatteryStatsImpl extends BatteryStats { private int mNumConnectivityChange; - private int mBatteryVoltageMv = -1; private int mEstimatedBatteryCapacityMah = -1; private int mLastLearnedBatteryCapacityUah = -1; @@ -1627,28 +1586,27 @@ public class BatteryStatsImpl extends BatteryStats { } public BatteryStatsImpl(Clock clock) { - this(clock, (File) null); + this(clock, null); } public BatteryStatsImpl(Clock clock, File historyDirectory) { init(clock); + mHandler = null; + mConstants = new Constants(mHandler); mStartClockTimeMs = clock.currentTimeMillis(); mCheckinFile = null; mDailyFile = null; if (historyDirectory == null) { mStatsFile = null; - mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer); + mHistory = new BatteryStatsHistory(mStepDetailsCalculator, mClock); } else { mStatsFile = new AtomicFile(new File(historyDirectory, "batterystats.bin")); - mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer, historyDirectory, - this::getMaxHistoryFiles); + mHistory = new BatteryStatsHistory(historyDirectory, mConstants.MAX_HISTORY_FILES, + mConstants.MAX_HISTORY_BUFFER, mStepDetailsCalculator, mClock); } - mHandler = null; mPlatformIdleStateCallback = null; mMeasuredEnergyRetriever = null; mUserInfoProvider = null; - mConstants = new Constants(mHandler); - clearHistoryLocked(); } private void init(Clock clock) { @@ -3911,406 +3869,188 @@ public class BatteryStatsImpl extends BatteryStats { return kmt; } - /** - * Returns the index for the specified tag. If this is the first time the tag is encountered - * while writing the current history buffer, the method returns - * <code>(index | TAG_FIRST_OCCURRENCE_FLAG)</code> - */ - private int writeHistoryTag(HistoryTag tag) { - if (tag.string == null) { - Slog.wtfStack(TAG, "writeHistoryTag called with null name"); - } - - final int stringLength = tag.string.length(); - if (stringLength > MAX_HISTORY_TAG_STRING_LENGTH) { - Slog.e(TAG, "Long battery history tag: " + tag.string); - tag.string = tag.string.substring(0, MAX_HISTORY_TAG_STRING_LENGTH); - } - - Integer idxObj = mHistoryTagPool.get(tag); - int idx; - if (idxObj != null) { - idx = idxObj; - if ((idx & BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG) != 0) { - mHistoryTagPool.put(tag, idx & ~BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG); - } - return idx; - } else if (mNextHistoryTagIdx < HISTORY_TAG_INDEX_LIMIT) { - idx = mNextHistoryTagIdx; - HistoryTag key = new HistoryTag(); - key.setTo(tag); - tag.poolIdx = idx; - mHistoryTagPool.put(key, idx); - mNextHistoryTagIdx++; - - mNumHistoryTagChars += stringLength + 1; - if (mHistoryTags != null) { - mHistoryTags.put(idx, key); - } - return idx | BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG; - } else { - // Tag pool overflow: include the tag itself in the parcel - return HISTORY_TAG_INDEX_LIMIT | BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG; - } - } - - /* - The history delta format uses flags to denote further data in subsequent ints in the parcel. - - There is always the first token, which may contain the delta time, or an indicator of - the length of the time (int or long) following this token. - - First token: always present, - 31 23 15 7 0 - â–ˆM|L|K|J|I|H|G|Fâ–ˆE|D|C|B|A|T|T|Tâ–ˆT|T|T|T|T|T|T|Tâ–ˆT|T|T|T|T|T|T|Tâ–ˆ - - T: the delta time if it is <= 0x7fffd. Otherwise 0x7fffe indicates an int immediately - follows containing the time, and 0x7ffff indicates a long immediately follows with the - delta time. - A: battery level changed and an int follows with battery data. - B: state changed and an int follows with state change data. - C: state2 has changed and an int follows with state2 change data. - D: wakelock/wakereason has changed and an wakelock/wakereason struct follows. - E: event data has changed and an event struct follows. - F: battery charge in coulombs has changed and an int with the charge follows. - G: state flag denoting that the mobile radio was active. - H: state flag denoting that the wifi radio was active. - I: state flag denoting that a wifi scan occurred. - J: state flag denoting that a wifi full lock was held. - K: state flag denoting that the gps was on. - L: state flag denoting that a wakelock was held. - M: state flag denoting that the cpu was running. - - Time int/long: if T in the first token is 0x7ffff or 0x7fffe, then an int or long follows - with the time delta. - - Battery level int: if A in the first token is set, - 31 23 15 7 0 - â–ˆL|L|L|L|L|L|L|Tâ–ˆT|T|T|T|T|T|T|Tâ–ˆT|V|V|V|V|V|V|Vâ–ˆV|V|V|V|V|V|V|Dâ–ˆ - - D: indicates that extra history details follow. - V: the battery voltage. - T: the battery temperature. - L: the battery level (out of 100). - - State change int: if B in the first token is set, - 31 23 15 7 0 - â–ˆS|S|S|H|H|H|P|Pâ–ˆF|E|D|C|B| | |Aâ–ˆ | | | | | | | â–ˆ | | | | | | | â–ˆ - - A: wifi multicast was on. - B: battery was plugged in. - C: screen was on. - D: phone was scanning for signal. - E: audio was on. - F: a sensor was active. - - State2 change int: if C in the first token is set, - 31 23 15 7 0 - â–ˆM|L|K|J|I|H|H|Gâ–ˆF|E|D|C| | | | â–ˆ | | | | | | | â–ˆ |B|B|B|A|A|A|Aâ–ˆ - - A: 4 bits indicating the wifi supplicant state: {@link BatteryStats#WIFI_SUPPL_STATE_NAMES}. - B: 3 bits indicating the wifi signal strength: 0, 1, 2, 3, 4. - C: a bluetooth scan was active. - D: the camera was active. - E: bluetooth was on. - F: a phone call was active. - G: the device was charging. - H: 2 bits indicating the device-idle (doze) state: off, light, full - I: the flashlight was on. - J: wifi was on. - K: wifi was running. - L: video was playing. - M: power save mode was on. - - Wakelock/wakereason struct: if D in the first token is set, - TODO(adamlesinski): describe wakelock/wakereason struct. - - Event struct: if E in the first token is set, - TODO(adamlesinski): describe the event struct. - - History step details struct: if D in the battery level int is set, - TODO(adamlesinski): describe the history step details struct. - - Battery charge int: if F in the first token is set, an int representing the battery charge - in coulombs follows. - */ + private class HistoryStepDetailsCalculatorImpl implements HistoryStepDetailsCalculator { + private final HistoryStepDetails mDetails = new HistoryStepDetails(); - @GuardedBy("this") - public void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) { - if (last == null || cur.cmd != HistoryItem.CMD_UPDATE) { - dest.writeInt(BatteryStatsHistory.DELTA_TIME_ABS); - cur.writeToParcel(dest, 0); - return; - } + private boolean mHasHistoryStepDetails; - final long deltaTime = cur.time - last.time; - final int lastBatteryLevelInt = buildBatteryLevelInt(last); - final int lastStateInt = buildStateInt(last); + private int mLastHistoryStepLevel; - int deltaTimeToken; - if (deltaTime < 0 || deltaTime > Integer.MAX_VALUE) { - deltaTimeToken = BatteryStatsHistory.DELTA_TIME_LONG; - } else if (deltaTime >= BatteryStatsHistory.DELTA_TIME_ABS) { - deltaTimeToken = BatteryStatsHistory.DELTA_TIME_INT; - } else { - deltaTimeToken = (int)deltaTime; - } - int firstToken = deltaTimeToken | (cur.states & BatteryStatsHistory.DELTA_STATE_MASK); - final int includeStepDetails = mLastHistoryStepLevel > cur.batteryLevel - ? BatteryStatsHistory.BATTERY_DELTA_LEVEL_FLAG : 0; - final boolean computeStepDetails = includeStepDetails != 0 - || mLastHistoryStepDetails == null; - final int batteryLevelInt = buildBatteryLevelInt(cur) | includeStepDetails; - final boolean batteryLevelIntChanged = batteryLevelInt != lastBatteryLevelInt; - if (batteryLevelIntChanged) { - firstToken |= BatteryStatsHistory.DELTA_BATTERY_LEVEL_FLAG; - } - final int stateInt = buildStateInt(cur); - final boolean stateIntChanged = stateInt != lastStateInt; - if (stateIntChanged) { - firstToken |= BatteryStatsHistory.DELTA_STATE_FLAG; - } - final boolean state2IntChanged = cur.states2 != last.states2; - if (state2IntChanged) { - firstToken |= BatteryStatsHistory.DELTA_STATE2_FLAG; - } - if (cur.wakelockTag != null || cur.wakeReasonTag != null) { - firstToken |= BatteryStatsHistory.DELTA_WAKELOCK_FLAG; - } - if (cur.eventCode != HistoryItem.EVENT_NONE) { - firstToken |= BatteryStatsHistory.DELTA_EVENT_FLAG; - } - - final boolean batteryChargeChanged = cur.batteryChargeUah != last.batteryChargeUah; - if (batteryChargeChanged) { - firstToken |= BatteryStatsHistory.DELTA_BATTERY_CHARGE_FLAG; - } - dest.writeInt(firstToken); - if (DEBUG) Slog.i(TAG, "WRITE DELTA: firstToken=0x" + Integer.toHexString(firstToken) - + " deltaTime=" + deltaTime); - - if (deltaTimeToken >= BatteryStatsHistory.DELTA_TIME_INT) { - if (deltaTimeToken == BatteryStatsHistory.DELTA_TIME_INT) { - if (DEBUG) Slog.i(TAG, "WRITE DELTA: int deltaTime=" + (int)deltaTime); - dest.writeInt((int)deltaTime); - } else { - if (DEBUG) Slog.i(TAG, "WRITE DELTA: long deltaTime=" + deltaTime); - dest.writeLong(deltaTime); - } - } - if (batteryLevelIntChanged) { - dest.writeInt(batteryLevelInt); - if (DEBUG) Slog.i(TAG, "WRITE DELTA: batteryToken=0x" - + Integer.toHexString(batteryLevelInt) - + " batteryLevel=" + cur.batteryLevel - + " batteryTemp=" + cur.batteryTemperature - + " batteryVolt=" + (int)cur.batteryVoltage); - } - if (stateIntChanged) { - dest.writeInt(stateInt); - if (DEBUG) Slog.i(TAG, "WRITE DELTA: stateToken=0x" - + Integer.toHexString(stateInt) - + " batteryStatus=" + cur.batteryStatus - + " batteryHealth=" + cur.batteryHealth - + " batteryPlugType=" + cur.batteryPlugType - + " states=0x" + Integer.toHexString(cur.states)); - } - if (state2IntChanged) { - dest.writeInt(cur.states2); - if (DEBUG) Slog.i(TAG, "WRITE DELTA: states2=0x" - + Integer.toHexString(cur.states2)); - } - if (cur.wakelockTag != null || cur.wakeReasonTag != null) { - int wakeLockIndex; - int wakeReasonIndex; - if (cur.wakelockTag != null) { - wakeLockIndex = writeHistoryTag(cur.wakelockTag); - if (DEBUG) Slog.i(TAG, "WRITE DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx - + " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string); - } else { - wakeLockIndex = 0xffff; - } - if (cur.wakeReasonTag != null) { - wakeReasonIndex = writeHistoryTag(cur.wakeReasonTag); - if (DEBUG) Slog.i(TAG, "WRITE DELTA: wakeReasonTag=#" + cur.wakeReasonTag.poolIdx - + " " + cur.wakeReasonTag.uid + ":" + cur.wakeReasonTag.string); - } else { - wakeReasonIndex = 0xffff; - } - dest.writeInt((wakeReasonIndex<<16) | wakeLockIndex); - if (cur.wakelockTag != null - && (wakeLockIndex & BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG) != 0) { - cur.wakelockTag.writeToParcel(dest, 0); - cur.tagsFirstOccurrence = true; - } - if (cur.wakeReasonTag != null - && (wakeReasonIndex & BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG) != 0) { - cur.wakeReasonTag.writeToParcel(dest, 0); - cur.tagsFirstOccurrence = true; - } - } - if (cur.eventCode != HistoryItem.EVENT_NONE) { - final int index = writeHistoryTag(cur.eventTag); - final int codeAndIndex = (cur.eventCode & 0xffff) | (index << 16); - dest.writeInt(codeAndIndex); - if ((index & BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG) != 0) { - cur.eventTag.writeToParcel(dest, 0); - cur.tagsFirstOccurrence = true; + /** + * Total time (in milliseconds) spent executing in user code. + */ + private long mLastStepCpuUserTimeMs; + private long mCurStepCpuUserTimeMs; + /** + * Total time (in milliseconds) spent executing in kernel code. + */ + private long mLastStepCpuSystemTimeMs; + private long mCurStepCpuSystemTimeMs; + /** + * Times from /proc/stat (but measured in milliseconds). + */ + private long mLastStepStatUserTimeMs; + private long mLastStepStatSystemTimeMs; + private long mLastStepStatIOWaitTimeMs; + private long mLastStepStatIrqTimeMs; + private long mLastStepStatSoftIrqTimeMs; + private long mLastStepStatIdleTimeMs; + private long mCurStepStatUserTimeMs; + private long mCurStepStatSystemTimeMs; + private long mCurStepStatIOWaitTimeMs; + private long mCurStepStatIrqTimeMs; + private long mCurStepStatSoftIrqTimeMs; + private long mCurStepStatIdleTimeMs; + + @Override + public HistoryStepDetails getHistoryStepDetails() { + if (mBatteryLevel >= mLastHistoryStepLevel && mHasHistoryStepDetails) { + mLastHistoryStepLevel = mBatteryLevel; + return null; } - if (DEBUG) Slog.i(TAG, "WRITE DELTA: event=" + cur.eventCode + " tag=#" - + cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":" - + cur.eventTag.string); - } - if (computeStepDetails) { + + // Perform a CPU update right after we do this collection, so we have started + // collecting good data for the next step. + requestImmediateCpuUpdate(); + if (mPlatformIdleStateCallback != null) { - mCurHistoryStepDetails.statSubsystemPowerState = + mDetails.statSubsystemPowerState = mPlatformIdleStateCallback.getSubsystemLowPowerStats(); if (DEBUG) Slog.i(TAG, "WRITE SubsystemPowerState:" + - mCurHistoryStepDetails.statSubsystemPowerState); - - } - computeHistoryStepDetails(mCurHistoryStepDetails, mLastHistoryStepDetails); - if (includeStepDetails != 0) { - mCurHistoryStepDetails.writeToParcel(dest); - } - cur.stepDetails = mCurHistoryStepDetails; - mLastHistoryStepDetails = mCurHistoryStepDetails; - } else { - cur.stepDetails = null; - } - if (mLastHistoryStepLevel < cur.batteryLevel) { - mLastHistoryStepDetails = null; - } - mLastHistoryStepLevel = cur.batteryLevel; - - if (batteryChargeChanged) { - if (DEBUG) Slog.i(TAG, "WRITE DELTA: batteryChargeUah=" + cur.batteryChargeUah); - dest.writeInt(cur.batteryChargeUah); - } - dest.writeDouble(cur.modemRailChargeMah); - dest.writeDouble(cur.wifiRailChargeMah); - } - - private int buildBatteryLevelInt(HistoryItem h) { - return ((((int)h.batteryLevel)<<25)&0xfe000000) - | ((((int)h.batteryTemperature)<<15)&0x01ff8000) - | ((((int)h.batteryVoltage)<<1)&0x00007ffe); - } - - private int buildStateInt(HistoryItem h) { - int plugType = 0; - if ((h.batteryPlugType&BatteryManager.BATTERY_PLUGGED_AC) != 0) { - plugType = 1; - } else if ((h.batteryPlugType&BatteryManager.BATTERY_PLUGGED_USB) != 0) { - plugType = 2; - } else if ((h.batteryPlugType&BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0) { - plugType = 3; - } - return ((h.batteryStatus & BatteryStatsHistory.STATE_BATTERY_STATUS_MASK) - << BatteryStatsHistory.STATE_BATTERY_STATUS_SHIFT) - | ((h.batteryHealth & BatteryStatsHistory.STATE_BATTERY_HEALTH_MASK) - << BatteryStatsHistory.STATE_BATTERY_HEALTH_SHIFT) - | ((plugType & BatteryStatsHistory.STATE_BATTERY_PLUG_MASK) - << BatteryStatsHistory.STATE_BATTERY_PLUG_SHIFT) - | (h.states & (~BatteryStatsHistory.STATE_BATTERY_MASK)); - } - - private void computeHistoryStepDetails(final HistoryStepDetails out, - final HistoryStepDetails last) { - final HistoryStepDetails tmp = last != null ? mTmpHistoryStepDetails : out; - - // Perform a CPU update right after we do this collection, so we have started - // collecting good data for the next step. - requestImmediateCpuUpdate(); - - if (last == null) { - // We are not generating a delta, so all we need to do is reset the stats - // we will later be doing a delta from. - final int NU = mUidStats.size(); - for (int i=0; i<NU; i++) { - final BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); - uid.mLastStepUserTimeMs = uid.mCurStepUserTimeMs; - uid.mLastStepSystemTimeMs = uid.mCurStepSystemTimeMs; - } - mLastStepCpuUserTimeMs = mCurStepCpuUserTimeMs; - mLastStepCpuSystemTimeMs = mCurStepCpuSystemTimeMs; - mLastStepStatUserTimeMs = mCurStepStatUserTimeMs; - mLastStepStatSystemTimeMs = mCurStepStatSystemTimeMs; - mLastStepStatIOWaitTimeMs = mCurStepStatIOWaitTimeMs; - mLastStepStatIrqTimeMs = mCurStepStatIrqTimeMs; - mLastStepStatSoftIrqTimeMs = mCurStepStatSoftIrqTimeMs; - mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs; - tmp.clear(); - return; - } - if (DEBUG) { - Slog.d(TAG, "Step stats last: user=" + mLastStepCpuUserTimeMs + " sys=" - + mLastStepStatSystemTimeMs + " io=" + mLastStepStatIOWaitTimeMs - + " irq=" + mLastStepStatIrqTimeMs + " sirq=" - + mLastStepStatSoftIrqTimeMs + " idle=" + mLastStepStatIdleTimeMs); - Slog.d(TAG, "Step stats cur: user=" + mCurStepCpuUserTimeMs + " sys=" - + mCurStepStatSystemTimeMs + " io=" + mCurStepStatIOWaitTimeMs - + " irq=" + mCurStepStatIrqTimeMs + " sirq=" - + mCurStepStatSoftIrqTimeMs + " idle=" + mCurStepStatIdleTimeMs); - } - out.userTime = (int) (mCurStepCpuUserTimeMs - mLastStepCpuUserTimeMs); - out.systemTime = (int) (mCurStepCpuSystemTimeMs - mLastStepCpuSystemTimeMs); - out.statUserTime = (int) (mCurStepStatUserTimeMs - mLastStepStatUserTimeMs); - out.statSystemTime = (int) (mCurStepStatSystemTimeMs - mLastStepStatSystemTimeMs); - out.statIOWaitTime = (int) (mCurStepStatIOWaitTimeMs - mLastStepStatIOWaitTimeMs); - out.statIrqTime = (int) (mCurStepStatIrqTimeMs - mLastStepStatIrqTimeMs); - out.statSoftIrqTime = (int) (mCurStepStatSoftIrqTimeMs - mLastStepStatSoftIrqTimeMs); - out.statIdlTime = (int) (mCurStepStatIdleTimeMs - mLastStepStatIdleTimeMs); - out.appCpuUid1 = out.appCpuUid2 = out.appCpuUid3 = -1; - out.appCpuUTime1 = out.appCpuUTime2 = out.appCpuUTime3 = 0; - out.appCpuSTime1 = out.appCpuSTime2 = out.appCpuSTime3 = 0; - final int NU = mUidStats.size(); - for (int i=0; i<NU; i++) { - final BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); - final int totalUTimeMs = (int) (uid.mCurStepUserTimeMs - uid.mLastStepUserTimeMs); - final int totalSTimeMs = (int) (uid.mCurStepSystemTimeMs - uid.mLastStepSystemTimeMs); - final int totalTimeMs = totalUTimeMs + totalSTimeMs; - uid.mLastStepUserTimeMs = uid.mCurStepUserTimeMs; - uid.mLastStepSystemTimeMs = uid.mCurStepSystemTimeMs; - if (totalTimeMs <= (out.appCpuUTime3 + out.appCpuSTime3)) { - continue; - } - if (totalTimeMs <= (out.appCpuUTime2 + out.appCpuSTime2)) { - out.appCpuUid3 = uid.mUid; - out.appCpuUTime3 = totalUTimeMs; - out.appCpuSTime3 = totalSTimeMs; + mDetails.statSubsystemPowerState); + } + + if (!mHasHistoryStepDetails) { + // We are not generating a delta, so all we need to do is reset the stats + // we will later be doing a delta from. + final int uidCount = mUidStats.size(); + for (int i = 0; i < uidCount; i++) { + final BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); + uid.mLastStepUserTimeMs = uid.mCurStepUserTimeMs; + uid.mLastStepSystemTimeMs = uid.mCurStepSystemTimeMs; + } + mLastStepCpuUserTimeMs = mCurStepCpuUserTimeMs; + mLastStepCpuSystemTimeMs = mCurStepCpuSystemTimeMs; + mLastStepStatUserTimeMs = mCurStepStatUserTimeMs; + mLastStepStatSystemTimeMs = mCurStepStatSystemTimeMs; + mLastStepStatIOWaitTimeMs = mCurStepStatIOWaitTimeMs; + mLastStepStatIrqTimeMs = mCurStepStatIrqTimeMs; + mLastStepStatSoftIrqTimeMs = mCurStepStatSoftIrqTimeMs; + mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs; + mDetails.clear(); } else { - out.appCpuUid3 = out.appCpuUid2; - out.appCpuUTime3 = out.appCpuUTime2; - out.appCpuSTime3 = out.appCpuSTime2; - if (totalTimeMs <= (out.appCpuUTime1 + out.appCpuSTime1)) { - out.appCpuUid2 = uid.mUid; - out.appCpuUTime2 = totalUTimeMs; - out.appCpuSTime2 = totalSTimeMs; - } else { - out.appCpuUid2 = out.appCpuUid1; - out.appCpuUTime2 = out.appCpuUTime1; - out.appCpuSTime2 = out.appCpuSTime1; - out.appCpuUid1 = uid.mUid; - out.appCpuUTime1 = totalUTimeMs; - out.appCpuSTime1 = totalSTimeMs; + if (DEBUG) { + Slog.d(TAG, "Step stats last: user=" + mLastStepCpuUserTimeMs + " sys=" + + mLastStepStatSystemTimeMs + " io=" + mLastStepStatIOWaitTimeMs + + " irq=" + mLastStepStatIrqTimeMs + " sirq=" + + mLastStepStatSoftIrqTimeMs + " idle=" + mLastStepStatIdleTimeMs); + Slog.d(TAG, "Step stats cur: user=" + mCurStepCpuUserTimeMs + " sys=" + + mCurStepStatSystemTimeMs + " io=" + mCurStepStatIOWaitTimeMs + + " irq=" + mCurStepStatIrqTimeMs + " sirq=" + + mCurStepStatSoftIrqTimeMs + " idle=" + mCurStepStatIdleTimeMs); + } + mDetails.userTime = (int) (mCurStepCpuUserTimeMs - mLastStepCpuUserTimeMs); + mDetails.systemTime = (int) (mCurStepCpuSystemTimeMs - mLastStepCpuSystemTimeMs); + mDetails.statUserTime = (int) (mCurStepStatUserTimeMs - mLastStepStatUserTimeMs); + mDetails.statSystemTime = + (int) (mCurStepStatSystemTimeMs - mLastStepStatSystemTimeMs); + mDetails.statIOWaitTime = + (int) (mCurStepStatIOWaitTimeMs - mLastStepStatIOWaitTimeMs); + mDetails.statIrqTime = (int) (mCurStepStatIrqTimeMs - mLastStepStatIrqTimeMs); + mDetails.statSoftIrqTime = + (int) (mCurStepStatSoftIrqTimeMs - mLastStepStatSoftIrqTimeMs); + mDetails.statIdlTime = (int) (mCurStepStatIdleTimeMs - mLastStepStatIdleTimeMs); + mDetails.appCpuUid1 = mDetails.appCpuUid2 = mDetails.appCpuUid3 = -1; + mDetails.appCpuUTime1 = mDetails.appCpuUTime2 = mDetails.appCpuUTime3 = 0; + mDetails.appCpuSTime1 = mDetails.appCpuSTime2 = mDetails.appCpuSTime3 = 0; + final int uidCount = mUidStats.size(); + for (int i = 0; i < uidCount; i++) { + final BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); + final int totalUTimeMs = + (int) (uid.mCurStepUserTimeMs - uid.mLastStepUserTimeMs); + final int totalSTimeMs = + (int) (uid.mCurStepSystemTimeMs - uid.mLastStepSystemTimeMs); + final int totalTimeMs = totalUTimeMs + totalSTimeMs; + uid.mLastStepUserTimeMs = uid.mCurStepUserTimeMs; + uid.mLastStepSystemTimeMs = uid.mCurStepSystemTimeMs; + if (totalTimeMs <= (mDetails.appCpuUTime3 + mDetails.appCpuSTime3)) { + continue; + } + if (totalTimeMs <= (mDetails.appCpuUTime2 + mDetails.appCpuSTime2)) { + mDetails.appCpuUid3 = uid.mUid; + mDetails.appCpuUTime3 = totalUTimeMs; + mDetails.appCpuSTime3 = totalSTimeMs; + } else { + mDetails.appCpuUid3 = mDetails.appCpuUid2; + mDetails.appCpuUTime3 = mDetails.appCpuUTime2; + mDetails.appCpuSTime3 = mDetails.appCpuSTime2; + if (totalTimeMs <= (mDetails.appCpuUTime1 + mDetails.appCpuSTime1)) { + mDetails.appCpuUid2 = uid.mUid; + mDetails.appCpuUTime2 = totalUTimeMs; + mDetails.appCpuSTime2 = totalSTimeMs; + } else { + mDetails.appCpuUid2 = mDetails.appCpuUid1; + mDetails.appCpuUTime2 = mDetails.appCpuUTime1; + mDetails.appCpuSTime2 = mDetails.appCpuSTime1; + mDetails.appCpuUid1 = uid.mUid; + mDetails.appCpuUTime1 = totalUTimeMs; + mDetails.appCpuSTime1 = totalSTimeMs; + } + } } + mLastStepCpuUserTimeMs = mCurStepCpuUserTimeMs; + mLastStepCpuSystemTimeMs = mCurStepCpuSystemTimeMs; + mLastStepStatUserTimeMs = mCurStepStatUserTimeMs; + mLastStepStatSystemTimeMs = mCurStepStatSystemTimeMs; + mLastStepStatIOWaitTimeMs = mCurStepStatIOWaitTimeMs; + mLastStepStatIrqTimeMs = mCurStepStatIrqTimeMs; + mLastStepStatSoftIrqTimeMs = mCurStepStatSoftIrqTimeMs; + mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs; + } + + mHasHistoryStepDetails = mBatteryLevel <= mLastHistoryStepLevel; + mLastHistoryStepLevel = mBatteryLevel; + + return mDetails; + } + + public void addCpuStats(int totalUTimeMs, int totalSTimeMs, int statUserTimeMs, + int statSystemTimeMs, int statIOWaitTimeMs, int statIrqTimeMs, + int statSoftIrqTimeMs, int statIdleTimeMs) { + if (DEBUG) { + Slog.d(TAG, "Adding cpu: tuser=" + totalUTimeMs + " tsys=" + totalSTimeMs + + " user=" + statUserTimeMs + " sys=" + statSystemTimeMs + + " io=" + statIOWaitTimeMs + " irq=" + statIrqTimeMs + + " sirq=" + statSoftIrqTimeMs + " idle=" + statIdleTimeMs); } + mCurStepCpuUserTimeMs += totalUTimeMs; + mCurStepCpuSystemTimeMs += totalSTimeMs; + mCurStepStatUserTimeMs += statUserTimeMs; + mCurStepStatSystemTimeMs += statSystemTimeMs; + mCurStepStatIOWaitTimeMs += statIOWaitTimeMs; + mCurStepStatIrqTimeMs += statIrqTimeMs; + mCurStepStatSoftIrqTimeMs += statSoftIrqTimeMs; + mCurStepStatIdleTimeMs += statIdleTimeMs; + } + + @Override + public void clear() { + mHasHistoryStepDetails = false; + mLastStepCpuUserTimeMs = mCurStepCpuUserTimeMs = 0; + mLastStepCpuSystemTimeMs = mCurStepCpuSystemTimeMs = 0; + mLastStepStatUserTimeMs = mCurStepStatUserTimeMs = 0; + mLastStepStatSystemTimeMs = mCurStepStatSystemTimeMs = 0; + mLastStepStatIOWaitTimeMs = mCurStepStatIOWaitTimeMs = 0; + mLastStepStatIrqTimeMs = mCurStepStatIrqTimeMs = 0; + mLastStepStatSoftIrqTimeMs = mCurStepStatSoftIrqTimeMs = 0; + mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs = 0; } - mLastStepCpuUserTimeMs = mCurStepCpuUserTimeMs; - mLastStepCpuSystemTimeMs = mCurStepCpuSystemTimeMs; - mLastStepStatUserTimeMs = mCurStepStatUserTimeMs; - mLastStepStatSystemTimeMs = mCurStepStatSystemTimeMs; - mLastStepStatIOWaitTimeMs = mCurStepStatIOWaitTimeMs; - mLastStepStatIrqTimeMs = mCurStepStatIrqTimeMs; - mLastStepStatSoftIrqTimeMs = mCurStepStatSoftIrqTimeMs; - mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs; } @GuardedBy("this") @Override public void commitCurrentHistoryBatchLocked() { - mHistoryLastWritten.cmd = HistoryItem.CMD_NULL; + mHistory.commitCurrentHistoryBatchLocked(); } @GuardedBy("this") @@ -4326,191 +4066,9 @@ public class BatteryStatsImpl extends BatteryStats { } @GuardedBy("this") - void addHistoryBufferLocked(long elapsedRealtimeMs, long uptimeMs, HistoryItem cur) { - if (!mHaveBatteryLevel || !mRecordingHistory) { - return; - } - - final long timeDiffMs = (mHistoryBaseTimeMs + elapsedRealtimeMs) - mHistoryLastWritten.time; - final int diffStates = mHistoryLastWritten.states^(cur.states&mActiveHistoryStates); - final int diffStates2 = mHistoryLastWritten.states2^(cur.states2&mActiveHistoryStates2); - final int lastDiffStates = mHistoryLastWritten.states^mHistoryLastLastWritten.states; - final int lastDiffStates2 = mHistoryLastWritten.states2^mHistoryLastLastWritten.states2; - if (DEBUG) { - Slog.i(TAG, "ADD: tdelta=" + timeDiffMs + " diff=" - + Integer.toHexString(diffStates) + " lastDiff=" - + Integer.toHexString(lastDiffStates) + " diff2=" - + Integer.toHexString(diffStates2) + " lastDiff2=" - + Integer.toHexString(lastDiffStates2)); - } - if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE - && timeDiffMs < 1000 && (diffStates & lastDiffStates) == 0 - && (diffStates2&lastDiffStates2) == 0 - && (!mHistoryLastWritten.tagsFirstOccurrence && !cur.tagsFirstOccurrence) - && (mHistoryLastWritten.wakelockTag == null || cur.wakelockTag == null) - && (mHistoryLastWritten.wakeReasonTag == null || cur.wakeReasonTag == null) - && mHistoryLastWritten.stepDetails == null - && (mHistoryLastWritten.eventCode == HistoryItem.EVENT_NONE - || cur.eventCode == HistoryItem.EVENT_NONE) - && mHistoryLastWritten.batteryLevel == cur.batteryLevel - && mHistoryLastWritten.batteryStatus == cur.batteryStatus - && mHistoryLastWritten.batteryHealth == cur.batteryHealth - && mHistoryLastWritten.batteryPlugType == cur.batteryPlugType - && mHistoryLastWritten.batteryTemperature == cur.batteryTemperature - && mHistoryLastWritten.batteryVoltage == cur.batteryVoltage) { - // We can merge this new change in with the last one. Merging is - // allowed as long as only the states have changed, and within those states - // as long as no bit has changed both between now and the last entry, as - // well as the last entry and the one before it (so we capture any toggles). - if (DEBUG) Slog.i(TAG, "ADD: rewinding back to " + mHistoryBufferLastPos); - mHistoryBuffer.setDataSize(mHistoryBufferLastPos); - mHistoryBuffer.setDataPosition(mHistoryBufferLastPos); - mHistoryBufferLastPos = -1; - elapsedRealtimeMs = mHistoryLastWritten.time - mHistoryBaseTimeMs; - // If the last written history had a wakelock tag, we need to retain it. - // Note that the condition above made sure that we aren't in a case where - // both it and the current history item have a wakelock tag. - if (mHistoryLastWritten.wakelockTag != null) { - cur.wakelockTag = cur.localWakelockTag; - cur.wakelockTag.setTo(mHistoryLastWritten.wakelockTag); - } - // If the last written history had a wake reason tag, we need to retain it. - // Note that the condition above made sure that we aren't in a case where - // both it and the current history item have a wakelock tag. - if (mHistoryLastWritten.wakeReasonTag != null) { - cur.wakeReasonTag = cur.localWakeReasonTag; - cur.wakeReasonTag.setTo(mHistoryLastWritten.wakeReasonTag); - } - // If the last written history had an event, we need to retain it. - // Note that the condition above made sure that we aren't in a case where - // both it and the current history item have an event. - if (mHistoryLastWritten.eventCode != HistoryItem.EVENT_NONE) { - cur.eventCode = mHistoryLastWritten.eventCode; - cur.eventTag = cur.localEventTag; - cur.eventTag.setTo(mHistoryLastWritten.eventTag); - } - mHistoryLastWritten.setTo(mHistoryLastLastWritten); - } - final int dataSize = mHistoryBuffer.dataSize(); - - if (dataSize >= mConstants.MAX_HISTORY_BUFFER) { - //open a new history file. - final long start = SystemClock.uptimeMillis(); - writeHistoryLocked(); - if (DEBUG) { - Slog.d(TAG, "addHistoryBufferLocked writeHistoryLocked takes ms:" - + (SystemClock.uptimeMillis() - start)); - } - mBatteryStatsHistory.startNextFile(); - mHistoryBuffer.setDataSize(0); - mHistoryBuffer.setDataPosition(0); - mHistoryBuffer.setDataCapacity(mConstants.MAX_HISTORY_BUFFER / 2); - mHistoryBufferLastPos = -1; - mHistoryLastWritten.clear(); - mHistoryLastLastWritten.clear(); - - // Mark every entry in the pool with a flag indicating that the tag - // has not yet been encountered while writing the current history buffer. - for (Map.Entry<HistoryTag, Integer> entry: mHistoryTagPool.entrySet()) { - entry.setValue(entry.getValue() | BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG); - } - // Make a copy of mHistoryCur. - HistoryItem copy = new HistoryItem(); - copy.setTo(cur); - // startRecordingHistory will reset mHistoryCur. - startRecordingHistory(elapsedRealtimeMs, uptimeMs, false); - // Add the copy into history buffer. - addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_UPDATE, copy); - return; - } - - if (dataSize == 0) { - // The history is currently empty; we need it to start with a time stamp. - cur.currentTime = mClock.currentTimeMillis(); - addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_RESET, cur); - } - addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_UPDATE, cur); - } - - @GuardedBy("this") - private void addHistoryBufferLocked(long elapsedRealtimeMs, byte cmd, HistoryItem cur) { - if (mBatteryStatsHistoryIterator != null) { - throw new IllegalStateException("Can't do this while iterating history!"); - } - mHistoryBufferLastPos = mHistoryBuffer.dataPosition(); - mHistoryLastLastWritten.setTo(mHistoryLastWritten); - final boolean hasTags = mHistoryLastWritten.tagsFirstOccurrence || cur.tagsFirstOccurrence; - mHistoryLastWritten.setTo(mHistoryBaseTimeMs + elapsedRealtimeMs, cmd, cur); - mHistoryLastWritten.tagsFirstOccurrence = hasTags; - mHistoryLastWritten.states &= mActiveHistoryStates; - mHistoryLastWritten.states2 &= mActiveHistoryStates2; - writeHistoryDelta(mHistoryBuffer, mHistoryLastWritten, mHistoryLastLastWritten); - mLastHistoryElapsedRealtimeMs = elapsedRealtimeMs; - cur.wakelockTag = null; - cur.wakeReasonTag = null; - cur.eventCode = HistoryItem.EVENT_NONE; - cur.eventTag = null; - cur.tagsFirstOccurrence = false; - if (DEBUG_HISTORY) Slog.i(TAG, "Writing history buffer: was " + mHistoryBufferLastPos - + " now " + mHistoryBuffer.dataPosition() - + " size is now " + mHistoryBuffer.dataSize()); - } - - @GuardedBy("this") - void addHistoryRecordLocked(long elapsedRealtimeMs, long uptimeMs) { - if (mTrackRunningHistoryElapsedRealtimeMs != 0) { - final long diffElapsedMs = elapsedRealtimeMs - mTrackRunningHistoryElapsedRealtimeMs; - final long diffUptimeMs = uptimeMs - mTrackRunningHistoryUptimeMs; - if (diffUptimeMs < (diffElapsedMs - 20)) { - final long wakeElapsedTimeMs = elapsedRealtimeMs - (diffElapsedMs - diffUptimeMs); - mHistoryAddTmp.setTo(mHistoryLastWritten); - mHistoryAddTmp.wakelockTag = null; - mHistoryAddTmp.wakeReasonTag = null; - mHistoryAddTmp.eventCode = HistoryItem.EVENT_NONE; - mHistoryAddTmp.states &= ~HistoryItem.STATE_CPU_RUNNING_FLAG; - addHistoryRecordInnerLocked(wakeElapsedTimeMs, uptimeMs, mHistoryAddTmp); - } - } - mHistoryCur.states |= HistoryItem.STATE_CPU_RUNNING_FLAG; - mTrackRunningHistoryElapsedRealtimeMs = elapsedRealtimeMs; - mTrackRunningHistoryUptimeMs = uptimeMs; - addHistoryRecordInnerLocked(elapsedRealtimeMs, uptimeMs, mHistoryCur); - } - - @GuardedBy("this") - void addHistoryRecordInnerLocked(long elapsedRealtimeMs, long uptimeMs, HistoryItem cur) { - addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, cur); - } - - @GuardedBy("this") - public void addHistoryEventLocked(long elapsedRealtimeMs, long uptimeMs, int code, + public void recordHistoryEventLocked(long elapsedRealtimeMs, long uptimeMs, int code, String name, int uid) { - mHistoryCur.eventCode = code; - mHistoryCur.eventTag = mHistoryCur.localEventTag; - mHistoryCur.eventTag.string = name; - mHistoryCur.eventTag.uid = uid; - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); - } - - @GuardedBy("this") - void clearHistoryLocked() { - if (DEBUG_HISTORY) Slog.i(TAG, "********** CLEARING HISTORY!"); - mHistoryBaseTimeMs = 0; - mLastHistoryElapsedRealtimeMs = 0; - mTrackRunningHistoryElapsedRealtimeMs = 0; - mTrackRunningHistoryUptimeMs = 0; - - mHistoryBuffer.setDataSize(0); - mHistoryBuffer.setDataPosition(0); - mHistoryBuffer.setDataCapacity(mConstants.MAX_HISTORY_BUFFER / 2); - mHistoryLastLastWritten.clear(); - mHistoryLastWritten.clear(); - mHistoryTagPool.clear(); - mNextHistoryTagIdx = 0; - mNumHistoryTagChars = 0; - mHistoryBufferLastPos = -1; - mActiveHistoryStates = 0xffffffff; - mActiveHistoryStates2 = 0xffffffff; + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, code, name, uid); } @GuardedBy("this") @@ -4663,13 +4221,13 @@ public class BatteryStatsImpl extends BatteryStats { if (!mActiveEvents.updateState(code, name, uid, 0)) { return; } - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, code, name, uid); + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, code, name, uid); } @GuardedBy("this") public void noteCurrentTimeChangedLocked(long currentTimeMs, long elapsedRealtimeMs, long uptimeMs) { - recordCurrentTimeChangeLocked(currentTimeMs, elapsedRealtimeMs, uptimeMs); + mHistory.recordCurrentTimeChange(elapsedRealtimeMs, uptimeMs, currentTimeMs); } @GuardedBy("this") @@ -4686,7 +4244,7 @@ public class BatteryStatsImpl extends BatteryStats { if (!mRecordAllHistory) { return; } - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_PROC_START, name, uid); + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_PROC_START, name, uid); } @GuardedBy("this") @@ -4744,8 +4302,7 @@ public class BatteryStatsImpl extends BatteryStats { if (!mRecordAllHistory) { return; } - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_PROC_FINISH, - name, uid); + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_PROC_FINISH, name, uid); } @GuardedBy("this") @@ -4761,7 +4318,7 @@ public class BatteryStatsImpl extends BatteryStats { if (!mActiveEvents.updateState(HistoryItem.EVENT_SYNC_START, name, uid, 0)) { return; } - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_SYNC_START, name, uid); + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_SYNC_START, name, uid); } @GuardedBy("this") @@ -4777,8 +4334,7 @@ public class BatteryStatsImpl extends BatteryStats { if (!mActiveEvents.updateState(HistoryItem.EVENT_SYNC_FINISH, name, uid, 0)) { return; } - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_SYNC_FINISH, - name, uid); + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_SYNC_FINISH, name, uid); } @GuardedBy("this") @@ -4794,7 +4350,7 @@ public class BatteryStatsImpl extends BatteryStats { if (!mActiveEvents.updateState(HistoryItem.EVENT_JOB_START, name, uid, 0)) { return; } - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_JOB_START, name, uid); + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_JOB_START, name, uid); } @GuardedBy("this") @@ -4812,7 +4368,7 @@ public class BatteryStatsImpl extends BatteryStats { if (!mActiveEvents.updateState(HistoryItem.EVENT_JOB_FINISH, name, uid, 0)) { return; } - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_JOB_FINISH, name, uid); + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_JOB_FINISH, name, uid); } @GuardedBy("this") @@ -4860,7 +4416,7 @@ public class BatteryStatsImpl extends BatteryStats { for (int i = 0; i < workSource.size(); ++i) { uid = mapUid(workSource.getUid(i)); if (mActiveEvents.updateState(historyItem, name, uid, 0)) { - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, historyItem, name, uid); + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, historyItem, name, uid); } } @@ -4869,7 +4425,7 @@ public class BatteryStatsImpl extends BatteryStats { for (int i = 0; i < workChains.size(); ++i) { uid = mapUid(workChains.get(i).getAttributionUid()); if (mActiveEvents.updateState(historyItem, name, uid, 0)) { - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, historyItem, name, uid); + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, historyItem, name, uid); } } } @@ -4877,7 +4433,7 @@ public class BatteryStatsImpl extends BatteryStats { uid = mapUid(uid); if (mActiveEvents.updateState(historyItem, name, uid, 0)) { - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, historyItem, name, uid); + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, historyItem, name, uid); } } } @@ -4952,7 +4508,7 @@ public class BatteryStatsImpl extends BatteryStats { for (HashMap.Entry<String, SparseIntArray> ent : active.entrySet()) { SparseIntArray uids = ent.getValue(); for (int j=0; j<uids.size(); j++) { - addHistoryEventLocked(mSecRealtime, mSecUptime, + mHistory.recordEvent(mSecRealtime, mSecUptime, HistoryItem.EVENT_PROC_FINISH, ent.getKey(), uids.keyAt(j)); } } @@ -4967,8 +4523,8 @@ public class BatteryStatsImpl extends BatteryStats { for (HashMap.Entry<String, SparseIntArray> ent : active.entrySet()) { SparseIntArray uids = ent.getValue(); for (int j=0; j<uids.size(); j++) { - addHistoryEventLocked(mSecRealtime, mSecUptime, - HistoryItem.EVENT_PROC_START, ent.getKey(), uids.keyAt(j)); + mHistory.recordEvent(mSecRealtime, mSecUptime, HistoryItem.EVENT_PROC_START, + ent.getKey(), uids.keyAt(j)); } } } @@ -5011,30 +4567,19 @@ public class BatteryStatsImpl extends BatteryStats { if (mRecordAllHistory) { if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, historyName, mappedUid, 0)) { - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_WAKE_LOCK_START, historyName, mappedUid); } } if (mWakeLockNesting == 0) { - mHistoryCur.states |= HistoryItem.STATE_WAKE_LOCK_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Start wake lock to: " - + Integer.toHexString(mHistoryCur.states)); - mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag; - mHistoryCur.wakelockTag.string = historyName; - mHistoryCur.wakelockTag.uid = mappedUid; mWakeLockImportant = !unimportantForLogging; - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); - } else if (!mWakeLockImportant && !unimportantForLogging - && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE) { - if (mHistoryLastWritten.wakelockTag != null) { - // We'll try to update the last tag. - mHistoryLastWritten.wakelockTag = null; - mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag; - mHistoryCur.wakelockTag.string = historyName; - mHistoryCur.wakelockTag.uid = mappedUid; - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); - } - mWakeLockImportant = true; + mHistory.recordWakelockStartEvent(elapsedRealtimeMs, uptimeMs, historyName, + mappedUid); + } else if (!mWakeLockImportant && !unimportantForLogging) { + if (mHistory.maybeUpdateWakelockTag(elapsedRealtimeMs, uptimeMs, historyName, + mappedUid)) { + mWakeLockImportant = true; + } } mWakeLockNesting++; } @@ -5087,15 +4632,13 @@ public class BatteryStatsImpl extends BatteryStats { } if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, mappedUid, 0)) { - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, mappedUid); } } if (mWakeLockNesting == 0) { - mHistoryCur.states &= ~HistoryItem.STATE_WAKE_LOCK_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Stop wake lock to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_WAKE_LOCK_FLAG); } } if (mappedUid >= 0) { @@ -5286,7 +4829,7 @@ public class BatteryStatsImpl extends BatteryStats { mappedUid, 0)) { return; } - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_LONG_WAKE_LOCK_START, + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_LONG_WAKE_LOCK_START, historyName, mappedUid); if (mappedUid != uid) { // Prevent the isolated uid mapping from being removed while the wakelock is @@ -5339,7 +4882,7 @@ public class BatteryStatsImpl extends BatteryStats { mappedUid, 0)) { return; } - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH, + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH, historyName, mappedUid); if (mappedUid != uid) { // Decrement the ref count for the isolated uid and delete the mapping if uneeded. @@ -5361,15 +4904,10 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void noteWakeupReasonLocked(String reason, long elapsedRealtimeMs, long uptimeMs) { - if (DEBUG_HISTORY) Slog.v(TAG, "Wakeup reason \"" + reason +"\": " - + Integer.toHexString(mHistoryCur.states)); aggregateLastWakeupUptimeLocked(elapsedRealtimeMs, uptimeMs); - mHistoryCur.wakeReasonTag = mHistoryCur.localWakeReasonTag; - mHistoryCur.wakeReasonTag.string = reason; - mHistoryCur.wakeReasonTag.uid = 0; + mHistory.recordWakeupEvent(elapsedRealtimeMs, uptimeMs, reason); mLastWakeupReason = reason; mLastWakeupUptimeMs = uptimeMs; - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); } @GuardedBy("this") @@ -5380,22 +4918,11 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void finishAddingCpuLocked(int totalUTimeMs, int totalSTimeMs, int statUserTimeMs, - int statSystemTimeMs, int statIOWaitTimeMs, int statIrqTimeMs, - int statSoftIrqTimeMs, int statIdleTimeMs) { - if (DEBUG) { - Slog.d(TAG, "Adding cpu: tuser=" + totalUTimeMs + " tsys=" + totalSTimeMs - + " user=" + statUserTimeMs + " sys=" + statSystemTimeMs - + " io=" + statIOWaitTimeMs + " irq=" + statIrqTimeMs - + " sirq=" + statSoftIrqTimeMs + " idle=" + statIdleTimeMs); - } - mCurStepCpuUserTimeMs += totalUTimeMs; - mCurStepCpuSystemTimeMs += totalSTimeMs; - mCurStepStatUserTimeMs += statUserTimeMs; - mCurStepStatSystemTimeMs += statSystemTimeMs; - mCurStepStatIOWaitTimeMs += statIOWaitTimeMs; - mCurStepStatIrqTimeMs += statIrqTimeMs; - mCurStepStatSoftIrqTimeMs += statSoftIrqTimeMs; - mCurStepStatIdleTimeMs += statIdleTimeMs; + int statSystemTimeMs, int statIOWaitTimeMs, int statIrqTimeMs, + int statSoftIrqTimeMs, int statIdleTimeMs) { + mStepDetailsCalculator.addCpuStats(totalUTimeMs, totalSTimeMs, statUserTimeMs, + statSystemTimeMs, statIOWaitTimeMs, statIrqTimeMs, + statSoftIrqTimeMs, statIdleTimeMs); } public void noteProcessDiedLocked(int uid, int pid) { @@ -5425,10 +4952,8 @@ public class BatteryStatsImpl extends BatteryStats { public void noteStartSensorLocked(int uid, int sensor, long elapsedRealtimeMs, long uptimeMs) { uid = mapUid(uid); if (mSensorNesting == 0) { - mHistoryCur.states |= HistoryItem.STATE_SENSOR_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Start sensor to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordStateStartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_SENSOR_ON_FLAG); } mSensorNesting++; getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -5445,10 +4970,8 @@ public class BatteryStatsImpl extends BatteryStats { uid = mapUid(uid); mSensorNesting--; if (mSensorNesting == 0) { - mHistoryCur.states &= ~HistoryItem.STATE_SENSOR_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Stop sensor to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_SENSOR_ON_FLAG); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) .noteStopSensor(sensor, elapsedRealtimeMs); @@ -5498,10 +5021,8 @@ public class BatteryStatsImpl extends BatteryStats { } final int mappedUid = mapUid(uid); if (mGpsNesting == 0) { - mHistoryCur.states |= HistoryItem.STATE_GPS_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Start GPS to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordStateStartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_GPS_ON_FLAG); } mGpsNesting++; @@ -5526,10 +5047,8 @@ public class BatteryStatsImpl extends BatteryStats { final int mappedUid = mapUid(uid); mGpsNesting--; if (mGpsNesting == 0) { - mHistoryCur.states &= ~HistoryItem.STATE_GPS_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Stop GPS to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_GPS_ON_FLAG); stopAllGpsSignalQualityTimersLocked(-1, elapsedRealtimeMs); mGpsSignalQualityBin = -1; } @@ -5562,12 +5081,9 @@ public class BatteryStatsImpl extends BatteryStats { if(!mGpsSignalQualityTimer[signalLevel].isRunningLocked()) { mGpsSignalQualityTimer[signalLevel].startRunningLocked(elapsedRealtimeMs); } - mHistoryCur.states2 = (mHistoryCur.states2&~HistoryItem.STATE2_GPS_SIGNAL_QUALITY_MASK) - | (signalLevel << HistoryItem.STATE2_GPS_SIGNAL_QUALITY_SHIFT); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordGpsSignalQualityEvent(elapsedRealtimeMs, uptimeMs, signalLevel); mGpsSignalQualityBin = signalLevel; } - return; } @GuardedBy("this") @@ -5740,41 +5256,33 @@ public class BatteryStatsImpl extends BatteryStats { } } - boolean updateHistory = false; + int startStates = 0; + int stopStates = 0; if (Display.isDozeState(state) && !Display.isDozeState(oldState)) { - mHistoryCur.states |= HistoryItem.STATE_SCREEN_DOZE_FLAG; + startStates |= HistoryItem.STATE_SCREEN_DOZE_FLAG; mScreenDozeTimer.startRunningLocked(elapsedRealtimeMs); - updateHistory = true; } else if (Display.isDozeState(oldState) && !Display.isDozeState(state)) { - mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_DOZE_FLAG; + stopStates |= HistoryItem.STATE_SCREEN_DOZE_FLAG; mScreenDozeTimer.stopRunningLocked(elapsedRealtimeMs); - updateHistory = true; } if (Display.isOnState(state)) { - mHistoryCur.states |= HistoryItem.STATE_SCREEN_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Screen on to: " - + Integer.toHexString(mHistoryCur.states)); + startStates |= HistoryItem.STATE_SCREEN_ON_FLAG; mScreenOnTimer.startRunningLocked(elapsedRealtimeMs); if (mScreenBrightnessBin >= 0) { mScreenBrightnessTimer[mScreenBrightnessBin] .startRunningLocked(elapsedRealtimeMs); } - updateHistory = true; } else if (Display.isOnState(oldState)) { - mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Screen off to: " - + Integer.toHexString(mHistoryCur.states)); + stopStates |= HistoryItem.STATE_SCREEN_ON_FLAG; mScreenOnTimer.stopRunningLocked(elapsedRealtimeMs); if (mScreenBrightnessBin >= 0) { mScreenBrightnessTimer[mScreenBrightnessBin] .stopRunningLocked(elapsedRealtimeMs); } - updateHistory = true; } - if (updateHistory) { - if (DEBUG_HISTORY) Slog.v(TAG, "Screen state to: " - + Display.stateToString(state)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + if (startStates != 0 || stopStates != 0) { + mHistory.recordStateChangeEvent(elapsedRealtimeMs, uptimeMs, startStates, + stopStates); } // Per screen state Cpu stats needed. Prepare to schedule an external sync. @@ -5888,13 +5396,7 @@ public class BatteryStatsImpl extends BatteryStats { long uptimeMs) { if (mScreenBrightnessBin != overallBin) { if (overallBin >= 0) { - mHistoryCur.states = (mHistoryCur.states & ~HistoryItem.STATE_BRIGHTNESS_MASK) - | (overallBin << HistoryItem.STATE_BRIGHTNESS_SHIFT); - if (DEBUG_HISTORY) { - Slog.v(TAG, "Screen brightness " + overallBin + " to: " - + Integer.toHexString(mHistoryCur.states)); - } - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordScreenBrightnessEvent(elapsedRealtimeMs, uptimeMs, overallBin); } if (mScreenState == Display.STATE_ON) { if (mScreenBrightnessBin >= 0) { @@ -5921,8 +5423,8 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void noteWakeUpLocked(String reason, int reasonUid, long elapsedRealtimeMs, long uptimeMs) { - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_SCREEN_WAKE_UP, - reason, reasonUid); + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_SCREEN_WAKE_UP, reason, + reasonUid); } @GuardedBy("this") @@ -5941,7 +5443,7 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void noteConnectivityChangedLocked(int type, String extra, long elapsedRealtimeMs, long uptimeMs) { - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_CONNECTIVITY_CHANGED, + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_CONNECTIVITY_CHANGED, extra, type); mNumConnectivityChange++; } @@ -5950,7 +5452,7 @@ public class BatteryStatsImpl extends BatteryStats { private void noteMobileRadioApWakeupLocked(final long elapsedRealtimeMillis, final long uptimeMillis, int uid) { uid = mapUid(uid); - addHistoryEventLocked(elapsedRealtimeMillis, uptimeMillis, HistoryItem.EVENT_WAKEUP_AP, "", + mHistory.recordEvent(elapsedRealtimeMillis, uptimeMillis, HistoryItem.EVENT_WAKEUP_AP, "", uid); getUidStatsLocked(uid, elapsedRealtimeMillis, uptimeMillis).noteMobileRadioApWakeupLocked(); } @@ -5976,7 +5478,8 @@ public class BatteryStatsImpl extends BatteryStats { } mMobileRadioActiveStartTimeMs = realElapsedRealtimeMs = timestampNs / (1000 * 1000); - mHistoryCur.states |= HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG; + mHistory.recordStateStartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG); } else { realElapsedRealtimeMs = timestampNs / (1000*1000); long lastUpdateTimeMs = mMobileRadioActiveStartTimeMs; @@ -5988,11 +5491,9 @@ public class BatteryStatsImpl extends BatteryStats { mMobileRadioActiveAdjustedTime.addCountLocked(elapsedRealtimeMs - realElapsedRealtimeMs); } - mHistoryCur.states &= ~HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG; + mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG); } - if (DEBUG_HISTORY) Slog.v(TAG, "Mobile network active " + active + " to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mMobileRadioPowerState = powerState; // Inform current RatBatteryStats that the modem active state might have changed. @@ -6042,17 +5543,14 @@ public class BatteryStatsImpl extends BatteryStats { mCurStepMode = (mCurStepMode&~STEP_LEVEL_MODE_POWER_SAVE) | stepState; mPowerSaveModeEnabled = enabled; if (enabled) { - mHistoryCur.states2 |= HistoryItem.STATE2_POWER_SAVE_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Power save mode enabled to: " - + Integer.toHexString(mHistoryCur.states2)); + mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_POWER_SAVE_FLAG); mPowerSaveModeEnabledTimer.startRunningLocked(elapsedRealtimeMs); } else { - mHistoryCur.states2 &= ~HistoryItem.STATE2_POWER_SAVE_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Power save mode disabled to: " - + Integer.toHexString(mHistoryCur.states2)); + mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_POWER_SAVE_FLAG); mPowerSaveModeEnabledTimer.stopRunningLocked(elapsedRealtimeMs); } - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); FrameworkStatsLog.write(FrameworkStatsLog.BATTERY_SAVER_MODE_STATE_CHANGED, enabled ? FrameworkStatsLog.BATTERY_SAVER_MODE_STATE_CHANGED__STATE__ON @@ -6076,7 +5574,7 @@ public class BatteryStatsImpl extends BatteryStats { nowLightIdling = true; } if (activeReason != null && (mDeviceIdling || mDeviceLightIdling)) { - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_ACTIVE, + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_ACTIVE, activeReason, activeUid); } if (mDeviceIdling != nowIdling || mDeviceLightIdling != nowLightIdling) { @@ -6106,11 +5604,7 @@ public class BatteryStatsImpl extends BatteryStats { } } if (mDeviceIdleMode != mode) { - mHistoryCur.states2 = (mHistoryCur.states2 & ~HistoryItem.STATE2_DEVICE_IDLE_MASK) - | (mode << HistoryItem.STATE2_DEVICE_IDLE_SHIFT); - if (DEBUG_HISTORY) Slog.v(TAG, "Device idle mode changed to: " - + Integer.toHexString(mHistoryCur.states2)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordDeviceIdleEvent(elapsedRealtimeMs, uptimeMs, mode); long lastDuration = elapsedRealtimeMs - mLastIdleTimeStartMs; mLastIdleTimeStartMs = elapsedRealtimeMs; if (mDeviceIdleMode == DEVICE_IDLE_MODE_LIGHT) { @@ -6138,7 +5632,7 @@ public class BatteryStatsImpl extends BatteryStats { public void notePackageInstalledLocked(String pkgName, long versionCode, long elapsedRealtimeMs, long uptimeMs) { // XXX need to figure out what to do with long version codes. - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_PACKAGE_INSTALLED, + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_PACKAGE_INSTALLED, pkgName, (int)versionCode); PackageChange pc = new PackageChange(); pc.mPackageName = pkgName; @@ -6150,8 +5644,8 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void notePackageUninstalledLocked(String pkgName, long elapsedRealtimeMs, long uptimeMs) { - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, - HistoryItem.EVENT_PACKAGE_UNINSTALLED, pkgName, 0); + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_PACKAGE_UNINSTALLED, + pkgName, 0); PackageChange pc = new PackageChange(); pc.mPackageName = pkgName; pc.mUpdate = true; @@ -6180,10 +5674,8 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void notePhoneOnLocked(long elapsedRealtimeMs, long uptimeMs) { if (!mPhoneOn) { - mHistoryCur.states2 |= HistoryItem.STATE2_PHONE_IN_CALL_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Phone on to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_PHONE_IN_CALL_FLAG); mPhoneOn = true; mPhoneOnTimer.startRunningLocked(elapsedRealtimeMs); } @@ -6192,10 +5684,8 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void notePhoneOffLocked(long elapsedRealtimeMs, long uptimeMs) { if (mPhoneOn) { - mHistoryCur.states2 &= ~HistoryItem.STATE2_PHONE_IN_CALL_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Phone off to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_PHONE_IN_CALL_FLAG); mPhoneOn = false; mPhoneOnTimer.stopRunningLocked(elapsedRealtimeMs); } @@ -6233,11 +5723,12 @@ public class BatteryStatsImpl extends BatteryStats { if (mUsbDataState != newState) { mUsbDataState = newState; if (connected) { - mHistoryCur.states2 |= HistoryItem.STATE2_USB_DATA_LINK_FLAG; + mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_USB_DATA_LINK_FLAG); } else { - mHistoryCur.states2 &= ~HistoryItem.STATE2_USB_DATA_LINK_FLAG; + mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_USB_DATA_LINK_FLAG); } - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); } } @@ -6258,6 +5749,10 @@ public class BatteryStatsImpl extends BatteryStats { long elapsedRealtimeMs, long uptimeMs) { boolean scanning = false; boolean newHistory = false; + int addStateFlag = 0; + int removeStateFlag = 0; + int newState = -1; + int newSignalStrength = -1; mPhoneServiceStateRaw = state; mPhoneSimStateRaw = simState; @@ -6286,10 +5781,8 @@ public class BatteryStatsImpl extends BatteryStats { scanning = true; strengthBin = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN; if (!mPhoneSignalScanningTimer.isRunningLocked()) { - mHistoryCur.states |= HistoryItem.STATE_PHONE_SCANNING_FLAG; + addStateFlag = HistoryItem.STATE_PHONE_SCANNING_FLAG; newHistory = true; - if (DEBUG_HISTORY) Slog.v(TAG, "Phone started scanning to: " - + Integer.toHexString(mHistoryCur.states)); mPhoneSignalScanningTimer.startRunningLocked(elapsedRealtimeMs); FrameworkStatsLog.write(FrameworkStatsLog.PHONE_SERVICE_STATE_CHANGED, state, simState, strengthBin); @@ -6299,9 +5792,7 @@ public class BatteryStatsImpl extends BatteryStats { if (!scanning) { // If we are no longer scanning, then stop the scanning timer. if (mPhoneSignalScanningTimer.isRunningLocked()) { - mHistoryCur.states &= ~HistoryItem.STATE_PHONE_SCANNING_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Phone stopped scanning to: " - + Integer.toHexString(mHistoryCur.states)); + removeStateFlag = HistoryItem.STATE_PHONE_SCANNING_FLAG; newHistory = true; mPhoneSignalScanningTimer.stopRunningLocked(elapsedRealtimeMs); FrameworkStatsLog.write(FrameworkStatsLog.PHONE_SERVICE_STATE_CHANGED, state, @@ -6310,10 +5801,7 @@ public class BatteryStatsImpl extends BatteryStats { } if (mPhoneServiceState != state) { - mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_PHONE_STATE_MASK) - | (state << HistoryItem.STATE_PHONE_STATE_SHIFT); - if (DEBUG_HISTORY) Slog.v(TAG, "Phone state " + state + " to: " - + Integer.toHexString(mHistoryCur.states)); + newState = state; newHistory = true; mPhoneServiceState = state; } @@ -6327,11 +5815,7 @@ public class BatteryStatsImpl extends BatteryStats { if (!mPhoneSignalStrengthsTimer[strengthBin].isRunningLocked()) { mPhoneSignalStrengthsTimer[strengthBin].startRunningLocked(elapsedRealtimeMs); } - mHistoryCur.states = - (mHistoryCur.states & ~HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_MASK) - | (strengthBin << HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_SHIFT); - if (DEBUG_HISTORY) Slog.v(TAG, "Signal strength " + strengthBin + " to: " - + Integer.toHexString(mHistoryCur.states)); + newSignalStrength = strengthBin; newHistory = true; FrameworkStatsLog.write( FrameworkStatsLog.PHONE_SIGNAL_STRENGTH_CHANGED, strengthBin); @@ -6342,7 +5826,8 @@ public class BatteryStatsImpl extends BatteryStats { } if (newHistory) { - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordPhoneStateChangeEvent(elapsedRealtimeMs, uptimeMs, + addStateFlag, removeStateFlag, newState, newSignalStrength); } } @@ -6466,11 +5951,7 @@ public class BatteryStatsImpl extends BatteryStats { if (DEBUG) Log.i(TAG, "Phone Data Connection -> " + dataType + " = " + hasData); if (mPhoneDataConnectionType != bin) { - mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_DATA_CONNECTION_MASK) - | (bin << HistoryItem.STATE_DATA_CONNECTION_SHIFT); - if (DEBUG_HISTORY) Slog.v(TAG, "Data connection " + bin + " to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordDataConnectionTypeChangeEvent(elapsedRealtimeMs, uptimeMs, bin); if (mPhoneDataConnectionType >= 0) { mPhoneDataConnectionsTimer[mPhoneDataConnectionType].stopRunningLocked( elapsedRealtimeMs); @@ -6543,10 +6024,8 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void noteWifiOnLocked(long elapsedRealtimeMs, long uptimeMs) { if (!mWifiOn) { - mHistoryCur.states2 |= HistoryItem.STATE2_WIFI_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "WIFI on to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_WIFI_ON_FLAG); mWifiOn = true; mWifiOnTimer.startRunningLocked(elapsedRealtimeMs); scheduleSyncExternalStatsLocked("wifi-off", ExternalStatsSync.UPDATE_WIFI); @@ -6556,10 +6035,8 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void noteWifiOffLocked(long elapsedRealtimeMs, long uptimeMs) { if (mWifiOn) { - mHistoryCur.states2 &= ~HistoryItem.STATE2_WIFI_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "WIFI off to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_WIFI_ON_FLAG); mWifiOn = false; mWifiOnTimer.stopRunningLocked(elapsedRealtimeMs); scheduleSyncExternalStatsLocked("wifi-on", ExternalStatsSync.UPDATE_WIFI); @@ -6570,10 +6047,8 @@ public class BatteryStatsImpl extends BatteryStats { public void noteAudioOnLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { uid = mapUid(uid); if (mAudioOnNesting == 0) { - mHistoryCur.states |= HistoryItem.STATE_AUDIO_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Audio on to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordStateStartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_AUDIO_ON_FLAG); mAudioOnTimer.startRunningLocked(elapsedRealtimeMs); } mAudioOnNesting++; @@ -6588,10 +6063,8 @@ public class BatteryStatsImpl extends BatteryStats { } uid = mapUid(uid); if (--mAudioOnNesting == 0) { - mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_AUDIO_ON_FLAG); mAudioOnTimer.stopRunningLocked(elapsedRealtimeMs); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -6602,10 +6075,8 @@ public class BatteryStatsImpl extends BatteryStats { public void noteVideoOnLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { uid = mapUid(uid); if (mVideoOnNesting == 0) { - mHistoryCur.states2 |= HistoryItem.STATE2_VIDEO_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Video on to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_VIDEO_ON_FLAG); mVideoOnTimer.startRunningLocked(elapsedRealtimeMs); } mVideoOnNesting++; @@ -6620,10 +6091,8 @@ public class BatteryStatsImpl extends BatteryStats { } uid = mapUid(uid); if (--mVideoOnNesting == 0) { - mHistoryCur.states2 &= ~HistoryItem.STATE2_VIDEO_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_VIDEO_ON_FLAG); mVideoOnTimer.stopRunningLocked(elapsedRealtimeMs); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -6634,10 +6103,8 @@ public class BatteryStatsImpl extends BatteryStats { public void noteResetAudioLocked(long elapsedRealtimeMs, long uptimeMs) { if (mAudioOnNesting > 0) { mAudioOnNesting = 0; - mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_AUDIO_ON_FLAG); mAudioOnTimer.stopAllRunningLocked(elapsedRealtimeMs); for (int i=0; i<mUidStats.size(); i++) { BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); @@ -6650,10 +6117,8 @@ public class BatteryStatsImpl extends BatteryStats { public void noteResetVideoLocked(long elapsedRealtimeMs, long uptimeMs) { if (mVideoOnNesting > 0) { mVideoOnNesting = 0; - mHistoryCur.states2 &= ~HistoryItem.STATE2_VIDEO_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_VIDEO_ON_FLAG); mVideoOnTimer.stopAllRunningLocked(elapsedRealtimeMs); for (int i=0; i<mUidStats.size(); i++) { BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); @@ -6705,10 +6170,8 @@ public class BatteryStatsImpl extends BatteryStats { public void noteFlashlightOnLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { uid = mapUid(uid); if (mFlashlightOnNesting++ == 0) { - mHistoryCur.states2 |= HistoryItem.STATE2_FLASHLIGHT_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight on to: " - + Integer.toHexString(mHistoryCur.states2)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_FLASHLIGHT_FLAG); mFlashlightOnTimer.startRunningLocked(elapsedRealtimeMs); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -6722,10 +6185,8 @@ public class BatteryStatsImpl extends BatteryStats { } uid = mapUid(uid); if (--mFlashlightOnNesting == 0) { - mHistoryCur.states2 &= ~HistoryItem.STATE2_FLASHLIGHT_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight off to: " - + Integer.toHexString(mHistoryCur.states2)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_FLASHLIGHT_FLAG); mFlashlightOnTimer.stopRunningLocked(elapsedRealtimeMs); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -6736,10 +6197,8 @@ public class BatteryStatsImpl extends BatteryStats { public void noteCameraOnLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { uid = mapUid(uid); if (mCameraOnNesting++ == 0) { - mHistoryCur.states2 |= HistoryItem.STATE2_CAMERA_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Camera on to: " - + Integer.toHexString(mHistoryCur.states2)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_CAMERA_FLAG); mCameraOnTimer.startRunningLocked(elapsedRealtimeMs); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -6753,10 +6212,8 @@ public class BatteryStatsImpl extends BatteryStats { } uid = mapUid(uid); if (--mCameraOnNesting == 0) { - mHistoryCur.states2 &= ~HistoryItem.STATE2_CAMERA_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Camera off to: " - + Integer.toHexString(mHistoryCur.states2)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_CAMERA_FLAG); mCameraOnTimer.stopRunningLocked(elapsedRealtimeMs); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -6767,10 +6224,8 @@ public class BatteryStatsImpl extends BatteryStats { public void noteResetCameraLocked(long elapsedRealtimeMs, long uptimeMs) { if (mCameraOnNesting > 0) { mCameraOnNesting = 0; - mHistoryCur.states2 &= ~HistoryItem.STATE2_CAMERA_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Camera off to: " - + Integer.toHexString(mHistoryCur.states2)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_CAMERA_FLAG); mCameraOnTimer.stopAllRunningLocked(elapsedRealtimeMs); for (int i=0; i<mUidStats.size(); i++) { BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); @@ -6783,10 +6238,8 @@ public class BatteryStatsImpl extends BatteryStats { public void noteResetFlashlightLocked(long elapsedRealtimeMs, long uptimeMs) { if (mFlashlightOnNesting > 0) { mFlashlightOnNesting = 0; - mHistoryCur.states2 &= ~HistoryItem.STATE2_FLASHLIGHT_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight off to: " - + Integer.toHexString(mHistoryCur.states2)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_FLASHLIGHT_FLAG); mFlashlightOnTimer.stopAllRunningLocked(elapsedRealtimeMs); for (int i=0; i<mUidStats.size(); i++) { BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); @@ -6803,10 +6256,8 @@ public class BatteryStatsImpl extends BatteryStats { } uid = mapUid(uid); if (mBluetoothScanNesting == 0) { - mHistoryCur.states2 |= HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "BLE scan started for: " - + Integer.toHexString(mHistoryCur.states2)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG); mBluetoothScanTimer.startRunningLocked(elapsedRealtimeMs); } mBluetoothScanNesting++; @@ -6847,10 +6298,8 @@ public class BatteryStatsImpl extends BatteryStats { uid = mapUid(uid); mBluetoothScanNesting--; if (mBluetoothScanNesting == 0) { - mHistoryCur.states2 &= ~HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "BLE scan stopped for: " - + Integer.toHexString(mHistoryCur.states2)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG); mBluetoothScanTimer.stopRunningLocked(elapsedRealtimeMs); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -6885,10 +6334,8 @@ public class BatteryStatsImpl extends BatteryStats { public void noteResetBluetoothScanLocked(long elapsedRealtimeMs, long uptimeMs) { if (mBluetoothScanNesting > 0) { mBluetoothScanNesting = 0; - mHistoryCur.states2 &= ~HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "BLE can stopped for: " - + Integer.toHexString(mHistoryCur.states2)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG); mBluetoothScanTimer.stopAllRunningLocked(elapsedRealtimeMs); for (int i=0; i<mUidStats.size(); i++) { BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); @@ -6928,7 +6375,7 @@ public class BatteryStatsImpl extends BatteryStats { private void noteWifiRadioApWakeupLocked(final long elapsedRealtimeMillis, final long uptimeMillis, int uid) { uid = mapUid(uid); - addHistoryEventLocked(elapsedRealtimeMillis, uptimeMillis, HistoryItem.EVENT_WAKEUP_AP, "", + mHistory.recordEvent(elapsedRealtimeMillis, uptimeMillis, HistoryItem.EVENT_WAKEUP_AP, "", uid); getUidStatsLocked(uid, elapsedRealtimeMillis, uptimeMillis).noteWifiRadioApWakeupLocked(); } @@ -6944,15 +6391,14 @@ public class BatteryStatsImpl extends BatteryStats { if (uid > 0) { noteWifiRadioApWakeupLocked(elapsedRealtimeMs, uptimeMs, uid); } - mHistoryCur.states |= HistoryItem.STATE_WIFI_RADIO_ACTIVE_FLAG; + mHistory.recordStateStartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_WIFI_RADIO_ACTIVE_FLAG); mWifiActiveTimer.startRunningLocked(elapsedRealtimeMs); } else { - mHistoryCur.states &= ~HistoryItem.STATE_WIFI_RADIO_ACTIVE_FLAG; + mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_WIFI_RADIO_ACTIVE_FLAG); mWifiActiveTimer.stopRunningLocked(timestampNs / (1000 * 1000)); } - if (DEBUG_HISTORY) Slog.v(TAG, "Wifi network active " + active + " to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mWifiRadioPowerState = powerState; } } @@ -6960,10 +6406,8 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void noteWifiRunningLocked(WorkSource ws, long elapsedRealtimeMs, long uptimeMs) { if (!mGlobalWifiRunning) { - mHistoryCur.states2 |= HistoryItem.STATE2_WIFI_RUNNING_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "WIFI running to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_WIFI_RUNNING_FLAG); mGlobalWifiRunning = true; mGlobalWifiRunningTimer.startRunningLocked(elapsedRealtimeMs); int N = ws.size(); @@ -7031,10 +6475,8 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void noteWifiStoppedLocked(WorkSource ws, long elapsedRealtimeMs, long uptimeMs) { if (mGlobalWifiRunning) { - mHistoryCur.states2 &= ~HistoryItem.STATE2_WIFI_RUNNING_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "WIFI stopped to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_WIFI_RUNNING_FLAG); mGlobalWifiRunning = false; mGlobalWifiRunningTimer.stopRunningLocked(elapsedRealtimeMs); int N = ws.size(); @@ -7082,12 +6524,7 @@ public class BatteryStatsImpl extends BatteryStats { } mWifiSupplState = supplState; mWifiSupplStateTimer[supplState].startRunningLocked(elapsedRealtimeMs); - mHistoryCur.states2 = - (mHistoryCur.states2&~HistoryItem.STATE2_WIFI_SUPPL_STATE_MASK) - | (supplState << HistoryItem.STATE2_WIFI_SUPPL_STATE_SHIFT); - if (DEBUG_HISTORY) Slog.v(TAG, "Wifi suppl state " + supplState + " to: " - + Integer.toHexString(mHistoryCur.states2)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordWifiSupplicantStateChangeEvent(elapsedRealtimeMs, uptimeMs, supplState); } } @@ -7116,12 +6553,8 @@ public class BatteryStatsImpl extends BatteryStats { if (!mWifiSignalStrengthsTimer[strengthBin].isRunningLocked()) { mWifiSignalStrengthsTimer[strengthBin].startRunningLocked(elapsedRealtimeMs); } - mHistoryCur.states2 = - (mHistoryCur.states2&~HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_MASK) - | (strengthBin << HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_SHIFT); - if (DEBUG_HISTORY) Slog.v(TAG, "Wifi signal strength " + strengthBin + " to: " - + Integer.toHexString(mHistoryCur.states2)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordWifiSignalStrengthChangeEvent(elapsedRealtimeMs, uptimeMs, + strengthBin); } else { stopAllWifiSignalStrengthTimersLocked(-1, elapsedRealtimeMs); } @@ -7134,10 +6567,8 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void noteFullWifiLockAcquiredLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { if (mWifiFullLockNesting == 0) { - mHistoryCur.states |= HistoryItem.STATE_WIFI_FULL_LOCK_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock on to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordStateStartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_WIFI_FULL_LOCK_FLAG); } mWifiFullLockNesting++; getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -7148,10 +6579,8 @@ public class BatteryStatsImpl extends BatteryStats { public void noteFullWifiLockReleasedLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { mWifiFullLockNesting--; if (mWifiFullLockNesting == 0) { - mHistoryCur.states &= ~HistoryItem.STATE_WIFI_FULL_LOCK_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock off to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_WIFI_FULL_LOCK_FLAG); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) .noteFullWifiLockReleasedLocked(elapsedRealtimeMs); @@ -7167,10 +6596,8 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void noteWifiScanStartedLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { if (mWifiScanNesting == 0) { - mHistoryCur.states |= HistoryItem.STATE_WIFI_SCAN_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan started for: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordStateStartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_WIFI_SCAN_FLAG); } mWifiScanNesting++; getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -7186,10 +6613,8 @@ public class BatteryStatsImpl extends BatteryStats { public void noteWifiScanStoppedLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { mWifiScanNesting--; if (mWifiScanNesting == 0) { - mHistoryCur.states &= ~HistoryItem.STATE_WIFI_SCAN_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan stopped for: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_WIFI_SCAN_FLAG); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) .noteWifiScanStoppedLocked(elapsedRealtimeMs); @@ -7214,14 +6639,10 @@ public class BatteryStatsImpl extends BatteryStats { public void noteWifiMulticastEnabledLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { uid = mapUid(uid); if (mWifiMulticastNesting == 0) { - mHistoryCur.states |= HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast on to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); - + mHistory.recordStateStartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG); // Start Wifi Multicast overall timer if (!mWifiMulticastWakelockTimer.isRunningLocked()) { - if (DEBUG_HISTORY) Slog.v(TAG, "WiFi Multicast Overall Timer Started"); mWifiMulticastWakelockTimer.startRunningLocked(elapsedRealtimeMs); } } @@ -7235,14 +6656,12 @@ public class BatteryStatsImpl extends BatteryStats { uid = mapUid(uid); mWifiMulticastNesting--; if (mWifiMulticastNesting == 0) { - mHistoryCur.states &= ~HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast off to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG); // Stop Wifi Multicast overall timer if (mWifiMulticastWakelockTimer.isRunningLocked()) { - if (DEBUG_HISTORY) Slog.v(TAG, "Multicast Overall Timer Stopped"); + if (DEBUG) Slog.v(TAG, "Multicast Overall Timer Stopped"); mWifiMulticastWakelockTimer.stopRunningLocked(elapsedRealtimeMs); } } @@ -7994,8 +7413,9 @@ public class BatteryStatsImpl extends BatteryStats { // If the start clock time has changed by more than a year, then presumably // the previous time was completely bogus. So we are going to figure out a // new time based on how much time has elapsed since we started counting. - recordCurrentTimeChangeLocked(currentTimeMs, mClock.elapsedRealtime(), - mClock.uptimeMillis()); + mHistory.recordCurrentTimeChange(mClock.elapsedRealtime(), mClock.uptimeMillis(), + currentTimeMs + ); return currentTimeMs - (mClock.elapsedRealtime() - (mRealtimeStartUs / 1000)); } return mStartClockTimeMs; @@ -11227,18 +10647,19 @@ public class BatteryStatsImpl extends BatteryStats { UserInfoProvider userInfoProvider) { init(clock); + mHandler = new MyHandler(handler.getLooper()); + mConstants = new Constants(mHandler); + if (systemDir == null) { mStatsFile = null; - mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer); + mHistory = new BatteryStatsHistory(mStepDetailsCalculator, mClock); } else { mStatsFile = new AtomicFile(new File(systemDir, "batterystats.bin")); - mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer, systemDir, - this::getMaxHistoryFiles); + mHistory = new BatteryStatsHistory(systemDir, mConstants.MAX_HISTORY_FILES, + mConstants.MAX_HISTORY_BUFFER, mStepDetailsCalculator, mClock); } mCheckinFile = new AtomicFile(new File(systemDir, "batterystats-checkin.bin")); mDailyFile = new AtomicFile(new File(systemDir, "batterystats-daily.xml")); - mHandler = new MyHandler(handler.getLooper()); - mConstants = new Constants(mHandler); mStartCount++; initTimersAndCounters(); mOnBattery = mOnBatteryInternal = false; @@ -11247,7 +10668,6 @@ public class BatteryStatsImpl extends BatteryStats { initTimes(uptimeUs, realtimeUs); mStartPlatformVersion = mEndPlatformVersion = Build.ID; initDischarge(realtimeUs); - clearHistoryLocked(); updateDailyDeadlineLocked(); mPlatformIdleStateCallback = cb; mMeasuredEnergyRetriever = energyStatsCb; @@ -11258,12 +10678,6 @@ public class BatteryStatsImpl extends BatteryStats { FrameworkStatsLog.write(FrameworkStatsLog.DEVICE_IDLE_MODE_STATE_CHANGED, mDeviceIdleMode); } - private int getMaxHistoryFiles() { - synchronized (this) { - return mConstants.MAX_HISTORY_FILES; - } - } - @VisibleForTesting protected void initTimersAndCounters() { mScreenOnTimer = new StopwatchTimer(mClock, null, -1, null, mOnBatteryTimeBase); @@ -11345,7 +10759,7 @@ public class BatteryStatsImpl extends BatteryStats { mDischargeUnplugLevel = 0; mDischargePlugLevel = -1; mDischargeCurrentLevel = 0; - mCurrentBatteryLevel = 0; + mBatteryLevel = 0; } public void setPowerProfileLocked(PowerProfile profile) { @@ -11732,7 +11146,7 @@ public class BatteryStatsImpl extends BatteryStats { } public int getHistoryUsedSize() { - return mBatteryStatsHistory.getHistoryUsedSize(); + return mHistory.getHistoryUsedSize(); } @Override @@ -11746,43 +11160,27 @@ public class BatteryStatsImpl extends BatteryStats { */ @VisibleForTesting public BatteryStatsHistoryIterator createBatteryStatsHistoryIterator() { - return new BatteryStatsHistoryIterator(mBatteryStatsHistory); + return mHistory.iterate(); } @Override public int getHistoryStringPoolSize() { - return mHistoryTagPool.size(); + return mHistory.getHistoryStringPoolSize(); } @Override public int getHistoryStringPoolBytes() { - return mNumHistoryTagChars; + return mHistory.getHistoryStringPoolBytes(); } @Override public String getHistoryTagPoolString(int index) { - ensureHistoryTagArray(); - HistoryTag historyTag = mHistoryTags.get(index); - return historyTag != null ? historyTag.string : null; + return mHistory.getHistoryTagPoolString(index); } @Override public int getHistoryTagPoolUid(int index) { - ensureHistoryTagArray(); - HistoryTag historyTag = mHistoryTags.get(index); - return historyTag != null ? historyTag.uid : Process.INVALID_UID; - } - - private void ensureHistoryTagArray() { - if (mHistoryTags != null) { - return; - } - - mHistoryTags = new SparseArray<>(mHistoryTagPool.size()); - for (Map.Entry<HistoryTag, Integer> entry: mHistoryTagPool.entrySet()) { - mHistoryTags.put(entry.getValue() & ~BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG, - entry.getKey()); - } + return mHistory.getHistoryTagPoolUid(index); } @Override @@ -11792,15 +11190,11 @@ public class BatteryStatsImpl extends BatteryStats { @Override public void finishIteratingHistoryLocked() { + mBatteryStatsHistoryIterator.close(); mBatteryStatsHistoryIterator = null; } @Override - public long getHistoryBaseTime() { - return mHistoryBaseTimeMs; - } - - @Override public int getStartCount() { return mStartCount; } @@ -11853,24 +11247,23 @@ public class BatteryStatsImpl extends BatteryStats { long realtimeUs = mSecRealtime * 1000; resetAllStatsLocked(mSecUptime, mSecRealtime, RESET_REASON_ADB_COMMAND); pullPendingStateUpdatesLocked(); - addHistoryRecordLocked(mSecRealtime, mSecUptime); - mDischargeCurrentLevel = mDischargeUnplugLevel = mDischargePlugLevel - = mCurrentBatteryLevel = mHistoryCur.batteryLevel; + mHistory.writeHistoryItem(mSecRealtime, mSecUptime); + mDischargeCurrentLevel = mDischargeUnplugLevel = mDischargePlugLevel = mBatteryLevel; mOnBatteryTimeBase.reset(uptimeUs, realtimeUs); mOnBatteryScreenOffTimeBase.reset(uptimeUs, realtimeUs); - if ((mHistoryCur.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) == 0) { + if (!mBatteryPluggedIn) { if (Display.isOnState(mScreenState)) { - mDischargeScreenOnUnplugLevel = mHistoryCur.batteryLevel; + mDischargeScreenOnUnplugLevel = mBatteryLevel; mDischargeScreenDozeUnplugLevel = 0; mDischargeScreenOffUnplugLevel = 0; } else if (Display.isDozeState(mScreenState)) { mDischargeScreenOnUnplugLevel = 0; - mDischargeScreenDozeUnplugLevel = mHistoryCur.batteryLevel; + mDischargeScreenDozeUnplugLevel = mBatteryLevel; mDischargeScreenOffUnplugLevel = 0; } else { mDischargeScreenOnUnplugLevel = 0; mDischargeScreenDozeUnplugLevel = 0; - mDischargeScreenOffUnplugLevel = mHistoryCur.batteryLevel; + mDischargeScreenOffUnplugLevel = mBatteryLevel; } mDischargeAmountScreenOn = 0; mDischargeAmountScreenOff = 0; @@ -12014,27 +11407,12 @@ public class BatteryStatsImpl extends BatteryStats { resetIfNotNull(mBinderThreadCpuTimesUs, false, elapsedRealtimeUs); - mLastHistoryStepDetails = null; - mLastStepCpuUserTimeMs = mLastStepCpuSystemTimeMs = 0; - mCurStepCpuUserTimeMs = mCurStepCpuSystemTimeMs = 0; - mLastStepCpuUserTimeMs = mCurStepCpuUserTimeMs = 0; - mLastStepCpuSystemTimeMs = mCurStepCpuSystemTimeMs = 0; - mLastStepStatUserTimeMs = mCurStepStatUserTimeMs = 0; - mLastStepStatSystemTimeMs = mCurStepStatSystemTimeMs = 0; - mLastStepStatIOWaitTimeMs = mCurStepStatIOWaitTimeMs = 0; - mLastStepStatIrqTimeMs = mCurStepStatIrqTimeMs = 0; - mLastStepStatSoftIrqTimeMs = mCurStepStatSoftIrqTimeMs = 0; - mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs = 0; - mNumAllUidCpuTimeReads = 0; mNumUidsRemoved = 0; initDischarge(elapsedRealtimeUs); - clearHistoryLocked(); - if (mBatteryStatsHistory != null) { - mBatteryStatsHistory.resetAllFiles(); - } + mHistory.reset(); // Flush external data, gathering snapshots, but don't process it since it is pre-reset data mIgnoreNextExternalStats = true; @@ -12057,7 +11435,7 @@ public class BatteryStatsImpl extends BatteryStats { for (HashMap.Entry<String, SparseIntArray> ent : active.entrySet()) { SparseIntArray uids = ent.getValue(); for (int j=0; j<uids.size(); j++) { - addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, i, ent.getKey(), + mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, i, ent.getKey(), uids.keyAt(j)); } } @@ -12482,9 +11860,8 @@ public class BatteryStatsImpl extends BatteryStats { (long) (mTmpRailStats.getWifiTotalEnergyUseduWs() / opVolt); mWifiActivity.getMonitoredRailChargeConsumedMaMs().addCountLocked( monitoredRailChargeConsumedMaMs); - mHistoryCur.wifiRailChargeMah += - (monitoredRailChargeConsumedMaMs / MILLISECONDS_IN_HOUR); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordWifiConsumedCharge(elapsedRealtimeMs, uptimeMs, + (monitoredRailChargeConsumedMaMs / MILLISECONDS_IN_HOUR)); mTmpRailStats.resetWifiTotalEnergyUsed(); if (uidEstimatedConsumptionMah != null) { @@ -12597,9 +11974,8 @@ public class BatteryStatsImpl extends BatteryStats { (long) (mTmpRailStats.getCellularTotalEnergyUseduWs() / opVolt); mModemActivity.getMonitoredRailChargeConsumedMaMs().addCountLocked( monitoredRailChargeConsumedMaMs); - mHistoryCur.modemRailChargeMah += - (monitoredRailChargeConsumedMaMs / MILLISECONDS_IN_HOUR); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordWifiConsumedCharge(elapsedRealtimeMs, uptimeMs, + (monitoredRailChargeConsumedMaMs / MILLISECONDS_IN_HOUR)); mTmpRailStats.resetCellularTotalEnergyUsed(); } @@ -12867,8 +12243,8 @@ public class BatteryStatsImpl extends BatteryStats { } } if (levelMaxTimeSpent == ModemActivityInfo.getNumTxPowerLevels() - 1) { - mHistoryCur.states2 |= HistoryItem.STATE2_CELLULAR_HIGH_TX_POWER_FLAG; - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, + HistoryItem.STATE2_CELLULAR_HIGH_TX_POWER_FLAG); } } @@ -14301,11 +13677,7 @@ public class BatteryStatsImpl extends BatteryStats { mHandler.removeCallbacks(mDeferSetCharging); if (mCharging != charging) { mCharging = charging; - if (charging) { - mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG; - } else { - mHistoryCur.states2 &= ~HistoryItem.STATE2_CHARGING_FLAG; - } + mHistory.setChargingState(charging); mHandler.sendEmptyMessage(MSG_REPORT_CHARGING); return true; } @@ -14319,6 +13691,15 @@ public class BatteryStatsImpl extends BatteryStats { mSystemReady = true; } + /** + * Force recording of all history events regardless of the "charging" state. + */ + @VisibleForTesting + public void forceRecordAllHistory() { + mHistory.forceRecordAllHistory(); + mRecordAllHistory = true; + } + @GuardedBy("this") protected void setOnBatteryLocked(final long mSecRealtime, final long mSecUptime, final boolean onBattery, final int oldStatus, final int level, final int chargeUah) { @@ -14402,15 +13783,12 @@ public class BatteryStatsImpl extends BatteryStats { mInitStepMode = mCurStepMode; mModStepMode = 0; pullPendingStateUpdatesLocked(); - mHistoryCur.batteryLevel = (byte)level; - mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: " - + Integer.toHexString(mHistoryCur.states)); if (reset) { - mRecordingHistory = true; - startRecordingHistory(mSecRealtime, mSecUptime, reset); + mHistory.startRecordingHistory(mSecRealtime, mSecUptime, reset); + initActiveHistoryEventsLocked(mSecRealtime, mSecUptime); } - addHistoryRecordLocked(mSecRealtime, mSecUptime); + mBatteryPluggedIn = false; + mHistory.recordBatteryState(mSecRealtime, mSecUptime, level, mBatteryPluggedIn); mDischargeCurrentLevel = mDischargeUnplugLevel = level; if (Display.isOnState(screenState)) { mDischargeScreenOnUnplugLevel = level; @@ -14432,11 +13810,8 @@ public class BatteryStatsImpl extends BatteryStats { } else { mOnBattery = mOnBatteryInternal = false; pullPendingStateUpdatesLocked(); - mHistoryCur.batteryLevel = (byte)level; - mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG; - if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(mSecRealtime, mSecUptime); + mBatteryPluggedIn = true; + mHistory.recordBatteryState(mSecRealtime, mSecUptime, level, mBatteryPluggedIn); mDischargeCurrentLevel = mDischargePlugLevel = level; if (level < mDischargeUnplugLevel) { mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1; @@ -14451,45 +13826,12 @@ public class BatteryStatsImpl extends BatteryStats { mModStepMode = 0; } if (doWrite || (mLastWriteTimeMs + (60 * 1000)) < mSecRealtime) { - if (mStatsFile != null && mBatteryStatsHistory.getActiveFile() != null) { + if (mStatsFile != null && !mHistory.isReadOnly()) { writeAsyncLocked(); } } } - @GuardedBy("this") - private void startRecordingHistory(final long elapsedRealtimeMs, final long uptimeMs, - boolean reset) { - mRecordingHistory = true; - mHistoryCur.currentTime = mClock.currentTimeMillis(); - addHistoryBufferLocked(elapsedRealtimeMs, - reset ? HistoryItem.CMD_RESET : HistoryItem.CMD_CURRENT_TIME, - mHistoryCur); - mHistoryCur.currentTime = 0; - if (reset) { - initActiveHistoryEventsLocked(elapsedRealtimeMs, uptimeMs); - } - } - - @GuardedBy("this") - private void recordCurrentTimeChangeLocked(final long currentTimeMs, - final long elapsedRealtimeMs, final long uptimeMs) { - if (mRecordingHistory) { - mHistoryCur.currentTime = currentTimeMs; - addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_CURRENT_TIME, mHistoryCur); - mHistoryCur.currentTime = 0; - } - } - - @GuardedBy("this") - private void recordShutdownLocked(final long currentTimeMs, final long elapsedRealtimeMs) { - if (mRecordingHistory) { - mHistoryCur.currentTime = currentTimeMs; - addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_SHUTDOWN, mHistoryCur); - mHistoryCur.currentTime = 0; - } - } - private void scheduleSyncExternalStatsLocked(String reason, int updateFlags) { if (mExternalSync != null) { mExternalSync.scheduleSync(reason, updateFlags); @@ -14507,8 +13849,7 @@ public class BatteryStatsImpl extends BatteryStats { // Temperature is encoded without the signed bit, so clamp any negative temperatures to 0. temp = Math.max(0, temp); - reportChangesToStatsLog(mHaveBatteryLevel ? mHistoryCur : null, - status, plugType, level); + reportChangesToStatsLog(status, plugType, level); final boolean onBattery = isOnBattery(plugType, status); if (!mHaveBatteryLevel) { @@ -14518,52 +13859,47 @@ public class BatteryStatsImpl extends BatteryStats { // plugged in, then twiddle our state to correctly reflect that // since we won't be going through the full setOnBattery(). if (onBattery == mOnBattery) { - if (onBattery) { - mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG; - } else { - mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG; - } + mHistory.setPluggedInState(!onBattery); } + mBatteryStatus = status; + mBatteryLevel = level; + mBatteryChargeUah = chargeUah; + // Always start out assuming charging, that will be updated later. - mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG; - mHistoryCur.batteryStatus = (byte)status; - mHistoryCur.batteryLevel = (byte)level; - mHistoryCur.batteryChargeUah = chargeUah; + mHistory.setBatteryState(true /* charging */, status, level, chargeUah); + mMaxChargeStepLevel = mMinDischargeStepLevel = mLastChargeStepLevel = mLastDischargeStepLevel = level; - } else if (mCurrentBatteryLevel != level || mOnBattery != onBattery) { + } else if (mBatteryLevel != level || mOnBattery != onBattery) { recordDailyStatsIfNeededLocked(level >= 100 && onBattery, currentTimeMs); } - int oldStatus = mHistoryCur.batteryStatus; + int oldStatus = mBatteryStatus; if (onBattery) { mDischargeCurrentLevel = level; - if (!mRecordingHistory) { - mRecordingHistory = true; - startRecordingHistory(elapsedRealtimeMs, uptimeMs, true); + if (!mHistory.isRecordingHistory()) { + mHistory.startRecordingHistory(elapsedRealtimeMs, uptimeMs, true); } } else if (level < 96 && status != BatteryManager.BATTERY_STATUS_UNKNOWN) { - if (!mRecordingHistory) { - mRecordingHistory = true; - startRecordingHistory(elapsedRealtimeMs, uptimeMs, true); + if (!mHistory.isRecordingHistory()) { + mHistory.startRecordingHistory(elapsedRealtimeMs, uptimeMs, true); } } - mBatteryVoltageMv = voltageMv; - mCurrentBatteryLevel = level; if (mDischargePlugLevel < 0) { mDischargePlugLevel = level; } if (onBattery != mOnBattery) { - mHistoryCur.batteryLevel = (byte)level; - mHistoryCur.batteryStatus = (byte)status; - mHistoryCur.batteryHealth = (byte)health; - mHistoryCur.batteryPlugType = (byte)plugType; - mHistoryCur.batteryTemperature = (short)temp; - mHistoryCur.batteryVoltage = (char) voltageMv; - if (chargeUah < mHistoryCur.batteryChargeUah) { + mBatteryLevel = level; + mBatteryStatus = status; + mBatteryHealth = health; + mBatteryPlugType = plugType; + mBatteryTemperature = temp; + mBatteryVoltageMv = voltageMv; + mHistory.setBatteryState(status, level, health, plugType, temp, voltageMv, chargeUah); + if (chargeUah < mBatteryChargeUah) { // Only record discharges - final long chargeDiff = mHistoryCur.batteryChargeUah - chargeUah; + final long chargeDiff = (long) mBatteryChargeUah - chargeUah; mDischargeCounter.addCountLocked(chargeDiff); mDischargeScreenOffCounter.addCountLocked(chargeDiff); if (Display.isDozeState(mScreenState)) { @@ -14575,12 +13911,12 @@ public class BatteryStatsImpl extends BatteryStats { mDischargeDeepDozeCounter.addCountLocked(chargeDiff); } } - mHistoryCur.batteryChargeUah = chargeUah; + mBatteryChargeUah = chargeUah; setOnBatteryLocked(elapsedRealtimeMs, uptimeMs, onBattery, oldStatus, level, chargeUah); } else { boolean changed = false; - if (mHistoryCur.batteryLevel != level) { - mHistoryCur.batteryLevel = (byte)level; + if (mBatteryLevel != level) { + mBatteryLevel = level; changed = true; // TODO(adamlesinski): Schedule the creation of a HistoryStepDetails record @@ -14588,33 +13924,33 @@ public class BatteryStatsImpl extends BatteryStats { mExternalSync.scheduleSyncDueToBatteryLevelChange( mConstants.BATTERY_LEVEL_COLLECTION_DELAY_MS); } - if (mHistoryCur.batteryStatus != status) { - mHistoryCur.batteryStatus = (byte)status; + if (mBatteryStatus != status) { + mBatteryStatus = status; changed = true; } - if (mHistoryCur.batteryHealth != health) { - mHistoryCur.batteryHealth = (byte)health; + if (mBatteryHealth != health) { + mBatteryHealth = health; changed = true; } - if (mHistoryCur.batteryPlugType != plugType) { - mHistoryCur.batteryPlugType = (byte)plugType; + if (mBatteryPlugType != plugType) { + mBatteryPlugType = plugType; changed = true; } - if (temp >= (mHistoryCur.batteryTemperature+10) - || temp <= (mHistoryCur.batteryTemperature-10)) { - mHistoryCur.batteryTemperature = (short)temp; + if (temp >= (mBatteryTemperature + 10) + || temp <= (mBatteryTemperature - 10)) { + mBatteryTemperature = temp; changed = true; } - if (voltageMv > (mHistoryCur.batteryVoltage + 20) - || voltageMv < (mHistoryCur.batteryVoltage - 20)) { - mHistoryCur.batteryVoltage = (char) voltageMv; + if (voltageMv > (mBatteryVoltageMv + 20) + || voltageMv < (mBatteryVoltageMv - 20)) { + mBatteryVoltageMv = voltageMv; changed = true; } - if (chargeUah >= (mHistoryCur.batteryChargeUah + 10) - || chargeUah <= (mHistoryCur.batteryChargeUah - 10)) { - if (chargeUah < mHistoryCur.batteryChargeUah) { + if (chargeUah >= (mBatteryChargeUah + 10) + || chargeUah <= (mBatteryChargeUah - 10)) { + if (chargeUah < mBatteryChargeUah) { // Only record discharges - final long chargeDiff = mHistoryCur.batteryChargeUah - chargeUah; + final long chargeDiff = (long) mBatteryChargeUah - chargeUah; mDischargeCounter.addCountLocked(chargeDiff); mDischargeScreenOffCounter.addCountLocked(chargeDiff); if (Display.isDozeState(mScreenState)) { @@ -14626,9 +13962,10 @@ public class BatteryStatsImpl extends BatteryStats { mDischargeDeepDozeCounter.addCountLocked(chargeDiff); } } - mHistoryCur.batteryChargeUah = chargeUah; + mBatteryChargeUah = chargeUah; changed = true; } + long modeBits = (((long)mInitStepMode) << STEP_LEVEL_INITIAL_MODE_SHIFT) | (((long)mModStepMode) << STEP_LEVEL_MODIFIED_MODE_SHIFT) | (((long)(level&0xff)) << STEP_LEVEL_LEVEL_SHIFT); @@ -14686,7 +14023,10 @@ public class BatteryStatsImpl extends BatteryStats { mLastChargeStepLevel = level; } if (changed) { - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + mHistory.setBatteryState(mBatteryStatus, mBatteryLevel, mBatteryHealth, + mBatteryPlugType, mBatteryTemperature, mBatteryVoltageMv, + mBatteryChargeUah); + mHistory.writeHistoryItem(elapsedRealtimeMs, uptimeMs); } } if (!onBattery && @@ -14695,7 +14035,7 @@ public class BatteryStatsImpl extends BatteryStats { // We don't record history while we are plugged in and fully charged // (or when battery is not present). The next time we are // unplugged, history will be cleared. - mRecordingHistory = DEBUG; + mHistory.setHistoryRecordingEnabled(DEBUG); } mLastLearnedBatteryCapacityUah = chargeFullUah; @@ -14714,17 +14054,18 @@ public class BatteryStatsImpl extends BatteryStats { } // Inform StatsLog of setBatteryState changes. - // If this is the first reporting, pass in recentPast == null. - private void reportChangesToStatsLog(HistoryItem recentPast, - final int status, final int plugType, final int level) { + private void reportChangesToStatsLog(final int status, final int plugType, final int level) { + if (!mHaveBatteryLevel) { + return; + } - if (recentPast == null || recentPast.batteryStatus != status) { + if (mBatteryStatus != status) { FrameworkStatsLog.write(FrameworkStatsLog.CHARGING_STATE_CHANGED, status); } - if (recentPast == null || recentPast.batteryPlugType != plugType) { + if (mBatteryPlugType != plugType) { FrameworkStatsLog.write(FrameworkStatsLog.PLUGGED_STATE_CHANGED, plugType); } - if (recentPast == null || recentPast.batteryLevel != level) { + if (mBatteryLevel != level) { FrameworkStatsLog.write(FrameworkStatsLog.BATTERY_LEVEL_CHANGED, level); } } @@ -14794,7 +14135,7 @@ public class BatteryStatsImpl extends BatteryStats { if (msPerLevel <= 0) { return -1; } - return (msPerLevel * mCurrentBatteryLevel) * 1000; + return (msPerLevel * mBatteryLevel) * 1000; } @Override @@ -14824,7 +14165,7 @@ public class BatteryStatsImpl extends BatteryStats { if (msPerLevel <= 0) { return -1; } - return (msPerLevel * (100 - mCurrentBatteryLevel)) * 1000; + return (msPerLevel * (100 - mBatteryLevel)) * 1000; } /*@hide */ @@ -15255,7 +14596,8 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void shutdownLocked() { - recordShutdownLocked(mClock.currentTimeMillis(), mClock.elapsedRealtime()); + mHistory.recordShutdownEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(), + mClock.currentTimeMillis()); writeSyncLocked(); mShuttingDown = true; } @@ -15463,7 +14805,6 @@ public class BatteryStatsImpl extends BatteryStats { PROC_STATE_CHANGE_COLLECTION_DELAY_MS = mParser.getLong( KEY_PROC_STATE_CHANGE_COLLECTION_DELAY_MS, DEFAULT_PROC_STATE_CHANGE_COLLECTION_DELAY_MS); - MAX_HISTORY_FILES = mParser.getInt(KEY_MAX_HISTORY_FILES, ActivityManager.isLowRamDeviceStatic() ? DEFAULT_MAX_HISTORY_FILES_LOW_RAM_DEVICE @@ -15474,9 +14815,20 @@ public class BatteryStatsImpl extends BatteryStats { : DEFAULT_MAX_HISTORY_BUFFER_KB) * 1024; updateBatteryChargedDelayMsLocked(); + + onChange(); } } + /** + * Propagates changes in constant values. + */ + @VisibleForTesting + public void onChange() { + mHistory.setMaxHistoryFiles(MAX_HISTORY_FILES); + mHistory.setMaxHistoryBufferSize(MAX_HISTORY_BUFFER); + } + private void updateBatteryChargedDelayMsLocked() { // a negative value indicates that we should ignore this override final int delay = Settings.Global.getInt(mResolver, @@ -15697,27 +15049,11 @@ public class BatteryStatsImpl extends BatteryStats { } private void writeHistoryLocked() { - if (mBatteryStatsHistory.getActiveFile() == null) { - Slog.w(TAG, "writeHistoryLocked: no history file associated with this instance"); - return; - } - if (mShuttingDown) { return; } - Parcel p = Parcel.obtain(); - try { - final long start = SystemClock.uptimeMillis(); - writeHistoryBuffer(p, true); - if (DEBUG) { - Slog.d(TAG, "writeHistoryBuffer duration ms:" - + (SystemClock.uptimeMillis() - start) + " bytes:" + p.dataSize()); - } - writeParcelToFileLocked(p, mBatteryStatsHistory.getActiveFile()); - } finally { - p.recycle(); - } + mHistory.writeHistory(); } private final ReentrantLock mWriteLock = new ReentrantLock(); @@ -15756,13 +15092,6 @@ public class BatteryStatsImpl extends BatteryStats { return; } - final AtomicFile activeHistoryFile = mBatteryStatsHistory.getActiveFile(); - if (activeHistoryFile == null) { - Slog.w(TAG, - "readLocked: no history file associated with this instance"); - return; - } - mUidStats.clear(); Parcel stats = Parcel.obtain(); @@ -15775,7 +15104,7 @@ public class BatteryStatsImpl extends BatteryStats { readSummaryFromParcel(stats); if (DEBUG) { Slog.d(TAG, "readLocked stats file:" + mStatsFile.getBaseFile().getPath() - + " bytes:" + raw.length + " takes ms:" + (SystemClock.uptimeMillis() + + " bytes:" + raw.length + " took ms:" + (SystemClock.uptimeMillis() - start)); } } @@ -15787,126 +15116,19 @@ public class BatteryStatsImpl extends BatteryStats { stats.recycle(); } - Parcel history = Parcel.obtain(); - try { - final long start = SystemClock.uptimeMillis(); - if (activeHistoryFile.exists()) { - byte[] raw = activeHistoryFile.readFully(); - if (raw.length > 0) { - history.unmarshall(raw, 0, raw.length); - history.setDataPosition(0); - readHistoryBuffer(history); - } - if (DEBUG) { - Slog.d(TAG, "readLocked history file::" - + activeHistoryFile.getBaseFile().getPath() - + " bytes:" + raw.length + " takes ms:" + (SystemClock.uptimeMillis() - - start)); - } - } - } catch (Exception e) { - Slog.e(TAG, "Error reading battery history", e); - clearHistoryLocked(); - mBatteryStatsHistory.resetAllFiles(); - } finally { - history.recycle(); + if (!mHistory.readSummary()) { + resetAllStatsLocked(SystemClock.uptimeMillis(), SystemClock.elapsedRealtime(), + RESET_REASON_CORRUPT_FILE); } mEndPlatformVersion = Build.ID; - if (mHistoryBuffer.dataPosition() > 0 - || mBatteryStatsHistory.getFilesNumbers().size() > 1) { - mRecordingHistory = true; - final long elapsedRealtimeMs = mClock.elapsedRealtime(); - final long uptimeMs = mClock.uptimeMillis(); - addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_START, mHistoryCur); - startRecordingHistory(elapsedRealtimeMs, uptimeMs, false); - } + mHistory.continueRecordingHistory(); recordDailyStatsIfNeededLocked(false, mClock.currentTimeMillis()); } @GuardedBy("this") - void readHistoryBuffer(Parcel in) throws ParcelFormatException { - final int version = in.readInt(); - if (version != BatteryStatsHistory.VERSION) { - Slog.w("BatteryStats", "readHistoryBuffer: version got " + version - + ", expected " + BatteryStatsHistory.VERSION + "; erasing old stats"); - return; - } - - final long historyBaseTime = in.readLong(); - - mHistoryBuffer.setDataSize(0); - mHistoryBuffer.setDataPosition(0); - - int bufSize = in.readInt(); - int curPos = in.dataPosition(); - if (bufSize >= (mConstants.MAX_HISTORY_BUFFER*100)) { - throw new ParcelFormatException("File corrupt: history data buffer too large " + - bufSize); - } else if ((bufSize&~3) != bufSize) { - throw new ParcelFormatException("File corrupt: history data buffer not aligned " + - bufSize); - } else { - if (DEBUG_HISTORY) Slog.i(TAG, "***************** READING NEW HISTORY: " + bufSize - + " bytes at " + curPos); - mHistoryBuffer.appendFrom(in, curPos, bufSize); - in.setDataPosition(curPos + bufSize); - } - - if (DEBUG_HISTORY) { - StringBuilder sb = new StringBuilder(128); - sb.append("****************** OLD mHistoryBaseTimeMs: "); - TimeUtils.formatDuration(mHistoryBaseTimeMs, sb); - Slog.i(TAG, sb.toString()); - } - mHistoryBaseTimeMs = historyBaseTime; - if (DEBUG_HISTORY) { - StringBuilder sb = new StringBuilder(128); - sb.append("****************** NEW mHistoryBaseTimeMs: "); - TimeUtils.formatDuration(mHistoryBaseTimeMs, sb); - Slog.i(TAG, sb.toString()); - } - - // We are just arbitrarily going to insert 1 minute from the sample of - // the last run until samples in this run. - if (mHistoryBaseTimeMs > 0) { - long oldnow = mClock.elapsedRealtime(); - mHistoryBaseTimeMs = mHistoryBaseTimeMs - oldnow + 1; - if (DEBUG_HISTORY) { - StringBuilder sb = new StringBuilder(128); - sb.append("****************** ADJUSTED mHistoryBaseTimeMs: "); - TimeUtils.formatDuration(mHistoryBaseTimeMs, sb); - Slog.i(TAG, sb.toString()); - } - } - } - - void writeHistoryBuffer(Parcel out, boolean inclData) { - if (DEBUG_HISTORY) { - StringBuilder sb = new StringBuilder(128); - sb.append("****************** WRITING mHistoryBaseTimeMs: "); - TimeUtils.formatDuration(mHistoryBaseTimeMs, sb); - sb.append(" mLastHistoryElapsedRealtimeMs: "); - TimeUtils.formatDuration(mLastHistoryElapsedRealtimeMs, sb); - Slog.i(TAG, sb.toString()); - } - out.writeInt(BatteryStatsHistory.VERSION); - out.writeLong(mHistoryBaseTimeMs + mLastHistoryElapsedRealtimeMs); - if (!inclData) { - out.writeInt(0); - out.writeInt(0); - return; - } - - out.writeInt(mHistoryBuffer.dataSize()); - if (DEBUG_HISTORY) Slog.i(TAG, "***************** WRITING HISTORY: " - + mHistoryBuffer.dataSize() + " bytes at " + out.dataPosition()); - out.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize()); - } - - @GuardedBy("this") public void readSummaryFromParcel(Parcel in) throws ParcelFormatException { final int version = in.readInt(); @@ -15916,31 +15138,7 @@ public class BatteryStatsImpl extends BatteryStats { return; } - boolean inclHistory = in.readBoolean(); - if (inclHistory) { - readHistoryBuffer(in); - mBatteryStatsHistory.readFromParcel(in); - } - - mHistoryTagPool.clear(); - mNextHistoryTagIdx = 0; - mNumHistoryTagChars = 0; - - int numTags = in.readInt(); - for (int i=0; i<numTags; i++) { - int idx = in.readInt(); - String str = in.readString(); - int uid = in.readInt(); - HistoryTag tag = new HistoryTag(); - tag.string = str; - tag.uid = uid; - tag.poolIdx = idx; - mHistoryTagPool.put(tag, idx); - if (idx >= mNextHistoryTagIdx) { - mNextHistoryTagIdx = idx+1; - } - mNumHistoryTagChars += tag.string.length() + 1; - } + mHistory.readSummaryFromParcel(in); mStartCount = in.readInt(); mUptimeUs = in.readLong(); @@ -15953,7 +15151,7 @@ public class BatteryStatsImpl extends BatteryStats { mDischargeUnplugLevel = in.readInt(); mDischargePlugLevel = in.readInt(); mDischargeCurrentLevel = in.readInt(); - mCurrentBatteryLevel = in.readInt(); + mBatteryLevel = in.readInt(); mEstimatedBatteryCapacityMah = in.readInt(); mLastLearnedBatteryCapacityUah = in.readInt(); mMinLearnedBatteryCapacityUah = in.readInt(); @@ -16456,19 +15654,7 @@ public class BatteryStatsImpl extends BatteryStats { out.writeInt(VERSION); - out.writeBoolean(inclHistory); - if (inclHistory) { - writeHistoryBuffer(out, true); - mBatteryStatsHistory.writeToParcel(out); - } - - out.writeInt(mHistoryTagPool.size()); - for (HashMap.Entry<HistoryTag, Integer> ent : mHistoryTagPool.entrySet()) { - HistoryTag tag = ent.getKey(); - out.writeInt(ent.getValue()); - out.writeString(tag.string); - out.writeInt(tag.uid); - } + mHistory.writeSummaryToParcel(out, inclHistory); out.writeInt(mStartCount); out.writeLong(computeUptime(nowUptime, STATS_SINCE_CHARGED)); @@ -16481,7 +15667,7 @@ public class BatteryStatsImpl extends BatteryStats { out.writeInt(mDischargeUnplugLevel); out.writeInt(mDischargePlugLevel); out.writeInt(mDischargeCurrentLevel); - out.writeInt(mCurrentBatteryLevel); + out.writeInt(mBatteryLevel); out.writeInt(mEstimatedBatteryCapacityMah); out.writeInt(mLastLearnedBatteryCapacityUah); out.writeInt(mMinLearnedBatteryCapacityUah); diff --git a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java index 0cdd4d101459..c36d950b6cf6 100644 --- a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java +++ b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java @@ -22,7 +22,6 @@ import android.os.BatteryConsumer; import android.os.BatteryStats; import android.os.BatteryUsageStats; import android.os.BatteryUsageStatsQuery; -import android.os.Parcel; import android.os.Process; import android.os.SystemClock; import android.os.UidBatteryConsumer; @@ -32,10 +31,8 @@ import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.os.BatteryStatsHistory; import com.android.internal.os.PowerProfile; -import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -220,18 +217,7 @@ public class BatteryUsageStatsProvider { } BatteryStatsImpl batteryStatsImpl = (BatteryStatsImpl) mStats; - - // Make a copy of battery history to avoid concurrent modification. - Parcel historyBuffer = Parcel.obtain(); - historyBuffer.appendFrom(batteryStatsImpl.mHistoryBuffer, 0, - batteryStatsImpl.mHistoryBuffer.dataSize()); - - final File systemDir = - batteryStatsImpl.mBatteryStatsHistory.getHistoryDirectory().getParentFile(); - final BatteryStatsHistory batteryStatsHistory = - new BatteryStatsHistory(historyBuffer, systemDir, null); - - batteryUsageStatsBuilder.setBatteryHistory(batteryStatsHistory); + batteryUsageStatsBuilder.setBatteryHistory(batteryStatsImpl.copyHistory()); } BatteryUsageStats stats = batteryUsageStatsBuilder.build(); diff --git a/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java b/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java index 06253a08d937..8b30995404f0 100644 --- a/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java +++ b/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java @@ -220,18 +220,17 @@ public class PowerStatsDataStorage { public void write(byte[] data) { if (data != null && data.length > 0) { mLock.lock(); - - long currentTimeMillis = System.currentTimeMillis(); try { + long currentTimeMillis = System.currentTimeMillis(); DataElement dataElement = new DataElement(data); mFileRotator.rewriteActive(new DataRewriter(dataElement.toByteArray()), currentTimeMillis); mFileRotator.maybeRotate(currentTimeMillis); } catch (IOException e) { Slog.e(TAG, "Failed to write to on-device storage: " + e); + } finally { + mLock.unlock(); } - - mLock.unlock(); } } @@ -240,21 +239,31 @@ public class PowerStatsDataStorage { * DataElement retrieved from on-device storage, callback is called. */ public void read(DataElementReadCallback callback) throws IOException { - mFileRotator.readMatching(new DataReader(callback), Long.MIN_VALUE, Long.MAX_VALUE); + mLock.lock(); + try { + mFileRotator.readMatching(new DataReader(callback), Long.MIN_VALUE, Long.MAX_VALUE); + } finally { + mLock.unlock(); + } } /** * Deletes all stored log data. */ public void deleteLogs() { - File[] files = mDataStorageDir.listFiles(); - for (int i = 0; i < files.length; i++) { - int versionDot = mDataStorageFilename.lastIndexOf('.'); - String beforeVersionDot = mDataStorageFilename.substring(0, versionDot); - // Check that the stems before the version match. - if (files[i].getName().startsWith(beforeVersionDot)) { - files[i].delete(); + mLock.lock(); + try { + File[] files = mDataStorageDir.listFiles(); + for (int i = 0; i < files.length; i++) { + int versionDot = mDataStorageFilename.lastIndexOf('.'); + String beforeVersionDot = mDataStorageFilename.substring(0, versionDot); + // Check that the stems before the version match. + if (files[i].getName().startsWith(beforeVersionDot)) { + files[i].delete(); + } } + } finally { + mLock.unlock(); } } } diff --git a/services/core/java/com/android/server/powerstats/PowerStatsLogger.java b/services/core/java/com/android/server/powerstats/PowerStatsLogger.java index ca675973b2fd..39ead13b03fe 100644 --- a/services/core/java/com/android/server/powerstats/PowerStatsLogger.java +++ b/services/core/java/com/android/server/powerstats/PowerStatsLogger.java @@ -159,12 +159,12 @@ public final class PowerStatsLogger extends Handler { EnergyMeasurementUtils.packProtoMessage(energyMeasurement, pos); if (DEBUG) EnergyMeasurementUtils.print(energyMeasurement); } catch (IOException e) { - Slog.e(TAG, "Failed to write energy meter data to incident report."); + Slog.e(TAG, "Failed to write energy meter data to incident report.", e); } } }); } catch (IOException e) { - Slog.e(TAG, "Failed to write energy meter info to incident report."); + Slog.e(TAG, "Failed to write energy meter info to incident report.", e); } pos.flush(); @@ -200,12 +200,12 @@ public final class PowerStatsLogger extends Handler { EnergyConsumerResultUtils.packProtoMessage(energyConsumerResult, pos, true); if (DEBUG) EnergyConsumerResultUtils.print(energyConsumerResult); } catch (IOException e) { - Slog.e(TAG, "Failed to write energy model data to incident report."); + Slog.e(TAG, "Failed to write energy model data to incident report.", e); } } }); } catch (IOException e) { - Slog.e(TAG, "Failed to write energy model info to incident report."); + Slog.e(TAG, "Failed to write energy model info to incident report.", e); } pos.flush(); @@ -241,12 +241,12 @@ public final class PowerStatsLogger extends Handler { StateResidencyResultUtils.packProtoMessage(stateResidencyResult, pos); if (DEBUG) StateResidencyResultUtils.print(stateResidencyResult); } catch (IOException e) { - Slog.e(TAG, "Failed to write residency data to incident report."); + Slog.e(TAG, "Failed to write residency data to incident report.", e); } } }); } catch (IOException e) { - Slog.e(TAG, "Failed to write residency data to incident report."); + Slog.e(TAG, "Failed to write residency data to incident report.", e); } pos.flush(); @@ -267,7 +267,7 @@ public final class PowerStatsLogger extends Handler { final FileInputStream fis = new FileInputStream(cachedFile.getPath()); fis.read(dataCached); } catch (IOException e) { - Slog.e(TAG, "Failed to read cached data from file"); + Slog.e(TAG, "Failed to read cached data from file", e); } // If the cached and current data are different, delete the data store. @@ -291,7 +291,7 @@ public final class PowerStatsLogger extends Handler { fos.write(data); atomicCachedFile.finishWrite(fos); } catch (IOException e) { - Slog.e(TAG, "Failed to write current data to cached file"); + Slog.e(TAG, "Failed to write current data to cached file", e); } } diff --git a/services/core/java/com/android/server/textservices/TextServicesManagerService.java b/services/core/java/com/android/server/textservices/TextServicesManagerService.java index cd2b8943ce11..8431f1cc0b4c 100644 --- a/services/core/java/com/android/server/textservices/TextServicesManagerService.java +++ b/services/core/java/com/android/server/textservices/TextServicesManagerService.java @@ -28,6 +28,7 @@ import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; @@ -583,10 +584,17 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { return; } final SpellCheckerInfo sci = spellCheckerMap.get(sciId); + final int uid = Binder.getCallingUid(); + if (!canCallerAccessSpellChecker(sci, uid, userId)) { + if (DBG) { + Slog.d(TAG, "Spell checker " + sci.getId() + + " is not visible to the caller " + uid); + } + return; + } HashMap<String, SpellCheckerBindGroup> spellCheckerBindGroups = tsd.mSpellCheckerBindGroups; SpellCheckerBindGroup bindGroup = spellCheckerBindGroups.get(sciId); - final int uid = Binder.getCallingUid(); if (bindGroup == null) { final long ident = Binder.clearCallingIdentity(); try { @@ -649,20 +657,28 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { public SpellCheckerInfo[] getEnabledSpellCheckers(@UserIdInt int userId) { verifyUser(userId); + final ArrayList<SpellCheckerInfo> spellCheckerList; synchronized (mLock) { final TextServicesData tsd = getDataFromCallingUserIdLocked(userId); if (tsd == null) return null; - ArrayList<SpellCheckerInfo> spellCheckerList = tsd.mSpellCheckerList; + spellCheckerList = new ArrayList<>(tsd.mSpellCheckerList); + } + int size = spellCheckerList.size(); + final int callingUid = Binder.getCallingUid(); + for (int i = size - 1; i >= 0; i--) { + if (canCallerAccessSpellChecker(spellCheckerList.get(i), callingUid, userId)) { + continue; + } if (DBG) { - Slog.d(TAG, "getEnabledSpellCheckers: " + spellCheckerList.size()); - for (int i = 0; i < spellCheckerList.size(); ++i) { - Slog.d(TAG, - "EnabledSpellCheckers: " + spellCheckerList.get(i).getPackageName()); - } + Slog.d(TAG, "Spell checker " + spellCheckerList.get(i).getPackageName() + + " is not visible to the caller " + callingUid); } - return spellCheckerList.toArray(new SpellCheckerInfo[spellCheckerList.size()]); + spellCheckerList.remove(i); } + + return spellCheckerList.isEmpty() ? null + : spellCheckerList.toArray(new SpellCheckerInfo[spellCheckerList.size()]); } @Override @@ -701,6 +717,26 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { } } + /** + * Filter the access to spell checkers by rules of the package visibility. Return {@code true} + * if the given spell checker is the currently selected one or visible to the caller. + * + * @param sci The spell checker to check. + * @param callingUid The caller that is going to access the spell checker. + * @param userId The user id where the spell checker resides. + * @return {@code true} if caller is able to access the spell checker. + */ + private boolean canCallerAccessSpellChecker(@NonNull SpellCheckerInfo sci, int callingUid, + @UserIdInt int userId) { + final SpellCheckerInfo currentSci = getCurrentSpellCheckerForUser(userId); + if (currentSci != null && currentSci.getId().equals(sci.getId())) { + return true; + } + final PackageManagerInternal pmInternal = + LocalServices.getService(PackageManagerInternal.class); + return !pmInternal.filterAppAccess(sci.getPackageName(), callingUid, userId); + } + private void setCurrentSpellCheckerLocked(@Nullable SpellCheckerInfo sci, TextServicesData tsd) { final String sciId = (sci != null) ? sci.getId() : ""; if (DBG) { diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java index 6162d716b85e..edd1ef36deda 100644 --- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java +++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java @@ -39,6 +39,7 @@ import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.os.SystemClock; +import android.os.SystemProperties; import android.util.IndentingPrintWriter; import android.util.Log; import android.util.Slog; @@ -141,6 +142,15 @@ public class TunerResourceManagerService extends SystemService implements IBinde (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE); mPriorityCongfig.parse(); + // Call SystemProperties.set() in mock app will throw exception because of permission. + if (!isForTesting) { + final boolean lazyHal = SystemProperties.getBoolean("ro.tuner.lazyhal", false); + if (!lazyHal) { + // The HAL is not a lazy HAL, enable the tuner server. + SystemProperties.set("tuner.server.enable", "true"); + } + } + if (mMediaResourceManager == null) { IBinder mediaResourceManagerBinder = getBinderService("media.resource_manager"); if (mediaResourceManagerBinder == null) { diff --git a/services/core/java/com/android/server/vibrator/AbstractVibratorStep.java b/services/core/java/com/android/server/vibrator/AbstractVibratorStep.java index eebd046b2601..be9053055fe3 100644 --- a/services/core/java/com/android/server/vibrator/AbstractVibratorStep.java +++ b/services/core/java/com/android/server/vibrator/AbstractVibratorStep.java @@ -31,9 +31,9 @@ abstract class AbstractVibratorStep extends Step { public final VibratorController controller; public final VibrationEffect.Composed effect; public final int segmentIndex; - public final long previousStepVibratorOffTimeout; long mVibratorOnResult; + long mPendingVibratorOffDeadline; boolean mVibratorCompleteCallbackReceived; /** @@ -43,19 +43,19 @@ abstract class AbstractVibratorStep extends Step { * @param controller The vibrator that is playing the effect. * @param effect The effect being played in this step. * @param index The index of the next segment to be played by this step - * @param previousStepVibratorOffTimeout The time the vibrator is expected to complete any + * @param pendingVibratorOffDeadline The time the vibrator is expected to complete any * previous vibration and turn off. This is used to allow this step to * be triggered when the completion callback is received, and can * be used to play effects back-to-back. */ AbstractVibratorStep(VibrationStepConductor conductor, long startTime, VibratorController controller, VibrationEffect.Composed effect, int index, - long previousStepVibratorOffTimeout) { + long pendingVibratorOffDeadline) { super(conductor, startTime); this.controller = controller; this.effect = effect; this.segmentIndex = index; - this.previousStepVibratorOffTimeout = previousStepVibratorOffTimeout; + mPendingVibratorOffDeadline = pendingVibratorOffDeadline; } public int getVibratorId() { @@ -69,27 +69,57 @@ abstract class AbstractVibratorStep extends Step { @Override public boolean acceptVibratorCompleteCallback(int vibratorId) { - boolean isSameVibrator = controller.getVibratorInfo().getId() == vibratorId; - mVibratorCompleteCallbackReceived |= isSameVibrator; + if (getVibratorId() != vibratorId) { + return false; + } + // Only activate this step if a timeout was set to wait for the vibration to complete, // otherwise we are waiting for the correct time to play the next step. - return isSameVibrator && (previousStepVibratorOffTimeout > SystemClock.uptimeMillis()); + boolean shouldAcceptCallback = mPendingVibratorOffDeadline > SystemClock.uptimeMillis(); + if (VibrationThread.DEBUG) { + Slog.d(VibrationThread.TAG, + "Received completion callback from " + vibratorId + + ", accepted = " + shouldAcceptCallback); + } + + // The callback indicates this vibrator has stopped, reset the timeout. + mPendingVibratorOffDeadline = 0; + mVibratorCompleteCallbackReceived = true; + return shouldAcceptCallback; } @Override public List<Step> cancel() { return Arrays.asList(new CompleteEffectVibratorStep(conductor, SystemClock.uptimeMillis(), - /* cancelled= */ true, controller, previousStepVibratorOffTimeout)); + /* cancelled= */ true, controller, mPendingVibratorOffDeadline)); } @Override public void cancelImmediately() { - if (previousStepVibratorOffTimeout > SystemClock.uptimeMillis()) { + if (mPendingVibratorOffDeadline > SystemClock.uptimeMillis()) { // Vibrator might be running from previous steps, so turn it off while canceling. stopVibrating(); } } + protected long handleVibratorOnResult(long vibratorOnResult) { + mVibratorOnResult = vibratorOnResult; + if (VibrationThread.DEBUG) { + Slog.d(VibrationThread.TAG, + "Turned on vibrator " + getVibratorId() + ", result = " + mVibratorOnResult); + } + if (mVibratorOnResult > 0) { + // Vibrator was turned on by this step, with vibratorOnResult as the duration. + // Set an extra timeout to wait for the vibrator completion callback. + mPendingVibratorOffDeadline = SystemClock.uptimeMillis() + mVibratorOnResult + + VibrationStepConductor.CALLBACKS_EXTRA_TIMEOUT; + } else { + // Vibrator does not support the request or failed to turn on, reset callback deadline. + mPendingVibratorOffDeadline = 0; + } + return mVibratorOnResult; + } + protected void stopVibrating() { if (VibrationThread.DEBUG) { Slog.d(VibrationThread.TAG, @@ -97,6 +127,7 @@ abstract class AbstractVibratorStep extends Step { } controller.off(); getVibration().stats().reportVibratorOff(); + mPendingVibratorOffDeadline = 0; } protected void changeAmplitude(float amplitude) { @@ -109,40 +140,29 @@ abstract class AbstractVibratorStep extends Step { } /** - * Return the {@link VibrationStepConductor#nextVibrateStep} with same timings, only jumping - * the segments. - */ - protected List<Step> skipToNextSteps(int segmentsSkipped) { - return nextSteps(startTime, previousStepVibratorOffTimeout, segmentsSkipped); - } - - /** - * Return the {@link VibrationStepConductor#nextVibrateStep} with same start and off timings - * calculated from {@link #getVibratorOnDuration()}, jumping all played segments. - * - * <p>This method has same behavior as {@link #skipToNextSteps(int)} when the vibrator - * result is non-positive, meaning the vibrator has either ignored or failed to turn on. + * Return the {@link VibrationStepConductor#nextVibrateStep} with start and off timings + * calculated from {@link #getVibratorOnDuration()} based on the current + * {@link SystemClock#uptimeMillis()} and jumping all played segments from the effect. */ protected List<Step> nextSteps(int segmentsPlayed) { - if (mVibratorOnResult <= 0) { - // Vibration was not started, so just skip the played segments and keep timings. - return skipToNextSteps(segmentsPlayed); + // Schedule next steps to run right away. + long nextStartTime = SystemClock.uptimeMillis(); + if (mVibratorOnResult > 0) { + // Vibrator was turned on by this step, with mVibratorOnResult as the duration. + // Schedule next steps for right after the vibration finishes. + nextStartTime += mVibratorOnResult; } - long nextStartTime = SystemClock.uptimeMillis() + mVibratorOnResult; - long nextVibratorOffTimeout = - nextStartTime + VibrationStepConductor.CALLBACKS_EXTRA_TIMEOUT; - return nextSteps(nextStartTime, nextVibratorOffTimeout, segmentsPlayed); + return nextSteps(nextStartTime, segmentsPlayed); } /** - * Return the {@link VibrationStepConductor#nextVibrateStep} with given start and off timings, - * which might be calculated independently, jumping all played segments. + * Return the {@link VibrationStepConductor#nextVibrateStep} with given start time, + * which might be calculated independently, and jumping all played segments from the effect. * - * <p>This should be used when the vibrator on/off state is not responsible for the steps - * execution timings, e.g. while playing the vibrator amplitudes. + * <p>This should be used when the vibrator on/off state is not responsible for the step + * execution timing, e.g. while playing the vibrator amplitudes. */ - protected List<Step> nextSteps(long nextStartTime, long vibratorOffTimeout, - int segmentsPlayed) { + protected List<Step> nextSteps(long nextStartTime, int segmentsPlayed) { int nextSegmentIndex = segmentIndex + segmentsPlayed; int effectSize = effect.getSegments().size(); int repeatIndex = effect.getRepeatIndex(); @@ -154,7 +174,7 @@ abstract class AbstractVibratorStep extends Step { nextSegmentIndex = repeatIndex + ((nextSegmentIndex - effectSize) % loopSize); } Step nextStep = conductor.nextVibrateStep(nextStartTime, controller, effect, - nextSegmentIndex, vibratorOffTimeout); + nextSegmentIndex, mPendingVibratorOffDeadline); return nextStep == null ? VibrationStepConductor.EMPTY_STEP_LIST : Arrays.asList(nextStep); } } diff --git a/services/core/java/com/android/server/vibrator/CompleteEffectVibratorStep.java b/services/core/java/com/android/server/vibrator/CompleteEffectVibratorStep.java index 8585e3473ef3..fb5140d862b7 100644 --- a/services/core/java/com/android/server/vibrator/CompleteEffectVibratorStep.java +++ b/services/core/java/com/android/server/vibrator/CompleteEffectVibratorStep.java @@ -34,9 +34,9 @@ final class CompleteEffectVibratorStep extends AbstractVibratorStep { private final boolean mCancelled; CompleteEffectVibratorStep(VibrationStepConductor conductor, long startTime, boolean cancelled, - VibratorController controller, long previousStepVibratorOffTimeout) { + VibratorController controller, long pendingVibratorOffDeadline) { super(conductor, startTime, controller, /* effect= */ null, /* index= */ -1, - previousStepVibratorOffTimeout); + pendingVibratorOffDeadline); mCancelled = cancelled; } @@ -73,10 +73,11 @@ final class CompleteEffectVibratorStep extends AbstractVibratorStep { return VibrationStepConductor.EMPTY_STEP_LIST; } + long now = SystemClock.uptimeMillis(); float currentAmplitude = controller.getCurrentAmplitude(); long remainingOnDuration = - previousStepVibratorOffTimeout - VibrationStepConductor.CALLBACKS_EXTRA_TIMEOUT - - SystemClock.uptimeMillis(); + mPendingVibratorOffDeadline - now + - VibrationStepConductor.CALLBACKS_EXTRA_TIMEOUT; long rampDownDuration = Math.min(remainingOnDuration, conductor.vibrationSettings.getRampDownDuration()); @@ -89,8 +90,10 @@ final class CompleteEffectVibratorStep extends AbstractVibratorStep { stopVibrating(); return VibrationStepConductor.EMPTY_STEP_LIST; } else { + // Vibration is completing normally, turn off after the deadline in case we + // don't receive the callback in time (callback also triggers it right away). return Arrays.asList(new TurnOffVibratorStep( - conductor, previousStepVibratorOffTimeout, controller)); + conductor, mPendingVibratorOffDeadline, controller)); } } @@ -100,13 +103,18 @@ final class CompleteEffectVibratorStep extends AbstractVibratorStep { + " from amplitude " + currentAmplitude + " for " + rampDownDuration + "ms"); } + + // If we are cancelling this vibration then make sure the vibrator will be turned off + // immediately after the ramp off duration. Otherwise, this is a planned ramp off for + // the remaining ON duration, then just propagate the mPendingVibratorOffDeadline so the + // turn off step will wait for the vibration completion callback and end gracefully. + long rampOffVibratorOffDeadline = + mCancelled ? (now + rampDownDuration) : mPendingVibratorOffDeadline; float amplitudeDelta = currentAmplitude / (rampDownDuration / stepDownDuration); float amplitudeTarget = currentAmplitude - amplitudeDelta; - long newVibratorOffTimeout = - mCancelled ? rampDownDuration : previousStepVibratorOffTimeout; return Arrays.asList( new RampOffVibratorStep(conductor, startTime, amplitudeTarget, amplitudeDelta, - controller, newVibratorOffTimeout)); + controller, rampOffVibratorOffDeadline)); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); } diff --git a/services/core/java/com/android/server/vibrator/ComposePrimitivesVibratorStep.java b/services/core/java/com/android/server/vibrator/ComposePrimitivesVibratorStep.java index f8b99265246a..545ec5bcff03 100644 --- a/services/core/java/com/android/server/vibrator/ComposePrimitivesVibratorStep.java +++ b/services/core/java/com/android/server/vibrator/ComposePrimitivesVibratorStep.java @@ -40,11 +40,11 @@ final class ComposePrimitivesVibratorStep extends AbstractVibratorStep { ComposePrimitivesVibratorStep(VibrationStepConductor conductor, long startTime, VibratorController controller, VibrationEffect.Composed effect, int index, - long previousStepVibratorOffTimeout) { + long pendingVibratorOffDeadline) { // This step should wait for the last vibration to finish (with the timeout) and for the // intended step start time (to respect the effect delays). - super(conductor, Math.max(startTime, previousStepVibratorOffTimeout), controller, effect, - index, previousStepVibratorOffTimeout); + super(conductor, Math.max(startTime, pendingVibratorOffDeadline), controller, effect, + index, pendingVibratorOffDeadline); } @Override @@ -60,18 +60,22 @@ final class ComposePrimitivesVibratorStep extends AbstractVibratorStep { if (primitives.isEmpty()) { Slog.w(VibrationThread.TAG, "Ignoring wrong segment for a ComposePrimitivesStep: " + effect.getSegments().get(segmentIndex)); - return skipToNextSteps(/* segmentsSkipped= */ 1); + // Skip this step and play the next one right away. + return nextSteps(/* segmentsPlayed= */ 1); } if (VibrationThread.DEBUG) { Slog.d(VibrationThread.TAG, "Compose " + primitives + " primitives on vibrator " - + controller.getVibratorInfo().getId()); + + getVibratorId()); } + PrimitiveSegment[] primitivesArray = primitives.toArray(new PrimitiveSegment[primitives.size()]); - mVibratorOnResult = controller.on(primitivesArray, getVibration().id); - getVibration().stats().reportComposePrimitives(mVibratorOnResult, primitivesArray); + long vibratorOnResult = controller.on(primitivesArray, getVibration().id); + handleVibratorOnResult(vibratorOnResult); + getVibration().stats().reportComposePrimitives(vibratorOnResult, primitivesArray); + // The next start and off times will be calculated from mVibratorOnResult. return nextSteps(/* segmentsPlayed= */ primitives.size()); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); diff --git a/services/core/java/com/android/server/vibrator/ComposePwleVibratorStep.java b/services/core/java/com/android/server/vibrator/ComposePwleVibratorStep.java index 81f52c912f28..8bfa2c3cd082 100644 --- a/services/core/java/com/android/server/vibrator/ComposePwleVibratorStep.java +++ b/services/core/java/com/android/server/vibrator/ComposePwleVibratorStep.java @@ -41,11 +41,11 @@ final class ComposePwleVibratorStep extends AbstractVibratorStep { ComposePwleVibratorStep(VibrationStepConductor conductor, long startTime, VibratorController controller, VibrationEffect.Composed effect, int index, - long previousStepVibratorOffTimeout) { + long pendingVibratorOffDeadline) { // This step should wait for the last vibration to finish (with the timeout) and for the // intended step start time (to respect the effect delays). - super(conductor, Math.max(startTime, previousStepVibratorOffTimeout), controller, effect, - index, previousStepVibratorOffTimeout); + super(conductor, Math.max(startTime, pendingVibratorOffDeadline), controller, effect, + index, pendingVibratorOffDeadline); } @Override @@ -61,7 +61,8 @@ final class ComposePwleVibratorStep extends AbstractVibratorStep { if (pwles.isEmpty()) { Slog.w(VibrationThread.TAG, "Ignoring wrong segment for a ComposePwleStep: " + effect.getSegments().get(segmentIndex)); - return skipToNextSteps(/* segmentsSkipped= */ 1); + // Skip this step and play the next one right away. + return nextSteps(/* segmentsPlayed= */ 1); } if (VibrationThread.DEBUG) { @@ -69,9 +70,11 @@ final class ComposePwleVibratorStep extends AbstractVibratorStep { + controller.getVibratorInfo().getId()); } RampSegment[] pwlesArray = pwles.toArray(new RampSegment[pwles.size()]); - mVibratorOnResult = controller.on(pwlesArray, getVibration().id); - getVibration().stats().reportComposePwle(mVibratorOnResult, pwlesArray); + long vibratorOnResult = controller.on(pwlesArray, getVibration().id); + handleVibratorOnResult(vibratorOnResult); + getVibration().stats().reportComposePwle(vibratorOnResult, pwlesArray); + // The next start and off times will be calculated from mVibratorOnResult. return nextSteps(/* segmentsPlayed= */ pwles.size()); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); diff --git a/services/core/java/com/android/server/vibrator/PerformPrebakedVibratorStep.java b/services/core/java/com/android/server/vibrator/PerformPrebakedVibratorStep.java index 41902147838d..d91bafa7c8c2 100644 --- a/services/core/java/com/android/server/vibrator/PerformPrebakedVibratorStep.java +++ b/services/core/java/com/android/server/vibrator/PerformPrebakedVibratorStep.java @@ -35,11 +35,11 @@ final class PerformPrebakedVibratorStep extends AbstractVibratorStep { PerformPrebakedVibratorStep(VibrationStepConductor conductor, long startTime, VibratorController controller, VibrationEffect.Composed effect, int index, - long previousStepVibratorOffTimeout) { + long pendingVibratorOffDeadline) { // This step should wait for the last vibration to finish (with the timeout) and for the // intended step start time (to respect the effect delays). - super(conductor, Math.max(startTime, previousStepVibratorOffTimeout), controller, effect, - index, previousStepVibratorOffTimeout); + super(conductor, Math.max(startTime, pendingVibratorOffDeadline), controller, effect, + index, pendingVibratorOffDeadline); } @Override @@ -50,7 +50,8 @@ final class PerformPrebakedVibratorStep extends AbstractVibratorStep { if (!(segment instanceof PrebakedSegment)) { Slog.w(VibrationThread.TAG, "Ignoring wrong segment for a " + "PerformPrebakedVibratorStep: " + segment); - return skipToNextSteps(/* segmentsSkipped= */ 1); + // Skip this step and play the next one right away. + return nextSteps(/* segmentsPlayed= */ 1); } PrebakedSegment prebaked = (PrebakedSegment) segment; @@ -61,10 +62,11 @@ final class PerformPrebakedVibratorStep extends AbstractVibratorStep { } VibrationEffect fallback = getVibration().getFallback(prebaked.getEffectId()); - mVibratorOnResult = controller.on(prebaked, getVibration().id); - getVibration().stats().reportPerformEffect(mVibratorOnResult, prebaked); + long vibratorOnResult = controller.on(prebaked, getVibration().id); + handleVibratorOnResult(vibratorOnResult); + getVibration().stats().reportPerformEffect(vibratorOnResult, prebaked); - if (mVibratorOnResult == 0 && prebaked.shouldFallback() + if (vibratorOnResult == 0 && prebaked.shouldFallback() && (fallback instanceof VibrationEffect.Composed)) { if (VibrationThread.DEBUG) { Slog.d(VibrationThread.TAG, "Playing fallback for effect " @@ -72,14 +74,15 @@ final class PerformPrebakedVibratorStep extends AbstractVibratorStep { } AbstractVibratorStep fallbackStep = conductor.nextVibrateStep(startTime, controller, replaceCurrentSegment((VibrationEffect.Composed) fallback), - segmentIndex, previousStepVibratorOffTimeout); + segmentIndex, mPendingVibratorOffDeadline); List<Step> fallbackResult = fallbackStep.play(); // Update the result with the fallback result so this step is seamlessly // replaced by the fallback to any outer application of this. - mVibratorOnResult = fallbackStep.getVibratorOnDuration(); + handleVibratorOnResult(fallbackStep.getVibratorOnDuration()); return fallbackResult; } + // The next start and off times will be calculated from mVibratorOnResult. return nextSteps(/* segmentsPlayed= */ 1); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); diff --git a/services/core/java/com/android/server/vibrator/RampOffVibratorStep.java b/services/core/java/com/android/server/vibrator/RampOffVibratorStep.java index 8cf5fb394d9d..84da9f2c58ec 100644 --- a/services/core/java/com/android/server/vibrator/RampOffVibratorStep.java +++ b/services/core/java/com/android/server/vibrator/RampOffVibratorStep.java @@ -30,9 +30,9 @@ final class RampOffVibratorStep extends AbstractVibratorStep { RampOffVibratorStep(VibrationStepConductor conductor, long startTime, float amplitudeTarget, float amplitudeDelta, VibratorController controller, - long previousStepVibratorOffTimeout) { + long pendingVibratorOffDeadline) { super(conductor, startTime, controller, /* effect= */ null, /* index= */ -1, - previousStepVibratorOffTimeout); + pendingVibratorOffDeadline); mAmplitudeTarget = amplitudeTarget; mAmplitudeDelta = amplitudeDelta; } @@ -68,15 +68,17 @@ final class RampOffVibratorStep extends AbstractVibratorStep { float newAmplitudeTarget = mAmplitudeTarget - mAmplitudeDelta; if (newAmplitudeTarget < VibrationStepConductor.RAMP_OFF_AMPLITUDE_MIN) { - // Vibrator amplitude cannot go further down, just turn it off. + // Vibrator amplitude cannot go further down, just turn it off with the configured + // deadline that has been adjusted for the scenario when this was triggered by a + // cancelled vibration. return Arrays.asList(new TurnOffVibratorStep( - conductor, previousStepVibratorOffTimeout, controller)); + conductor, mPendingVibratorOffDeadline, controller)); } return Arrays.asList(new RampOffVibratorStep( conductor, startTime + conductor.vibrationSettings.getRampStepDuration(), newAmplitudeTarget, mAmplitudeDelta, controller, - previousStepVibratorOffTimeout)); + mPendingVibratorOffDeadline)); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); } diff --git a/services/core/java/com/android/server/vibrator/SetAmplitudeVibratorStep.java b/services/core/java/com/android/server/vibrator/SetAmplitudeVibratorStep.java index 6fb9111793ea..1672470f1f1a 100644 --- a/services/core/java/com/android/server/vibrator/SetAmplitudeVibratorStep.java +++ b/services/core/java/com/android/server/vibrator/SetAmplitudeVibratorStep.java @@ -39,26 +39,34 @@ final class SetAmplitudeVibratorStep extends AbstractVibratorStep { */ private static final int REPEATING_EFFECT_ON_DURATION = 5000; // 5s - private long mNextOffTime; - SetAmplitudeVibratorStep(VibrationStepConductor conductor, long startTime, VibratorController controller, VibrationEffect.Composed effect, int index, - long previousStepVibratorOffTimeout) { + long pendingVibratorOffDeadline) { // This step has a fixed startTime coming from the timings of the waveform it's playing. - super(conductor, startTime, controller, effect, index, previousStepVibratorOffTimeout); - mNextOffTime = previousStepVibratorOffTimeout; + super(conductor, startTime, controller, effect, index, pendingVibratorOffDeadline); } @Override public boolean acceptVibratorCompleteCallback(int vibratorId) { - if (controller.getVibratorInfo().getId() == vibratorId) { - mVibratorCompleteCallbackReceived = true; - mNextOffTime = SystemClock.uptimeMillis(); + // Ensure the super method is called and will reset the off timeout and boolean flag. + // This is true if the vibrator was ON and this callback has the same vibratorId. + if (!super.acceptVibratorCompleteCallback(vibratorId)) { + return false; } + // Timings are tightly controlled here, so only trigger this step if the vibrator was // supposed to be ON but has completed prematurely, to turn it back on as soon as - // possible. - return mNextOffTime < startTime && controller.getCurrentAmplitude() > 0; + // possible. If the vibrator turned off during a zero-amplitude step, just wait for + // the correct start time of this step before playing it. + boolean shouldAcceptCallback = + (SystemClock.uptimeMillis() < startTime) && (controller.getCurrentAmplitude() > 0); + + if (VibrationThread.DEBUG) { + Slog.d(VibrationThread.TAG, + "Amplitude step received completion callback from " + vibratorId + + ", accepted = " + shouldAcceptCallback); + } + return shouldAcceptCallback; } @Override @@ -78,40 +86,38 @@ final class SetAmplitudeVibratorStep extends AbstractVibratorStep { if (mVibratorCompleteCallbackReceived && latency < 0) { // This step was run early because the vibrator turned off prematurely. // Turn it back on and return this same step to run at the exact right time. - mNextOffTime = turnVibratorBackOn(/* remainingDuration= */ -latency); + turnVibratorBackOn(/* remainingDuration= */ -latency); return Arrays.asList(new SetAmplitudeVibratorStep(conductor, startTime, controller, - effect, segmentIndex, mNextOffTime)); + effect, segmentIndex, mPendingVibratorOffDeadline)); } VibrationEffectSegment segment = effect.getSegments().get(segmentIndex); if (!(segment instanceof StepSegment)) { Slog.w(VibrationThread.TAG, "Ignoring wrong segment for a SetAmplitudeVibratorStep: " + segment); - return skipToNextSteps(/* segmentsSkipped= */ 1); + // Use original startTime to avoid propagating latencies to the waveform. + return nextSteps(startTime, /* segmentsPlayed= */ 1); } StepSegment stepSegment = (StepSegment) segment; if (stepSegment.getDuration() == 0) { - // Skip waveform entries with zero timing. - return skipToNextSteps(/* segmentsSkipped= */ 1); + // Use original startTime to avoid propagating latencies to the waveform. + return nextSteps(startTime, /* segmentsPlayed= */ 1); } float amplitude = stepSegment.getAmplitude(); if (amplitude == 0) { - if (previousStepVibratorOffTimeout > now) { + if (mPendingVibratorOffDeadline > now) { // Amplitude cannot be set to zero, so stop the vibrator. stopVibrating(); - mNextOffTime = now; } } else { - if (startTime >= mNextOffTime) { + if (startTime >= mPendingVibratorOffDeadline) { // Vibrator is OFF. Turn vibrator back on for the duration of another // cycle before setting the amplitude. long onDuration = getVibratorOnDuration(effect, segmentIndex); if (onDuration > 0) { - mVibratorOnResult = startVibrating(onDuration); - mNextOffTime = now + onDuration - + VibrationStepConductor.CALLBACKS_EXTRA_TIMEOUT; + startVibrating(onDuration); } } changeAmplitude(amplitude); @@ -119,27 +125,32 @@ final class SetAmplitudeVibratorStep extends AbstractVibratorStep { // Use original startTime to avoid propagating latencies to the waveform. long nextStartTime = startTime + segment.getDuration(); - return nextSteps(nextStartTime, mNextOffTime, /* segmentsPlayed= */ 1); + return nextSteps(nextStartTime, /* segmentsPlayed= */ 1); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); } } - private long turnVibratorBackOn(long remainingDuration) { + private void turnVibratorBackOn(long remainingDuration) { long onDuration = getVibratorOnDuration(effect, segmentIndex); if (onDuration <= 0) { // Vibrator is supposed to go back off when this step starts, so just leave it off. - return previousStepVibratorOffTimeout; + return; } onDuration += remainingDuration; + + if (VibrationThread.DEBUG) { + Slog.d(VibrationThread.TAG, + "Turning the vibrator back ON using the remaining duration of " + + remainingDuration + "ms, for a total of " + onDuration + "ms"); + } + float expectedAmplitude = controller.getCurrentAmplitude(); - mVibratorOnResult = startVibrating(onDuration); - if (mVibratorOnResult > 0) { + long vibratorOnResult = startVibrating(onDuration); + if (vibratorOnResult > 0) { // Set the amplitude back to the value it was supposed to be playing at. changeAmplitude(expectedAmplitude); } - return SystemClock.uptimeMillis() + onDuration - + VibrationStepConductor.CALLBACKS_EXTRA_TIMEOUT; } private long startVibrating(long duration) { @@ -149,6 +160,7 @@ final class SetAmplitudeVibratorStep extends AbstractVibratorStep { + duration + "ms"); } long vibratorOnResult = controller.on(duration, getVibration().id); + handleVibratorOnResult(vibratorOnResult); getVibration().stats().reportVibratorOn(vibratorOnResult); return vibratorOnResult; } diff --git a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java index 0799b955b6f1..0af171871792 100644 --- a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java +++ b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java @@ -112,8 +112,7 @@ final class VibrationStepConductor implements IBinder.DeathRecipient { @Nullable AbstractVibratorStep nextVibrateStep(long startTime, VibratorController controller, - VibrationEffect.Composed effect, int segmentIndex, - long previousStepVibratorOffTimeout) { + VibrationEffect.Composed effect, int segmentIndex, long pendingVibratorOffDeadline) { if (Build.IS_DEBUGGABLE) { expectIsVibrationThread(true); } @@ -123,24 +122,24 @@ final class VibrationStepConductor implements IBinder.DeathRecipient { if (segmentIndex < 0) { // No more segments to play, last step is to complete the vibration on this vibrator. return new CompleteEffectVibratorStep(this, startTime, /* cancelled= */ false, - controller, previousStepVibratorOffTimeout); + controller, pendingVibratorOffDeadline); } VibrationEffectSegment segment = effect.getSegments().get(segmentIndex); if (segment instanceof PrebakedSegment) { return new PerformPrebakedVibratorStep(this, startTime, controller, effect, - segmentIndex, previousStepVibratorOffTimeout); + segmentIndex, pendingVibratorOffDeadline); } if (segment instanceof PrimitiveSegment) { return new ComposePrimitivesVibratorStep(this, startTime, controller, effect, - segmentIndex, previousStepVibratorOffTimeout); + segmentIndex, pendingVibratorOffDeadline); } if (segment instanceof RampSegment) { return new ComposePwleVibratorStep(this, startTime, controller, effect, segmentIndex, - previousStepVibratorOffTimeout); + pendingVibratorOffDeadline); } return new SetAmplitudeVibratorStep(this, startTime, controller, effect, segmentIndex, - previousStepVibratorOffTimeout); + pendingVibratorOffDeadline); } /** Called when this conductor is going to be started running by the VibrationThread. */ diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java index 2f12a820eb81..d1cde602b391 100644 --- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java +++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java @@ -387,8 +387,8 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { * An internal-only version of vibrate that allows the caller access to the {@link Vibration}. * The Vibration is only returned if it is ongoing after this method returns. */ - @Nullable @VisibleForTesting + @Nullable Vibration vibrateInternal(int uid, String opPkg, @NonNull CombinedVibration effect, @Nullable VibrationAttributes attrs, String reason, IBinder token) { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate, reason = " + reason); @@ -1844,6 +1844,8 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { attrs, commonOptions.description, deathBinder); if (vib != null && !commonOptions.background) { try { + // Waits for the client vibration to finish, but the VibrationThread may still + // do cleanup after this. vib.waitForEnd(); } catch (InterruptedException e) { } diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index 55d6b2fe8226..c940a658015d 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -375,9 +375,6 @@ public class AppTransition implements Dump { final AnimationAdapter topOpeningAnim = wc != null ? wc.getAnimation() : null; int redoLayout = notifyAppTransitionStartingLocked( - AppTransition.isKeyguardGoingAwayTransitOld(transit), - AppTransition.isKeyguardOccludeTransitOld(transit), - topOpeningAnim != null ? topOpeningAnim.getDurationHint() : 0, topOpeningAnim != null ? topOpeningAnim.getStatusBarTransitionsStartTime() : SystemClock.uptimeMillis(), @@ -416,7 +413,7 @@ public class AppTransition implements Dump { } void freeze() { - final boolean keyguardGoingAway = mNextAppTransitionRequests.contains( + final boolean keyguardGoingAwayCancelled = mNextAppTransitionRequests.contains( TRANSIT_KEYGUARD_GOING_AWAY); // The RemoteAnimationControl didn't register AppTransitionListener and @@ -429,7 +426,7 @@ public class AppTransition implements Dump { mNextAppTransitionRequests.clear(); clear(); setReady(); - notifyAppTransitionCancelledLocked(keyguardGoingAway); + notifyAppTransitionCancelledLocked(keyguardGoingAwayCancelled); } private void setAppTransitionState(int state) { @@ -479,9 +476,9 @@ public class AppTransition implements Dump { } } - private void notifyAppTransitionCancelledLocked(boolean keyguardGoingAway) { + private void notifyAppTransitionCancelledLocked(boolean keyguardGoingAwayCancelled) { for (int i = 0; i < mListeners.size(); i++) { - mListeners.get(i).onAppTransitionCancelledLocked(keyguardGoingAway); + mListeners.get(i).onAppTransitionCancelledLocked(keyguardGoingAwayCancelled); } } @@ -491,14 +488,12 @@ public class AppTransition implements Dump { } } - private int notifyAppTransitionStartingLocked(boolean keyguardGoingAway, - boolean keyguardOcclude, long duration, long statusBarAnimationStartTime, + private int notifyAppTransitionStartingLocked(long statusBarAnimationStartTime, long statusBarAnimationDuration) { int redoLayout = 0; for (int i = 0; i < mListeners.size(); i++) { - redoLayout |= mListeners.get(i).onAppTransitionStartingLocked(keyguardGoingAway, - keyguardOcclude, duration, statusBarAnimationStartTime, - statusBarAnimationDuration); + redoLayout |= mListeners.get(i).onAppTransitionStartingLocked( + statusBarAnimationStartTime, statusBarAnimationDuration); } return redoLayout; } diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index 44f388b6ed39..4b0005d77e40 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -20,10 +20,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_FLAG_APP_CRASHED; -import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION; -import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION; -import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE; -import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER; import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND; import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY; import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE; @@ -95,7 +91,6 @@ import android.view.WindowManager.LayoutParams; import android.view.WindowManager.TransitionFlags; import android.view.WindowManager.TransitionOldType; import android.view.WindowManager.TransitionType; -import android.view.animation.Animation; import android.window.ITaskFragmentOrganizer; import com.android.internal.annotations.VisibleForTesting; @@ -297,7 +292,6 @@ public class AppTransitionController { final int flags = appTransition.getTransitFlags(); layoutRedo = appTransition.goodToGo(transit, topOpeningApp); - handleNonAppWindowsInTransition(transit, flags); appTransition.postAnimationCallback(); appTransition.clear(); } finally { @@ -1171,30 +1165,6 @@ public class AppTransitionController { } } - private void handleNonAppWindowsInTransition(@TransitionOldType int transit, int flags) { - if (transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY - && !WindowManagerService.sEnableRemoteKeyguardGoingAwayAnimation) { - if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0 - && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0 - && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION) == 0) { - Animation anim = mService.mPolicy.createKeyguardWallpaperExit( - (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0); - if (anim != null) { - anim.scaleCurrentDuration(mService.getTransitionAnimationScaleLocked()); - mDisplayContent.mWallpaperController.startWallpaperAnimation(anim); - } - } - } - if ((transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY - || transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER) - && !WindowManagerService.sEnableRemoteKeyguardGoingAwayAnimation) { - mDisplayContent.startKeyguardExitOnNonAppWindows( - transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER, - (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0, - (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION) != 0); - } - } - private boolean transitionGoodToGo(ArraySet<? extends WindowContainer> apps, ArrayMap<WindowContainer, Integer> outReasons) { ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 77737028fd37..1c90bbae79ec 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -6586,7 +6586,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } @Override - public void onAppTransitionCancelledLocked(boolean keyguardGoingAway) { + public void onAppTransitionCancelledLocked(boolean keyguardGoingAwayCancelled) { // It is only needed when freezing display in legacy transition. if (mTransitionController.isShellTransitionsEnabled()) return; continueUpdateOrientationForDiffOrienLaunchingApp(); diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 8e06a810ead1..508e6dc77a61 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -619,9 +619,8 @@ public class DisplayPolicy { } @Override - public int onAppTransitionStartingLocked(boolean keyguardGoingAway, - boolean keyguardOccluding, long duration, - long statusBarAnimationStartTime, long statusBarAnimationDuration) { + public int onAppTransitionStartingLocked(long statusBarAnimationStartTime, + long statusBarAnimationDuration) { mHandler.post(() -> { StatusBarManagerInternal statusBar = getStatusBarManagerInternal(); if (statusBar != null) { @@ -633,7 +632,7 @@ public class DisplayPolicy { } @Override - public void onAppTransitionCancelledLocked(boolean keyguardGoingAway) { + public void onAppTransitionCancelledLocked(boolean keyguardGoingAwayCancelled) { mHandler.post(mAppTransitionCancelled); } diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index 5b702eac7059..7bb57d827a43 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -161,15 +161,14 @@ public class RecentsAnimationController implements DeathRecipient { */ final AppTransitionListener mAppTransitionListener = new AppTransitionListener() { @Override - public int onAppTransitionStartingLocked(boolean keyguardGoingAway, - boolean keyguardOccluding, long duration, long statusBarAnimationStartTime, + public int onAppTransitionStartingLocked(long statusBarAnimationStartTime, long statusBarAnimationDuration) { continueDeferredCancel(); return 0; } @Override - public void onAppTransitionCancelledLocked(boolean keyguardGoingAway) { + public void onAppTransitionCancelledLocked(boolean keyguardGoingAwayCancelled) { continueDeferredCancel(); } diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 80b7514d3502..c586b155a222 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -32,13 +32,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS; -import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY; -import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION; -import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION; -import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE; -import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED; -import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; @@ -74,7 +68,6 @@ import android.os.Binder; import android.os.IBinder; import android.os.IRemoteCallback; import android.os.RemoteException; -import android.os.SystemClock; import android.os.Trace; import android.util.ArrayMap; import android.util.ArraySet; @@ -82,7 +75,6 @@ import android.util.Slog; import android.util.SparseArray; import android.view.SurfaceControl; import android.view.WindowManager; -import android.view.animation.Animation; import android.window.RemoteTransition; import android.window.TransitionInfo; @@ -1150,36 +1142,9 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe private void handleNonAppWindowsInTransition(@NonNull DisplayContent dc, @TransitionType int transit, @TransitionFlags int flags) { - if ((transit == TRANSIT_KEYGUARD_GOING_AWAY - || (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY) != 0) - && !WindowManagerService.sEnableRemoteKeyguardGoingAwayAnimation) { - if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0 - && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0 - && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION) == 0) { - Animation anim = mController.mAtm.mWindowManager.mPolicy - .createKeyguardWallpaperExit( - (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0); - if (anim != null) { - anim.scaleCurrentDuration( - mController.mAtm.mWindowManager.getTransitionAnimationScaleLocked()); - dc.mWallpaperController.startWallpaperAnimation(anim); - } - } - dc.startKeyguardExitOnNonAppWindows( - (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0, - (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0, - (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION) != 0); - if (!WindowManagerService.sEnableRemoteKeyguardGoingAwayAnimation) { - // When remote animation is enabled for KEYGUARD_GOING_AWAY transition, SysUI - // receives IRemoteAnimationRunner#onAnimationStart to start animation, so we don't - // need to call IKeyguardService#keyguardGoingAway here. - mController.mAtm.mWindowManager.mPolicy.startKeyguardExitAnimation( - SystemClock.uptimeMillis(), 0 /* duration */); - } - } if ((flags & TRANSIT_FLAG_KEYGUARD_LOCKED) != 0) { mController.mAtm.mWindowManager.mPolicy.applyKeyguardOcclusionChange( - true /* keyguardOccludingStarted */); + false /* notify */); } } diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index f62efbfbd08d..e2438097bce4 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -655,11 +655,9 @@ class TransitionController { } void dispatchLegacyAppTransitionStarting(TransitionInfo info, long statusBarTransitionDelay) { - final boolean keyguardGoingAway = info.isKeyguardGoingAway(); for (int i = 0; i < mLegacyListeners.size(); ++i) { // TODO(shell-transitions): handle (un)occlude transition. - mLegacyListeners.get(i).onAppTransitionStartingLocked(keyguardGoingAway, - false /* keyguardOcclude */, 0 /* durationHint */, + mLegacyListeners.get(i).onAppTransitionStartingLocked( SystemClock.uptimeMillis() + statusBarTransitionDelay, AnimationAdapter.STATUS_BAR_TRANSITION_DURATION); } @@ -674,7 +672,7 @@ class TransitionController { void dispatchLegacyAppTransitionCancelled() { for (int i = 0; i < mLegacyListeners.size(); ++i) { mLegacyListeners.get(i).onAppTransitionCancelledLocked( - false /* keyguardGoingAway */); + false /* keyguardGoingAwayCancelled */); } } diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index a71c3866ba38..11475ac6150b 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -220,9 +220,10 @@ public abstract class WindowManagerInternal { /** * Called when a pending app transition gets cancelled. * - * @param keyguardGoingAway true if keyguard going away transition got cancelled. + * @param keyguardGoingAwayCancelled {@code true} if keyguard going away transition was + * cancelled. */ - public void onAppTransitionCancelledLocked(boolean keyguardGoingAway) {} + public void onAppTransitionCancelledLocked(boolean keyguardGoingAwayCancelled) {} /** * Called when an app transition is timed out. @@ -232,9 +233,6 @@ public abstract class WindowManagerInternal { /** * Called when an app transition gets started * - * @param keyguardGoingAway true if keyguard going away transition is started. - * @param keyguardOccluding true if keyguard (un)occlude transition is started. - * @param duration the total duration of the transition * @param statusBarAnimationStartTime the desired start time for all visual animations in * the status bar caused by this app transition in uptime millis * @param statusBarAnimationDuration the duration for all visual animations in the status @@ -245,8 +243,7 @@ public abstract class WindowManagerInternal { * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_WALLPAPER}, * or {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_ANIM}. */ - public int onAppTransitionStartingLocked(boolean keyguardGoingAway, - boolean keyguardOccluding, long duration, long statusBarAnimationStartTime, + public int onAppTransitionStartingLocked(long statusBarAnimationStartTime, long statusBarAnimationDuration) { return 0; } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index b4386f6ad206..8025cb296b32 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -425,32 +425,6 @@ public class WindowManagerService extends IWindowManager.Stub SystemProperties.getBoolean(ENABLE_SHELL_TRANSITIONS, false); /** - * Run Keyguard animation as remote animation in System UI instead of local animation in - * the server process. - * - * 0: Runs all keyguard animation as local animation - * 1: Only runs keyguard going away animation as remote animation - * 2: Runs all keyguard animation as remote animation - */ - private static final String ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY = - "persist.wm.enable_remote_keyguard_animation"; - - private static final int sEnableRemoteKeyguardAnimation = - SystemProperties.getInt(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, 2); - - /** - * @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY - */ - public static final boolean sEnableRemoteKeyguardGoingAwayAnimation = - sEnableRemoteKeyguardAnimation >= 1; - - /** - * @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY - */ - public static final boolean sEnableRemoteKeyguardOccludeAnimation = - sEnableRemoteKeyguardAnimation >= 2; - - /** * Allows a fullscreen windowing mode activity to launch in its desired orientation directly * when the display has different orientation. */ @@ -1118,7 +1092,7 @@ public class WindowManagerService extends IWindowManager.Stub = new WindowManagerInternal.AppTransitionListener() { @Override - public void onAppTransitionCancelledLocked(boolean keyguardGoingAway) { + public void onAppTransitionCancelledLocked(boolean keyguardGoingAwayCancelled) { } @Override diff --git a/services/proguard.flags b/services/proguard.flags index c9303462fb6a..606f360f2cc5 100644 --- a/services/proguard.flags +++ b/services/proguard.flags @@ -104,6 +104,9 @@ -keep,allowoptimization,allowaccessmodification class com.android.server.input.InputManagerService { <methods>; } +-keep,allowoptimization,allowaccessmodification class com.android.server.input.NativeInputManagerService$NativeImpl { + <methods>; +} -keep,allowoptimization,allowaccessmodification class com.android.server.usb.UsbHostManager { *** usbDeviceRemoved(...); *** usbDeviceAdded(...); diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java index d90d8b8bfac0..5cf026e64f67 100644 --- a/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java @@ -68,7 +68,8 @@ public class ScribeTest { private MockitoSession mMockingSession; private Scribe mScribeUnderTest; private File mTestFileDir; - private final List<InstalledPackageInfo> mInstalledPackages = new ArrayList<>(); + private final SparseArrayMap<String, InstalledPackageInfo> mInstalledPackages = + new SparseArrayMap<>(); private final List<Analyst.Report> mReports = new ArrayList<>(); @Mock @@ -455,6 +456,6 @@ public class ScribeTest { ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.uid = UserHandle.getUid(userId, Math.abs(pkgName.hashCode())); pkgInfo.applicationInfo = applicationInfo; - mInstalledPackages.add(new InstalledPackageInfo(pkgInfo)); + mInstalledPackages.add(userId, pkgName, new InstalledPackageInfo(pkgInfo)); } } diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInteractionControllerNodeRequestsTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInteractionControllerNodeRequestsTest.java index 842b23c91e41..4a16874c7acf 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInteractionControllerNodeRequestsTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInteractionControllerNodeRequestsTest.java @@ -17,13 +17,13 @@ package com.android.server.accessibility; -import static android.view.accessibility.AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; import static android.view.accessibility.AccessibilityNodeInfo.FLAG_PREFETCH_ANCESTORS; import static android.view.accessibility.AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS_BREADTH_FIRST; import static android.view.accessibility.AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS_DEPTH_FIRST; import static android.view.accessibility.AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS_HYBRID; import static android.view.accessibility.AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS; import static android.view.accessibility.AccessibilityNodeInfo.FLAG_PREFETCH_UNINTERRUPTIBLE; +import static android.view.accessibility.AccessibilityNodeInfo.FLAG_SERVICE_REQUESTS_INCLUDE_NOT_IMPORTANT_VIEWS; import static android.view.accessibility.AccessibilityNodeInfo.ROOT_NODE_ID; import static org.junit.Assert.assertEquals; @@ -528,7 +528,8 @@ public class AccessibilityInteractionControllerNodeRequestsTest { // different client that holds different fetch flags for TextView1. sendNodeRequestToController(nodeId, mMockClientCallback2, mMockClient2InteractionId, - FLAG_PREFETCH_SIBLINGS | FLAG_INCLUDE_NOT_IMPORTANT_VIEWS + FLAG_PREFETCH_SIBLINGS + | FLAG_SERVICE_REQUESTS_INCLUDE_NOT_IMPORTANT_VIEWS | FLAG_PREFETCH_ANCESTORS); } } diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java b/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java index 5a6d2d398f7d..b7f564094cde 100644 --- a/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java +++ b/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java @@ -25,6 +25,7 @@ import static org.mockito.Mockito.when; import android.hardware.input.IInputDevicesChangedListener; import android.hardware.input.IInputManager; +import android.hardware.input.InputDeviceCountryCode; import android.hardware.input.InputManager; import android.os.RemoteException; import android.testing.TestableLooper; @@ -84,7 +85,7 @@ class InputManagerMockHelper { final InputDevice device = new InputDevice(mDevices.size() /*id*/, 1 /*generation*/, 0, inv.getArgument(0) /*name*/, inv.getArgument(1) /*vendorId*/, inv.getArgument(2) /*productId*/, inv.getArgument(3) /*descriptor*/, true, 0, 0, - null, false, false, false, false, false); + null, InputDeviceCountryCode.INVALID, false, false, false, false, false); mDevices.add(device); try { mDevicesChangedListener.onInputDevicesChanged( diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java index 0841bfc1d88c..7ce7ac9a84cf 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java @@ -17,6 +17,7 @@ package com.android.server.pm; import static com.android.server.pm.permission.CompatibilityPermissionInfo.COMPAT_PERMS; +import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.assertArrayEquals; @@ -101,7 +102,6 @@ import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Array; import java.lang.reflect.Field; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; @@ -260,6 +260,38 @@ public class PackageParserTest { } /** + * Extracts the asset file to $mTmpDir/$dirname/$filename. + */ + private File extractFile(String filename, String dirname) throws Exception { + final Context context = InstrumentationRegistry.getTargetContext(); + File dir = new File(mTmpDir, dirname); + dir.mkdir(); + final File tmpFile = new File(dir, filename); + try (InputStream inputStream = context.getAssets().openNonAsset(filename)) { + Files.copy(inputStream, tmpFile.toPath(), REPLACE_EXISTING); + } + return tmpFile; + } + + /** + * Tests the path of cached ParsedPackage. + */ + @Test + public void testCache_SameFileName() throws Exception { + // Prepare 2 package files with the same name but different paths + TestPackageParser2 parser = new TestPackageParser2(mTmpDir); + final File f1 = extractFile(TEST_APP1_APK, "dir1"); + final File f2 = extractFile(TEST_APP1_APK, "dir2"); + // Sleep for a while so that the cache file will be newer and valid + Thread.sleep(1000); + ParsedPackage pr1 = parser.parsePackage(f1, 0, true); + ParsedPackage pr2 = parser.parsePackage(f2, 0, true); + // Check the path of cached ParsedPackage + assertThat(pr1.getPath()).isEqualTo(f1.getAbsolutePath()); + assertThat(pr2.getPath()).isEqualTo(f2.getAbsolutePath()); + } + + /** * Tests AndroidManifest.xml with no android:isolatedSplits attribute. */ @Test @@ -632,8 +664,8 @@ public class PackageParserTest { } /** - * A trivial subclass of package parser that only caches the package name, and throws away - * all other information. + * A subclass of package parser that adds a "cache_" prefix to the package name for the cached + * results. This is used by tests to tell if a ParsedPackage is generated from the cache or not. */ public static class CachePackageNameParser extends PackageParser2 { @@ -657,15 +689,10 @@ public class PackageParserTest { void setCacheDir(@NonNull File cacheDir) { this.mCacher = new PackageCacher(cacheDir) { @Override - public byte[] toCacheEntry(ParsedPackage pkg) { - return ("cache_" + pkg.getPackageName()).getBytes(StandardCharsets.UTF_8); - } - - @Override public ParsedPackage fromCacheEntry(byte[] cacheEntry) { - return ((ParsedPackage) PackageImpl.forTesting( - new String(cacheEntry, StandardCharsets.UTF_8)) - .hideAsParsed()); + ParsedPackage parsed = super.fromCacheEntry(cacheEntry); + parsed.setPackageName("cache_" + parsed.getPackageName()); + return parsed; } }; } diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt index 6ee91b89cadc..2332817911f7 100644 --- a/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt @@ -17,9 +17,11 @@ package com.android.server.pm.parsing import android.content.pm.ApplicationInfo +import java.io.File -class TestPackageParser2 : PackageParser2(null /* separateProcesses */, null /* displayMetrics */, - null /* cacheDir */, object : PackageParser2.Callback() { +class TestPackageParser2(var cacheDir: File? = null) : PackageParser2( + null /* separateProcesses */, null /* displayMetrics */, + cacheDir /* cacheDir */, object : PackageParser2.Callback() { override fun isChangeEnabled(changeId: Long, appInfo: ApplicationInfo): Boolean { return true } diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java b/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java index 61a7f3853746..5c9348525861 100644 --- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java +++ b/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java @@ -28,6 +28,7 @@ import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import com.android.internal.os.BatteryStatsHistory; +import com.android.internal.os.Clock; import org.junit.Before; import org.junit.Test; @@ -49,13 +50,14 @@ public class BatteryStatsHistoryTest { private final Parcel mHistoryBuffer = Parcel.obtain(); private File mSystemDir; private File mHistoryDir; + private final Clock mClock = new MockClock(); @Before public void setUp() { MockitoAnnotations.initMocks(this); Context context = InstrumentationRegistry.getContext(); mSystemDir = context.getDataDir(); - mHistoryDir = new File(mSystemDir, BatteryStatsHistory.HISTORY_DIR); + mHistoryDir = new File(mSystemDir, "battery-history"); String[] files = mHistoryDir.list(); if (files != null) { for (int i = 0; i < files.length; i++) { @@ -67,8 +69,8 @@ public class BatteryStatsHistoryTest { @Test public void testConstruct() { - BatteryStatsHistory history = - new BatteryStatsHistory(mHistoryBuffer, mSystemDir, () -> 32); + BatteryStatsHistory history = new BatteryStatsHistory(mHistoryBuffer, mSystemDir, 32, 1024, + null, mClock); createActiveFile(history); verifyFileNumbers(history, Arrays.asList(0)); verifyActiveFile(history, "0.bin"); @@ -76,8 +78,8 @@ public class BatteryStatsHistoryTest { @Test public void testStartNextFile() { - BatteryStatsHistory history = - new BatteryStatsHistory(mHistoryBuffer, mSystemDir, () -> 32); + BatteryStatsHistory history = new BatteryStatsHistory(mHistoryBuffer, mSystemDir, 32, 1024, + null, mClock); List<Integer> fileList = new ArrayList<>(); fileList.add(0); createActiveFile(history); @@ -114,13 +116,13 @@ public class BatteryStatsHistoryTest { assertEquals(0, history.getHistoryUsedSize()); // create a new BatteryStatsHistory object, it will pick up existing history files. - BatteryStatsHistory history2 = - new BatteryStatsHistory(mHistoryBuffer, mSystemDir, () -> 32); - // verify construct can pick up all files from file system. + BatteryStatsHistory history2 = new BatteryStatsHistory(mHistoryBuffer, mSystemDir, 32, 1024, + null, mClock); + // verify constructor can pick up all files from file system. verifyFileNumbers(history2, fileList); verifyActiveFile(history2, "33.bin"); - history2.resetAllFiles(); + history2.reset(); createActiveFile(history2); // verify all existing files are deleted. for (int i = 2; i < 33; ++i) { diff --git a/services/tests/servicestests/src/com/android/server/power/stats/MockBatteryStatsImpl.java b/services/tests/servicestests/src/com/android/server/power/stats/MockBatteryStatsImpl.java index 713e78638b95..570b2ee617f5 100644 --- a/services/tests/servicestests/src/com/android/server/power/stats/MockBatteryStatsImpl.java +++ b/services/tests/servicestests/src/com/android/server/power/stats/MockBatteryStatsImpl.java @@ -63,6 +63,7 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl { MockBatteryStatsImpl(Clock clock, File historyDirectory) { super(clock, historyDirectory); initTimersAndCounters(); + setMaxHistoryBuffer(128 * 1024); setExternalStatsSyncLocked(mExternalStatsSync); informThatAllExternalStatsAreFlushed(); @@ -104,12 +105,6 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl { return mForceOnBattery ? true : super.isOnBattery(); } - public void forceRecordAllHistory() { - mHaveBatteryLevel = true; - mRecordingHistory = true; - mRecordAllHistory = true; - } - public TimeBase getOnBatteryBackgroundTimeBase(int uid) { return getUidStatsLocked(uid).mOnBatteryBackgroundTimeBase; } @@ -201,12 +196,14 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl { @GuardedBy("this") public MockBatteryStatsImpl setMaxHistoryFiles(int maxHistoryFiles) { mConstants.MAX_HISTORY_FILES = maxHistoryFiles; + mConstants.onChange(); return this; } @GuardedBy("this") public MockBatteryStatsImpl setMaxHistoryBuffer(int maxHistoryBuffer) { mConstants.MAX_HISTORY_BUFFER = maxHistoryBuffer; + mConstants.onChange(); return this; } diff --git a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java index 3f9caa95df4a..ec4ad8965f7d 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java @@ -33,6 +33,7 @@ import android.content.Context; import android.content.ContextWrapper; import android.hardware.input.IInputDevicesChangedListener; import android.hardware.input.IInputManager; +import android.hardware.input.InputDeviceCountryCode; import android.hardware.input.InputManager; import android.os.CombinedVibration; import android.os.Handler; @@ -328,7 +329,8 @@ public class InputDeviceDelegateTest { private InputDevice createInputDevice(int id, boolean hasVibrator) { return new InputDevice(id, 0, 0, "name", 0, 0, "description", false, 0, 0, - null, hasVibrator, false, false, false /* hasSensor */, false /* hasBattery */); + null, InputDeviceCountryCode.INVALID, hasVibrator, false, false, + false /* hasSensor */, false /* hasBattery */); } diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java index ca162efe0f6e..efc240d3f172 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java @@ -574,7 +574,7 @@ public class VibrationThreadTest { } @Test - public void vibrate_singleVibratorComposedAndNoCapability_ignoresVibration() throws Exception { + public void vibrate_singleVibratorComposedAndNoCapability_ignoresVibration() { long vibrationId = 1; VibrationEffect effect = VibrationEffect.startComposition() .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f) @@ -666,6 +666,47 @@ public class VibrationThreadTest { } @Test + public void vibrate_singleVibratorComposedWithFallback_replacedInTheMiddleOfComposition() { + FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID); + fakeVibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK); + fakeVibrator.setSupportedPrimitives( + VibrationEffect.Composition.PRIMITIVE_CLICK, + VibrationEffect.Composition.PRIMITIVE_TICK); + fakeVibrator.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS); + + long vibrationId = 1; + VibrationEffect fallback = VibrationEffect.createOneShot(10, 100); + VibrationEffect effect = VibrationEffect.startComposition() + .addEffect(VibrationEffect.get(VibrationEffect.EFFECT_CLICK)) + .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f) + .addEffect(VibrationEffect.get(VibrationEffect.EFFECT_TICK)) + .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f) + .compose(); + Vibration vib = createVibration(vibrationId, CombinedVibration.createParallel(effect)); + vib.addFallback(VibrationEffect.EFFECT_TICK, fallback); + startThreadAndDispatcher(vib); + waitForCompletion(); + + // Use first duration the vibrator is turned on since we cannot estimate the clicks. + verify(mManagerHooks).noteVibratorOn(eq(UID), anyLong()); + verify(mManagerHooks).noteVibratorOff(eq(UID)); + verify(mControllerCallbacks, times(4)).onComplete(eq(VIBRATOR_ID), eq(vibrationId)); + verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED); + assertFalse(mControllers.get(VIBRATOR_ID).isVibrating()); + + List<VibrationEffectSegment> segments = + mVibratorProviders.get(VIBRATOR_ID).getEffectSegments(vibrationId); + assertTrue("Wrong segments: " + segments, segments.size() >= 4); + assertTrue(segments.get(0) instanceof PrebakedSegment); + assertTrue(segments.get(1) instanceof PrimitiveSegment); + for (int i = 2; i < segments.size() - 1; i++) { + // One or more step segments as fallback for the EFFECT_TICK. + assertTrue(segments.get(i) instanceof StepSegment); + } + assertTrue(segments.get(segments.size() - 1) instanceof PrimitiveSegment); + } + + @Test public void vibrate_singleVibratorPwle_runsComposePwle() throws Exception { FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID); fakeVibrator.setCapabilities(IVibrator.CAP_COMPOSE_PWLE_EFFECTS); diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java index 36bec750e3bc..1a8df719c223 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java @@ -46,6 +46,7 @@ import android.content.Context; import android.content.ContextWrapper; import android.content.pm.PackageManagerInternal; import android.hardware.input.IInputManager; +import android.hardware.input.InputDeviceCountryCode; import android.hardware.input.InputManager; import android.hardware.vibrator.IVibrator; import android.hardware.vibrator.IVibratorManager; @@ -72,6 +73,7 @@ import android.os.VibratorInfo; import android.os.test.TestLooper; import android.os.vibrator.PrebakedSegment; import android.os.vibrator.PrimitiveSegment; +import android.os.vibrator.StepSegment; import android.os.vibrator.VibrationConfig; import android.os.vibrator.VibrationEffectSegment; import android.platform.test.annotations.Presubmit; @@ -99,6 +101,7 @@ import org.mockito.junit.MockitoRule; import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -391,22 +394,22 @@ public class VibratorManagerServiceTest { IVibratorStateListener listenerMock = mockVibratorStateListener(); service.registerVibratorStateListener(1, listenerMock); - vibrate(service, VibrationEffect.createOneShot(40, 100), ALARM_ATTRS); - // Wait until service knows vibrator is on. - assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS)); - // Wait until effect ends. - assertTrue(waitUntil(s -> !s.isVibrating(1), service, TEST_TIMEOUT_MILLIS)); + long oneShotDuration = 20; + vibrateAndWaitUntilFinished(service, + VibrationEffect.createOneShot(oneShotDuration, VibrationEffect.DEFAULT_AMPLITUDE), + ALARM_ATTRS); InOrder inOrderVerifier = inOrder(listenerMock); // First notification done when listener is registered. inOrderVerifier.verify(listenerMock).onVibrating(eq(false)); inOrderVerifier.verify(listenerMock).onVibrating(eq(true)); - inOrderVerifier.verify(listenerMock).onVibrating(eq(false)); + // The last notification is after the vibration has completed. + inOrderVerifier.verify(listenerMock, timeout(TEST_TIMEOUT_MILLIS)).onVibrating(eq(false)); inOrderVerifier.verifyNoMoreInteractions(); InOrder batteryVerifier = inOrder(mBatteryStatsMock); batteryVerifier.verify(mBatteryStatsMock) - .noteVibratorOn(UID, 40 + mVibrationConfig.getRampDownDurationMs()); + .noteVibratorOn(UID, oneShotDuration + mVibrationConfig.getRampDownDurationMs()); batteryVerifier.verify(mBatteryStatsMock).noteVibratorOff(UID); } @@ -577,22 +580,18 @@ public class VibratorManagerServiceTest { setRingerMode(AudioManager.RINGER_MODE_SILENT); VibratorManagerService service = createSystemReadyService(); - vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), RINGTONE_ATTRS); - // Wait before checking it never played. - assertFalse(waitUntil(s -> !fakeVibrator.getAllEffectSegments().isEmpty(), - service, /* timeout= */ 50)); + vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), + RINGTONE_ATTRS); setRingerMode(AudioManager.RINGER_MODE_NORMAL); service = createSystemReadyService(); - vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK), RINGTONE_ATTRS); - assertTrue(waitUntil(s -> fakeVibrator.getAllEffectSegments().size() == 1, - service, TEST_TIMEOUT_MILLIS)); + vibrateAndWaitUntilFinished( + service, VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK), RINGTONE_ATTRS); setRingerMode(AudioManager.RINGER_MODE_VIBRATE); service = createSystemReadyService(); - vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK), RINGTONE_ATTRS); - assertTrue(waitUntil(s -> fakeVibrator.getAllEffectSegments().size() == 2, - service, TEST_TIMEOUT_MILLIS)); + vibrateAndWaitUntilFinished( + service, VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK), RINGTONE_ATTRS); assertEquals( Arrays.asList(expectedPrebaked(VibrationEffect.EFFECT_HEAVY_CLICK), @@ -607,27 +606,18 @@ public class VibratorManagerServiceTest { fakeVibrator.setSupportedEffects(VibrationEffect.EFFECT_TICK, VibrationEffect.EFFECT_CLICK, VibrationEffect.EFFECT_HEAVY_CLICK, VibrationEffect.EFFECT_DOUBLE_CLICK); VibratorManagerService service = createSystemReadyService(); - mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE); - // The haptic feedback should be ignored in low power, but not the ringtone. The end - // of the test asserts which actual effects ended up playing. - vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_TICK), HAPTIC_FEEDBACK_ATTRS); - vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), RINGTONE_ATTRS); - assertTrue(waitUntil(s -> fakeVibrator.getAllEffectSegments().size() == 1, - service, TEST_TIMEOUT_MILLIS)); - // Allow the ringtone to complete, as the other vibrations won't cancel it. - assertTrue(waitUntil(s -> !s.isVibrating(1), service, TEST_TIMEOUT_MILLIS)); + mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE); + vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_TICK), + HAPTIC_FEEDBACK_ATTRS); + vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), + RINGTONE_ATTRS); mRegisteredPowerModeListener.onLowPowerModeChanged(NORMAL_POWER_STATE); - vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK), - /* attrs= */ null); - assertTrue(waitUntil(s -> fakeVibrator.getAllEffectSegments().size() == 2, - service, TEST_TIMEOUT_MILLIS)); - - vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK), - NOTIFICATION_ATTRS); - assertTrue(waitUntil(s -> fakeVibrator.getAllEffectSegments().size() == 3, - service, TEST_TIMEOUT_MILLIS)); + vibrateAndWaitUntilFinished(service, + VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK), /* attrs= */ null); + vibrateAndWaitUntilFinished(service, + VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK), NOTIFICATION_ATTRS); assertEquals( Arrays.asList(expectedPrebaked(VibrationEffect.EFFECT_CLICK), @@ -693,22 +683,17 @@ public class VibratorManagerServiceTest { Vibrator.VIBRATION_INTENSITY_HIGH); VibratorManagerService service = createSystemReadyService(); - VibrationAttributes enforceFreshAttrs = new VibrationAttributes.Builder() + VibrationAttributes notificationWithFreshAttrs = new VibrationAttributes.Builder() .setUsage(VibrationAttributes.USAGE_NOTIFICATION) .setFlags(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE) .build(); setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_LOW); - vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), NOTIFICATION_ATTRS); - // VibrationThread will start this vibration async, so wait before vibrating a second time. - assertTrue(waitUntil(s -> mVibratorProviders.get(0).getAllEffectSegments().size() > 0, - service, TEST_TIMEOUT_MILLIS)); - - vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_TICK), enforceFreshAttrs); - // VibrationThread will start this vibration async, so wait before checking. - assertTrue(waitUntil(s -> mVibratorProviders.get(0).getAllEffectSegments().size() > 1, - service, TEST_TIMEOUT_MILLIS)); + vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), + NOTIFICATION_ATTRS); + vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_TICK), + notificationWithFreshAttrs); assertEquals( Arrays.asList( @@ -784,21 +769,22 @@ public class VibratorManagerServiceTest { vibrate(service, repeatingEffect, new VibrationAttributes.Builder().setUsage( VibrationAttributes.USAGE_UNKNOWN).build()); - // VibrationThread will start this vibration async, so wait before checking it started. + // VibrationThread will start this vibration async, wait until it has started. assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(), service, TEST_TIMEOUT_MILLIS)); - vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), HAPTIC_FEEDBACK_ATTRS); - - // Wait before checking it never played a second effect. - assertFalse(waitUntil(s -> mVibratorProviders.get(1).getAllEffectSegments().size() > 1, - service, /* timeout= */ 50)); + vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), + HAPTIC_FEEDBACK_ATTRS); // The time estimate is recorded when the vibration starts, repeating vibrations // are capped at BATTERY_STATS_REPEATING_VIBRATION_DURATION (=5000). verify(mBatteryStatsMock).noteVibratorOn(UID, 5000); // The second vibration shouldn't have recorded that the vibrators were turned on. verify(mBatteryStatsMock, times(1)).noteVibratorOn(anyInt(), anyLong()); + // No segment played is the prebaked CLICK from the second vibration. + assertFalse( + mVibratorProviders.get(1).getAllEffectSegments().stream() + .anyMatch(segment -> segment instanceof PrebakedSegment)); } @Test @@ -811,7 +797,7 @@ public class VibratorManagerServiceTest { new long[]{10_000, 10_000}, new int[]{128, 255}, -1); vibrate(service, alarmEffect, ALARM_ATTRS); - // VibrationThread will start this vibration async, so wait before checking it started. + // VibrationThread will start this vibration async, wait until it has started. assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(), service, TEST_TIMEOUT_MILLIS)); @@ -841,14 +827,15 @@ public class VibratorManagerServiceTest { assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(), service, TEST_TIMEOUT_MILLIS)); - vibrate(service, effect, HAPTIC_FEEDBACK_ATTRS); - - // Wait before checking it never played a second effect. - assertFalse(waitUntil(s -> mVibratorProviders.get(1).getAllEffectSegments().size() > 1, - service, /* timeout= */ 50)); + vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), + HAPTIC_FEEDBACK_ATTRS); // The second vibration shouldn't have recorded that the vibrators were turned on. verify(mBatteryStatsMock, times(1)).noteVibratorOn(anyInt(), anyLong()); + // The second vibration shouldn't have played any prebaked segment. + assertFalse( + mVibratorProviders.get(1).getAllEffectSegments().stream() + .anyMatch(segment -> segment instanceof PrebakedSegment)); } @Test @@ -856,6 +843,7 @@ public class VibratorManagerServiceTest { throws Exception { mockVibrators(1); mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); + mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK); VibratorManagerService service = createSystemReadyService(); VibrationEffect effect = VibrationEffect.createWaveform( @@ -866,14 +854,16 @@ public class VibratorManagerServiceTest { assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(), service, TEST_TIMEOUT_MILLIS)); - vibrate(service, effect, RINGTONE_ATTRS); - - // VibrationThread will start this vibration async, so wait before checking it started. - assertTrue(waitUntil(s -> mVibratorProviders.get(1).getAllEffectSegments().size() > 1, - service, TEST_TIMEOUT_MILLIS)); + vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), + RINGTONE_ATTRS); // The second vibration should have recorded that the vibrators were turned on. verify(mBatteryStatsMock, times(2)).noteVibratorOn(anyInt(), anyLong()); + // One segment played is the prebaked CLICK from the second vibration. + assertEquals(1, + mVibratorProviders.get(1).getAllEffectSegments().stream() + .filter(PrebakedSegment.class::isInstance) + .count()); } @Test @@ -892,12 +882,10 @@ public class VibratorManagerServiceTest { CombinedVibration effect = CombinedVibration.createParallel( VibrationEffect.createOneShot(10, 10)); - vibrate(service, effect, ALARM_ATTRS); - verify(mIInputManagerMock).vibrateCombined(eq(1), eq(effect), any()); + vibrateAndWaitUntilFinished(service, effect, ALARM_ATTRS); - // VibrationThread will start this vibration async, so wait before checking it never played. - assertFalse(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(), - service, /* timeout= */ 50)); + verify(mIInputManagerMock).vibrateCombined(eq(1), eq(effect), any()); + assertTrue(mVibratorProviders.get(1).getAllEffectSegments().isEmpty()); } @Test @@ -992,9 +980,7 @@ public class VibratorManagerServiceTest { .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK) .compose()) .combine(); - vibrate(service, effect, ALARM_ATTRS); - assertTrue(waitUntil(s -> !fakeVibrator1.getAllEffectSegments().isEmpty(), service, - TEST_TIMEOUT_MILLIS)); + vibrateAndWaitUntilFinished(service, effect, ALARM_ATTRS); verify(mNativeWrapperMock).prepareSynced(eq(new int[]{1, 2})); verify(mNativeWrapperMock).triggerSynced(anyLong()); @@ -1016,9 +1002,7 @@ public class VibratorManagerServiceTest { .addVibrator(1, VibrationEffect.get(VibrationEffect.EFFECT_CLICK)) .addVibrator(2, VibrationEffect.createOneShot(10, 100)) .combine(); - vibrate(service, effect, ALARM_ATTRS); - assertTrue(waitUntil(s -> !fakeVibrator1.getAllEffectSegments().isEmpty(), service, - TEST_TIMEOUT_MILLIS)); + vibrateAndWaitUntilFinished(service, effect, ALARM_ATTRS); verify(mNativeWrapperMock, never()).prepareSynced(any()); verify(mNativeWrapperMock, never()).triggerSynced(anyLong()); @@ -1036,9 +1020,7 @@ public class VibratorManagerServiceTest { .addVibrator(1, VibrationEffect.createOneShot(10, 50)) .addVibrator(2, VibrationEffect.createOneShot(10, 100)) .combine(); - vibrate(service, effect, ALARM_ATTRS); - assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(), - service, TEST_TIMEOUT_MILLIS)); + vibrateAndWaitUntilFinished(service, effect, ALARM_ATTRS); verify(mNativeWrapperMock).prepareSynced(eq(new int[]{1, 2})); verify(mNativeWrapperMock, never()).triggerSynced(anyLong()); @@ -1057,9 +1039,7 @@ public class VibratorManagerServiceTest { .addVibrator(1, VibrationEffect.createOneShot(10, 50)) .addVibrator(2, VibrationEffect.createOneShot(10, 100)) .combine(); - vibrate(service, effect, ALARM_ATTRS); - assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(), - service, TEST_TIMEOUT_MILLIS)); + vibrateAndWaitUntilFinished(service, effect, ALARM_ATTRS); verify(mNativeWrapperMock).prepareSynced(eq(new int[]{1, 2})); verify(mNativeWrapperMock).triggerSynced(anyLong()); @@ -1096,28 +1076,21 @@ public class VibratorManagerServiceTest { VibrationEffect.Composition.PRIMITIVE_TICK); VibratorManagerService service = createSystemReadyService(); - vibrate(service, VibrationEffect.startComposition() + vibrateAndWaitUntilFinished(service, VibrationEffect.startComposition() .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f) .compose(), HAPTIC_FEEDBACK_ATTRS); - assertTrue(waitUntil(s -> fakeVibrator.getAllEffectSegments().size() == 1, - service, TEST_TIMEOUT_MILLIS)); - vibrate(service, CombinedVibration.startSequential() + vibrateAndWaitUntilFinished(service, CombinedVibration.startSequential() .addNext(1, VibrationEffect.createOneShot(100, 125)) .combine(), NOTIFICATION_ATTRS); - assertTrue(waitUntil(s -> fakeVibrator.getAllEffectSegments().size() == 2, - service, TEST_TIMEOUT_MILLIS)); - vibrate(service, VibrationEffect.startComposition() + vibrateAndWaitUntilFinished(service, VibrationEffect.startComposition() .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f) .compose(), ALARM_ATTRS); - assertTrue(waitUntil(s -> fakeVibrator.getAllEffectSegments().size() == 3, - service, TEST_TIMEOUT_MILLIS)); // Ring vibrations have intensity OFF and are not played. - vibrate(service, VibrationEffect.createOneShot(100, 125), RINGTONE_ATTRS); - assertFalse(waitUntil(s -> fakeVibrator.getAllEffectSegments().size() > 3, - service, /* timeout= */ 50)); + vibrateAndWaitUntilFinished(service, VibrationEffect.createOneShot(100, 125), + RINGTONE_ATTRS); // Only 3 effects played successfully. assertEquals(3, fakeVibrator.getAllEffectSegments().size()); @@ -1145,6 +1118,7 @@ public class VibratorManagerServiceTest { .combine(), HAPTIC_FEEDBACK_ATTRS); + // VibrationThread will start this vibration async, so wait until vibration is triggered. assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS)); mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE); @@ -1159,14 +1133,50 @@ public class VibratorManagerServiceTest { VibratorManagerService service = createSystemReadyService(); vibrate(service, VibrationEffect.createOneShot(1000, 100), HAPTIC_FEEDBACK_ATTRS); + + // VibrationThread will start this vibration async, so wait until vibration is triggered. assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS)); service.updateServiceState(); + // Vibration is not stopped nearly after updating service. assertFalse(waitUntil(s -> !s.isVibrating(1), service, 50)); } @Test + public void vibrate_prebakedAndComposedVibrationsWithFallbacks_playsFallbackOnlyForPredefined() + throws Exception { + mockVibrators(1); + mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS); + mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK); + mVibratorProviders.get(1).setSupportedPrimitives( + VibrationEffect.Composition.PRIMITIVE_CLICK); + + VibratorManagerService service = createSystemReadyService(); + vibrateAndWaitUntilFinished(service, + VibrationEffect.startComposition() + .addEffect(VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK)) + .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK) + .addEffect(VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK)) + .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK) + .compose(), + ALARM_ATTRS); + + List<VibrationEffectSegment> segments = mVibratorProviders.get(1).getAllEffectSegments(); + // At least one step segment played as fallback for unusupported vibration effect + assertTrue(segments.size() > 2); + // 0: Supported effect played + assertTrue(segments.get(0) instanceof PrebakedSegment); + // 1: No segment for unsupported primitive + // 2: One or more intermediate step segments as fallback for unsupported effect + for (int i = 1; i < segments.size() - 1; i++) { + assertTrue(segments.get(i) instanceof StepSegment); + } + // 3: Supported primitive played + assertTrue(segments.get(segments.size() - 1) instanceof PrimitiveSegment); + } + + @Test public void cancelVibrate_withoutUsageFilter_stopsVibrating() throws Exception { mockVibrators(1); VibratorManagerService service = createSystemReadyService(); @@ -1175,9 +1185,13 @@ public class VibratorManagerServiceTest { assertFalse(service.isVibrating(1)); vibrate(service, VibrationEffect.createOneShot(10 * TEST_TIMEOUT_MILLIS, 100), ALARM_ATTRS); + + // VibrationThread will start this vibration async, so wait until vibration is triggered. assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS)); service.cancelVibrate(VibrationAttributes.USAGE_FILTER_MATCH_ALL, service); + + // Alarm cancelled on filter match all. assertTrue(waitUntil(s -> !s.isVibrating(1), service, TEST_TIMEOUT_MILLIS)); } @@ -1187,6 +1201,8 @@ public class VibratorManagerServiceTest { VibratorManagerService service = createSystemReadyService(); vibrate(service, VibrationEffect.createOneShot(10 * TEST_TIMEOUT_MILLIS, 100), ALARM_ATTRS); + + // VibrationThread will start this vibration async, so wait until vibration is triggered. assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS)); // Vibration is not cancelled with a different usage. @@ -1216,6 +1232,8 @@ public class VibratorManagerServiceTest { VibratorManagerService service = createSystemReadyService(); vibrate(service, VibrationEffect.createOneShot(10 * TEST_TIMEOUT_MILLIS, 100), attrs); + + // VibrationThread will start this vibration async, so wait until vibration is triggered. assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS)); // Do not cancel UNKNOWN vibration when filter is being applied for other usages. @@ -1232,6 +1250,8 @@ public class VibratorManagerServiceTest { assertTrue(waitUntil(s -> !s.isVibrating(1), service, TEST_TIMEOUT_MILLIS)); vibrate(service, VibrationEffect.createOneShot(10 * TEST_TIMEOUT_MILLIS, 100), attrs); + + // VibrationThread will start this vibration async, so wait until vibration is triggered. assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS)); // Cancel UNKNOWN vibration when all vibrations are being cancelled. @@ -1312,6 +1332,8 @@ public class VibratorManagerServiceTest { VibrationEffect effect = VibrationEffect.createOneShot(10 * TEST_TIMEOUT_MILLIS, 100); vibrate(service, effect, HAPTIC_FEEDBACK_ATTRS); + + // VibrationThread will start this vibration async, so wait until vibration is triggered. assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS)); ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME, AUDIO_ATTRS, @@ -1793,7 +1815,8 @@ public class VibratorManagerServiceTest { private InputDevice createInputDeviceWithVibrator(int id) { return new InputDevice(id, 0, 0, "name", 0, 0, "description", false, 0, 0, - null, /* hasVibrator= */ true, false, false, false, false); + null, InputDeviceCountryCode.INVALID, /* hasVibrator= */ true, false, false, false, + false); } private static <T> void addLocalServiceMock(Class<T> clazz, T mock) { diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java index 8546763aebec..88e58eab58aa 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java @@ -281,7 +281,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { verify(mMockRunner).onAnimationCanceled(null /* taskIds */, null /* taskSnapshots */); // Simulate the app transition finishing - mController.mAppTransitionListener.onAppTransitionStartingLocked(false, false, 0, 0, 0); + mController.mAppTransitionListener.onAppTransitionStartingLocked(0, 0); verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, false); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java index d2cb7ba5d311..13da1543cfb8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -310,11 +310,11 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { } @Override - public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) { + public void startKeyguardExitAnimation(long startTime) { } @Override - public int applyKeyguardOcclusionChange(boolean keyguardOccludingStarted) { + public int applyKeyguardOcclusionChange(boolean notify) { return 0; } diff --git a/tests/Input/src/com/android/test/input/InputDeviceTest.java b/tests/Input/src/com/android/test/input/InputDeviceTest.java index 63500774816a..836d406d903c 100644 --- a/tests/Input/src/com/android/test/input/InputDeviceTest.java +++ b/tests/Input/src/com/android/test/input/InputDeviceTest.java @@ -17,8 +17,8 @@ package android.view; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import android.hardware.input.InputDeviceCountryCode; import android.os.Parcel; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -55,11 +55,12 @@ public class InputDeviceTest { assertEquals(device.isExternal(), outDevice.isExternal()); assertEquals(device.getSources(), outDevice.getSources()); assertEquals(device.getKeyboardType(), outDevice.getKeyboardType()); + assertEquals(device.getCountryCode(), outDevice.getCountryCode()); assertEquals(device.getMotionRanges().size(), outDevice.getMotionRanges().size()); KeyCharacterMap keyCharacterMap = device.getKeyCharacterMap(); KeyCharacterMap outKeyCharacterMap = outDevice.getKeyCharacterMap(); - assertTrue("keyCharacterMap not equal", keyCharacterMap.equals(outKeyCharacterMap)); + assertEquals("keyCharacterMap not equal", keyCharacterMap, outKeyCharacterMap); for (int j = 0; j < device.getMotionRanges().size(); j++) { assertMotionRangeEquals(device.getMotionRanges().get(j), @@ -70,10 +71,11 @@ public class InputDeviceTest { private void assertInputDeviceParcelUnparcel(KeyCharacterMap keyCharacterMap) { final InputDevice device = new InputDevice(DEVICE_ID, 0 /* generation */, 0 /* controllerNumber */, "name", - 0 /* vendorId */, 0 /* productId */, "descriptor", true /* isExternal */, - 0 /* sources */, 0 /* keyboardType */, keyCharacterMap, - false /* hasVibrator */, false /* hasMicrophone */, false /* hasButtonUnderpad */, - true /* hasSensor */, false /* hasBattery */); + 0 /* vendorId */, 0 /* productId */, "descriptor", true /* isExternal */, + 0 /* sources */, 0 /* keyboardType */, keyCharacterMap, + InputDeviceCountryCode.INTERNATIONAL, false /* hasVibrator */, + false /* hasMicrophone */, false /* hasButtonUnderpad */, + true /* hasSensor */, false /* hasBattery */); Parcel parcel = Parcel.obtain(); device.writeToParcel(parcel, 0); diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java index 44265511ee50..f1fc503c8556 100644 --- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java +++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java @@ -169,6 +169,12 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { assertTrue(getDevice().pushFile(apex, "/" + partition + "/apex/" + fileName)); } + private void installTestApex(String fileName, String... extraArgs) throws Exception { + CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild()); + final File apex = buildHelper.getTestFile(fileName); + getDevice().installPackage(apex, false, extraArgs); + } + private void pushTestVendorApexAllowList(String installerPackageName) throws Exception { if (!getDevice().isAdbRoot()) { getDevice().enableAdbRoot(); @@ -551,7 +557,7 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { pushTestApex(REBOOTLESS_V1, "vendor"); getDevice().reboot(); runPhase("testVendorApex_VerifyFactory"); - installPackage(REBOOTLESS_V2, "--staged"); + installTestApex(REBOOTLESS_V2, "--staged"); getDevice().reboot(); runPhase("testVendorApex_VerifyData"); } @@ -565,7 +571,7 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { pushTestApex(REBOOTLESS_V1, "vendor"); getDevice().reboot(); runPhase("testVendorApex_VerifyFactory"); - installPackage(REBOOTLESS_V2, "--force-non-staged"); + installTestApex(REBOOTLESS_V2, "--force-non-staged"); runPhase("testVendorApex_VerifyData"); } diff --git a/tests/testables/src/android/testing/TestableLooper.java b/tests/testables/src/android/testing/TestableLooper.java index ebe9b5706bf8..edd6dd3468ef 100644 --- a/tests/testables/src/android/testing/TestableLooper.java +++ b/tests/testables/src/android/testing/TestableLooper.java @@ -30,6 +30,7 @@ import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.lang.reflect.Field; import java.util.Map; /** @@ -45,6 +46,9 @@ public class TestableLooper { * catch crashes. */ public static final boolean HOLD_MAIN_THREAD = false; + private static final Field MESSAGE_QUEUE_MESSAGES_FIELD; + private static final Field MESSAGE_NEXT_FIELD; + private static final Field MESSAGE_WHEN_FIELD; private Looper mLooper; private MessageQueue mQueue; @@ -54,6 +58,19 @@ public class TestableLooper { private Runnable mEmptyMessage; private TestLooperManager mQueueWrapper; + static { + try { + MESSAGE_QUEUE_MESSAGES_FIELD = MessageQueue.class.getDeclaredField("mMessages"); + MESSAGE_QUEUE_MESSAGES_FIELD.setAccessible(true); + MESSAGE_NEXT_FIELD = Message.class.getDeclaredField("next"); + MESSAGE_NEXT_FIELD.setAccessible(true); + MESSAGE_WHEN_FIELD = Message.class.getDeclaredField("when"); + MESSAGE_WHEN_FIELD.setAccessible(true); + } catch (NoSuchFieldException e) { + throw new RuntimeException("Failed to initialize TestableLooper", e); + } + } + public TestableLooper(Looper l) throws Exception { this(acquireLooperManager(l), l); } @@ -119,6 +136,33 @@ public class TestableLooper { while (processQueuedMessages() != 0) ; } + public void moveTimeForward(long milliSeconds) { + try { + Message msg = getMessageLinkedList(); + while (msg != null) { + long updatedWhen = msg.getWhen() - milliSeconds; + if (updatedWhen < 0) { + updatedWhen = 0; + } + MESSAGE_WHEN_FIELD.set(msg, updatedWhen); + msg = (Message) MESSAGE_NEXT_FIELD.get(msg); + } + } catch (IllegalAccessException e) { + throw new RuntimeException("Access failed in TestableLooper: set - Message.when", e); + } + } + + private Message getMessageLinkedList() { + try { + MessageQueue queue = mLooper.getQueue(); + return (Message) MESSAGE_QUEUE_MESSAGES_FIELD.get(queue); + } catch (IllegalAccessException e) { + throw new RuntimeException( + "Access failed in TestableLooper: get - MessageQueue.mMessages", + e); + } + } + private int processQueuedMessages() { int count = 0; mEmptyMessage = () -> { }; diff --git a/tests/testables/tests/AndroidManifest.xml b/tests/testables/tests/AndroidManifest.xml index 1731f6be4bf2..2bfb04fdb765 100644 --- a/tests/testables/tests/AndroidManifest.xml +++ b/tests/testables/tests/AndroidManifest.xml @@ -21,7 +21,7 @@ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> <uses-permission android:name="android.permission.MANAGE_USERS" /> - <application android:debuggable="true" android:testOnly="true"> + <application android:debuggable="true"> <uses-library android:name="android.test.runner" /> </application> diff --git a/tests/testables/tests/AndroidTest.xml b/tests/testables/tests/AndroidTest.xml deleted file mode 100644 index de1165fca1a2..000000000000 --- a/tests/testables/tests/AndroidTest.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2022 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> -<configuration description="Runs Testable Tests."> - <option name="test-tag" value="TestablesTests" /> - <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> - <option name="cleanup-apks" value="true" /> - <option name="install-arg" value="-t" /> - <option name="test-file-name" value="TestablesTests.apk" /> - </target_preparer> - <test class="com.android.tradefed.testtype.AndroidJUnitTest"> - <option name="package" value="com.android.testables"/> - </test> -</configuration>
\ No newline at end of file diff --git a/tests/testables/tests/src/android/testing/TestableLooperTest.java b/tests/testables/tests/src/android/testing/TestableLooperTest.java index 25f6a48871d3..0f491b86626c 100644 --- a/tests/testables/tests/src/android/testing/TestableLooperTest.java +++ b/tests/testables/tests/src/android/testing/TestableLooperTest.java @@ -19,15 +19,19 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.InOrder; import android.os.Handler; import android.os.Looper; @@ -162,7 +166,7 @@ public class TestableLooperTest { @Test public void testCorrectLooperExecution() throws Exception { - boolean[] hasRun = new boolean[] { false }; + boolean[] hasRun = new boolean[]{false}; Runnable r = () -> { assertEquals("Should run on main looper", Looper.getMainLooper(), Looper.myLooper()); hasRun[0] = true; @@ -177,4 +181,63 @@ public class TestableLooperTest { testableLooper.destroy(); } } + + @Test + public void testDelayedDispatchNoTimeMove() { + Handler handler = spy(new Handler(mTestableLooper.getLooper())); + InOrder inOrder = inOrder(handler); + + final Message messageA = handler.obtainMessage(1); + final Message messageB = handler.obtainMessage(2); + + handler.sendMessageDelayed(messageA, 0); + handler.sendMessageDelayed(messageB, 0); + + mTestableLooper.processAllMessages(); + + inOrder.verify(handler).dispatchMessage(messageA); + inOrder.verify(handler).dispatchMessage(messageB); + } + + @Test + public void testDelayedMessageDoesntSend() { + Handler handler = spy(new Handler(mTestableLooper.getLooper())); + InOrder inOrder = inOrder(handler); + + final Message messageA = handler.obtainMessage(1); + final Message messageB = handler.obtainMessage(2); + final Message messageC = handler.obtainMessage(3); + + handler.sendMessageDelayed(messageA, 0); + handler.sendMessageDelayed(messageB, 0); + handler.sendMessageDelayed(messageC, 500); + + mTestableLooper.processAllMessages(); + + inOrder.verify(handler).dispatchMessage(messageA); + inOrder.verify(handler).dispatchMessage(messageB); + verify(handler, never()).dispatchMessage(messageC); + } + + @Test + public void testMessageSendsAfterDelay() { + Handler handler = spy(new Handler(mTestableLooper.getLooper())); + InOrder inOrder = inOrder(handler); + + final Message messageA = handler.obtainMessage(1); + final Message messageB = handler.obtainMessage(2); + final Message messageC = handler.obtainMessage(3); + + handler.sendMessageDelayed(messageA, 0); + handler.sendMessageDelayed(messageB, 0); + handler.sendMessageDelayed(messageC, 500); + + mTestableLooper.moveTimeForward(500); + mTestableLooper.processAllMessages(); + + inOrder.verify(handler).dispatchMessage(messageA); + inOrder.verify(handler).dispatchMessage(messageB); + inOrder.verify(handler).dispatchMessage(messageC); + } + } |