Merge "Allow UiAutomation to adopt the shell permission indentity"
This commit is contained in:
@@ -6117,8 +6117,10 @@ package android.app {
|
||||
}
|
||||
|
||||
public final class UiAutomation {
|
||||
method public void adoptShellPermissionIdentity();
|
||||
method public void clearWindowAnimationFrameStats();
|
||||
method public boolean clearWindowContentFrameStats(int);
|
||||
method public void dropShellPermissionIdentity();
|
||||
method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException;
|
||||
method public android.os.ParcelFileDescriptor executeShellCommand(String);
|
||||
method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
|
||||
|
||||
@@ -263,7 +263,9 @@ package android.content.pm {
|
||||
method public abstract String getPermissionControllerPackageName();
|
||||
method @NonNull public abstract String getServicesSystemSharedLibraryPackageName();
|
||||
method @NonNull public abstract String getSharedSystemSharedLibraryPackageName();
|
||||
method @RequiresPermission("android.permission.GRANT_RUNTIME_PERMISSIONS") public abstract void grantRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
|
||||
method public abstract boolean isPermissionReviewModeEnabled();
|
||||
method @RequiresPermission("android.permission.REVOKE_RUNTIME_PERMISSIONS") public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
|
||||
field public static final String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage";
|
||||
field public static final String FEATURE_FILE_BASED_ENCRYPTION = "android.software.file_based_encryption";
|
||||
field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000
|
||||
|
||||
@@ -2513,7 +2513,7 @@ public class AppOpsManager {
|
||||
*/
|
||||
public int noteProxyOpNoThrow(int op, String proxiedPackageName) {
|
||||
try {
|
||||
return mService.noteProxyOperation(op, mContext.getOpPackageName(),
|
||||
return mService.noteProxyOperation(op, Process.myUid(), mContext.getOpPackageName(),
|
||||
Binder.getCallingUid(), proxiedPackageName);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
|
||||
@@ -18,12 +18,55 @@ package android.app;
|
||||
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import com.android.internal.util.function.QuadFunction;
|
||||
import com.android.internal.util.function.TriFunction;
|
||||
|
||||
/**
|
||||
* App ops service local interface.
|
||||
*
|
||||
* @hide Only for use within the system server.
|
||||
*/
|
||||
public abstract class AppOpsManagerInternal {
|
||||
/** Interface to override app ops checks via composition */
|
||||
public interface CheckOpsDelegate {
|
||||
/**
|
||||
* Allows overriding check operation behavior.
|
||||
*
|
||||
* @param code The op code to check.
|
||||
* @param uid The UID for which to check.
|
||||
* @param packageName The package for which to check.
|
||||
* @param superImpl The super implementation.
|
||||
* @return The app op check result.
|
||||
*/
|
||||
int checkOperation(int code, int uid, String packageName,
|
||||
TriFunction<Integer, Integer, String, Integer> superImpl);
|
||||
|
||||
/**
|
||||
* Allows overriding check audio operation behavior.
|
||||
*
|
||||
* @param code The op code to check.
|
||||
* @param usage The audio op usage.
|
||||
* @param uid The UID for which to check.
|
||||
* @param packageName The package for which to check.
|
||||
* @param superImpl The super implementation.
|
||||
* @return The app op check result.
|
||||
*/
|
||||
int checkAudioOperation(int code, int usage, int uid, String packageName,
|
||||
QuadFunction<Integer, Integer, Integer, String, Integer> superImpl);
|
||||
|
||||
/**
|
||||
* Allows overriding note operation behavior.
|
||||
*
|
||||
* @param code The op code to note.
|
||||
* @param uid The UID for which to note.
|
||||
* @param packageName The package for which to note.
|
||||
* @param superImpl The super implementation.
|
||||
* @return The app op note result.
|
||||
*/
|
||||
int noteOperation(int code, int uid, String packageName,
|
||||
TriFunction<Integer, Integer, String, Integer> superImpl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the currently configured device and profile owners. Specifies the package uid (value)
|
||||
* that has been configured for each user (key) that has one. These will be allowed privileged
|
||||
|
||||
@@ -714,4 +714,19 @@ interface IActivityManager {
|
||||
|
||||
/** @see android.app.ActivityManager#alwaysShowUnsupportedCompileSdkWarning */
|
||||
void alwaysShowUnsupportedCompileSdkWarning(in ComponentName activity);
|
||||
|
||||
/**
|
||||
* Method for the shell UID to start deletating its permission identity to an
|
||||
* active instrumenation. The shell can delegate permissions only to one active
|
||||
* instrumentation at a time. An active instrumentation is one running and
|
||||
* started from the shell.
|
||||
*/
|
||||
void startDelegateShellPermissionIdentity(int uid);
|
||||
|
||||
/**
|
||||
* Method for the shell UID to stop deletating its permission identity to an
|
||||
* active instrumenation. An active instrumentation is one running and
|
||||
* started from the shell.
|
||||
*/
|
||||
void stopDelegateShellPermissionIdentity();
|
||||
}
|
||||
|
||||
@@ -47,7 +47,8 @@ interface IUiAutomationConnection {
|
||||
in ParcelFileDescriptor source);
|
||||
void grantRuntimePermission(String packageName, String permission, int userId);
|
||||
void revokeRuntimePermission(String packageName, String permission, int userId);
|
||||
|
||||
void adoptShellPermissionIdentity(int uid);
|
||||
void dropShellPermissionIdentity();
|
||||
// Called from the system process.
|
||||
oneway void shutdown();
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import android.os.HandlerThread;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
@@ -52,6 +53,7 @@ import android.view.accessibility.AccessibilityWindowInfo;
|
||||
import android.view.accessibility.IAccessibilityInteractionConnection;
|
||||
|
||||
import com.android.internal.util.function.pooled.PooledLambda;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -351,6 +353,46 @@ public final class UiAutomation {
|
||||
mIsDestroyed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adopt the permission identity of the shell UID. This allows you to call APIs protected
|
||||
* permissions which normal apps cannot hold but are granted to the shell UID. If you
|
||||
* already adopted the shell permission identity this method would be a no-op.
|
||||
* Note that your permission state becomes that of the shell UID and it is not a
|
||||
* combination of your and the shell UID permissions.
|
||||
*
|
||||
* @see #dropShellPermissionIdentity()
|
||||
*/
|
||||
public void adoptShellPermissionIdentity() {
|
||||
synchronized (mLock) {
|
||||
throwIfNotConnectedLocked();
|
||||
}
|
||||
try {
|
||||
// Calling out without a lock held.
|
||||
mUiAutomationConnection.adoptShellPermissionIdentity(Process.myUid());
|
||||
} catch (RemoteException re) {
|
||||
Log.e(LOG_TAG, "Error executing adopting shell permission identity!", re);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop the shell permission identity adopted by a previous call to
|
||||
* {@link #adoptShellPermissionIdentity()}. If you did not adopt the shell permission
|
||||
* identity this method would be a no-op.
|
||||
*
|
||||
* @see #adoptShellPermissionIdentity()
|
||||
*/
|
||||
public void dropShellPermissionIdentity() {
|
||||
synchronized (mLock) {
|
||||
throwIfNotConnectedLocked();
|
||||
}
|
||||
try {
|
||||
// Calling out without a lock held.
|
||||
mUiAutomationConnection.dropShellPermissionIdentity();
|
||||
} catch (RemoteException re) {
|
||||
Log.e(LOG_TAG, "Error executing dropping shell permission identity!", re);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a global action. Such an action can be performed at any moment
|
||||
* regardless of the current application or user location in that application.
|
||||
@@ -1004,6 +1046,8 @@ public final class UiAutomation {
|
||||
*
|
||||
* @param command The command to execute.
|
||||
* @return A file descriptor to the standard output stream.
|
||||
*
|
||||
* @see #adoptShellPermissionIdentity()
|
||||
*/
|
||||
public ParcelFileDescriptor executeShellCommand(String command) {
|
||||
synchronized (mLock) {
|
||||
@@ -1086,22 +1130,6 @@ public final class UiAutomation {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static float getDegreesForRotation(int value) {
|
||||
switch (value) {
|
||||
case Surface.ROTATION_90: {
|
||||
return 360f - 90f;
|
||||
}
|
||||
case Surface.ROTATION_180: {
|
||||
return 360f - 180f;
|
||||
}
|
||||
case Surface.ROTATION_270: {
|
||||
return 360f - 270f;
|
||||
} default: {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isConnectedLocked() {
|
||||
return mConnectionId != CONNECTION_ID_UNDEFINED;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
import android.view.IWindowManager;
|
||||
import android.view.InputEvent;
|
||||
import android.view.SurfaceControl;
|
||||
@@ -38,7 +39,6 @@ import android.view.WindowAnimationFrameStats;
|
||||
import android.view.WindowContentFrameStats;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.IAccessibilityManager;
|
||||
import android.util.Log;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
@@ -72,6 +72,9 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub {
|
||||
private final IPackageManager mPackageManager = IPackageManager.Stub
|
||||
.asInterface(ServiceManager.getService("package"));
|
||||
|
||||
private final IActivityManager mActivityManager = IActivityManager.Stub
|
||||
.asInterface(ServiceManager.getService("activity"));
|
||||
|
||||
private final Object mLock = new Object();
|
||||
|
||||
private final Binder mToken = new Binder();
|
||||
@@ -275,6 +278,36 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adoptShellPermissionIdentity(int uid) throws RemoteException {
|
||||
synchronized (mLock) {
|
||||
throwIfCalledByNotTrustedUidLocked();
|
||||
throwIfShutdownLocked();
|
||||
throwIfNotConnectedLocked();
|
||||
}
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mActivityManager.startDelegateShellPermissionIdentity(uid);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dropShellPermissionIdentity() throws RemoteException {
|
||||
synchronized (mLock) {
|
||||
throwIfCalledByNotTrustedUidLocked();
|
||||
throwIfShutdownLocked();
|
||||
throwIfNotConnectedLocked();
|
||||
}
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mActivityManager.stopDelegateShellPermissionIdentity();
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
public class Repeater implements Runnable {
|
||||
// Continuously read readFrom and write back to writeTo until EOF is encountered
|
||||
private final InputStream readFrom;
|
||||
|
||||
@@ -3623,6 +3623,7 @@ public abstract class PackageManager {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@TestApi
|
||||
@SystemApi
|
||||
@RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS)
|
||||
public abstract void grantRuntimePermission(@NonNull String packageName,
|
||||
@@ -3649,6 +3650,7 @@ public abstract class PackageManager {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@TestApi
|
||||
@SystemApi
|
||||
@RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS)
|
||||
public abstract void revokeRuntimePermission(@NonNull String packageName,
|
||||
|
||||
@@ -29,9 +29,12 @@ import android.os.Bundle;
|
||||
import android.os.PersistableBundle;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.internal.util.function.TriFunction;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
/**
|
||||
* Package manager local system service interface.
|
||||
@@ -64,6 +67,32 @@ public abstract class PackageManagerInternal {
|
||||
void onPackageRemoved(@NonNull String packageName);
|
||||
}
|
||||
|
||||
/** Interface to override permission checks via composition */
|
||||
public interface CheckPermissionDelegate {
|
||||
/**
|
||||
* Allows overriding check permission behavior.
|
||||
*
|
||||
* @param permName The permission to check.
|
||||
* @param pkgName The package for which to check.
|
||||
* @param userId The user for which to check.
|
||||
* @param superImpl The super implementation.
|
||||
* @return The check permission result.
|
||||
*/
|
||||
int checkPermission(String permName, String pkgName, int userId,
|
||||
TriFunction<String, String, Integer, Integer> superImpl);
|
||||
|
||||
/**
|
||||
* Allows overriding check UID permission behavior.
|
||||
*
|
||||
* @param permName The permission to check.
|
||||
* @param uid The UID for which to check.
|
||||
* @param superImpl The super implementation.
|
||||
* @return The check permission result.
|
||||
*/
|
||||
int checkUidPermission(String permName, int uid,
|
||||
BiFunction<String, Integer, Integer> superImpl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provider for package names.
|
||||
*/
|
||||
@@ -633,4 +662,18 @@ public abstract class PackageManagerInternal {
|
||||
* Ask the package manager to compile layouts in the given package.
|
||||
*/
|
||||
public abstract boolean compileLayouts(String packageName);
|
||||
|
||||
/**
|
||||
* Get the delegate to influence permission checking.
|
||||
*
|
||||
* @return The delegate instance or null to clear.
|
||||
*/
|
||||
public abstract @Nullable CheckPermissionDelegate getCheckPermissionDelegate();
|
||||
|
||||
/**
|
||||
* Set a delegate to influence permission checking.
|
||||
*
|
||||
* @param delegate A delegate instance or null to clear.
|
||||
*/
|
||||
public abstract void setCheckPermissionDelegate(@Nullable CheckPermissionDelegate delegate);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ interface IAppOpsService {
|
||||
void stopWatchingMode(IAppOpsCallback callback);
|
||||
IBinder getToken(IBinder clientToken);
|
||||
int permissionToOpCode(String permission);
|
||||
int noteProxyOperation(int code, String proxyPackageName,
|
||||
int noteProxyOperation(int code, int proxyUid, String proxyPackageName,
|
||||
int callingUid, String callingPackageName);
|
||||
|
||||
// Remaining methods are only used in Java.
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.app.ActivityThread;
|
||||
import android.app.AppGlobals;
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.AppOpsManagerInternal;
|
||||
import android.app.AppOpsManagerInternal.CheckOpsDelegate;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
@@ -207,6 +208,8 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
|
||||
SparseIntArray mProfileOwners;
|
||||
|
||||
private CheckOpsDelegate mCheckOpsDelegate;
|
||||
|
||||
/**
|
||||
* All times are in milliseconds. These constants are kept synchronized with the system
|
||||
* global Settings. Any access to this class or its fields should be done while
|
||||
@@ -1411,15 +1414,39 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
public CheckOpsDelegate getAppOpsServiceDelegate() {
|
||||
synchronized (this) {
|
||||
return mCheckOpsDelegate;
|
||||
}
|
||||
}
|
||||
|
||||
public void setAppOpsServiceDelegate(CheckOpsDelegate delegate) {
|
||||
synchronized (this) {
|
||||
mCheckOpsDelegate = delegate;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int checkOperation(int code, int uid, String packageName) {
|
||||
verifyIncomingUid(uid);
|
||||
verifyIncomingOp(code);
|
||||
String resolvedPackageName = resolvePackageName(uid, packageName);
|
||||
if (resolvedPackageName == null) {
|
||||
return AppOpsManager.MODE_IGNORED;
|
||||
}
|
||||
final CheckOpsDelegate delegate;
|
||||
synchronized (this) {
|
||||
if (mCheckOpsDelegate == null) {
|
||||
return checkOperationImpl(code, uid, packageName);
|
||||
}
|
||||
delegate = mCheckOpsDelegate;
|
||||
}
|
||||
return delegate.checkOperation(code, uid, packageName,
|
||||
AppOpsService.this::checkOperationImpl);
|
||||
}
|
||||
|
||||
private int checkOperationImpl(int code, int uid, String packageName) {
|
||||
synchronized (this) {
|
||||
verifyIncomingUid(uid);
|
||||
verifyIncomingOp(code);
|
||||
String resolvedPackageName = resolvePackageName(uid, packageName);
|
||||
if (resolvedPackageName == null) {
|
||||
return AppOpsManager.MODE_IGNORED;
|
||||
}
|
||||
if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
|
||||
return AppOpsManager.MODE_IGNORED;
|
||||
}
|
||||
@@ -1439,20 +1466,33 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
|
||||
@Override
|
||||
public int checkAudioOperation(int code, int usage, int uid, String packageName) {
|
||||
boolean suspended;
|
||||
try {
|
||||
suspended = isPackageSuspendedForUser(packageName, uid);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// Package not found.
|
||||
suspended = false;
|
||||
}
|
||||
|
||||
if (suspended) {
|
||||
Slog.i(TAG, "Audio disabled for suspended package=" + packageName + " for uid=" + uid);
|
||||
return AppOpsManager.MODE_IGNORED;
|
||||
}
|
||||
|
||||
final CheckOpsDelegate delegate;
|
||||
synchronized (this) {
|
||||
if (mCheckOpsDelegate == null) {
|
||||
return checkAudioOperationImpl(code, usage, uid, packageName);
|
||||
}
|
||||
delegate = mCheckOpsDelegate;
|
||||
}
|
||||
return delegate.checkAudioOperation(code, usage, uid, packageName,
|
||||
AppOpsService.this::checkAudioOperationImpl);
|
||||
}
|
||||
|
||||
private int checkAudioOperationImpl(int code, int usage, int uid, String packageName) {
|
||||
synchronized (this) {
|
||||
boolean suspended;
|
||||
try {
|
||||
suspended = isPackageSuspendedForUser(packageName, uid);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// Package not found.
|
||||
suspended = false;
|
||||
}
|
||||
|
||||
if (suspended) {
|
||||
Slog.i(TAG, "Audio disabled for suspended package=" + packageName
|
||||
+ " for uid=" + uid);
|
||||
return AppOpsManager.MODE_IGNORED;
|
||||
}
|
||||
|
||||
final int mode = checkRestrictionLocked(code, usage, uid, packageName);
|
||||
if (mode != AppOpsManager.MODE_ALLOWED) {
|
||||
return mode;
|
||||
@@ -1530,10 +1570,10 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int noteProxyOperation(int code, String proxyPackageName,
|
||||
int proxiedUid, String proxiedPackageName) {
|
||||
public int noteProxyOperation(int code, int proxyUid,
|
||||
String proxyPackageName, int proxiedUid, String proxiedPackageName) {
|
||||
verifyIncomingUid(proxyUid);
|
||||
verifyIncomingOp(code);
|
||||
final int proxyUid = Binder.getCallingUid();
|
||||
String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
|
||||
if (resolveProxyPackageName == null) {
|
||||
return AppOpsManager.MODE_IGNORED;
|
||||
@@ -1553,6 +1593,18 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
|
||||
@Override
|
||||
public int noteOperation(int code, int uid, String packageName) {
|
||||
final CheckOpsDelegate delegate;
|
||||
synchronized (this) {
|
||||
if (mCheckOpsDelegate == null) {
|
||||
return noteOperationImpl(code, uid, packageName);
|
||||
}
|
||||
delegate = mCheckOpsDelegate;
|
||||
}
|
||||
return delegate.noteOperation(code, uid, packageName,
|
||||
AppOpsService.this::noteOperationImpl);
|
||||
}
|
||||
|
||||
private int noteOperationImpl(int code, int uid, String packageName) {
|
||||
verifyIncomingUid(uid);
|
||||
verifyIncomingOp(code);
|
||||
String resolvedPackageName = resolvePackageName(uid, packageName);
|
||||
|
||||
@@ -233,6 +233,7 @@ import android.app.ActivityThread;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.AppGlobals;
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.AppOpsManagerInternal.CheckOpsDelegate;
|
||||
import android.app.ApplicationErrorReport;
|
||||
import android.app.ApplicationThreadConstants;
|
||||
import android.app.BroadcastOptions;
|
||||
@@ -296,6 +297,7 @@ import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.content.pm.PackageManagerInternal.CheckPermissionDelegate;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.content.pm.PathPermission;
|
||||
import android.content.pm.PermissionInfo;
|
||||
@@ -432,6 +434,8 @@ import com.android.internal.util.FastPrintWriter;
|
||||
import com.android.internal.util.FastXmlSerializer;
|
||||
import com.android.internal.util.MemInfoReader;
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.internal.util.function.QuadFunction;
|
||||
import com.android.internal.util.function.TriFunction;
|
||||
import com.android.server.AlarmManagerInternal;
|
||||
import com.android.server.AppOpsService;
|
||||
import com.android.server.AttributeCache;
|
||||
@@ -516,6 +520,7 @@ import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public class ActivityManagerService extends IActivityManager.Stub
|
||||
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
|
||||
@@ -22177,6 +22182,8 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
|
||||
// Can't call out of the system process with a lock held, so post a message.
|
||||
if (app.instr.mUiAutomationConnection != null) {
|
||||
mAppOpsService.setAppOpsServiceDelegate(null);
|
||||
getPackageManagerInternalLocked().setCheckPermissionDelegate(null);
|
||||
mHandler.obtainMessage(SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG,
|
||||
app.instr.mUiAutomationConnection).sendToTarget();
|
||||
}
|
||||
@@ -27189,4 +27196,143 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startDelegateShellPermissionIdentity(int delegateUid) {
|
||||
if (UserHandle.getCallingAppId() != Process.SHELL_UID
|
||||
&& UserHandle.getCallingAppId() != Process.ROOT_UID) {
|
||||
throw new SecurityException("Only the shell can delegate its permissions");
|
||||
}
|
||||
|
||||
// We allow delegation only to one instrumentation started from the shell
|
||||
synchronized (ActivityManagerService.this) {
|
||||
// If there is a delegate it should be the same instance for app ops and permissions.
|
||||
if (mAppOpsService.getAppOpsServiceDelegate()
|
||||
!= getPackageManagerInternalLocked().getCheckPermissionDelegate()) {
|
||||
throw new IllegalStateException("Bad shell delegate state");
|
||||
}
|
||||
|
||||
// If the delegate is already set up for the target UID, nothing to do.
|
||||
if (mAppOpsService.getAppOpsServiceDelegate() != null) {
|
||||
if (!(mAppOpsService.getAppOpsServiceDelegate() instanceof ShellDelegate)) {
|
||||
throw new IllegalStateException("Bad shell delegate state");
|
||||
}
|
||||
if (((ShellDelegate) mAppOpsService.getAppOpsServiceDelegate())
|
||||
.getDelegateUid() != delegateUid) {
|
||||
throw new SecurityException("Shell can delegate permissions only "
|
||||
+ "to one instrumentation at a time");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
final int instrCount = mActiveInstrumentation.size();
|
||||
for (int i = 0; i < instrCount; i++) {
|
||||
final ActiveInstrumentation instr = mActiveInstrumentation.get(i);
|
||||
if (instr.mTargetInfo.uid != delegateUid) {
|
||||
continue;
|
||||
}
|
||||
// If instrumentation started from the shell the connection is not null
|
||||
if (instr.mUiAutomationConnection == null) {
|
||||
throw new SecurityException("Shell can delegate its permissions" +
|
||||
" only to an instrumentation started from the shell");
|
||||
}
|
||||
|
||||
// Hook them up...
|
||||
final ShellDelegate shellDelegate = new ShellDelegate(
|
||||
instr.mTargetInfo.packageName, delegateUid);
|
||||
mAppOpsService.setAppOpsServiceDelegate(shellDelegate);
|
||||
getPackageManagerInternalLocked().setCheckPermissionDelegate(shellDelegate);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopDelegateShellPermissionIdentity() {
|
||||
if (UserHandle.getCallingAppId() != Process.SHELL_UID
|
||||
&& UserHandle.getCallingAppId() != Process.ROOT_UID) {
|
||||
throw new SecurityException("Only the shell can delegate its permissions");
|
||||
}
|
||||
synchronized (ActivityManagerService.this) {
|
||||
mAppOpsService.setAppOpsServiceDelegate(null);
|
||||
getPackageManagerInternalLocked().setCheckPermissionDelegate(null);
|
||||
}
|
||||
}
|
||||
|
||||
private class ShellDelegate implements CheckOpsDelegate, CheckPermissionDelegate {
|
||||
private final String mTargetPackageName;
|
||||
private final int mTargetUid;
|
||||
|
||||
ShellDelegate(String targetPacakgeName, int targetUid) {
|
||||
mTargetPackageName = targetPacakgeName;
|
||||
mTargetUid = targetUid;
|
||||
}
|
||||
|
||||
int getDelegateUid() {
|
||||
return mTargetUid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int checkOperation(int code, int uid, String packageName,
|
||||
TriFunction<Integer, Integer, String, Integer> superImpl) {
|
||||
if (uid == mTargetUid) {
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
return superImpl.apply(code, Process.SHELL_UID,
|
||||
"com.android.shell");
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
return superImpl.apply(code, uid, packageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int checkAudioOperation(int code, int usage, int uid, String packageName,
|
||||
QuadFunction<Integer, Integer, Integer, String, Integer> superImpl) {
|
||||
if (uid == mTargetUid) {
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
return superImpl.apply(code, usage, Process.SHELL_UID,
|
||||
"com.android.shell");
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
return superImpl.apply(code, usage, uid, packageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int noteOperation(int code, int uid, String packageName,
|
||||
TriFunction<Integer, Integer, String, Integer> superImpl) {
|
||||
if (uid == mTargetUid) {
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
return mAppOpsService.noteProxyOperation(code, Process.SHELL_UID,
|
||||
"com.android.shell", uid, packageName);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
return superImpl.apply(code, uid, packageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int checkPermission(String permName, String pkgName, int userId,
|
||||
TriFunction<String, String, Integer, Integer> superImpl) {
|
||||
if (mTargetPackageName.equals(pkgName)) {
|
||||
return superImpl.apply(permName, "com.android.shell", userId);
|
||||
}
|
||||
return superImpl.apply(permName, pkgName, userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int checkUidPermission(String permName, int uid,
|
||||
BiFunction<String, Integer, Integer> superImpl) {
|
||||
if (uid == mTargetUid) {
|
||||
return superImpl.apply(permName, Process.SHELL_UID);
|
||||
}
|
||||
return superImpl.apply(permName, uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,6 +177,7 @@ import android.content.pm.PackageList;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.LegacyPackageDeleteObserver;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.content.pm.PackageManagerInternal.CheckPermissionDelegate;
|
||||
import android.content.pm.PackageManagerInternal.PackageListObserver;
|
||||
import android.content.pm.PackageParser;
|
||||
import android.content.pm.PackageParser.ActivityIntentInfo;
|
||||
@@ -297,6 +298,8 @@ import com.android.internal.util.FastXmlSerializer;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.internal.util.XmlUtils;
|
||||
import com.android.internal.util.function.QuadFunction;
|
||||
import com.android.internal.util.function.TriFunction;
|
||||
import com.android.server.AttributeCache;
|
||||
import com.android.server.DeviceIdleController;
|
||||
import com.android.server.EventLogTags;
|
||||
@@ -376,6 +379,7 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
@@ -1043,6 +1047,9 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
void receiveVerificationResponse(int verificationId);
|
||||
}
|
||||
|
||||
@GuardedBy("mPackages")
|
||||
private CheckPermissionDelegate mCheckPermissionDelegate;
|
||||
|
||||
private class IntentVerifierProxy implements IntentFilterVerifier<ActivityIntentInfo> {
|
||||
private Context mContext;
|
||||
private ComponentName mIntentFilterVerifierComponent;
|
||||
@@ -5352,11 +5359,35 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
|
||||
@Override
|
||||
public int checkPermission(String permName, String pkgName, int userId) {
|
||||
final CheckPermissionDelegate checkPermissionDelegate;
|
||||
synchronized (mPackages) {
|
||||
if (mCheckPermissionDelegate == null) {
|
||||
return checkPermissionImpl(permName, pkgName, userId);
|
||||
}
|
||||
checkPermissionDelegate = mCheckPermissionDelegate;
|
||||
}
|
||||
return checkPermissionDelegate.checkPermission(permName, pkgName, userId,
|
||||
PackageManagerService.this::checkPermissionImpl);
|
||||
}
|
||||
|
||||
private int checkPermissionImpl(String permName, String pkgName, int userId) {
|
||||
return mPermissionManager.checkPermission(permName, pkgName, getCallingUid(), userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int checkUidPermission(String permName, int uid) {
|
||||
final CheckPermissionDelegate checkPermissionDelegate;
|
||||
synchronized (mPackages) {
|
||||
if (mCheckPermissionDelegate == null) {
|
||||
return checkUidPermissionImpl(permName, uid);
|
||||
}
|
||||
checkPermissionDelegate = mCheckPermissionDelegate;
|
||||
}
|
||||
return checkPermissionDelegate.checkUidPermission(permName, uid,
|
||||
PackageManagerService.this::checkUidPermissionImpl);
|
||||
}
|
||||
|
||||
private int checkUidPermissionImpl(String permName, int uid) {
|
||||
synchronized (mPackages) {
|
||||
final String[] packageNames = getPackagesForUid(uid);
|
||||
final PackageParser.Package pkg = (packageNames != null && packageNames.length > 0)
|
||||
@@ -9236,6 +9267,16 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mPackages")
|
||||
public CheckPermissionDelegate getCheckPermissionDelegateLocked() {
|
||||
return mCheckPermissionDelegate;
|
||||
}
|
||||
|
||||
@GuardedBy("mPackages")
|
||||
public void setCheckPermissionDelegateLocked(CheckPermissionDelegate delegate) {
|
||||
mCheckPermissionDelegate = delegate;
|
||||
}
|
||||
|
||||
@GuardedBy("mPackages")
|
||||
private void notifyPackageUseLocked(String packageName, int reason) {
|
||||
final PackageParser.Package p = mPackages.get(packageName);
|
||||
@@ -24515,6 +24556,20 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
|
||||
}
|
||||
return mArtManagerService.compileLayouts(pkg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CheckPermissionDelegate getCheckPermissionDelegate() {
|
||||
synchronized (mPackages) {
|
||||
return PackageManagerService.this.getCheckPermissionDelegateLocked();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCheckPermissionDelegate(CheckPermissionDelegate delegate) {
|
||||
synchronized (mPackages) {
|
||||
PackageManagerService.this.setCheckPermissionDelegateLocked(delegate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,19 +21,11 @@ import android.annotation.Nullable;
|
||||
import android.content.pm.PackageParser;
|
||||
import android.content.pm.PermissionGroupInfo;
|
||||
import android.content.pm.PermissionInfo;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.PackageManager.PermissionInfoFlags;
|
||||
import android.content.pm.PackageParser.Permission;
|
||||
|
||||
import com.android.server.pm.SharedUserSetting;
|
||||
import com.android.server.pm.permission.PermissionManagerInternal.PermissionCallback;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Internal interfaces to be used by other components within the system server.
|
||||
|
||||
@@ -10,7 +10,9 @@ package android.test.mock {
|
||||
method public String getPermissionControllerPackageName();
|
||||
method @NonNull public String getServicesSystemSharedLibraryPackageName();
|
||||
method @NonNull public String getSharedSystemSharedLibraryPackageName();
|
||||
method public void grantRuntimePermission(String, String, android.os.UserHandle);
|
||||
method public boolean isPermissionReviewModeEnabled();
|
||||
method public void revokeRuntimePermission(String, String, android.os.UserHandle);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user