Watch uid proc state instead of importance for 1-time permissions am: 0be78fbbf7 am: 1f8e607935

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17738545

Change-Id: I142a525e07c7c0dd9fafdef45e2af4ebaeaf9806
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Evan Severson
2023-05-04 06:59:44 +00:00
committed by Automerger Merge Worker
4 changed files with 114 additions and 125 deletions

View File

@@ -77,8 +77,7 @@ interface IPermissionManager {
List<SplitPermissionInfoParcelable> getSplitPermissions(); List<SplitPermissionInfoParcelable> getSplitPermissions();
void startOneTimePermissionSession(String packageName, int userId, long timeout, void startOneTimePermissionSession(String packageName, int userId, long timeout,
long revokeAfterKilledDelay, int importanceToResetTimer, long revokeAfterKilledDelay);
int importanceToKeepSessionAlive);
void stopOneTimePermissionSession(String packageName, int userId); void stopOneTimePermissionSession(String packageName, int userId);

View File

@@ -1371,8 +1371,7 @@ public final class PermissionManager {
@ActivityManager.RunningAppProcessInfo.Importance int importanceToKeepSessionAlive) { @ActivityManager.RunningAppProcessInfo.Importance int importanceToKeepSessionAlive) {
try { try {
mPermissionManager.startOneTimePermissionSession(packageName, mContext.getUserId(), mPermissionManager.startOneTimePermissionSession(packageName, mContext.getUserId(),
timeoutMillis, revokeAfterKilledDelayMillis, importanceToResetTimer, timeoutMillis, revokeAfterKilledDelayMillis);
importanceToKeepSessionAlive);
} catch (RemoteException e) { } catch (RemoteException e) {
e.rethrowFromSystemServer(); e.rethrowFromSystemServer();
} }

View File

@@ -16,17 +16,18 @@
package com.android.server.pm.permission; package com.android.server.pm.permission;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.app.AlarmManager; import android.app.AlarmManager;
import android.app.IActivityManager;
import android.app.IUidObserver;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.Handler; import android.os.Handler;
import android.os.RemoteException;
import android.permission.PermissionControllerManager; import android.permission.PermissionControllerManager;
import android.provider.DeviceConfig; import android.provider.DeviceConfig;
import android.util.Log; import android.util.Log;
@@ -47,7 +48,7 @@ public class OneTimePermissionUserManager {
"one_time_permissions_killed_delay_millis"; "one_time_permissions_killed_delay_millis";
private final @NonNull Context mContext; private final @NonNull Context mContext;
private final @NonNull ActivityManager mActivityManager; private final @NonNull IActivityManager mIActivityManager;
private final @NonNull AlarmManager mAlarmManager; private final @NonNull AlarmManager mAlarmManager;
private final @NonNull PermissionControllerManager mPermissionControllerManager; private final @NonNull PermissionControllerManager mPermissionControllerManager;
@@ -77,49 +78,14 @@ public class OneTimePermissionUserManager {
OneTimePermissionUserManager(@NonNull Context context) { OneTimePermissionUserManager(@NonNull Context context) {
mContext = context; mContext = context;
mActivityManager = context.getSystemService(ActivityManager.class); mIActivityManager = ActivityManager.getService();
mAlarmManager = context.getSystemService(AlarmManager.class); mAlarmManager = context.getSystemService(AlarmManager.class);
mPermissionControllerManager = context.getSystemService(PermissionControllerManager.class); mPermissionControllerManager = context.getSystemService(PermissionControllerManager.class);
mHandler = context.getMainThreadHandler(); 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, void startPackageOneTimeSession(@NonNull String packageName, long timeoutMillis,
long revokeAfterKilledDelayMillis, int importanceToResetTimer, long revokeAfterKilledDelayMillis) {
int importanceToKeepSessionAlive) {
int uid; int uid;
try { try {
uid = mContext.getPackageManager().getPackageUid(packageName, 0); uid = mContext.getPackageManager().getPackageUid(packageName, 0);
@@ -131,13 +97,11 @@ public class OneTimePermissionUserManager {
synchronized (mLock) { synchronized (mLock) {
PackageInactivityListener listener = mListeners.get(uid); PackageInactivityListener listener = mListeners.get(uid);
if (listener != null) { if (listener != null) {
listener.updateSessionParameters(timeoutMillis, revokeAfterKilledDelayMillis, listener.updateSessionParameters(timeoutMillis, revokeAfterKilledDelayMillis);
importanceToResetTimer, importanceToKeepSessionAlive);
return; return;
} }
listener = new PackageInactivityListener(uid, packageName, timeoutMillis, listener = new PackageInactivityListener(uid, packageName, timeoutMillis,
revokeAfterKilledDelayMillis, importanceToResetTimer, revokeAfterKilledDelayMillis);
importanceToKeepSessionAlive);
mListeners.put(uid, listener); mListeners.put(uid, listener);
} }
} }
@@ -182,34 +146,58 @@ public class OneTimePermissionUserManager {
private static final long TIMER_INACTIVE = -1; 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 int mUid;
private final @NonNull String mPackageName; private final @NonNull String mPackageName;
private long mTimeout; private long mTimeout;
private long mRevokeAfterKilledDelay; private long mRevokeAfterKilledDelay;
private int mImportanceToResetTimer;
private int mImportanceToKeepSessionAlive;
private boolean mIsAlarmSet; private boolean mIsAlarmSet;
private boolean mIsFinished; private boolean mIsFinished;
private long mTimerStart = TIMER_INACTIVE; 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 mInnerLock = new Object();
private final Object mToken = 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);
}
}
@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, private PackageInactivityListener(int uid, @NonNull String packageName, long timeout,
long revokeAfterkilledDelay, int importanceToResetTimer, long revokeAfterkilledDelay) {
int importanceToKeepSessionAlive) {
Log.i(LOG_TAG, Log.i(LOG_TAG,
"Start tracking " + packageName + ". uid=" + uid + " timeout=" + timeout "Start tracking " + packageName + ". uid=" + uid + " timeout=" + timeout
+ " killedDelay=" + revokeAfterkilledDelay + " killedDelay=" + revokeAfterkilledDelay);
+ " importanceToResetTimer=" + importanceToResetTimer
+ " importanceToKeepSessionAlive=" + importanceToKeepSessionAlive);
mUid = uid; mUid = uid;
mPackageName = packageName; mPackageName = packageName;
@@ -219,27 +207,24 @@ public class OneTimePermissionUserManager {
DeviceConfig.NAMESPACE_PERMISSIONS, PROPERTY_KILLED_DELAY_CONFIG_KEY, DeviceConfig.NAMESPACE_PERMISSIONS, PROPERTY_KILLED_DELAY_CONFIG_KEY,
DEFAULT_KILLED_DELAY_MILLIS) DEFAULT_KILLED_DELAY_MILLIS)
: revokeAfterkilledDelay; : revokeAfterkilledDelay;
mImportanceToResetTimer = importanceToResetTimer;
mImportanceToKeepSessionAlive = importanceToKeepSessionAlive;
mStartTimerListener = try {
(changingUid, importance) -> onImportanceChanged(changingUid, importance); mIActivityManager.registerUidObserver(mObserver,
mSessionKillableListener = ActivityManager.UID_OBSERVER_GONE | ActivityManager.UID_OBSERVER_PROCSTATE,
(changingUid, importance) -> onImportanceChanged(changingUid, importance); ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
mGoneListener = null);
(changingUid, importance) -> onImportanceChanged(changingUid, importance); } 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();
}
}
mActivityManager.addOnUidImportanceListener(mStartTimerListener, updateUidState();
importanceToResetTimer);
mActivityManager.addOnUidImportanceListener(mSessionKillableListener,
importanceToKeepSessionAlive);
mActivityManager.addOnUidImportanceListener(mGoneListener, IMPORTANCE_CACHED);
onImportanceChanged(mUid, mActivityManager.getPackageImportance(packageName));
} }
public void updateSessionParameters(long timeoutMillis, long revokeAfterKilledDelayMillis, public void updateSessionParameters(long timeoutMillis, long revokeAfterKilledDelayMillis) {
int importanceToResetTimer, int importanceToKeepSessionAlive) {
synchronized (mInnerLock) { synchronized (mInnerLock) {
mTimeout = Math.min(mTimeout, timeoutMillis); mTimeout = Math.min(mTimeout, timeoutMillis);
mRevokeAfterKilledDelay = Math.min(mRevokeAfterKilledDelay, mRevokeAfterKilledDelay = Math.min(mRevokeAfterKilledDelay,
@@ -248,63 +233,79 @@ public class OneTimePermissionUserManager {
DeviceConfig.NAMESPACE_PERMISSIONS, DeviceConfig.NAMESPACE_PERMISSIONS,
PROPERTY_KILLED_DELAY_CONFIG_KEY, DEFAULT_KILLED_DELAY_MILLIS) PROPERTY_KILLED_DELAY_CONFIG_KEY, DEFAULT_KILLED_DELAY_MILLIS)
: revokeAfterKilledDelayMillis); : revokeAfterKilledDelayMillis);
mImportanceToResetTimer = Math.min(importanceToResetTimer, mImportanceToResetTimer);
mImportanceToKeepSessionAlive = Math.min(importanceToKeepSessionAlive,
mImportanceToKeepSessionAlive);
Log.v(LOG_TAG, Log.v(LOG_TAG,
"Updated params for " + mPackageName + ". timeout=" + mTimeout "Updated params for " + mPackageName + ". timeout=" + mTimeout
+ " killedDelay=" + mRevokeAfterKilledDelay + " killedDelay=" + mRevokeAfterKilledDelay);
+ " importanceToResetTimer=" + mImportanceToResetTimer updateUidState();
+ " importanceToKeepSessionAlive=" + mImportanceToKeepSessionAlive);
onImportanceChanged(mUid, mActivityManager.getPackageImportance(mPackageName));
} }
} }
private void onImportanceChanged(int uid, int importance) { private int getCurrentState() {
if (uid != mUid) { try {
return; return getStateFromProcState(mIActivityManager.getUidProcessState(mUid, null));
} catch (RemoteException e) {
Log.e(LOG_TAG, "Couldn't check uid proc state", e);
} }
return STATE_GONE;
}
Log.v(LOG_TAG, "Importance changed for " + mPackageName + " (" + mUid + ")." private int getStateFromProcState(int procState) {
+ " importance=" + importance); if (procState == ActivityManager.PROCESS_STATE_NONEXISTENT) {
return STATE_GONE;
} else {
if (procState > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
return STATE_TIMER;
} else {
return STATE_ACTIVE;
}
}
}
private void updateUidState() {
updateUidState(getCurrentState());
}
private void updateUidState(int state) {
Log.v(LOG_TAG, "Updating state for " + mPackageName + " (" + mUid + ")."
+ " state=" + state);
synchronized (mInnerLock) { synchronized (mInnerLock) {
// Remove any pending inactivity callback // Remove any pending inactivity callback
mHandler.removeCallbacksAndMessages(mToken); mHandler.removeCallbacksAndMessages(mToken);
if (importance > IMPORTANCE_CACHED) { if (state == STATE_GONE) {
if (mRevokeAfterKilledDelay == 0) { if (mRevokeAfterKilledDelay == 0) {
onPackageInactiveLocked(); onPackageInactiveLocked();
return; return;
} }
// Delay revocation in case app is restarting // Delay revocation in case app is restarting
mHandler.postDelayed(() -> { mHandler.postDelayed(() -> {
int imp = mActivityManager.getUidImportance(mUid); int currentState;
if (imp > IMPORTANCE_CACHED) { synchronized (mInnerLock) {
onPackageInactiveLocked(); currentState = getCurrentState();
} else { if (currentState == STATE_GONE) {
if (DEBUG) { onPackageInactiveLocked();
Log.d(LOG_TAG, "No longer gone after delayed revocation. " return;
+ "Rechecking for " + mPackageName + " (" + mUid + ").");
} }
onImportanceChanged(mUid, imp);
} }
if (DEBUG) {
Log.d(LOG_TAG, "No longer gone after delayed revocation. "
+ "Rechecking for " + mPackageName + " (" + mUid
+ ").");
}
updateUidState(currentState);
}, mToken, mRevokeAfterKilledDelay); }, mToken, mRevokeAfterKilledDelay);
return; return;
} } else if (state == STATE_TIMER) {
if (importance > mImportanceToResetTimer) {
if (mTimerStart == TIMER_INACTIVE) { if (mTimerStart == TIMER_INACTIVE) {
if (DEBUG) { if (DEBUG) {
Log.d(LOG_TAG, "Start the timer for " Log.d(LOG_TAG, "Start the timer for "
+ mPackageName + " (" + mUid + ")."); + mPackageName + " (" + mUid + ").");
} }
mTimerStart = System.currentTimeMillis(); mTimerStart = System.currentTimeMillis();
setAlarmLocked();
} }
} else { } else if (state == STATE_ACTIVE) {
mTimerStart = TIMER_INACTIVE; mTimerStart = TIMER_INACTIVE;
}
if (importance > mImportanceToKeepSessionAlive) {
setAlarmLocked();
} else {
cancelAlarmLocked(); cancelAlarmLocked();
} }
} }
@@ -318,19 +319,9 @@ public class OneTimePermissionUserManager {
mIsFinished = true; mIsFinished = true;
cancelAlarmLocked(); cancelAlarmLocked();
try { try {
mActivityManager.removeOnUidImportanceListener(mStartTimerListener); mIActivityManager.unregisterUidObserver(mObserver);
} catch (IllegalArgumentException e) { } catch (RemoteException e) {
Log.e(LOG_TAG, "Could not remove start timer listener", e); Log.e(LOG_TAG, "Unable to unregister uid observer.", 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);
} }
} }
} }
@@ -394,9 +385,11 @@ public class OneTimePermissionUserManager {
mPermissionControllerManager.notifyOneTimePermissionSessionTimeout( mPermissionControllerManager.notifyOneTimePermissionSessionTimeout(
mPackageName); mPackageName);
}); });
mActivityManager.removeOnUidImportanceListener(mStartTimerListener); try {
mActivityManager.removeOnUidImportanceListener(mSessionKillableListener); mIActivityManager.unregisterUidObserver(mObserver);
mActivityManager.removeOnUidImportanceListener(mGoneListener); } catch (RemoteException e) {
Log.e(LOG_TAG, "Unable to unregister uid observer.", e);
}
synchronized (mLock) { synchronized (mLock) {
mListeners.remove(mUid); mListeners.remove(mUid);
} }

View File

@@ -386,8 +386,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
@Override @Override
public void startOneTimePermissionSession(String packageName, @UserIdInt int userId, public void startOneTimePermissionSession(String packageName, @UserIdInt int userId,
long timeoutMillis, long revokeAfterKilledDelayMillis, int importanceToResetTimer, long timeoutMillis, long revokeAfterKilledDelayMillis) {
int importanceToKeepSessionAlive) {
mContext.enforceCallingOrSelfPermission( mContext.enforceCallingOrSelfPermission(
Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS, Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS,
"Must hold " + Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS "Must hold " + Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS
@@ -397,8 +396,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final long token = Binder.clearCallingIdentity(); final long token = Binder.clearCallingIdentity();
try { try {
getOneTimePermissionUserManager(userId).startPackageOneTimeSession(packageName, getOneTimePermissionUserManager(userId).startPackageOneTimeSession(packageName,
timeoutMillis, revokeAfterKilledDelayMillis, importanceToResetTimer, timeoutMillis, revokeAfterKilledDelayMillis);
importanceToKeepSessionAlive);
} finally { } finally {
Binder.restoreCallingIdentity(token); Binder.restoreCallingIdentity(token);
} }