Loading cmds/statsd/src/atoms.proto +47 −2 Original line number Diff line number Diff line Loading @@ -393,6 +393,8 @@ message Atom { WifiConnectionResultReported wifi_connection_result_reported = 253 [(module) = "wifi"]; AppFreezeChanged app_freeze_changed = 254 [(module) = "framework"]; SnapshotMergeReported snapshot_merge_reported = 255; ForegroundServiceAppOpSessionEnded foreground_service_app_op_session_ended = 256 [(module) = "framework"]; SdkExtensionStatus sdk_extension_status = 354; } Loading Loading @@ -3285,12 +3287,12 @@ message OverlayStateChanged { ]; } /* /** * Logs foreground service starts and stops. * Note that this is not when a service starts or stops, but when it is * considered foreground. * Logged from * //frameworks/base/services/core/java/com/android/server/am/ActiveServices.java * frameworks/base/services/core/java/com/android/server/am/ActiveServices.java */ message ForegroundServiceStateChanged { optional int32 uid = 1 [(is_uid) = true]; Loading @@ -3302,6 +3304,49 @@ message ForegroundServiceStateChanged { EXIT = 2; } optional State state = 3; // Whether the fgs is allowed while-in-use permissions, i.e. is considered 'in-use' to the user. // (If the fgs was started while the app wasn't TOP it usually will be denied these permissions) optional bool allow_while_in_use_permission = 4; } /** * Logs the number of times a uid accesses a sensitive AppOp during a foreground service session. * A foreground service session is any continuous period during which the uid holds at least one * foreground service; the atom will be pushed when the uid no longer holds any foreground services. * Accesses initiated while the uid is in the TOP state are ignored. * Sessions with no attempted accesses are not logged. * Logged from * frameworks/base/services/core/java/com/android/server/am/ActiveServices.java */ message ForegroundServiceAppOpSessionEnded { optional int32 uid = 1 [(is_uid) = true]; // The operation's name. // To the extent possible, preserve the mapping from AppOpsManager.OP_ constants. // Only these named ops are actually logged. enum AppOpName { OP_NONE = -1; // Also represents UNKNOWN. OP_COARSE_LOCATION = 0; OP_FINE_LOCATION = 1; OP_CAMERA = 26; OP_RECORD_AUDIO = 27; } optional AppOpName app_op_name = 2 [default = OP_NONE]; // The uid's permission mode for accessing the AppOp during this fgs session. enum Mode { MODE_UNKNOWN = 0; MODE_ALLOWED = 1; // Always allowed MODE_IGNORED = 2; // Denied MODE_FOREGROUND = 3; // Allow-while-in-use (or allowed-one-time) } optional Mode app_op_mode = 3; // Number of times this AppOp was requested and allowed. optional int32 count_ops_accepted = 4; // Number of times this AppOp was requested but denied. optional int32 count_ops_rejected = 5; } /** Loading core/java/android/app/AppOpsManager.java +11 −6 Original line number Diff line number Diff line Loading @@ -6910,11 +6910,7 @@ public class AppOpsManager { * Does not throw a security exception, does not translate {@link #MODE_FOREGROUND}. */ public int unsafeCheckOpRaw(@NonNull String op, int uid, @NonNull String packageName) { try { return mService.checkOperationRaw(strOpToOp(op), uid, packageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } return unsafeCheckOpRawNoThrow(op, uid, packageName); } /** Loading @@ -6923,8 +6919,17 @@ public class AppOpsManager { * {@link #MODE_FOREGROUND}. */ public int unsafeCheckOpRawNoThrow(@NonNull String op, int uid, @NonNull String packageName) { return unsafeCheckOpRawNoThrow(strOpToOp(op), uid, packageName); } /** * Returns the <em>raw</em> mode associated with the op. * Does not throw a security exception, does not translate {@link #MODE_FOREGROUND}. * @hide */ public int unsafeCheckOpRawNoThrow(int op, int uid, @NonNull String packageName) { try { return mService.checkOperationRaw(strOpToOp(op), uid, packageName); return mService.checkOperationRaw(op, uid, packageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading services/core/java/com/android/server/am/ActiveServices.java +217 −3 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SERVICE_E import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerInternal; Loading Loading @@ -88,11 +89,13 @@ import android.util.EventLog; import android.util.PrintWriterPrinter; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; import android.webkit.WebViewZygote; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.procstats.ServiceState; import com.android.internal.messages.nano.SystemMessageProto; import com.android.internal.notification.SystemNotificationChannels; Loading Loading @@ -177,6 +180,10 @@ public final class ActiveServices { /** Temporary list for holding the results of calls to {@link #collectPackageServicesLocked} */ private ArrayList<ServiceRecord> mTmpCollectionResults = null; /** Mapping from uid to their foreground service AppOpCallbacks (if they have one). */ @GuardedBy("mAm") private final SparseArray<AppOpCallback> mFgsAppOpCallbacks = new SparseArray<>(); /** * For keeping ActiveForegroundApps retaining state while the screen is off. */ Loading Loading @@ -1455,7 +1462,9 @@ public final class ActiveServices { null, true, false, ""); FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.appInfo.uid, r.shortInstanceName, FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER); FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER, r.mAllowWhileInUsePermissionInFgs); registerAppOpCallbackLocked(r); mAm.updateForegroundServiceUsageStats(r.name, r.userId, true); } r.postNotification(); Loading Loading @@ -1504,9 +1513,11 @@ public final class ActiveServices { mAm.mAppOpsService.finishOperation( AppOpsManager.getToken(mAm.mAppOpsService), AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null); unregisterAppOpCallbackLocked(r); FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.appInfo.uid, r.shortInstanceName, FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT); FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT, r.mAllowWhileInUsePermissionInFgs); mAm.updateForegroundServiceUsageStats(r.name, r.userId, false); if (r.app != null) { mAm.updateLruProcessLocked(r.app, false, null); Loading @@ -1527,6 +1538,207 @@ public final class ActiveServices { } } /** Registers an AppOpCallback for monitoring special AppOps for this foreground service. */ private void registerAppOpCallbackLocked(@NonNull ServiceRecord r) { if (r.app == null) { return; } final int uid = r.appInfo.uid; AppOpCallback callback = mFgsAppOpCallbacks.get(uid); if (callback == null) { callback = new AppOpCallback(r.app, mAm.getAppOpsManager()); mFgsAppOpCallbacks.put(uid, callback); } callback.registerLocked(); } /** Unregisters a foreground service's AppOpCallback. */ private void unregisterAppOpCallbackLocked(@NonNull ServiceRecord r) { final int uid = r.appInfo.uid; final AppOpCallback callback = mFgsAppOpCallbacks.get(uid); if (callback != null) { callback.unregisterLocked(); if (callback.isObsoleteLocked()) { mFgsAppOpCallbacks.remove(uid); } } } /** * For monitoring when {@link #LOGGED_AP_OPS} AppOps occur by an app while it is holding * at least one foreground service and is not also in the TOP state. * Once the uid no longer holds any foreground services, this callback becomes stale * (marked by {@link #isObsoleteLocked()}) and must no longer be used. * * Methods that end in Locked should only be called while the mAm lock is held. */ private static final class AppOpCallback { /** AppOps that should be logged if they occur during a foreground service. */ private static final int[] LOGGED_AP_OPS = new int[] { AppOpsManager.OP_COARSE_LOCATION, AppOpsManager.OP_FINE_LOCATION, AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_CAMERA }; private final ProcessRecord mProcessRecord; /** Count of acceptances per appop (for LOGGED_AP_OPS) during this fgs session. */ @GuardedBy("mCounterLock") private final SparseIntArray mAcceptedOps = new SparseIntArray(); /** Count of rejections per appop (for LOGGED_AP_OPS) during this fgs session. */ @GuardedBy("mCounterLock") private final SparseIntArray mRejectedOps = new SparseIntArray(); /** Lock for the purposes of mAcceptedOps and mRejectedOps. */ private final Object mCounterLock = new Object(); /** * AppOp Mode (e.g. {@link AppOpsManager#MODE_ALLOWED} per op. * This currently cannot change without the process being killed, so they are constants. */ private final SparseIntArray mAppOpModes = new SparseIntArray(); /** * Number of foreground services currently associated with this AppOpCallback (i.e. * currently held for this uid). */ @GuardedBy("mAm") private int mNumFgs = 0; /** * Indicates that this Object is stale and must not be used. * Specifically, when mNumFgs decreases down to 0, the callbacks will be unregistered and * this AppOpCallback is unusable. */ @GuardedBy("mAm") private boolean mDestroyed = false; private final AppOpsManager mAppOpsManager; AppOpCallback(@NonNull ProcessRecord r, @NonNull AppOpsManager appOpsManager) { mProcessRecord = r; mAppOpsManager = appOpsManager; for (int op : LOGGED_AP_OPS) { int mode = appOpsManager.unsafeCheckOpRawNoThrow(op, r.uid, r.info.packageName); mAppOpModes.put(op, mode); } } private final AppOpsManager.OnOpNotedListener mOpNotedCallback = new AppOpsManager.OnOpNotedListener() { @Override public void onOpNoted(int op, int uid, String pkgName, int result) { if (uid == mProcessRecord.uid && isNotTop()) { incrementOpCount(op, result == AppOpsManager.MODE_ALLOWED); } } }; private final AppOpsManager.OnOpActiveChangedInternalListener mOpActiveCallback = new AppOpsManager.OnOpActiveChangedInternalListener() { @Override public void onOpActiveChanged(int op, int uid, String pkgName, boolean active) { if (uid == mProcessRecord.uid && active && isNotTop()) { incrementOpCount(op, true); } } }; private boolean isNotTop() { return mProcessRecord.getCurProcState() != ActivityManager.PROCESS_STATE_TOP; } private void incrementOpCount(int op, boolean allowed) { synchronized (mCounterLock) { final SparseIntArray counter = allowed ? mAcceptedOps : mRejectedOps; final int index = counter.indexOfKey(op); if (index < 0) { counter.put(op, 1); } else { counter.setValueAt(index, counter.valueAt(index) + 1); } } } void registerLocked() { if (isObsoleteLocked()) { Slog.wtf(TAG, "Trying to register on a stale AppOpCallback."); return; } mNumFgs++; if (mNumFgs == 1) { mAppOpsManager.startWatchingNoted(LOGGED_AP_OPS, mOpNotedCallback); mAppOpsManager.startWatchingActive(LOGGED_AP_OPS, mOpActiveCallback); } } void unregisterLocked() { mNumFgs--; if (mNumFgs <= 0) { mDestroyed = true; logFinalValues(); mAppOpsManager.stopWatchingNoted(mOpNotedCallback); mAppOpsManager.stopWatchingActive(mOpActiveCallback); } } /** * Indicates that all foreground services for this uid are now over and the callback is * stale and must never be used again. */ boolean isObsoleteLocked() { return mDestroyed; } private void logFinalValues() { synchronized (mCounterLock) { for (int op : LOGGED_AP_OPS) { final int acceptances = mAcceptedOps.get(op); final int rejections = mRejectedOps.get(op); if (acceptances > 0 || rejections > 0) { FrameworkStatsLog.write( FrameworkStatsLog.FOREGROUND_SERVICE_APP_OP_SESSION_ENDED, mProcessRecord.uid, opToEnum(op), modeToEnum(mAppOpModes.get(op)), acceptances, rejections ); } } } } /** Maps AppOp mode to atoms.proto enum. */ private static int modeToEnum(int mode) { switch (mode) { case AppOpsManager.MODE_ALLOWED: return FrameworkStatsLog .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_MODE__MODE_ALLOWED; case AppOpsManager.MODE_IGNORED: return FrameworkStatsLog .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_MODE__MODE_IGNORED; case AppOpsManager.MODE_FOREGROUND: return FrameworkStatsLog .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_MODE__MODE_FOREGROUND; default: return FrameworkStatsLog .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_MODE__MODE_UNKNOWN; } } } /** Maps AppOp op value to atoms.proto enum. */ private static int opToEnum(int op) { switch (op) { case AppOpsManager.OP_COARSE_LOCATION: return FrameworkStatsLog .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_NAME__OP_COARSE_LOCATION; case AppOpsManager.OP_FINE_LOCATION: return FrameworkStatsLog .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_NAME__OP_FINE_LOCATION; case AppOpsManager.OP_CAMERA: return FrameworkStatsLog .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_NAME__OP_CAMERA; case AppOpsManager.OP_RECORD_AUDIO: return FrameworkStatsLog .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_NAME__OP_RECORD_AUDIO; default: return FrameworkStatsLog .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_NAME__OP_NONE; } } private void cancelForegroundNotificationLocked(ServiceRecord r) { if (r.foregroundId != 0) { // First check to see if this app has any other active foreground services Loading Loading @@ -3136,9 +3348,11 @@ public final class ActiveServices { mAm.mAppOpsService.finishOperation( AppOpsManager.getToken(mAm.mAppOpsService), AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null); unregisterAppOpCallbackLocked(r); FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.appInfo.uid, r.shortInstanceName, FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT); FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT, r.mAllowWhileInUsePermissionInFgs); mAm.updateForegroundServiceUsageStats(r.name, r.userId, false); } Loading Loading
cmds/statsd/src/atoms.proto +47 −2 Original line number Diff line number Diff line Loading @@ -393,6 +393,8 @@ message Atom { WifiConnectionResultReported wifi_connection_result_reported = 253 [(module) = "wifi"]; AppFreezeChanged app_freeze_changed = 254 [(module) = "framework"]; SnapshotMergeReported snapshot_merge_reported = 255; ForegroundServiceAppOpSessionEnded foreground_service_app_op_session_ended = 256 [(module) = "framework"]; SdkExtensionStatus sdk_extension_status = 354; } Loading Loading @@ -3285,12 +3287,12 @@ message OverlayStateChanged { ]; } /* /** * Logs foreground service starts and stops. * Note that this is not when a service starts or stops, but when it is * considered foreground. * Logged from * //frameworks/base/services/core/java/com/android/server/am/ActiveServices.java * frameworks/base/services/core/java/com/android/server/am/ActiveServices.java */ message ForegroundServiceStateChanged { optional int32 uid = 1 [(is_uid) = true]; Loading @@ -3302,6 +3304,49 @@ message ForegroundServiceStateChanged { EXIT = 2; } optional State state = 3; // Whether the fgs is allowed while-in-use permissions, i.e. is considered 'in-use' to the user. // (If the fgs was started while the app wasn't TOP it usually will be denied these permissions) optional bool allow_while_in_use_permission = 4; } /** * Logs the number of times a uid accesses a sensitive AppOp during a foreground service session. * A foreground service session is any continuous period during which the uid holds at least one * foreground service; the atom will be pushed when the uid no longer holds any foreground services. * Accesses initiated while the uid is in the TOP state are ignored. * Sessions with no attempted accesses are not logged. * Logged from * frameworks/base/services/core/java/com/android/server/am/ActiveServices.java */ message ForegroundServiceAppOpSessionEnded { optional int32 uid = 1 [(is_uid) = true]; // The operation's name. // To the extent possible, preserve the mapping from AppOpsManager.OP_ constants. // Only these named ops are actually logged. enum AppOpName { OP_NONE = -1; // Also represents UNKNOWN. OP_COARSE_LOCATION = 0; OP_FINE_LOCATION = 1; OP_CAMERA = 26; OP_RECORD_AUDIO = 27; } optional AppOpName app_op_name = 2 [default = OP_NONE]; // The uid's permission mode for accessing the AppOp during this fgs session. enum Mode { MODE_UNKNOWN = 0; MODE_ALLOWED = 1; // Always allowed MODE_IGNORED = 2; // Denied MODE_FOREGROUND = 3; // Allow-while-in-use (or allowed-one-time) } optional Mode app_op_mode = 3; // Number of times this AppOp was requested and allowed. optional int32 count_ops_accepted = 4; // Number of times this AppOp was requested but denied. optional int32 count_ops_rejected = 5; } /** Loading
core/java/android/app/AppOpsManager.java +11 −6 Original line number Diff line number Diff line Loading @@ -6910,11 +6910,7 @@ public class AppOpsManager { * Does not throw a security exception, does not translate {@link #MODE_FOREGROUND}. */ public int unsafeCheckOpRaw(@NonNull String op, int uid, @NonNull String packageName) { try { return mService.checkOperationRaw(strOpToOp(op), uid, packageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } return unsafeCheckOpRawNoThrow(op, uid, packageName); } /** Loading @@ -6923,8 +6919,17 @@ public class AppOpsManager { * {@link #MODE_FOREGROUND}. */ public int unsafeCheckOpRawNoThrow(@NonNull String op, int uid, @NonNull String packageName) { return unsafeCheckOpRawNoThrow(strOpToOp(op), uid, packageName); } /** * Returns the <em>raw</em> mode associated with the op. * Does not throw a security exception, does not translate {@link #MODE_FOREGROUND}. * @hide */ public int unsafeCheckOpRawNoThrow(int op, int uid, @NonNull String packageName) { try { return mService.checkOperationRaw(strOpToOp(op), uid, packageName); return mService.checkOperationRaw(op, uid, packageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading
services/core/java/com/android/server/am/ActiveServices.java +217 −3 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SERVICE_E import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerInternal; Loading Loading @@ -88,11 +89,13 @@ import android.util.EventLog; import android.util.PrintWriterPrinter; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; import android.webkit.WebViewZygote; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.procstats.ServiceState; import com.android.internal.messages.nano.SystemMessageProto; import com.android.internal.notification.SystemNotificationChannels; Loading Loading @@ -177,6 +180,10 @@ public final class ActiveServices { /** Temporary list for holding the results of calls to {@link #collectPackageServicesLocked} */ private ArrayList<ServiceRecord> mTmpCollectionResults = null; /** Mapping from uid to their foreground service AppOpCallbacks (if they have one). */ @GuardedBy("mAm") private final SparseArray<AppOpCallback> mFgsAppOpCallbacks = new SparseArray<>(); /** * For keeping ActiveForegroundApps retaining state while the screen is off. */ Loading Loading @@ -1455,7 +1462,9 @@ public final class ActiveServices { null, true, false, ""); FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.appInfo.uid, r.shortInstanceName, FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER); FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER, r.mAllowWhileInUsePermissionInFgs); registerAppOpCallbackLocked(r); mAm.updateForegroundServiceUsageStats(r.name, r.userId, true); } r.postNotification(); Loading Loading @@ -1504,9 +1513,11 @@ public final class ActiveServices { mAm.mAppOpsService.finishOperation( AppOpsManager.getToken(mAm.mAppOpsService), AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null); unregisterAppOpCallbackLocked(r); FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.appInfo.uid, r.shortInstanceName, FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT); FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT, r.mAllowWhileInUsePermissionInFgs); mAm.updateForegroundServiceUsageStats(r.name, r.userId, false); if (r.app != null) { mAm.updateLruProcessLocked(r.app, false, null); Loading @@ -1527,6 +1538,207 @@ public final class ActiveServices { } } /** Registers an AppOpCallback for monitoring special AppOps for this foreground service. */ private void registerAppOpCallbackLocked(@NonNull ServiceRecord r) { if (r.app == null) { return; } final int uid = r.appInfo.uid; AppOpCallback callback = mFgsAppOpCallbacks.get(uid); if (callback == null) { callback = new AppOpCallback(r.app, mAm.getAppOpsManager()); mFgsAppOpCallbacks.put(uid, callback); } callback.registerLocked(); } /** Unregisters a foreground service's AppOpCallback. */ private void unregisterAppOpCallbackLocked(@NonNull ServiceRecord r) { final int uid = r.appInfo.uid; final AppOpCallback callback = mFgsAppOpCallbacks.get(uid); if (callback != null) { callback.unregisterLocked(); if (callback.isObsoleteLocked()) { mFgsAppOpCallbacks.remove(uid); } } } /** * For monitoring when {@link #LOGGED_AP_OPS} AppOps occur by an app while it is holding * at least one foreground service and is not also in the TOP state. * Once the uid no longer holds any foreground services, this callback becomes stale * (marked by {@link #isObsoleteLocked()}) and must no longer be used. * * Methods that end in Locked should only be called while the mAm lock is held. */ private static final class AppOpCallback { /** AppOps that should be logged if they occur during a foreground service. */ private static final int[] LOGGED_AP_OPS = new int[] { AppOpsManager.OP_COARSE_LOCATION, AppOpsManager.OP_FINE_LOCATION, AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_CAMERA }; private final ProcessRecord mProcessRecord; /** Count of acceptances per appop (for LOGGED_AP_OPS) during this fgs session. */ @GuardedBy("mCounterLock") private final SparseIntArray mAcceptedOps = new SparseIntArray(); /** Count of rejections per appop (for LOGGED_AP_OPS) during this fgs session. */ @GuardedBy("mCounterLock") private final SparseIntArray mRejectedOps = new SparseIntArray(); /** Lock for the purposes of mAcceptedOps and mRejectedOps. */ private final Object mCounterLock = new Object(); /** * AppOp Mode (e.g. {@link AppOpsManager#MODE_ALLOWED} per op. * This currently cannot change without the process being killed, so they are constants. */ private final SparseIntArray mAppOpModes = new SparseIntArray(); /** * Number of foreground services currently associated with this AppOpCallback (i.e. * currently held for this uid). */ @GuardedBy("mAm") private int mNumFgs = 0; /** * Indicates that this Object is stale and must not be used. * Specifically, when mNumFgs decreases down to 0, the callbacks will be unregistered and * this AppOpCallback is unusable. */ @GuardedBy("mAm") private boolean mDestroyed = false; private final AppOpsManager mAppOpsManager; AppOpCallback(@NonNull ProcessRecord r, @NonNull AppOpsManager appOpsManager) { mProcessRecord = r; mAppOpsManager = appOpsManager; for (int op : LOGGED_AP_OPS) { int mode = appOpsManager.unsafeCheckOpRawNoThrow(op, r.uid, r.info.packageName); mAppOpModes.put(op, mode); } } private final AppOpsManager.OnOpNotedListener mOpNotedCallback = new AppOpsManager.OnOpNotedListener() { @Override public void onOpNoted(int op, int uid, String pkgName, int result) { if (uid == mProcessRecord.uid && isNotTop()) { incrementOpCount(op, result == AppOpsManager.MODE_ALLOWED); } } }; private final AppOpsManager.OnOpActiveChangedInternalListener mOpActiveCallback = new AppOpsManager.OnOpActiveChangedInternalListener() { @Override public void onOpActiveChanged(int op, int uid, String pkgName, boolean active) { if (uid == mProcessRecord.uid && active && isNotTop()) { incrementOpCount(op, true); } } }; private boolean isNotTop() { return mProcessRecord.getCurProcState() != ActivityManager.PROCESS_STATE_TOP; } private void incrementOpCount(int op, boolean allowed) { synchronized (mCounterLock) { final SparseIntArray counter = allowed ? mAcceptedOps : mRejectedOps; final int index = counter.indexOfKey(op); if (index < 0) { counter.put(op, 1); } else { counter.setValueAt(index, counter.valueAt(index) + 1); } } } void registerLocked() { if (isObsoleteLocked()) { Slog.wtf(TAG, "Trying to register on a stale AppOpCallback."); return; } mNumFgs++; if (mNumFgs == 1) { mAppOpsManager.startWatchingNoted(LOGGED_AP_OPS, mOpNotedCallback); mAppOpsManager.startWatchingActive(LOGGED_AP_OPS, mOpActiveCallback); } } void unregisterLocked() { mNumFgs--; if (mNumFgs <= 0) { mDestroyed = true; logFinalValues(); mAppOpsManager.stopWatchingNoted(mOpNotedCallback); mAppOpsManager.stopWatchingActive(mOpActiveCallback); } } /** * Indicates that all foreground services for this uid are now over and the callback is * stale and must never be used again. */ boolean isObsoleteLocked() { return mDestroyed; } private void logFinalValues() { synchronized (mCounterLock) { for (int op : LOGGED_AP_OPS) { final int acceptances = mAcceptedOps.get(op); final int rejections = mRejectedOps.get(op); if (acceptances > 0 || rejections > 0) { FrameworkStatsLog.write( FrameworkStatsLog.FOREGROUND_SERVICE_APP_OP_SESSION_ENDED, mProcessRecord.uid, opToEnum(op), modeToEnum(mAppOpModes.get(op)), acceptances, rejections ); } } } } /** Maps AppOp mode to atoms.proto enum. */ private static int modeToEnum(int mode) { switch (mode) { case AppOpsManager.MODE_ALLOWED: return FrameworkStatsLog .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_MODE__MODE_ALLOWED; case AppOpsManager.MODE_IGNORED: return FrameworkStatsLog .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_MODE__MODE_IGNORED; case AppOpsManager.MODE_FOREGROUND: return FrameworkStatsLog .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_MODE__MODE_FOREGROUND; default: return FrameworkStatsLog .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_MODE__MODE_UNKNOWN; } } } /** Maps AppOp op value to atoms.proto enum. */ private static int opToEnum(int op) { switch (op) { case AppOpsManager.OP_COARSE_LOCATION: return FrameworkStatsLog .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_NAME__OP_COARSE_LOCATION; case AppOpsManager.OP_FINE_LOCATION: return FrameworkStatsLog .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_NAME__OP_FINE_LOCATION; case AppOpsManager.OP_CAMERA: return FrameworkStatsLog .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_NAME__OP_CAMERA; case AppOpsManager.OP_RECORD_AUDIO: return FrameworkStatsLog .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_NAME__OP_RECORD_AUDIO; default: return FrameworkStatsLog .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_NAME__OP_NONE; } } private void cancelForegroundNotificationLocked(ServiceRecord r) { if (r.foregroundId != 0) { // First check to see if this app has any other active foreground services Loading Loading @@ -3136,9 +3348,11 @@ public final class ActiveServices { mAm.mAppOpsService.finishOperation( AppOpsManager.getToken(mAm.mAppOpsService), AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null); unregisterAppOpCallbackLocked(r); FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.appInfo.uid, r.shortInstanceName, FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT); FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT, r.mAllowWhileInUsePermissionInFgs); mAm.updateForegroundServiceUsageStats(r.name, r.userId, false); } Loading