diff options
Diffstat (limited to 'services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java')
-rw-r--r-- | services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java | 230 |
1 files changed, 111 insertions, 119 deletions
diff --git a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java index 881f8707fdd8..d28048ce74c7 100644 --- a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java +++ b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java @@ -16,23 +16,26 @@ package com.android.server.pm.permission; -import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED; - import android.annotation.NonNull; import android.app.ActivityManager; +import android.app.ActivityManagerInternal; import android.app.AlarmManager; +import android.app.IActivityManager; +import android.app.IUidObserver; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.os.Handler; +import android.os.RemoteException; import android.permission.PermissionControllerManager; import android.provider.DeviceConfig; import android.util.Log; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; +import com.android.server.LocalServices; /** * Class that handles one-time permissions for a user @@ -47,7 +50,8 @@ public class OneTimePermissionUserManager { "one_time_permissions_killed_delay_millis"; private final @NonNull Context mContext; - private final @NonNull ActivityManager mActivityManager; + private final @NonNull IActivityManager mIActivityManager; + private final @NonNull ActivityManagerInternal mActivityManagerInternal; private final @NonNull AlarmManager mAlarmManager; private final @NonNull PermissionControllerManager mPermissionControllerManager; @@ -77,49 +81,15 @@ public class OneTimePermissionUserManager { OneTimePermissionUserManager(@NonNull Context context) { mContext = context; - mActivityManager = context.getSystemService(ActivityManager.class); + mIActivityManager = ActivityManager.getService(); + mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); mAlarmManager = context.getSystemService(AlarmManager.class); mPermissionControllerManager = context.getSystemService(PermissionControllerManager.class); mHandler = context.getMainThreadHandler(); } - /** - * Starts a one-time permission session for a given package. A one-time permission session is - * ended if app becomes inactive. Inactivity is defined as the package's uid importance level - * staying > importanceToResetTimer for timeoutMillis milliseconds. If the package's uid - * importance level goes <= importanceToResetTimer then the timer is reset and doesn't start - * until going > importanceToResetTimer. - * <p> - * When this timeoutMillis is reached if the importance level is <= importanceToKeepSessionAlive - * then the session is extended until either the importance goes above - * importanceToKeepSessionAlive which will end the session or <= importanceToResetTimer which - * will continue the session and reset the timer. - * </p> - * <p> - * Importance levels are defined in {@link android.app.ActivityManager.RunningAppProcessInfo}. - * </p> - * <p> - * Once the session ends PermissionControllerService#onNotifyOneTimePermissionSessionTimeout - * is invoked. - * </p> - * <p> - * Note that if there is currently an active session for a package a new one isn't created and - * the existing one isn't changed. - * </p> - * @param packageName The package to start a one-time permission session for - * @param timeoutMillis Number of milliseconds for an app to be in an inactive state - * @param revokeAfterKilledDelayMillis Number of milliseconds to wait after the process dies - * before ending the session. Set to -1 to use default value - * for the device. - * @param importanceToResetTimer The least important level to uid must be to reset the timer - * @param importanceToKeepSessionAlive The least important level the uid must be to keep the - * session alive - * - * @hide - */ void startPackageOneTimeSession(@NonNull String packageName, long timeoutMillis, - long revokeAfterKilledDelayMillis, int importanceToResetTimer, - int importanceToKeepSessionAlive) { + long revokeAfterKilledDelayMillis) { int uid; try { uid = mContext.getPackageManager().getPackageUid(packageName, 0); @@ -131,13 +101,11 @@ public class OneTimePermissionUserManager { synchronized (mLock) { PackageInactivityListener listener = mListeners.get(uid); if (listener != null) { - listener.updateSessionParameters(timeoutMillis, revokeAfterKilledDelayMillis, - importanceToResetTimer, importanceToKeepSessionAlive); + listener.updateSessionParameters(timeoutMillis, revokeAfterKilledDelayMillis); return; } listener = new PackageInactivityListener(uid, packageName, timeoutMillis, - revokeAfterKilledDelayMillis, importanceToResetTimer, - importanceToKeepSessionAlive); + revokeAfterKilledDelayMillis); mListeners.put(uid, listener); } } @@ -182,34 +150,58 @@ public class OneTimePermissionUserManager { private static final long TIMER_INACTIVE = -1; + private static final int STATE_GONE = 0; + private static final int STATE_TIMER = 1; + private static final int STATE_ACTIVE = 2; + private final int mUid; private final @NonNull String mPackageName; private long mTimeout; private long mRevokeAfterKilledDelay; - private int mImportanceToResetTimer; - private int mImportanceToKeepSessionAlive; private boolean mIsAlarmSet; private boolean mIsFinished; private long mTimerStart = TIMER_INACTIVE; - private final ActivityManager.OnUidImportanceListener mStartTimerListener; - private final ActivityManager.OnUidImportanceListener mSessionKillableListener; - private final ActivityManager.OnUidImportanceListener mGoneListener; - private final Object mInnerLock = new Object(); private final Object mToken = new Object(); + private final IUidObserver.Stub mObserver = new IUidObserver.Stub() { + @Override + public void onUidGone(int uid, boolean disabled) { + if (uid == mUid) { + PackageInactivityListener.this.updateUidState(STATE_GONE); + } + } - private PackageInactivityListener(int uid, @NonNull String packageName, long timeout, - long revokeAfterkilledDelay, int importanceToResetTimer, - int importanceToKeepSessionAlive) { + @Override + public void onUidStateChanged(int uid, int procState, long procStateSeq, + int capability) { + if (uid == mUid) { + if (procState > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE + && procState != ActivityManager.PROCESS_STATE_NONEXISTENT) { + PackageInactivityListener.this.updateUidState(STATE_TIMER); + } else { + PackageInactivityListener.this.updateUidState(STATE_ACTIVE); + } + } + } + + public void onUidActive(int uid) { + } + public void onUidIdle(int uid, boolean disabled) { + } + public void onUidProcAdjChanged(int uid) { + } + public void onUidCachedChanged(int uid, boolean cached) { + } + }; + private PackageInactivityListener(int uid, @NonNull String packageName, long timeout, + long revokeAfterkilledDelay) { Log.i(LOG_TAG, "Start tracking " + packageName + ". uid=" + uid + " timeout=" + timeout - + " killedDelay=" + revokeAfterkilledDelay - + " importanceToResetTimer=" + importanceToResetTimer - + " importanceToKeepSessionAlive=" + importanceToKeepSessionAlive); + + " killedDelay=" + revokeAfterkilledDelay); mUid = uid; mPackageName = packageName; @@ -219,27 +211,24 @@ public class OneTimePermissionUserManager { DeviceConfig.NAMESPACE_PERMISSIONS, PROPERTY_KILLED_DELAY_CONFIG_KEY, DEFAULT_KILLED_DELAY_MILLIS) : revokeAfterkilledDelay; - mImportanceToResetTimer = importanceToResetTimer; - mImportanceToKeepSessionAlive = importanceToKeepSessionAlive; - - mStartTimerListener = - (changingUid, importance) -> onImportanceChanged(changingUid, importance); - mSessionKillableListener = - (changingUid, importance) -> onImportanceChanged(changingUid, importance); - mGoneListener = - (changingUid, importance) -> onImportanceChanged(changingUid, importance); - - mActivityManager.addOnUidImportanceListener(mStartTimerListener, - importanceToResetTimer); - mActivityManager.addOnUidImportanceListener(mSessionKillableListener, - importanceToKeepSessionAlive); - mActivityManager.addOnUidImportanceListener(mGoneListener, IMPORTANCE_CACHED); - - onImportanceChanged(mUid, mActivityManager.getPackageImportance(packageName)); + + try { + mIActivityManager.registerUidObserver(mObserver, + ActivityManager.UID_OBSERVER_GONE | ActivityManager.UID_OBSERVER_PROCSTATE, + ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, + null); + } catch (RemoteException e) { + Log.e(LOG_TAG, "Couldn't check uid proc state", e); + // Can't register uid observer, just revoke immediately + synchronized (mInnerLock) { + onPackageInactiveLocked(); + } + } + + updateUidState(); } - public void updateSessionParameters(long timeoutMillis, long revokeAfterKilledDelayMillis, - int importanceToResetTimer, int importanceToKeepSessionAlive) { + public void updateSessionParameters(long timeoutMillis, long revokeAfterKilledDelayMillis) { synchronized (mInnerLock) { mTimeout = Math.min(mTimeout, timeoutMillis); mRevokeAfterKilledDelay = Math.min(mRevokeAfterKilledDelay, @@ -248,63 +237,74 @@ public class OneTimePermissionUserManager { DeviceConfig.NAMESPACE_PERMISSIONS, PROPERTY_KILLED_DELAY_CONFIG_KEY, DEFAULT_KILLED_DELAY_MILLIS) : revokeAfterKilledDelayMillis); - mImportanceToResetTimer = Math.min(importanceToResetTimer, mImportanceToResetTimer); - mImportanceToKeepSessionAlive = Math.min(importanceToKeepSessionAlive, - mImportanceToKeepSessionAlive); Log.v(LOG_TAG, "Updated params for " + mPackageName + ". timeout=" + mTimeout - + " killedDelay=" + mRevokeAfterKilledDelay - + " importanceToResetTimer=" + mImportanceToResetTimer - + " importanceToKeepSessionAlive=" + mImportanceToKeepSessionAlive); - onImportanceChanged(mUid, mActivityManager.getPackageImportance(mPackageName)); + + " killedDelay=" + mRevokeAfterKilledDelay); + updateUidState(); } } - private void onImportanceChanged(int uid, int importance) { - if (uid != mUid) { - return; + private int getCurrentState() { + return getStateFromProcState(mActivityManagerInternal.getUidProcessState(mUid)); + } + + private int getStateFromProcState(int procState) { + if (procState == ActivityManager.PROCESS_STATE_NONEXISTENT) { + return STATE_GONE; + } else { + if (procState > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) { + return STATE_TIMER; + } else { + return STATE_ACTIVE; + } } + } - Log.v(LOG_TAG, "Importance changed for " + mPackageName + " (" + mUid + ")." - + " importance=" + importance); + private void updateUidState() { + updateUidState(getCurrentState()); + } + + private void updateUidState(int state) { + Log.v(LOG_TAG, "Updating state for " + mPackageName + " (" + mUid + ")." + + " state=" + state); synchronized (mInnerLock) { // Remove any pending inactivity callback mHandler.removeCallbacksAndMessages(mToken); - if (importance > IMPORTANCE_CACHED) { + if (state == STATE_GONE) { if (mRevokeAfterKilledDelay == 0) { onPackageInactiveLocked(); return; } // Delay revocation in case app is restarting mHandler.postDelayed(() -> { - int imp = mActivityManager.getUidImportance(mUid); - if (imp > IMPORTANCE_CACHED) { - onPackageInactiveLocked(); - } else { - if (DEBUG) { - Log.d(LOG_TAG, "No longer gone after delayed revocation. " - + "Rechecking for " + mPackageName + " (" + mUid + ")."); + int currentState; + synchronized (mInnerLock) { + currentState = getCurrentState(); + if (currentState == STATE_GONE) { + onPackageInactiveLocked(); + return; } - onImportanceChanged(mUid, imp); } + if (DEBUG) { + Log.d(LOG_TAG, "No longer gone after delayed revocation. " + + "Rechecking for " + mPackageName + " (" + mUid + + ")."); + } + updateUidState(currentState); }, mToken, mRevokeAfterKilledDelay); return; - } - if (importance > mImportanceToResetTimer) { + } else if (state == STATE_TIMER) { if (mTimerStart == TIMER_INACTIVE) { if (DEBUG) { Log.d(LOG_TAG, "Start the timer for " + mPackageName + " (" + mUid + ")."); } mTimerStart = System.currentTimeMillis(); + setAlarmLocked(); } - } else { + } else if (state == STATE_ACTIVE) { mTimerStart = TIMER_INACTIVE; - } - if (importance > mImportanceToKeepSessionAlive) { - setAlarmLocked(); - } else { cancelAlarmLocked(); } } @@ -318,19 +318,9 @@ public class OneTimePermissionUserManager { mIsFinished = true; cancelAlarmLocked(); try { - mActivityManager.removeOnUidImportanceListener(mStartTimerListener); - } catch (IllegalArgumentException e) { - Log.e(LOG_TAG, "Could not remove start timer listener", e); - } - try { - mActivityManager.removeOnUidImportanceListener(mSessionKillableListener); - } catch (IllegalArgumentException e) { - Log.e(LOG_TAG, "Could not remove session killable listener", e); - } - try { - mActivityManager.removeOnUidImportanceListener(mGoneListener); - } catch (IllegalArgumentException e) { - Log.e(LOG_TAG, "Could not remove gone listener", e); + mIActivityManager.unregisterUidObserver(mObserver); + } catch (RemoteException e) { + Log.e(LOG_TAG, "Unable to unregister uid observer.", e); } } } @@ -394,9 +384,11 @@ public class OneTimePermissionUserManager { mPermissionControllerManager.notifyOneTimePermissionSessionTimeout( mPackageName); }); - mActivityManager.removeOnUidImportanceListener(mStartTimerListener); - mActivityManager.removeOnUidImportanceListener(mSessionKillableListener); - mActivityManager.removeOnUidImportanceListener(mGoneListener); + try { + mIActivityManager.unregisterUidObserver(mObserver); + } catch (RemoteException e) { + Log.e(LOG_TAG, "Unable to unregister uid observer.", e); + } synchronized (mLock) { mListeners.remove(mUid); } |