diff options
160 files changed, 4777 insertions, 3294 deletions
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java index 448ee6160ce0..cd86d6a4d6c7 100644 --- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java +++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java @@ -273,9 +273,7 @@ public class UserLifecycleTests { mRunner.resumeTiming(); Log.i(TAG, "Starting timer"); - runThenWaitForBroadcasts(testUser, () -> { - mAm.switchUser(testUser); - }, Intent.ACTION_USER_UNLOCKED); + switchUser(testUser); mRunner.pauseTiming(); Log.i(TAG, "Stopping timer"); diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java index 59cd82e971bf..3bbc5a369684 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java @@ -176,12 +176,13 @@ public final class BatteryController extends RestrictingController { Slog.d(TAG, "maybeReportNewChargingStateLocked: " + powerConnected + "/" + stablePower + "/" + batteryNotLow); } + final long nowElapsed = sElapsedRealtimeClock.millis(); + mFlexibilityController.setConstraintSatisfied( - JobStatus.CONSTRAINT_CHARGING, mService.isBatteryCharging()); - mFlexibilityController - .setConstraintSatisfied(JobStatus.CONSTRAINT_BATTERY_NOT_LOW, batteryNotLow); + JobStatus.CONSTRAINT_CHARGING, mService.isBatteryCharging(), nowElapsed); + mFlexibilityController.setConstraintSatisfied( + JobStatus.CONSTRAINT_BATTERY_NOT_LOW, batteryNotLow, nowElapsed); - final long nowElapsed = sElapsedRealtimeClock.millis(); for (int i = mTrackedTasks.size() - 1; i >= 0; i--) { final JobStatus ts = mTrackedTasks.valueAt(i); if (ts.hasChargingConstraint()) { diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java index 2e41dfd2888c..3ca1ad58955d 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java @@ -137,9 +137,9 @@ public final class FlexibilityController extends StateController { new PrefetchController.PrefetchChangedListener() { @Override public void onPrefetchCacheUpdated(ArraySet<JobStatus> jobs, int userId, - String pkgName, long prevEstimatedLaunchTime, long newEstimatedLaunchTime) { + String pkgName, long prevEstimatedLaunchTime, + long newEstimatedLaunchTime, long nowElapsed) { synchronized (mLock) { - final long nowElapsed = sElapsedRealtimeClock.millis(); final long prefetchThreshold = mPrefetchController.getLaunchTimeThresholdMs(); boolean jobWasInPrefetchWindow = prevEstimatedLaunchTime @@ -158,8 +158,8 @@ public final class FlexibilityController extends StateController { if (!js.hasFlexibilityConstraint()) { continue; } - mFlexibilityTracker.resetJobNumDroppedConstraints(js); - mFlexibilityAlarmQueue.scheduleDropNumConstraintsAlarm(js); + mFlexibilityTracker.resetJobNumDroppedConstraints(js, nowElapsed); + mFlexibilityAlarmQueue.scheduleDropNumConstraintsAlarm(js, nowElapsed); } } } @@ -191,7 +191,7 @@ public final class FlexibilityController extends StateController { js.setTrackingController(JobStatus.TRACKING_FLEXIBILITY); final long nowElapsed = sElapsedRealtimeClock.millis(); js.setFlexibilityConstraintSatisfied(nowElapsed, isFlexibilitySatisfiedLocked(js)); - mFlexibilityAlarmQueue.scheduleDropNumConstraintsAlarm(js); + mFlexibilityAlarmQueue.scheduleDropNumConstraintsAlarm(js, nowElapsed); } } @@ -239,7 +239,7 @@ public final class FlexibilityController extends StateController { * Changes flexibility constraint satisfaction for affected jobs. */ @VisibleForTesting - void setConstraintSatisfied(int constraint, boolean state) { + void setConstraintSatisfied(int constraint, boolean state, long nowElapsed) { synchronized (mLock) { final boolean old = (mSatisfiedFlexibleConstraints & constraint) != 0; if (old == state) { @@ -255,8 +255,6 @@ public final class FlexibilityController extends StateController { // The rest did not have a change in state and are still satisfied or unsatisfied. final int numConstraintsToUpdate = Math.max(curSatisfied, prevSatisfied); - final long nowElapsed = sElapsedRealtimeClock.millis(); - // In order to get the range of all potentially satisfied jobs, we start at the number // of satisfied system-wide constraints and iterate to the max number of potentially // satisfied constraints, determined by how many job-specific constraints exist. @@ -329,10 +327,9 @@ public final class FlexibilityController extends StateController { @VisibleForTesting @GuardedBy("mLock") - int getCurPercentOfLifecycleLocked(JobStatus js) { + int getCurPercentOfLifecycleLocked(JobStatus js, long nowElapsed) { final long earliest = getLifeCycleBeginningElapsedLocked(js); final long latest = getLifeCycleEndElapsedLocked(js, earliest); - final long nowElapsed = sElapsedRealtimeClock.millis(); if (latest == NO_LIFECYCLE_END || earliest >= nowElapsed) { return 0; } @@ -414,8 +411,8 @@ public final class FlexibilityController extends StateController { .getJobsByNumRequiredConstraints(j); for (int i = 0; i < jobs.size(); i++) { JobStatus js = jobs.valueAt(i); - mFlexibilityTracker.resetJobNumDroppedConstraints(js); - mFlexibilityAlarmQueue.scheduleDropNumConstraintsAlarm(js); + mFlexibilityTracker.resetJobNumDroppedConstraints(js, nowElapsed); + mFlexibilityAlarmQueue.scheduleDropNumConstraintsAlarm(js, nowElapsed); if (js.setFlexibilityConstraintSatisfied( nowElapsed, isFlexibilitySatisfiedLocked(js))) { changedJobs.add(js); @@ -479,8 +476,8 @@ public final class FlexibilityController extends StateController { mTrackedJobs.get(js.getNumRequiredFlexibleConstraints() - 1).remove(js); } - public void resetJobNumDroppedConstraints(JobStatus js) { - final int curPercent = getCurPercentOfLifecycleLocked(js); + public void resetJobNumDroppedConstraints(JobStatus js, long nowElapsed) { + final int curPercent = getCurPercentOfLifecycleLocked(js, nowElapsed); int toDrop = 0; final int jsMaxFlexibleConstraints = NUM_SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS + (js.getPreferUnmetered() ? 1 : 0); @@ -489,7 +486,8 @@ public final class FlexibilityController extends StateController { toDrop++; } } - adjustJobsRequiredConstraints(js, js.getNumDroppedFlexibleConstraints() - toDrop); + adjustJobsRequiredConstraints( + js, js.getNumDroppedFlexibleConstraints() - toDrop, nowElapsed); } /** Returns all tracked jobs. */ @@ -502,13 +500,12 @@ public final class FlexibilityController extends StateController { * Returns false if the job status's number of flexible constraints is now 0. * Jobs with 0 required flexible constraints are removed from the tracker. */ - public boolean adjustJobsRequiredConstraints(JobStatus js, int n) { + public boolean adjustJobsRequiredConstraints(JobStatus js, int n, long nowElapsed) { if (n == 0) { return false; } remove(js); js.adjustNumRequiredFlexibleConstraints(n); - final long nowElapsed = sElapsedRealtimeClock.millis(); js.setFlexibilityConstraintSatisfied(nowElapsed, isFlexibilitySatisfiedLocked(js)); if (js.getNumRequiredFlexibleConstraints() <= 0) { maybeStopTrackingJobLocked(js, null, false); @@ -553,7 +550,7 @@ public final class FlexibilityController extends StateController { return js.getSourceUserId() == userId; } - public void scheduleDropNumConstraintsAlarm(JobStatus js) { + public void scheduleDropNumConstraintsAlarm(JobStatus js, long nowElapsed) { long nextTimeElapsed; synchronized (mLock) { final long earliest = getLifeCycleBeginningElapsedLocked(js); @@ -567,7 +564,7 @@ public final class FlexibilityController extends StateController { if (latest - nextTimeElapsed < mDeadlineProximityLimitMs) { mFlexibilityTracker.adjustJobsRequiredConstraints( - js, -js.getNumRequiredFlexibleConstraints()); + js, -js.getNumRequiredFlexibleConstraints(), nowElapsed); return; } addAlarm(js, nextTimeElapsed); @@ -578,21 +575,21 @@ public final class FlexibilityController extends StateController { protected void processExpiredAlarms(@NonNull ArraySet<JobStatus> expired) { synchronized (mLock) { ArraySet<JobStatus> changedJobs = new ArraySet<>(); + final long nowElapsed = sElapsedRealtimeClock.millis(); for (int i = 0; i < expired.size(); i++) { JobStatus js = expired.valueAt(i); boolean wasFlexibilitySatisfied = js.isConstraintSatisfied(CONSTRAINT_FLEXIBLE); final long earliest = getLifeCycleBeginningElapsedLocked(js); final long latest = getLifeCycleEndElapsedLocked(js, earliest); - final long nowElapsed = sElapsedRealtimeClock.millis(); if (latest - nowElapsed < mDeadlineProximityLimitMs) { mFlexibilityTracker.adjustJobsRequiredConstraints(js, - -js.getNumRequiredFlexibleConstraints()); + -js.getNumRequiredFlexibleConstraints(), nowElapsed); } else { long nextTimeElapsed = getNextConstraintDropTimeElapsedLocked(js, earliest, latest); - if (mFlexibilityTracker.adjustJobsRequiredConstraints(js, -1) + if (mFlexibilityTracker.adjustJobsRequiredConstraints(js, -1, nowElapsed) && nextTimeElapsed != NO_LIFECYCLE_END) { mFlexibilityAlarmQueue.addAlarm(js, nextTimeElapsed); } diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java index d5750f8d7974..dd0621728724 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java @@ -95,9 +95,10 @@ public final class IdleController extends RestrictingController implements Idlen */ @Override public void reportNewIdleState(boolean isIdle) { - mFlexibilityController.setConstraintSatisfied(JobStatus.CONSTRAINT_IDLE, isIdle); synchronized (mLock) { final long nowElapsed = sElapsedRealtimeClock.millis(); + mFlexibilityController.setConstraintSatisfied( + JobStatus.CONSTRAINT_IDLE, isIdle, nowElapsed); for (int i = mTrackedTasks.size()-1; i >= 0; i--) { mTrackedTasks.valueAt(i).setIdleConstraintSatisfied(nowElapsed, isIdle); } diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java index 0945b7e796fd..e04cec30d26b 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java @@ -105,7 +105,7 @@ public class PrefetchController extends StateController { public interface PrefetchChangedListener { /** Callback to inform listeners when estimated launch times change. */ void onPrefetchCacheUpdated(ArraySet<JobStatus> jobs, int userId, String pkgName, - long prevEstimatedLaunchTime, long newEstimatedLaunchTime); + long prevEstimatedLaunchTime, long newEstimatedLaunchTime, long nowElapsed); } @SuppressWarnings("FieldCanBeLocal") @@ -308,8 +308,9 @@ public class PrefetchController extends StateController { final long nowElapsed = sElapsedRealtimeClock.millis(); updateThresholdAlarmLocked(userId, pkgName, now, nowElapsed); for (int i = 0; i < mPrefetchChangedListeners.size(); i++) { - mPrefetchChangedListeners.valueAt(i).onPrefetchCacheUpdated(jobs, - userId, pkgName, prevEstimatedLaunchTime, newEstimatedLaunchTime); + mPrefetchChangedListeners.valueAt(i).onPrefetchCacheUpdated( + jobs, userId, pkgName, prevEstimatedLaunchTime, + newEstimatedLaunchTime, nowElapsed); } if (maybeUpdateConstraintForPkgLocked(now, nowElapsed, userId, pkgName)) { mStateChangedListener.onControllerStateChanged(jobs); diff --git a/core/api/current.txt b/core/api/current.txt index 3efe2ef5baea..e0433399f374 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -51979,6 +51979,7 @@ package android.view.accessibility { method public boolean isTextEntryKey(); method public boolean isTextSelectable(); method public boolean isVisibleToUser(); + method public void makeQueryableFromAppProcess(@NonNull android.view.View); method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View); method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View, int); method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo obtain(); diff --git a/core/api/system-current.txt b/core/api/system-current.txt index be84032df9a4..a0cc4f0d6775 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -11479,6 +11479,7 @@ package android.service.notification { method public void onPanelRevealed(int); method public void onSuggestedReplySent(@NonNull String, @NonNull CharSequence, int); method public final void unsnoozeNotification(@NonNull String); + field public static final String ACTION_NOTIFICATION_ASSISTANT_DETAIL_SETTINGS = "android.service.notification.action.NOTIFICATION_ASSISTANT_DETAIL_SETTINGS"; field public static final String FEEDBACK_RATING = "feedback.rating"; field public static final String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService"; field public static final int SOURCE_FROM_APP = 0; // 0x0 diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 2a5916dfb6a8..d6b90a2792a9 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -1906,6 +1906,7 @@ public class AppOpsManager { OP_SCHEDULE_EXACT_ALARM, OP_MANAGE_MEDIA, OP_TURN_SCREEN_ON, + OP_GET_USAGE_STATS, }; static final AppOpInfo[] sAppOpInfos = new AppOpInfo[]{ diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java index 7092e43596ec..7247ef77afb4 100644 --- a/core/java/android/hardware/face/FaceManager.java +++ b/core/java/android/hardware/face/FaceManager.java @@ -29,6 +29,7 @@ import android.content.Context; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricFaceConstants; +import android.hardware.biometrics.BiometricStateListener; import android.hardware.biometrics.CryptoObject; import android.hardware.biometrics.IBiometricServiceLockoutResetCallback; import android.os.Binder; @@ -674,6 +675,45 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan } /** + * Forwards BiometricStateListener to FaceService. + * + * @param listener new BiometricStateListener being added + * @hide + */ + public void registerBiometricStateListener(@NonNull BiometricStateListener listener) { + try { + mService.registerBiometricStateListener(listener); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Adds a callback that gets called when the service registers all of the face + * authenticators (HALs). + * + * If the face authenticators are already registered when the callback is added, the + * callback is invoked immediately. + * + * The callback is automatically removed after it's invoked. + * + * @hide + */ + @RequiresPermission(USE_BIOMETRIC_INTERNAL) + public void addAuthenticatorsRegisteredCallback( + IFaceAuthenticatorsRegisteredCallback callback) { + if (mService != null) { + try { + mService.addAuthenticatorsRegisteredCallback(callback); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } else { + Slog.w(TAG, "addAuthenticatorsRegisteredCallback(): Service not connected!"); + } + } + + /** * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) diff --git a/core/java/android/hardware/face/IFaceAuthenticatorsRegisteredCallback.aidl b/core/java/android/hardware/face/IFaceAuthenticatorsRegisteredCallback.aidl new file mode 100644 index 000000000000..78f978d21ed7 --- /dev/null +++ b/core/java/android/hardware/face/IFaceAuthenticatorsRegisteredCallback.aidl @@ -0,0 +1,35 @@ +/* + * 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.hardware.face; + +import android.hardware.face.FaceSensorPropertiesInternal; +import java.util.List; + +/** + * Callback to notify FaceManager that FaceService has registered all of the + * face authenticators (HALs). + * See {@link android.hardware.face.IFaceService#registerAuthenticators}. + * + * @hide + */ +oneway interface IFaceAuthenticatorsRegisteredCallback { + /** + * Notifies FaceManager that all of the face authenticators have been registered. + * + * @param sensors A consolidated list of sensor properties for all of the authenticators. + */ + void onAllAuthenticatorsRegistered(in List<FaceSensorPropertiesInternal> sensors); +} diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl index 369248edd580..9b56f43a0f22 100644 --- a/core/java/android/hardware/face/IFaceService.aidl +++ b/core/java/android/hardware/face/IFaceService.aidl @@ -17,9 +17,11 @@ package android.hardware.face; import android.hardware.biometrics.IBiometricSensorReceiver; import android.hardware.biometrics.IBiometricServiceLockoutResetCallback; +import android.hardware.biometrics.IBiometricStateListener; import android.hardware.biometrics.IInvalidationCallback; import android.hardware.biometrics.ITestSession; import android.hardware.biometrics.ITestSessionCallback; +import android.hardware.face.IFaceAuthenticatorsRegisteredCallback; import android.hardware.face.IFaceServiceReceiver; import android.hardware.face.Face; import android.hardware.face.FaceSensorPropertiesInternal; @@ -163,4 +165,11 @@ interface IFaceService { // hidlSensors must be non-null and empty. See AuthService.java @EnforcePermission("USE_BIOMETRIC_INTERNAL") void registerAuthenticators(in List<FaceSensorPropertiesInternal> hidlSensors); + + // Adds a callback which gets called when the service registers all of the face + // authenticators. The callback is automatically removed after it's invoked. + void addAuthenticatorsRegisteredCallback(IFaceAuthenticatorsRegisteredCallback callback); + + // Registers BiometricStateListener. + void registerBiometricStateListener(IBiometricStateListener listener); } diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index cc7ed183ed64..1ba9a0471c88 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -202,8 +202,10 @@ interface IFingerprintService { void setSidefpsController(in ISidefpsController controller); // Registers BiometricStateListener. + @EnforcePermission("USE_BIOMETRIC_INTERNAL") void registerBiometricStateListener(IBiometricStateListener listener); // Sends a power button pressed event to all listeners. + @EnforcePermission("USE_BIOMETRIC_INTERNAL") oneway void onPowerPressed(); } diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 26600e256ca1..9d05cec06d01 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -2317,6 +2317,11 @@ 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(); @@ -7601,6 +7606,8 @@ 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/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java index 91042bfa3402..a38ef9676072 100644 --- a/core/java/android/service/notification/NotificationAssistantService.java +++ b/core/java/android/service/notification/NotificationAssistantService.java @@ -91,6 +91,21 @@ public abstract class NotificationAssistantService extends NotificationListenerS = "android.service.notification.NotificationAssistantService"; /** + * Activity Action: Show notification assistant detail setting page in NAS app. + * <p> + * In some cases, a matching Activity may not exist, so ensure you + * safeguard against this. + * <p> + * Input: Nothing. + * <p> + * Output: Nothing. + */ + @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_NOTIFICATION_ASSISTANT_DETAIL_SETTINGS = + "android.service.notification.action.NOTIFICATION_ASSISTANT_DETAIL_SETTINGS"; + + + /** * Data type: int, the feedback rating score provided by user. The score can be any integer * value depends on the experimental and feedback UX design. */ diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 9091b7955616..59bc061f54aa 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -173,6 +173,7 @@ import android.view.WindowInsets.Type; import android.view.WindowInsets.Type.InsetsType; import android.view.WindowManager.LayoutParams.SoftInputModeFlags; import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityInteractionClient; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener; import android.view.accessibility.AccessibilityManager.HighTextContrastChangeListener; @@ -5318,6 +5319,7 @@ public final class ViewRootImpl implements ViewParent, } mAccessibilityInteractionConnectionManager.ensureNoConnection(); + mAccessibilityInteractionConnectionManager.ensureNoDirectConnection(); removeSendWindowContentChangedCallback(); destroyHardwareRenderer(); @@ -9570,6 +9572,14 @@ public final class ViewRootImpl implements ViewParent, } } + /** + * Return the connection ID for the {@link AccessibilityInteractionController} of this instance. + * @see AccessibilityNodeInfo#makeQueryableFromAppProcess(View) + */ + public int getDirectAccessibilityConnectionId() { + return mAccessibilityInteractionConnectionManager.ensureDirectConnection(); + } + @Override public boolean showContextMenuForChild(View originalView) { return false; @@ -10445,6 +10455,8 @@ public final class ViewRootImpl implements ViewParent, */ final class AccessibilityInteractionConnectionManager implements AccessibilityStateChangeListener { + private int mDirectConnectionId = AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID; + @Override public void onAccessibilityStateChanged(boolean enabled) { if (enabled) { @@ -10488,6 +10500,21 @@ public final class ViewRootImpl implements ViewParent, mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow); } } + + public int ensureDirectConnection() { + if (mDirectConnectionId == AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID) { + mDirectConnectionId = AccessibilityInteractionClient.addDirectConnection( + new AccessibilityInteractionConnection(ViewRootImpl.this)); + } + return mDirectConnectionId; + } + + public void ensureNoDirectConnection() { + if (mDirectConnectionId != AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID) { + AccessibilityInteractionClient.removeConnection(mDirectConnectionId); + mDirectConnectionId = AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID; + } + } } final class HighContrastTextManager implements HighTextContrastChangeListener { diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java index 68532781f08b..227a8ef6fd60 100644 --- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java +++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java @@ -114,6 +114,10 @@ public final class AccessibilityInteractionClient private static final SparseArray<IAccessibilityServiceConnection> sConnectionCache = new SparseArray<>(); + // Used to generate connection ids for direct app-process connections. Start sufficiently far + // enough from the connection ids generated by AccessibilityManagerService. + private static int sDirectConnectionIdCounter = 1 << 30; + /** List of timestamps which indicate the latest time an a11y service receives a scroll event from a window, mapping from windowId -> timestamp. */ private static final SparseLongArray sScrollingWindows = new SparseLongArray(); @@ -232,6 +236,12 @@ public final class AccessibilityInteractionClient return; } synchronized (sConnectionCache) { + IAccessibilityServiceConnection existingConnection = getConnection(connectionId); + if (existingConnection instanceof DirectAccessibilityConnection) { + throw new IllegalArgumentException( + "Cannot add service connection with id " + connectionId + + " which conflicts with existing direct connection."); + } sConnectionCache.put(connectionId, connection); if (!initializeCache) { return; @@ -242,6 +252,33 @@ public final class AccessibilityInteractionClient } /** + * Adds a new {@link DirectAccessibilityConnection} using the provided + * {@link IAccessibilityInteractionConnection} to create a direct connection between + * this client and the {@link android.view.ViewRootImpl} for queries inside the app process. + * + * <p> + * See {@link DirectAccessibilityConnection} for supported methods. + * </p> + * + * @param connection The ViewRootImpl's {@link IAccessibilityInteractionConnection}. + */ + public static int addDirectConnection(IAccessibilityInteractionConnection connection) { + synchronized (sConnectionCache) { + int connectionId = sDirectConnectionIdCounter++; + if (getConnection(connectionId) != null) { + throw new IllegalArgumentException( + "Cannot add direct connection with existing id " + connectionId); + } + DirectAccessibilityConnection directAccessibilityConnection = + new DirectAccessibilityConnection(connection); + sConnectionCache.put(connectionId, directAccessibilityConnection); + // Do not use AccessibilityCache for this connection, since there is no corresponding + // AccessibilityService to handle cache invalidation events. + return connectionId; + } + } + + /** * Gets a cached associated with the connection id if available. * */ diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index 953f2615b539..5d527500ff7b 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -58,6 +58,7 @@ import android.view.SurfaceView; import android.view.TouchDelegate; import android.view.View; import android.view.ViewGroup; +import android.view.ViewRootImpl; import android.widget.TextView; import com.android.internal.R; @@ -82,7 +83,9 @@ import java.util.Objects; * </p> * <p> * Once an accessibility node info is delivered to an accessibility service it is - * made immutable and calling a state mutation method generates an error. + * made immutable and calling a state mutation method generates an error. See + * {@link #makeQueryableFromAppProcess(View)} if you would like to inspect the + * node tree from the app process for testing or debugging tools. * </p> * <p> * Please refer to {@link android.accessibilityservice.AccessibilityService} for @@ -1156,8 +1159,8 @@ public class AccessibilityNodeInfo implements Parcelable { * @param index The child index. * @return The child node. * - * @throws IllegalStateException If called outside of an AccessibilityService. - * + * @throws IllegalStateException If called outside of an {@link AccessibilityService} and before + * calling {@link #makeQueryableFromAppProcess(View)}. */ public AccessibilityNodeInfo getChild(int index) { return getChild(index, FLAG_PREFETCH_DESCENDANTS_HYBRID); @@ -1171,7 +1174,8 @@ public class AccessibilityNodeInfo implements Parcelable { * @param prefetchingStrategy the prefetching strategy. * @return The child node. * - * @throws IllegalStateException If called outside of an AccessibilityService. + * @throws IllegalStateException If called outside of an {@link AccessibilityService} and before + * calling {@link #makeQueryableFromAppProcess(View)}. * * @see AccessibilityNodeInfo#getParent(int) for a description of prefetching. */ @@ -1893,6 +1897,9 @@ public class AccessibilityNodeInfo implements Parcelable { * Gets the parent. * * @return The parent. + * + * @throws IllegalStateException If called outside of an {@link AccessibilityService} and before + * calling {@link #makeQueryableFromAppProcess(View)}. */ public AccessibilityNodeInfo getParent() { enforceSealed(); @@ -1920,7 +1927,8 @@ public class AccessibilityNodeInfo implements Parcelable { * @param prefetchingStrategy the prefetching strategy. * @return The parent. * - * @throws IllegalStateException If called outside of an AccessibilityService. + * @throws IllegalStateException If called outside of an {@link AccessibilityService} and before + * calling {@link #makeQueryableFromAppProcess(View)}. * * @see #FLAG_PREFETCH_ANCESTORS * @see #FLAG_PREFETCH_DESCENDANTS_BREADTH_FIRST @@ -3642,6 +3650,47 @@ public class AccessibilityNodeInfo implements Parcelable { } /** + * Connects this node to the View's root so that operations on this node can query the entire + * {@link AccessibilityNodeInfo} tree and perform accessibility actions on nodes. + * + * <p> + * This is intended for short-lived inspections from testing or debugging tools in the app + * process. After calling this method, all nodes linked to this node (children, ancestors, etc.) + * are also queryable. Operations on this node tree will only succeed as long as the associated + * view hierarchy remains attached to a window. + * </p> + * + * <p> + * Calling this method more than once on the same node is a no-op; if you wish to inspect a + * different view hierarchy then create a new node from any view in that hierarchy and call this + * method on that node. + * </p> + * + * <p> + * Testing or debugging tools should create this {@link AccessibilityNodeInfo} node using + * {@link View#createAccessibilityNodeInfo()} or {@link AccessibilityNodeProvider} and call this + * method, then navigate and interact with the node tree by calling methods on the node. + * </p> + * + * @param view The view that generated this node, or any view in the same view-root hierarchy. + * @throws IllegalStateException If called from an {@link AccessibilityService}, or if provided + * a {@link View} that is not attached to a window. + */ + public void makeQueryableFromAppProcess(@NonNull View view) { + enforceNotSealed(); + if (mConnectionId != UNDEFINED_CONNECTION_ID) { + return; + } + + ViewRootImpl viewRootImpl = view.getViewRootImpl(); + if (viewRootImpl == null) { + throw new IllegalStateException( + "Cannot link a node to a view that is not attached to a window."); + } + setConnectionId(viewRootImpl.getDirectAccessibilityConnectionId()); + } + + /** * Sets if this instance is sealed. * * @param sealed Whether is sealed. @@ -3665,15 +3714,21 @@ public class AccessibilityNodeInfo implements Parcelable { return mSealed; } + private static boolean usingDirectConnection(int connectionId) { + return AccessibilityInteractionClient.getConnection( + connectionId) instanceof DirectAccessibilityConnection; + } + /** - * Enforces that this instance is sealed. + * Enforces that this instance is sealed, unless using a {@link DirectAccessibilityConnection} + * which allows queries while the node is not sealed. * * @throws IllegalStateException If this instance is not sealed. * * @hide */ protected void enforceSealed() { - if (!isSealed()) { + if (!usingDirectConnection(mConnectionId) && !isSealed()) { throw new IllegalStateException("Cannot perform this " + "action on a not sealed instance."); } @@ -4499,7 +4554,8 @@ public class AccessibilityNodeInfo implements Parcelable { private static boolean canPerformRequestOverConnection(int connectionId, int windowId, long accessibilityNodeId) { - return ((windowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) + final boolean hasWindowId = windowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; + return ((usingDirectConnection(connectionId) || hasWindowId) && (getAccessibilityViewId(accessibilityNodeId) != UNDEFINED_ITEM_ID) && (connectionId != UNDEFINED_CONNECTION_ID)); } diff --git a/core/java/android/view/accessibility/DirectAccessibilityConnection.java b/core/java/android/view/accessibility/DirectAccessibilityConnection.java new file mode 100644 index 000000000000..71746ee5dbab --- /dev/null +++ b/core/java/android/view/accessibility/DirectAccessibilityConnection.java @@ -0,0 +1,136 @@ +/* + * 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.view.accessibility; + +import android.accessibilityservice.IAccessibilityServiceConnection; +import android.graphics.Matrix; +import android.graphics.Region; +import android.os.Bundle; +import android.os.Process; +import android.os.RemoteException; +import android.view.MagnificationSpec; + +/** + * Minimal {@link IAccessibilityServiceConnection} implementation that interacts + * with the {@link android.view.AccessibilityInteractionController} of a + * {@link android.view.ViewRootImpl}. + * + * <p> + * Uses {@link android.view.ViewRootImpl}'s {@link IAccessibilityServiceConnection} that wraps + * {@link android.view.AccessibilityInteractionController} within the app process, so that no + * interprocess communication is performed. + * </p> + * + * <p> + * Only the following methods are supported: + * <li>{@link #findAccessibilityNodeInfoByAccessibilityId}</li> + * <li>{@link #findAccessibilityNodeInfosByText}</li> + * <li>{@link #findAccessibilityNodeInfosByViewId}</li> + * <li>{@link #findFocus}</li> + * <li>{@link #focusSearch}</li> + * <li>{@link #performAccessibilityAction}</li> + * </p> + * + * <p> + * Other methods are no-ops and return default values. + * </p> + */ +class DirectAccessibilityConnection extends IAccessibilityServiceConnection.Default { + private final IAccessibilityInteractionConnection mAccessibilityInteractionConnection; + + // 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; + private static final MagnificationSpec MAGNIFICATION_SPEC = new MagnificationSpec(); + private static final int PID = Process.myPid(); + private static final Region INTERACTIVE_REGION = null; + private static final float[] TRANSFORM_MATRIX = new float[9]; + + static { + Matrix.IDENTITY_MATRIX.getValues(TRANSFORM_MATRIX); + } + + DirectAccessibilityConnection( + IAccessibilityInteractionConnection accessibilityInteractionConnection) { + mAccessibilityInteractionConnection = accessibilityInteractionConnection; + } + + @Override + public String[] findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId, + long accessibilityNodeId, int interactionId, + IAccessibilityInteractionConnectionCallback callback, int flags, long threadId, + Bundle arguments) throws RemoteException { + mAccessibilityInteractionConnection.findAccessibilityNodeInfoByAccessibilityId( + accessibilityNodeId, INTERACTIVE_REGION, interactionId, callback, FETCH_FLAGS, PID, + threadId, MAGNIFICATION_SPEC, TRANSFORM_MATRIX, arguments); + return new String[0]; + } + + @Override + public String[] findAccessibilityNodeInfosByText(int accessibilityWindowId, + long accessibilityNodeId, String text, int interactionId, + IAccessibilityInteractionConnectionCallback callback, long threadId) + throws RemoteException { + mAccessibilityInteractionConnection.findAccessibilityNodeInfosByText(accessibilityNodeId, + text, INTERACTIVE_REGION, interactionId, callback, FETCH_FLAGS, PID, threadId, + MAGNIFICATION_SPEC, TRANSFORM_MATRIX); + return new String[0]; + } + + @Override + public String[] findAccessibilityNodeInfosByViewId(int accessibilityWindowId, + long accessibilityNodeId, String viewId, int interactionId, + IAccessibilityInteractionConnectionCallback callback, long threadId) + throws RemoteException { + mAccessibilityInteractionConnection.findAccessibilityNodeInfosByViewId(accessibilityNodeId, + viewId, INTERACTIVE_REGION, interactionId, callback, FETCH_FLAGS, PID, threadId, + MAGNIFICATION_SPEC, TRANSFORM_MATRIX); + return new String[0]; + } + + @Override + public String[] findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType, + int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId) + throws RemoteException { + mAccessibilityInteractionConnection.findFocus(accessibilityNodeId, focusType, + INTERACTIVE_REGION, interactionId, callback, FETCH_FLAGS, PID, threadId, + MAGNIFICATION_SPEC, TRANSFORM_MATRIX); + return new String[0]; + } + + @Override + public String[] focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction, + int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId) + throws RemoteException { + mAccessibilityInteractionConnection.focusSearch(accessibilityNodeId, direction, + INTERACTIVE_REGION, interactionId, callback, FETCH_FLAGS, PID, threadId, + MAGNIFICATION_SPEC, TRANSFORM_MATRIX); + return new String[0]; + } + + @Override + public boolean performAccessibilityAction(int accessibilityWindowId, long accessibilityNodeId, + int action, Bundle arguments, int interactionId, + IAccessibilityInteractionConnectionCallback callback, long threadId) + throws RemoteException { + mAccessibilityInteractionConnection.performAccessibilityAction(accessibilityNodeId, action, + arguments, interactionId, callback, FETCH_FLAGS, PID, threadId); + return true; + } +} diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java index 6909965edcd8..962870e733f7 100644 --- a/core/java/com/android/internal/os/BatteryStatsHistory.java +++ b/core/java/com/android/internal/os/BatteryStatsHistory.java @@ -17,35 +17,25 @@ package com.android.internal.os; import android.annotation.Nullable; -import android.os.BatteryManager; -import android.os.BatteryStats.HistoryItem; -import android.os.BatteryStats.HistoryStepDetails; -import android.os.BatteryStats.HistoryTag; +import android.os.BatteryStats; 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.concurrent.locks.ReentrantLock; +import java.util.function.Supplier; /** * BatteryStatsHistory encapsulates battery history files. @@ -66,62 +56,57 @@ import java.util.concurrent.locks.ReentrantLock; * 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 - private static final int VERSION = 208; + public static final int VERSION = 208; - private static final String HISTORY_DIR = "battery-history"; - private static final String FILE_SUFFIX = ".bin"; + public static final String HISTORY_DIR = "battery-history"; + public 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. - 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. + 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. // Flag in delta int: a new battery level int follows. - static final int DELTA_BATTERY_LEVEL_FLAG = 0x00080000; + public static final int DELTA_BATTERY_LEVEL_FLAG = 0x00080000; // Flag in delta int: a new full state and battery status int follows. - static final int DELTA_STATE_FLAG = 0x00100000; + public static final int DELTA_STATE_FLAG = 0x00100000; // Flag in delta int: a new full state2 int follows. - static final int DELTA_STATE2_FLAG = 0x00200000; + public static final int DELTA_STATE2_FLAG = 0x00200000; // Flag in delta int: contains a wakelock or wakeReason tag. - static final int DELTA_WAKELOCK_FLAG = 0x00400000; + public static final int DELTA_WAKELOCK_FLAG = 0x00400000; // Flag in delta int: contains an event description. - static final int DELTA_EVENT_FLAG = 0x00800000; + public static final int DELTA_EVENT_FLAG = 0x00800000; // Flag in delta int: contains the battery charge count in uAh. - static final int DELTA_BATTERY_CHARGE_FLAG = 0x01000000; + public static final int DELTA_BATTERY_CHARGE_FLAG = 0x01000000; // These upper bits are the frequently changing state bits. - static final int DELTA_STATE_MASK = 0xfe000000; + public 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. - 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; + 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; // We use the low bit of the battery state int to indicate that we have full details // from a battery level change. - static final int BATTERY_DELTA_LEVEL_FLAG = 0x00000001; + public 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 - static final int TAG_FIRST_OCCURRENCE_FLAG = 0x8000; + public 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. */ @@ -159,77 +144,19 @@ 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 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 + * @param historyBuffer The in-memory history buffer. + * @param systemDir typically /data/system + * @param maxHistoryFiles the largest number of history buffer files to keep */ - 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, - int maxHistoryFiles, int maxHistoryBufferSize, - HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) { + Supplier<Integer> maxHistoryFiles) { mHistoryBuffer = historyBuffer; - mSystemDir = systemDir; + mHistoryDir = new File(systemDir, HISTORY_DIR); 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()); @@ -265,81 +192,19 @@ 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 a checkin file. + * such as Settings app or checkin file. + * @param historyBuffer the history buffer */ - private BatteryStatsHistory(Parcel historyBuffer, - HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) { - mHistoryBuffer = historyBuffer; - mClock = clock; - mSystemDir = null; + public BatteryStatsHistory(Parcel historyBuffer) { 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; - } - - /** - * 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); + mHistoryBuffer = historyBuffer; + mMaxHistoryFiles = null; } - /** - * Returns true if this instance only supports reading history. - */ - public boolean isReadOnly() { - return mActiveFile == null; + public File getHistoryDirectory() { + return mHistoryDir; } /** @@ -356,13 +221,12 @@ 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)); } /** @@ -370,7 +234,7 @@ public class BatteryStatsHistory { * create next history file. */ public void startNextFile() { - if (mMaxHistoryFiles == 0) { + if (mMaxHistoryFiles == null) { Slog.wtf(TAG, "mMaxHistoryFiles should not be zero when writing history"); return; } @@ -400,7 +264,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) { + while (mFileNumbers.size() > mMaxHistoryFiles.get()) { int oldest = mFileNumbers.get(0); getFile(oldest).delete(); mFileNumbers.remove(0); @@ -408,43 +272,36 @@ public class BatteryStatsHistory { } /** - * Clear history buffer and delete all existing history files. Active history file start from - * number 0 again. + * Delete all existing history files. Active history file start from number 0 again. */ - public void reset() { - if (DEBUG) Slog.i(TAG, "********** CLEARING HISTORY!"); + public void resetAllFiles() { 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 BatteryStatsHistoryIterator iterate() { + public boolean startIteratingHistory() { mRecordCount = 0; mCurrentFileIndex = 0; mCurrentParcel = null; mCurrentParcelEnd = 0; mParcelIndex = 0; - mBatteryStatsHistoryIterator = new BatteryStatsHistoryIterator(this); - return mBatteryStatsHistoryIterator; + return true; } /** * Finish iterating history files and history buffer. */ - void finishIteratingHistory() { + public 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); } @@ -454,12 +311,11 @@ 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(HistoryItem out) { + public Parcel getNextParcel(BatteryStats.HistoryItem out) { if (mRecordCount == 0) { // reset out if it is the first record. out.clear(); @@ -467,7 +323,8 @@ 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; @@ -532,8 +389,7 @@ 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. */ @@ -546,8 +402,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); @@ -557,7 +413,6 @@ 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. */ @@ -573,68 +428,18 @@ 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) { @@ -645,13 +450,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); @@ -675,55 +480,17 @@ public class BatteryStatsHistory { Parcel historyBuffer = Parcel.obtain(); historyBuffer.unmarshall(historyBlob, 0, historyBlob.length); - BatteryStatsHistory history = new BatteryStatsHistory(historyBuffer, null, - Clock.SYSTEM_CLOCK); + BatteryStatsHistory history = new BatteryStatsHistory(historyBuffer); 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 */); } @@ -731,7 +498,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; @@ -754,12 +521,10 @@ public class BatteryStatsHistory { return stats.getAvailableBytes() > MIN_FREE_SPACE; } - @VisibleForTesting public List<Integer> getFilesNumbers() { return mFileNumbers; } - @VisibleForTesting public AtomicFile getActiveFile() { return mActiveFile; } @@ -769,972 +534,15 @@ 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 1bf878cb9119..de8b414c4b78 100644 --- a/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java +++ b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java @@ -36,6 +36,7 @@ public class BatteryStatsHistoryIterator { public BatteryStatsHistoryIterator(@NonNull BatteryStatsHistory history) { mBatteryStatsHistory = history; + mBatteryStatsHistory.startIteratingHistory(); } /** @@ -230,11 +231,4 @@ 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/opengl/util.cpp b/core/jni/android/opengl/util.cpp index d8522658d747..17cfbfc63f65 100644 --- a/core/jni/android/opengl/util.cpp +++ b/core/jni/android/opengl/util.cpp @@ -720,19 +720,22 @@ static jint util_texImage2D(JNIEnv *env, jclass clazz, jint target, jint level, jint internalformat, jobject bitmapObj, jint type, jint border) { graphics::Bitmap bitmap(env, bitmapObj); - AndroidBitmapInfo bitmapInfo = bitmap.getInfo(); + if (bitmap.isValid() && bitmap.getPixels() != nullptr) { + AndroidBitmapInfo bitmapInfo = bitmap.getInfo(); - if (internalformat < 0) { - internalformat = getInternalFormat(bitmapInfo.format); - } - if (type < 0) { - type = getType(bitmapInfo.format); - } + if (internalformat < 0) { + internalformat = getInternalFormat(bitmapInfo.format); + } + if (type < 0) { + type = getType(bitmapInfo.format); + } - if (checkInternalFormat(bitmapInfo.format, internalformat, type)) { - glTexImage2D(target, level, internalformat, bitmapInfo.width, bitmapInfo.height, border, - getPixelFormatFromInternalFormat(internalformat), type, bitmap.getPixels()); - return 0; + if (checkInternalFormat(bitmapInfo.format, internalformat, type)) { + glTexImage2D(target, level, internalformat, bitmapInfo.width, bitmapInfo.height, border, + getPixelFormatFromInternalFormat(internalformat), type, + bitmap.getPixels()); + return 0; + } } return -1; } @@ -741,19 +744,21 @@ static jint util_texSubImage2D(JNIEnv *env, jclass clazz, jint target, jint leve jint xoffset, jint yoffset, jobject bitmapObj, jint format, jint type) { graphics::Bitmap bitmap(env, bitmapObj); - AndroidBitmapInfo bitmapInfo = bitmap.getInfo(); - - int internalFormat = getInternalFormat(bitmapInfo.format); - if (format < 0) { - format = getPixelFormatFromInternalFormat(internalFormat); - if (format == GL_PALETTE8_RGBA8_OES) - return -1; // glCompressedTexSubImage2D() not supported - } + if (bitmap.isValid() && bitmap.getPixels() != nullptr) { + AndroidBitmapInfo bitmapInfo = bitmap.getInfo(); + + int internalFormat = getInternalFormat(bitmapInfo.format); + if (format < 0) { + format = getPixelFormatFromInternalFormat(internalFormat); + if (format == GL_PALETTE8_RGBA8_OES) + return -1; // glCompressedTexSubImage2D() not supported + } - if (checkInternalFormat(bitmapInfo.format, internalFormat, type)) { - glTexSubImage2D(target, level, xoffset, yoffset, bitmapInfo.width, bitmapInfo.height, - format, type, bitmap.getPixels()); - return 0; + if (checkInternalFormat(bitmapInfo.format, internalFormat, type)) { + glTexSubImage2D(target, level, xoffset, yoffset, bitmapInfo.width, bitmapInfo.height, + format, type, bitmap.getPixels()); + return 0; + } } return -1; } diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml b/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml index 8533a5994d33..b0dab90b6add 100644 --- a/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml +++ b/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml @@ -16,92 +16,98 @@ --> <!-- Layout for TvPipMenuView --> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/tv_pip_menu" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:gravity="center|top"> + android:id="@+id/tv_pip_menu" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="center|top"> <!-- Matches the PiP app content --> - <View + <FrameLayout android:id="@+id/tv_pip" android:layout_width="0dp" android:layout_height="0dp" - android:alpha="0" - android:background="@color/tv_pip_menu_background" android:layout_marginTop="@dimen/pip_menu_outer_space" android:layout_marginStart="@dimen/pip_menu_outer_space" - android:layout_marginEnd="@dimen/pip_menu_outer_space"/> - - <ScrollView - android:id="@+id/tv_pip_menu_scroll" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_alignTop="@+id/tv_pip" - android:layout_alignStart="@+id/tv_pip" - android:layout_alignEnd="@+id/tv_pip" - android:layout_alignBottom="@+id/tv_pip" - android:scrollbars="none" - android:visibility="gone"/> - - <HorizontalScrollView - android:id="@+id/tv_pip_menu_horizontal_scroll" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_alignTop="@+id/tv_pip" - android:layout_alignStart="@+id/tv_pip" - android:layout_alignEnd="@+id/tv_pip" - android:layout_alignBottom="@+id/tv_pip" - android:scrollbars="none"> - - <LinearLayout - android:id="@+id/tv_pip_menu_action_buttons" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:orientation="horizontal" - android:alpha="0"> + android:layout_marginEnd="@dimen/pip_menu_outer_space"> - <Space - android:layout_width="@dimen/pip_menu_button_wrapper_margin" - android:layout_height="@dimen/pip_menu_button_wrapper_margin"/> - - <com.android.wm.shell.common.TvWindowMenuActionButton - android:id="@+id/tv_pip_menu_fullscreen_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:src="@drawable/pip_ic_fullscreen_white" - android:text="@string/pip_fullscreen" /> + <View + android:id="@+id/tv_pip_menu_background" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@color/tv_pip_menu_background" + android:alpha="0"/> - <com.android.wm.shell.common.TvWindowMenuActionButton - android:id="@+id/tv_pip_menu_close_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:src="@drawable/pip_ic_close_white" - android:text="@string/pip_close" /> + <View + android:id="@+id/tv_pip_menu_dim_layer" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@color/tv_pip_menu_dim_layer" + android:alpha="0"/> - <!-- More TvPipMenuActionButtons may be added here at runtime. --> + <ScrollView + android:id="@+id/tv_pip_menu_scroll" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:scrollbars="none" + android:visibility="gone"/> - <com.android.wm.shell.common.TvWindowMenuActionButton - android:id="@+id/tv_pip_menu_move_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:src="@drawable/pip_ic_move_white" - android:text="@string/pip_move" /> + <HorizontalScrollView + android:id="@+id/tv_pip_menu_horizontal_scroll" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:scrollbars="none"> - <com.android.wm.shell.common.TvWindowMenuActionButton - android:id="@+id/tv_pip_menu_expand_button" + <LinearLayout + android:id="@+id/tv_pip_menu_action_buttons" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:src="@drawable/pip_ic_collapse" - android:visibility="gone" - android:text="@string/pip_collapse" /> - - <Space - android:layout_width="@dimen/pip_menu_button_wrapper_margin" - android:layout_height="@dimen/pip_menu_button_wrapper_margin"/> - - </LinearLayout> - </HorizontalScrollView> + android:orientation="horizontal" + android:alpha="0"> + + <Space + android:layout_width="@dimen/pip_menu_button_wrapper_margin" + android:layout_height="@dimen/pip_menu_button_wrapper_margin"/> + + <com.android.wm.shell.pip.tv.TvPipMenuActionButton + android:id="@+id/tv_pip_menu_fullscreen_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/pip_ic_fullscreen_white" + android:text="@string/pip_fullscreen" /> + + <com.android.wm.shell.pip.tv.TvPipMenuActionButton + android:id="@+id/tv_pip_menu_close_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/pip_ic_close_white" + android:text="@string/pip_close" /> + + <!-- More TvPipMenuActionButtons may be added here at runtime. --> + + <com.android.wm.shell.pip.tv.TvPipMenuActionButton + android:id="@+id/tv_pip_menu_move_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/pip_ic_move_white" + android:text="@string/pip_move" /> + + <com.android.wm.shell.pip.tv.TvPipMenuActionButton + android:id="@+id/tv_pip_menu_expand_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/pip_ic_collapse" + android:visibility="gone" + android:text="@string/pip_collapse" /> + + <Space + android:layout_width="@dimen/pip_menu_button_wrapper_margin" + android:layout_height="@dimen/pip_menu_button_wrapper_margin"/> + + </LinearLayout> + </HorizontalScrollView> + </FrameLayout> + <!-- Frame around the content, just overlapping the corners to make them round --> <View android:id="@+id/tv_pip_border" android:layout_width="0dp" @@ -111,6 +117,7 @@ android:layout_marginEnd="@dimen/pip_menu_outer_space_frame" android:background="@drawable/tv_pip_menu_border"/> + <!-- Temporarily extending the background to show an edu text hint for opening the menu --> <FrameLayout android:id="@+id/tv_pip_menu_edu_text_container" android:layout_width="match_parent" @@ -138,6 +145,7 @@ android:textAppearance="@style/TvPipEduText"/> </FrameLayout> + <!-- Frame around the PiP content + edu text hint - used to highlight open menu --> <View android:id="@+id/tv_pip_menu_frame" android:layout_width="match_parent" @@ -145,7 +153,8 @@ android:layout_margin="@dimen/pip_menu_outer_space_frame" android:background="@drawable/tv_pip_menu_border"/> - <com.android.wm.shell.common.TvWindowMenuActionButton + <!-- Move menu --> + <com.android.wm.shell.pip.tv.TvPipMenuActionButton android:id="@+id/tv_pip_menu_done_button" android:layout_width="wrap_content" android:layout_height="wrap_content" diff --git a/libs/WindowManager/Shell/res/values/colors_tv.xml b/libs/WindowManager/Shell/res/values/colors_tv.xml index 3e71c1010278..e6933ca3fce6 100644 --- a/libs/WindowManager/Shell/res/values/colors_tv.xml +++ b/libs/WindowManager/Shell/res/values/colors_tv.xml @@ -25,6 +25,7 @@ <color name="tv_window_menu_icon_bg_unfocused">#990E0E0F</color> <color name="tv_pip_menu_focus_border">#E8EAED</color> + <color name="tv_pip_menu_dim_layer">#990E0E0F</color> <color name="tv_pip_menu_background">#1E232C</color> <color name="tv_pip_edu_text">#99D2E3FC</color> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java index 4d7c8465bcc2..97e017a65b04 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java @@ -97,6 +97,9 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener { private final ImageView mArrowLeft; private final TvWindowMenuActionButton mA11yDoneButton; + private final View mPipBackground; + private final View mDimLayer; + private final ScrollView mScrollView; private final HorizontalScrollView mHorizontalScrollView; private View mFocusedButton; @@ -148,6 +151,9 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener { mExpandButton = findViewById(R.id.tv_pip_menu_expand_button); mExpandButton.setOnClickListener(this); + mPipBackground = findViewById(R.id.tv_pip_menu_background); + mDimLayer = findViewById(R.id.tv_pip_menu_dim_layer); + mScrollView = findViewById(R.id.tv_pip_menu_scroll); mHorizontalScrollView = findViewById(R.id.tv_pip_menu_horizontal_scroll); @@ -231,7 +237,7 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener { mCurrentPipBounds.width() / (float) mCurrentPipBounds.height(), finishBounds.width() / (float) finishBounds.height()); if (ratioChanged) { - mPipView.animate() + mPipBackground.animate() .alpha(1f) .setInterpolator(TvPipInterpolators.EXIT) .setDuration(mResizeAnimationDuration / 2) @@ -272,7 +278,7 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener { "%s: onPipTransitionFinished()", TAG); // Fade in content by fading out view on top. - mPipView.animate() + mPipBackground.animate() .alpha(0f) .setDuration(mResizeAnimationDuration / 2) .setInterpolator(TvPipInterpolators.ENTER) @@ -770,6 +776,7 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener { refocusPreviousButton(); } animateAlphaTo(show ? 1 : 0, mActionButtonsContainer); + animateAlphaTo(show ? 1 : 0, mDimLayer); } private void setFrameHighlighted(boolean highlighted) { diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt index 0a54b8c016fb..a8154e818a04 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt @@ -32,7 +32,6 @@ import com.android.server.wm.flicker.statusBarLayerPositionAtStartAndEnd import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible import com.android.server.wm.flicker.taskBarLayerIsVisibleAtStartAndEnd import com.android.server.wm.flicker.taskBarWindowIsAlwaysVisible -import com.android.server.wm.traces.common.ComponentMatcher import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper import org.junit.Assume import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt index 8b717a0cb75e..06361f9ca4ab 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt @@ -17,10 +17,10 @@ @file:JvmName("CommonConstants") package com.android.wm.shell.flicker -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher const val SYSTEM_UI_PACKAGE_NAME = "com.android.systemui" -val APP_PAIR_SPLIT_DIVIDER_COMPONENT = ComponentMatcher("", "AppPairSplitDivider#") -val DOCKED_STACK_DIVIDER_COMPONENT = ComponentMatcher("", "DockedStackDivider#") -val SPLIT_SCREEN_DIVIDER_COMPONENT = ComponentMatcher("", "StageCoordinatorSplitDivider#") -val SPLIT_DECOR_MANAGER = ComponentMatcher("", "SplitDecorManager#") +val APP_PAIR_SPLIT_DIVIDER_COMPONENT = ComponentNameMatcher("", "AppPairSplitDivider#") +val DOCKED_STACK_DIVIDER_COMPONENT = ComponentNameMatcher("", "DockedStackDivider#") +val SPLIT_SCREEN_DIVIDER_COMPONENT = ComponentNameMatcher("", "StageCoordinatorSplitDivider#") +val SPLIT_DECOR_MANAGER = ComponentNameMatcher("", "SplitDecorManager#") diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt index ffbac39c6078..826cc2ef16d6 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt @@ -17,10 +17,10 @@ package com.android.wm.shell.flicker.helpers import android.app.Instrumentation -import com.android.server.wm.traces.common.IComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher class AppPairsHelper( instrumentation: Instrumentation, activityLabel: String, - component: IComponentMatcher + component: ComponentNameMatcher ) : BaseAppHelper(instrumentation, activityLabel, component) diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt index c4379e9a27cc..01ba9907c24c 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt @@ -26,13 +26,13 @@ import androidx.test.uiautomator.UiObject2 import androidx.test.uiautomator.Until import com.android.compatibility.common.util.SystemUtil import com.android.server.wm.flicker.helpers.StandardAppHelper -import com.android.server.wm.traces.common.IComponentMatcher +import com.android.server.wm.traces.common.IComponentNameMatcher import java.io.IOException abstract class BaseAppHelper( instrumentation: Instrumentation, launcherName: String, - component: IComponentMatcher + component: IComponentNameMatcher ) : StandardAppHelper( instrumentation, launcherName, @@ -46,9 +46,6 @@ abstract class BaseAppHelper( hasSystemFeature(FEATURE_LEANBACK) || hasSystemFeature(FEATURE_LEANBACK_ONLY) } - val defaultWindowName: String - get() = toWindowName() - val ui: UiObject2? get() = uiDevice.findObject(appSelector) diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/MultiWindowHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/MultiWindowHelper.kt index 92b1d216f5ab..245a82f938b3 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/MultiWindowHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/MultiWindowHelper.kt @@ -19,12 +19,12 @@ package com.android.wm.shell.flicker.helpers import android.app.Instrumentation import android.content.Context import android.provider.Settings -import com.android.server.wm.traces.common.IComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher class MultiWindowHelper( instrumentation: Instrumentation, activityLabel: String, - componentsInfo: IComponentMatcher + componentsInfo: ComponentNameMatcher ) : BaseAppHelper(instrumentation, activityLabel, componentsInfo) { companion object { diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt index a1226e682e05..240e8711d43e 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt @@ -28,6 +28,7 @@ import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.Until import com.android.launcher3.tapl.LauncherInstrumentation import com.android.server.wm.traces.common.IComponentMatcher +import com.android.server.wm.traces.common.IComponentNameMatcher import com.android.server.wm.traces.parser.toFlickerComponent import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper import com.android.wm.shell.flicker.SPLIT_DECOR_MANAGER @@ -37,8 +38,8 @@ import com.android.wm.shell.flicker.testapp.Components class SplitScreenHelper( instrumentation: Instrumentation, activityLabel: String, - componentsInfo: IComponentMatcher -) : BaseAppHelper(instrumentation, activityLabel, componentsInfo) { + componentInfo: IComponentNameMatcher +) : BaseAppHelper(instrumentation, activityLabel, componentInfo) { companion object { const val TEST_REPETITIONS = 1 @@ -280,12 +281,12 @@ class SplitScreenHelper( fun copyContentFromLeftToRight( instrumentation: Instrumentation, device: UiDevice, - sourceApp: IComponentMatcher, - destinationApp: IComponentMatcher, + sourceApp: IComponentNameMatcher, + destinationApp: IComponentNameMatcher, ) { // Copy text from sourceApp val textView = device.wait(Until.findObject( - By.res(sourceApp.packageNames.firstOrNull(), "SplitScreenTest")), TIMEOUT_MS) + By.res(sourceApp.packageName, "SplitScreenTest")), TIMEOUT_MS) longPress(instrumentation, textView.getVisibleCenter()) val copyBtn = device.wait(Until.findObject(By.text("Copy")), TIMEOUT_MS) @@ -293,7 +294,7 @@ class SplitScreenHelper( // Paste text to destinationApp val editText = device.wait(Until.findObject( - By.res(destinationApp.packageNames.firstOrNull(), "plain_text_input")), TIMEOUT_MS) + By.res(destinationApp.packageName, "plain_text_input")), TIMEOUT_MS) longPress(instrumentation, editText.getVisibleCenter()) val pasteBtn = device.wait(Until.findObject(By.text("Paste")), TIMEOUT_MS) diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt index 045022414fe0..d194472b9000 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt @@ -25,7 +25,7 @@ import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group3 import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -155,9 +155,9 @@ open class EnterPipTest(testSpec: FlickerTestParameter) : PipTransition(testSpec @Test fun launcherLayerBecomesVisible() { testSpec.assertLayers { - isInvisible(ComponentMatcher.LAUNCHER) + isInvisible(ComponentNameMatcher.LAUNCHER) .then() - .isVisible(ComponentMatcher.LAUNCHER) + .isVisible(ComponentNameMatcher.LAUNCHER) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt index dff447b97b9b..507562b00f4f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt @@ -30,7 +30,6 @@ import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.entireScreenCovered import com.android.server.wm.flicker.helpers.WindowUtils import com.android.server.wm.flicker.navBarLayerPositionAtStartAndEnd -import com.android.server.wm.traces.common.ComponentMatcher import com.android.wm.shell.flicker.helpers.FixedAppHelper import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_PORTRAIT diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt index 33f787182868..fd1fe65fa3a8 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt @@ -23,7 +23,7 @@ import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled import com.android.server.wm.flicker.helpers.setRotation -import com.android.server.wm.traces.common.ComponentMatcher.Companion.LAUNCHER +import com.android.server.wm.traces.common.ComponentNameMatcher.Companion.LAUNCHER import org.junit.Test /** diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt index 5b5b9fc174f6..31a39c190dd6 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt @@ -24,7 +24,7 @@ import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group3 import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -63,9 +63,9 @@ class ExitPipWithSwipeDownTest(testSpec: FlickerTestParameter) : ExitPipTransiti val pipCenterY = pipRegion.centerY() val displayCenterX = device.displayWidth / 2 val barComponent = if (testSpec.isTablet) { - ComponentMatcher.TASK_BAR + ComponentNameMatcher.TASK_BAR } else { - ComponentMatcher.NAV_BAR + ComponentNameMatcher.NAV_BAR } val barLayerHeight = wmHelper.currentState.layerState .getLayerWithBuffer(barComponent) diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt index 1c0bd0caa901..fd661cfc3ee1 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt @@ -25,7 +25,7 @@ import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group3 import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -151,7 +151,7 @@ class ExpandPipOnDoubleClickTest(testSpec: FlickerTestParameter) : PipTransition @Test fun launcherIsAlwaysVisible() { testSpec.assertLayers { - isVisible(ComponentMatcher.LAUNCHER) + isVisible(ComponentNameMatcher.LAUNCHER) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt index 911d402cfde7..454927e57aa2 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt @@ -28,7 +28,7 @@ import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.WindowUtils import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled import com.android.server.wm.flicker.helpers.setRotation -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import com.android.wm.shell.flicker.helpers.ImeAppHelper import org.junit.Assume.assumeFalse import org.junit.Before @@ -105,7 +105,7 @@ open class PipKeyboardTest(testSpec: FlickerTestParameter) : PipTransition(testS @Test open fun pipIsAboveAppWindow() { testSpec.assertWmTag(TAG_IME_VISIBLE) { - isAboveWindow(ComponentMatcher.IME, pipApp) + isAboveWindow(ComponentNameMatcher.IME, pipApp) } } diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp index 9a4bda2ee1df..3c67edc9a428 100644 --- a/libs/hwui/hwui/Typeface.cpp +++ b/libs/hwui/hwui/Typeface.cpp @@ -125,9 +125,14 @@ Typeface* Typeface::createWithDifferentBaseWeight(Typeface* src, int weight) { } Typeface* Typeface::createFromFamilies(std::vector<std::shared_ptr<minikin::FontFamily>>&& families, - int weight, int italic) { + int weight, int italic, const Typeface* fallback) { Typeface* result = new Typeface; - result->fFontCollection = minikin::FontCollection::create(families); + if (fallback == nullptr) { + result->fFontCollection = minikin::FontCollection::create(std::move(families)); + } else { + result->fFontCollection = + fallback->fFontCollection->createCollectionWithFamilies(std::move(families)); + } if (weight == RESOLVE_BY_FONT_TABLE || italic == RESOLVE_BY_FONT_TABLE) { int weightFromFont; diff --git a/libs/hwui/hwui/Typeface.h b/libs/hwui/hwui/Typeface.h index 0c3ef01ab26b..565136e53676 100644 --- a/libs/hwui/hwui/Typeface.h +++ b/libs/hwui/hwui/Typeface.h @@ -78,7 +78,8 @@ public: Typeface* src, const std::vector<minikin::FontVariation>& variations); static Typeface* createFromFamilies( - std::vector<std::shared_ptr<minikin::FontFamily>>&& families, int weight, int italic); + std::vector<std::shared_ptr<minikin::FontFamily>>&& families, int weight, int italic, + const Typeface* fallback); static void setDefault(const Typeface* face); diff --git a/libs/hwui/jni/Typeface.cpp b/libs/hwui/jni/Typeface.cpp index f5ed5689e4e8..209b35c5537c 100644 --- a/libs/hwui/jni/Typeface.cpp +++ b/libs/hwui/jni/Typeface.cpp @@ -109,27 +109,14 @@ static jint Typeface_getWeight(CRITICAL_JNI_PARAMS_COMMA jlong faceHandle) { static jlong Typeface_createFromArray(JNIEnv *env, jobject, jlongArray familyArray, jlong fallbackPtr, int weight, int italic) { ScopedLongArrayRO families(env, familyArray); - std::vector<std::shared_ptr<minikin::FontFamily>> familyVec; Typeface* typeface = (fallbackPtr == 0) ? nullptr : toTypeface(fallbackPtr); - if (typeface != nullptr) { - const std::shared_ptr<minikin::FontCollection>& fallbackCollection = - toTypeface(fallbackPtr)->fFontCollection; - familyVec.reserve(families.size() + fallbackCollection->getFamilyCount()); - for (size_t i = 0; i < families.size(); i++) { - FontFamilyWrapper* family = reinterpret_cast<FontFamilyWrapper*>(families[i]); - familyVec.emplace_back(family->family); - } - for (size_t i = 0; i < fallbackCollection->getFamilyCount(); i++) { - familyVec.emplace_back(fallbackCollection->getFamilyAt(i)); - } - } else { - familyVec.reserve(families.size()); - for (size_t i = 0; i < families.size(); i++) { - FontFamilyWrapper* family = reinterpret_cast<FontFamilyWrapper*>(families[i]); - familyVec.emplace_back(family->family); - } + std::vector<std::shared_ptr<minikin::FontFamily>> familyVec; + familyVec.reserve(families.size()); + for (size_t i = 0; i < families.size(); i++) { + FontFamilyWrapper* family = reinterpret_cast<FontFamilyWrapper*>(families[i]); + familyVec.emplace_back(family->family); } - return toJLong(Typeface::createFromFamilies(std::move(familyVec), weight, italic)); + return toJLong(Typeface::createFromFamilies(std::move(familyVec), weight, italic, typeface)); } // CriticalNative diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h index 81bcb4e609df..c5196eeccea3 100644 --- a/libs/hwui/renderthread/VulkanManager.h +++ b/libs/hwui/renderthread/VulkanManager.h @@ -54,8 +54,6 @@ typedef void(VKAPI_PTR* PFN_vkFrameBoundaryANDROID)(VkDevice device, VkSemaphore #include <SkColorSpace.h> #include <SkRefCnt.h> -class GrVkExtensions; - namespace android { namespace uirenderer { namespace renderthread { diff --git a/libs/hwui/tests/unit/TypefaceTests.cpp b/libs/hwui/tests/unit/TypefaceTests.cpp index 25cc8ca0dafb..499afa039d1f 100644 --- a/libs/hwui/tests/unit/TypefaceTests.cpp +++ b/libs/hwui/tests/unit/TypefaceTests.cpp @@ -73,7 +73,8 @@ std::vector<std::shared_ptr<minikin::FontFamily>> makeSingleFamlyVector(const ch TEST(TypefaceTest, resolveDefault_and_setDefaultTest) { std::unique_ptr<Typeface> regular(Typeface::createFromFamilies( - makeSingleFamlyVector(kRobotoVariable), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)); + makeSingleFamlyVector(kRobotoVariable), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE, + nullptr /* fallback */)); EXPECT_EQ(regular.get(), Typeface::resolveDefault(regular.get())); // Keep the original to restore it later. @@ -351,24 +352,24 @@ TEST(TypefaceTest, createAbsolute) { TEST(TypefaceTest, createFromFamilies_Single) { // In Java, new // Typeface.Builder("Roboto-Regular.ttf").setWeight(400).setItalic(false).build(); - std::unique_ptr<Typeface> regular( - Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoVariable), 400, false)); + std::unique_ptr<Typeface> regular(Typeface::createFromFamilies( + makeSingleFamlyVector(kRobotoVariable), 400, false, nullptr /* fallback */)); EXPECT_EQ(400, regular->fStyle.weight()); EXPECT_EQ(minikin::FontStyle::Slant::UPRIGHT, regular->fStyle.slant()); EXPECT_EQ(Typeface::kNormal, regular->fAPIStyle); // In Java, new // Typeface.Builder("Roboto-Regular.ttf").setWeight(700).setItalic(false).build(); - std::unique_ptr<Typeface> bold( - Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoVariable), 700, false)); + std::unique_ptr<Typeface> bold(Typeface::createFromFamilies( + makeSingleFamlyVector(kRobotoVariable), 700, false, nullptr /* fallback */)); EXPECT_EQ(700, bold->fStyle.weight()); EXPECT_EQ(minikin::FontStyle::Slant::UPRIGHT, bold->fStyle.slant()); EXPECT_EQ(Typeface::kBold, bold->fAPIStyle); // In Java, new // Typeface.Builder("Roboto-Regular.ttf").setWeight(400).setItalic(true).build(); - std::unique_ptr<Typeface> italic( - Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoVariable), 400, true)); + std::unique_ptr<Typeface> italic(Typeface::createFromFamilies( + makeSingleFamlyVector(kRobotoVariable), 400, true, nullptr /* fallback */)); EXPECT_EQ(400, italic->fStyle.weight()); EXPECT_EQ(minikin::FontStyle::Slant::ITALIC, italic->fStyle.slant()); EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle); @@ -376,8 +377,8 @@ TEST(TypefaceTest, createFromFamilies_Single) { // In Java, // new // Typeface.Builder("Roboto-Regular.ttf").setWeight(700).setItalic(true).build(); - std::unique_ptr<Typeface> boldItalic( - Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoVariable), 700, true)); + std::unique_ptr<Typeface> boldItalic(Typeface::createFromFamilies( + makeSingleFamlyVector(kRobotoVariable), 700, true, nullptr /* fallback */)); EXPECT_EQ(700, boldItalic->fStyle.weight()); EXPECT_EQ(minikin::FontStyle::Slant::ITALIC, boldItalic->fStyle.slant()); EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle); @@ -385,8 +386,8 @@ TEST(TypefaceTest, createFromFamilies_Single) { // In Java, // new // Typeface.Builder("Roboto-Regular.ttf").setWeight(1100).setItalic(false).build(); - std::unique_ptr<Typeface> over1000( - Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoVariable), 1100, false)); + std::unique_ptr<Typeface> over1000(Typeface::createFromFamilies( + makeSingleFamlyVector(kRobotoVariable), 1100, false, nullptr /* fallback */)); EXPECT_EQ(1000, over1000->fStyle.weight()); EXPECT_EQ(minikin::FontStyle::Slant::UPRIGHT, over1000->fStyle.slant()); EXPECT_EQ(Typeface::kBold, over1000->fAPIStyle); @@ -394,30 +395,33 @@ TEST(TypefaceTest, createFromFamilies_Single) { TEST(TypefaceTest, createFromFamilies_Single_resolveByTable) { // In Java, new Typeface.Builder("Family-Regular.ttf").build(); - std::unique_ptr<Typeface> regular(Typeface::createFromFamilies( - makeSingleFamlyVector(kRegularFont), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)); + std::unique_ptr<Typeface> regular( + Typeface::createFromFamilies(makeSingleFamlyVector(kRegularFont), RESOLVE_BY_FONT_TABLE, + RESOLVE_BY_FONT_TABLE, nullptr /* fallback */)); EXPECT_EQ(400, regular->fStyle.weight()); EXPECT_EQ(minikin::FontStyle::Slant::UPRIGHT, regular->fStyle.slant()); EXPECT_EQ(Typeface::kNormal, regular->fAPIStyle); // In Java, new Typeface.Builder("Family-Bold.ttf").build(); - std::unique_ptr<Typeface> bold(Typeface::createFromFamilies( - makeSingleFamlyVector(kBoldFont), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)); + std::unique_ptr<Typeface> bold( + Typeface::createFromFamilies(makeSingleFamlyVector(kBoldFont), RESOLVE_BY_FONT_TABLE, + RESOLVE_BY_FONT_TABLE, nullptr /* fallback */)); EXPECT_EQ(700, bold->fStyle.weight()); EXPECT_EQ(minikin::FontStyle::Slant::UPRIGHT, bold->fStyle.slant()); EXPECT_EQ(Typeface::kBold, bold->fAPIStyle); // In Java, new Typeface.Builder("Family-Italic.ttf").build(); - std::unique_ptr<Typeface> italic(Typeface::createFromFamilies( - makeSingleFamlyVector(kItalicFont), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)); + std::unique_ptr<Typeface> italic( + Typeface::createFromFamilies(makeSingleFamlyVector(kItalicFont), RESOLVE_BY_FONT_TABLE, + RESOLVE_BY_FONT_TABLE, nullptr /* fallback */)); EXPECT_EQ(400, italic->fStyle.weight()); EXPECT_EQ(minikin::FontStyle::Slant::ITALIC, italic->fStyle.slant()); EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle); // In Java, new Typeface.Builder("Family-BoldItalic.ttf").build(); - std::unique_ptr<Typeface> boldItalic( - Typeface::createFromFamilies(makeSingleFamlyVector(kBoldItalicFont), - RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)); + std::unique_ptr<Typeface> boldItalic(Typeface::createFromFamilies( + makeSingleFamlyVector(kBoldItalicFont), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE, + nullptr /* fallback */)); EXPECT_EQ(700, boldItalic->fStyle.weight()); EXPECT_EQ(minikin::FontStyle::Slant::ITALIC, boldItalic->fStyle.slant()); EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle); @@ -427,8 +431,9 @@ TEST(TypefaceTest, createFromFamilies_Family) { std::vector<std::shared_ptr<minikin::FontFamily>> families = { buildFamily(kRegularFont), buildFamily(kBoldFont), buildFamily(kItalicFont), buildFamily(kBoldItalicFont)}; - std::unique_ptr<Typeface> typeface(Typeface::createFromFamilies( - std::move(families), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)); + std::unique_ptr<Typeface> typeface( + Typeface::createFromFamilies(std::move(families), RESOLVE_BY_FONT_TABLE, + RESOLVE_BY_FONT_TABLE, nullptr /* fallback */)); EXPECT_EQ(400, typeface->fStyle.weight()); EXPECT_EQ(minikin::FontStyle::Slant::UPRIGHT, typeface->fStyle.slant()); } @@ -436,10 +441,24 @@ TEST(TypefaceTest, createFromFamilies_Family) { TEST(TypefaceTest, createFromFamilies_Family_withoutRegular) { std::vector<std::shared_ptr<minikin::FontFamily>> families = { buildFamily(kBoldFont), buildFamily(kItalicFont), buildFamily(kBoldItalicFont)}; - std::unique_ptr<Typeface> typeface(Typeface::createFromFamilies( - std::move(families), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)); + std::unique_ptr<Typeface> typeface( + Typeface::createFromFamilies(std::move(families), RESOLVE_BY_FONT_TABLE, + RESOLVE_BY_FONT_TABLE, nullptr /* fallback */)); EXPECT_EQ(700, typeface->fStyle.weight()); EXPECT_EQ(minikin::FontStyle::Slant::UPRIGHT, typeface->fStyle.slant()); } +TEST(TypefaceTest, createFromFamilies_Family_withFallback) { + std::vector<std::shared_ptr<minikin::FontFamily>> fallbackFamilies = { + buildFamily(kBoldFont), buildFamily(kItalicFont), buildFamily(kBoldItalicFont)}; + std::unique_ptr<Typeface> fallback( + Typeface::createFromFamilies(std::move(fallbackFamilies), RESOLVE_BY_FONT_TABLE, + RESOLVE_BY_FONT_TABLE, nullptr /* fallback */)); + std::unique_ptr<Typeface> regular( + Typeface::createFromFamilies(makeSingleFamlyVector(kRegularFont), RESOLVE_BY_FONT_TABLE, + RESOLVE_BY_FONT_TABLE, fallback.get())); + EXPECT_EQ(400, regular->fStyle.weight()); + EXPECT_EQ(minikin::FontStyle::Slant::UPRIGHT, regular->fStyle.slant()); +} + } // namespace diff --git a/native/android/system_fonts.cpp b/native/android/system_fonts.cpp index 4df745ff6a20..30d0c35bcbb0 100644 --- a/native/android/system_fonts.cpp +++ b/native/android/system_fonts.cpp @@ -245,32 +245,23 @@ ASystemFontIterator* ASystemFontIterator_open() { std::unique_ptr<ASystemFontIterator> ite(new ASystemFontIterator()); std::unordered_set<AFont, FontHasher> fonts; - minikin::SystemFonts::getFontMap( - [&fonts](const std::vector<std::shared_ptr<minikin::FontCollection>>& collections) { - for (const auto& fc : collections) { - for (uint32_t i = 0; i < fc->getFamilyCount(); ++i) { - const auto& family = fc->getFamilyAt(i); - for (uint32_t j = 0; j < family->getNumFonts(); ++j) { - const minikin::Font* font = family->getFont(j); - - std::optional<std::string> locale; - uint32_t localeId = font->getLocaleListId(); - if (localeId != minikin::kEmptyLocaleListId) { - locale.emplace(minikin::getLocaleString(localeId)); - } - std::vector<std::pair<uint32_t, float>> axes; - for (const auto& [tag, value] : font->typeface()->GetAxes()) { - axes.push_back(std::make_pair(tag, value)); - } - - fonts.insert( - {font->typeface()->GetFontPath(), std::move(locale), - font->style().weight(), - font->style().slant() == minikin::FontStyle::Slant::ITALIC, - static_cast<uint32_t>(font->typeface()->GetFontIndex()), - axes}); - } + minikin::SystemFonts::getFontSet( + [&fonts](const std::vector<std::shared_ptr<minikin::Font>>& fontSet) { + for (const auto& font : fontSet) { + std::optional<std::string> locale; + uint32_t localeId = font->getLocaleListId(); + if (localeId != minikin::kEmptyLocaleListId) { + locale.emplace(minikin::getLocaleString(localeId)); } + std::vector<std::pair<uint32_t, float>> axes; + for (const auto& [tag, value] : font->typeface()->GetAxes()) { + axes.push_back(std::make_pair(tag, value)); + } + + fonts.insert({font->typeface()->GetFontPath(), std::move(locale), + font->style().weight(), + font->style().slant() == minikin::FontStyle::Slant::ITALIC, + static_cast<uint32_t>(font->typeface()->GetFontIndex()), axes}); } }); diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt index 937e59493632..36361ddfe08a 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt @@ -17,7 +17,6 @@ package com.android.settingslib.spa.gallery.page import android.os.Bundle -import androidx.compose.foundation.layout.Column import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.Preview import androidx.navigation.NavType @@ -28,12 +27,14 @@ import com.android.settingslib.spa.framework.compose.toState import com.android.settingslib.spa.framework.theme.SettingsTheme import com.android.settingslib.spa.widget.preference.Preference import com.android.settingslib.spa.widget.preference.PreferenceModel +import com.android.settingslib.spa.widget.scaffold.RegularScaffold +private const val TITLE = "Sample page with arguments" private const val STRING_PARAM_NAME = "stringParam" private const val INT_PARAM_NAME = "intParam" object ArgumentPageProvider : SettingsPageProvider { - override val name = Destinations.Argument + override val name = "Argument" override val arguments = listOf( navArgument(STRING_PARAM_NAME) { type = NavType.StringType }, @@ -51,17 +52,17 @@ object ArgumentPageProvider : SettingsPageProvider { @Composable fun EntryItem(stringParam: String, intParam: Int) { Preference(object : PreferenceModel { - override val title = "Sample page with arguments" + override val title = TITLE override val summary = "$STRING_PARAM_NAME=$stringParam, $INT_PARAM_NAME=$intParam".toState() - override val onClick = navigator("${Destinations.Argument}/$stringParam/$intParam") + override val onClick = navigator("$name/$stringParam/$intParam") }) } } @Composable fun ArgumentPage(stringParam: String, intParam: Int) { - Column { + RegularScaffold(title = TITLE) { Preference(object : PreferenceModel { override val title = "String param value" override val summary = stringParam.toState() diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt index 143c365d3a74..82005ec44c74 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt @@ -17,12 +17,8 @@ package com.android.settingslib.spa.gallery.page import android.os.Bundle -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable import androidx.compose.runtime.remember -import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import com.android.settingslib.spa.framework.api.SettingsPageProvider import com.android.settingslib.spa.framework.compose.navigator @@ -30,8 +26,11 @@ import com.android.settingslib.spa.framework.compose.stateOf import com.android.settingslib.spa.framework.theme.SettingsTheme import com.android.settingslib.spa.widget.preference.Preference import com.android.settingslib.spa.widget.preference.PreferenceModel +import com.android.settingslib.spa.widget.scaffold.RegularScaffold import com.android.settingslib.spa.widget.ui.Footer +private const val TITLE = "Sample Footer" + object FooterPageProvider : SettingsPageProvider { override val name = "Footer" @@ -43,7 +42,7 @@ object FooterPageProvider : SettingsPageProvider { @Composable fun EntryItem() { Preference(object : PreferenceModel { - override val title = "Sample Footer" + override val title = TITLE override val onClick = navigator(name) }) } @@ -51,7 +50,7 @@ object FooterPageProvider : SettingsPageProvider { @Composable private fun FooterPage() { - Column(Modifier.verticalScroll(rememberScrollState())) { + RegularScaffold(title = TITLE) { Preference(remember { object : PreferenceModel { override val title = "Some Preference" diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/HomePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/HomePage.kt index ee077f4a25e6..6b7de8d29d0f 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/HomePage.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/HomePage.kt @@ -31,7 +31,7 @@ import com.android.settingslib.spa.framework.theme.SettingsTheme import com.android.settingslib.spa.gallery.R object HomePageProvider : SettingsPageProvider { - override val name = Destinations.Home + override val name = "Home" @Composable override fun Page(arguments: Bundle?) { diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PageRepository.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PageRepository.kt index 64652257c20b..cbfc60395d69 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PageRepository.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PageRepository.kt @@ -18,14 +18,6 @@ package com.android.settingslib.spa.gallery.page import com.android.settingslib.spa.framework.api.SettingsPageRepository -object Destinations { - const val Home = "Home" - const val Preference = "Preference" - const val SwitchPreference = "SwitchPreference" - const val Argument = "Argument" - const val Slider = "Slider" -} - val galleryPageRepository = SettingsPageRepository( allPages = listOf( HomePageProvider, @@ -36,5 +28,5 @@ val galleryPageRepository = SettingsPageRepository( SettingsPagerPageProvider, FooterPageProvider, ), - startDestination = Destinations.Home, + startDestination = HomePageProvider.name, ) diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PreferencePage.kt index 8a29d35ad9d9..0463e58f09f6 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PreferencePage.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PreferencePage.kt @@ -17,9 +17,6 @@ package com.android.settingslib.spa.gallery.page import android.os.Bundle -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.DisabledByDefault import androidx.compose.material.icons.outlined.TouchApp @@ -31,7 +28,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.produceState import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import com.android.settingslib.spa.framework.api.SettingsPageProvider import com.android.settingslib.spa.framework.compose.navigator @@ -39,11 +35,14 @@ import com.android.settingslib.spa.framework.compose.toState import com.android.settingslib.spa.framework.theme.SettingsTheme import com.android.settingslib.spa.widget.preference.Preference import com.android.settingslib.spa.widget.preference.PreferenceModel +import com.android.settingslib.spa.widget.scaffold.RegularScaffold import com.android.settingslib.spa.widget.ui.SettingsIcon import kotlinx.coroutines.delay +private const val TITLE = "Sample Preference" + object PreferencePageProvider : SettingsPageProvider { - override val name = Destinations.Preference + override val name = "Preference" @Composable override fun Page(arguments: Bundle?) { @@ -53,15 +52,15 @@ object PreferencePageProvider : SettingsPageProvider { @Composable fun EntryItem() { Preference(object : PreferenceModel { - override val title = "Sample Preference" - override val onClick = navigator(Destinations.Preference) + override val title = TITLE + override val onClick = navigator(name) }) } } @Composable private fun PreferencePage() { - Column(Modifier.verticalScroll(rememberScrollState())) { + RegularScaffold(title = TITLE) { Preference(object : PreferenceModel { override val title = "Preference" }) diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt index 9bcac1b84a0b..04046fa18df1 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt @@ -17,9 +17,6 @@ package com.android.settingslib.spa.gallery.page import android.os.Bundle -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.AccessAlarm import androidx.compose.material.icons.outlined.MusicNote @@ -29,18 +26,20 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import com.android.settingslib.spa.framework.api.SettingsPageProvider import com.android.settingslib.spa.framework.compose.navigator import com.android.settingslib.spa.framework.theme.SettingsTheme import com.android.settingslib.spa.widget.preference.Preference import com.android.settingslib.spa.widget.preference.PreferenceModel +import com.android.settingslib.spa.widget.scaffold.RegularScaffold import com.android.settingslib.spa.widget.ui.SettingsSlider import com.android.settingslib.spa.widget.ui.SettingsSliderModel +private const val TITLE = "Sample Slider" + object SliderPageProvider : SettingsPageProvider { - override val name = Destinations.Slider + override val name = "Slider" @Composable override fun Page(arguments: Bundle?) { @@ -50,15 +49,15 @@ object SliderPageProvider : SettingsPageProvider { @Composable fun EntryItem() { Preference(object : PreferenceModel { - override val title = "Sample Slider" - override val onClick = navigator(Destinations.Slider) + override val title = TITLE + override val onClick = navigator(name) }) } } @Composable private fun SliderPage() { - Column(Modifier.verticalScroll(rememberScrollState())) { + RegularScaffold(title = TITLE) { SettingsSlider(object : SettingsSliderModel { override val title = "Slider" override val initValue = 40 diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SwitchPreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SwitchPreferencePage.kt index b6f725821728..e9e5d356d2d4 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SwitchPreferencePage.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SwitchPreferencePage.kt @@ -17,15 +17,11 @@ package com.android.settingslib.spa.gallery.page import android.os.Bundle -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.produceState import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import com.android.settingslib.spa.framework.api.SettingsPageProvider import com.android.settingslib.spa.framework.compose.navigator @@ -35,10 +31,13 @@ import com.android.settingslib.spa.widget.preference.Preference import com.android.settingslib.spa.widget.preference.PreferenceModel import com.android.settingslib.spa.widget.preference.SwitchPreference import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel +import com.android.settingslib.spa.widget.scaffold.RegularScaffold import kotlinx.coroutines.delay +private const val TITLE = "Sample SwitchPreference" + object SwitchPreferencePageProvider : SettingsPageProvider { - override val name = Destinations.SwitchPreference + override val name = "SwitchPreference" @Composable override fun Page(arguments: Bundle?) { @@ -48,15 +47,15 @@ object SwitchPreferencePageProvider : SettingsPageProvider { @Composable fun EntryItem() { Preference(object : PreferenceModel { - override val title = "Sample SwitchPreference" - override val onClick = navigator(Destinations.SwitchPreference) + override val title = TITLE + override val onClick = navigator(name) }) } } @Composable private fun SwitchPreferencePage() { - Column(Modifier.verticalScroll(rememberScrollState())) { + RegularScaffold(title = TITLE) { SampleSwitchPreference() SampleSwitchPreferenceWithSummary() SampleSwitchPreferenceWithAsyncSummary() diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt index e1ca69bd7940..7d3e10768e46 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt @@ -31,4 +31,5 @@ object SettingsDimension { end = itemPaddingEnd, bottom = itemPaddingVertical, ) + val itemPaddingAround = 8.dp } diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt new file mode 100644 index 000000000000..0a41a1a95936 --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt @@ -0,0 +1,46 @@ +/* + * 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.settingslib.spa.widget.scaffold + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.ArrowBack +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import com.android.settingslib.spa.framework.compose.LocalNavController + +@Composable +internal fun NavigateUp() { + val navController = LocalNavController.current + val contentDescription = stringResource( + id = androidx.appcompat.R.string.abc_action_bar_up_description, + ) + BackAction(contentDescription) { + navController.navigateUp() + } +} + +@Composable +private fun BackAction(contentDescription: String, onClick: () -> Unit) { + IconButton(onClick) { + Icon( + imageVector = Icons.Outlined.ArrowBack, + contentDescription = contentDescription, + ) + } +} diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/RegularScaffold.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/RegularScaffold.kt new file mode 100644 index 000000000000..3325d5382f2e --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/RegularScaffold.kt @@ -0,0 +1,83 @@ +/* + * 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.settingslib.spa.widget.scaffold + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SmallTopAppBar +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import com.android.settingslib.spa.framework.theme.SettingsDimension +import com.android.settingslib.spa.framework.theme.SettingsTheme + +/** + * A [Scaffold] which content is scrollable and wrapped in a [Column]. + * + * For example, this is for the pages with some preferences and is scrollable when the items out of + * the screen. + */ +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun RegularScaffold( + title: String, + actions: @Composable RowScope.() -> Unit = {}, + content: @Composable () -> Unit, +) { + Scaffold( + topBar = { + SmallTopAppBar( + title = { + Text( + text = title, + modifier = Modifier.padding(SettingsDimension.itemPaddingAround), + ) + }, + navigationIcon = { NavigateUp() }, + actions = actions, + colors = settingsTopAppBarColors(), + ) + }, + ) { paddingValues -> + Column(Modifier.verticalScroll(rememberScrollState())) { + Spacer(Modifier.padding(paddingValues)) + content() + } + } +} + +@Composable +internal fun settingsTopAppBarColors() = TopAppBarDefaults.largeTopAppBarColors( + containerColor = SettingsTheme.colorScheme.surfaceHeader, + scrolledContainerColor = SettingsTheme.colorScheme.surfaceHeader, +) + +@Preview +@Composable +private fun RegularScaffoldPreview() { + SettingsTheme { + RegularScaffold(title = "Display") {} + } +} diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/app/AppOpsController.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt index 3808f64386ef..c2d85a54bc32 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/app/AppOpsController.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settingslib.spaprivileged.framework.app +package com.android.settingslib.spaprivileged.model.app import android.app.AppOpsManager import android.app.AppOpsManager.MODE_ALLOWED diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/app/AppRecord.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppRecord.kt index 8dde897cb23d..297868871389 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/app/AppRecord.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppRecord.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settingslib.spaprivileged.framework.app +package com.android.settingslib.spaprivileged.model.app import android.content.pm.ApplicationInfo diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/app/AppRepository.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppRepository.kt index a6378ef53437..7ffa9384bfe2 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/app/AppRepository.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppRepository.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settingslib.spaprivileged.framework.app +package com.android.settingslib.spaprivileged.model.app import android.content.Context import android.content.pm.ApplicationInfo diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/app/Apps.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/Apps.kt index f6755459c1b7..6e1afd94fe29 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/app/Apps.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/Apps.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settingslib.spaprivileged.framework.app +package com.android.settingslib.spaprivileged.model.app import android.content.pm.ApplicationInfo import android.os.UserHandle diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/app/PackageManagers.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/PackageManagers.kt index 66b05da03b3f..0cc497a3e899 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/app/PackageManagers.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/PackageManagers.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settingslib.spaprivileged.framework.app +package com.android.settingslib.spaprivileged.model.app import android.content.pm.ApplicationInfo import android.content.pm.PackageInfo diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/enterprise/EnterpriseRepository.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/EnterpriseRepository.kt index ae0cb772533c..fab3ae8e510b 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/enterprise/EnterpriseRepository.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/EnterpriseRepository.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settingslib.spaprivileged.framework.enterprise +package com.android.settingslib.spaprivileged.model.enterprise import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyResources.Strings.Settings.PERSONAL_CATEGORY_HEADER diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt index 5ae514cfb524..d802b049b830 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt @@ -33,8 +33,8 @@ import androidx.compose.ui.unit.dp import com.android.settingslib.spa.framework.compose.rememberDrawablePainter import com.android.settingslib.spa.widget.ui.SettingsBody import com.android.settingslib.spa.widget.ui.SettingsTitle -import com.android.settingslib.spaprivileged.framework.app.PackageManagers -import com.android.settingslib.spaprivileged.framework.app.rememberAppRepository +import com.android.settingslib.spaprivileged.model.app.PackageManagers +import com.android.settingslib.spaprivileged.model.app.rememberAppRepository @Composable fun AppInfo(packageName: String, userId: Int) { diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt index 57e9e9ac1b9b..430ac5409711 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt @@ -31,8 +31,8 @@ import com.android.settingslib.spa.framework.api.SettingsPageProvider import com.android.settingslib.spa.framework.compose.rememberContext import com.android.settingslib.spa.widget.preference.SwitchPreference import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel -import com.android.settingslib.spaprivileged.framework.app.AppRecord -import com.android.settingslib.spaprivileged.framework.app.PackageManagers +import com.android.settingslib.spaprivileged.model.app.AppRecord +import com.android.settingslib.spaprivileged.model.app.PackageManagers import kotlinx.coroutines.Dispatchers private const val PERMISSION = "permission" diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListModel.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListModel.kt index 88ad9daa85b3..3782f7cd301e 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListModel.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListModel.kt @@ -20,7 +20,7 @@ import android.content.Context import android.content.pm.ApplicationInfo import androidx.compose.runtime.Composable import androidx.compose.runtime.State -import com.android.settingslib.spaprivileged.framework.app.AppRecord +import com.android.settingslib.spaprivileged.model.app.AppRecord interface TogglePermissionAppListModel<T : AppRecord> { val pageTitleResId: Int diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/scaffold/WorkProfilePager.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/WorkProfilePager.kt index 09864a17adfc..aa5ccf146d47 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/scaffold/WorkProfilePager.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/WorkProfilePager.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settingslib.spaprivileged.template.scaffold +package com.android.settingslib.spaprivileged.template.common import android.content.pm.UserInfo import android.os.UserHandle @@ -23,7 +23,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.platform.LocalContext import com.android.settingslib.spa.widget.scaffold.SettingsPager -import com.android.settingslib.spaprivileged.framework.enterprise.EnterpriseRepository +import com.android.settingslib.spaprivileged.model.enterprise.EnterpriseRepository @Composable fun WorkProfilePager(content: @Composable (userInfo: UserInfo) -> Unit) { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 2f9bc1c59624..d75285283cbc 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -54,6 +54,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.database.ContentObserver; import android.hardware.SensorPrivacyManager; +import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricFingerprintConstants; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricSourceType; @@ -2018,12 +2019,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab // in case authenticators aren't registered yet at this point: mAuthController.addCallback(new AuthController.Callback() { @Override - public void onAllAuthenticatorsRegistered() { + public void onAllAuthenticatorsRegistered( + @BiometricAuthenticator.Modality int modality) { mainExecutor.execute(() -> updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE)); } @Override - public void onEnrollmentsChanged() { + public void onEnrollmentsChanged(@BiometricAuthenticator.Modality int modality) { mainExecutor.execute(() -> updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE)); } }); diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java index 06e1828ef9f4..d6974dfac570 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java @@ -16,6 +16,7 @@ package com.android.keyguard; +import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT; import static com.android.keyguard.LockIconView.ICON_FINGERPRINT; @@ -29,6 +30,7 @@ import android.content.res.Resources; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.drawable.AnimatedStateListDrawable; +import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricSourceType; import android.os.Process; import android.os.VibrationAttributes; @@ -701,13 +703,17 @@ public class LockIconViewController extends ViewController<LockIconView> impleme private final AuthController.Callback mAuthControllerCallback = new AuthController.Callback() { @Override - public void onAllAuthenticatorsRegistered() { - updateUdfpsConfig(); + public void onAllAuthenticatorsRegistered(@BiometricAuthenticator.Modality int modality) { + if (modality == TYPE_FINGERPRINT) { + updateUdfpsConfig(); + } } @Override - public void onEnrollmentsChanged() { - updateUdfpsConfig(); + public void onEnrollmentsChanged(@BiometricAuthenticator.Modality int modality) { + if (modality == TYPE_FINGERPRINT) { + updateUdfpsConfig(); + } } @Override diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index 47ff59cfc281..282f25104c44 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -46,6 +46,7 @@ import android.hardware.biometrics.PromptInfo; import android.hardware.display.DisplayManager; import android.hardware.face.FaceManager; import android.hardware.face.FaceSensorPropertiesInternal; +import android.hardware.face.IFaceAuthenticatorsRegisteredCallback; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; @@ -156,25 +157,6 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba } }; - private final IFingerprintAuthenticatorsRegisteredCallback - mFingerprintAuthenticatorsRegisteredCallback = - new IFingerprintAuthenticatorsRegisteredCallback.Stub() { - @Override - public void onAllAuthenticatorsRegistered( - List<FingerprintSensorPropertiesInternal> sensors) { - mHandler.post(() -> handleAllFingerprintAuthenticatorsRegistered(sensors)); - } - }; - - private final BiometricStateListener mBiometricStateListener = - new BiometricStateListener() { - @Override - public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) { - mHandler.post( - () -> handleEnrollmentsChanged(userId, sensorId, hasEnrollments)); - } - }; - @VisibleForTesting final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override @@ -249,8 +231,8 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba List<FingerprintSensorPropertiesInternal> sensors) { mExecution.assertIsMainThread(); if (DEBUG) { - Log.d(TAG, "handleAllAuthenticatorsRegistered | sensors: " + Arrays.toString( - sensors.toArray())); + Log.d(TAG, "handleAllFingerprintAuthenticatorsRegistered | sensors: " + + Arrays.toString(sensors.toArray())); } mAllFingerprintAuthenticatorsRegistered = true; mFpProps = sensors; @@ -292,15 +274,42 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba mSidefpsController = mSidefpsControllerFactory.get(); } - mFingerprintManager.registerBiometricStateListener(mBiometricStateListener); + mFingerprintManager.registerBiometricStateListener(new BiometricStateListener() { + @Override + public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) { + mHandler.post(() -> handleEnrollmentsChanged( + TYPE_FINGERPRINT, userId, sensorId, hasEnrollments)); + } + }); updateFingerprintLocation(); for (Callback cb : mCallbacks) { - cb.onAllAuthenticatorsRegistered(); + cb.onAllAuthenticatorsRegistered(TYPE_FINGERPRINT); } } - private void handleEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) { + private void handleAllFaceAuthenticatorsRegistered(List<FaceSensorPropertiesInternal> sensors) { + mExecution.assertIsMainThread(); + if (DEBUG) { + Log.d(TAG, "handleAllFaceAuthenticatorsRegistered | sensors: " + Arrays.toString( + sensors.toArray())); + } + + mFaceManager.registerBiometricStateListener(new BiometricStateListener() { + @Override + public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) { + mHandler.post(() -> handleEnrollmentsChanged( + TYPE_FACE, userId, sensorId, hasEnrollments)); + } + }); + + for (Callback cb : mCallbacks) { + cb.onAllAuthenticatorsRegistered(TYPE_FACE); + } + } + + private void handleEnrollmentsChanged(@Modality int modality, int userId, int sensorId, + boolean hasEnrollments) { mExecution.assertIsMainThread(); Log.d(TAG, "handleEnrollmentsChanged, userId: " + userId + ", sensorId: " + sensorId + ", hasEnrollments: " + hasEnrollments); @@ -314,7 +323,7 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba } } for (Callback cb : mCallbacks) { - cb.onEnrollmentsChanged(); + cb.onEnrollmentsChanged(modality); } } @@ -700,7 +709,26 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba if (mFingerprintManager != null) { mFingerprintManager.addAuthenticatorsRegisteredCallback( - mFingerprintAuthenticatorsRegisteredCallback); + new IFingerprintAuthenticatorsRegisteredCallback.Stub() { + @Override + public void onAllAuthenticatorsRegistered( + List<FingerprintSensorPropertiesInternal> sensors) { + mHandler.post(() -> + handleAllFingerprintAuthenticatorsRegistered(sensors)); + } + }); + } + if (mFaceManager != null) { + mFaceManager.addAuthenticatorsRegisteredCallback( + new IFaceAuthenticatorsRegisteredCallback.Stub() { + @Override + public void onAllAuthenticatorsRegistered( + List<FaceSensorPropertiesInternal> sensors) { + mHandler.post(() -> + handleAllFaceAuthenticatorsRegistered(sensors)); + } + } + ); } mStableDisplaySize = mDisplayManager.getStableDisplaySize(); @@ -1116,13 +1144,13 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba * Called when authenticators are registered. If authenticators are already * registered before this call, this callback will never be triggered. */ - default void onAllAuthenticatorsRegistered() {} + default void onAllAuthenticatorsRegistered(@Modality int modality) {} /** - * Called when UDFPS enrollments have changed. This is called after boot and on changes to + * Called when enrollments have changed. This is called after boot and on changes to * enrollment. */ - default void onEnrollmentsChanged() {} + default void onEnrollmentsChanged(@Modality int modality) {} /** * Called when the biometric prompt starts showing. diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt index 38fab8ffbfad..fd3f6007d8a9 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt @@ -308,7 +308,7 @@ class AuthRippleController @Inject constructor( private val authControllerCallback = object : AuthController.Callback { - override fun onAllAuthenticatorsRegistered() { + override fun onAllAuthenticatorsRegistered(modality: Int) { updateUdfpsDependentParams() updateSensorLocation() } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java index a9e310d25f9c..7da2cf150147 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java @@ -16,12 +16,15 @@ package com.android.systemui.doze; +import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; + import static com.android.systemui.doze.DozeMachine.State.DOZE; import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD; import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSED; import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSING; import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSE_DONE; +import android.hardware.biometrics.BiometricAuthenticator; import android.os.Handler; import android.util.Log; import android.view.Display; @@ -232,13 +235,17 @@ public class DozeScreenState implements DozeMachine.Part { private final AuthController.Callback mAuthControllerCallback = new AuthController.Callback() { @Override - public void onAllAuthenticatorsRegistered() { - updateUdfpsController(); + public void onAllAuthenticatorsRegistered(@BiometricAuthenticator.Modality int modality) { + if (modality == TYPE_FINGERPRINT) { + updateUdfpsController(); + } } @Override - public void onEnrollmentsChanged() { - updateUdfpsController(); + public void onEnrollmentsChanged(@BiometricAuthenticator.Modality int modality) { + if (modality == TYPE_FINGERPRINT) { + updateUdfpsController(); + } } }; } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java index da6c163b1eea..997a6e554364 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java @@ -16,6 +16,8 @@ package com.android.systemui.doze; +import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; + import static com.android.systemui.doze.DozeLog.REASON_SENSOR_QUICK_PICKUP; import static com.android.systemui.doze.DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS; import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_DISPLAY; @@ -29,6 +31,7 @@ import android.hardware.Sensor; import android.hardware.SensorManager; import android.hardware.TriggerEvent; import android.hardware.TriggerEventListener; +import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.display.AmbientDisplayConfiguration; import android.net.Uri; import android.os.Handler; @@ -835,13 +838,17 @@ public class DozeSensors { private final AuthController.Callback mAuthControllerCallback = new AuthController.Callback() { @Override - public void onAllAuthenticatorsRegistered() { - updateUdfpsEnrolled(); + public void onAllAuthenticatorsRegistered(@BiometricAuthenticator.Modality int modality) { + if (modality == TYPE_FINGERPRINT) { + updateUdfpsEnrolled(); + } } @Override - public void onEnrollmentsChanged() { - updateUdfpsEnrolled(); + public void onEnrollmentsChanged(@BiometricAuthenticator.Modality int modality) { + if (modality == TYPE_FINGERPRINT) { + updateUdfpsEnrolled(); + } } private void updateUdfpsEnrolled() { diff --git a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt index 948fb1428780..60380064e098 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt @@ -129,6 +129,15 @@ class QSLogger @Inject constructor( }) } + fun logInternetTileUpdate(lastType: Int, callback: String) { + log(VERBOSE, { + int1 = lastType + str1 = callback + }, { + "mLastTileState=$int1, Callback=$str1." + }) + } + fun logTileUpdated(tileSpec: String, state: QSTile.State) { log(VERBOSE, { str1 = tileSpec diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java index 170fecf1c8fd..ae464771bf48 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java @@ -369,11 +369,10 @@ public class InternetTile extends QSTileImpl<SignalState> { mWifiInfo.mNoDefaultNetwork = noDefaultNetwork; mWifiInfo.mNoValidatedNetwork = noValidatedNetwork; mWifiInfo.mNoNetworksAvailable = noNetworksAvailable; - if (mLastTileState == LAST_STATE_WIFI) { - refreshState(mWifiInfo); - } else { - refreshState(mCellularInfo); + if (!noDefaultNetwork) { + return; } + refreshState(mWifiInfo); } @Override @@ -388,6 +387,7 @@ public class InternetTile extends QSTileImpl<SignalState> { @Override protected void handleUpdateState(SignalState state, Object arg) { + mQSLogger.logInternetTileUpdate(mLastTileState, arg == null ? "null" : arg.toString()); if (arg instanceof CellularCallbackInfo) { mLastTileState = LAST_STATE_CELLULAR; handleUpdateCellularState(state, arg); @@ -605,4 +605,9 @@ public class InternetTile extends QSTileImpl<SignalState> { pw.print(" "); pw.println("mLastTileState=" + mLastTileState); pw.print(" "); pw.println("mSignalCallback=" + mSignalCallback.toString()); } + + // For testing usage only. + protected int getLastTileState() { + return mLastTileState; + } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index c281965550e4..3e00aec8cb28 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -16,6 +16,7 @@ package com.android.keyguard; +import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT; import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE; import static android.telephony.SubscriptionManager.NAME_SOURCE_CARRIER_ID; @@ -1006,7 +1007,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { // WHEN udfps is now enrolled when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(true); - callback.onEnrollmentsChanged(); + callback.onEnrollmentsChanged(TYPE_FINGERPRINT); // THEN isUdfspEnrolled is TRUE assertThat(mKeyguardUpdateMonitor.isUdfpsEnrolled()).isTrue(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java index d158892e4ec5..e0d1f7a19130 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -60,6 +60,9 @@ import android.hardware.biometrics.PromptInfo; import android.hardware.biometrics.SensorProperties; import android.hardware.display.DisplayManager; import android.hardware.face.FaceManager; +import android.hardware.face.FaceSensorProperties; +import android.hardware.face.FaceSensorPropertiesInternal; +import android.hardware.face.IFaceAuthenticatorsRegisteredCallback; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; @@ -154,7 +157,9 @@ public class AuthControllerTest extends SysuiTestCase { @Mock private InteractionJankMonitor mInteractionJankMonitor; @Captor - ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> mAuthenticatorsRegisteredCaptor; + ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> mFpAuthenticatorsRegisteredCaptor; + @Captor + ArgumentCaptor<IFaceAuthenticatorsRegisteredCallback> mFaceAuthenticatorsRegisteredCaptor; @Captor ArgumentCaptor<BiometricStateListener> mBiometricStateCaptor; @Captor @@ -193,25 +198,38 @@ public class AuthControllerTest extends SysuiTestCase { when(mDisplayManager.getStableDisplaySize()).thenReturn(new Point()); when(mFingerprintManager.isHardwareDetected()).thenReturn(true); - - final List<ComponentInfoInternal> componentInfo = new ArrayList<>(); - componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */, - "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */, - "00000001" /* serialNumber */, "" /* softwareVersion */)); - componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */, - "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */, - "vendor/version/revision" /* softwareVersion */)); - - FingerprintSensorPropertiesInternal prop = new FingerprintSensorPropertiesInternal( - 1 /* sensorId */, - SensorProperties.STRENGTH_STRONG, - 1 /* maxEnrollmentsPerUser */, - componentInfo, - FingerprintSensorProperties.TYPE_UDFPS_OPTICAL, - true /* resetLockoutRequireHardwareAuthToken */); - List<FingerprintSensorPropertiesInternal> props = new ArrayList<>(); - props.add(prop); - when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(props); + when(mFaceManager.isHardwareDetected()).thenReturn(true); + + final List<ComponentInfoInternal> fpComponentInfo = List.of( + new ComponentInfoInternal("faceSensor" /* componentId */, + "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */, + "00000001" /* serialNumber */, "" /* softwareVersion */)); + final List<ComponentInfoInternal> faceComponentInfo = List.of( + new ComponentInfoInternal("matchingAlgorithm" /* componentId */, + "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */, + "vendor/version/revision" /* softwareVersion */)); + + final List<FingerprintSensorPropertiesInternal> fpProps = List.of( + new FingerprintSensorPropertiesInternal( + 1 /* sensorId */, + SensorProperties.STRENGTH_STRONG, + 1 /* maxEnrollmentsPerUser */, + fpComponentInfo, + FingerprintSensorProperties.TYPE_UDFPS_OPTICAL, + true /* resetLockoutRequireHardwareAuthToken */)); + when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(fpProps); + + final List<FaceSensorPropertiesInternal> faceProps = List.of( + new FaceSensorPropertiesInternal( + 2 /* sensorId */, + SensorProperties.STRENGTH_STRONG, + 1 /* maxEnrollmentsPerUser */, + fpComponentInfo, + FaceSensorProperties.TYPE_RGB, + true /* supportsFaceDetection */, + true /* supportsSelfIllumination */, + true /* resetLockoutRequireHardwareAuthToken */)); + when(mFaceManager.getSensorPropertiesInternal()).thenReturn(faceProps); mAuthController = new TestableAuthController(mContextSpy, mExecution, mCommandQueue, mActivityTaskManager, mWindowManager, mFingerprintManager, mFaceManager, @@ -219,12 +237,15 @@ public class AuthControllerTest extends SysuiTestCase { mAuthController.start(); verify(mFingerprintManager).addAuthenticatorsRegisteredCallback( - mAuthenticatorsRegisteredCaptor.capture()); + mFpAuthenticatorsRegisteredCaptor.capture()); + verify(mFaceManager).addAuthenticatorsRegisteredCallback( + mFaceAuthenticatorsRegisteredCaptor.capture()); when(mStatusBarStateController.isDozing()).thenReturn(false); verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture()); - mAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(props); + mFpAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(fpProps); + mFaceAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(faceProps); // Ensures that the operations posted on the handler get executed. mTestableLooper.processAllMessages(); @@ -237,6 +258,7 @@ public class AuthControllerTest extends SysuiTestCase { throws RemoteException { // This test is sensitive to prior FingerprintManager interactions. reset(mFingerprintManager); + reset(mFaceManager); // This test requires an uninitialized AuthController. AuthController authController = new TestableAuthController(mContextSpy, mExecution, @@ -246,21 +268,27 @@ public class AuthControllerTest extends SysuiTestCase { authController.start(); verify(mFingerprintManager).addAuthenticatorsRegisteredCallback( - mAuthenticatorsRegisteredCaptor.capture()); + mFpAuthenticatorsRegisteredCaptor.capture()); + verify(mFaceManager).addAuthenticatorsRegisteredCallback( + mFaceAuthenticatorsRegisteredCaptor.capture()); mTestableLooper.processAllMessages(); verify(mFingerprintManager, never()).registerBiometricStateListener(any()); + verify(mFaceManager, never()).registerBiometricStateListener(any()); - mAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(new ArrayList<>()); + mFpAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(List.of()); + mFaceAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(List.of()); mTestableLooper.processAllMessages(); verify(mFingerprintManager).registerBiometricStateListener(any()); + verify(mFaceManager).registerBiometricStateListener(any()); } @Test public void testDoesNotCrash_afterEnrollmentsChangedForUnknownSensor() throws RemoteException { // This test is sensitive to prior FingerprintManager interactions. reset(mFingerprintManager); + reset(mFaceManager); // This test requires an uninitialized AuthController. AuthController authController = new TestableAuthController(mContextSpy, mExecution, @@ -270,18 +298,25 @@ public class AuthControllerTest extends SysuiTestCase { authController.start(); verify(mFingerprintManager).addAuthenticatorsRegisteredCallback( - mAuthenticatorsRegisteredCaptor.capture()); + mFpAuthenticatorsRegisteredCaptor.capture()); + verify(mFaceManager).addAuthenticatorsRegisteredCallback( + mFaceAuthenticatorsRegisteredCaptor.capture()); // Emulates a device with no authenticators (empty list). - mAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(new ArrayList<>()); + mFpAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(List.of()); + mFaceAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(List.of()); mTestableLooper.processAllMessages(); verify(mFingerprintManager).registerBiometricStateListener( mBiometricStateCaptor.capture()); + verify(mFaceManager).registerBiometricStateListener( + mBiometricStateCaptor.capture()); // Enrollments changed for an unknown sensor. - mBiometricStateCaptor.getValue().onEnrollmentsChanged(0 /* userId */, - 0xbeef /* sensorId */, true /* hasEnrollments */); + for (BiometricStateListener listener : mBiometricStateCaptor.getAllValues()) { + listener.onEnrollmentsChanged(0 /* userId */, + 0xbeef /* sensorId */, true /* hasEnrollments */); + } mTestableLooper.processAllMessages(); // Nothing should crash. @@ -827,4 +862,3 @@ public class AuthControllerTest extends SysuiTestCase { } } } - diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java index 9ffc5a57cef6..b33f9a7f3933 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java @@ -16,6 +16,8 @@ package com.android.systemui.doze; +import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; + import static com.android.systemui.doze.DozeLog.REASON_SENSOR_TAP; import static com.android.systemui.doze.DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS; import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN; @@ -412,7 +414,7 @@ public class DozeSensorsTest extends SysuiTestCase { // WHEN enrollment changes to TRUE when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(true); - mAuthControllerCallback.onEnrollmentsChanged(); + mAuthControllerCallback.onEnrollmentsChanged(TYPE_FINGERPRINT); // THEN mConfigured = TRUE assertTrue(triggerSensor.mConfigured); diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java index 24d051508fde..5ec6bdf3c00b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java @@ -16,6 +16,8 @@ package com.android.systemui.keyguard; +import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; + import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.keyguard.LockIconView.ICON_LOCK; import static com.android.keyguard.LockIconView.ICON_UNLOCK; @@ -219,7 +221,7 @@ public class LockIconViewControllerTest extends SysuiTestCase { Pair<Float, PointF> udfps = setupUdfps(); // WHEN all authenticators are registered - mAuthControllerCallback.onAllAuthenticatorsRegistered(); + mAuthControllerCallback.onAllAuthenticatorsRegistered(TYPE_FINGERPRINT); mDelayableExecutor.runAllReady(); // THEN lock icon view location is updated with the same coordinates as auth controller vals diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileTest.java new file mode 100644 index 000000000000..d91baa5e7fcb --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileTest.java @@ -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 com.android.systemui.qs.tiles; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + + +import android.os.Handler; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import androidx.test.filters.SmallTest; + +import com.android.internal.logging.MetricsLogger; +import com.android.systemui.R; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.classifier.FalsingManagerFake; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.qs.QSTileHost; +import com.android.systemui.qs.logging.QSLogger; +import com.android.systemui.qs.tiles.dialog.InternetDialogFactory; +import com.android.systemui.statusbar.connectivity.AccessPointController; +import com.android.systemui.statusbar.connectivity.NetworkController; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) +@SmallTest +public class InternetTileTest extends SysuiTestCase { + + @Mock + private QSTileHost mHost; + @Mock + private NetworkController mNetworkController; + @Mock + private AccessPointController mAccessPointController; + @Mock + private InternetDialogFactory mInternetDialogFactory; + + private TestableLooper mTestableLooper; + private InternetTile mTile; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mTestableLooper = TestableLooper.get(this); + when(mHost.getContext()).thenReturn(mContext); + when(mHost.getUserContext()).thenReturn(mContext); + + mTile = new InternetTile( + mHost, + mTestableLooper.getLooper(), + new Handler(mTestableLooper.getLooper()), + new FalsingManagerFake(), + mock(MetricsLogger.class), + mock(StatusBarStateController.class), + mock(ActivityStarter.class), + mock(QSLogger.class), + mNetworkController, + mAccessPointController, + mInternetDialogFactory + ); + + mTile.initialize(); + mTestableLooper.processAllMessages(); + } + + @Test + public void setConnectivityStatus_defaultNetworkNotExists_updateTile() { + mTile.mSignalCallback.setConnectivityStatus( + /* noDefaultNetwork= */ true, + /* noValidatedNetwork= */ true, + /* noNetworksAvailable= */ true); + mTestableLooper.processAllMessages(); + assertThat(String.valueOf(mTile.getState().secondaryLabel)) + .isEqualTo(mContext.getString(R.string.quick_settings_networks_unavailable)); + assertThat(mTile.getLastTileState()).isEqualTo(1); + } + + @Test + public void setConnectivityStatus_defaultNetworkExists_notUpdateTile() { + mTile.mSignalCallback.setConnectivityStatus( + /* noDefaultNetwork= */ false, + /* noValidatedNetwork= */ true, + /* noNetworksAvailable= */ true); + mTestableLooper.processAllMessages(); + assertThat(String.valueOf(mTile.getState().secondaryLabel)) + .isNotEqualTo(mContext.getString(R.string.quick_settings_networks_unavailable)); + assertThat(String.valueOf(mTile.getState().secondaryLabel)) + .isNotEqualTo(mContext.getString(R.string.quick_settings_networks_available)); + assertThat(mTile.getLastTileState()).isEqualTo(-1); + } +} diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index a5bcb0517d25..248e35e6964d 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -63,7 +63,6 @@ import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE; import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED; import static android.app.AppOpsManager.UID_STATE_PERSISTENT; import static android.app.AppOpsManager.UID_STATE_TOP; -import static android.app.AppOpsManager.WATCH_FOREGROUND_CHANGES; import static android.app.AppOpsManager._NUM_OP; import static android.app.AppOpsManager.extractFlagsFromKey; import static android.app.AppOpsManager.extractUidStateFromKey; @@ -563,6 +562,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch public ArrayMap<String, Ops> pkgOps; // true indicates there is an interested observer, false there isn't but it has such an op + //TODO: Move foregroundOps and hasForegroundWatchers into the AppOpsServiceInterface. public SparseBooleanArray foregroundOps; public boolean hasForegroundWatchers; @@ -658,48 +658,24 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch return mode; } - private void evalForegroundWatchers(int op, SparseArray<ArraySet<ModeCallback>> watchers, - SparseBooleanArray which) { - boolean curValue = which.get(op, false); - ArraySet<ModeCallback> callbacks = watchers.get(op); - if (callbacks != null) { - for (int cbi = callbacks.size() - 1; !curValue && cbi >= 0; cbi--) { - if ((callbacks.valueAt(cbi).mFlags - & AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) { - hasForegroundWatchers = true; - curValue = true; - } + public void evalForegroundOps() { + foregroundOps = null; + foregroundOps = mAppOpsServiceInterface.evalForegroundUidOps(uid, foregroundOps); + if (pkgOps != null) { + for (int i = pkgOps.size() - 1; i >= 0; i--) { + foregroundOps = mAppOpsServiceInterface + .evalForegroundPackageOps(pkgOps.valueAt(i).packageName, foregroundOps); } } - which.put(op, curValue); - } - - public void evalForegroundOps(SparseArray<ArraySet<ModeCallback>> watchers) { - SparseBooleanArray which = null; hasForegroundWatchers = false; - final SparseIntArray opModes = getNonDefaultUidModes(); - for (int i = opModes.size() - 1; i >= 0; i--) { - if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) { - if (which == null) { - which = new SparseBooleanArray(); - } - evalForegroundWatchers(opModes.keyAt(i), watchers, which); - } - } - if (pkgOps != null) { - for (int i = pkgOps.size() - 1; i >= 0; i--) { - Ops ops = pkgOps.valueAt(i); - for (int j = ops.size() - 1; j >= 0; j--) { - if (ops.valueAt(j).getMode() == AppOpsManager.MODE_FOREGROUND) { - if (which == null) { - which = new SparseBooleanArray(); - } - evalForegroundWatchers(ops.keyAt(j), watchers, which); - } + if (foregroundOps != null) { + for (int i = 0; i < foregroundOps.size(); i++) { + if (foregroundOps.valueAt(i)) { + hasForegroundWatchers = true; + break; } } } - foregroundOps = which; } } @@ -1562,33 +1538,24 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch } } - final SparseArray<ArraySet<ModeCallback>> mOpModeWatchers = new SparseArray<>(); - final ArrayMap<String, ArraySet<ModeCallback>> mPackageModeWatchers = new ArrayMap<>(); final ArrayMap<IBinder, ModeCallback> mModeWatchers = new ArrayMap<>(); final ArrayMap<IBinder, SparseArray<ActiveCallback>> mActiveWatchers = new ArrayMap<>(); final ArrayMap<IBinder, SparseArray<StartedCallback>> mStartedWatchers = new ArrayMap<>(); final ArrayMap<IBinder, SparseArray<NotedCallback>> mNotedWatchers = new ArrayMap<>(); final AudioRestrictionManager mAudioRestrictionManager = new AudioRestrictionManager(); - final class ModeCallback implements DeathRecipient { + final class ModeCallback extends OnOpModeChangedListener implements DeathRecipient { /** If mWatchedOpCode==ALL_OPS notify for ops affected by the switch-op */ public static final int ALL_OPS = -2; - final IAppOpsCallback mCallback; - final int mWatchingUid; - final int mFlags; - final int mWatchedOpCode; - final int mCallingUid; - final int mCallingPid; + // Need to keep this only because stopWatchingMode needs an IAppOpsCallback. + // Otherwise we can just use the IBinder object. + private final IAppOpsCallback mCallback; - ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int watchedOp, + ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int watchedOpCode, int callingUid, int callingPid) { - mCallback = callback; - mWatchingUid = watchingUid; - mFlags = flags; - mWatchedOpCode = watchedOp; - mCallingUid = callingUid; - mCallingPid = callingPid; + super(watchingUid, flags, watchedOpCode, callingUid, callingPid); + this.mCallback = callback; try { mCallback.asBinder().linkToDeath(this, 0); } catch (RemoteException e) { @@ -1596,20 +1563,16 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch } } - public boolean isWatchingUid(int uid) { - return uid == UID_ANY || mWatchingUid < 0 || mWatchingUid == uid; - } - @Override public String toString() { StringBuilder sb = new StringBuilder(128); sb.append("ModeCallback{"); sb.append(Integer.toHexString(System.identityHashCode(this))); sb.append(" watchinguid="); - UserHandle.formatUid(sb, mWatchingUid); + UserHandle.formatUid(sb, getWatchingUid()); sb.append(" flags=0x"); - sb.append(Integer.toHexString(mFlags)); - switch (mWatchedOpCode) { + sb.append(Integer.toHexString(getFlags())); + switch (getWatchedOpCode()) { case OP_NONE: break; case ALL_OPS: @@ -1617,13 +1580,13 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch break; default: sb.append(" op="); - sb.append(opToName(mWatchedOpCode)); + sb.append(opToName(getWatchedOpCode())); break; } sb.append(" from uid="); - UserHandle.formatUid(sb, mCallingUid); + UserHandle.formatUid(sb, getCallingUid()); sb.append(" pid="); - sb.append(mCallingPid); + sb.append(getCallingPid()); sb.append('}'); return sb.toString(); } @@ -1636,6 +1599,11 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch public void binderDied() { stopWatchingMode(mCallback); } + + @Override + public void onOpModeChanged(int op, int uid, String packageName) throws RemoteException { + mCallback.opChanged(op, uid, packageName); + } } final class ActiveCallback implements DeathRecipient { @@ -1804,7 +1772,14 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch public AppOpsService(File storagePath, Handler handler, Context context) { mContext = context; - mAppOpsServiceInterface = new LegacyAppOpsServiceInterfaceImpl(this, this); + + for (int switchedCode = 0; switchedCode < _NUM_OP; switchedCode++) { + int switchCode = AppOpsManager.opToSwitch(switchedCode); + mSwitchedOps.put(switchCode, + ArrayUtils.appendInt(mSwitchedOps.get(switchCode), switchedCode)); + } + mAppOpsServiceInterface = + new LegacyAppOpsServiceInterfaceImpl(this, this, handler, context, mSwitchedOps); LockGuard.installLock(this, LockGuard.INDEX_APP_OPS); mFile = new AtomicFile(storagePath, "appops"); @@ -1818,12 +1793,6 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch mHandler = handler; mConstants = new Constants(mHandler); readState(); - - for (int switchedCode = 0; switchedCode < _NUM_OP; switchedCode++) { - int switchCode = AppOpsManager.opToSwitch(switchedCode); - mSwitchedOps.put(switchCode, - ArrayUtils.appendInt(mSwitchedOps.get(switchCode), switchedCode)); - } } public void publish() { @@ -1982,20 +1951,20 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch final String[] changedPkgs = intent.getStringArrayExtra( Intent.EXTRA_CHANGED_PACKAGE_LIST); for (int code : OPS_RESTRICTED_ON_SUSPEND) { - ArraySet<ModeCallback> callbacks; + ArraySet<OnOpModeChangedListener> onModeChangedListeners; synchronized (AppOpsService.this) { - callbacks = mOpModeWatchers.get(code); - if (callbacks == null) { + onModeChangedListeners = + mAppOpsServiceInterface.getOpModeChangedListeners(code); + if (onModeChangedListeners == null) { continue; } - callbacks = new ArraySet<>(callbacks); } for (int i = 0; i < changedUids.length; i++) { final int changedUid = changedUids[i]; final String changedPkg = changedPkgs[i]; // We trust packagemanager to insert matching uid and packageNames in the // extras - notifyOpChanged(callbacks, code, changedUid, changedPkg); + notifyOpChanged(onModeChangedListeners, code, changedUid, changedPkg); } } } @@ -2596,7 +2565,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch if (!uidState.setUidMode(code, mode)) { return; } - uidState.evalForegroundOps(mOpModeWatchers); + uidState.evalForegroundOps(); if (mode != MODE_ERRORED && mode != previousMode) { updateStartedOpModeForUidLocked(code, mode == MODE_IGNORED, uid); } @@ -2615,78 +2584,10 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch */ private void notifyOpChangedForAllPkgsInUid(int code, int uid, boolean onlyForeground, @Nullable IAppOpsCallback callbackToIgnore) { - String[] uidPackageNames = getPackagesForUid(uid); - ArrayMap<ModeCallback, ArraySet<String>> callbackSpecs = null; - - synchronized (this) { - ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code); - if (callbacks != null) { - final int callbackCount = callbacks.size(); - for (int i = 0; i < callbackCount; i++) { - ModeCallback callback = callbacks.valueAt(i); - if (onlyForeground && (callback.mFlags & WATCH_FOREGROUND_CHANGES) == 0) { - continue; - } - - ArraySet<String> changedPackages = new ArraySet<>(); - Collections.addAll(changedPackages, uidPackageNames); - if (callbackSpecs == null) { - callbackSpecs = new ArrayMap<>(); - } - callbackSpecs.put(callback, changedPackages); - } - } - - for (String uidPackageName : uidPackageNames) { - callbacks = mPackageModeWatchers.get(uidPackageName); - if (callbacks != null) { - if (callbackSpecs == null) { - callbackSpecs = new ArrayMap<>(); - } - final int callbackCount = callbacks.size(); - for (int i = 0; i < callbackCount; i++) { - ModeCallback callback = callbacks.valueAt(i); - if (onlyForeground && (callback.mFlags & WATCH_FOREGROUND_CHANGES) == 0) { - continue; - } - - ArraySet<String> changedPackages = callbackSpecs.get(callback); - if (changedPackages == null) { - changedPackages = new ArraySet<>(); - callbackSpecs.put(callback, changedPackages); - } - changedPackages.add(uidPackageName); - } - } - } - - if (callbackSpecs != null && callbackToIgnore != null) { - callbackSpecs.remove(mModeWatchers.get(callbackToIgnore.asBinder())); - } - } - - if (callbackSpecs == null) { - return; - } - - for (int i = 0; i < callbackSpecs.size(); i++) { - final ModeCallback callback = callbackSpecs.keyAt(i); - final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i); - if (reportedPackageNames == null) { - mHandler.sendMessage(PooledLambda.obtainMessage( - AppOpsService::notifyOpChanged, - this, callback, code, uid, (String) null)); - - } else { - final int reportedPackageCount = reportedPackageNames.size(); - for (int j = 0; j < reportedPackageCount; j++) { - final String reportedPackageName = reportedPackageNames.valueAt(j); - mHandler.sendMessage(PooledLambda.obtainMessage( - AppOpsService::notifyOpChanged, - this, callback, code, uid, reportedPackageName)); - } - } - } + ModeCallback listenerToIgnore = callbackToIgnore != null + ? mModeWatchers.get(callbackToIgnore.asBinder()) : null; + mAppOpsServiceInterface.notifyOpChangedForAllPkgsInUid(code, uid, onlyForeground, + listenerToIgnore); } private void updatePermissionRevokedCompat(int uid, int switchCode, int mode) { @@ -2810,7 +2711,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch return; } - ArraySet<ModeCallback> repCbs = null; + ArraySet<OnOpModeChangedListener> repCbs = null; code = AppOpsManager.opToSwitch(code); PackageVerificationResult pvr; @@ -2831,16 +2732,17 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch op.setMode(mode); if (uidState != null) { - uidState.evalForegroundOps(mOpModeWatchers); + uidState.evalForegroundOps(); } - ArraySet<ModeCallback> cbs = mOpModeWatchers.get(code); + ArraySet<OnOpModeChangedListener> cbs = + mAppOpsServiceInterface.getOpModeChangedListeners(code); if (cbs != null) { if (repCbs == null) { repCbs = new ArraySet<>(); } repCbs.addAll(cbs); } - cbs = mPackageModeWatchers.get(packageName); + cbs = mAppOpsServiceInterface.getPackageModeChangedListeners(packageName); if (cbs != null) { if (repCbs == null) { repCbs = new ArraySet<>(); @@ -2871,47 +2773,17 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch notifyOpChangedSync(code, uid, packageName, mode, previousMode); } - private void notifyOpChanged(ArraySet<ModeCallback> callbacks, int code, + private void notifyOpChanged(ArraySet<OnOpModeChangedListener> callbacks, int code, int uid, String packageName) { for (int i = 0; i < callbacks.size(); i++) { - final ModeCallback callback = callbacks.valueAt(i); + final OnOpModeChangedListener callback = callbacks.valueAt(i); notifyOpChanged(callback, code, uid, packageName); } } - private void notifyOpChanged(ModeCallback callback, int code, + private void notifyOpChanged(OnOpModeChangedListener callback, int code, int uid, String packageName) { - if (uid != UID_ANY && callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) { - return; - } - - // See CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE - int[] switchedCodes; - if (callback.mWatchedOpCode == ALL_OPS) { - switchedCodes = mSwitchedOps.get(code); - } else if (callback.mWatchedOpCode == OP_NONE) { - switchedCodes = new int[]{code}; - } else { - switchedCodes = new int[]{callback.mWatchedOpCode}; - } - - for (int switchedCode : switchedCodes) { - // There are features watching for mode changes such as window manager - // and location manager which are in our process. The callbacks in these - // features may require permissions our remote caller does not have. - final long identity = Binder.clearCallingIdentity(); - try { - if (shouldIgnoreCallback(switchedCode, callback.mCallingPid, - callback.mCallingUid)) { - continue; - } - callback.mCallback.opChanged(switchedCode, uid, packageName); - } catch (RemoteException e) { - /* ignore */ - } finally { - Binder.restoreCallingIdentity(identity); - } - } + mAppOpsServiceInterface.notifyOpChanged(callback, code, uid, packageName); } private static ArrayList<ChangeRec> addChange(ArrayList<ChangeRec> reports, @@ -2936,9 +2808,10 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch return reports; } - private static HashMap<ModeCallback, ArrayList<ChangeRec>> addCallbacks( - HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks, - int op, int uid, String packageName, int previousMode, ArraySet<ModeCallback> cbs) { + private static HashMap<OnOpModeChangedListener, ArrayList<ChangeRec>> addCallbacks( + HashMap<OnOpModeChangedListener, ArrayList<ChangeRec>> callbacks, + int op, int uid, String packageName, int previousMode, + ArraySet<OnOpModeChangedListener> cbs) { if (cbs == null) { return callbacks; } @@ -2947,7 +2820,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch } final int N = cbs.size(); for (int i=0; i<N; i++) { - ModeCallback cb = cbs.valueAt(i); + OnOpModeChangedListener cb = cbs.valueAt(i); ArrayList<ChangeRec> reports = callbacks.get(cb); ArrayList<ChangeRec> changed = addChange(reports, op, uid, packageName, previousMode); if (changed != reports) { @@ -2990,7 +2863,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch enforceManageAppOpsModes(callingPid, callingUid, reqUid); - HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks = null; + HashMap<OnOpModeChangedListener, ArrayList<ChangeRec>> callbacks = null; ArrayList<ChangeRec> allChanges = new ArrayList<>(); synchronized (this) { boolean changed = false; @@ -3007,9 +2880,11 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch uidState.setUidMode(code, AppOpsManager.opToDefaultMode(code)); for (String packageName : getPackagesForUid(uidState.uid)) { callbacks = addCallbacks(callbacks, code, uidState.uid, packageName, - previousMode, mOpModeWatchers.get(code)); + previousMode, + mAppOpsServiceInterface.getOpModeChangedListeners(code)); callbacks = addCallbacks(callbacks, code, uidState.uid, packageName, - previousMode, mPackageModeWatchers.get(packageName)); + previousMode, mAppOpsServiceInterface + .getPackageModeChangedListeners(packageName)); allChanges = addChange(allChanges, code, uidState.uid, packageName, previousMode); @@ -3053,9 +2928,11 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch uidChanged = true; final int uid = curOp.uidState.uid; callbacks = addCallbacks(callbacks, curOp.op, uid, packageName, - previousMode, mOpModeWatchers.get(curOp.op)); + previousMode, + mAppOpsServiceInterface.getOpModeChangedListeners(curOp.op)); callbacks = addCallbacks(callbacks, curOp.op, uid, packageName, - previousMode, mPackageModeWatchers.get(packageName)); + previousMode, mAppOpsServiceInterface + .getPackageModeChangedListeners(packageName)); allChanges = addChange(allChanges, curOp.op, uid, packageName, previousMode); @@ -3075,7 +2952,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch mUidStates.remove(uidState.uid); } if (uidChanged) { - uidState.evalForegroundOps(mOpModeWatchers); + uidState.evalForegroundOps(); } } @@ -3084,8 +2961,9 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch } } if (callbacks != null) { - for (Map.Entry<ModeCallback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) { - ModeCallback cb = ent.getKey(); + for (Map.Entry<OnOpModeChangedListener, ArrayList<ChangeRec>> ent + : callbacks.entrySet()) { + OnOpModeChangedListener cb = ent.getKey(); ArrayList<ChangeRec> reports = ent.getValue(); for (int i=0; i<reports.size(); i++) { ChangeRec rep = reports.get(i); @@ -3121,7 +2999,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch for (int uidi = mUidStates.size() - 1; uidi >= 0; uidi--) { final UidState uidState = mUidStates.valueAt(uidi); if (uidState.foregroundOps != null) { - uidState.evalForegroundOps(mOpModeWatchers); + uidState.evalForegroundOps(); } } } @@ -3169,20 +3047,10 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch mModeWatchers.put(callback.asBinder(), cb); } if (switchOp != AppOpsManager.OP_NONE) { - ArraySet<ModeCallback> cbs = mOpModeWatchers.get(switchOp); - if (cbs == null) { - cbs = new ArraySet<>(); - mOpModeWatchers.put(switchOp, cbs); - } - cbs.add(cb); + mAppOpsServiceInterface.startWatchingOpModeChanged(cb, switchOp); } if (mayWatchPackageName) { - ArraySet<ModeCallback> cbs = mPackageModeWatchers.get(packageName); - if (cbs == null) { - cbs = new ArraySet<>(); - mPackageModeWatchers.put(packageName, cbs); - } - cbs.add(cb); + mAppOpsServiceInterface.startWatchingPackageModeChanged(cb, packageName); } evalAllForegroundOpsLocked(); } @@ -3197,21 +3065,9 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch ModeCallback cb = mModeWatchers.remove(callback.asBinder()); if (cb != null) { cb.unlinkToDeath(); - for (int i=mOpModeWatchers.size()-1; i>=0; i--) { - ArraySet<ModeCallback> cbs = mOpModeWatchers.valueAt(i); - cbs.remove(cb); - if (cbs.size() <= 0) { - mOpModeWatchers.removeAt(i); - } - } - for (int i=mPackageModeWatchers.size()-1; i>=0; i--) { - ArraySet<ModeCallback> cbs = mPackageModeWatchers.valueAt(i); - cbs.remove(cb); - if (cbs.size() <= 0) { - mPackageModeWatchers.removeAt(i); - } - } + mAppOpsServiceInterface.removeListener(cb); } + evalAllForegroundOpsLocked(); } } @@ -4542,12 +4398,14 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch AppOpsService::notifyOpChangedForAllPkgsInUid, this, code, uidState.uid, true, null)); } else if (uidState.pkgOps != null) { - final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code); - if (callbacks != null) { - for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) { - final ModeCallback callback = callbacks.valueAt(cbi); - if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0 - || !callback.isWatchingUid(uidState.uid)) { + final ArraySet<OnOpModeChangedListener> listenerSet = + mAppOpsServiceInterface.getOpModeChangedListeners(code); + if (listenerSet != null) { + for (int cbi = listenerSet.size() - 1; cbi >= 0; cbi--) { + final OnOpModeChangedListener listener = listenerSet.valueAt(cbi); + if ((listener.getFlags() + & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0 + || !listener.isWatchingUid(uidState.uid)) { continue; } for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) { @@ -4558,7 +4416,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch if (op.getMode() == AppOpsManager.MODE_FOREGROUND) { mHandler.sendMessage(PooledLambda.obtainMessage( AppOpsService::notifyOpChanged, - this, callback, code, uidState.uid, + this, listenerSet.valueAt(cbi), code, uidState.uid, uidState.pkgOps.keyAt(pkgi))); } } @@ -5045,7 +4903,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch } } if (changed) { - uidState.evalForegroundOps(mOpModeWatchers); + uidState.evalForegroundOps(); } } } @@ -5131,7 +4989,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch XmlUtils.skipCurrentTag(parser); } } - uidState.evalForegroundOps(mOpModeWatchers); + uidState.evalForegroundOps(); } private void readAttributionOp(TypedXmlPullParser parser, @NonNull Op parent, @@ -6122,62 +5980,17 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch } pw.println(); } - if (mOpModeWatchers.size() > 0 && !dumpHistory) { - boolean printedHeader = false; - for (int i=0; i<mOpModeWatchers.size(); i++) { - if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) { - continue; - } - boolean printedOpHeader = false; - ArraySet<ModeCallback> callbacks = mOpModeWatchers.valueAt(i); - for (int j=0; j<callbacks.size(); j++) { - final ModeCallback cb = callbacks.valueAt(j); - if (dumpPackage != null - && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) { - continue; - } - needSep = true; - if (!printedHeader) { - pw.println(" Op mode watchers:"); - printedHeader = true; - } - if (!printedOpHeader) { - pw.print(" Op "); - pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i))); - pw.println(":"); - printedOpHeader = true; - } - pw.print(" #"); pw.print(j); pw.print(": "); - pw.println(cb); - } - } - } - if (mPackageModeWatchers.size() > 0 && dumpOp < 0 && !dumpHistory) { - boolean printedHeader = false; - for (int i=0; i<mPackageModeWatchers.size(); i++) { - if (dumpPackage != null && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) { - continue; - } - needSep = true; - if (!printedHeader) { - pw.println(" Package mode watchers:"); - printedHeader = true; - } - pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i)); - pw.println(":"); - ArraySet<ModeCallback> callbacks = mPackageModeWatchers.valueAt(i); - for (int j=0; j<callbacks.size(); j++) { - pw.print(" #"); pw.print(j); pw.print(": "); - pw.println(callbacks.valueAt(j)); - } - } + + if (!dumpHistory) { + needSep |= mAppOpsServiceInterface.dumpListeners(dumpOp, dumpUid, dumpPackage, pw); } + if (mModeWatchers.size() > 0 && dumpOp < 0 && !dumpHistory) { boolean printedHeader = false; - for (int i=0; i<mModeWatchers.size(); i++) { + for (int i = 0; i < mModeWatchers.size(); i++) { final ModeCallback cb = mModeWatchers.valueAt(i); if (dumpPackage != null - && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) { + && dumpUid != UserHandle.getAppId(cb.getWatchingUid())) { continue; } needSep = true; @@ -6729,16 +6542,15 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch } private void notifyWatchersOfChange(int code, int uid) { - final ArraySet<ModeCallback> clonedCallbacks; + final ArraySet<OnOpModeChangedListener> modeChangedListenerSet; synchronized (this) { - ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code); - if (callbacks == null) { + modeChangedListenerSet = mAppOpsServiceInterface.getOpModeChangedListeners(code); + if (modeChangedListenerSet == null) { return; } - clonedCallbacks = new ArraySet<>(callbacks); } - notifyOpChanged(clonedCallbacks, code, uid, null); + notifyOpChanged(modeChangedListenerSet, code, uid, null); } @Override diff --git a/services/core/java/com/android/server/appop/AppOpsServiceInterface.java b/services/core/java/com/android/server/appop/AppOpsServiceInterface.java index cd5ea120f878..c707086fb2fb 100644 --- a/services/core/java/com/android/server/appop/AppOpsServiceInterface.java +++ b/services/core/java/com/android/server/appop/AppOpsServiceInterface.java @@ -14,12 +14,20 @@ * limitations under the License. */ package com.android.server.appop; + import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.AppOpsManager.Mode; +import android.util.ArraySet; +import android.util.SparseBooleanArray; import android.util.SparseIntArray; + +import java.io.PrintWriter; + /** * Interface for accessing and modifying modes for app-ops i.e. package and uid modes. - * In the future this interface will also include mode callbacks and op restrictions. + * This interface also includes functions for added and removing op mode watchers. + * In the future this interface will also include op restrictions. */ public interface AppOpsServiceInterface { /** @@ -95,4 +103,93 @@ public interface AppOpsServiceInterface { * Stop tracking app-op modes for all uid and packages. */ void clearAllModes(); + + /** + * Registers changedListener to listen to op's mode change. + * @param changedListener the listener that must be trigger on the op's mode change. + * @param op op representing the app-op whose mode change needs to be listened to. + */ + void startWatchingOpModeChanged(@NonNull OnOpModeChangedListener changedListener, int op); + + /** + * Registers changedListener to listen to package's app-op's mode change. + * @param changedListener the listener that must be trigger on the mode change. + * @param packageName of the package whose app-op's mode change needs to be listened to. + */ + void startWatchingPackageModeChanged(@NonNull OnOpModeChangedListener changedListener, + @NonNull String packageName); + + /** + * Stop the changedListener from triggering on any mode change. + * @param changedListener the listener that needs to be removed. + */ + void removeListener(@NonNull OnOpModeChangedListener changedListener); + + /** + * Temporary API which will be removed once we can safely untangle the methods that use this. + * Returns a set of OnOpModeChangedListener that are listening for op's mode changes. + * @param op app-op whose mode change is being listened to. + */ + ArraySet<OnOpModeChangedListener> getOpModeChangedListeners(int op); + + /** + * Temporary API which will be removed once we can safely untangle the methods that use this. + * Returns a set of OnOpModeChangedListener that are listening for package's op's mode changes. + * @param packageName of package whose app-op's mode change is being listened to. + */ + ArraySet<OnOpModeChangedListener> getPackageModeChangedListeners(@NonNull String packageName); + + /** + * Temporary API which will be removed once we can safely untangle the methods that use this. + * Notify that the app-op's mode is changed by triggering the change listener. + * @param changedListener the change listener. + * @param op App-op whose mode has changed + * @param uid user id associated with the app-op + * @param packageName package name that is associated with the app-op + */ + void notifyOpChanged(@NonNull OnOpModeChangedListener changedListener, int op, int uid, + @Nullable String packageName); + + /** + * Temporary API which will be removed once we can safely untangle the methods that use this. + * Notify that the app-op's mode is changed to all packages associated with the uid by + * triggering the appropriate change listener. + * @param op App-op whose mode has changed + * @param uid user id associated with the app-op + * @param onlyForeground true if only watchers that + * @param callbackToIgnore callback that should be ignored. + */ + void notifyOpChangedForAllPkgsInUid(int op, int uid, boolean onlyForeground, + @Nullable OnOpModeChangedListener callbackToIgnore); + + /** + * TODO: Move hasForegroundWatchers and foregroundOps into this. + * Go over the list of app-ops for the uid and mark app-ops with MODE_FOREGROUND in + * foregroundOps. + * @param uid for which the app-op's mode needs to be marked. + * @param foregroundOps boolean array where app-ops that have MODE_FOREGROUND are marked true. + * @return foregroundOps. + */ + SparseBooleanArray evalForegroundUidOps(int uid, SparseBooleanArray foregroundOps); + + /** + * Go over the list of app-ops for the package name and mark app-ops with MODE_FOREGROUND in + * foregroundOps. + * @param packageName for which the app-op's mode needs to be marked. + * @param foregroundOps boolean array where app-ops that have MODE_FOREGROUND are marked true. + * @return foregroundOps. + */ + SparseBooleanArray evalForegroundPackageOps(String packageName, + SparseBooleanArray foregroundOps); + + /** + * Dump op mode and package mode listeners and their details. + * @param dumpOp if -1 then op mode listeners for all app-ops are dumped. If it's set to an + * app-op, only the watchers for that app-op are dumped. + * @param dumpUid uid for which we want to dump op mode watchers. + * @param dumpPackage if not null and if dumpOp is -1, dumps watchers for the package name. + * @param printWriter writer to dump to. + */ + boolean dumpListeners(int dumpOp, int dumpUid, String dumpPackage, PrintWriter printWriter); + } diff --git a/services/core/java/com/android/server/appop/LegacyAppOpsServiceInterfaceImpl.java b/services/core/java/com/android/server/appop/LegacyAppOpsServiceInterfaceImpl.java index c27c0d3de5d7..2d498ea2117c 100644 --- a/services/core/java/com/android/server/appop/LegacyAppOpsServiceInterfaceImpl.java +++ b/services/core/java/com/android/server/appop/LegacyAppOpsServiceInterfaceImpl.java @@ -16,15 +16,39 @@ package com.android.server.appop; +import static android.app.AppOpsManager.OP_NONE; +import static android.app.AppOpsManager.WATCH_FOREGROUND_CHANGES; +import static android.app.AppOpsManager.opRestrictsRead; + +import static com.android.server.appop.AppOpsService.ModeCallback.ALL_OPS; + +import android.Manifest; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.AppOpsManager.Mode; +import android.content.Context; +import android.content.pm.PackageManager; +import android.os.Binder; +import android.os.Handler; +import android.os.RemoteException; +import android.os.UserHandle; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.SparseArray; +import android.util.SparseBooleanArray; import android.util.SparseIntArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.function.pooled.PooledLambda; + +import libcore.util.EmptyArray; + +import java.io.PrintWriter; +import java.util.Collections; +import java.util.Objects; /** @@ -33,8 +57,13 @@ import com.android.internal.annotations.VisibleForTesting; */ public class LegacyAppOpsServiceInterfaceImpl implements AppOpsServiceInterface { - // Should be the same object that the AppOpsService is using for locking. + static final String TAG = "LegacyAppOpsServiceInterfaceImpl"; + + // Must be the same object that the AppOpsService is using for locking. final Object mLock; + final Handler mHandler; + final Context mContext; + final SparseArray<int[]> mSwitchedOps; @GuardedBy("mLock") @VisibleForTesting @@ -43,13 +72,25 @@ public class LegacyAppOpsServiceInterfaceImpl implements AppOpsServiceInterface @GuardedBy("mLock") final ArrayMap<String, SparseIntArray> mPackageModes = new ArrayMap<>(); + final SparseArray<ArraySet<OnOpModeChangedListener>> mOpModeWatchers = new SparseArray<>(); + final ArrayMap<String, ArraySet<OnOpModeChangedListener>> mPackageModeWatchers = + new ArrayMap<>(); + final PersistenceScheduler mPersistenceScheduler; + // Constant meaning that any UID should be matched when dispatching callbacks + private static final int UID_ANY = -2; + + LegacyAppOpsServiceInterfaceImpl(PersistenceScheduler persistenceScheduler, - @NonNull Object lock) { + @NonNull Object lock, Handler handler, Context context, + SparseArray<int[]> switchedOps) { this.mPersistenceScheduler = persistenceScheduler; this.mLock = lock; + this.mHandler = handler; + this.mContext = context; + this.mSwitchedOps = switchedOps; } @Override @@ -158,7 +199,6 @@ public class LegacyAppOpsServiceInterfaceImpl implements AppOpsServiceInterface } } - @Override public boolean areUidModesDefault(int uid) { synchronized (mLock) { @@ -195,4 +235,335 @@ public class LegacyAppOpsServiceInterfaceImpl implements AppOpsServiceInterface } } -} + @Override + public void startWatchingOpModeChanged(@NonNull OnOpModeChangedListener changedListener, + int op) { + Objects.requireNonNull(changedListener); + synchronized (mLock) { + ArraySet<OnOpModeChangedListener> modeWatcherSet = mOpModeWatchers.get(op); + if (modeWatcherSet == null) { + modeWatcherSet = new ArraySet<>(); + mOpModeWatchers.put(op, modeWatcherSet); + } + modeWatcherSet.add(changedListener); + } + } + + @Override + public void startWatchingPackageModeChanged(@NonNull OnOpModeChangedListener changedListener, + @NonNull String packageName) { + Objects.requireNonNull(changedListener); + Objects.requireNonNull(packageName); + synchronized (mLock) { + ArraySet<OnOpModeChangedListener> modeWatcherSet = + mPackageModeWatchers.get(packageName); + if (modeWatcherSet == null) { + modeWatcherSet = new ArraySet<>(); + mPackageModeWatchers.put(packageName, modeWatcherSet); + } + modeWatcherSet.add(changedListener); + } + } + + @Override + public void removeListener(@NonNull OnOpModeChangedListener changedListener) { + Objects.requireNonNull(changedListener); + + synchronized (mLock) { + for (int i = mOpModeWatchers.size() - 1; i >= 0; i--) { + ArraySet<OnOpModeChangedListener> cbs = mOpModeWatchers.valueAt(i); + cbs.remove(changedListener); + if (cbs.size() <= 0) { + mOpModeWatchers.removeAt(i); + } + } + + for (int i = mPackageModeWatchers.size() - 1; i >= 0; i--) { + ArraySet<OnOpModeChangedListener> cbs = mPackageModeWatchers.valueAt(i); + cbs.remove(changedListener); + if (cbs.size() <= 0) { + mPackageModeWatchers.removeAt(i); + } + } + } + } + + @Override + public ArraySet<OnOpModeChangedListener> getOpModeChangedListeners(int op) { + synchronized (mLock) { + ArraySet<OnOpModeChangedListener> modeChangedListenersSet = mOpModeWatchers.get(op); + if (modeChangedListenersSet == null) { + return new ArraySet<>(); + } + return new ArraySet<>(modeChangedListenersSet); + } + } + + @Override + public ArraySet<OnOpModeChangedListener> getPackageModeChangedListeners( + @NonNull String packageName) { + Objects.requireNonNull(packageName); + + synchronized (mLock) { + ArraySet<OnOpModeChangedListener> modeChangedListenersSet = + mPackageModeWatchers.get(packageName); + if (modeChangedListenersSet == null) { + return new ArraySet<>(); + } + return new ArraySet<>(modeChangedListenersSet); + } + } + + @Override + public void notifyOpChanged(@NonNull OnOpModeChangedListener onModeChangedListener, int code, + int uid, @Nullable String packageName) { + Objects.requireNonNull(onModeChangedListener); + + if (uid != UID_ANY && onModeChangedListener.getWatchingUid() >= 0 + && onModeChangedListener.getWatchingUid() != uid) { + return; + } + + // See CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE + int[] switchedCodes; + if (onModeChangedListener.getWatchedOpCode() == ALL_OPS) { + switchedCodes = mSwitchedOps.get(code); + } else if (onModeChangedListener.getWatchedOpCode() == OP_NONE) { + switchedCodes = new int[]{code}; + } else { + switchedCodes = new int[]{onModeChangedListener.getWatchedOpCode()}; + } + + for (int switchedCode : switchedCodes) { + // There are features watching for mode changes such as window manager + // and location manager which are in our process. The callbacks in these + // features may require permissions our remote caller does not have. + final long identity = Binder.clearCallingIdentity(); + try { + if (shouldIgnoreCallback(switchedCode, onModeChangedListener.getCallingPid(), + onModeChangedListener.getCallingUid())) { + continue; + } + onModeChangedListener.onOpModeChanged(switchedCode, uid, packageName); + } catch (RemoteException e) { + /* ignore */ + } finally { + Binder.restoreCallingIdentity(identity); + } + } + } + + private boolean shouldIgnoreCallback(int op, int watcherPid, int watcherUid) { + // If it's a restricted read op, ignore it if watcher doesn't have manage ops permission, + // as watcher should not use this to signal if the value is changed. + return opRestrictsRead(op) && mContext.checkPermission(Manifest.permission.MANAGE_APPOPS, + watcherPid, watcherUid) != PackageManager.PERMISSION_GRANTED; + } + + @Override + public void notifyOpChangedForAllPkgsInUid(int code, int uid, boolean onlyForeground, + @Nullable OnOpModeChangedListener callbackToIgnore) { + String[] uidPackageNames = getPackagesForUid(uid); + ArrayMap<OnOpModeChangedListener, ArraySet<String>> callbackSpecs = null; + + synchronized (mLock) { + ArraySet<OnOpModeChangedListener> callbacks = mOpModeWatchers.get(code); + if (callbacks != null) { + final int callbackCount = callbacks.size(); + for (int i = 0; i < callbackCount; i++) { + OnOpModeChangedListener callback = callbacks.valueAt(i); + + if (onlyForeground && (callback.getFlags() + & WATCH_FOREGROUND_CHANGES) == 0) { + continue; + } + + ArraySet<String> changedPackages = new ArraySet<>(); + Collections.addAll(changedPackages, uidPackageNames); + if (callbackSpecs == null) { + callbackSpecs = new ArrayMap<>(); + } + callbackSpecs.put(callback, changedPackages); + } + } + + for (String uidPackageName : uidPackageNames) { + callbacks = mPackageModeWatchers.get(uidPackageName); + if (callbacks != null) { + if (callbackSpecs == null) { + callbackSpecs = new ArrayMap<>(); + } + final int callbackCount = callbacks.size(); + for (int i = 0; i < callbackCount; i++) { + OnOpModeChangedListener callback = callbacks.valueAt(i); + + if (onlyForeground && (callback.getFlags() + & WATCH_FOREGROUND_CHANGES) == 0) { + continue; + } + + ArraySet<String> changedPackages = callbackSpecs.get(callback); + if (changedPackages == null) { + changedPackages = new ArraySet<>(); + callbackSpecs.put(callback, changedPackages); + } + changedPackages.add(uidPackageName); + } + } + } + + if (callbackSpecs != null && callbackToIgnore != null) { + callbackSpecs.remove(callbackToIgnore); + } + } + + if (callbackSpecs == null) { + return; + } + + for (int i = 0; i < callbackSpecs.size(); i++) { + final OnOpModeChangedListener callback = callbackSpecs.keyAt(i); + final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i); + if (reportedPackageNames == null) { + mHandler.sendMessage(PooledLambda.obtainMessage( + LegacyAppOpsServiceInterfaceImpl::notifyOpChanged, + this, callback, code, uid, (String) null)); + + } else { + final int reportedPackageCount = reportedPackageNames.size(); + for (int j = 0; j < reportedPackageCount; j++) { + final String reportedPackageName = reportedPackageNames.valueAt(j); + mHandler.sendMessage(PooledLambda.obtainMessage( + LegacyAppOpsServiceInterfaceImpl::notifyOpChanged, + this, callback, code, uid, reportedPackageName)); + } + } + } + } + + private static String[] getPackagesForUid(int uid) { + String[] packageNames = null; + + // Very early during boot the package manager is not yet or not yet fully started. At this + // time there are no packages yet. + if (AppGlobals.getPackageManager() != null) { + try { + packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid); + } catch (RemoteException e) { + /* ignore - local call */ + } + } + if (packageNames == null) { + return EmptyArray.STRING; + } + return packageNames; + } + + @Override + public SparseBooleanArray evalForegroundUidOps(int uid, SparseBooleanArray foregroundOps) { + synchronized (mLock) { + return evalForegroundOps(mUidModes.get(uid), foregroundOps); + } + } + + @Override + public SparseBooleanArray evalForegroundPackageOps(String packageName, + SparseBooleanArray foregroundOps) { + synchronized (mLock) { + return evalForegroundOps(mPackageModes.get(packageName), foregroundOps); + } + } + + private SparseBooleanArray evalForegroundOps(SparseIntArray opModes, + SparseBooleanArray foregroundOps) { + SparseBooleanArray tempForegroundOps = foregroundOps; + if (opModes != null) { + for (int i = opModes.size() - 1; i >= 0; i--) { + if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) { + if (tempForegroundOps == null) { + tempForegroundOps = new SparseBooleanArray(); + } + evalForegroundWatchers(opModes.keyAt(i), tempForegroundOps); + } + } + } + return tempForegroundOps; + } + + private void evalForegroundWatchers(int op, SparseBooleanArray foregroundOps) { + boolean curValue = foregroundOps.get(op, false); + ArraySet<OnOpModeChangedListener> listenerSet = mOpModeWatchers.get(op); + if (listenerSet != null) { + for (int cbi = listenerSet.size() - 1; !curValue && cbi >= 0; cbi--) { + if ((listenerSet.valueAt(cbi).getFlags() + & AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) { + curValue = true; + } + } + } + foregroundOps.put(op, curValue); + } + + @Override + public boolean dumpListeners(int dumpOp, int dumpUid, String dumpPackage, + PrintWriter printWriter) { + boolean needSep = false; + if (mOpModeWatchers.size() > 0) { + boolean printedHeader = false; + for (int i = 0; i < mOpModeWatchers.size(); i++) { + if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) { + continue; + } + boolean printedOpHeader = false; + ArraySet<OnOpModeChangedListener> modeChangedListenerSet = + mOpModeWatchers.valueAt(i); + for (int j = 0; j < modeChangedListenerSet.size(); j++) { + final OnOpModeChangedListener listener = modeChangedListenerSet.valueAt(j); + if (dumpPackage != null + && dumpUid != UserHandle.getAppId(listener.getWatchingUid())) { + continue; + } + needSep = true; + if (!printedHeader) { + printWriter.println(" Op mode watchers:"); + printedHeader = true; + } + if (!printedOpHeader) { + printWriter.print(" Op "); + printWriter.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i))); + printWriter.println(":"); + printedOpHeader = true; + } + printWriter.print(" #"); printWriter.print(j); printWriter.print(": "); + printWriter.println(listener.toString()); + } + } + } + + if (mPackageModeWatchers.size() > 0 && dumpOp < 0) { + boolean printedHeader = false; + for (int i = 0; i < mPackageModeWatchers.size(); i++) { + if (dumpPackage != null + && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) { + continue; + } + needSep = true; + if (!printedHeader) { + printWriter.println(" Package mode watchers:"); + printedHeader = true; + } + printWriter.print(" Pkg "); printWriter.print(mPackageModeWatchers.keyAt(i)); + printWriter.println(":"); + ArraySet<OnOpModeChangedListener> modeChangedListenerSet = + mPackageModeWatchers.valueAt(i); + + for (int j = 0; j < modeChangedListenerSet.size(); j++) { + printWriter.print(" #"); printWriter.print(j); printWriter.print(": "); + printWriter.println(modeChangedListenerSet.valueAt(j).toString()); + } + } + } + return needSep; + } + +}
\ No newline at end of file diff --git a/services/core/java/com/android/server/appop/OnOpModeChangedListener.java b/services/core/java/com/android/server/appop/OnOpModeChangedListener.java new file mode 100644 index 000000000000..5ebe8119f046 --- /dev/null +++ b/services/core/java/com/android/server/appop/OnOpModeChangedListener.java @@ -0,0 +1,102 @@ +/* + * 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.server.appop; + +import android.os.RemoteException; + +/** + * Listener for mode changes, encapsulates methods that should be triggered in the event of a mode + * change. + */ +abstract class OnOpModeChangedListener { + + // Constant meaning that any UID should be matched when dispatching callbacks + private static final int UID_ANY = -2; + + private int mWatchingUid; + private int mFlags; + private int mWatchedOpCode; + private int mCallingUid; + private int mCallingPid; + + OnOpModeChangedListener(int watchingUid, int flags, int watchedOpCode, int callingUid, + int callingPid) { + this.mWatchingUid = watchingUid; + this.mFlags = flags; + this.mWatchedOpCode = watchedOpCode; + this.mCallingUid = callingUid; + this.mCallingPid = callingPid; + } + + /** + * Returns the user id that is watching for the mode change. + */ + public int getWatchingUid() { + return mWatchingUid; + } + + /** + * Returns the flags associated with the mode change listener. + */ + public int getFlags() { + return mFlags; + } + + /** + * Get the app-op whose mode change should trigger the callback. + */ + public int getWatchedOpCode() { + return mWatchedOpCode; + } + + /** + * Get the user-id that triggered the app-op mode change to be watched. + */ + public int getCallingUid() { + return mCallingUid; + } + + /** + * Get the process-id that triggered the app-op mode change to be watched. + */ + public int getCallingPid() { + return mCallingPid; + } + + /** + * returns true if the user id passed in the param is the one that is watching for op mode + * changed. + */ + public boolean isWatchingUid(int uid) { + return uid == UID_ANY || mWatchingUid < 0 || mWatchingUid == uid; + } + + /** + * Method that should be triggered when the app-op's mode is changed. + * @param op app-op whose mode-change is being listened to. + * @param uid user-is associated with the app-op. + * @param packageName package name associated with the app-op. + */ + public abstract void onOpModeChanged(int op, int uid, String packageName) + throws RemoteException; + + /** + * Return human readable string representing the listener. + */ + public abstract String toString(); + +} diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/BiometricServiceProvider.java new file mode 100644 index 000000000000..0f1fe68ad1d7 --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/BiometricServiceProvider.java @@ -0,0 +1,61 @@ +/* + * 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.server.biometrics.sensors; + +import android.annotation.NonNull; +import android.hardware.biometrics.SensorPropertiesInternal; +import android.util.proto.ProtoOutputStream; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.List; + +/** + * Common attributes for all biometric service providers. + * + * @param <T> Internal settings type. + */ +public interface BiometricServiceProvider<T extends SensorPropertiesInternal> { + + /** Checks if the specified sensor is owned by this provider. */ + boolean containsSensor(int sensorId); + + /** All sensor properties. */ + @NonNull + List<T> getSensorProperties(); + + /** Properties for the given sensor id. */ + @NonNull + T getSensorProperties(int sensorId); + + boolean isHardwareDetected(int sensorId); + + /** If the user has any enrollments for the given sensor. */ + boolean hasEnrollments(int sensorId, int userId); + + long getAuthenticatorId(int sensorId, int userId); + + @LockoutTracker.LockoutMode + int getLockoutModeForUser(int sensorId, int userId); + + void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto, + boolean clearSchedulerBuffer); + + void dumpProtoMetrics(int sensorId, @NonNull FileDescriptor fd); + + void dumpInternal(int sensorId, @NonNull PrintWriter pw); +} diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricServiceRegistry.java b/services/core/java/com/android/server/biometrics/sensors/BiometricServiceRegistry.java new file mode 100644 index 000000000000..4779f6f931ee --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/BiometricServiceRegistry.java @@ -0,0 +1,243 @@ +/* + * 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.server.biometrics.sensors; + + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.hardware.biometrics.IBiometricAuthenticator; +import android.hardware.biometrics.IBiometricService; +import android.hardware.biometrics.SensorPropertiesInternal; +import android.os.Handler; +import android.os.IInterface; +import android.os.Process; +import android.os.RemoteCallbackList; +import android.os.RemoteException; +import android.util.Pair; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.ServiceThread; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.Supplier; + +/** + * Container for all BiometricServiceProvider implementations. + * + * @param <T> The service provider type. + * @param <P> The internal properties type. + * @param <C> The registration callback for {@link #invokeRegisteredCallback(IInterface, List)}. + */ +public abstract class BiometricServiceRegistry<T extends BiometricServiceProvider<P>, + P extends SensorPropertiesInternal, + C extends IInterface> { + + private static final String TAG = "BiometricServiceRegistry"; + + // Volatile so they can be read without a lock once all services are registered. + // But, ideally remove this and provide immutable copies via the callback instead. + @Nullable + private volatile List<T> mServiceProviders; + @Nullable + private volatile List<P> mAllProps; + + @NonNull + private final Supplier<IBiometricService> mBiometricServiceSupplier; + @NonNull + private final RemoteCallbackList<C> mRegisteredCallbacks = new RemoteCallbackList<>(); + + public BiometricServiceRegistry(@NonNull Supplier<IBiometricService> biometricSupplier) { + mBiometricServiceSupplier = biometricSupplier; + } + + /** + * Register an implementation by creating a new authenticator and initializing it via + * {@link IBiometricService#registerAuthenticator(int, int, int, IBiometricAuthenticator)} + * using the given properties. + * + * @param service service to register with + * @param props internal properties to initialize the authenticator + */ + protected abstract void registerService(@NonNull IBiometricService service, @NonNull P props); + + /** + * Invoke the callback to notify clients that all authenticators have been registered. + * + * @param callback callback to invoke + * @param allProps properties of all authenticators + */ + protected abstract void invokeRegisteredCallback(@NonNull C callback, + @NonNull List<P> allProps) throws RemoteException; + + /** + * Register all authenticators in a background thread. + * + * @param serviceProvider Supplier function that will be invoked on the background thread. + */ + public void registerAll(Supplier<List<T>> serviceProvider) { + // Some HAL might not be started before the system service and will cause the code below + // to wait, and some of the operations below might take a significant amount of time to + // complete (calls to the HALs). To avoid blocking the rest of system server we put + // this on a background thread. + final ServiceThread thread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, + true /* allowIo */); + thread.start(); + final Handler handler = new Handler(thread.getLooper()); + handler.post(() -> registerAllInBackground(serviceProvider)); + thread.quitSafely(); + } + + /** Register authenticators now, only called by {@link #registerAll(Supplier).} */ + @VisibleForTesting + public void registerAllInBackground(Supplier<List<T>> serviceProvider) { + List<T> providers = serviceProvider.get(); + if (providers == null) { + providers = new ArrayList<>(); + } + + final IBiometricService biometricService = mBiometricServiceSupplier.get(); + if (biometricService == null) { + throw new IllegalStateException("biometric service cannot be null"); + } + + // Register each sensor individually with BiometricService + final List<P> allProps = new ArrayList<>(); + for (T provider : providers) { + final List<P> props = provider.getSensorProperties(); + for (P prop : props) { + registerService(biometricService, prop); + } + allProps.addAll(props); + } + + finishRegistration(providers, allProps); + } + + private synchronized void finishRegistration( + @NonNull List<T> providers, @NonNull List<P> allProps) { + mServiceProviders = Collections.unmodifiableList(providers); + mAllProps = Collections.unmodifiableList(allProps); + broadcastAllAuthenticatorsRegistered(); + } + + /** + * Add a callback that will be invoked once the work from {@link #registerAll(Supplier)} + * has finished registering all providers (executes immediately if already done). + * + * @param callback registration callback + */ + public synchronized void addAllRegisteredCallback(@Nullable C callback) { + if (callback == null) { + Slog.e(TAG, "addAllRegisteredCallback, callback is null"); + return; + } + + final boolean registered = mRegisteredCallbacks.register(callback); + final boolean allRegistered = mServiceProviders != null; + if (registered && allRegistered) { + broadcastAllAuthenticatorsRegistered(); + } else if (!registered) { + Slog.e(TAG, "addAllRegisteredCallback failed to register callback"); + } + } + + private synchronized void broadcastAllAuthenticatorsRegistered() { + final int n = mRegisteredCallbacks.beginBroadcast(); + for (int i = 0; i < n; ++i) { + final C cb = mRegisteredCallbacks.getBroadcastItem(i); + try { + invokeRegisteredCallback(cb, mAllProps); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception in broadcastAllAuthenticatorsRegistered", e); + } finally { + mRegisteredCallbacks.unregister(cb); + } + } + mRegisteredCallbacks.finishBroadcast(); + } + + /** + * Get a list of registered providers. + * + * Undefined until {@link #registerAll(Supplier)} has fired the completion callback. + */ + @NonNull + public List<T> getProviders() { + return mServiceProviders != null ? mServiceProviders : Collections.emptyList(); + } + + /** + * Gets the provider for given sensor id or null if not registered. + * + * Undefined until {@link #registerAll(Supplier)} has fired the completion callback. + */ + @Nullable + public T getProviderForSensor(int sensorId) { + if (mServiceProviders != null) { + for (T provider : mServiceProviders) { + if (provider.containsSensor(sensorId)) { + return provider; + } + } + } + return null; + } + + /** + * Finds the provider for devices with only a single sensor. + * + * If no providers returns null. If multiple sensors are present this method + * will return the first one that is found (this is a legacy for test devices that + * use aidl/hidl concurrently and should not occur on real devices). + * + * Undefined until {@link #registerAll(Supplier)} has fired the completion callback. + */ + @Nullable + public Pair<Integer, T> getSingleProvider() { + if (mAllProps == null || mAllProps.isEmpty()) { + Slog.e(TAG, "No sensors found"); + return null; + } + + if (mAllProps.size() > 1) { + Slog.e(TAG, "getSingleProvider() called but multiple sensors present: " + + mAllProps.size()); + } + + final int sensorId = mAllProps.get(0).sensorId; + final T provider = getProviderForSensor(sensorId); + if (provider != null) { + return new Pair<>(sensorId, provider); + } + + Slog.e(TAG, "Single sensor: " + sensorId + ", but provider not found"); + return null; + } + + /** + * Get the properties for all providers. + * + * Undefined until {@link #registerAll(Supplier)} has fired the completion callback. + */ + @NonNull + public List<P> getAllProperties() { + return mAllProps != null ? mAllProps : Collections.emptyList(); + } +} diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricStateCallback.java b/services/core/java/com/android/server/biometrics/sensors/BiometricStateCallback.java index 0d789f7a1840..f8543162f95e 100644 --- a/services/core/java/com/android/server/biometrics/sensors/BiometricStateCallback.java +++ b/services/core/java/com/android/server/biometrics/sensors/BiometricStateCallback.java @@ -23,32 +23,64 @@ import static android.hardware.biometrics.BiometricStateListener.STATE_IDLE; import static android.hardware.biometrics.BiometricStateListener.STATE_KEYGUARD_AUTH; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.pm.UserInfo; import android.hardware.biometrics.BiometricStateListener; import android.hardware.biometrics.IBiometricStateListener; +import android.hardware.biometrics.SensorPropertiesInternal; import android.os.RemoteException; +import android.os.UserManager; import android.util.Slog; import com.android.server.biometrics.Utils; +import java.util.Collections; +import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; /** * A callback for receiving notifications about biometric sensor state changes. + * + * @param <T> service provider type + * @param <P> internal property type */ -public class BiometricStateCallback implements ClientMonitorCallback { +public class BiometricStateCallback<T extends BiometricServiceProvider<P>, + P extends SensorPropertiesInternal> implements ClientMonitorCallback { private static final String TAG = "BiometricStateCallback"; @NonNull - private final CopyOnWriteArrayList<IBiometricStateListener> - mBiometricStateListeners = new CopyOnWriteArrayList<>(); - - private @BiometricStateListener.State int mBiometricState; + private final CopyOnWriteArrayList<IBiometricStateListener> mBiometricStateListeners = + new CopyOnWriteArrayList<>(); + @NonNull + private final UserManager mUserManager; + @BiometricStateListener.State + private int mBiometricState; + @NonNull + private List<T> mProviders = List.of(); - public BiometricStateCallback() { + /** + * Create a new callback that must be {@link #start(List)}ed. + * + * @param userManager user manager + */ + public BiometricStateCallback(@NonNull UserManager userManager) { mBiometricState = STATE_IDLE; + mUserManager = userManager; + } + + /** + * This should be called when the service has been initialized and all providers are ready. + * + * @param allProviders all registered biometric service providers + */ + public synchronized void start(@NonNull List<T> allProviders) { + mProviders = Collections.unmodifiableList(allProviders); + broadcastCurrentEnrollmentState(null /* listener */); } + /** Get the current state. */ + @BiometricStateListener.State public int getBiometricState() { return mBiometricState; } @@ -120,23 +152,43 @@ public class BiometricStateCallback implements ClientMonitorCallback { } /** - * This should be invoked when: - * 1) Enrolled --> None-enrolled - * 2) None-enrolled --> enrolled - * 3) HAL becomes ready - * 4) Listener is registered + * Enables clients to register a BiometricStateListener. For example, this is used to forward + * fingerprint sensor state changes to SideFpsEventHandler. + * + * @param listener listener to register */ - public void notifyAllEnrollmentStateChanged(int userId, int sensorId, + public synchronized void registerBiometricStateListener( + @NonNull IBiometricStateListener listener) { + mBiometricStateListeners.add(listener); + broadcastCurrentEnrollmentState(listener); + } + + private synchronized void broadcastCurrentEnrollmentState( + @Nullable IBiometricStateListener listener) { + for (T provider : mProviders) { + for (SensorPropertiesInternal prop : provider.getSensorProperties()) { + for (UserInfo userInfo : mUserManager.getAliveUsers()) { + final boolean enrolled = provider.hasEnrollments(prop.sensorId, userInfo.id); + if (listener != null) { + notifyEnrollmentStateChanged( + listener, userInfo.id, prop.sensorId, enrolled); + } else { + notifyAllEnrollmentStateChanged( + userInfo.id, prop.sensorId, enrolled); + } + } + } + } + } + + private void notifyAllEnrollmentStateChanged(int userId, int sensorId, boolean hasEnrollments) { for (IBiometricStateListener listener : mBiometricStateListeners) { notifyEnrollmentStateChanged(listener, userId, sensorId, hasEnrollments); } } - /** - * Notifies the listener of enrollment state changes. - */ - public void notifyEnrollmentStateChanged(@NonNull IBiometricStateListener listener, + private void notifyEnrollmentStateChanged(@NonNull IBiometricStateListener listener, int userId, int sensorId, boolean hasEnrollments) { try { listener.onEnrollmentsChanged(userId, sensorId, hasEnrollments); @@ -144,14 +196,4 @@ public class BiometricStateCallback implements ClientMonitorCallback { Slog.e(TAG, "Remote exception", e); } } - - /** - * Enables clients to register a BiometricStateListener. For example, this is used to forward - * fingerprint sensor state changes to SideFpsEventHandler. - * - * @param listener - */ - public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) { - mBiometricStateListeners.add(listener); - } } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java index 79e65cc6d2e5..271bce9890c6 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java @@ -17,20 +17,18 @@ package com.android.server.biometrics.sensors.face; import static android.Manifest.permission.INTERACT_ACROSS_USERS; -import static android.Manifest.permission.MANAGE_BIOMETRIC; import static android.Manifest.permission.MANAGE_FACE; import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL; -import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.content.Context; -import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.biometrics.IBiometricSensorReceiver; import android.hardware.biometrics.IBiometricService; import android.hardware.biometrics.IBiometricServiceLockoutResetCallback; +import android.hardware.biometrics.IBiometricStateListener; import android.hardware.biometrics.IInvalidationCallback; import android.hardware.biometrics.ITestSession; import android.hardware.biometrics.ITestSessionCallback; @@ -39,18 +37,18 @@ import android.hardware.biometrics.face.SensorProps; import android.hardware.face.Face; import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.face.FaceServiceReceiver; +import android.hardware.face.IFaceAuthenticatorsRegisteredCallback; import android.hardware.face.IFaceService; import android.hardware.face.IFaceServiceReceiver; import android.os.Binder; -import android.os.Handler; import android.os.IBinder; import android.os.NativeHandle; -import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; import android.os.ShellCallback; import android.os.UserHandle; +import android.os.UserManager; import android.util.Pair; import android.util.Slog; import android.util.proto.ProtoOutputStream; @@ -58,10 +56,10 @@ import android.view.Surface; import com.android.internal.util.DumpUtils; import com.android.internal.widget.LockPatternUtils; -import com.android.server.ServiceThread; import com.android.server.SystemService; import com.android.server.biometrics.Utils; import com.android.server.biometrics.log.BiometricContext; +import com.android.server.biometrics.sensors.BiometricStateCallback; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; import com.android.server.biometrics.sensors.LockoutResetDispatcher; import com.android.server.biometrics.sensors.LockoutTracker; @@ -88,51 +86,10 @@ public class FaceService extends SystemService { private final LockoutResetDispatcher mLockoutResetDispatcher; private final LockPatternUtils mLockPatternUtils; @NonNull - private final List<ServiceProvider> mServiceProviders; - - @Nullable - private ServiceProvider getProviderForSensor(int sensorId) { - for (ServiceProvider provider : mServiceProviders) { - if (provider.containsSensor(sensorId)) { - return provider; - } - } - return null; - } - - /** - * For devices with only a single provider, returns that provider. If no providers, or multiple - * providers exist, returns null. - */ - @Nullable - private Pair<Integer, ServiceProvider> getSingleProvider() { - final List<FaceSensorPropertiesInternal> properties = getSensorProperties(); - if (properties.size() != 1) { - Slog.e(TAG, "Multiple sensors found: " + properties.size()); - return null; - } - - // Theoretically we can just return the first provider, but maybe this is easier to - // understand. - final int sensorId = properties.get(0).sensorId; - for (ServiceProvider provider : mServiceProviders) { - if (provider.containsSensor(sensorId)) { - return new Pair<>(sensorId, provider); - } - } - - Slog.e(TAG, "Single sensor, but provider not found"); - return null; - } - + private final FaceServiceRegistry mRegistry; @NonNull - private List<FaceSensorPropertiesInternal> getSensorProperties() { - final List<FaceSensorPropertiesInternal> properties = new ArrayList<>(); - for (ServiceProvider provider : mServiceProviders) { - properties.addAll(provider.getSensorProperties()); - } - return properties; - } + private final BiometricStateCallback<ServiceProvider, FaceSensorPropertiesInternal> + mBiometricStateCallback; /** * Receives the incoming binder calls from FaceManager. @@ -142,8 +99,7 @@ public class FaceService extends SystemService { @Override public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback, @NonNull String opPackageName) { - - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "Null provider for createTestSession, sensorId: " + sensorId); @@ -156,9 +112,8 @@ public class FaceService extends SystemService { @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override public byte[] dumpSensorServiceStateProto(int sensorId, boolean clearSchedulerBuffer) { - final ProtoOutputStream proto = new ProtoOutputStream(); - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider != null) { provider.dumpProtoState(sensorId, proto, clearSchedulerBuffer); } @@ -170,16 +125,14 @@ public class FaceService extends SystemService { @Override // Binder call public List<FaceSensorPropertiesInternal> getSensorPropertiesInternal( String opPackageName) { - - return FaceService.this.getSensorProperties(); + return mRegistry.getAllProperties(); } @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override // Binder call public FaceSensorPropertiesInternal getSensorProperties(int sensorId, @NonNull String opPackageName) { - - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "No matching sensor for getSensorProperties, sensorId: " + sensorId + ", caller: " + opPackageName); @@ -193,8 +146,7 @@ public class FaceService extends SystemService { @Override // Binder call public void generateChallenge(IBinder token, int sensorId, int userId, IFaceServiceReceiver receiver, String opPackageName) { - - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "No matching sensor for generateChallenge, sensorId: " + sensorId); return; @@ -207,8 +159,7 @@ public class FaceService extends SystemService { @Override // Binder call public void revokeChallenge(IBinder token, int sensorId, int userId, String opPackageName, long challenge) { - - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "No matching sensor for revokeChallenge, sensorId: " + sensorId); return; @@ -222,8 +173,7 @@ public class FaceService extends SystemService { public long enroll(int userId, final IBinder token, final byte[] hardwareAuthToken, final IFaceServiceReceiver receiver, final String opPackageName, final int[] disabledFeatures, Surface previewSurface, boolean debugConsent) { - - final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider(); if (provider == null) { Slog.w(TAG, "Null provider for enroll"); return -1; @@ -245,8 +195,7 @@ public class FaceService extends SystemService { @android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_BIOMETRIC) @Override // Binder call public void cancelEnrollment(final IBinder token, long requestId) { - - final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider(); if (provider == null) { Slog.w(TAG, "Null provider for cancelEnrollment"); return; @@ -260,7 +209,6 @@ public class FaceService extends SystemService { public long authenticate(final IBinder token, final long operationId, int userId, final IFaceServiceReceiver receiver, final String opPackageName, boolean isKeyguardBypassEnabled) { - // TODO(b/152413782): If the sensor supports face detect and the device is encrypted or // lockdown, something wrong happened. See similar path in FingerprintService. @@ -273,7 +221,7 @@ public class FaceService extends SystemService { // permission. final boolean isKeyguard = Utils.isKeyguard(getContext(), opPackageName); - final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider(); if (provider == null) { Slog.w(TAG, "Null provider for authenticate"); return -1; @@ -301,7 +249,7 @@ public class FaceService extends SystemService { return -1; } - final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider(); if (provider == null) { Slog.w(TAG, "Null provider for detectFace"); return -1; @@ -318,8 +266,7 @@ public class FaceService extends SystemService { IBinder token, long operationId, int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication) { - - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "Null provider for prepareForAuthentication"); return; @@ -336,8 +283,7 @@ public class FaceService extends SystemService { @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override // Binder call public void startPreparedClient(int sensorId, int cookie) { - - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "Null provider for startPreparedClient"); return; @@ -350,8 +296,7 @@ public class FaceService extends SystemService { @Override // Binder call public void cancelAuthentication(final IBinder token, final String opPackageName, final long requestId) { - - final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider(); if (provider == null) { Slog.w(TAG, "Null provider for cancelAuthentication"); return; @@ -370,7 +315,7 @@ public class FaceService extends SystemService { return; } - final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider(); if (provider == null) { Slog.w(TAG, "Null provider for cancelFaceDetect"); return; @@ -383,8 +328,7 @@ public class FaceService extends SystemService { @Override // Binder call public void cancelAuthenticationFromService(int sensorId, final IBinder token, final String opPackageName, final long requestId) { - - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "Null provider for cancelAuthenticationFromService"); return; @@ -397,8 +341,7 @@ public class FaceService extends SystemService { @Override // Binder call public void remove(final IBinder token, final int faceId, final int userId, final IFaceServiceReceiver receiver, final String opPackageName) { - - final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider(); if (provider == null) { Slog.w(TAG, "Null provider for remove"); return; @@ -412,7 +355,6 @@ public class FaceService extends SystemService { @Override // Binder call public void removeAll(final IBinder token, final int userId, final IFaceServiceReceiver receiver, final String opPackageName) { - final FaceServiceReceiver internalReceiver = new FaceServiceReceiver() { int sensorsFinishedRemoving = 0; final int numSensors = getSensorPropertiesInternal( @@ -432,7 +374,7 @@ public class FaceService extends SystemService { // This effectively iterates through all sensors, but has to do so by finding all // sensors under each provider. - for (ServiceProvider provider : mServiceProviders) { + for (ServiceProvider provider : mRegistry.getProviders()) { List<FaceSensorPropertiesInternal> props = provider.getSensorProperties(); for (FaceSensorPropertiesInternal prop : props) { provider.scheduleRemoveAll(prop.sensorId, token, userId, internalReceiver, @@ -467,27 +409,27 @@ public class FaceService extends SystemService { try { if (args.length > 1 && "--proto".equals(args[0]) && "--state".equals(args[1])) { final ProtoOutputStream proto = new ProtoOutputStream(fd); - for (ServiceProvider provider : mServiceProviders) { + for (ServiceProvider provider : mRegistry.getProviders()) { for (FaceSensorPropertiesInternal props : provider.getSensorProperties()) { provider.dumpProtoState(props.sensorId, proto, false); } } proto.flush(); } else if (args.length > 0 && "--proto".equals(args[0])) { - for (ServiceProvider provider : mServiceProviders) { + for (ServiceProvider provider : mRegistry.getProviders()) { for (FaceSensorPropertiesInternal props : provider.getSensorProperties()) { provider.dumpProtoMetrics(props.sensorId, fd); } } } else if (args.length > 1 && "--hal".equals(args[0])) { - for (ServiceProvider provider : mServiceProviders) { + for (ServiceProvider provider : mRegistry.getProviders()) { for (FaceSensorPropertiesInternal props : provider.getSensorProperties()) { provider.dumpHal(props.sensorId, fd, Arrays.copyOfRange(args, 1, args.length, args.getClass())); } } } else { - for (ServiceProvider provider : mServiceProviders) { + for (ServiceProvider provider : mRegistry.getProviders()) { for (FaceSensorPropertiesInternal props : provider.getSensorProperties()) { pw.println("Dumping for sensorId: " + props.sensorId + ", provider: " + provider.getClass().getSimpleName()); @@ -504,10 +446,9 @@ public class FaceService extends SystemService { @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override // Binder call public boolean isHardwareDetected(int sensorId, String opPackageName) { - final long token = Binder.clearCallingIdentity(); try { - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "Null provider for isHardwareDetected, caller: " + opPackageName); return false; @@ -521,12 +462,11 @@ public class FaceService extends SystemService { @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override // Binder call public List<Face> getEnrolledFaces(int sensorId, int userId, String opPackageName) { - if (userId != UserHandle.getCallingUserId()) { Utils.checkPermission(getContext(), INTERACT_ACROSS_USERS); } - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "Null provider for getEnrolledFaces, caller: " + opPackageName); return Collections.emptyList(); @@ -538,12 +478,11 @@ public class FaceService extends SystemService { @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override // Binder call public boolean hasEnrolledFaces(int sensorId, int userId, String opPackageName) { - if (userId != UserHandle.getCallingUserId()) { Utils.checkPermission(getContext(), INTERACT_ACROSS_USERS); } - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "Null provider for hasEnrolledFaces, caller: " + opPackageName); return false; @@ -555,8 +494,7 @@ public class FaceService extends SystemService { @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override // Binder call public @LockoutTracker.LockoutMode int getLockoutModeForUser(int sensorId, int userId) { - - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "Null provider for getLockoutModeForUser"); return LockoutTracker.LOCKOUT_NONE; @@ -569,8 +507,7 @@ public class FaceService extends SystemService { @Override public void invalidateAuthenticatorId(int sensorId, int userId, IInvalidationCallback callback) { - - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "Null provider for invalidateAuthenticatorId"); return; @@ -582,7 +519,7 @@ public class FaceService extends SystemService { @Override // Binder call public long getAuthenticatorId(int sensorId, int userId) { - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "Null provider for getAuthenticatorId"); return 0; @@ -595,8 +532,7 @@ public class FaceService extends SystemService { @Override // Binder call public void resetLockout(IBinder token, int sensorId, int userId, byte[] hardwareAuthToken, String opPackageName) { - - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "Null provider for resetLockout, caller: " + opPackageName); return; @@ -610,8 +546,7 @@ public class FaceService extends SystemService { public void setFeature(final IBinder token, int userId, int feature, boolean enabled, final byte[] hardwareAuthToken, IFaceServiceReceiver receiver, final String opPackageName) { - - final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider(); if (provider == null) { Slog.w(TAG, "Null provider for setFeature"); return; @@ -625,8 +560,7 @@ public class FaceService extends SystemService { @Override public void getFeature(final IBinder token, int userId, int feature, IFaceServiceReceiver receiver, final String opPackageName) { - - final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider(); if (provider == null) { Slog.w(TAG, "Null provider for getFeature"); return; @@ -636,18 +570,14 @@ public class FaceService extends SystemService { new ClientMonitorCallbackConverter(receiver), opPackageName); } - private void addHidlProviders(@NonNull List<FaceSensorPropertiesInternal> hidlSensors) { - for (FaceSensorPropertiesInternal hidlSensor : hidlSensors) { - mServiceProviders.add( - Face10.newInstance(getContext(), hidlSensor, mLockoutResetDispatcher)); - } - } + private List<ServiceProvider> getAidlProviders() { + final List<ServiceProvider> providers = new ArrayList<>(); - private void addAidlProviders() { final String[] instances = ServiceManager.getDeclaredInstances(IFace.DESCRIPTOR); if (instances == null || instances.length == 0) { - return; + return providers; } + for (String instance : instances) { final String fqName = IFace.DESCRIPTOR + "/" + instance; final IFace face = IFace.Stub.asInterface( @@ -660,53 +590,41 @@ public class FaceService extends SystemService { final SensorProps[] props = face.getSensorProps(); final FaceProvider provider = new FaceProvider(getContext(), props, instance, mLockoutResetDispatcher, BiometricContext.getInstance(getContext())); - mServiceProviders.add(provider); + providers.add(provider); } catch (RemoteException e) { Slog.e(TAG, "Remote exception in getSensorProps: " + fqName); } } + + return providers; } @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override // Binder call public void registerAuthenticators( @NonNull List<FaceSensorPropertiesInternal> hidlSensors) { - - // Some HAL might not be started before the system service and will cause the code below - // to wait, and some of the operations below might take a significant amount of time to - // complete (calls to the HALs). To avoid blocking the rest of system server we put - // this on a background thread. - final ServiceThread thread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, - true /* allowIo */); - thread.start(); - final Handler handler = new Handler(thread.getLooper()); - - handler.post(() -> { - addHidlProviders(hidlSensors); - addAidlProviders(); - - final IBiometricService biometricService = IBiometricService.Stub.asInterface( - ServiceManager.getService(Context.BIOMETRIC_SERVICE)); - - // Register each sensor individually with BiometricService - for (ServiceProvider provider : mServiceProviders) { - final List<FaceSensorPropertiesInternal> props = provider.getSensorProperties(); - for (FaceSensorPropertiesInternal prop : props) { - final int sensorId = prop.sensorId; - final @BiometricManager.Authenticators.Types int strength = - Utils.propertyStrengthToAuthenticatorStrength(prop.sensorStrength); - final FaceAuthenticator authenticator = new FaceAuthenticator( - mServiceWrapper, sensorId); - try { - biometricService.registerAuthenticator(sensorId, TYPE_FACE, strength, - authenticator); - } catch (RemoteException e) { - Slog.e(TAG, "Remote exception when registering sensorId: " + sensorId); - } - } + mRegistry.registerAll(() -> { + final List<ServiceProvider> providers = new ArrayList<>(); + for (FaceSensorPropertiesInternal hidlSensor : hidlSensors) { + providers.add( + Face10.newInstance(getContext(), hidlSensor, mLockoutResetDispatcher)); } + providers.addAll(getAidlProviders()); + return providers; }); } + + @Override + public void addAuthenticatorsRegisteredCallback( + IFaceAuthenticatorsRegisteredCallback callback) { + Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); + mRegistry.addAllRegisteredCallback(callback); + } + + @Override + public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) { + mBiometricStateCallback.registerBiometricStateListener(listener); + } } public FaceService(Context context) { @@ -714,7 +632,16 @@ public class FaceService extends SystemService { mServiceWrapper = new FaceServiceWrapper(); mLockoutResetDispatcher = new LockoutResetDispatcher(context); mLockPatternUtils = new LockPatternUtils(context); - mServiceProviders = new ArrayList<>(); + mBiometricStateCallback = new BiometricStateCallback<>(UserManager.get(context)); + mRegistry = new FaceServiceRegistry(mServiceWrapper, + () -> IBiometricService.Stub.asInterface( + ServiceManager.getService(Context.BIOMETRIC_SERVICE))); + mRegistry.addAllRegisteredCallback(new IFaceAuthenticatorsRegisteredCallback.Stub() { + @Override + public void onAllAuthenticatorsRegistered(List<FaceSensorPropertiesInternal> sensors) { + mBiometricStateCallback.start(mRegistry.getProviders()); + } + }); } @Override @@ -752,7 +679,7 @@ public class FaceService extends SystemService { if (Utils.isVirtualEnabled(getContext())) { Slog.i(TAG, "Sync virtual enrollments"); final int userId = ActivityManager.getCurrentUser(); - for (ServiceProvider provider : mServiceProviders) { + for (ServiceProvider provider : mRegistry.getProviders()) { for (FaceSensorPropertiesInternal props : provider.getSensorProperties()) { provider.scheduleInternalCleanup(props.sensorId, userId, null /* callback */, true /* favorHalEnrollments */); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceServiceRegistry.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceServiceRegistry.java new file mode 100644 index 000000000000..0f0a81d24473 --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceServiceRegistry.java @@ -0,0 +1,71 @@ +/* + * 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.server.biometrics.sensors.face; + +import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.hardware.biometrics.BiometricManager; +import android.hardware.biometrics.IBiometricService; +import android.hardware.face.FaceSensorPropertiesInternal; +import android.hardware.face.IFaceAuthenticatorsRegisteredCallback; +import android.hardware.face.IFaceService; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.server.biometrics.Utils; +import com.android.server.biometrics.sensors.BiometricServiceRegistry; + +import java.util.List; +import java.util.function.Supplier; + +/** Registry for {@link IFaceService} providers. */ +public class FaceServiceRegistry extends BiometricServiceRegistry<ServiceProvider, + FaceSensorPropertiesInternal, IFaceAuthenticatorsRegisteredCallback> { + + private static final String TAG = "FaceServiceRegistry"; + + @NonNull + private final IFaceService mService; + + /** Creates a new registry tied to the given service. */ + public FaceServiceRegistry(@NonNull IFaceService service, + @Nullable Supplier<IBiometricService> biometricSupplier) { + super(biometricSupplier); + mService = service; + } + + @Override + protected void registerService(@NonNull IBiometricService service, + @NonNull FaceSensorPropertiesInternal props) { + @BiometricManager.Authenticators.Types final int strength = + Utils.propertyStrengthToAuthenticatorStrength(props.sensorStrength); + try { + service.registerAuthenticator(props.sensorId, TYPE_FACE, strength, + new FaceAuthenticator(mService, props.sensorId)); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception when registering sensorId: " + props.sensorId); + } + } + + @Override + protected void invokeRegisteredCallback(@NonNull IFaceAuthenticatorsRegisteredCallback callback, + @NonNull List<FaceSensorPropertiesInternal> allProps) throws RemoteException { + callback.onAllAuthenticatorsRegistered(allProps); + } +} diff --git a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java index 6f98365332e2..4efaedbd5530 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java @@ -26,15 +26,13 @@ import android.hardware.face.FaceManager; import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.face.IFaceServiceReceiver; import android.os.IBinder; -import android.util.proto.ProtoOutputStream; import android.view.Surface; +import com.android.server.biometrics.sensors.BiometricServiceProvider; import com.android.server.biometrics.sensors.ClientMonitorCallback; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; -import com.android.server.biometrics.sensors.LockoutTracker; import java.io.FileDescriptor; -import java.io.PrintWriter; import java.util.List; /** @@ -56,24 +54,11 @@ import java.util.List; * to check (e.g. via {@link FaceManager#getSensorPropertiesInternal()}) that the code path isn't * taken. ServiceProviders will provide a no-op for unsupported operations to fail safely. */ -public interface ServiceProvider { - /** - * Checks if the specified sensor is owned by this provider. - */ - boolean containsSensor(int sensorId); - - @NonNull - List<FaceSensorPropertiesInternal> getSensorProperties(); - - @NonNull - FaceSensorPropertiesInternal getSensorProperties(int sensorId); +public interface ServiceProvider extends BiometricServiceProvider<FaceSensorPropertiesInternal> { @NonNull List<Face> getEnrolledFaces(int sensorId, int userId); - @LockoutTracker.LockoutMode - int getLockoutModeForUser(int sensorId, int userId); - /** * Requests for the authenticatorId (whose source of truth is in the TEE or equivalent) to be * invalidated. See {@link com.android.server.biometrics.sensors.InvalidationRequesterClient} @@ -84,10 +69,6 @@ public interface ServiceProvider { + " this method"); } - long getAuthenticatorId(int sensorId, int userId); - - boolean isHardwareDetected(int sensorId); - void scheduleGenerateChallenge(int sensorId, int userId, @NonNull IBinder token, @NonNull IFaceServiceReceiver receiver, String opPackageName); @@ -142,13 +123,6 @@ public interface ServiceProvider { void scheduleInternalCleanup(int sensorId, int userId, @Nullable ClientMonitorCallback callback, boolean favorHalEnrollments); - void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto, - boolean clearSchedulerBuffer); - - void dumpProtoMetrics(int sensorId, @NonNull FileDescriptor fd); - - void dumpInternal(int sensorId, @NonNull PrintWriter pw); - @NonNull ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback, @NonNull String opPackageName); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java index 19d54c84c706..6bff179e8eb7 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java @@ -285,6 +285,11 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { } @Override + public boolean hasEnrollments(int sensorId, int userId) { + return !getEnrolledFaces(sensorId, userId).isEmpty(); + } + + @Override public void scheduleInvalidateAuthenticatorId(int sensorId, int userId, @NonNull IInvalidationCallback callback) { mHandler.post(() -> { diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java index 65289122747c..c0a119ff5f1e 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java @@ -484,6 +484,11 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { } @Override + public boolean hasEnrollments(int sensorId, int userId) { + return !getEnrolledFaces(sensorId, userId).isEmpty(); + } + + @Override @LockoutTracker.LockoutMode public int getLockoutModeForUser(int sensorId, int userId) { return mLockoutTracker.getLockoutModeForUser(userId); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java index 2ba449ae089e..7e2742edd47a 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java @@ -17,14 +17,11 @@ package com.android.server.biometrics.sensors.fingerprint; import static android.Manifest.permission.INTERACT_ACROSS_USERS; -import static android.Manifest.permission.MANAGE_BIOMETRIC; import static android.Manifest.permission.MANAGE_FINGERPRINT; -import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT; import static android.Manifest.permission.TEST_BIOMETRIC; import static android.Manifest.permission.USE_BIOMETRIC; import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL; import static android.Manifest.permission.USE_FINGERPRINT; -import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_VENDOR; import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_USER_CANCELED; import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_VENDOR; @@ -36,8 +33,6 @@ import android.app.ActivityManager; import android.app.AppOpsManager; import android.content.Context; import android.content.pm.PackageManager; -import android.content.pm.UserInfo; -import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.biometrics.IBiometricSensorReceiver; @@ -65,7 +60,6 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Process; -import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; @@ -79,11 +73,9 @@ import android.util.Slog; import android.util.proto.ProtoOutputStream; import com.android.internal.R; -import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.DumpUtils; import com.android.internal.widget.LockPatternUtils; -import com.android.server.ServiceThread; import com.android.server.SystemService; import com.android.server.biometrics.Utils; import com.android.server.biometrics.log.BiometricContext; @@ -115,74 +107,32 @@ public class FingerprintService extends SystemService { protected static final String TAG = "FingerprintService"; - private final Object mLock = new Object(); private final AppOpsManager mAppOps; private final LockoutResetDispatcher mLockoutResetDispatcher; private final GestureAvailabilityDispatcher mGestureAvailabilityDispatcher; private final LockPatternUtils mLockPatternUtils; - @NonNull private final List<ServiceProvider> mServiceProviders; - @NonNull private final BiometricStateCallback mBiometricStateCallback; - @NonNull private final Handler mHandler; - @NonNull private final BiometricContext mBiometricContext; - @NonNull private final Supplier<IBiometricService> mBiometricServiceSupplier; - @NonNull private final Function<String, IFingerprint> mIFingerprintProvider; - - @GuardedBy("mLock") - @NonNull private final RemoteCallbackList<IFingerprintAuthenticatorsRegisteredCallback> - mAuthenticatorsRegisteredCallbacks; - - @GuardedBy("mLock") - @NonNull private final List<FingerprintSensorPropertiesInternal> mSensorProps; - - /** - * Registers BiometricStateListener in list stored by FingerprintService - * @param listener new BiometricStateListener being added - */ - public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) { - mBiometricStateCallback.registerBiometricStateListener(listener); - broadcastCurrentEnrollmentState(listener); - } - - /** - * @param listener if non-null, notifies only this listener. if null, notifies all listeners - * in {@link BiometricStateCallback}. This is slightly ugly, but reduces - * redundant code. - */ - private void broadcastCurrentEnrollmentState(@Nullable IBiometricStateListener listener) { - final UserManager um = UserManager.get(getContext()); - synchronized (mLock) { - // Update the new listener with current state of all sensors - for (FingerprintSensorPropertiesInternal prop : mSensorProps) { - final ServiceProvider provider = getProviderForSensor(prop.sensorId); - for (UserInfo userInfo : um.getAliveUsers()) { - final boolean enrolled = !provider - .getEnrolledFingerprints(prop.sensorId, userInfo.id).isEmpty(); - - // Defer this work and allow the loop to release the lock sooner - mHandler.post(() -> { - if (listener != null) { - mBiometricStateCallback.notifyEnrollmentStateChanged( - listener, userInfo.id, prop.sensorId, enrolled); - } else { - mBiometricStateCallback.notifyAllEnrollmentStateChanged( - userInfo.id, prop.sensorId, enrolled); - } - }); - } - } - } - } + @NonNull + private final BiometricContext mBiometricContext; + @NonNull + private final Supplier<String[]> mAidlInstanceNameSupplier; + @NonNull + private final Function<String, IFingerprint> mIFingerprintProvider; + @NonNull + private final BiometricStateCallback<ServiceProvider, FingerprintSensorPropertiesInternal> + mBiometricStateCallback; + @NonNull + private final Handler mHandler; + @NonNull + private final FingerprintServiceRegistry mRegistry; - /** - * Receives the incoming binder calls from FingerprintManager. - */ - private final IFingerprintService.Stub mServiceWrapper = new IFingerprintService.Stub() { + /** Receives the incoming binder calls from FingerprintManager. */ + @VisibleForTesting + final IFingerprintService.Stub mServiceWrapper = new IFingerprintService.Stub() { @android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC) @Override public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback, @NonNull String opPackageName) { - - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "Null provider for createTestSession, sensorId: " + sensorId); @@ -195,9 +145,8 @@ public class FingerprintService extends SystemService { @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override public byte[] dumpSensorServiceStateProto(int sensorId, boolean clearSchedulerBuffer) { - final ProtoOutputStream proto = new ProtoOutputStream(); - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider != null) { provider.dumpProtoState(sensorId, proto, clearSchedulerBuffer); } @@ -212,16 +161,14 @@ public class FingerprintService extends SystemService { != PackageManager.PERMISSION_GRANTED) { Utils.checkPermission(getContext(), TEST_BIOMETRIC); } - - return FingerprintService.this.getSensorProperties(); + return mRegistry.getAllProperties(); } @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override public FingerprintSensorPropertiesInternal getSensorProperties(int sensorId, @NonNull String opPackageName) { - - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "No matching sensor for getSensorProperties, sensorId: " + sensorId + ", caller: " + opPackageName); @@ -234,8 +181,7 @@ public class FingerprintService extends SystemService { @Override // Binder call public void generateChallenge(IBinder token, int sensorId, int userId, IFingerprintServiceReceiver receiver, String opPackageName) { - - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "No matching sensor for generateChallenge, sensorId: " + sensorId); return; @@ -248,8 +194,7 @@ public class FingerprintService extends SystemService { @Override // Binder call public void revokeChallenge(IBinder token, int sensorId, int userId, String opPackageName, long challenge) { - - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "No matching sensor for revokeChallenge, sensorId: " + sensorId); return; @@ -264,8 +209,7 @@ public class FingerprintService extends SystemService { public long enroll(final IBinder token, @NonNull final byte[] hardwareAuthToken, final int userId, final IFingerprintServiceReceiver receiver, final String opPackageName, @FingerprintManager.EnrollReason int enrollReason) { - - final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider(); if (provider == null) { Slog.w(TAG, "Null provider for enroll"); return -1; @@ -278,8 +222,7 @@ public class FingerprintService extends SystemService { @android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_FINGERPRINT) @Override // Binder call public void cancelEnrollment(final IBinder token, long requestId) { - - final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider(); if (provider == null) { Slog.w(TAG, "Null provider for cancelEnrollment"); return; @@ -339,10 +282,10 @@ public class FingerprintService extends SystemService { final Pair<Integer, ServiceProvider> provider; if (sensorId == FingerprintManager.SENSOR_ID_ANY) { - provider = getSingleProvider(); + provider = mRegistry.getSingleProvider(); } else { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); - provider = new Pair<>(sensorId, getProviderForSensor(sensorId)); + provider = new Pair<>(sensorId, mRegistry.getProviderForSensor(sensorId)); } if (provider == null) { Slog.w(TAG, "Null provider for authenticate"); @@ -374,7 +317,6 @@ public class FingerprintService extends SystemService { final IFingerprintServiceReceiver receiver, final String opPackageName, boolean ignoreEnrollmentState) throws PackageManager.NameNotFoundException { - final Context context = getUiContext(); final Context promptContext = context.createPackageContextAsUser( opPackageName, 0 /* flags */, UserHandle.getUserHandleForUid(uId)); @@ -468,7 +410,7 @@ public class FingerprintService extends SystemService { return -1; } - final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider(); if (provider == null) { Slog.w(TAG, "Null provider for detectFingerprint"); return -1; @@ -484,8 +426,7 @@ public class FingerprintService extends SystemService { public void prepareForAuthentication(int sensorId, IBinder token, long operationId, int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication) { - - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "Null provider for prepareForAuthentication"); return; @@ -501,8 +442,7 @@ public class FingerprintService extends SystemService { @android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_BIOMETRIC) @Override // Binder call public void startPreparedClient(int sensorId, int cookie) { - - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "Null provider for startPreparedClient"); return; @@ -532,7 +472,7 @@ public class FingerprintService extends SystemService { return; } - final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider(); if (provider == null) { Slog.w(TAG, "Null provider for cancelAuthentication"); return; @@ -553,7 +493,7 @@ public class FingerprintService extends SystemService { // For IBiometricsFingerprint2.1, cancelling fingerprint detect is the same as // cancelling authentication. - final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider(); if (provider == null) { Slog.w(TAG, "Null provider for cancelFingerprintDetect"); return; @@ -566,11 +506,9 @@ public class FingerprintService extends SystemService { @Override // Binder call public void cancelAuthenticationFromService(final int sensorId, final IBinder token, final String opPackageName, final long requestId) { - - Slog.d(TAG, "cancelAuthenticationFromService, sensorId: " + sensorId); - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "Null provider for cancelAuthenticationFromService"); return; @@ -583,8 +521,7 @@ public class FingerprintService extends SystemService { @Override // Binder call public void remove(final IBinder token, final int fingerId, final int userId, final IFingerprintServiceReceiver receiver, final String opPackageName) { - - final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider(); if (provider == null) { Slog.w(TAG, "Null provider for remove"); return; @@ -617,7 +554,7 @@ public class FingerprintService extends SystemService { // This effectively iterates through all sensors, but has to do so by finding all // sensors under each provider. - for (ServiceProvider provider : mServiceProviders) { + for (ServiceProvider provider : mRegistry.getProviders()) { List<FingerprintSensorPropertiesInternal> props = provider.getSensorProperties(); for (FingerprintSensorPropertiesInternal prop : props) { provider.scheduleRemoveAll(prop.sensorId, token, internalReceiver, userId, @@ -652,7 +589,7 @@ public class FingerprintService extends SystemService { try { if (args.length > 1 && "--proto".equals(args[0]) && "--state".equals(args[1])) { final ProtoOutputStream proto = new ProtoOutputStream(fd); - for (ServiceProvider provider : mServiceProviders) { + for (ServiceProvider provider : mRegistry.getProviders()) { for (FingerprintSensorPropertiesInternal props : provider.getSensorProperties()) { provider.dumpProtoState(props.sensorId, proto, false); @@ -660,14 +597,14 @@ public class FingerprintService extends SystemService { } proto.flush(); } else if (args.length > 0 && "--proto".equals(args[0])) { - for (ServiceProvider provider : mServiceProviders) { + for (ServiceProvider provider : mRegistry.getProviders()) { for (FingerprintSensorPropertiesInternal props : provider.getSensorProperties()) { provider.dumpProtoMetrics(props.sensorId, fd); } } } else { - for (ServiceProvider provider : mServiceProviders) { + for (ServiceProvider provider : mRegistry.getProviders()) { for (FingerprintSensorPropertiesInternal props : provider.getSensorProperties()) { pw.println("Dumping for sensorId: " + props.sensorId @@ -698,7 +635,7 @@ public class FingerprintService extends SystemService { final long token = Binder.clearCallingIdentity(); try { - final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider(); if (provider == null) { Slog.w(TAG, "Null provider for isHardwareDetectedDeprecated, caller: " + opPackageName); @@ -713,8 +650,7 @@ public class FingerprintService extends SystemService { @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override // Binder call public boolean isHardwareDetected(int sensorId, String opPackageName) { - - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "Null provider for isHardwareDetected, caller: " + opPackageName); return false; @@ -730,7 +666,7 @@ public class FingerprintService extends SystemService { return; } - final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider(); if (provider == null) { Slog.w(TAG, "Null provider for rename"); return; @@ -781,8 +717,7 @@ public class FingerprintService extends SystemService { @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) public boolean hasEnrolledFingerprints(int sensorId, int userId, String opPackageName) { - - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "Null provider for hasEnrolledFingerprints, caller: " + opPackageName); return false; @@ -794,8 +729,7 @@ public class FingerprintService extends SystemService { @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override // Binder call public @LockoutTracker.LockoutMode int getLockoutModeForUser(int sensorId, int userId) { - - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "Null provider for getLockoutModeForUser"); return LockoutTracker.LOCKOUT_NONE; @@ -807,8 +741,7 @@ public class FingerprintService extends SystemService { @Override public void invalidateAuthenticatorId(int sensorId, int userId, IInvalidationCallback callback) { - - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "Null provider for invalidateAuthenticatorId"); return; @@ -819,8 +752,7 @@ public class FingerprintService extends SystemService { @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override // Binder call public long getAuthenticatorId(int sensorId, int userId) { - - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "Null provider for getAuthenticatorId"); return 0; @@ -832,8 +764,7 @@ public class FingerprintService extends SystemService { @Override // Binder call public void resetLockout(IBinder token, int sensorId, int userId, @Nullable byte[] hardwareAuthToken, String opPackageName) { - - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "Null provider for resetLockout, caller: " + opPackageName); return; @@ -864,55 +795,38 @@ public class FingerprintService extends SystemService { @Override // Binder call public void registerAuthenticators( @NonNull List<FingerprintSensorPropertiesInternal> hidlSensors) { - - // Some HAL might not be started before the system service and will cause the code below - // to wait, and some of the operations below might take a significant amount of time to - // complete (calls to the HALs). To avoid blocking the rest of system server we put - // this on a background thread. - final ServiceThread thread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, - true /* allowIo */); - thread.start(); - final Handler handler = new Handler(thread.getLooper()); - handler.post(() -> { + mRegistry.registerAll(() -> { + final List<ServiceProvider> providers = new ArrayList<>(); + providers.addAll(getHidlProviders(hidlSensors)); List<String> aidlSensors = new ArrayList<>(); - final String[] instances = - ServiceManager.getDeclaredInstances(IFingerprint.DESCRIPTOR); + final String[] instances = mAidlInstanceNameSupplier.get(); if (instances != null) { aidlSensors.addAll(Lists.newArrayList(instances)); } - registerAuthenticatorsForService(aidlSensors, hidlSensors); + providers.addAll(getAidlProviders( + Utils.filterAvailableHalInstances(getContext(), aidlSensors))); + return providers; }); - thread.quitSafely(); } @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override public void addAuthenticatorsRegisteredCallback( IFingerprintAuthenticatorsRegisteredCallback callback) { - if (callback == null) { - Slog.e(TAG, "addAuthenticatorsRegisteredCallback, callback is null"); - return; - } + mRegistry.addAllRegisteredCallback(callback); + } - final boolean registered; - final boolean hasSensorProps; - synchronized (mLock) { - registered = mAuthenticatorsRegisteredCallbacks.register(callback); - hasSensorProps = !mSensorProps.isEmpty(); - } - if (registered && hasSensorProps) { - broadcastAllAuthenticatorsRegistered(); - } else if (!registered) { - Slog.e(TAG, "addAuthenticatorsRegisteredCallback failed to register callback"); - } + @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) + @Override + public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) { + mBiometricStateCallback.registerBiometricStateListener(listener); } @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override public void onPointerDown(long requestId, int sensorId, int x, int y, float minor, float major) { - - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "No matching provider for onFingerDown, sensorId: " + sensorId); return; @@ -923,8 +837,7 @@ public class FingerprintService extends SystemService { @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override public void onPointerUp(long requestId, int sensorId) { - - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "No matching provider for onFingerUp, sensorId: " + sensorId); return; @@ -935,8 +848,7 @@ public class FingerprintService extends SystemService { @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override public void onUiReady(long requestId, int sensorId) { - - final ServiceProvider provider = getProviderForSensor(sensorId); + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); if (provider == null) { Slog.w(TAG, "No matching provider for onUiReady, sensorId: " + sensorId); return; @@ -947,8 +859,7 @@ public class FingerprintService extends SystemService { @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override public void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller) { - - for (ServiceProvider provider : mServiceProviders) { + for (ServiceProvider provider : mRegistry.getProviders()) { provider.setUdfpsOverlayController(controller); } } @@ -956,22 +867,15 @@ public class FingerprintService extends SystemService { @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override public void setSidefpsController(@NonNull ISidefpsController controller) { - - for (ServiceProvider provider : mServiceProviders) { + for (ServiceProvider provider : mRegistry.getProviders()) { provider.setSidefpsController(controller); } } - @Override - public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) { - Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); - FingerprintService.this.registerBiometricStateListener(listener); - } - + @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override public void onPowerPressed() { - Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); - for (ServiceProvider provider : mServiceProviders) { + for (ServiceProvider provider : mRegistry.getProviders()) { provider.onPowerPressed(); } } @@ -981,6 +885,7 @@ public class FingerprintService extends SystemService { this(context, BiometricContext.getInstance(context), () -> IBiometricService.Stub.asInterface( ServiceManager.getService(Context.BIOMETRIC_SERVICE)), + () -> ServiceManager.getDeclaredInstances(IFingerprint.DESCRIPTOR), (fqName) -> IFingerprint.Stub.asInterface( Binder.allowBlocking(ServiceManager.waitForDeclaredService(fqName)))); } @@ -988,61 +893,34 @@ public class FingerprintService extends SystemService { @VisibleForTesting FingerprintService(Context context, BiometricContext biometricContext, - Supplier<IBiometricService> biometricServiceProvider, + Supplier<IBiometricService> biometricServiceSupplier, + Supplier<String[]> aidlInstanceNameSupplier, Function<String, IFingerprint> fingerprintProvider) { super(context); mBiometricContext = biometricContext; - mBiometricServiceSupplier = biometricServiceProvider; + mAidlInstanceNameSupplier = aidlInstanceNameSupplier; mIFingerprintProvider = fingerprintProvider; mAppOps = context.getSystemService(AppOpsManager.class); mGestureAvailabilityDispatcher = new GestureAvailabilityDispatcher(); mLockoutResetDispatcher = new LockoutResetDispatcher(context); mLockPatternUtils = new LockPatternUtils(context); - mServiceProviders = new ArrayList<>(); - mBiometricStateCallback = new BiometricStateCallback(); - mAuthenticatorsRegisteredCallbacks = new RemoteCallbackList<>(); - mSensorProps = new ArrayList<>(); + mBiometricStateCallback = new BiometricStateCallback<>(UserManager.get(context)); mHandler = new Handler(Looper.getMainLooper()); + mRegistry = new FingerprintServiceRegistry(mServiceWrapper, biometricServiceSupplier); + mRegistry.addAllRegisteredCallback(new IFingerprintAuthenticatorsRegisteredCallback.Stub() { + @Override + public void onAllAuthenticatorsRegistered( + List<FingerprintSensorPropertiesInternal> sensors) { + mBiometricStateCallback.start(mRegistry.getProviders()); + } + }); } - @VisibleForTesting - void registerAuthenticatorsForService(@NonNull List<String> aidlInstanceNames, + @NonNull + private List<ServiceProvider> getHidlProviders( @NonNull List<FingerprintSensorPropertiesInternal> hidlSensors) { - addHidlProviders(hidlSensors); - addAidlProviders(Utils.filterAvailableHalInstances(getContext(), aidlInstanceNames)); - - final IBiometricService biometricService = mBiometricServiceSupplier.get(); - - // Register each sensor individually with BiometricService - for (ServiceProvider provider : mServiceProviders) { - final List<FingerprintSensorPropertiesInternal> props = - provider.getSensorProperties(); - for (FingerprintSensorPropertiesInternal prop : props) { - final int sensorId = prop.sensorId; - @BiometricManager.Authenticators.Types final int strength = - Utils.propertyStrengthToAuthenticatorStrength(prop.sensorStrength); - final FingerprintAuthenticator authenticator = new FingerprintAuthenticator( - mServiceWrapper, sensorId); - try { - biometricService.registerAuthenticator(sensorId, TYPE_FINGERPRINT, - strength, authenticator); - } catch (RemoteException e) { - Slog.e(TAG, "Remote exception when registering sensorId: " + sensorId); - } - } - } - - synchronized (mLock) { - for (ServiceProvider provider : mServiceProviders) { - mSensorProps.addAll(provider.getSensorProperties()); - } - } + final List<ServiceProvider> providers = new ArrayList<>(); - broadcastCurrentEnrollmentState(null); // broadcasts to all listeners - broadcastAllAuthenticatorsRegistered(); - } - - private void addHidlProviders(List<FingerprintSensorPropertiesInternal> hidlSensors) { for (FingerprintSensorPropertiesInternal hidlSensor : hidlSensors) { final Fingerprint21 fingerprint21; if ((Build.IS_USERDEBUG || Build.IS_ENG) @@ -1059,11 +937,16 @@ public class FingerprintService extends SystemService { mBiometricStateCallback, hidlSensor, mHandler, mLockoutResetDispatcher, mGestureAvailabilityDispatcher); } - mServiceProviders.add(fingerprint21); + providers.add(fingerprint21); } + + return providers; } - private void addAidlProviders(List<String> instances) { + @NonNull + private List<ServiceProvider> getAidlProviders(@NonNull List<String> instances) { + final List<ServiceProvider> providers = new ArrayList<>(); + for (String instance : instances) { final String fqName = IFingerprint.DESCRIPTOR + "/" + instance; final IFingerprint fp = mIFingerprintProvider.apply(fqName); @@ -1075,7 +958,7 @@ public class FingerprintService extends SystemService { mLockoutResetDispatcher, mGestureAvailabilityDispatcher, mBiometricContext); Slog.i(TAG, "Adding AIDL provider: " + fqName); - mServiceProviders.add(provider); + providers.add(provider); } catch (RemoteException e) { Slog.e(TAG, "Remote exception in getSensorProps: " + fqName); } @@ -1083,38 +966,8 @@ public class FingerprintService extends SystemService { Slog.e(TAG, "Unable to get declared service: " + fqName); } } - } - // Notifies the callbacks that all of the authenticators have been registered and removes the - // invoked callbacks from the callback list. - private void broadcastAllAuthenticatorsRegistered() { - // Make a local copy of the data so it can be used outside of the synchronized block when - // making Binder calls. - final List<IFingerprintAuthenticatorsRegisteredCallback> callbacks = new ArrayList<>(); - final List<FingerprintSensorPropertiesInternal> props; - synchronized (mLock) { - if (!mSensorProps.isEmpty()) { - props = new ArrayList<>(mSensorProps); - } else { - Slog.e(TAG, "mSensorProps is empty"); - return; - } - final int n = mAuthenticatorsRegisteredCallbacks.beginBroadcast(); - for (int i = 0; i < n; ++i) { - final IFingerprintAuthenticatorsRegisteredCallback cb = - mAuthenticatorsRegisteredCallbacks.getBroadcastItem(i); - callbacks.add(cb); - mAuthenticatorsRegisteredCallbacks.unregister(cb); - } - mAuthenticatorsRegisteredCallbacks.finishBroadcast(); - } - for (IFingerprintAuthenticatorsRegisteredCallback cb : callbacks) { - try { - cb.onAllAuthenticatorsRegistered(props); - } catch (RemoteException e) { - Slog.e(TAG, "Remote exception in onAllAuthenticatorsRegistered", e); - } - } + return providers; } @Override @@ -1122,51 +975,9 @@ public class FingerprintService extends SystemService { publishBinderService(Context.FINGERPRINT_SERVICE, mServiceWrapper); } - @Nullable - private ServiceProvider getProviderForSensor(int sensorId) { - for (ServiceProvider provider : mServiceProviders) { - if (provider.containsSensor(sensorId)) { - return provider; - } - } - return null; - } - - /** - * For devices with only a single provider, returns that provider. If multiple providers, - * returns the first one. If no providers, returns null. - */ - @Nullable - private Pair<Integer, ServiceProvider> getSingleProvider() { - final List<FingerprintSensorPropertiesInternal> properties = getSensorProperties(); - if (properties.isEmpty()) { - Slog.e(TAG, "No providers found"); - return null; - } - - // Theoretically we can just return the first provider, but maybe this is easier to - // understand. - final int sensorId = properties.get(0).sensorId; - for (ServiceProvider provider : mServiceProviders) { - if (provider.containsSensor(sensorId)) { - return new Pair<>(sensorId, provider); - } - } - - Slog.e(TAG, "Provider not found"); - return null; - } - - @NonNull - private List<FingerprintSensorPropertiesInternal> getSensorProperties() { - synchronized (mLock) { - return mSensorProps; - } - } - @NonNull private List<Fingerprint> getEnrolledFingerprintsDeprecated(int userId, String opPackageName) { - final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider(); if (provider == null) { Slog.w(TAG, "Null provider for getEnrolledFingerprintsDeprecated, caller: " + opPackageName); @@ -1229,7 +1040,7 @@ public class FingerprintService extends SystemService { if (Utils.isVirtualEnabled(getContext())) { Slog.i(TAG, "Sync virtual enrollments"); final int userId = ActivityManager.getCurrentUser(); - for (ServiceProvider provider : mServiceProviders) { + for (ServiceProvider provider : mRegistry.getProviders()) { for (FingerprintSensorPropertiesInternal props : provider.getSensorProperties()) { provider.scheduleInternalCleanup(props.sensorId, userId, null /* callback */, true /* favorHalEnrollments */); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceRegistry.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceRegistry.java new file mode 100644 index 000000000000..33810b764f23 --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceRegistry.java @@ -0,0 +1,72 @@ +/* + * 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.server.biometrics.sensors.fingerprint; + +import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.hardware.biometrics.BiometricManager; +import android.hardware.biometrics.IBiometricService; +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; +import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; +import android.hardware.fingerprint.IFingerprintService; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.server.biometrics.Utils; +import com.android.server.biometrics.sensors.BiometricServiceRegistry; + +import java.util.List; +import java.util.function.Supplier; + +/** Registry for {@link IFingerprintService} providers. */ +public class FingerprintServiceRegistry extends BiometricServiceRegistry<ServiceProvider, + FingerprintSensorPropertiesInternal, IFingerprintAuthenticatorsRegisteredCallback> { + + private static final String TAG = "FingerprintServiceRegistry"; + + @NonNull + private final IFingerprintService mService; + + /** Creates a new registry tied to the given service. */ + public FingerprintServiceRegistry(@NonNull IFingerprintService service, + @Nullable Supplier<IBiometricService> biometricSupplier) { + super(biometricSupplier); + mService = service; + } + + @Override + protected void registerService(@NonNull IBiometricService service, + @NonNull FingerprintSensorPropertiesInternal props) { + @BiometricManager.Authenticators.Types final int strength = + Utils.propertyStrengthToAuthenticatorStrength(props.sensorStrength); + try { + service.registerAuthenticator(props.sensorId, TYPE_FINGERPRINT, strength, + new FingerprintAuthenticator(mService, props.sensorId)); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception when registering sensorId: " + props.sensorId); + } + } + + @Override + protected void invokeRegisteredCallback( + @NonNull IFingerprintAuthenticatorsRegisteredCallback callback, + @NonNull List<FingerprintSensorPropertiesInternal> allProps) throws RemoteException { + callback.onAllAuthenticatorsRegistered(allProps); + } +} diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java index 275d7e445a75..9075e7ec2080 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java @@ -28,14 +28,11 @@ import android.hardware.fingerprint.IFingerprintServiceReceiver; import android.hardware.fingerprint.ISidefpsController; import android.hardware.fingerprint.IUdfpsOverlayController; import android.os.IBinder; -import android.util.proto.ProtoOutputStream; +import com.android.server.biometrics.sensors.BiometricServiceProvider; import com.android.server.biometrics.sensors.ClientMonitorCallback; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; -import com.android.server.biometrics.sensors.LockoutTracker; -import java.io.FileDescriptor; -import java.io.PrintWriter; import java.util.List; /** @@ -59,23 +56,8 @@ import java.util.List; * fail safely. */ @SuppressWarnings("deprecation") -public interface ServiceProvider { - /** - * Checks if the specified sensor is owned by this provider. - */ - boolean containsSensor(int sensorId); - - @NonNull - List<FingerprintSensorPropertiesInternal> getSensorProperties(); - - /** - * Returns the internal properties of the specified sensor, if owned by this provider. - * - * @param sensorId The ID of a fingerprint sensor, or -1 for any sensor. - * @return An object representing the internal properties of the specified sensor. - */ - @Nullable - FingerprintSensorPropertiesInternal getSensorProperties(int sensorId); +public interface ServiceProvider extends + BiometricServiceProvider<FingerprintSensorPropertiesInternal> { void scheduleResetLockout(int sensorId, int userId, @Nullable byte[] hardwareAuthToken); @@ -126,16 +108,11 @@ public interface ServiceProvider { void scheduleInternalCleanup(int sensorId, int userId, @Nullable ClientMonitorCallback callback, boolean favorHalEnrollments); - boolean isHardwareDetected(int sensorId); - void rename(int sensorId, int fingerId, int userId, @NonNull String name); @NonNull List<Fingerprint> getEnrolledFingerprints(int sensorId, int userId); - @LockoutTracker.LockoutMode - int getLockoutModeForUser(int sensorId, int userId); - /** * Requests for the authenticatorId (whose source of truth is in the TEE or equivalent) to * be invalidated. See {@link com.android.server.biometrics.sensors.InvalidationRequesterClient} @@ -143,7 +120,6 @@ public interface ServiceProvider { void scheduleInvalidateAuthenticatorId(int sensorId, int userId, @NonNull IInvalidationCallback callback); - long getAuthenticatorId(int sensorId, int userId); void onPointerDown(long requestId, int sensorId, int x, int y, float minor, float major); @@ -161,13 +137,6 @@ public interface ServiceProvider { */ void setSidefpsController(@NonNull ISidefpsController controller); - void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto, - boolean clearSchedulerBuffer); - - void dumpProtoMetrics(int sensorId, @NonNull FileDescriptor fd); - - void dumpInternal(int sensorId, @NonNull PrintWriter pw); - @NonNull ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback, @NonNull String opPackageName); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java index 2dc005206b42..3fe6332fcaa0 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java @@ -565,6 +565,11 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi } @Override + public boolean hasEnrollments(int sensorId, int userId) { + return !getEnrolledFingerprints(sensorId, userId).isEmpty(); + } + + @Override public void scheduleInvalidateAuthenticatorId(int sensorId, int userId, @NonNull IInvalidationCallback callback) { mHandler.post(() -> { diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java index ed482f013869..0e6df8e0df77 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java @@ -789,6 +789,11 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider } @Override + public boolean hasEnrollments(int sensorId, int userId) { + return !getEnrolledFingerprints(sensorId, userId).isEmpty(); + } + + @Override @LockoutTracker.LockoutMode public int getLockoutModeForUser(int sensorId, int userId) { return mLockoutTracker.getLockoutModeForUser(userId); } diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java index 5731af68df95..297439f33a8b 100644 --- a/services/core/java/com/android/server/pm/UserManagerInternal.java +++ b/services/core/java/com/android/server/pm/UserManagerInternal.java @@ -315,4 +315,10 @@ public abstract class UserManagerInternal { /** TODO(b/239982558): add javadoc / mention invalid_id is used to unassing */ public abstract void assignUserToDisplay(@UserIdInt int userId, int displayId); + + /** + * Returns {@code true} if the user is visible (as defined by + * {@link UserManager#isUserVisible()} in the given display. + */ + public abstract boolean isUserVisible(@UserIdInt int userId, int displayId); } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 87ab87df0b0c..e423ea9170d7 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -7005,7 +7005,12 @@ public class UserManagerService extends IUserManager.Stub { mUsersOnSecondaryDisplays.put(userId, displayId); } } - } + + @Override + public boolean isUserVisible(int userId, int displayId) { + return isUserVisibleOnDisplay(userId, displayId); + } + } // class LocalService /** * Check if user has restrictions 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 df902c2916ba..fe4aa534df6f 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.recordHistoryEventLocked( + mStats.addHistoryEventLocked( 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 37643c3c6f6f..202beb377b2c 100644 --- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java +++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java @@ -108,7 +108,6 @@ 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; @@ -174,6 +173,7 @@ 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,11 +322,6 @@ 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; @@ -418,7 +413,7 @@ public class BatteryStatsImpl extends BatteryStats { if (changed) { final long uptimeMs = mClock.uptimeMillis(); final long elapsedRealtimeMs = mClock.elapsedRealtime(); - mHistory.writeHistoryItem(elapsedRealtimeMs, uptimeMs); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); } } } @@ -673,16 +668,16 @@ public class BatteryStatsImpl extends BatteryStats { /** * Mapping isolated uids to the actual owning app uid. */ - private final SparseIntArray mIsolatedUids = new SparseIntArray(); + final SparseIntArray mIsolatedUids = new SparseIntArray(); /** * Internal reference count of isolated uids. */ - private final SparseIntArray mIsolatedUidRefCounts = new SparseIntArray(); + final SparseIntArray mIsolatedUidRefCounts = new SparseIntArray(); /** * The statistics we have collected organized by uids. */ - private final SparseArray<BatteryStatsImpl.Uid> mUidStats = new SparseArray<>(); + 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. @@ -690,21 +685,20 @@ public class BatteryStatsImpl extends BatteryStats { // changes. @VisibleForTesting protected ArrayList<StopwatchTimer> mPartialTimers = 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<>(); + 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<>(); // Last partial timers we use for distributing CPU usage. @VisibleForTesting @@ -719,24 +713,69 @@ public class BatteryStatsImpl extends BatteryStats { protected final TimeBase mOnBatteryScreenOffTimeBase = new TimeBase(true); private boolean mSystemReady; - 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; + 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; @NonNull - private final BatteryStatsHistory mHistory; + 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 BatteryStatsHistoryIterator mBatteryStatsHistoryIterator; @@ -1352,6 +1391,7 @@ public class BatteryStatsImpl extends BatteryStats { int mDischargeUnplugLevel; int mDischargePlugLevel; int mDischargeCurrentLevel; + int mCurrentBatteryLevel; int mLowDischargeAmountSinceCharge; int mHighDischargeAmountSinceCharge; int mDischargeScreenOnUnplugLevel; @@ -1403,6 +1443,7 @@ public class BatteryStatsImpl extends BatteryStats { private int mNumConnectivityChange; + private int mBatteryVoltageMv = -1; private int mEstimatedBatteryCapacityMah = -1; private int mLastLearnedBatteryCapacityUah = -1; @@ -1586,27 +1627,28 @@ public class BatteryStatsImpl extends BatteryStats { } public BatteryStatsImpl(Clock clock) { - this(clock, null); + this(clock, (File) 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; - mHistory = new BatteryStatsHistory(mStepDetailsCalculator, mClock); + mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer); } else { mStatsFile = new AtomicFile(new File(historyDirectory, "batterystats.bin")); - mHistory = new BatteryStatsHistory(historyDirectory, mConstants.MAX_HISTORY_FILES, - mConstants.MAX_HISTORY_BUFFER, mStepDetailsCalculator, mClock); + mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer, historyDirectory, + this::getMaxHistoryFiles); } + mHandler = null; mPlatformIdleStateCallback = null; mMeasuredEnergyRetriever = null; mUserInfoProvider = null; + mConstants = new Constants(mHandler); + clearHistoryLocked(); } private void init(Clock clock) { @@ -3869,188 +3911,406 @@ public class BatteryStatsImpl extends BatteryStats { return kmt; } - private class HistoryStepDetailsCalculatorImpl implements HistoryStepDetailsCalculator { - private final HistoryStepDetails mDetails = new HistoryStepDetails(); - - private boolean mHasHistoryStepDetails; + /** + * 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; + } + } - private int mLastHistoryStepLevel; + /* + 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. + */ - /** - * 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; - } + @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; + } - // Perform a CPU update right after we do this collection, so we have started - // collecting good data for the next step. - requestImmediateCpuUpdate(); + final long deltaTime = cur.time - last.time; + final int lastBatteryLevelInt = buildBatteryLevelInt(last); + final int lastStateInt = buildStateInt(last); - if (mPlatformIdleStateCallback != null) { - mDetails.statSubsystemPowerState = - mPlatformIdleStateCallback.getSubsystemLowPowerStats(); - if (DEBUG) Slog.i(TAG, "WRITE SubsystemPowerState:" + - 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(); + 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.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; + 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; } - - 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); + 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; } - mCurStepCpuUserTimeMs += totalUTimeMs; - mCurStepCpuSystemTimeMs += totalSTimeMs; - mCurStepStatUserTimeMs += statUserTimeMs; - mCurStepStatSystemTimeMs += statSystemTimeMs; - mCurStepStatIOWaitTimeMs += statIOWaitTimeMs; - mCurStepStatIrqTimeMs += statIrqTimeMs; - mCurStepStatSoftIrqTimeMs += statSoftIrqTimeMs; - mCurStepStatIdleTimeMs += statIdleTimeMs; + if (DEBUG) Slog.i(TAG, "WRITE DELTA: event=" + cur.eventCode + " tag=#" + + cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":" + + cur.eventTag.string); } + if (computeStepDetails) { + if (mPlatformIdleStateCallback != null) { + mCurHistoryStepDetails.statSubsystemPowerState = + mPlatformIdleStateCallback.getSubsystemLowPowerStats(); + if (DEBUG) Slog.i(TAG, "WRITE SubsystemPowerState:" + + mCurHistoryStepDetails.statSubsystemPowerState); - @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; + } + 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; + } 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; + } + } } + mLastStepCpuUserTimeMs = mCurStepCpuUserTimeMs; + mLastStepCpuSystemTimeMs = mCurStepCpuSystemTimeMs; + mLastStepStatUserTimeMs = mCurStepStatUserTimeMs; + mLastStepStatSystemTimeMs = mCurStepStatSystemTimeMs; + mLastStepStatIOWaitTimeMs = mCurStepStatIOWaitTimeMs; + mLastStepStatIrqTimeMs = mCurStepStatIrqTimeMs; + mLastStepStatSoftIrqTimeMs = mCurStepStatSoftIrqTimeMs; + mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs; } @GuardedBy("this") @Override public void commitCurrentHistoryBatchLocked() { - mHistory.commitCurrentHistoryBatchLocked(); + mHistoryLastWritten.cmd = HistoryItem.CMD_NULL; } @GuardedBy("this") @@ -4066,9 +4326,191 @@ public class BatteryStatsImpl extends BatteryStats { } @GuardedBy("this") - public void recordHistoryEventLocked(long elapsedRealtimeMs, long uptimeMs, int code, + 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, String name, int uid) { - mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, code, name, 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; } @GuardedBy("this") @@ -4221,13 +4663,13 @@ public class BatteryStatsImpl extends BatteryStats { if (!mActiveEvents.updateState(code, name, uid, 0)) { return; } - mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, code, name, uid); + addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, code, name, uid); } @GuardedBy("this") public void noteCurrentTimeChangedLocked(long currentTimeMs, long elapsedRealtimeMs, long uptimeMs) { - mHistory.recordCurrentTimeChange(elapsedRealtimeMs, uptimeMs, currentTimeMs); + recordCurrentTimeChangeLocked(currentTimeMs, elapsedRealtimeMs, uptimeMs); } @GuardedBy("this") @@ -4244,7 +4686,7 @@ public class BatteryStatsImpl extends BatteryStats { if (!mRecordAllHistory) { return; } - mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_PROC_START, name, uid); + addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_PROC_START, name, uid); } @GuardedBy("this") @@ -4302,7 +4744,8 @@ public class BatteryStatsImpl extends BatteryStats { if (!mRecordAllHistory) { return; } - mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_PROC_FINISH, name, uid); + addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_PROC_FINISH, + name, uid); } @GuardedBy("this") @@ -4318,7 +4761,7 @@ public class BatteryStatsImpl extends BatteryStats { if (!mActiveEvents.updateState(HistoryItem.EVENT_SYNC_START, name, uid, 0)) { return; } - mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_SYNC_START, name, uid); + addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_SYNC_START, name, uid); } @GuardedBy("this") @@ -4334,7 +4777,8 @@ public class BatteryStatsImpl extends BatteryStats { if (!mActiveEvents.updateState(HistoryItem.EVENT_SYNC_FINISH, name, uid, 0)) { return; } - mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_SYNC_FINISH, name, uid); + addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_SYNC_FINISH, + name, uid); } @GuardedBy("this") @@ -4350,7 +4794,7 @@ public class BatteryStatsImpl extends BatteryStats { if (!mActiveEvents.updateState(HistoryItem.EVENT_JOB_START, name, uid, 0)) { return; } - mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_JOB_START, name, uid); + addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_JOB_START, name, uid); } @GuardedBy("this") @@ -4368,7 +4812,7 @@ public class BatteryStatsImpl extends BatteryStats { if (!mActiveEvents.updateState(HistoryItem.EVENT_JOB_FINISH, name, uid, 0)) { return; } - mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_JOB_FINISH, name, uid); + addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_JOB_FINISH, name, uid); } @GuardedBy("this") @@ -4416,7 +4860,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)) { - mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, historyItem, name, uid); + addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, historyItem, name, uid); } } @@ -4425,7 +4869,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)) { - mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, historyItem, name, uid); + addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, historyItem, name, uid); } } } @@ -4433,7 +4877,7 @@ public class BatteryStatsImpl extends BatteryStats { uid = mapUid(uid); if (mActiveEvents.updateState(historyItem, name, uid, 0)) { - mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, historyItem, name, uid); + addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, historyItem, name, uid); } } } @@ -4508,7 +4952,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++) { - mHistory.recordEvent(mSecRealtime, mSecUptime, + addHistoryEventLocked(mSecRealtime, mSecUptime, HistoryItem.EVENT_PROC_FINISH, ent.getKey(), uids.keyAt(j)); } } @@ -4523,8 +4967,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++) { - mHistory.recordEvent(mSecRealtime, mSecUptime, HistoryItem.EVENT_PROC_START, - ent.getKey(), uids.keyAt(j)); + addHistoryEventLocked(mSecRealtime, mSecUptime, + HistoryItem.EVENT_PROC_START, ent.getKey(), uids.keyAt(j)); } } } @@ -4567,19 +5011,30 @@ public class BatteryStatsImpl extends BatteryStats { if (mRecordAllHistory) { if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, historyName, mappedUid, 0)) { - mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, + addHistoryEventLocked(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; - mHistory.recordWakelockStartEvent(elapsedRealtimeMs, uptimeMs, historyName, - mappedUid); - } else if (!mWakeLockImportant && !unimportantForLogging) { - if (mHistory.maybeUpdateWakelockTag(elapsedRealtimeMs, uptimeMs, historyName, - mappedUid)) { - mWakeLockImportant = true; - } + 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; } mWakeLockNesting++; } @@ -4632,13 +5087,15 @@ public class BatteryStatsImpl extends BatteryStats { } if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, mappedUid, 0)) { - mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, + addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, mappedUid); } } if (mWakeLockNesting == 0) { - mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE_WAKE_LOCK_FLAG); + mHistoryCur.states &= ~HistoryItem.STATE_WAKE_LOCK_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Stop wake lock to: " + + Integer.toHexString(mHistoryCur.states)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); } } if (mappedUid >= 0) { @@ -4829,7 +5286,7 @@ public class BatteryStatsImpl extends BatteryStats { mappedUid, 0)) { return; } - mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_LONG_WAKE_LOCK_START, + addHistoryEventLocked(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 @@ -4882,7 +5339,7 @@ public class BatteryStatsImpl extends BatteryStats { mappedUid, 0)) { return; } - mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH, + addHistoryEventLocked(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. @@ -4904,10 +5361,15 @@ 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); - mHistory.recordWakeupEvent(elapsedRealtimeMs, uptimeMs, reason); + mHistoryCur.wakeReasonTag = mHistoryCur.localWakeReasonTag; + mHistoryCur.wakeReasonTag.string = reason; + mHistoryCur.wakeReasonTag.uid = 0; mLastWakeupReason = reason; mLastWakeupUptimeMs = uptimeMs; + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); } @GuardedBy("this") @@ -4918,11 +5380,22 @@ 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) { - mStepDetailsCalculator.addCpuStats(totalUTimeMs, totalSTimeMs, statUserTimeMs, - statSystemTimeMs, statIOWaitTimeMs, statIrqTimeMs, - statSoftIrqTimeMs, statIdleTimeMs); + 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; } public void noteProcessDiedLocked(int uid, int pid) { @@ -4952,8 +5425,10 @@ public class BatteryStatsImpl extends BatteryStats { public void noteStartSensorLocked(int uid, int sensor, long elapsedRealtimeMs, long uptimeMs) { uid = mapUid(uid); if (mSensorNesting == 0) { - mHistory.recordStateStartEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE_SENSOR_ON_FLAG); + mHistoryCur.states |= HistoryItem.STATE_SENSOR_ON_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Start sensor to: " + + Integer.toHexString(mHistoryCur.states)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); } mSensorNesting++; getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -4970,8 +5445,10 @@ public class BatteryStatsImpl extends BatteryStats { uid = mapUid(uid); mSensorNesting--; if (mSensorNesting == 0) { - mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE_SENSOR_ON_FLAG); + mHistoryCur.states &= ~HistoryItem.STATE_SENSOR_ON_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Stop sensor to: " + + Integer.toHexString(mHistoryCur.states)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) .noteStopSensor(sensor, elapsedRealtimeMs); @@ -5021,8 +5498,10 @@ public class BatteryStatsImpl extends BatteryStats { } final int mappedUid = mapUid(uid); if (mGpsNesting == 0) { - mHistory.recordStateStartEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE_GPS_ON_FLAG); + mHistoryCur.states |= HistoryItem.STATE_GPS_ON_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Start GPS to: " + + Integer.toHexString(mHistoryCur.states)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); } mGpsNesting++; @@ -5047,8 +5526,10 @@ public class BatteryStatsImpl extends BatteryStats { final int mappedUid = mapUid(uid); mGpsNesting--; if (mGpsNesting == 0) { - mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE_GPS_ON_FLAG); + mHistoryCur.states &= ~HistoryItem.STATE_GPS_ON_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Stop GPS to: " + + Integer.toHexString(mHistoryCur.states)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); stopAllGpsSignalQualityTimersLocked(-1, elapsedRealtimeMs); mGpsSignalQualityBin = -1; } @@ -5081,9 +5562,12 @@ public class BatteryStatsImpl extends BatteryStats { if(!mGpsSignalQualityTimer[signalLevel].isRunningLocked()) { mGpsSignalQualityTimer[signalLevel].startRunningLocked(elapsedRealtimeMs); } - mHistory.recordGpsSignalQualityEvent(elapsedRealtimeMs, uptimeMs, signalLevel); + mHistoryCur.states2 = (mHistoryCur.states2&~HistoryItem.STATE2_GPS_SIGNAL_QUALITY_MASK) + | (signalLevel << HistoryItem.STATE2_GPS_SIGNAL_QUALITY_SHIFT); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mGpsSignalQualityBin = signalLevel; } + return; } @GuardedBy("this") @@ -5256,33 +5740,41 @@ public class BatteryStatsImpl extends BatteryStats { } } - int startStates = 0; - int stopStates = 0; + boolean updateHistory = false; if (Display.isDozeState(state) && !Display.isDozeState(oldState)) { - startStates |= HistoryItem.STATE_SCREEN_DOZE_FLAG; + mHistoryCur.states |= HistoryItem.STATE_SCREEN_DOZE_FLAG; mScreenDozeTimer.startRunningLocked(elapsedRealtimeMs); + updateHistory = true; } else if (Display.isDozeState(oldState) && !Display.isDozeState(state)) { - stopStates |= HistoryItem.STATE_SCREEN_DOZE_FLAG; + mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_DOZE_FLAG; mScreenDozeTimer.stopRunningLocked(elapsedRealtimeMs); + updateHistory = true; } if (Display.isOnState(state)) { - startStates |= HistoryItem.STATE_SCREEN_ON_FLAG; + mHistoryCur.states |= HistoryItem.STATE_SCREEN_ON_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Screen on to: " + + Integer.toHexString(mHistoryCur.states)); mScreenOnTimer.startRunningLocked(elapsedRealtimeMs); if (mScreenBrightnessBin >= 0) { mScreenBrightnessTimer[mScreenBrightnessBin] .startRunningLocked(elapsedRealtimeMs); } + updateHistory = true; } else if (Display.isOnState(oldState)) { - stopStates |= HistoryItem.STATE_SCREEN_ON_FLAG; + mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_ON_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Screen off to: " + + Integer.toHexString(mHistoryCur.states)); mScreenOnTimer.stopRunningLocked(elapsedRealtimeMs); if (mScreenBrightnessBin >= 0) { mScreenBrightnessTimer[mScreenBrightnessBin] .stopRunningLocked(elapsedRealtimeMs); } + updateHistory = true; } - if (startStates != 0 || stopStates != 0) { - mHistory.recordStateChangeEvent(elapsedRealtimeMs, uptimeMs, startStates, - stopStates); + if (updateHistory) { + if (DEBUG_HISTORY) Slog.v(TAG, "Screen state to: " + + Display.stateToString(state)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); } // Per screen state Cpu stats needed. Prepare to schedule an external sync. @@ -5396,7 +5888,13 @@ public class BatteryStatsImpl extends BatteryStats { long uptimeMs) { if (mScreenBrightnessBin != overallBin) { if (overallBin >= 0) { - mHistory.recordScreenBrightnessEvent(elapsedRealtimeMs, uptimeMs, overallBin); + 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); } if (mScreenState == Display.STATE_ON) { if (mScreenBrightnessBin >= 0) { @@ -5424,8 +5922,8 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void noteWakeUpLocked(String reason, int reasonUid, long elapsedRealtimeMs, long uptimeMs) { - mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_SCREEN_WAKE_UP, reason, - reasonUid); + addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_SCREEN_WAKE_UP, + reason, reasonUid); } @GuardedBy("this") @@ -5444,7 +5942,7 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void noteConnectivityChangedLocked(int type, String extra, long elapsedRealtimeMs, long uptimeMs) { - mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_CONNECTIVITY_CHANGED, + addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_CONNECTIVITY_CHANGED, extra, type); mNumConnectivityChange++; } @@ -5453,7 +5951,7 @@ public class BatteryStatsImpl extends BatteryStats { private void noteMobileRadioApWakeupLocked(final long elapsedRealtimeMillis, final long uptimeMillis, int uid) { uid = mapUid(uid); - mHistory.recordEvent(elapsedRealtimeMillis, uptimeMillis, HistoryItem.EVENT_WAKEUP_AP, "", + addHistoryEventLocked(elapsedRealtimeMillis, uptimeMillis, HistoryItem.EVENT_WAKEUP_AP, "", uid); getUidStatsLocked(uid, elapsedRealtimeMillis, uptimeMillis).noteMobileRadioApWakeupLocked(); } @@ -5479,8 +5977,7 @@ public class BatteryStatsImpl extends BatteryStats { } mMobileRadioActiveStartTimeMs = realElapsedRealtimeMs = timestampNs / (1000 * 1000); - mHistory.recordStateStartEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG); + mHistoryCur.states |= HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG; } else { realElapsedRealtimeMs = timestampNs / (1000*1000); long lastUpdateTimeMs = mMobileRadioActiveStartTimeMs; @@ -5492,9 +5989,11 @@ public class BatteryStatsImpl extends BatteryStats { mMobileRadioActiveAdjustedTime.addCountLocked(elapsedRealtimeMs - realElapsedRealtimeMs); } - mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG); + mHistoryCur.states &= ~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. @@ -5544,14 +6043,17 @@ public class BatteryStatsImpl extends BatteryStats { mCurStepMode = (mCurStepMode&~STEP_LEVEL_MODE_POWER_SAVE) | stepState; mPowerSaveModeEnabled = enabled; if (enabled) { - mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_POWER_SAVE_FLAG); + mHistoryCur.states2 |= HistoryItem.STATE2_POWER_SAVE_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Power save mode enabled to: " + + Integer.toHexString(mHistoryCur.states2)); mPowerSaveModeEnabledTimer.startRunningLocked(elapsedRealtimeMs); } else { - mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_POWER_SAVE_FLAG); + mHistoryCur.states2 &= ~HistoryItem.STATE2_POWER_SAVE_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Power save mode disabled to: " + + Integer.toHexString(mHistoryCur.states2)); mPowerSaveModeEnabledTimer.stopRunningLocked(elapsedRealtimeMs); } + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); FrameworkStatsLog.write(FrameworkStatsLog.BATTERY_SAVER_MODE_STATE_CHANGED, enabled ? FrameworkStatsLog.BATTERY_SAVER_MODE_STATE_CHANGED__STATE__ON @@ -5575,7 +6077,7 @@ public class BatteryStatsImpl extends BatteryStats { nowLightIdling = true; } if (activeReason != null && (mDeviceIdling || mDeviceLightIdling)) { - mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_ACTIVE, + addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_ACTIVE, activeReason, activeUid); } if (mDeviceIdling != nowIdling || mDeviceLightIdling != nowLightIdling) { @@ -5605,7 +6107,11 @@ public class BatteryStatsImpl extends BatteryStats { } } if (mDeviceIdleMode != mode) { - mHistory.recordDeviceIdleEvent(elapsedRealtimeMs, uptimeMs, 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); long lastDuration = elapsedRealtimeMs - mLastIdleTimeStartMs; mLastIdleTimeStartMs = elapsedRealtimeMs; if (mDeviceIdleMode == DEVICE_IDLE_MODE_LIGHT) { @@ -5633,7 +6139,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. - mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_PACKAGE_INSTALLED, + addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_PACKAGE_INSTALLED, pkgName, (int)versionCode); PackageChange pc = new PackageChange(); pc.mPackageName = pkgName; @@ -5645,8 +6151,8 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void notePackageUninstalledLocked(String pkgName, long elapsedRealtimeMs, long uptimeMs) { - mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_PACKAGE_UNINSTALLED, - pkgName, 0); + addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, + HistoryItem.EVENT_PACKAGE_UNINSTALLED, pkgName, 0); PackageChange pc = new PackageChange(); pc.mPackageName = pkgName; pc.mUpdate = true; @@ -5675,8 +6181,10 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void notePhoneOnLocked(long elapsedRealtimeMs, long uptimeMs) { if (!mPhoneOn) { - mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_PHONE_IN_CALL_FLAG); + mHistoryCur.states2 |= HistoryItem.STATE2_PHONE_IN_CALL_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Phone on to: " + + Integer.toHexString(mHistoryCur.states)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mPhoneOn = true; mPhoneOnTimer.startRunningLocked(elapsedRealtimeMs); } @@ -5685,8 +6193,10 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void notePhoneOffLocked(long elapsedRealtimeMs, long uptimeMs) { if (mPhoneOn) { - mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_PHONE_IN_CALL_FLAG); + mHistoryCur.states2 &= ~HistoryItem.STATE2_PHONE_IN_CALL_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Phone off to: " + + Integer.toHexString(mHistoryCur.states)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mPhoneOn = false; mPhoneOnTimer.stopRunningLocked(elapsedRealtimeMs); } @@ -5724,12 +6234,11 @@ public class BatteryStatsImpl extends BatteryStats { if (mUsbDataState != newState) { mUsbDataState = newState; if (connected) { - mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_USB_DATA_LINK_FLAG); + mHistoryCur.states2 |= HistoryItem.STATE2_USB_DATA_LINK_FLAG; } else { - mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_USB_DATA_LINK_FLAG); + mHistoryCur.states2 &= ~HistoryItem.STATE2_USB_DATA_LINK_FLAG; } + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); } } @@ -5750,10 +6259,6 @@ 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; @@ -5782,8 +6287,10 @@ public class BatteryStatsImpl extends BatteryStats { scanning = true; strengthBin = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN; if (!mPhoneSignalScanningTimer.isRunningLocked()) { - addStateFlag = HistoryItem.STATE_PHONE_SCANNING_FLAG; + mHistoryCur.states |= 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); @@ -5793,7 +6300,9 @@ public class BatteryStatsImpl extends BatteryStats { if (!scanning) { // If we are no longer scanning, then stop the scanning timer. if (mPhoneSignalScanningTimer.isRunningLocked()) { - removeStateFlag = HistoryItem.STATE_PHONE_SCANNING_FLAG; + mHistoryCur.states &= ~HistoryItem.STATE_PHONE_SCANNING_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Phone stopped scanning to: " + + Integer.toHexString(mHistoryCur.states)); newHistory = true; mPhoneSignalScanningTimer.stopRunningLocked(elapsedRealtimeMs); FrameworkStatsLog.write(FrameworkStatsLog.PHONE_SERVICE_STATE_CHANGED, state, @@ -5802,7 +6311,10 @@ public class BatteryStatsImpl extends BatteryStats { } if (mPhoneServiceState != state) { - newState = 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)); newHistory = true; mPhoneServiceState = state; } @@ -5816,7 +6328,11 @@ public class BatteryStatsImpl extends BatteryStats { if (!mPhoneSignalStrengthsTimer[strengthBin].isRunningLocked()) { mPhoneSignalStrengthsTimer[strengthBin].startRunningLocked(elapsedRealtimeMs); } - newSignalStrength = strengthBin; + 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)); newHistory = true; FrameworkStatsLog.write( FrameworkStatsLog.PHONE_SIGNAL_STRENGTH_CHANGED, strengthBin); @@ -5827,8 +6343,7 @@ public class BatteryStatsImpl extends BatteryStats { } if (newHistory) { - mHistory.recordPhoneStateChangeEvent(elapsedRealtimeMs, uptimeMs, - addStateFlag, removeStateFlag, newState, newSignalStrength); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); } } @@ -5952,7 +6467,11 @@ public class BatteryStatsImpl extends BatteryStats { if (DEBUG) Log.i(TAG, "Phone Data Connection -> " + dataType + " = " + hasData); if (mPhoneDataConnectionType != bin) { - mHistory.recordDataConnectionTypeChangeEvent(elapsedRealtimeMs, uptimeMs, 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); if (mPhoneDataConnectionType >= 0) { mPhoneDataConnectionsTimer[mPhoneDataConnectionType].stopRunningLocked( elapsedRealtimeMs); @@ -6025,8 +6544,10 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void noteWifiOnLocked(long elapsedRealtimeMs, long uptimeMs) { if (!mWifiOn) { - mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_WIFI_ON_FLAG); + mHistoryCur.states2 |= HistoryItem.STATE2_WIFI_ON_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "WIFI on to: " + + Integer.toHexString(mHistoryCur.states)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mWifiOn = true; mWifiOnTimer.startRunningLocked(elapsedRealtimeMs); scheduleSyncExternalStatsLocked("wifi-off", ExternalStatsSync.UPDATE_WIFI); @@ -6036,8 +6557,10 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void noteWifiOffLocked(long elapsedRealtimeMs, long uptimeMs) { if (mWifiOn) { - mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_WIFI_ON_FLAG); + mHistoryCur.states2 &= ~HistoryItem.STATE2_WIFI_ON_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "WIFI off to: " + + Integer.toHexString(mHistoryCur.states)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mWifiOn = false; mWifiOnTimer.stopRunningLocked(elapsedRealtimeMs); scheduleSyncExternalStatsLocked("wifi-on", ExternalStatsSync.UPDATE_WIFI); @@ -6048,8 +6571,10 @@ public class BatteryStatsImpl extends BatteryStats { public void noteAudioOnLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { uid = mapUid(uid); if (mAudioOnNesting == 0) { - mHistory.recordStateStartEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE_AUDIO_ON_FLAG); + mHistoryCur.states |= HistoryItem.STATE_AUDIO_ON_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Audio on to: " + + Integer.toHexString(mHistoryCur.states)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mAudioOnTimer.startRunningLocked(elapsedRealtimeMs); } mAudioOnNesting++; @@ -6064,8 +6589,10 @@ public class BatteryStatsImpl extends BatteryStats { } uid = mapUid(uid); if (--mAudioOnNesting == 0) { - mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE_AUDIO_ON_FLAG); + mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: " + + Integer.toHexString(mHistoryCur.states)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mAudioOnTimer.stopRunningLocked(elapsedRealtimeMs); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -6076,8 +6603,10 @@ public class BatteryStatsImpl extends BatteryStats { public void noteVideoOnLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { uid = mapUid(uid); if (mVideoOnNesting == 0) { - mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_VIDEO_ON_FLAG); + mHistoryCur.states2 |= HistoryItem.STATE2_VIDEO_ON_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Video on to: " + + Integer.toHexString(mHistoryCur.states)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mVideoOnTimer.startRunningLocked(elapsedRealtimeMs); } mVideoOnNesting++; @@ -6092,8 +6621,10 @@ public class BatteryStatsImpl extends BatteryStats { } uid = mapUid(uid); if (--mVideoOnNesting == 0) { - mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_VIDEO_ON_FLAG); + mHistoryCur.states2 &= ~HistoryItem.STATE2_VIDEO_ON_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: " + + Integer.toHexString(mHistoryCur.states)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mVideoOnTimer.stopRunningLocked(elapsedRealtimeMs); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -6104,8 +6635,10 @@ public class BatteryStatsImpl extends BatteryStats { public void noteResetAudioLocked(long elapsedRealtimeMs, long uptimeMs) { if (mAudioOnNesting > 0) { mAudioOnNesting = 0; - mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE_AUDIO_ON_FLAG); + mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: " + + Integer.toHexString(mHistoryCur.states)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mAudioOnTimer.stopAllRunningLocked(elapsedRealtimeMs); for (int i=0; i<mUidStats.size(); i++) { BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); @@ -6118,8 +6651,10 @@ public class BatteryStatsImpl extends BatteryStats { public void noteResetVideoLocked(long elapsedRealtimeMs, long uptimeMs) { if (mVideoOnNesting > 0) { mVideoOnNesting = 0; - mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_VIDEO_ON_FLAG); + mHistoryCur.states2 &= ~HistoryItem.STATE2_VIDEO_ON_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: " + + Integer.toHexString(mHistoryCur.states)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mVideoOnTimer.stopAllRunningLocked(elapsedRealtimeMs); for (int i=0; i<mUidStats.size(); i++) { BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); @@ -6171,8 +6706,10 @@ public class BatteryStatsImpl extends BatteryStats { public void noteFlashlightOnLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { uid = mapUid(uid); if (mFlashlightOnNesting++ == 0) { - mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_FLASHLIGHT_FLAG); + mHistoryCur.states2 |= HistoryItem.STATE2_FLASHLIGHT_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight on to: " + + Integer.toHexString(mHistoryCur.states2)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mFlashlightOnTimer.startRunningLocked(elapsedRealtimeMs); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -6186,8 +6723,10 @@ public class BatteryStatsImpl extends BatteryStats { } uid = mapUid(uid); if (--mFlashlightOnNesting == 0) { - mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_FLASHLIGHT_FLAG); + mHistoryCur.states2 &= ~HistoryItem.STATE2_FLASHLIGHT_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight off to: " + + Integer.toHexString(mHistoryCur.states2)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mFlashlightOnTimer.stopRunningLocked(elapsedRealtimeMs); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -6198,8 +6737,10 @@ public class BatteryStatsImpl extends BatteryStats { public void noteCameraOnLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { uid = mapUid(uid); if (mCameraOnNesting++ == 0) { - mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_CAMERA_FLAG); + mHistoryCur.states2 |= HistoryItem.STATE2_CAMERA_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Camera on to: " + + Integer.toHexString(mHistoryCur.states2)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mCameraOnTimer.startRunningLocked(elapsedRealtimeMs); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -6213,8 +6754,10 @@ public class BatteryStatsImpl extends BatteryStats { } uid = mapUid(uid); if (--mCameraOnNesting == 0) { - mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_CAMERA_FLAG); + mHistoryCur.states2 &= ~HistoryItem.STATE2_CAMERA_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Camera off to: " + + Integer.toHexString(mHistoryCur.states2)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mCameraOnTimer.stopRunningLocked(elapsedRealtimeMs); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -6225,8 +6768,10 @@ public class BatteryStatsImpl extends BatteryStats { public void noteResetCameraLocked(long elapsedRealtimeMs, long uptimeMs) { if (mCameraOnNesting > 0) { mCameraOnNesting = 0; - mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_CAMERA_FLAG); + mHistoryCur.states2 &= ~HistoryItem.STATE2_CAMERA_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Camera off to: " + + Integer.toHexString(mHistoryCur.states2)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mCameraOnTimer.stopAllRunningLocked(elapsedRealtimeMs); for (int i=0; i<mUidStats.size(); i++) { BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); @@ -6239,8 +6784,10 @@ public class BatteryStatsImpl extends BatteryStats { public void noteResetFlashlightLocked(long elapsedRealtimeMs, long uptimeMs) { if (mFlashlightOnNesting > 0) { mFlashlightOnNesting = 0; - mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_FLASHLIGHT_FLAG); + mHistoryCur.states2 &= ~HistoryItem.STATE2_FLASHLIGHT_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight off to: " + + Integer.toHexString(mHistoryCur.states2)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mFlashlightOnTimer.stopAllRunningLocked(elapsedRealtimeMs); for (int i=0; i<mUidStats.size(); i++) { BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); @@ -6257,8 +6804,10 @@ public class BatteryStatsImpl extends BatteryStats { } uid = mapUid(uid); if (mBluetoothScanNesting == 0) { - mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG); + mHistoryCur.states2 |= HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "BLE scan started for: " + + Integer.toHexString(mHistoryCur.states2)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mBluetoothScanTimer.startRunningLocked(elapsedRealtimeMs); } mBluetoothScanNesting++; @@ -6299,8 +6848,10 @@ public class BatteryStatsImpl extends BatteryStats { uid = mapUid(uid); mBluetoothScanNesting--; if (mBluetoothScanNesting == 0) { - mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG); + mHistoryCur.states2 &= ~HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "BLE scan stopped for: " + + Integer.toHexString(mHistoryCur.states2)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mBluetoothScanTimer.stopRunningLocked(elapsedRealtimeMs); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -6335,8 +6886,10 @@ public class BatteryStatsImpl extends BatteryStats { public void noteResetBluetoothScanLocked(long elapsedRealtimeMs, long uptimeMs) { if (mBluetoothScanNesting > 0) { mBluetoothScanNesting = 0; - mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG); + mHistoryCur.states2 &= ~HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "BLE can stopped for: " + + Integer.toHexString(mHistoryCur.states2)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mBluetoothScanTimer.stopAllRunningLocked(elapsedRealtimeMs); for (int i=0; i<mUidStats.size(); i++) { BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); @@ -6376,7 +6929,7 @@ public class BatteryStatsImpl extends BatteryStats { private void noteWifiRadioApWakeupLocked(final long elapsedRealtimeMillis, final long uptimeMillis, int uid) { uid = mapUid(uid); - mHistory.recordEvent(elapsedRealtimeMillis, uptimeMillis, HistoryItem.EVENT_WAKEUP_AP, "", + addHistoryEventLocked(elapsedRealtimeMillis, uptimeMillis, HistoryItem.EVENT_WAKEUP_AP, "", uid); getUidStatsLocked(uid, elapsedRealtimeMillis, uptimeMillis).noteWifiRadioApWakeupLocked(); } @@ -6392,14 +6945,15 @@ public class BatteryStatsImpl extends BatteryStats { if (uid > 0) { noteWifiRadioApWakeupLocked(elapsedRealtimeMs, uptimeMs, uid); } - mHistory.recordStateStartEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE_WIFI_RADIO_ACTIVE_FLAG); + mHistoryCur.states |= HistoryItem.STATE_WIFI_RADIO_ACTIVE_FLAG; mWifiActiveTimer.startRunningLocked(elapsedRealtimeMs); } else { - mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE_WIFI_RADIO_ACTIVE_FLAG); + mHistoryCur.states &= ~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; } } @@ -6407,8 +6961,10 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void noteWifiRunningLocked(WorkSource ws, long elapsedRealtimeMs, long uptimeMs) { if (!mGlobalWifiRunning) { - mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_WIFI_RUNNING_FLAG); + mHistoryCur.states2 |= HistoryItem.STATE2_WIFI_RUNNING_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "WIFI running to: " + + Integer.toHexString(mHistoryCur.states)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mGlobalWifiRunning = true; mGlobalWifiRunningTimer.startRunningLocked(elapsedRealtimeMs); int N = ws.size(); @@ -6476,8 +7032,10 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void noteWifiStoppedLocked(WorkSource ws, long elapsedRealtimeMs, long uptimeMs) { if (mGlobalWifiRunning) { - mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_WIFI_RUNNING_FLAG); + mHistoryCur.states2 &= ~HistoryItem.STATE2_WIFI_RUNNING_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "WIFI stopped to: " + + Integer.toHexString(mHistoryCur.states)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mGlobalWifiRunning = false; mGlobalWifiRunningTimer.stopRunningLocked(elapsedRealtimeMs); int N = ws.size(); @@ -6525,7 +7083,12 @@ public class BatteryStatsImpl extends BatteryStats { } mWifiSupplState = supplState; mWifiSupplStateTimer[supplState].startRunningLocked(elapsedRealtimeMs); - mHistory.recordWifiSupplicantStateChangeEvent(elapsedRealtimeMs, uptimeMs, supplState); + 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); } } @@ -6554,8 +7117,12 @@ public class BatteryStatsImpl extends BatteryStats { if (!mWifiSignalStrengthsTimer[strengthBin].isRunningLocked()) { mWifiSignalStrengthsTimer[strengthBin].startRunningLocked(elapsedRealtimeMs); } - mHistory.recordWifiSignalStrengthChangeEvent(elapsedRealtimeMs, uptimeMs, - strengthBin); + 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); } else { stopAllWifiSignalStrengthTimersLocked(-1, elapsedRealtimeMs); } @@ -6568,8 +7135,10 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void noteFullWifiLockAcquiredLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { if (mWifiFullLockNesting == 0) { - mHistory.recordStateStartEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE_WIFI_FULL_LOCK_FLAG); + 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); } mWifiFullLockNesting++; getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -6580,8 +7149,10 @@ public class BatteryStatsImpl extends BatteryStats { public void noteFullWifiLockReleasedLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { mWifiFullLockNesting--; if (mWifiFullLockNesting == 0) { - mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE_WIFI_FULL_LOCK_FLAG); + 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); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) .noteFullWifiLockReleasedLocked(elapsedRealtimeMs); @@ -6597,8 +7168,10 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void noteWifiScanStartedLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { if (mWifiScanNesting == 0) { - mHistory.recordStateStartEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE_WIFI_SCAN_FLAG); + mHistoryCur.states |= HistoryItem.STATE_WIFI_SCAN_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan started for: " + + Integer.toHexString(mHistoryCur.states)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); } mWifiScanNesting++; getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) @@ -6614,8 +7187,10 @@ public class BatteryStatsImpl extends BatteryStats { public void noteWifiScanStoppedLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { mWifiScanNesting--; if (mWifiScanNesting == 0) { - mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE_WIFI_SCAN_FLAG); + mHistoryCur.states &= ~HistoryItem.STATE_WIFI_SCAN_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan stopped for: " + + Integer.toHexString(mHistoryCur.states)); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) .noteWifiScanStoppedLocked(elapsedRealtimeMs); @@ -6640,10 +7215,14 @@ public class BatteryStatsImpl extends BatteryStats { public void noteWifiMulticastEnabledLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { uid = mapUid(uid); if (mWifiMulticastNesting == 0) { - mHistory.recordStateStartEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG); + 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); + // Start Wifi Multicast overall timer if (!mWifiMulticastWakelockTimer.isRunningLocked()) { + if (DEBUG_HISTORY) Slog.v(TAG, "WiFi Multicast Overall Timer Started"); mWifiMulticastWakelockTimer.startRunningLocked(elapsedRealtimeMs); } } @@ -6657,12 +7236,14 @@ public class BatteryStatsImpl extends BatteryStats { uid = mapUid(uid); mWifiMulticastNesting--; if (mWifiMulticastNesting == 0) { - mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG); + 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); // Stop Wifi Multicast overall timer if (mWifiMulticastWakelockTimer.isRunningLocked()) { - if (DEBUG) Slog.v(TAG, "Multicast Overall Timer Stopped"); + if (DEBUG_HISTORY) Slog.v(TAG, "Multicast Overall Timer Stopped"); mWifiMulticastWakelockTimer.stopRunningLocked(elapsedRealtimeMs); } } @@ -7414,9 +7995,8 @@ 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. - mHistory.recordCurrentTimeChange(mClock.elapsedRealtime(), mClock.uptimeMillis(), - currentTimeMs - ); + recordCurrentTimeChangeLocked(currentTimeMs, mClock.elapsedRealtime(), + mClock.uptimeMillis()); return currentTimeMs - (mClock.elapsedRealtime() - (mRealtimeStartUs / 1000)); } return mStartClockTimeMs; @@ -10648,19 +11228,18 @@ public class BatteryStatsImpl extends BatteryStats { UserInfoProvider userInfoProvider) { init(clock); - mHandler = new MyHandler(handler.getLooper()); - mConstants = new Constants(mHandler); - if (systemDir == null) { mStatsFile = null; - mHistory = new BatteryStatsHistory(mStepDetailsCalculator, mClock); + mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer); } else { mStatsFile = new AtomicFile(new File(systemDir, "batterystats.bin")); - mHistory = new BatteryStatsHistory(systemDir, mConstants.MAX_HISTORY_FILES, - mConstants.MAX_HISTORY_BUFFER, mStepDetailsCalculator, mClock); + mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer, systemDir, + this::getMaxHistoryFiles); } 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; @@ -10669,6 +11248,7 @@ public class BatteryStatsImpl extends BatteryStats { initTimes(uptimeUs, realtimeUs); mStartPlatformVersion = mEndPlatformVersion = Build.ID; initDischarge(realtimeUs); + clearHistoryLocked(); updateDailyDeadlineLocked(); mPlatformIdleStateCallback = cb; mMeasuredEnergyRetriever = energyStatsCb; @@ -10679,6 +11259,12 @@ 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); @@ -10760,7 +11346,7 @@ public class BatteryStatsImpl extends BatteryStats { mDischargeUnplugLevel = 0; mDischargePlugLevel = -1; mDischargeCurrentLevel = 0; - mBatteryLevel = 0; + mCurrentBatteryLevel = 0; } public void setPowerProfileLocked(PowerProfile profile) { @@ -11147,7 +11733,7 @@ public class BatteryStatsImpl extends BatteryStats { } public int getHistoryUsedSize() { - return mHistory.getHistoryUsedSize(); + return mBatteryStatsHistory.getHistoryUsedSize(); } @Override @@ -11161,27 +11747,43 @@ public class BatteryStatsImpl extends BatteryStats { */ @VisibleForTesting public BatteryStatsHistoryIterator createBatteryStatsHistoryIterator() { - return mHistory.iterate(); + return new BatteryStatsHistoryIterator(mBatteryStatsHistory); } @Override public int getHistoryStringPoolSize() { - return mHistory.getHistoryStringPoolSize(); + return mHistoryTagPool.size(); } @Override public int getHistoryStringPoolBytes() { - return mHistory.getHistoryStringPoolBytes(); + return mNumHistoryTagChars; } @Override public String getHistoryTagPoolString(int index) { - return mHistory.getHistoryTagPoolString(index); + ensureHistoryTagArray(); + HistoryTag historyTag = mHistoryTags.get(index); + return historyTag != null ? historyTag.string : null; } @Override public int getHistoryTagPoolUid(int index) { - return mHistory.getHistoryTagPoolUid(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()); + } } @Override @@ -11191,11 +11793,15 @@ 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; } @@ -11248,23 +11854,24 @@ public class BatteryStatsImpl extends BatteryStats { long realtimeUs = mSecRealtime * 1000; resetAllStatsLocked(mSecUptime, mSecRealtime, RESET_REASON_ADB_COMMAND); pullPendingStateUpdatesLocked(); - mHistory.writeHistoryItem(mSecRealtime, mSecUptime); - mDischargeCurrentLevel = mDischargeUnplugLevel = mDischargePlugLevel = mBatteryLevel; + addHistoryRecordLocked(mSecRealtime, mSecUptime); + mDischargeCurrentLevel = mDischargeUnplugLevel = mDischargePlugLevel + = mCurrentBatteryLevel = mHistoryCur.batteryLevel; mOnBatteryTimeBase.reset(uptimeUs, realtimeUs); mOnBatteryScreenOffTimeBase.reset(uptimeUs, realtimeUs); - if (!mBatteryPluggedIn) { + if ((mHistoryCur.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) == 0) { if (Display.isOnState(mScreenState)) { - mDischargeScreenOnUnplugLevel = mBatteryLevel; + mDischargeScreenOnUnplugLevel = mHistoryCur.batteryLevel; mDischargeScreenDozeUnplugLevel = 0; mDischargeScreenOffUnplugLevel = 0; } else if (Display.isDozeState(mScreenState)) { mDischargeScreenOnUnplugLevel = 0; - mDischargeScreenDozeUnplugLevel = mBatteryLevel; + mDischargeScreenDozeUnplugLevel = mHistoryCur.batteryLevel; mDischargeScreenOffUnplugLevel = 0; } else { mDischargeScreenOnUnplugLevel = 0; mDischargeScreenDozeUnplugLevel = 0; - mDischargeScreenOffUnplugLevel = mBatteryLevel; + mDischargeScreenOffUnplugLevel = mHistoryCur.batteryLevel; } mDischargeAmountScreenOn = 0; mDischargeAmountScreenOff = 0; @@ -11408,12 +12015,27 @@ 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); - mHistory.reset(); + clearHistoryLocked(); + if (mBatteryStatsHistory != null) { + mBatteryStatsHistory.resetAllFiles(); + } // Flush external data, gathering snapshots, but don't process it since it is pre-reset data mIgnoreNextExternalStats = true; @@ -11436,7 +12058,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++) { - mHistory.recordEvent(elapsedRealtimeMs, uptimeMs, i, ent.getKey(), + addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, i, ent.getKey(), uids.keyAt(j)); } } @@ -11861,8 +12483,9 @@ public class BatteryStatsImpl extends BatteryStats { (long) (mTmpRailStats.getWifiTotalEnergyUseduWs() / opVolt); mWifiActivity.getMonitoredRailChargeConsumedMaMs().addCountLocked( monitoredRailChargeConsumedMaMs); - mHistory.recordWifiConsumedCharge(elapsedRealtimeMs, uptimeMs, - (monitoredRailChargeConsumedMaMs / MILLISECONDS_IN_HOUR)); + mHistoryCur.wifiRailChargeMah += + (monitoredRailChargeConsumedMaMs / MILLISECONDS_IN_HOUR); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mTmpRailStats.resetWifiTotalEnergyUsed(); if (uidEstimatedConsumptionMah != null) { @@ -11975,8 +12598,9 @@ public class BatteryStatsImpl extends BatteryStats { (long) (mTmpRailStats.getCellularTotalEnergyUseduWs() / opVolt); mModemActivity.getMonitoredRailChargeConsumedMaMs().addCountLocked( monitoredRailChargeConsumedMaMs); - mHistory.recordWifiConsumedCharge(elapsedRealtimeMs, uptimeMs, - (monitoredRailChargeConsumedMaMs / MILLISECONDS_IN_HOUR)); + mHistoryCur.modemRailChargeMah += + (monitoredRailChargeConsumedMaMs / MILLISECONDS_IN_HOUR); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mTmpRailStats.resetCellularTotalEnergyUsed(); } @@ -12244,8 +12868,8 @@ public class BatteryStatsImpl extends BatteryStats { } } if (levelMaxTimeSpent == ModemActivityInfo.getNumTxPowerLevels() - 1) { - mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs, - HistoryItem.STATE2_CELLULAR_HIGH_TX_POWER_FLAG); + mHistoryCur.states2 |= HistoryItem.STATE2_CELLULAR_HIGH_TX_POWER_FLAG; + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); } } @@ -13678,7 +14302,11 @@ public class BatteryStatsImpl extends BatteryStats { mHandler.removeCallbacks(mDeferSetCharging); if (mCharging != charging) { mCharging = charging; - mHistory.setChargingState(charging); + if (charging) { + mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG; + } else { + mHistoryCur.states2 &= ~HistoryItem.STATE2_CHARGING_FLAG; + } mHandler.sendEmptyMessage(MSG_REPORT_CHARGING); return true; } @@ -13692,15 +14320,6 @@ 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) { @@ -13784,12 +14403,15 @@ 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) { - mHistory.startRecordingHistory(mSecRealtime, mSecUptime, reset); - initActiveHistoryEventsLocked(mSecRealtime, mSecUptime); + mRecordingHistory = true; + startRecordingHistory(mSecRealtime, mSecUptime, reset); } - mBatteryPluggedIn = false; - mHistory.recordBatteryState(mSecRealtime, mSecUptime, level, mBatteryPluggedIn); + addHistoryRecordLocked(mSecRealtime, mSecUptime); mDischargeCurrentLevel = mDischargeUnplugLevel = level; if (Display.isOnState(screenState)) { mDischargeScreenOnUnplugLevel = level; @@ -13811,8 +14433,11 @@ public class BatteryStatsImpl extends BatteryStats { } else { mOnBattery = mOnBatteryInternal = false; pullPendingStateUpdatesLocked(); - mBatteryPluggedIn = true; - mHistory.recordBatteryState(mSecRealtime, mSecUptime, level, mBatteryPluggedIn); + 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); mDischargeCurrentLevel = mDischargePlugLevel = level; if (level < mDischargeUnplugLevel) { mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1; @@ -13827,12 +14452,45 @@ public class BatteryStatsImpl extends BatteryStats { mModStepMode = 0; } if (doWrite || (mLastWriteTimeMs + (60 * 1000)) < mSecRealtime) { - if (mStatsFile != null && !mHistory.isReadOnly()) { + if (mStatsFile != null && mBatteryStatsHistory.getActiveFile() != null) { 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); @@ -13850,7 +14508,8 @@ 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(status, plugType, level); + reportChangesToStatsLog(mHaveBatteryLevel ? mHistoryCur : null, + status, plugType, level); final boolean onBattery = isOnBattery(plugType, status); if (!mHaveBatteryLevel) { @@ -13860,47 +14519,52 @@ 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) { - mHistory.setPluggedInState(!onBattery); + if (onBattery) { + mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG; + } else { + mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG; + } } - mBatteryStatus = status; - mBatteryLevel = level; - mBatteryChargeUah = chargeUah; - // Always start out assuming charging, that will be updated later. - mHistory.setBatteryState(true /* charging */, status, level, chargeUah); - + mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG; + mHistoryCur.batteryStatus = (byte)status; + mHistoryCur.batteryLevel = (byte)level; + mHistoryCur.batteryChargeUah = chargeUah; mMaxChargeStepLevel = mMinDischargeStepLevel = mLastChargeStepLevel = mLastDischargeStepLevel = level; - } else if (mBatteryLevel != level || mOnBattery != onBattery) { + } else if (mCurrentBatteryLevel != level || mOnBattery != onBattery) { recordDailyStatsIfNeededLocked(level >= 100 && onBattery, currentTimeMs); } - int oldStatus = mBatteryStatus; + int oldStatus = mHistoryCur.batteryStatus; if (onBattery) { mDischargeCurrentLevel = level; - if (!mHistory.isRecordingHistory()) { - mHistory.startRecordingHistory(elapsedRealtimeMs, uptimeMs, true); + if (!mRecordingHistory) { + mRecordingHistory = true; + startRecordingHistory(elapsedRealtimeMs, uptimeMs, true); } } else if (level < 96 && status != BatteryManager.BATTERY_STATUS_UNKNOWN) { - if (!mHistory.isRecordingHistory()) { - mHistory.startRecordingHistory(elapsedRealtimeMs, uptimeMs, true); + if (!mRecordingHistory) { + mRecordingHistory = true; + startRecordingHistory(elapsedRealtimeMs, uptimeMs, true); } } + mBatteryVoltageMv = voltageMv; + mCurrentBatteryLevel = level; if (mDischargePlugLevel < 0) { mDischargePlugLevel = level; } if (onBattery != mOnBattery) { - mBatteryLevel = level; - mBatteryStatus = status; - mBatteryHealth = health; - mBatteryPlugType = plugType; - mBatteryTemperature = temp; - mBatteryVoltageMv = voltageMv; - mHistory.setBatteryState(status, level, health, plugType, temp, voltageMv, chargeUah); - if (chargeUah < mBatteryChargeUah) { + 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) { // Only record discharges - final long chargeDiff = (long) mBatteryChargeUah - chargeUah; + final long chargeDiff = mHistoryCur.batteryChargeUah - chargeUah; mDischargeCounter.addCountLocked(chargeDiff); mDischargeScreenOffCounter.addCountLocked(chargeDiff); if (Display.isDozeState(mScreenState)) { @@ -13912,12 +14576,12 @@ public class BatteryStatsImpl extends BatteryStats { mDischargeDeepDozeCounter.addCountLocked(chargeDiff); } } - mBatteryChargeUah = chargeUah; + mHistoryCur.batteryChargeUah = chargeUah; setOnBatteryLocked(elapsedRealtimeMs, uptimeMs, onBattery, oldStatus, level, chargeUah); } else { boolean changed = false; - if (mBatteryLevel != level) { - mBatteryLevel = level; + if (mHistoryCur.batteryLevel != level) { + mHistoryCur.batteryLevel = (byte)level; changed = true; // TODO(adamlesinski): Schedule the creation of a HistoryStepDetails record @@ -13925,33 +14589,33 @@ public class BatteryStatsImpl extends BatteryStats { mExternalSync.scheduleSyncDueToBatteryLevelChange( mConstants.BATTERY_LEVEL_COLLECTION_DELAY_MS); } - if (mBatteryStatus != status) { - mBatteryStatus = status; + if (mHistoryCur.batteryStatus != status) { + mHistoryCur.batteryStatus = (byte)status; changed = true; } - if (mBatteryHealth != health) { - mBatteryHealth = health; + if (mHistoryCur.batteryHealth != health) { + mHistoryCur.batteryHealth = (byte)health; changed = true; } - if (mBatteryPlugType != plugType) { - mBatteryPlugType = plugType; + if (mHistoryCur.batteryPlugType != plugType) { + mHistoryCur.batteryPlugType = (byte)plugType; changed = true; } - if (temp >= (mBatteryTemperature + 10) - || temp <= (mBatteryTemperature - 10)) { - mBatteryTemperature = temp; + if (temp >= (mHistoryCur.batteryTemperature+10) + || temp <= (mHistoryCur.batteryTemperature-10)) { + mHistoryCur.batteryTemperature = (short)temp; changed = true; } - if (voltageMv > (mBatteryVoltageMv + 20) - || voltageMv < (mBatteryVoltageMv - 20)) { - mBatteryVoltageMv = voltageMv; + if (voltageMv > (mHistoryCur.batteryVoltage + 20) + || voltageMv < (mHistoryCur.batteryVoltage - 20)) { + mHistoryCur.batteryVoltage = (char) voltageMv; changed = true; } - if (chargeUah >= (mBatteryChargeUah + 10) - || chargeUah <= (mBatteryChargeUah - 10)) { - if (chargeUah < mBatteryChargeUah) { + if (chargeUah >= (mHistoryCur.batteryChargeUah + 10) + || chargeUah <= (mHistoryCur.batteryChargeUah - 10)) { + if (chargeUah < mHistoryCur.batteryChargeUah) { // Only record discharges - final long chargeDiff = (long) mBatteryChargeUah - chargeUah; + final long chargeDiff = mHistoryCur.batteryChargeUah - chargeUah; mDischargeCounter.addCountLocked(chargeDiff); mDischargeScreenOffCounter.addCountLocked(chargeDiff); if (Display.isDozeState(mScreenState)) { @@ -13963,10 +14627,9 @@ public class BatteryStatsImpl extends BatteryStats { mDischargeDeepDozeCounter.addCountLocked(chargeDiff); } } - mBatteryChargeUah = chargeUah; + mHistoryCur.batteryChargeUah = 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); @@ -14024,10 +14687,7 @@ public class BatteryStatsImpl extends BatteryStats { mLastChargeStepLevel = level; } if (changed) { - mHistory.setBatteryState(mBatteryStatus, mBatteryLevel, mBatteryHealth, - mBatteryPlugType, mBatteryTemperature, mBatteryVoltageMv, - mBatteryChargeUah); - mHistory.writeHistoryItem(elapsedRealtimeMs, uptimeMs); + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); } } if (!onBattery && @@ -14036,7 +14696,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. - mHistory.setHistoryRecordingEnabled(DEBUG); + mRecordingHistory = DEBUG; } mLastLearnedBatteryCapacityUah = chargeFullUah; @@ -14055,18 +14715,17 @@ public class BatteryStatsImpl extends BatteryStats { } // Inform StatsLog of setBatteryState changes. - private void reportChangesToStatsLog(final int status, final int plugType, final int level) { - if (!mHaveBatteryLevel) { - return; - } + // If this is the first reporting, pass in recentPast == null. + private void reportChangesToStatsLog(HistoryItem recentPast, + final int status, final int plugType, final int level) { - if (mBatteryStatus != status) { + if (recentPast == null || recentPast.batteryStatus != status) { FrameworkStatsLog.write(FrameworkStatsLog.CHARGING_STATE_CHANGED, status); } - if (mBatteryPlugType != plugType) { + if (recentPast == null || recentPast.batteryPlugType != plugType) { FrameworkStatsLog.write(FrameworkStatsLog.PLUGGED_STATE_CHANGED, plugType); } - if (mBatteryLevel != level) { + if (recentPast == null || recentPast.batteryLevel != level) { FrameworkStatsLog.write(FrameworkStatsLog.BATTERY_LEVEL_CHANGED, level); } } @@ -14136,7 +14795,7 @@ public class BatteryStatsImpl extends BatteryStats { if (msPerLevel <= 0) { return -1; } - return (msPerLevel * mBatteryLevel) * 1000; + return (msPerLevel * mCurrentBatteryLevel) * 1000; } @Override @@ -14166,7 +14825,7 @@ public class BatteryStatsImpl extends BatteryStats { if (msPerLevel <= 0) { return -1; } - return (msPerLevel * (100 - mBatteryLevel)) * 1000; + return (msPerLevel * (100 - mCurrentBatteryLevel)) * 1000; } /*@hide */ @@ -14597,8 +15256,7 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void shutdownLocked() { - mHistory.recordShutdownEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(), - mClock.currentTimeMillis()); + recordShutdownLocked(mClock.currentTimeMillis(), mClock.elapsedRealtime()); writeSyncLocked(); mShuttingDown = true; } @@ -14806,6 +15464,7 @@ 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 @@ -14816,20 +15475,9 @@ 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, @@ -15050,11 +15698,27 @@ 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; } - mHistory.writeHistory(); + 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(); + } } private final ReentrantLock mWriteLock = new ReentrantLock(); @@ -15093,6 +15757,13 @@ 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(); @@ -15105,7 +15776,7 @@ public class BatteryStatsImpl extends BatteryStats { readSummaryFromParcel(stats); if (DEBUG) { Slog.d(TAG, "readLocked stats file:" + mStatsFile.getBaseFile().getPath() - + " bytes:" + raw.length + " took ms:" + (SystemClock.uptimeMillis() + + " bytes:" + raw.length + " takes ms:" + (SystemClock.uptimeMillis() - start)); } } @@ -15117,19 +15788,126 @@ public class BatteryStatsImpl extends BatteryStats { stats.recycle(); } - if (!mHistory.readSummary()) { - resetAllStatsLocked(SystemClock.uptimeMillis(), SystemClock.elapsedRealtime(), - RESET_REASON_CORRUPT_FILE); + 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(); } mEndPlatformVersion = Build.ID; - mHistory.continueRecordingHistory(); + 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); + } 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(); @@ -15139,7 +15917,31 @@ public class BatteryStatsImpl extends BatteryStats { return; } - mHistory.readSummaryFromParcel(in); + 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; + } mStartCount = in.readInt(); mUptimeUs = in.readLong(); @@ -15152,7 +15954,7 @@ public class BatteryStatsImpl extends BatteryStats { mDischargeUnplugLevel = in.readInt(); mDischargePlugLevel = in.readInt(); mDischargeCurrentLevel = in.readInt(); - mBatteryLevel = in.readInt(); + mCurrentBatteryLevel = in.readInt(); mEstimatedBatteryCapacityMah = in.readInt(); mLastLearnedBatteryCapacityUah = in.readInt(); mMinLearnedBatteryCapacityUah = in.readInt(); @@ -15655,7 +16457,19 @@ public class BatteryStatsImpl extends BatteryStats { out.writeInt(VERSION); - mHistory.writeSummaryToParcel(out, inclHistory); + 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); + } out.writeInt(mStartCount); out.writeLong(computeUptime(nowUptime, STATS_SINCE_CHARGED)); @@ -15668,7 +16482,7 @@ public class BatteryStatsImpl extends BatteryStats { out.writeInt(mDischargeUnplugLevel); out.writeInt(mDischargePlugLevel); out.writeInt(mDischargeCurrentLevel); - out.writeInt(mBatteryLevel); + out.writeInt(mCurrentBatteryLevel); 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 c36d950b6cf6..0cdd4d101459 100644 --- a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java +++ b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java @@ -22,6 +22,7 @@ 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; @@ -31,8 +32,10 @@ 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; @@ -217,7 +220,18 @@ public class BatteryUsageStatsProvider { } BatteryStatsImpl batteryStatsImpl = (BatteryStatsImpl) mStats; - batteryUsageStatsBuilder.setBatteryHistory(batteryStatsImpl.copyHistory()); + + // 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); } BatteryUsageStats stats = batteryUsageStatsBuilder.build(); diff --git a/services/core/java/com/android/server/wm/AppWarnings.java b/services/core/java/com/android/server/wm/AppWarnings.java index 994f07959f3b..5a2409927ecc 100644 --- a/services/core/java/com/android/server/wm/AppWarnings.java +++ b/services/core/java/com/android/server/wm/AppWarnings.java @@ -17,8 +17,12 @@ package com.android.server.wm; import android.annotation.UiThread; +import android.app.AlertDialog; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.res.Configuration; import android.os.Build; import android.os.Handler; @@ -305,21 +309,21 @@ class AppWarnings { private void hideDialogsForPackageUiThread(String name) { // Hides the "unsupported display" dialog if necessary. if (mUnsupportedDisplaySizeDialog != null && (name == null || name.equals( - mUnsupportedDisplaySizeDialog.getPackageName()))) { + mUnsupportedDisplaySizeDialog.mPackageName))) { mUnsupportedDisplaySizeDialog.dismiss(); mUnsupportedDisplaySizeDialog = null; } // Hides the "unsupported compile SDK" dialog if necessary. if (mUnsupportedCompileSdkDialog != null && (name == null || name.equals( - mUnsupportedCompileSdkDialog.getPackageName()))) { + mUnsupportedCompileSdkDialog.mPackageName))) { mUnsupportedCompileSdkDialog.dismiss(); mUnsupportedCompileSdkDialog = null; } // Hides the "deprecated target sdk version" dialog if necessary. if (mDeprecatedTargetSdkVersionDialog != null && (name == null || name.equals( - mDeprecatedTargetSdkVersionDialog.getPackageName()))) { + mDeprecatedTargetSdkVersionDialog.mPackageName))) { mDeprecatedTargetSdkVersionDialog.dismiss(); mDeprecatedTargetSdkVersionDialog = null; } @@ -431,6 +435,49 @@ class AppWarnings { } } + static class BaseDialog { + final AppWarnings mManager; + final String mPackageName; + AlertDialog mDialog; + private BroadcastReceiver mCloseReceiver; + + BaseDialog(AppWarnings manager, String packageName) { + mManager = manager; + mPackageName = packageName; + } + + @UiThread + void show() { + if (mDialog == null) return; + if (mCloseReceiver == null) { + mCloseReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) { + mManager.mUiHandler.hideDialogsForPackage(mPackageName); + } + } + }; + mManager.mUiContext.registerReceiver(mCloseReceiver, + new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), + Context.RECEIVER_EXPORTED); + } + Slog.w(TAG, "Showing " + getClass().getSimpleName() + " for package " + mPackageName); + mDialog.show(); + } + + @UiThread + void dismiss() { + if (mDialog == null) return; + if (mCloseReceiver != null) { + mManager.mUiContext.unregisterReceiver(mCloseReceiver); + mCloseReceiver = null; + } + mDialog.dismiss(); + mDialog = null; + } + } + /** * Handles messages on the ActivityTaskManagerService thread. */ diff --git a/services/core/java/com/android/server/wm/DeprecatedTargetSdkVersionDialog.java b/services/core/java/com/android/server/wm/DeprecatedTargetSdkVersionDialog.java index 37244bd5bd06..1a7a9b258400 100644 --- a/services/core/java/com/android/server/wm/DeprecatedTargetSdkVersionDialog.java +++ b/services/core/java/com/android/server/wm/DeprecatedTargetSdkVersionDialog.java @@ -16,31 +16,23 @@ package com.android.server.wm; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; - import android.app.AlertDialog; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; -import android.util.Log; import android.view.Window; import android.view.WindowManager; import com.android.internal.R; import com.android.server.utils.AppInstallerUtil; -public class DeprecatedTargetSdkVersionDialog { - private static final String TAG = TAG_WITH_CLASS_NAME ? "DeprecatedTargetSdkVersionDialog" : TAG_ATM; - - private final AlertDialog mDialog; - private final String mPackageName; +class DeprecatedTargetSdkVersionDialog extends AppWarnings.BaseDialog { - public DeprecatedTargetSdkVersionDialog(final AppWarnings manager, Context context, + DeprecatedTargetSdkVersionDialog(final AppWarnings manager, Context context, ApplicationInfo appInfo) { - mPackageName = appInfo.packageName; + super(manager, appInfo.packageName); final PackageManager pm = context.getPackageManager(); final CharSequence label = appInfo.loadSafeLabel(pm, @@ -75,17 +67,4 @@ public class DeprecatedTargetSdkVersionDialog { // DO NOT MODIFY. Used by CTS to verify the dialog is displayed. window.getAttributes().setTitle("DeprecatedTargetSdkVersionDialog"); } - - public String getPackageName() { - return mPackageName; - } - - public void show() { - Log.w(TAG, "Showing SDK deprecation warning for package " + mPackageName); - mDialog.show(); - } - - public void dismiss() { - mDialog.dismiss(); - } } diff --git a/services/core/java/com/android/server/wm/UnsupportedCompileSdkDialog.java b/services/core/java/com/android/server/wm/UnsupportedCompileSdkDialog.java index 6a878b983543..f376e8b1f9ed 100644 --- a/services/core/java/com/android/server/wm/UnsupportedCompileSdkDialog.java +++ b/services/core/java/com/android/server/wm/UnsupportedCompileSdkDialog.java @@ -29,13 +29,11 @@ import android.widget.CheckBox; import com.android.internal.R; import com.android.server.utils.AppInstallerUtil; -public class UnsupportedCompileSdkDialog { - private final AlertDialog mDialog; - private final String mPackageName; +class UnsupportedCompileSdkDialog extends AppWarnings.BaseDialog { - public UnsupportedCompileSdkDialog(final AppWarnings manager, Context context, + UnsupportedCompileSdkDialog(final AppWarnings manager, Context context, ApplicationInfo appInfo) { - mPackageName = appInfo.packageName; + super(manager, appInfo.packageName); final PackageManager pm = context.getPackageManager(); final CharSequence label = appInfo.loadSafeLabel(pm, @@ -72,16 +70,4 @@ public class UnsupportedCompileSdkDialog { alwaysShow.setOnCheckedChangeListener((buttonView, isChecked) -> manager.setPackageFlag( mPackageName, AppWarnings.FLAG_HIDE_COMPILE_SDK, !isChecked)); } - - public String getPackageName() { - return mPackageName; - } - - public void show() { - mDialog.show(); - } - - public void dismiss() { - mDialog.dismiss(); - } } diff --git a/services/core/java/com/android/server/wm/UnsupportedDisplaySizeDialog.java b/services/core/java/com/android/server/wm/UnsupportedDisplaySizeDialog.java index 4a800c41fdeb..b11c22de4286 100644 --- a/services/core/java/com/android/server/wm/UnsupportedDisplaySizeDialog.java +++ b/services/core/java/com/android/server/wm/UnsupportedDisplaySizeDialog.java @@ -16,8 +16,6 @@ package com.android.server.wm; -import com.android.internal.R; - import android.app.AlertDialog; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -27,13 +25,13 @@ import android.view.Window; import android.view.WindowManager; import android.widget.CheckBox; -public class UnsupportedDisplaySizeDialog { - private final AlertDialog mDialog; - private final String mPackageName; +import com.android.internal.R; - public UnsupportedDisplaySizeDialog(final AppWarnings manager, Context context, +class UnsupportedDisplaySizeDialog extends AppWarnings.BaseDialog { + + UnsupportedDisplaySizeDialog(final AppWarnings manager, Context context, ApplicationInfo appInfo) { - mPackageName = appInfo.packageName; + super(manager, appInfo.packageName); final PackageManager pm = context.getPackageManager(); final CharSequence label = appInfo.loadSafeLabel(pm, @@ -63,16 +61,4 @@ public class UnsupportedDisplaySizeDialog { alwaysShow.setOnCheckedChangeListener((buttonView, isChecked) -> manager.setPackageFlag( mPackageName, AppWarnings.FLAG_HIDE_DISPLAY_SIZE, !isChecked)); } - - public String getPackageName() { - return mPackageName; - } - - public void show() { - mDialog.show(); - } - - public void dismiss() { - mDialog.dismiss(); - } } diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java index 1b39add3b421..9d039bd09a2f 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java @@ -209,7 +209,8 @@ public class FlexibilityControllerTest { public void testOnConstantsUpdated_DeadlineProximity() { JobStatus js = createJobStatus("testDeadlineProximityConfig", createJob(0)); setDeviceConfigLong(KEY_DEADLINE_PROXIMITY_LIMIT, Long.MAX_VALUE); - mFlexibilityController.mFlexibilityAlarmQueue.scheduleDropNumConstraintsAlarm(js); + mFlexibilityController.mFlexibilityAlarmQueue + .scheduleDropNumConstraintsAlarm(js, FROZEN_TIME); assertEquals(0, js.getNumRequiredFlexibleConstraints()); } @@ -336,26 +337,31 @@ public class FlexibilityControllerTest { @Test public void testCurPercent() { long deadline = 1000; + long nowElapsed; JobInfo.Builder jb = createJob(0).setOverrideDeadline(deadline); JobStatus js = createJobStatus("time", jb); assertEquals(FROZEN_TIME, mFlexibilityController.getLifeCycleBeginningElapsedLocked(js)); assertEquals(deadline + FROZEN_TIME, mFlexibilityController.getLifeCycleEndElapsedLocked(js, FROZEN_TIME)); + nowElapsed = 600 + FROZEN_TIME; JobSchedulerService.sElapsedRealtimeClock = - Clock.fixed(Instant.ofEpochMilli(600 + FROZEN_TIME), ZoneOffset.UTC); - assertEquals(60, mFlexibilityController.getCurPercentOfLifecycleLocked(js)); + Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC); + assertEquals(60, mFlexibilityController.getCurPercentOfLifecycleLocked(js, nowElapsed)); + nowElapsed = 1400; JobSchedulerService.sElapsedRealtimeClock = - Clock.fixed(Instant.ofEpochMilli(1400), ZoneOffset.UTC); - assertEquals(100, mFlexibilityController.getCurPercentOfLifecycleLocked(js)); + Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC); + assertEquals(100, mFlexibilityController.getCurPercentOfLifecycleLocked(js, nowElapsed)); + nowElapsed = 950 + FROZEN_TIME; JobSchedulerService.sElapsedRealtimeClock = - Clock.fixed(Instant.ofEpochMilli(950 + FROZEN_TIME), ZoneOffset.UTC); - assertEquals(95, mFlexibilityController.getCurPercentOfLifecycleLocked(js)); + Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC); + assertEquals(95, mFlexibilityController.getCurPercentOfLifecycleLocked(js, nowElapsed)); + nowElapsed = FROZEN_TIME; JobSchedulerService.sElapsedRealtimeClock = - Clock.fixed(Instant.ofEpochMilli(FROZEN_TIME), ZoneOffset.UTC); + Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC); long delay = 100; deadline = 1100; jb = createJob(0).setOverrideDeadline(deadline).setMinimumLatency(delay); @@ -366,18 +372,21 @@ public class FlexibilityControllerTest { assertEquals(deadline + FROZEN_TIME, mFlexibilityController.getLifeCycleEndElapsedLocked(js, FROZEN_TIME + delay)); + nowElapsed = 600 + FROZEN_TIME + delay; JobSchedulerService.sElapsedRealtimeClock = - Clock.fixed(Instant.ofEpochMilli(600 + FROZEN_TIME + delay), ZoneOffset.UTC); + Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC); - assertEquals(60, mFlexibilityController.getCurPercentOfLifecycleLocked(js)); + assertEquals(60, mFlexibilityController.getCurPercentOfLifecycleLocked(js, nowElapsed)); + nowElapsed = 1400; JobSchedulerService.sElapsedRealtimeClock = - Clock.fixed(Instant.ofEpochMilli(1400), ZoneOffset.UTC); - assertEquals(100, mFlexibilityController.getCurPercentOfLifecycleLocked(js)); + Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC); + assertEquals(100, mFlexibilityController.getCurPercentOfLifecycleLocked(js, nowElapsed)); + nowElapsed = 950 + FROZEN_TIME + delay; JobSchedulerService.sElapsedRealtimeClock = - Clock.fixed(Instant.ofEpochMilli(950 + FROZEN_TIME + delay), ZoneOffset.UTC); - assertEquals(95, mFlexibilityController.getCurPercentOfLifecycleLocked(js)); + Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC); + assertEquals(95, mFlexibilityController.getCurPercentOfLifecycleLocked(js, nowElapsed)); } @Test @@ -491,19 +500,19 @@ public class FlexibilityControllerTest { assertEquals(3, trackedJobs.get(2).size()); assertEquals(0, trackedJobs.get(3).size()); - flexTracker.adjustJobsRequiredConstraints(jobs[0], -1); + flexTracker.adjustJobsRequiredConstraints(jobs[0], -1, FROZEN_TIME); assertEquals(0, trackedJobs.get(0).size()); assertEquals(1, trackedJobs.get(1).size()); assertEquals(2, trackedJobs.get(2).size()); assertEquals(0, trackedJobs.get(3).size()); - flexTracker.adjustJobsRequiredConstraints(jobs[0], -1); + flexTracker.adjustJobsRequiredConstraints(jobs[0], -1, FROZEN_TIME); assertEquals(1, trackedJobs.get(0).size()); assertEquals(0, trackedJobs.get(1).size()); assertEquals(2, trackedJobs.get(2).size()); assertEquals(0, trackedJobs.get(3).size()); - flexTracker.adjustJobsRequiredConstraints(jobs[0], -1); + flexTracker.adjustJobsRequiredConstraints(jobs[0], -1, FROZEN_TIME); assertEquals(0, trackedJobs.get(0).size()); assertEquals(0, trackedJobs.get(1).size()); assertEquals(2, trackedJobs.get(2).size()); @@ -515,24 +524,25 @@ public class FlexibilityControllerTest { assertEquals(1, trackedJobs.get(2).size()); assertEquals(0, trackedJobs.get(3).size()); - flexTracker.resetJobNumDroppedConstraints(jobs[0]); + flexTracker.resetJobNumDroppedConstraints(jobs[0], FROZEN_TIME); assertEquals(0, trackedJobs.get(0).size()); assertEquals(0, trackedJobs.get(1).size()); assertEquals(2, trackedJobs.get(2).size()); assertEquals(0, trackedJobs.get(3).size()); - flexTracker.adjustJobsRequiredConstraints(jobs[0], -2); + flexTracker.adjustJobsRequiredConstraints(jobs[0], -2, FROZEN_TIME); assertEquals(1, trackedJobs.get(0).size()); assertEquals(0, trackedJobs.get(1).size()); assertEquals(1, trackedJobs.get(2).size()); assertEquals(0, trackedJobs.get(3).size()); + final long nowElapsed = ((DEFAULT_FALLBACK_FLEXIBILITY_DEADLINE_MS / 2) + + HOUR_IN_MILLIS); JobSchedulerService.sElapsedRealtimeClock = - Clock.fixed(Instant.ofEpochMilli((DEFAULT_FALLBACK_FLEXIBILITY_DEADLINE_MS / 2) - + HOUR_IN_MILLIS), ZoneOffset.UTC); + Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC); - flexTracker.resetJobNumDroppedConstraints(jobs[0]); + flexTracker.resetJobNumDroppedConstraints(jobs[0], nowElapsed); assertEquals(0, trackedJobs.get(0).size()); assertEquals(1, trackedJobs.get(1).size()); assertEquals(1, trackedJobs.get(2).size()); @@ -615,13 +625,13 @@ public class FlexibilityControllerTest { @Test public void testSetConstraintSatisfied_Constraints() { - mFlexibilityController.setConstraintSatisfied(CONSTRAINT_IDLE, false); + mFlexibilityController.setConstraintSatisfied(CONSTRAINT_IDLE, false, FROZEN_TIME); assertFalse(mFlexibilityController.isConstraintSatisfied(CONSTRAINT_IDLE)); - mFlexibilityController.setConstraintSatisfied(CONSTRAINT_IDLE, true); + mFlexibilityController.setConstraintSatisfied(CONSTRAINT_IDLE, true, FROZEN_TIME); assertTrue(mFlexibilityController.isConstraintSatisfied(CONSTRAINT_IDLE)); - mFlexibilityController.setConstraintSatisfied(CONSTRAINT_IDLE, false); + mFlexibilityController.setConstraintSatisfied(CONSTRAINT_IDLE, false, FROZEN_TIME); assertFalse(mFlexibilityController.isConstraintSatisfied(CONSTRAINT_IDLE)); } @@ -651,20 +661,21 @@ public class FlexibilityControllerTest { createJobStatus(String.valueOf(i), jb), null); } } - mFlexibilityController.setConstraintSatisfied(CONSTRAINT_CHARGING, false); - mFlexibilityController.setConstraintSatisfied(CONSTRAINT_IDLE, false); - mFlexibilityController.setConstraintSatisfied(CONSTRAINT_BATTERY_NOT_LOW, false); + mFlexibilityController.setConstraintSatisfied(CONSTRAINT_CHARGING, false, FROZEN_TIME); + mFlexibilityController.setConstraintSatisfied(CONSTRAINT_IDLE, false, FROZEN_TIME); + mFlexibilityController.setConstraintSatisfied( + CONSTRAINT_BATTERY_NOT_LOW, false, FROZEN_TIME); assertEquals(0, mFlexibilityController.mSatisfiedFlexibleConstraints); for (int i = 0; i < constraintCombinations.length; i++) { constraints = constraintCombinations[i]; mFlexibilityController.setConstraintSatisfied(CONSTRAINT_CHARGING, - (constraints & CONSTRAINT_CHARGING) != 0); + (constraints & CONSTRAINT_CHARGING) != 0, FROZEN_TIME); mFlexibilityController.setConstraintSatisfied(CONSTRAINT_IDLE, - (constraints & CONSTRAINT_IDLE) != 0); + (constraints & CONSTRAINT_IDLE) != 0, FROZEN_TIME); mFlexibilityController.setConstraintSatisfied(CONSTRAINT_BATTERY_NOT_LOW, - (constraints & CONSTRAINT_BATTERY_NOT_LOW) != 0); + (constraints & CONSTRAINT_BATTERY_NOT_LOW) != 0, FROZEN_TIME); assertEquals(constraints, mFlexibilityController.mSatisfiedFlexibleConstraints); synchronized (mFlexibilityController.mLock) { @@ -679,6 +690,7 @@ public class FlexibilityControllerTest { JobInfo.Builder jb = createJob(22).setOverrideDeadline(100L); JobStatus js = createJobStatus("testResetJobNumDroppedConstraints", jb); js.adjustNumRequiredFlexibleConstraints(3); + long nowElapsed; mFlexibilityController.mFlexibilityTracker.add(js); @@ -687,45 +699,51 @@ public class FlexibilityControllerTest { assertEquals(1, mFlexibilityController .mFlexibilityTracker.getJobsByNumRequiredConstraints(3).size()); + + nowElapsed = 155L; JobSchedulerService.sElapsedRealtimeClock = - Clock.fixed(Instant.ofEpochMilli(155L), ZoneOffset.UTC); + Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC); - mFlexibilityController.mFlexibilityTracker.adjustJobsRequiredConstraints(js, -1); + mFlexibilityController.mFlexibilityTracker + .adjustJobsRequiredConstraints(js, -1, nowElapsed); assertEquals(2, js.getNumRequiredFlexibleConstraints()); assertEquals(1, js.getNumDroppedFlexibleConstraints()); assertEquals(1, mFlexibilityController .mFlexibilityTracker.getJobsByNumRequiredConstraints(2).size()); - mFlexibilityController.mFlexibilityTracker.resetJobNumDroppedConstraints(js); + mFlexibilityController.mFlexibilityTracker.resetJobNumDroppedConstraints(js, nowElapsed); assertEquals(2, js.getNumRequiredFlexibleConstraints()); assertEquals(1, js.getNumDroppedFlexibleConstraints()); assertEquals(1, mFlexibilityController .mFlexibilityTracker.getJobsByNumRequiredConstraints(2).size()); + nowElapsed = 140L; JobSchedulerService.sElapsedRealtimeClock = - Clock.fixed(Instant.ofEpochMilli(140L), ZoneOffset.UTC); + Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC); - mFlexibilityController.mFlexibilityTracker.resetJobNumDroppedConstraints(js); + mFlexibilityController.mFlexibilityTracker.resetJobNumDroppedConstraints(js, nowElapsed); assertEquals(3, js.getNumRequiredFlexibleConstraints()); assertEquals(0, js.getNumDroppedFlexibleConstraints()); assertEquals(1, mFlexibilityController .mFlexibilityTracker.getJobsByNumRequiredConstraints(3).size()); + nowElapsed = 175L; JobSchedulerService.sElapsedRealtimeClock = - Clock.fixed(Instant.ofEpochMilli(175), ZoneOffset.UTC); + Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC); - mFlexibilityController.mFlexibilityTracker.resetJobNumDroppedConstraints(js); + mFlexibilityController.mFlexibilityTracker.resetJobNumDroppedConstraints(js, nowElapsed); assertEquals(0, js.getNumRequiredFlexibleConstraints()); assertEquals(3, js.getNumDroppedFlexibleConstraints()); + nowElapsed = 165L; JobSchedulerService.sElapsedRealtimeClock = - Clock.fixed(Instant.ofEpochMilli(165L), ZoneOffset.UTC); + Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC); - mFlexibilityController.mFlexibilityTracker.resetJobNumDroppedConstraints(js); + mFlexibilityController.mFlexibilityTracker.resetJobNumDroppedConstraints(js, nowElapsed); assertEquals(1, js.getNumRequiredFlexibleConstraints()); assertEquals(2, js.getNumDroppedFlexibleConstraints()); @@ -745,12 +763,14 @@ public class FlexibilityControllerTest { mFlexibilityController.maybeStartTrackingJobLocked(js, null); + final long nowElapsed = 150L; JobSchedulerService.sElapsedRealtimeClock = - Clock.fixed(Instant.ofEpochMilli(150L), ZoneOffset.UTC); + Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC); mFlexibilityController.mPrefetchChangedListener.onPrefetchCacheUpdated( jobs, js.getUserId(), js.getSourcePackageName(), Long.MAX_VALUE, - 1150L + mFlexibilityController.mConstants.PREFETCH_FORCE_BATCH_RELAX_THRESHOLD_MS); + 1150L + mFlexibilityController.mConstants.PREFETCH_FORCE_BATCH_RELAX_THRESHOLD_MS, + nowElapsed); assertEquals(150L, (long) mFlexibilityController.mPrefetchLifeCycleStart @@ -758,7 +778,7 @@ public class FlexibilityControllerTest { assertEquals(150L, mFlexibilityController.getLifeCycleBeginningElapsedLocked(js)); assertEquals(1150L, mFlexibilityController.getLifeCycleEndElapsedLocked(js, 150L)); - assertEquals(0, mFlexibilityController.getCurPercentOfLifecycleLocked(js)); + assertEquals(0, mFlexibilityController.getCurPercentOfLifecycleLocked(js, FROZEN_TIME)); assertEquals(650L, mFlexibilityController .getNextConstraintDropTimeElapsedLocked(js)); assertEquals(3, js.getNumRequiredFlexibleConstraints()); diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java index 969389c27e70..bb477b18d5fa 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java @@ -490,9 +490,9 @@ public class PrefetchControllerTest { final PrefetchController.PrefetchChangedListener prefetchChangedListener = new PrefetchController.PrefetchChangedListener() { @Override - public void onPrefetchCacheUpdated( - ArraySet<JobStatus> jobs, int userId, String pkgName, - long prevEstimatedLaunchTime, long newEstimatedLaunchTime) { + public void onPrefetchCacheUpdated(ArraySet<JobStatus> jobs, + int userId, String pkgName, long prevEstimatedLaunchTime, + long newEstimatedLaunchTime, long nowElapsed) { onPrefetchCacheChangedCalled[0] = true; } }; diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceRegistryTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceRegistryTest.java new file mode 100644 index 000000000000..903ed9082481 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceRegistryTest.java @@ -0,0 +1,172 @@ +/* + * 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.server.biometrics.sensors.face; + +import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; +import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_STRONG; +import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_WEAK; +import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG; +import static android.hardware.biometrics.SensorProperties.STRENGTH_WEAK; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.hardware.biometrics.IBiometricService; +import android.hardware.face.FaceSensorProperties; +import android.hardware.face.FaceSensorPropertiesInternal; +import android.hardware.face.IFaceAuthenticatorsRegisteredCallback; +import android.hardware.face.IFaceService; +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.util.ArrayList; +import java.util.List; + +@Presubmit +@SmallTest +public class FaceServiceRegistryTest { + + private static final int SENSOR_ID_1 = 1; + private static final int SENSOR_ID_2 = 2; + + @Rule + public final MockitoRule mockito = MockitoJUnit.rule(); + + @Mock + private IBiometricService mBiometricService; + @Mock + private IFaceService mFaceService; + @Mock + private ServiceProvider mProvider1; + @Mock + private ServiceProvider mProvider2; + @Captor + private ArgumentCaptor<Integer> mIdCaptor; + @Captor + private ArgumentCaptor<Integer> mStrengthCaptor; + + private FaceSensorPropertiesInternal mProvider1Props; + private FaceSensorPropertiesInternal mProvider2Props; + private FaceServiceRegistry mRegistry; + + @Before + public void setup() { + mProvider1Props = new FaceSensorPropertiesInternal(SENSOR_ID_1, + STRENGTH_WEAK, 5 /* maxEnrollmentsPerUser */, + List.of(), FaceSensorProperties.TYPE_RGB, + true /* supportsFace Detection */, + true /* supportsSelfIllumination */, + false /* resetLockoutRequiresHardwareAuthToken */); + mProvider2Props = new FaceSensorPropertiesInternal(SENSOR_ID_2, + STRENGTH_STRONG, 5 /* maxEnrollmentsPerUser */, + List.of(), FaceSensorProperties.TYPE_IR, + true /* supportsFace Detection */, + true /* supportsSelfIllumination */, + false /* resetLockoutRequiresHardwareAuthToken */); + + when(mProvider1.getSensorProperties()).thenReturn(List.of(mProvider1Props)); + when(mProvider1.containsSensor(eq(SENSOR_ID_1))).thenReturn(true); + when(mProvider2.getSensorProperties()).thenReturn(List.of(mProvider2Props)); + when(mProvider2.containsSensor(eq(SENSOR_ID_2))).thenReturn(true); + mRegistry = new FaceServiceRegistry(mFaceService, () -> mBiometricService); + } + + @Test + public void registersAllProviders() throws Exception { + mRegistry.registerAllInBackground(() -> List.of(mProvider1, mProvider2)); + + assertThat(mRegistry.getProviders()).containsExactly(mProvider1, mProvider2); + assertThat(mRegistry.getAllProperties()).containsExactly(mProvider1Props, mProvider2Props); + verify(mBiometricService, times(2)).registerAuthenticator( + mIdCaptor.capture(), eq(TYPE_FACE), mStrengthCaptor.capture(), any()); + assertThat(mIdCaptor.getAllValues()).containsExactly(SENSOR_ID_1, SENSOR_ID_2); + assertThat(mStrengthCaptor.getAllValues()) + .containsExactly(BIOMETRIC_WEAK, BIOMETRIC_STRONG); + } + + @Test + public void getsProviderById() { + mRegistry.registerAllInBackground(() -> List.of(mProvider1, mProvider2)); + + assertThat(mRegistry.getProviderForSensor(SENSOR_ID_1)).isSameInstanceAs(mProvider1); + assertThat(mRegistry.getProviderForSensor(SENSOR_ID_2)).isSameInstanceAs(mProvider2); + assertThat(mRegistry.getProviderForSensor(500)).isNull(); + } + + @Test + public void getsSingleProvider() { + mRegistry.registerAllInBackground(() -> List.of(mProvider1)); + + assertThat(mRegistry.getSingleProvider().second).isSameInstanceAs(mProvider1); + assertThat(mRegistry.getProviders()).containsExactly(mProvider1); + assertThat(mRegistry.getProviderForSensor(SENSOR_ID_1)).isSameInstanceAs(mProvider1); + } + + @Test + public void getSingleProviderFindsFirstWhenMultiple() { + mRegistry.registerAllInBackground(() -> List.of(mProvider1, mProvider2)); + + assertThat(mRegistry.getSingleProvider().second).isSameInstanceAs(mProvider1); + } + + @Test + public void registersListenerBeforeAllRegistered() { + final List<FaceSensorPropertiesInternal> all = new ArrayList<>(); + mRegistry.addAllRegisteredCallback(new IFaceAuthenticatorsRegisteredCallback.Stub() { + @Override + public void onAllAuthenticatorsRegistered( + List<FaceSensorPropertiesInternal> sensors) { + all.addAll(sensors); + } + }); + + mRegistry.registerAllInBackground(() -> List.of(mProvider1, mProvider2)); + + assertThat(all).containsExactly(mProvider1Props, mProvider2Props); + } + + @Test + public void registersListenerAfterAllRegistered() { + mRegistry.registerAllInBackground(() -> List.of(mProvider1, mProvider2)); + + final List<FaceSensorPropertiesInternal> all = new ArrayList<>(); + mRegistry.addAllRegisteredCallback(new IFaceAuthenticatorsRegisteredCallback.Stub() { + @Override + public void onAllAuthenticatorsRegistered( + List<FaceSensorPropertiesInternal> sensors) { + all.addAll(sensors); + } + }); + + assertThat(all).containsExactly(mProvider1Props, mProvider2Props); + } +} diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/BiometricStateCallbackTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/BiometricStateCallbackTest.java index 5f88c99b1d1e..0e30782eaece 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/BiometricStateCallbackTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/BiometricStateCallbackTest.java @@ -16,6 +16,8 @@ package com.android.server.biometrics.sensors.fingerprint; +import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG; + import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; @@ -24,38 +26,73 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.content.pm.UserInfo; import android.hardware.biometrics.BiometricStateListener; +import android.hardware.biometrics.SensorPropertiesInternal; +import android.os.UserManager; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; import com.android.server.biometrics.sensors.AuthenticationClient; +import com.android.server.biometrics.sensors.BiometricServiceProvider; import com.android.server.biometrics.sensors.BiometricStateCallback; import com.android.server.biometrics.sensors.EnrollClient; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.util.List; @Presubmit @SmallTest public class BiometricStateCallbackTest { - private BiometricStateCallback mCallback; + private static final int USER_ID = 10; + private static final int SENSOR_ID = 2; + + @Rule + public final MockitoRule mockito = MockitoJUnit.rule(); + + private BiometricStateCallback<FakeProvider, SensorPropertiesInternal> mCallback; @Mock - BiometricStateListener mBiometricStateListener; + private UserManager mUserManager; + @Mock + private BiometricStateListener mBiometricStateListener; + @Mock + private FakeProvider mFakeProvider; + + private SensorPropertiesInternal mFakeProviderProps; @Before public void setup() { - MockitoAnnotations.initMocks(this); - - mCallback = new BiometricStateCallback(); + mFakeProviderProps = new SensorPropertiesInternal(SENSOR_ID, STRENGTH_STRONG, + 5 /* maxEnrollmentsPerUser */, List.of(), + false /* resetLockoutRequiresHardwareAuthToken */, + false /* resetLockoutRequiresChallenge */); + when(mFakeProvider.getSensorProperties()).thenReturn(List.of(mFakeProviderProps)); + when(mFakeProvider.getSensorProperties(eq(SENSOR_ID))).thenReturn(mFakeProviderProps); + when(mFakeProvider.hasEnrollments(eq(SENSOR_ID), eq(USER_ID))).thenReturn(true); + when(mUserManager.getAliveUsers()).thenReturn( + List.of(new UserInfo(USER_ID, "name", 0))); + + mCallback = new BiometricStateCallback<>(mUserManager); mCallback.registerBiometricStateListener(mBiometricStateListener); } @Test + public void startNotifiesEnrollments() { + mCallback.start(List.of(mFakeProvider)); + + verify(mBiometricStateListener).onEnrollmentsChanged(eq(USER_ID), eq(SENSOR_ID), eq(true)); + } + + @Test public void testNoEnrollmentsToEnrollments_callbackNotified() { testEnrollmentCallback(true /* changed */, true /* isNowEnrolled */, true /* expectCallback */, true /* expectedCallbackValue */); @@ -102,4 +139,6 @@ public class BiometricStateCallbackTest { verify(mBiometricStateListener, never()).onEnrollmentsChanged(anyInt(), anyInt(), anyBoolean()); } + + private interface FakeProvider extends BiometricServiceProvider<SensorPropertiesInternal> {} } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceRegistryTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceRegistryTest.java new file mode 100644 index 000000000000..13c3f64fec93 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceRegistryTest.java @@ -0,0 +1,168 @@ +/* + * 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.server.biometrics.sensors.fingerprint; + +import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; +import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_STRONG; +import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_WEAK; +import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG; +import static android.hardware.biometrics.SensorProperties.STRENGTH_WEAK; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.hardware.biometrics.IBiometricService; +import android.hardware.fingerprint.FingerprintSensorProperties; +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; +import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; +import android.hardware.fingerprint.IFingerprintService; +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.util.ArrayList; +import java.util.List; + +@Presubmit +@SmallTest +public class FingerprintServiceRegistryTest { + + private static final int SENSOR_ID_1 = 1; + private static final int SENSOR_ID_2 = 2; + + @Rule + public final MockitoRule mockito = MockitoJUnit.rule(); + + @Mock + private IBiometricService mBiometricService; + @Mock + private IFingerprintService mFingerprintService; + @Mock + private ServiceProvider mProvider1; + @Mock + private ServiceProvider mProvider2; + @Captor + private ArgumentCaptor<Integer> mIdCaptor; + @Captor + private ArgumentCaptor<Integer> mStrengthCaptor; + + private FingerprintSensorPropertiesInternal mProvider1Props; + private FingerprintSensorPropertiesInternal mProvider2Props; + private FingerprintServiceRegistry mRegistry; + + @Before + public void setup() { + mProvider1Props = new FingerprintSensorPropertiesInternal(SENSOR_ID_1, + STRENGTH_WEAK, 5 /* maxEnrollmentsPerUser */, + List.of(), FingerprintSensorProperties.TYPE_UDFPS_OPTICAL, + false /* resetLockoutRequiresHardwareAuthToken */); + mProvider2Props = new FingerprintSensorPropertiesInternal(SENSOR_ID_2, + STRENGTH_STRONG, 5 /* maxEnrollmentsPerUser */, + List.of(), FingerprintSensorProperties.TYPE_UNKNOWN, + false /* resetLockoutRequiresHardwareAuthToken */); + + when(mProvider1.getSensorProperties()).thenReturn(List.of(mProvider1Props)); + when(mProvider1.containsSensor(eq(SENSOR_ID_1))).thenReturn(true); + when(mProvider2.getSensorProperties()).thenReturn(List.of(mProvider2Props)); + when(mProvider2.containsSensor(eq(SENSOR_ID_2))).thenReturn(true); + mRegistry = new FingerprintServiceRegistry(mFingerprintService, () -> mBiometricService); + } + + @Test + public void registersAllProviders() throws Exception { + mRegistry.registerAllInBackground(() -> List.of(mProvider1, mProvider2)); + + assertThat(mRegistry.getProviders()).containsExactly(mProvider1, mProvider2); + assertThat(mRegistry.getAllProperties()).containsExactly(mProvider1Props, mProvider2Props); + verify(mBiometricService, times(2)).registerAuthenticator( + mIdCaptor.capture(), eq(TYPE_FINGERPRINT), mStrengthCaptor.capture(), any()); + assertThat(mIdCaptor.getAllValues()).containsExactly(SENSOR_ID_1, SENSOR_ID_2); + assertThat(mStrengthCaptor.getAllValues()) + .containsExactly(BIOMETRIC_WEAK, BIOMETRIC_STRONG); + } + + @Test + public void getsProviderById() { + mRegistry.registerAllInBackground(() -> List.of(mProvider1, mProvider2)); + + assertThat(mRegistry.getProviderForSensor(SENSOR_ID_1)).isSameInstanceAs(mProvider1); + assertThat(mRegistry.getProviderForSensor(SENSOR_ID_2)).isSameInstanceAs(mProvider2); + assertThat(mRegistry.getProviderForSensor(500)).isNull(); + } + + @Test + public void getsSingleProvider() { + mRegistry.registerAllInBackground(() -> List.of(mProvider1)); + + assertThat(mRegistry.getSingleProvider().second).isSameInstanceAs(mProvider1); + assertThat(mRegistry.getProviders()).containsExactly(mProvider1); + assertThat(mRegistry.getProviderForSensor(SENSOR_ID_1)).isSameInstanceAs(mProvider1); + } + + @Test + public void getSingleProviderFindsFirstWhenMultiple() { + mRegistry.registerAllInBackground(() -> List.of(mProvider1, mProvider2)); + + assertThat(mRegistry.getSingleProvider().second).isSameInstanceAs(mProvider1); + } + + @Test + public void registersListenerBeforeAllRegistered() { + final List<FingerprintSensorPropertiesInternal> all = new ArrayList<>(); + mRegistry.addAllRegisteredCallback(new IFingerprintAuthenticatorsRegisteredCallback.Stub() { + @Override + public void onAllAuthenticatorsRegistered( + List<FingerprintSensorPropertiesInternal> sensors) { + all.addAll(sensors); + } + }); + + mRegistry.registerAllInBackground(() -> List.of(mProvider1, mProvider2)); + + assertThat(all).containsExactly(mProvider1Props, mProvider2Props); + } + + @Test + public void registersListenerAfterAllRegistered() { + mRegistry.registerAllInBackground(() -> List.of(mProvider1, mProvider2)); + + final List<FingerprintSensorPropertiesInternal> all = new ArrayList<>(); + mRegistry.addAllRegisteredCallback(new IFingerprintAuthenticatorsRegisteredCallback.Stub() { + @Override + public void onAllAuthenticatorsRegistered( + List<FingerprintSensorPropertiesInternal> sensors) { + all.addAll(sensors); + } + }); + + assertThat(all).containsExactly(mProvider1Props, mProvider2Props); + } +} diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java index ca3677e3b5ff..a4048a27dfb5 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java @@ -32,7 +32,8 @@ import android.hardware.biometrics.fingerprint.FingerprintSensorType; import android.hardware.biometrics.fingerprint.IFingerprint; import android.hardware.biometrics.fingerprint.SensorLocation; import android.hardware.biometrics.fingerprint.SensorProps; -import android.os.RemoteException; +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; +import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.platform.test.annotations.Presubmit; import android.provider.Settings; import android.testing.TestableContext; @@ -52,6 +53,8 @@ import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; @Presubmit @SmallTest @@ -94,9 +97,12 @@ public class FingerprintServiceTest { mContext.getTestablePermissions().setPermission( USE_BIOMETRIC_INTERNAL, PackageManager.PERMISSION_GRANTED); + } + private void initServiceWith(String... aidlInstances) { mService = new FingerprintService(mContext, mBiometricContext, () -> mIBiometricService, + () -> aidlInstances, (fqName) -> { if (fqName.endsWith(NAME_DEFAULT)) return mIFingerprintDefault; if (fqName.endsWith(NAME_VIRTUAL)) return mIFingerprintVirtual; @@ -105,29 +111,50 @@ public class FingerprintServiceTest { } @Test - public void registerAuthenticators_defaultOnly() throws RemoteException { - mService.registerAuthenticatorsForService(List.of(NAME_DEFAULT, NAME_VIRTUAL), List.of()); + public void registerAuthenticators_defaultOnly() throws Exception { + initServiceWith(NAME_DEFAULT, NAME_VIRTUAL); + + mService.mServiceWrapper.registerAuthenticators(List.of()); + waitForRegistration(); verify(mIBiometricService).registerAuthenticator(eq(ID_DEFAULT), anyInt(), anyInt(), any()); } @Test - public void registerAuthenticators_virtualOnly() throws RemoteException { + public void registerAuthenticators_virtualOnly() throws Exception { + initServiceWith(NAME_DEFAULT, NAME_VIRTUAL); Settings.Secure.putInt(mSettingsRule.mockContentResolver(mContext), Settings.Secure.BIOMETRIC_VIRTUAL_ENABLED, 1); - mService.registerAuthenticatorsForService(List.of(NAME_DEFAULT, NAME_VIRTUAL), List.of()); + mService.mServiceWrapper.registerAuthenticators(List.of()); + waitForRegistration(); verify(mIBiometricService).registerAuthenticator(eq(ID_VIRTUAL), anyInt(), anyInt(), any()); } @Test - public void registerAuthenticators_virtualAlwaysWhenNoOther() throws RemoteException { - mService.registerAuthenticatorsForService(List.of(NAME_VIRTUAL), List.of()); + public void registerAuthenticators_virtualAlwaysWhenNoOther() throws Exception { + initServiceWith(NAME_VIRTUAL); + + mService.mServiceWrapper.registerAuthenticators(List.of()); + waitForRegistration(); verify(mIBiometricService).registerAuthenticator(eq(ID_VIRTUAL), anyInt(), anyInt(), any()); } + private void waitForRegistration() throws Exception { + final CountDownLatch latch = new CountDownLatch(1); + mService.mServiceWrapper.addAuthenticatorsRegisteredCallback( + new IFingerprintAuthenticatorsRegisteredCallback.Stub() { + @Override + public void onAllAuthenticatorsRegistered( + List<FingerprintSensorPropertiesInternal> sensors) { + latch.countDown(); + } + }); + latch.await(5, TimeUnit.SECONDS); + } + private static SensorProps createProps(int id, byte strength, byte type) { final SensorProps props = new SensorProps(); props.commonProps = new CommonProps(); 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 5c9348525861..61a7f3853746 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,7 +28,6 @@ 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; @@ -50,14 +49,13 @@ 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, "battery-history"); + mHistoryDir = new File(mSystemDir, BatteryStatsHistory.HISTORY_DIR); String[] files = mHistoryDir.list(); if (files != null) { for (int i = 0; i < files.length; i++) { @@ -69,8 +67,8 @@ public class BatteryStatsHistoryTest { @Test public void testConstruct() { - BatteryStatsHistory history = new BatteryStatsHistory(mHistoryBuffer, mSystemDir, 32, 1024, - null, mClock); + BatteryStatsHistory history = + new BatteryStatsHistory(mHistoryBuffer, mSystemDir, () -> 32); createActiveFile(history); verifyFileNumbers(history, Arrays.asList(0)); verifyActiveFile(history, "0.bin"); @@ -78,8 +76,8 @@ public class BatteryStatsHistoryTest { @Test public void testStartNextFile() { - BatteryStatsHistory history = new BatteryStatsHistory(mHistoryBuffer, mSystemDir, 32, 1024, - null, mClock); + BatteryStatsHistory history = + new BatteryStatsHistory(mHistoryBuffer, mSystemDir, () -> 32); List<Integer> fileList = new ArrayList<>(); fileList.add(0); createActiveFile(history); @@ -116,13 +114,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, 1024, - null, mClock); - // verify constructor can pick up all files from file system. + BatteryStatsHistory history2 = + new BatteryStatsHistory(mHistoryBuffer, mSystemDir, () -> 32); + // verify construct can pick up all files from file system. verifyFileNumbers(history2, fileList); verifyActiveFile(history2, "33.bin"); - history2.reset(); + history2.resetAllFiles(); 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 570b2ee617f5..713e78638b95 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,7 +63,6 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl { MockBatteryStatsImpl(Clock clock, File historyDirectory) { super(clock, historyDirectory); initTimersAndCounters(); - setMaxHistoryBuffer(128 * 1024); setExternalStatsSyncLocked(mExternalStatsSync); informThatAllExternalStatsAreFlushed(); @@ -105,6 +104,12 @@ 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; } @@ -196,14 +201,12 @@ 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/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt index be7fb7315955..8df3548465bd 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt @@ -21,7 +21,6 @@ import android.platform.test.annotations.Presubmit import androidx.test.platform.app.InstrumentationRegistry import com.android.launcher3.tapl.LauncherInstrumentation import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.traces.common.ComponentMatcher import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper import org.junit.Assume import org.junit.Test diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt index 472a0fa376bf..eddb55346af8 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt @@ -19,7 +19,7 @@ package com.android.server.wm.flicker import com.android.server.wm.flicker.helpers.WindowUtils import com.android.server.wm.flicker.traces.region.RegionSubject -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import com.android.server.wm.traces.common.IComponentMatcher /** @@ -28,7 +28,7 @@ import com.android.server.wm.traces.common.IComponentMatcher */ fun FlickerTestParameter.statusBarWindowIsAlwaysVisible() { assertWm { - this.isAboveAppWindowVisible(ComponentMatcher.STATUS_BAR) + this.isAboveAppWindowVisible(ComponentNameMatcher.STATUS_BAR) } } @@ -38,7 +38,7 @@ fun FlickerTestParameter.statusBarWindowIsAlwaysVisible() { */ fun FlickerTestParameter.navBarWindowIsAlwaysVisible() { assertWm { - this.isAboveAppWindowVisible(ComponentMatcher.NAV_BAR) + this.isAboveAppWindowVisible(ComponentNameMatcher.NAV_BAR) } } @@ -48,10 +48,10 @@ fun FlickerTestParameter.navBarWindowIsAlwaysVisible() { */ fun FlickerTestParameter.navBarWindowIsVisibleAtStartAndEnd() { assertWmStart { - this.isAboveAppWindowVisible(ComponentMatcher.NAV_BAR) + this.isAboveAppWindowVisible(ComponentNameMatcher.NAV_BAR) } assertWmEnd { - this.isAboveAppWindowVisible(ComponentMatcher.NAV_BAR) + this.isAboveAppWindowVisible(ComponentNameMatcher.NAV_BAR) } } @@ -61,7 +61,7 @@ fun FlickerTestParameter.navBarWindowIsVisibleAtStartAndEnd() { */ fun FlickerTestParameter.taskBarWindowIsAlwaysVisible() { assertWm { - this.isAboveAppWindowVisible(ComponentMatcher.TASK_BAR) + this.isAboveAppWindowVisible(ComponentNameMatcher.TASK_BAR) } } @@ -71,7 +71,7 @@ fun FlickerTestParameter.taskBarWindowIsAlwaysVisible() { */ fun FlickerTestParameter.taskBarWindowIsVisibleAtEnd() { assertWmEnd { - this.isAboveAppWindowVisible(ComponentMatcher.TASK_BAR) + this.isAboveAppWindowVisible(ComponentNameMatcher.TASK_BAR) } } @@ -114,10 +114,10 @@ fun FlickerTestParameter.entireScreenCovered(allStates: Boolean = true) { */ fun FlickerTestParameter.navBarLayerIsVisibleAtStartAndEnd() { assertLayersStart { - this.isVisible(ComponentMatcher.NAV_BAR) + this.isVisible(ComponentNameMatcher.NAV_BAR) } assertLayersEnd { - this.isVisible(ComponentMatcher.NAV_BAR) + this.isVisible(ComponentNameMatcher.NAV_BAR) } } @@ -136,7 +136,7 @@ fun FlickerTestParameter.taskBarLayerIsVisibleAtStartAndEnd() { */ fun FlickerTestParameter.taskBarLayerIsVisibleAtStart() { assertLayersStart { - this.isVisible(ComponentMatcher.TASK_BAR) + this.isVisible(ComponentNameMatcher.TASK_BAR) } } @@ -146,7 +146,7 @@ fun FlickerTestParameter.taskBarLayerIsVisibleAtStart() { */ fun FlickerTestParameter.taskBarLayerIsVisibleAtEnd() { assertLayersEnd { - this.isVisible(ComponentMatcher.TASK_BAR) + this.isVisible(ComponentNameMatcher.TASK_BAR) } } @@ -156,10 +156,10 @@ fun FlickerTestParameter.taskBarLayerIsVisibleAtEnd() { */ fun FlickerTestParameter.statusBarLayerIsVisibleAtStartAndEnd() { assertLayersStart { - this.isVisible(ComponentMatcher.STATUS_BAR) + this.isVisible(ComponentNameMatcher.STATUS_BAR) } assertLayersEnd { - this.isVisible(ComponentMatcher.STATUS_BAR) + this.isVisible(ComponentNameMatcher.STATUS_BAR) } } @@ -171,7 +171,7 @@ fun FlickerTestParameter.navBarLayerPositionAtStart() { assertLayersStart { val display = this.entry.displays.firstOrNull { !it.isVirtual } ?: error("There is no display!") - this.visibleRegion(ComponentMatcher.NAV_BAR) + this.visibleRegion(ComponentNameMatcher.NAV_BAR) .coversExactly(WindowUtils.getNavigationBarPosition(display, isGesturalNavigation)) } } @@ -184,7 +184,7 @@ fun FlickerTestParameter.navBarLayerPositionAtEnd() { assertLayersEnd { val display = this.entry.displays.minByOrNull { it.id } ?: throw RuntimeException("There is no display!") - this.visibleRegion(ComponentMatcher.NAV_BAR) + this.visibleRegion(ComponentNameMatcher.NAV_BAR) .coversExactly(WindowUtils.getNavigationBarPosition(display, isGesturalNavigation)) } } @@ -206,7 +206,7 @@ fun FlickerTestParameter.statusBarLayerPositionAtStart() { assertLayersStart { val display = this.entry.displays.minByOrNull { it.id } ?: throw RuntimeException("There is no display!") - this.visibleRegion(ComponentMatcher.STATUS_BAR) + this.visibleRegion(ComponentNameMatcher.STATUS_BAR) .coversExactly(WindowUtils.getStatusBarPosition(display)) } } @@ -219,7 +219,7 @@ fun FlickerTestParameter.statusBarLayerPositionAtEnd() { assertLayersEnd { val display = this.entry.displays.minByOrNull { it.id } ?: throw RuntimeException("There is no display!") - this.visibleRegion(ComponentMatcher.STATUS_BAR) + this.visibleRegion(ComponentNameMatcher.STATUS_BAR) .coversExactly(WindowUtils.getStatusBarPosition(display)) } } @@ -244,7 +244,7 @@ fun FlickerTestParameter.snapshotStartingWindowLayerCoversExactlyOnApp( invoke("snapshotStartingWindowLayerCoversExactlyOnApp") { val snapshotLayers = it.subjects.filter { subject -> subject.name.contains( - ComponentMatcher.SNAPSHOT.toLayerName()) && subject.isVisible + ComponentNameMatcher.SNAPSHOT.toLayerName()) && subject.isVisible } // Verify the size of snapshotRegion covers appVisibleRegion exactly in animation. if (snapshotLayers.isNotEmpty()) { @@ -291,10 +291,10 @@ fun FlickerTestParameter.replacesLayer( val assertion = this.isVisible(originalLayer) if (ignoreEntriesWithRotationLayer) { - assertion.then().isVisible(ComponentMatcher.ROTATION, isOptional = true) + assertion.then().isVisible(ComponentNameMatcher.ROTATION, isOptional = true) } if (ignoreSnapshot) { - assertion.then().isVisible(ComponentMatcher.SNAPSHOT, isOptional = true) + assertion.then().isVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true) } if (ignoreSplashscreen) { assertion.then().isSplashScreenVisibleFor(newLayer, isOptional = true) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt index 7ff093474399..cb197cdf04d3 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt @@ -24,7 +24,7 @@ import com.android.server.wm.flicker.helpers.SimpleAppHelper import com.android.server.wm.flicker.helpers.StandardAppHelper import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.replacesLayer -import com.android.server.wm.traces.common.ComponentMatcher.Companion.LAUNCHER +import com.android.server.wm.traces.common.ComponentNameMatcher.Companion.LAUNCHER import org.junit.Test /** diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt index af3a8c502008..b8fe9f9df882 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt @@ -26,7 +26,7 @@ import androidx.window.extensions.WindowExtensions import androidx.window.extensions.WindowExtensionsProvider import androidx.window.extensions.embedding.ActivityEmbeddingComponent import com.android.server.wm.flicker.testapp.ActivityOptions -import com.android.server.wm.traces.common.IComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import com.android.server.wm.traces.common.windowmanager.WindowManagerState.Companion.STATE_RESUMED import com.android.server.wm.traces.parser.toFlickerComponent import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper @@ -35,7 +35,7 @@ import org.junit.Assume.assumeNotNull class ActivityEmbeddingAppHelper @JvmOverloads constructor( instr: Instrumentation, launcherName: String = ActivityOptions.ACTIVITY_EMBEDDING_LAUNCHER_NAME, - component: IComponentMatcher = MAIN_ACTIVITY_COMPONENT, + component: ComponentNameMatcher = MAIN_ACTIVITY_COMPONENT, launcherStrategy: ILauncherStrategy = LauncherStrategyFactory .getInstance(instr) .launcherStrategy diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/CameraAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/CameraAppHelper.kt index bd0ae4d47383..34f9ce43b4bc 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/CameraAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/CameraAppHelper.kt @@ -21,12 +21,11 @@ import android.content.Intent import android.content.pm.PackageManager import android.content.pm.ResolveInfo import android.provider.MediaStore -import com.android.server.wm.traces.common.ComponentMatcher -import com.android.server.wm.traces.common.IComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher class CameraAppHelper @JvmOverloads constructor( - instrumentation: Instrumentation, - private val pkgManager: PackageManager = instrumentation.context.packageManager + instrumentation: Instrumentation, + pkgManager: PackageManager = instrumentation.context.packageManager ) : StandardAppHelper(instrumentation, getCameraLauncherName(pkgManager), getCameraComponent(pkgManager)){ companion object{ @@ -40,9 +39,9 @@ class CameraAppHelper @JvmOverloads constructor( ?: error("unable to resolve camera activity") } - private fun getCameraComponent(pkgManager: PackageManager): IComponentMatcher { + private fun getCameraComponent(pkgManager: PackageManager): ComponentNameMatcher { val resolveInfo = getResolveInfo(pkgManager) - return ComponentMatcher(resolveInfo.activityInfo.packageName, + return ComponentNameMatcher(resolveInfo.activityInfo.packageName, className = resolveInfo.activityInfo.name) } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt index 28858d4843a1..b696fc30c19f 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt @@ -20,13 +20,13 @@ import android.app.Instrumentation import android.support.test.launcherhelper.ILauncherStrategy import android.support.test.launcherhelper.LauncherStrategyFactory import com.android.server.wm.flicker.testapp.ActivityOptions -import com.android.server.wm.traces.common.IComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import com.android.server.wm.traces.parser.toFlickerComponent class FixedOrientationAppHelper @JvmOverloads constructor( instr: Instrumentation, launcherName: String = ActivityOptions.PORTRAIT_ONLY_ACTIVITY_LAUNCHER_NAME, - component: IComponentMatcher = + component: ComponentNameMatcher = ActivityOptions.PORTRAIT_ONLY_ACTIVITY_COMPONENT_NAME.toFlickerComponent(), launcherStrategy: ILauncherStrategy = LauncherStrategyFactory .getInstance(instr) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt index f536a151d8fd..e01cceb5d636 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt @@ -23,7 +23,7 @@ import android.view.WindowInsets.Type.statusBars import androidx.test.uiautomator.By import androidx.test.uiautomator.Until import com.android.server.wm.flicker.testapp.ActivityOptions -import com.android.server.wm.traces.common.IComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import com.android.server.wm.traces.parser.toFlickerComponent import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper import java.util.regex.Pattern @@ -33,7 +33,7 @@ class ImeAppAutoFocusHelper @JvmOverloads constructor( private val rotation: Int, private val imePackageName: String = IME_PACKAGE, launcherName: String = ActivityOptions.IME_ACTIVITY_AUTO_FOCUS_LAUNCHER_NAME, - component: IComponentMatcher = + component: ComponentNameMatcher = ActivityOptions.IME_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME.toFlickerComponent() ) : ImeAppHelper(instr, launcherName, component) { override fun openIME(wmHelper: WindowManagerStateHelper) { diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt index db64c4769715..b672b1bc0da5 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt @@ -22,14 +22,14 @@ import android.support.test.launcherhelper.LauncherStrategyFactory import androidx.test.uiautomator.By import androidx.test.uiautomator.Until import com.android.server.wm.flicker.testapp.ActivityOptions -import com.android.server.wm.traces.common.IComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import com.android.server.wm.traces.parser.toFlickerComponent import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper open class ImeAppHelper @JvmOverloads constructor( instr: Instrumentation, launcherName: String = ActivityOptions.IME_ACTIVITY_LAUNCHER_NAME, - component: IComponentMatcher = + component: ComponentNameMatcher = ActivityOptions.IME_ACTIVITY_COMPONENT_NAME.toFlickerComponent(), launcherStrategy: ILauncherStrategy = LauncherStrategyFactory .getInstance(instr) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt index f74054ea4459..df47e9dfacd9 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt @@ -20,16 +20,14 @@ import android.app.Instrumentation import androidx.test.uiautomator.By import androidx.test.uiautomator.Until import com.android.server.wm.flicker.testapp.ActivityOptions -import com.android.server.wm.traces.common.IComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import com.android.server.wm.traces.parser.toFlickerComponent import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper class ImeEditorPopupDialogAppHelper @JvmOverloads constructor( instr: Instrumentation, - private val rotation: Int, - private val imePackageName: String = IME_PACKAGE, launcherName: String = ActivityOptions.EDITOR_POPUP_DIALOG_ACTIVITY_LAUNCHER_NAME, - component: IComponentMatcher = + component: ComponentNameMatcher = ActivityOptions.EDITOR_POPUP_DIALOG_ACTIVITY_COMPONENT_NAME.toFlickerComponent() ) : ImeAppHelper(instr, launcherName, component) { override fun openIME(wmHelper: WindowManagerStateHelper) { diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt index 7f8b5633391b..d3945c1749e3 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt @@ -20,13 +20,13 @@ import android.app.Instrumentation import android.support.test.launcherhelper.ILauncherStrategy import android.support.test.launcherhelper.LauncherStrategyFactory import com.android.server.wm.flicker.testapp.ActivityOptions -import com.android.server.wm.traces.common.IComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import com.android.server.wm.traces.parser.toFlickerComponent class ImeStateInitializeHelper @JvmOverloads constructor( instr: Instrumentation, launcherName: String = ActivityOptions.IME_ACTIVITY_INITIALIZE_LAUNCHER_NAME, - component: IComponentMatcher = + component: ComponentNameMatcher = ActivityOptions.IME_ACTIVITY_INITIALIZE_COMPONENT_NAME.toFlickerComponent(), launcherStrategy: ILauncherStrategy = LauncherStrategyFactory .getInstance(instr) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt index 149576e4ec1d..9fb574cf1c04 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt @@ -23,14 +23,14 @@ import androidx.test.uiautomator.By import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.Until import com.android.server.wm.flicker.testapp.ActivityOptions -import com.android.server.wm.traces.common.IComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import com.android.server.wm.traces.parser.toFlickerComponent import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper class NewTasksAppHelper @JvmOverloads constructor( instr: Instrumentation, launcherName: String = ActivityOptions.LAUNCH_NEW_TASK_ACTIVITY_LAUNCHER_NAME, - component: IComponentMatcher = + component: ComponentNameMatcher = ActivityOptions.LAUNCH_NEW_TASK_ACTIVITY_COMPONENT_NAME.toFlickerComponent(), launcherStrategy: ILauncherStrategy = LauncherStrategyFactory .getInstance(instr) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt index a9769d01caff..a1dbeeaef5cc 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt @@ -20,13 +20,13 @@ import android.app.Instrumentation import android.support.test.launcherhelper.ILauncherStrategy import android.support.test.launcherhelper.LauncherStrategyFactory import com.android.server.wm.flicker.testapp.ActivityOptions -import com.android.server.wm.traces.common.IComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import com.android.server.wm.traces.parser.toFlickerComponent class NonResizeableAppHelper @JvmOverloads constructor( instr: Instrumentation, launcherName: String = ActivityOptions.NON_RESIZEABLE_ACTIVITY_LAUNCHER_NAME, - component: IComponentMatcher = + component: ComponentNameMatcher = ActivityOptions.NON_RESIZEABLE_ACTIVITY_COMPONENT_NAME.toFlickerComponent(), launcherStrategy: ILauncherStrategy = LauncherStrategyFactory .getInstance(instr) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt index 50d036c4450f..b031a4523ab0 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt @@ -22,14 +22,14 @@ import android.support.test.launcherhelper.LauncherStrategyFactory import androidx.test.uiautomator.By import androidx.test.uiautomator.Until import com.android.server.wm.flicker.testapp.ActivityOptions -import com.android.server.wm.traces.common.IComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import com.android.server.wm.traces.parser.toFlickerComponent import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper class NotificationAppHelper @JvmOverloads constructor( instr: Instrumentation, launcherName: String = ActivityOptions.NOTIFICATION_ACTIVITY_LAUNCHER_NAME, - component: IComponentMatcher = + component: ComponentNameMatcher = ActivityOptions.NOTIFICATION_ACTIVITY_COMPONENT_NAME.toFlickerComponent(), launcherStrategy: ILauncherStrategy = LauncherStrategyFactory .getInstance(instr) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt index 459ca5b3208f..6d466d72d7dd 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt @@ -20,13 +20,13 @@ import android.app.Instrumentation import android.support.test.launcherhelper.ILauncherStrategy import android.support.test.launcherhelper.LauncherStrategyFactory import com.android.server.wm.flicker.testapp.ActivityOptions -import com.android.server.wm.traces.common.IComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import com.android.server.wm.traces.parser.toFlickerComponent class SeamlessRotationAppHelper @JvmOverloads constructor( instr: Instrumentation, launcherName: String = ActivityOptions.SEAMLESS_ACTIVITY_LAUNCHER_NAME, - component: IComponentMatcher = + component: ComponentNameMatcher = ActivityOptions.SEAMLESS_ACTIVITY_COMPONENT_NAME.toFlickerComponent(), launcherStrategy: ILauncherStrategy = LauncherStrategyFactory .getInstance(instr) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt index 4952dbaeb551..804ab3864591 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt @@ -20,13 +20,13 @@ import android.app.Instrumentation import android.support.test.launcherhelper.ILauncherStrategy import android.support.test.launcherhelper.LauncherStrategyFactory import com.android.server.wm.flicker.testapp.ActivityOptions -import com.android.server.wm.traces.common.IComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import com.android.server.wm.traces.parser.toFlickerComponent class ShowWhenLockedAppHelper @JvmOverloads constructor( instr: Instrumentation, launcherName: String = ActivityOptions.SHOW_WHEN_LOCKED_ACTIVITY_LAUNCHER_NAME, - component: IComponentMatcher = + component: ComponentNameMatcher = ActivityOptions.SHOW_WHEN_LOCKED_ACTIVITY_COMPONENT_NAME.toFlickerComponent(), launcherStrategy: ILauncherStrategy = LauncherStrategyFactory .getInstance(instr) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt index 6bddcac21a4d..5da273a7f1dc 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt @@ -20,13 +20,13 @@ import android.app.Instrumentation import android.support.test.launcherhelper.ILauncherStrategy import android.support.test.launcherhelper.LauncherStrategyFactory import com.android.server.wm.flicker.testapp.ActivityOptions -import com.android.server.wm.traces.common.IComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import com.android.server.wm.traces.parser.toFlickerComponent class SimpleAppHelper @JvmOverloads constructor( instr: Instrumentation, launcherName: String = ActivityOptions.SIMPLE_ACTIVITY_LAUNCHER_NAME, - component: IComponentMatcher = + component: ComponentNameMatcher = ActivityOptions.SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME.toFlickerComponent(), launcherStrategy: ILauncherStrategy = LauncherStrategyFactory .getInstance(instr) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt index a17344f3879b..060e9af4a51c 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt @@ -23,14 +23,14 @@ import androidx.test.uiautomator.By import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.Until import com.android.server.wm.flicker.testapp.ActivityOptions -import com.android.server.wm.traces.common.IComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import com.android.server.wm.traces.parser.toFlickerComponent import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper class TwoActivitiesAppHelper @JvmOverloads constructor( instr: Instrumentation, launcherName: String = ActivityOptions.BUTTON_ACTIVITY_LAUNCHER_NAME, - component: IComponentMatcher = + component: ComponentNameMatcher = ActivityOptions.BUTTON_ACTIVITY_COMPONENT_NAME.toFlickerComponent(), launcherStrategy: ILauncherStrategy = LauncherStrategyFactory .getInstance(instr) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt index 6b8fde21e53d..f6f3f58f29cb 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt @@ -27,7 +27,7 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group2 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -83,7 +83,7 @@ class CloseImeAutoOpenWindowToAppTest(testSpec: FlickerTestParameter) : BaseTest @Test fun imeLayerVisibleStart() { testSpec.assertLayersStart { - this.isVisible(ComponentMatcher.IME) + this.isVisible(ComponentNameMatcher.IME) } } @@ -91,7 +91,7 @@ class CloseImeAutoOpenWindowToAppTest(testSpec: FlickerTestParameter) : BaseTest @Test fun imeLayerInvisibleEnd() { testSpec.assertLayersEnd { - this.isInvisible(ComponentMatcher.IME) + this.isInvisible(ComponentNameMatcher.IME) } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt index a92ecb953a01..52f561ec4497 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt @@ -27,7 +27,7 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group2 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -92,7 +92,7 @@ class CloseImeAutoOpenWindowToHomeTest(testSpec: FlickerTestParameter) : BaseTes @Test fun imeLayerVisibleStart() { testSpec.assertLayersStart { - this.isVisible(ComponentMatcher.IME) + this.isVisible(ComponentNameMatcher.IME) } } @@ -100,7 +100,7 @@ class CloseImeAutoOpenWindowToHomeTest(testSpec: FlickerTestParameter) : BaseTes @Test fun imeLayerInvisibleEnd() { testSpec.assertLayersEnd { - this.isInvisible(ComponentMatcher.IME) + this.isInvisible(ComponentNameMatcher.IME) } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeEditorPopupDialogTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeEditorPopupDialogTest.kt index 0e4d1dd009e2..c6e25d3de4cd 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeEditorPopupDialogTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeEditorPopupDialogTest.kt @@ -28,7 +28,7 @@ import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.ImeEditorPopupDialogAppHelper import com.android.server.wm.flicker.traces.region.RegionSubject -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -41,7 +41,7 @@ import org.junit.runners.Parameterized @FixMethodOrder(MethodSorters.NAME_ASCENDING) @Group4 class CloseImeEditorPopupDialogTest(testSpec: FlickerTestParameter) : BaseTest(testSpec) { - private val imeTestApp = ImeEditorPopupDialogAppHelper(instrumentation, testSpec.startRotation) + private val imeTestApp = ImeEditorPopupDialogAppHelper(instrumentation) /** {@inheritDoc} */ override val transition: FlickerBuilder.() -> Unit = { @@ -102,12 +102,12 @@ class CloseImeEditorPopupDialogTest(testSpec: FlickerTestParameter) : BaseTest(t @Test fun imeLayerAndImeSnapshotVisibleOnScreen() { testSpec.assertLayers { - this.isVisible(ComponentMatcher.IME) + this.isVisible(ComponentNameMatcher.IME) .then() - .isVisible(ComponentMatcher.IME_SNAPSHOT) + .isVisible(ComponentNameMatcher.IME_SNAPSHOT) .then() - .isInvisible(ComponentMatcher.IME_SNAPSHOT, isOptional = true) - .isInvisible(ComponentMatcher.IME) + .isInvisible(ComponentNameMatcher.IME_SNAPSHOT, isOptional = true) + .isInvisible(ComponentNameMatcher.IME) } } @@ -118,7 +118,7 @@ class CloseImeEditorPopupDialogTest(testSpec: FlickerTestParameter) : BaseTest(t this.invoke("imeSnapshotAssociatedOnAppVisibleRegion") { val imeSnapshotLayers = it.subjects.filter { subject -> subject.name.contains( - ComponentMatcher.IME_SNAPSHOT.toLayerName() + ComponentNameMatcher.IME_SNAPSHOT.toLayerName() ) && subject.isVisible } if (imeSnapshotLayers.isNotEmpty()) { diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt index 452aa63e2bf9..23bd2200397a 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt @@ -27,7 +27,7 @@ import com.android.server.wm.flicker.annotation.Group2 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.ImeAppHelper import com.android.server.wm.flicker.navBarLayerPositionAtStartAndEnd -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import org.junit.Assume import org.junit.FixMethodOrder import org.junit.Test @@ -73,9 +73,9 @@ class CloseImeWindowToAppTest(testSpec: FlickerTestParameter) : BaseTest(testSpe override fun visibleWindowsShownMoreThanOneConsecutiveEntry() { testSpec.assertWm { this.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf( - ComponentMatcher.IME, - ComponentMatcher.SPLASH_SCREEN, - ComponentMatcher.SNAPSHOT)) + ComponentNameMatcher.IME, + ComponentNameMatcher.SPLASH_SCREEN, + ComponentNameMatcher.SNAPSHOT)) } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt index 856df260c2be..8ce184072d32 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt @@ -27,7 +27,7 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group2 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.ImeAppHelper -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -78,9 +78,9 @@ class CloseImeWindowToHomeTest(testSpec: FlickerTestParameter) : BaseTest(testSp testSpec.assertWm { this.visibleWindowsShownMoreThanOneConsecutiveEntry( listOf( - ComponentMatcher.IME, - ComponentMatcher.SPLASH_SCREEN, - ComponentMatcher.SNAPSHOT + ComponentNameMatcher.IME, + ComponentNameMatcher.SPLASH_SCREEN, + ComponentNameMatcher.SNAPSHOT ) ) } @@ -93,8 +93,8 @@ class CloseImeWindowToHomeTest(testSpec: FlickerTestParameter) : BaseTest(testSp testSpec.assertLayers { this.visibleLayersShownMoreThanOneConsecutiveEntry( listOf( - ComponentMatcher.IME, - ComponentMatcher.SPLASH_SCREEN + ComponentNameMatcher.IME, + ComponentNameMatcher.SPLASH_SCREEN ) ) } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt index 19cab3c20dae..9c99d966e345 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt @@ -18,52 +18,52 @@ package com.android.server.wm.flicker.ime import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher fun FlickerTestParameter.imeLayerBecomesVisible() { assertLayers { - this.isInvisible(ComponentMatcher.IME) + this.isInvisible(ComponentNameMatcher.IME) .then() - .isVisible(ComponentMatcher.IME) + .isVisible(ComponentNameMatcher.IME) } } fun FlickerTestParameter.imeLayerBecomesInvisible() { assertLayers { - this.isVisible(ComponentMatcher.IME) + this.isVisible(ComponentNameMatcher.IME) .then() - .isInvisible(ComponentMatcher.IME) + .isInvisible(ComponentNameMatcher.IME) } } fun FlickerTestParameter.imeWindowIsAlwaysVisible(rotatesScreen: Boolean = false) { if (rotatesScreen) { assertWm { - this.isNonAppWindowVisible(ComponentMatcher.IME) + this.isNonAppWindowVisible(ComponentNameMatcher.IME) .then() - .isNonAppWindowInvisible(ComponentMatcher.IME) + .isNonAppWindowInvisible(ComponentNameMatcher.IME) .then() - .isNonAppWindowVisible(ComponentMatcher.IME) + .isNonAppWindowVisible(ComponentNameMatcher.IME) } } else { assertWm { - this.isNonAppWindowVisible(ComponentMatcher.IME) + this.isNonAppWindowVisible(ComponentNameMatcher.IME) } } } fun FlickerTestParameter.imeWindowBecomesVisible() { assertWm { - this.isNonAppWindowInvisible(ComponentMatcher.IME) + this.isNonAppWindowInvisible(ComponentNameMatcher.IME) .then() - .isNonAppWindowVisible(ComponentMatcher.IME) + .isNonAppWindowVisible(ComponentNameMatcher.IME) } } fun FlickerTestParameter.imeWindowBecomesInvisible() { assertWm { - this.isNonAppWindowVisible(ComponentMatcher.IME) + this.isNonAppWindowVisible(ComponentNameMatcher.IME) .then() - .isNonAppWindowInvisible(ComponentMatcher.IME) + .isNonAppWindowInvisible(ComponentNameMatcher.IME) } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt index 4569a5b4910e..a04a50f02c26 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt @@ -30,7 +30,7 @@ import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.FixMethodOrder @@ -101,7 +101,7 @@ class LaunchAppShowImeAndDialogThemeAppTest( @Test fun imeLayerExistsEnd() { testSpec.assertLayersEnd { - this.isVisible(ComponentMatcher.IME) + this.isVisible(ComponentNameMatcher.IME) } } @@ -112,7 +112,7 @@ class LaunchAppShowImeAndDialogThemeAppTest( @Test fun imeSnapshotNotVisible() { testSpec.assertLayers { - this.isInvisible(ComponentMatcher.IME_SNAPSHOT) + this.isInvisible(ComponentNameMatcher.IME_SNAPSHOT) } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt index 977719c5f670..04e4bc94de9c 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt @@ -28,7 +28,7 @@ import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper import com.android.server.wm.flicker.helpers.ImeStateInitializeHelper import com.android.server.wm.flicker.helpers.setRotation -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -114,7 +114,7 @@ class LaunchAppShowImeOnStartTest(testSpec: FlickerTestParameter) : BaseTest(tes @Test fun imeLayerNotExistsStart() { testSpec.assertLayersStart { - this.isInvisible(ComponentMatcher.IME) + this.isInvisible(ComponentNameMatcher.IME) } } @@ -125,7 +125,7 @@ class LaunchAppShowImeOnStartTest(testSpec: FlickerTestParameter) : BaseTest(tes @Test fun imeLayerExistsEnd() { testSpec.assertLayersEnd { - this.isVisible(ComponentMatcher.IME) + this.isVisible(ComponentNameMatcher.IME) } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt index 16cf22abecc2..9475734ef3f5 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt @@ -31,7 +31,7 @@ import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled import com.android.server.wm.flicker.navBarLayerIsVisibleAtStartAndEnd import com.android.server.wm.flicker.statusBarLayerIsVisibleAtStartAndEnd -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import com.android.server.wm.traces.common.WindowManagerConditionsFactory import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper import org.junit.Assume @@ -138,10 +138,10 @@ class OpenImeWindowToOverViewTest(testSpec: FlickerTestParameter) : BaseTest(tes Assume.assumeTrue(testSpec.isGesturalNavigation) Assume.assumeTrue(isShellTransitionsEnabled) testSpec.assertLayersStart { - this.isVisible(ComponentMatcher.NAV_BAR) + this.isVisible(ComponentNameMatcher.NAV_BAR) } testSpec.assertLayersEnd { - this.isInvisible(ComponentMatcher.NAV_BAR) + this.isInvisible(ComponentNameMatcher.NAV_BAR) } } @@ -156,10 +156,10 @@ class OpenImeWindowToOverViewTest(testSpec: FlickerTestParameter) : BaseTest(tes Assume.assumeTrue(testSpec.isGesturalNavigation) Assume.assumeFalse(testSpec.isTablet) testSpec.assertLayersStart { - this.isVisible(ComponentMatcher.STATUS_BAR) + this.isVisible(ComponentNameMatcher.STATUS_BAR) } testSpec.assertLayersEnd { - this.isInvisible(ComponentMatcher.STATUS_BAR) + this.isInvisible(ComponentNameMatcher.STATUS_BAR) } } @@ -215,10 +215,10 @@ class OpenImeWindowToOverViewTest(testSpec: FlickerTestParameter) : BaseTest(tes Assume.assumeFalse(testSpec.isTablet) Assume.assumeTrue(isShellTransitionsEnabled) testSpec.assertLayersStart { - this.isVisible(ComponentMatcher.STATUS_BAR) + this.isVisible(ComponentNameMatcher.STATUS_BAR) } testSpec.assertLayersEnd { - this.isInvisible(ComponentMatcher.STATUS_BAR) + this.isInvisible(ComponentNameMatcher.STATUS_BAR) } } @@ -235,7 +235,7 @@ class OpenImeWindowToOverViewTest(testSpec: FlickerTestParameter) : BaseTest(tes @Test fun imeLayerIsVisibleAndAssociatedWithAppWidow() { testSpec.assertLayersStart { - isVisible(ComponentMatcher.IME).visibleRegion(ComponentMatcher.IME) + isVisible(ComponentNameMatcher.IME).visibleRegion(ComponentNameMatcher.IME) .coversAtMost( isVisible(imeTestApp) .visibleRegion(imeTestApp).region @@ -243,10 +243,10 @@ class OpenImeWindowToOverViewTest(testSpec: FlickerTestParameter) : BaseTest(tes } testSpec.assertLayers { this.invoke("imeLayerIsVisibleAndAlignAppWidow") { - val imeVisibleRegion = it.visibleRegion(ComponentMatcher.IME) + val imeVisibleRegion = it.visibleRegion(ComponentNameMatcher.IME) val appVisibleRegion = it.visibleRegion(imeTestApp) if (imeVisibleRegion.region.isNotEmpty) { - it.isVisible(ComponentMatcher.IME) + it.isVisible(ComponentNameMatcher.IME) imeVisibleRegion.coversAtMost(appVisibleRegion.region) } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt index 2207fe571e9f..2e22e6224813 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt @@ -29,7 +29,7 @@ import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled import com.android.server.wm.flicker.helpers.reopenAppFromOverview import com.android.server.wm.flicker.helpers.setRotation -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import org.junit.Assume import org.junit.FixMethodOrder import org.junit.Test @@ -84,11 +84,11 @@ open class ReOpenImeWindowTest(testSpec: FlickerTestParameter) : BaseTest(testSp override fun visibleLayersShownMoreThanOneConsecutiveEntry() { // depends on how much of the animation transactions are sent to SF at once // sometimes this layer appears for 2-3 frames, sometimes for only 1 - val recentTaskComponent = ComponentMatcher("", "RecentTaskScreenshotSurface") + val recentTaskComponent = ComponentNameMatcher("", "RecentTaskScreenshotSurface") testSpec.assertLayers { this.visibleLayersShownMoreThanOneConsecutiveEntry( - listOf(ComponentMatcher.SPLASH_SCREEN, - ComponentMatcher.SNAPSHOT, recentTaskComponent) + listOf(ComponentNameMatcher.SPLASH_SCREEN, + ComponentNameMatcher.SNAPSHOT, recentTaskComponent) ) } } @@ -97,11 +97,11 @@ open class ReOpenImeWindowTest(testSpec: FlickerTestParameter) : BaseTest(testSp @Presubmit @Test override fun visibleWindowsShownMoreThanOneConsecutiveEntry() { - val component = ComponentMatcher("", "RecentTaskScreenshotSurface") + val component = ComponentNameMatcher("", "RecentTaskScreenshotSurface") testSpec.assertWm { this.visibleWindowsShownMoreThanOneConsecutiveEntry( - ignoreWindows = listOf(ComponentMatcher.SPLASH_SCREEN, - ComponentMatcher.SNAPSHOT, + ignoreWindows = listOf(ComponentNameMatcher.SPLASH_SCREEN, + ComponentNameMatcher.SNAPSHOT, component) ) } @@ -111,9 +111,9 @@ open class ReOpenImeWindowTest(testSpec: FlickerTestParameter) : BaseTest(testSp @Test fun launcherWindowBecomesInvisible() { testSpec.assertWm { - this.isAppWindowVisible(ComponentMatcher.LAUNCHER) + this.isAppWindowVisible(ComponentNameMatcher.LAUNCHER) .then() - .isAppWindowInvisible(ComponentMatcher.LAUNCHER) + .isAppWindowInvisible(ComponentNameMatcher.LAUNCHER) } } @@ -157,11 +157,11 @@ open class ReOpenImeWindowTest(testSpec: FlickerTestParameter) : BaseTest(testSp fun imeLayerIsBecomesVisibleLegacy() { Assume.assumeFalse(isShellTransitionsEnabled) testSpec.assertLayers { - this.isVisible(ComponentMatcher.IME) + this.isVisible(ComponentNameMatcher.IME) .then() - .isInvisible(ComponentMatcher.IME) + .isInvisible(ComponentNameMatcher.IME) .then() - .isVisible(ComponentMatcher.IME) + .isVisible(ComponentNameMatcher.IME) } } @@ -170,7 +170,7 @@ open class ReOpenImeWindowTest(testSpec: FlickerTestParameter) : BaseTest(testSp fun imeLayerBecomesVisibleShellTransit() { Assume.assumeTrue(isShellTransitionsEnabled) testSpec.assertLayers { - this.isVisible(ComponentMatcher.IME) + this.isVisible(ComponentNameMatcher.IME) } } @@ -178,9 +178,9 @@ open class ReOpenImeWindowTest(testSpec: FlickerTestParameter) : BaseTest(testSp @Test fun appLayerReplacesLauncher() { testSpec.assertLayers { - this.isVisible(ComponentMatcher.LAUNCHER) + this.isVisible(ComponentNameMatcher.LAUNCHER) .then() - .isVisible(ComponentMatcher.SNAPSHOT, isOptional = true) + .isVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true) .then() .isVisible(testApp) } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt index be7b80e8db82..4f47ec439da8 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt @@ -31,7 +31,7 @@ import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper import com.android.server.wm.flicker.helpers.SimpleAppHelper import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled import com.android.server.wm.flicker.helpers.setRotation -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import org.junit.Assume import org.junit.Before import org.junit.FixMethodOrder @@ -177,20 +177,20 @@ open class SwitchImeWindowsFromGestureNavTest( @Test open fun imeLayerIsVisibleWhenSwitchingToImeApp() { testSpec.assertLayersStart { - isVisible(ComponentMatcher.IME) + isVisible(ComponentNameMatcher.IME) } testSpec.assertLayersTag(TAG_IME_VISIBLE) { - isVisible(ComponentMatcher.IME) + isVisible(ComponentNameMatcher.IME) } testSpec.assertLayersEnd { - isVisible(ComponentMatcher.IME) + isVisible(ComponentNameMatcher.IME) } } @Test fun imeLayerIsInvisibleWhenSwitchingToTestApp() { testSpec.assertLayersTag(TAG_IME_INVISIBLE) { - isInvisible(ComponentMatcher.IME) + isInvisible(ComponentNameMatcher.IME) } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest_ShellTransit.kt index a8c0a0b55009..5ac1712adbf2 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest_ShellTransit.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest_ShellTransit.kt @@ -24,7 +24,6 @@ import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled import com.android.server.wm.flicker.navBarWindowIsVisibleAtStartAndEnd -import com.android.server.wm.traces.common.ComponentMatcher import org.junit.Assume import org.junit.Before import org.junit.FixMethodOrder diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt index 86b8e5fa1647..33c280ea78bb 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt @@ -27,7 +27,7 @@ import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.TwoActivitiesAppHelper import com.android.server.wm.flicker.testapp.ActivityOptions -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import com.android.server.wm.traces.parser.toFlickerComponent import org.junit.FixMethodOrder import org.junit.Test @@ -118,7 +118,7 @@ class ActivitiesTransitionTest(testSpec: FlickerTestParameter) : BaseTest(testSp @Test fun launcherWindowNotOnTop() { testSpec.assertWm { - this.isAppWindowNotOnTop(ComponentMatcher.LAUNCHER) + this.isAppWindowNotOnTop(ComponentNameMatcher.LAUNCHER) } } @@ -128,7 +128,7 @@ class ActivitiesTransitionTest(testSpec: FlickerTestParameter) : BaseTest(testSp @Presubmit @Test fun launcherLayerNotVisible() { - testSpec.assertLayers { this.isInvisible(ComponentMatcher.LAUNCHER) } + testSpec.assertLayers { this.isInvisible(ComponentNameMatcher.LAUNCHER) } } companion object { diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt index 2d4d7986a67e..bece406d5a96 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt @@ -19,7 +19,7 @@ package com.android.server.wm.flicker.launch import android.platform.test.annotations.Presubmit import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.replacesLayer -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import org.junit.Test /** @@ -46,7 +46,7 @@ abstract class OpenAppFromLauncherTransition( */ open fun appLayerReplacesLauncher() { testSpec.replacesLayer( - ComponentMatcher.LAUNCHER, testApp, + ComponentNameMatcher.LAUNCHER, testApp, ignoreEntriesWithRotationLayer = true, ignoreSnapshot = true, ignoreSplashscreen = true ) @@ -61,12 +61,12 @@ abstract class OpenAppFromLauncherTransition( @Test open fun appWindowReplacesLauncherAsTopWindow() { testSpec.assertWm { - this.isAppWindowOnTop(ComponentMatcher.LAUNCHER) + this.isAppWindowOnTop(ComponentNameMatcher.LAUNCHER) .then() .isAppWindowOnTop( testApp - .or(ComponentMatcher.SNAPSHOT) - .or(ComponentMatcher.SPLASH_SCREEN) + .or(ComponentNameMatcher.SNAPSHOT) + .or(ComponentNameMatcher.SPLASH_SCREEN) ) } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt index 220e4caf5faa..bfc7b39f9d9f 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt @@ -26,7 +26,6 @@ import com.android.server.wm.flicker.annotation.Group1 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.navBarLayerPositionAtEnd import com.android.server.wm.flicker.statusBarLayerPositionAtEnd -import com.android.server.wm.traces.common.ComponentMatcher import org.junit.Assume import org.junit.FixMethodOrder import org.junit.Ignore diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt index 9ed1bde86647..e517c2ad2c49 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt @@ -27,7 +27,7 @@ import com.android.server.wm.flicker.annotation.Group1 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.navBarLayerPositionAtEnd import com.android.server.wm.flicker.statusBarLayerPositionAtEnd -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import org.junit.Assume import org.junit.FixMethodOrder import org.junit.Ignore @@ -86,9 +86,9 @@ open class OpenAppFromLockNotificationWarm(testSpec: FlickerTestParameter) : testSpec.assertWm { this.hasNoVisibleAppWindow() .then() - .isAppWindowOnTop(ComponentMatcher.SNAPSHOT, isOptional = true) + .isAppWindowOnTop(ComponentNameMatcher.SNAPSHOT, isOptional = true) .then() - .isAppWindowOnTop(ComponentMatcher.SPLASH_SCREEN, isOptional = true) + .isAppWindowOnTop(ComponentNameMatcher.SPLASH_SCREEN, isOptional = true) .then() .isAppWindowOnTop(testApp) } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt index 29730591c957..75311eaf5c66 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt @@ -26,7 +26,7 @@ import com.android.server.wm.flicker.annotation.Group1 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.ShowWhenLockedAppHelper import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -88,7 +88,7 @@ class OpenAppFromLockNotificationWithLockOverlayApp(testSpec: FlickerTestParamet testSpec.assertWm { this.hasNoVisibleAppWindow() .then() - .isAppWindowOnTop(ComponentMatcher.SNAPSHOT, isOptional = true) + .isAppWindowOnTop(ComponentNameMatcher.SNAPSHOT, isOptional = true) .then() .isAppWindowOnTop(showWhenLockedApp) } @@ -100,7 +100,7 @@ class OpenAppFromLockNotificationWithLockOverlayApp(testSpec: FlickerTestParamet testSpec.assertLayers { this.isInvisible(showWhenLockedApp) .then() - .isVisible(ComponentMatcher.SNAPSHOT, isOptional = true) + .isVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true) .then() .isVisible(showWhenLockedApp) } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt index 1d8b0a64c70f..ecc60b8d45c0 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt @@ -22,7 +22,7 @@ import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.navBarLayerPositionAtEnd import com.android.server.wm.flicker.statusBarLayerPositionAtEnd -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import org.junit.Assume import org.junit.Ignore import org.junit.Test @@ -77,9 +77,9 @@ abstract class OpenAppFromLockTransition(testSpec: FlickerTestParameter) : testSpec.assertWm { this.hasNoVisibleAppWindow() .then() - .isAppWindowOnTop(ComponentMatcher.SNAPSHOT, isOptional = true) + .isAppWindowOnTop(ComponentNameMatcher.SNAPSHOT, isOptional = true) .then() - .isAppWindowOnTop(ComponentMatcher.SPLASH_SCREEN, isOptional = true) + .isAppWindowOnTop(ComponentNameMatcher.SPLASH_SCREEN, isOptional = true) .then() .isAppWindowOnTop(testApp) } @@ -152,7 +152,7 @@ abstract class OpenAppFromLockTransition(testSpec: FlickerTestParameter) : @Test fun statusBarLayerIsVisibleAtEnd() { testSpec.assertLayersEnd { - this.isVisible(ComponentMatcher.STATUS_BAR) + this.isVisible(ComponentNameMatcher.STATUS_BAR) } } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt index 866e819bf5fc..78baddff582c 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt @@ -34,7 +34,6 @@ import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen import com.android.server.wm.flicker.taskBarLayerIsVisibleAtEnd import com.android.server.wm.flicker.taskBarWindowIsVisibleAtEnd -import com.android.server.wm.traces.common.ComponentMatcher import org.junit.Assume import org.junit.FixMethodOrder import org.junit.Ignore diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt index 647607794fa9..53be7d43cce8 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt @@ -29,7 +29,7 @@ import com.android.server.wm.flicker.annotation.FlickerServiceCompatible import com.android.server.wm.flicker.annotation.Group1 import com.android.server.wm.flicker.helpers.NonResizeableAppHelper import com.android.server.wm.flicker.statusBarLayerPositionAtEnd -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import org.junit.Assume import org.junit.FixMethodOrder import org.junit.Ignore @@ -76,9 +76,9 @@ open class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : fun navBarLayerVisibilityChanges() { Assume.assumeFalse(testSpec.isTablet) testSpec.assertLayers { - this.isInvisible(ComponentMatcher.NAV_BAR) + this.isInvisible(ComponentNameMatcher.NAV_BAR) .then() - .isVisible(ComponentMatcher.NAV_BAR) + .isVisible(ComponentNameMatcher.NAV_BAR) } } @@ -102,9 +102,9 @@ open class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : fun navBarWindowsVisibilityChanges() { Assume.assumeFalse(testSpec.isTablet) testSpec.assertWm { - this.isNonAppWindowInvisible(ComponentMatcher.NAV_BAR) + this.isNonAppWindowInvisible(ComponentNameMatcher.NAV_BAR) .then() - .isAboveAppWindowVisible(ComponentMatcher.NAV_BAR) + .isAboveAppWindowVisible(ComponentNameMatcher.NAV_BAR) } } @@ -117,7 +117,7 @@ open class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : fun taskBarLayerIsVisibleAtEnd() { Assume.assumeTrue(testSpec.isTablet) testSpec.assertLayersEnd { - this.isVisible(ComponentMatcher.TASK_BAR) + this.isVisible(ComponentNameMatcher.TASK_BAR) } } @@ -130,7 +130,7 @@ open class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : @Test override fun statusBarLayerIsVisibleAtStartAndEnd() { testSpec.assertLayersEnd { - this.isVisible(ComponentMatcher.STATUS_BAR) + this.isVisible(ComponentNameMatcher.STATUS_BAR) } } @@ -180,7 +180,7 @@ open class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : fun navBarLayerIsVisibleAtEnd() { Assume.assumeFalse(testSpec.isTablet) testSpec.assertLayersEnd { - this.isVisible(ComponentMatcher.NAV_BAR) + this.isVisible(ComponentNameMatcher.NAV_BAR) } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt index 5d2b56707de9..8658c03acf60 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt @@ -24,7 +24,7 @@ import com.android.server.wm.flicker.helpers.SimpleAppHelper import com.android.server.wm.flicker.helpers.StandardAppHelper import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import org.junit.Test /** @@ -65,9 +65,9 @@ abstract class OpenAppTransition(testSpec: FlickerTestParameter) : BaseTest(test .then() .isInvisible(testApp, isOptional = true) .then() - .isVisible(ComponentMatcher.SNAPSHOT, isOptional = true) + .isVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true) .then() - .isVisible(ComponentMatcher.SPLASH_SCREEN, isOptional = true) + .isVisible(ComponentNameMatcher.SPLASH_SCREEN, isOptional = true) .then() .isVisible(testApp) } @@ -77,9 +77,9 @@ abstract class OpenAppTransition(testSpec: FlickerTestParameter) : BaseTest(test testSpec.assertLayers { this.isInvisible(testApp) .then() - .isVisible(ComponentMatcher.SNAPSHOT, isOptional = true) + .isVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true) .then() - .isVisible(ComponentMatcher.SPLASH_SCREEN, isOptional = true) + .isVisible(ComponentNameMatcher.SPLASH_SCREEN, isOptional = true) .then() .isVisible(testApp) } @@ -110,9 +110,9 @@ abstract class OpenAppTransition(testSpec: FlickerTestParameter) : BaseTest(test testSpec.assertWm { this.isAppWindowInvisible(testApp) .then() - .isAppWindowVisible(ComponentMatcher.SNAPSHOT, isOptional = true) + .isAppWindowVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true) .then() - .isAppWindowVisible(ComponentMatcher.SPLASH_SCREEN, isOptional = true) + .isAppWindowVisible(ComponentNameMatcher.SPLASH_SCREEN, isOptional = true) .then() .isAppWindowVisible(testApp) } @@ -130,8 +130,8 @@ abstract class OpenAppTransition(testSpec: FlickerTestParameter) : BaseTest(test .then() .isAppWindowOnTop( testApp - .or(ComponentMatcher.SNAPSHOT) - .or(ComponentMatcher.SPLASH_SCREEN) + .or(ComponentNameMatcher.SNAPSHOT) + .or(ComponentNameMatcher.SPLASH_SCREEN) ) } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt index b482e5f3c3fb..fe5e74b87f93 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt @@ -30,9 +30,9 @@ import com.android.server.wm.flicker.helpers.NewTasksAppHelper import com.android.server.wm.flicker.helpers.WindowUtils import com.android.server.wm.flicker.testapp.ActivityOptions.LAUNCH_NEW_TASK_ACTIVITY_COMPONENT_NAME import com.android.server.wm.flicker.testapp.ActivityOptions.SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME -import com.android.server.wm.traces.common.ComponentMatcher -import com.android.server.wm.traces.common.ComponentMatcher.Companion.SPLASH_SCREEN -import com.android.server.wm.traces.common.ComponentMatcher.Companion.WALLPAPER_BBQ_WRAPPER +import com.android.server.wm.traces.common.ComponentNameMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher.Companion.SPLASH_SCREEN +import com.android.server.wm.traces.common.ComponentNameMatcher.Companion.WALLPAPER_BBQ_WRAPPER import com.android.server.wm.traces.common.IComponentMatcher import com.android.server.wm.traces.parser.toFlickerComponent import org.junit.FixMethodOrder @@ -117,7 +117,7 @@ class TaskTransitionTest(testSpec: FlickerTestParameter) : BaseTest(testSpec) { @Test fun launcherWindowIsNeverVisible() { testSpec.assertWm { - this.isAppWindowInvisible(ComponentMatcher.LAUNCHER) + this.isAppWindowInvisible(ComponentNameMatcher.LAUNCHER) } } @@ -130,7 +130,7 @@ class TaskTransitionTest(testSpec: FlickerTestParameter) : BaseTest(testSpec) { @Test fun launcherLayerIsNeverVisible() { testSpec.assertLayers { - this.isInvisible(ComponentMatcher.LAUNCHER) + this.isInvisible(ComponentNameMatcher.LAUNCHER) } } @@ -140,7 +140,7 @@ class TaskTransitionTest(testSpec: FlickerTestParameter) : BaseTest(testSpec) { @Postsubmit @Test fun colorLayerIsVisibleDuringTransition() { - val bgColorLayer = ComponentMatcher("", "colorBackgroundLayer") + val bgColorLayer = ComponentNameMatcher("", "colorBackgroundLayer") val displayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation) testSpec.assertLayers { diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt index a9fb0f261465..181767b3448d 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt @@ -30,7 +30,7 @@ import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.NonResizeableAppHelper import com.android.server.wm.flicker.helpers.SimpleAppHelper import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import com.android.server.wm.traces.common.Rect import org.junit.Assume import org.junit.Before @@ -178,7 +178,7 @@ open class QuickSwitchBetweenTwoAppsBackTest( testSpec.assertWm { this.isAppWindowInvisible(testApp1) .then() - .isAppWindowVisible(ComponentMatcher.SNAPSHOT, isOptional = true) + .isAppWindowVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true) .then() .isAppWindowVisible(testApp1) } @@ -238,9 +238,9 @@ open class QuickSwitchBetweenTwoAppsBackTest( this.isAppWindowVisible(testApp2) .then() // TODO: Do we actually want to test this? Seems too implementation specific... - .isAppWindowVisible(ComponentMatcher.LAUNCHER, isOptional = true) + .isAppWindowVisible(ComponentNameMatcher.LAUNCHER, isOptional = true) .then() - .isAppWindowVisible(ComponentMatcher.SNAPSHOT, isOptional = true) + .isAppWindowVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true) .then() .isAppWindowVisible(testApp1) } @@ -257,9 +257,9 @@ open class QuickSwitchBetweenTwoAppsBackTest( testSpec.assertLayers { this.isVisible(testApp2) .then() - .isVisible(ComponentMatcher.LAUNCHER, isOptional = true) + .isVisible(ComponentNameMatcher.LAUNCHER, isOptional = true) .then() - .isVisible(ComponentMatcher.SNAPSHOT, isOptional = true) + .isVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true) .then() .isVisible(testApp1) } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt index 2607ee5bb0ef..461bae482299 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt @@ -24,7 +24,6 @@ import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.annotation.Group1 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled import com.android.server.wm.flicker.navBarWindowIsVisibleAtStartAndEnd -import com.android.server.wm.traces.common.ComponentMatcher import org.junit.Assume import org.junit.Before import org.junit.FixMethodOrder diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt index 3b602126399d..0f05622c81bc 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt @@ -31,7 +31,7 @@ import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.NonResizeableAppHelper import com.android.server.wm.flicker.helpers.SimpleAppHelper import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import com.android.server.wm.traces.common.Rect import org.junit.Assume import org.junit.Before @@ -112,7 +112,7 @@ open class QuickSwitchBetweenTwoAppsForwardTest( @Test open fun startsWithApp1WindowsCoverFullScreen() { testSpec.assertWmStart { - this.visibleRegion(testApp1.or(ComponentMatcher.LETTERBOX)) + this.visibleRegion(testApp1.or(ComponentNameMatcher.LETTERBOX)) .coversExactly(startDisplayBounds) } } @@ -160,7 +160,7 @@ open class QuickSwitchBetweenTwoAppsForwardTest( @Test open fun endsWithApp2LayersCoveringFullScreen() { testSpec.assertLayersEnd { - this.visibleRegion(testApp2.or(ComponentMatcher.LETTERBOX)) + this.visibleRegion(testApp2.or(ComponentNameMatcher.LETTERBOX)) .coversExactly(startDisplayBounds) } } @@ -187,7 +187,7 @@ open class QuickSwitchBetweenTwoAppsForwardTest( testSpec.assertWm { this.isAppWindowInvisible(testApp2) .then() - .isAppWindowVisible(ComponentMatcher.SNAPSHOT, isOptional = true) + .isAppWindowVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true) .then() .isAppWindowVisible(testApp2) } @@ -246,9 +246,9 @@ open class QuickSwitchBetweenTwoAppsForwardTest( testSpec.assertWm { this.isAppWindowVisible(testApp1) .then() - .isAppWindowVisible(ComponentMatcher.LAUNCHER, isOptional = true) + .isAppWindowVisible(ComponentNameMatcher.LAUNCHER, isOptional = true) .then() - .isAppWindowVisible(ComponentMatcher.SNAPSHOT, isOptional = true) + .isAppWindowVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true) .then() .isAppWindowVisible(testApp2) } @@ -265,9 +265,9 @@ open class QuickSwitchBetweenTwoAppsForwardTest( testSpec.assertLayers { this.isVisible(testApp1) .then() - .isVisible(ComponentMatcher.LAUNCHER, isOptional = true) + .isVisible(ComponentNameMatcher.LAUNCHER, isOptional = true) .then() - .isVisible(ComponentMatcher.SNAPSHOT, isOptional = true) + .isVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true) .then() .isVisible(testApp2) } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest_ShellTransit.kt index 27ae12566e94..f644b97e03df 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest_ShellTransit.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest_ShellTransit.kt @@ -24,7 +24,6 @@ import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.annotation.Group1 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled import com.android.server.wm.flicker.navBarWindowIsVisibleAtStartAndEnd -import com.android.server.wm.traces.common.ComponentMatcher import org.junit.Assume import org.junit.Before import org.junit.FixMethodOrder diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt index c79b55251c74..d1f356c830eb 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt @@ -30,7 +30,7 @@ import com.android.server.wm.flicker.annotation.Group1 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.SimpleAppHelper import com.android.server.wm.flicker.navBarWindowIsVisibleAtStartAndEnd -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import com.android.server.wm.traces.common.Rect import org.junit.Assume import org.junit.FixMethodOrder @@ -152,7 +152,7 @@ class QuickSwitchFromLauncherTest(testSpec: FlickerTestParameter) : BaseTest(tes @Test fun startsWithLauncherWindowsCoverFullScreen() { testSpec.assertWmStart { - this.visibleRegion(ComponentMatcher.LAUNCHER).coversExactly(startDisplayBounds) + this.visibleRegion(ComponentNameMatcher.LAUNCHER).coversExactly(startDisplayBounds) } } @@ -164,7 +164,7 @@ class QuickSwitchFromLauncherTest(testSpec: FlickerTestParameter) : BaseTest(tes @Test fun startsWithLauncherLayersCoverFullScreen() { testSpec.assertLayersStart { - this.visibleRegion(ComponentMatcher.LAUNCHER).coversExactly(startDisplayBounds) + this.visibleRegion(ComponentNameMatcher.LAUNCHER).coversExactly(startDisplayBounds) } } @@ -175,7 +175,7 @@ class QuickSwitchFromLauncherTest(testSpec: FlickerTestParameter) : BaseTest(tes @Test fun startsWithLauncherBeingOnTop() { testSpec.assertWmStart { - this.isAppWindowOnTop(ComponentMatcher.LAUNCHER) + this.isAppWindowOnTop(ComponentNameMatcher.LAUNCHER) } } @@ -228,9 +228,9 @@ class QuickSwitchFromLauncherTest(testSpec: FlickerTestParameter) : BaseTest(tes @Test fun launcherWindowBecomesAndStaysInvisible() { testSpec.assertWm { - this.isAppWindowOnTop(ComponentMatcher.LAUNCHER) + this.isAppWindowOnTop(ComponentNameMatcher.LAUNCHER) .then() - .isAppWindowNotOnTop(ComponentMatcher.LAUNCHER) + .isAppWindowNotOnTop(ComponentNameMatcher.LAUNCHER) } } @@ -243,9 +243,9 @@ class QuickSwitchFromLauncherTest(testSpec: FlickerTestParameter) : BaseTest(tes @Test fun launcherLayerBecomesAndStaysInvisible() { testSpec.assertLayers { - this.isVisible(ComponentMatcher.LAUNCHER) + this.isVisible(ComponentNameMatcher.LAUNCHER) .then() - .isInvisible(ComponentMatcher.LAUNCHER) + .isInvisible(ComponentNameMatcher.LAUNCHER) } } @@ -258,9 +258,9 @@ class QuickSwitchFromLauncherTest(testSpec: FlickerTestParameter) : BaseTest(tes @Test fun appWindowIsVisibleOnceLauncherWindowIsInvisible() { testSpec.assertWm { - this.isAppWindowOnTop(ComponentMatcher.LAUNCHER) + this.isAppWindowOnTop(ComponentNameMatcher.LAUNCHER) .then() - .isAppWindowVisible(ComponentMatcher.SNAPSHOT, isOptional = true) + .isAppWindowVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true) .then() .isAppWindowVisible(testApp) } @@ -275,9 +275,9 @@ class QuickSwitchFromLauncherTest(testSpec: FlickerTestParameter) : BaseTest(tes @Test fun appLayerIsVisibleOnceLauncherLayerIsInvisible() { testSpec.assertLayers { - this.isVisible(ComponentMatcher.LAUNCHER) + this.isVisible(ComponentNameMatcher.LAUNCHER) .then() - .isVisible(ComponentMatcher.SNAPSHOT, isOptional = true) + .isVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true) .then() .isVisible(testApp) } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt index 5e80fabcd8a4..4be8963bf7b7 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt @@ -25,7 +25,7 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group3 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.SimpleAppHelper -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -106,10 +106,10 @@ class ChangeAppRotationTest( testSpec.assertLayers { this.isVisible(testApp) .then() - .isVisible(ComponentMatcher.ROTATION) + .isVisible(ComponentNameMatcher.ROTATION) .then() .isVisible(testApp) - .isInvisible(ComponentMatcher.ROTATION) + .isInvisible(ComponentNameMatcher.ROTATION) } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt index 36a152117dcc..7e159d465b13 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt @@ -22,7 +22,7 @@ import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.StandardAppHelper import com.android.server.wm.flicker.helpers.setRotation -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import org.junit.Test /** @@ -55,9 +55,9 @@ abstract class RotationTransition(testSpec: FlickerTestParameter) : BaseTest(tes testSpec.assertLayers { this.visibleLayersShownMoreThanOneConsecutiveEntry( ignoreLayers = listOf( - ComponentMatcher.SPLASH_SCREEN, - ComponentMatcher.SNAPSHOT, - ComponentMatcher("", "SecondaryHomeHandle") + ComponentNameMatcher.SPLASH_SCREEN, + ComponentNameMatcher.SNAPSHOT, + ComponentNameMatcher("", "SecondaryHomeHandle") ) ) } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt index 1e3caa43a07c..0912812afef9 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt @@ -27,7 +27,7 @@ import com.android.server.wm.flicker.annotation.Group3 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.SeamlessRotationAppHelper import com.android.server.wm.flicker.testapp.ActivityOptions -import com.android.server.wm.traces.common.ComponentMatcher +import com.android.server.wm.traces.common.ComponentNameMatcher import org.junit.FixMethodOrder import org.junit.Ignore import org.junit.Test @@ -186,7 +186,7 @@ open class SeamlessAppRotationTest( @Test fun statusBarWindowIsAlwaysInvisible() { testSpec.assertWm { - this.isAboveAppWindowInvisible(ComponentMatcher.STATUS_BAR) + this.isAboveAppWindowInvisible(ComponentNameMatcher.STATUS_BAR) } } @@ -198,7 +198,7 @@ open class SeamlessAppRotationTest( @Test fun statusBarLayerIsAlwaysInvisible() { testSpec.assertLayers { - this.isInvisible(ComponentMatcher.STATUS_BAR) + this.isInvisible(ComponentNameMatcher.STATUS_BAR) } } diff --git a/tools/lint/Android.bp b/tools/lint/Android.bp index 260104145505..96618f413db1 100644 --- a/tools/lint/Android.bp +++ b/tools/lint/Android.bp @@ -51,3 +51,9 @@ java_test_host { unit_test: true, }, } + +python_binary_host { + name: "lint_fix", + main: "fix/lint_fix.py", + srcs: ["fix/lint_fix.py"], +} diff --git a/tools/lint/README.md b/tools/lint/README.md index c674d36431b7..99149c140c1c 100644 --- a/tools/lint/README.md +++ b/tools/lint/README.md @@ -44,6 +44,10 @@ m out/soong/.intermediates/frameworks/base/services/autofill/services.autofill/a environment variable with the id of the lint. For example: `ANDROID_LINT_CHECK=UnusedTokenOfOriginalCallingIdentity m out/[...]/lint-report.html` +## How to apply automatic fixes suggested by lint + +See [lint_fix](fix/README.md) + ## Create or update a baseline Baseline files can be used to silence known errors (and warnings) that are deemed to be safe. When diff --git a/tools/lint/fix/README.md b/tools/lint/fix/README.md new file mode 100644 index 000000000000..367d0bcb1aa7 --- /dev/null +++ b/tools/lint/fix/README.md @@ -0,0 +1,46 @@ +# Refactoring the platform with lint +Inspiration: go/refactor-the-platform-with-lint\ +**Special Thanks: brufino@, azharaa@, for the prior work that made this all possible** + +## What is this? + +It's a python script that runs the framework linter, +and then copies modified files back into the source tree.\ +Why python, you ask? Because python is cool ¯\_(ツ)_/¯. + +## Why? + +Lint is not allowed to modify source files directly via lint's `--apply-suggestions` flag. +As a compromise, soong zips up the (potentially) modified sources and leaves them in an intermediate +directory. This script runs the lint, unpacks those files, and copies them back into the tree. + +## How do I run it? +**WARNING: You probably want to commit/stash any changes to your working tree before doing this...** + +From this directory, run `python lint_fix.py -h`. +The script's help output explains things that are omitted here. + +Alternatively, there is a python binary target you can build to make this +available anywhere in your tree: +``` +m lint_fix +lint_fix -h +``` + +**Gotcha**: You must have run `source build/envsetup.sh` and `lunch` first. + +Example: `lint_fix frameworks/base/services/core/services.core.unboosted UseEnforcePermissionAnnotation --dry-run` +```shell +( +export ANDROID_LINT_CHECK=UseEnforcePermissionAnnotation; +cd $ANDROID_BUILD_TOP; +source build/envsetup.sh; +rm out/soong/.intermediates/frameworks/base/services/core/services.core.unboosted/android_common/lint/lint-report.html; +m out/soong/.intermediates/frameworks/base/services/core/services.core.unboosted/android_common/lint/lint-report.html; +cd out/soong/.intermediates/frameworks/base/services/core/services.core.unboosted/android_common/lint; +unzip suggested-fixes.zip -d suggested-fixes; +cd suggested-fixes; +find . -path ./out -prune -o -name '*.java' -print | xargs -n 1 sh -c 'cp $1 $ANDROID_BUILD_TOP/$1' --; +rm -rf suggested-fixes +) +``` diff --git a/tools/lint/fix/lint_fix.py b/tools/lint/fix/lint_fix.py new file mode 100644 index 000000000000..3ff8131489ff --- /dev/null +++ b/tools/lint/fix/lint_fix.py @@ -0,0 +1,76 @@ +import argparse +import os +import sys + +ANDROID_BUILD_TOP = os.environ.get("ANDROID_BUILD_TOP") +PATH_PREFIX = "out/soong/.intermediates" +PATH_SUFFIX = "android_common/lint" +FIX_DIR = "suggested-fixes" + +parser = argparse.ArgumentParser(description=""" +This is a python script that applies lint fixes to the platform: +1. Set up the environment, etc. +2. Build the lint and run it. +3. Unpack soong's intermediate zip containing source files modified by lint. +4. Copy the modified files back into the tree. + +**Gotcha**: You must have run `source build/envsetup.sh` and `lunch` \ +so that the `ANDROID_BUILD_TOP` environment variable has been set. +Alternatively, set it manually in your shell. +""", formatter_class=argparse.RawTextHelpFormatter) + +parser.add_argument('build_path', metavar='build_path', type=str, + help='The build module to run ' + '(e.g. frameworks/base/framework-minus-apex or ' + 'frameworks/base/services/core/services.core.unboosted)') + +parser.add_argument('--check', metavar='check', type=str, + help='Which lint to run. Passed to the ANDROID_LINT_CHECK environment variable.') + +parser.add_argument('--dry-run', dest='dry_run', action='store_true', + help='Just print the resulting shell script instead of running it.') + +parser.add_argument('--no-fix', dest='no_fix', action='store_true', + help='Just build and run the lint, do NOT apply the fixes.') + +args = parser.parse_args() + +path = f"{PATH_PREFIX}/{args.build_path}/{PATH_SUFFIX}" +target = f"{path}/lint-report.html" + +commands = [] + +if not args.dry_run: + commands += [f"export ANDROID_BUILD_TOP={ANDROID_BUILD_TOP}"] + +if args.check: + commands += [f"export ANDROID_LINT_CHECK={args.check}"] + +commands += [ + "cd $ANDROID_BUILD_TOP", + "source build/envsetup.sh", + f"rm {target}", # remove the file first so soong doesn't think there is no work to do + f"m {target}", +] + +if not args.no_fix: + commands += [ + f"cd {path}", + f"unzip {FIX_DIR}.zip -d {FIX_DIR}", + f"cd {FIX_DIR}", + # Find all the java files in the fix directory, excluding the ./out subdirectory, + # and copy them back into the same path within the tree. + f"find . -path ./out -prune -o -name '*.java' -print | xargs -n 1 sh -c 'cp $1 $ANDROID_BUILD_TOP/$1' --", + f"rm -rf {FIX_DIR}" + ] + +if args.dry_run: + print("(\n" + ";\n".join(commands) + "\n)") + sys.exit(0) + +with_echo = [] +for c in commands: + with_echo.append(f'echo "{c}"') + with_echo.append(c) + +os.system("(\n" + ";\n".join(with_echo) + "\n)") |