Merge changes I30579090,I7a725647 into tm-dev
* changes: [1-time permissions] Use internal api to check proc states Watch uid proc state instead of importance for 1-time permissions
This commit is contained in:
committed by
Android (Google) Code Review
commit
fb0f85333c
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@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 +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);
|
||||
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 +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));
|
||||
}
|
||||
|
||||
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 +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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user