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();
void startOneTimePermissionSession(String packageName, int userId, long timeout,
long revokeAfterKilledDelay, int importanceToResetTimer,
int importanceToKeepSessionAlive);
long revokeAfterKilledDelay);
void stopOneTimePermissionSession(String packageName, int userId);

View File

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

View File

@@ -16,17 +16,18 @@
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.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;
@@ -47,7 +48,7 @@ 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 AlarmManager mAlarmManager;
private final @NonNull PermissionControllerManager mPermissionControllerManager;
@@ -77,49 +78,14 @@ public class OneTimePermissionUserManager {
OneTimePermissionUserManager(@NonNull Context context) {
mContext = context;
mActivityManager = context.getSystemService(ActivityManager.class);
mIActivityManager = ActivityManager.getService();
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 +97,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 +146,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);
}
}
@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, int importanceToResetTimer,
int importanceToKeepSessionAlive) {
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 +207,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);
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();
}
}
mActivityManager.addOnUidImportanceListener(mStartTimerListener,
importanceToResetTimer);
mActivityManager.addOnUidImportanceListener(mSessionKillableListener,
importanceToKeepSessionAlive);
mActivityManager.addOnUidImportanceListener(mGoneListener, IMPORTANCE_CACHED);
onImportanceChanged(mUid, mActivityManager.getPackageImportance(packageName));
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 +233,79 @@ 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() {
try {
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 + ")."
+ " importance=" + importance);
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;
}
}
}
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 +319,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 +385,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);
}

View File

@@ -386,8 +386,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
@Override
public void startOneTimePermissionSession(String packageName, @UserIdInt int userId,
long timeoutMillis, long revokeAfterKilledDelayMillis, int importanceToResetTimer,
int importanceToKeepSessionAlive) {
long timeoutMillis, long revokeAfterKilledDelayMillis) {
mContext.enforceCallingOrSelfPermission(
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();
try {
getOneTimePermissionUserManager(userId).startPackageOneTimeSession(packageName,
timeoutMillis, revokeAfterKilledDelayMillis, importanceToResetTimer,
importanceToKeepSessionAlive);
timeoutMillis, revokeAfterKilledDelayMillis);
} finally {
Binder.restoreCallingIdentity(token);
}