diff options
4 files changed, 241 insertions, 31 deletions
diff --git a/cmds/appops/src/com/android/commands/appops/AppOpsCommand.java b/cmds/appops/src/com/android/commands/appops/AppOpsCommand.java index c414f58300c3..3ec63b429a28 100644 --- a/cmds/appops/src/com/android/commands/appops/AppOpsCommand.java +++ b/cmds/appops/src/com/android/commands/appops/AppOpsCommand.java @@ -24,10 +24,12 @@ import android.content.pm.IPackageManager; import android.os.ServiceManager; import android.os.UserHandle; +import android.util.TimeUtils; import com.android.internal.app.IAppOpsService; import com.android.internal.os.BaseCommand; import java.io.PrintStream; +import java.util.List; /** * This class is a command line utility for manipulating AppOps permissions. @@ -40,15 +42,19 @@ public class AppOpsCommand extends BaseCommand { @Override public void onShowUsage(PrintStream out) { - out.println("usage: adb shell appops set <PACKAGE> <OP> " - + "<allow|ignore|deny|default> [--user <USER_ID>]\n" + out.println("usage: appops set [--user <USER_ID>] <PACKAGE> <OP> <MODE>\n" + + " appops get [--user <USER_ID>] <PACKAGE> [<OP>]\n" + + " appops reset [--user <USER_ID>] [<PACKAGE>]\n" + " <PACKAGE> an Android package name.\n" + " <OP> an AppOps operation.\n" + + " <MODE> one of allow, ignore, deny, or default\n" + " <USER_ID> the user id under which the package is installed. If --user is not\n" + " specified, the current user is assumed.\n"); } private static final String COMMAND_SET = "set"; + private static final String COMMAND_GET = "get"; + private static final String COMMAND_RESET = "reset"; @Override public void onRun() throws Exception { @@ -58,8 +64,17 @@ public class AppOpsCommand extends BaseCommand { runSet(); break; + case COMMAND_GET: + runGet(); + break; + + case COMMAND_RESET: + runReset(); + break; + default: - throw new IllegalArgumentException("Unknown command '" + command + "'."); + System.err.println("Error: Unknown command: '" + command + "'."); + break; } } @@ -71,6 +86,23 @@ public class AppOpsCommand extends BaseCommand { private static final String MODE_IGNORE = "ignore"; private static final String MODE_DEFAULT = "default"; + private int strOpToOp(String op) { + try { + return AppOpsManager.strOpToOp(op); + } catch (IllegalArgumentException e) { + } + try { + return Integer.parseInt(op); + } catch (NumberFormatException e) { + } + try { + return AppOpsManager.strDebugOpToOp(op); + } catch (IllegalArgumentException e) { + System.err.println("Error: " + e.getMessage()); + return -1; + } + } + private void runSet() throws Exception { String packageName = null; String op = null; @@ -87,20 +119,27 @@ public class AppOpsCommand extends BaseCommand { } else if (mode == null) { mode = argument; } else { - throw new IllegalArgumentException("Unsupported argument: " + argument); + System.err.println("Error: Unsupported argument: " + argument); + return; } } } if (packageName == null) { - throw new IllegalArgumentException("Package name not specified."); + System.err.println("Error: Package name not specified."); + return; } else if (op == null) { - throw new IllegalArgumentException("Operation not specified."); + System.err.println("Error: Operation not specified."); + return; } else if (mode == null) { - throw new IllegalArgumentException("Mode not specified."); + System.err.println("Error: Mode not specified."); + return; } - final int opInt = AppOpsManager.strOpToOp(op); + final int opInt = strOpToOp(op); + if (opInt < 0) { + return; + } final int modeInt; switch (mode) { case MODE_ALLOW: @@ -116,7 +155,8 @@ public class AppOpsCommand extends BaseCommand { modeInt = AppOpsManager.MODE_DEFAULT; break; default: - throw new IllegalArgumentException("Mode is invalid."); + System.err.println("Error: Mode " + mode + " is not valid,"); + return; } // Parsing complete, let's execute the command. @@ -130,8 +170,155 @@ public class AppOpsCommand extends BaseCommand { ServiceManager.getService(Context.APP_OPS_SERVICE)); final int uid = pm.getPackageUid(packageName, userId); if (uid < 0) { - throw new Exception("No UID for " + packageName + " for user " + userId); + System.err.println("Error: No UID for " + packageName + " in user " + userId); + return; } appOpsService.setMode(opInt, uid, packageName, modeInt); } + + private void runGet() throws Exception { + String packageName = null; + String op = null; + int userId = UserHandle.USER_CURRENT; + for (String argument; (argument = nextArg()) != null;) { + if (ARGUMENT_USER.equals(argument)) { + userId = Integer.parseInt(nextArgRequired()); + } else { + if (packageName == null) { + packageName = argument; + } else if (op == null) { + op = argument; + } else { + System.err.println("Error: Unsupported argument: " + argument); + return; + } + } + } + + if (packageName == null) { + System.err.println("Error: Package name not specified."); + return; + } + + final int opInt = op != null ? strOpToOp(op) : 0; + + // Parsing complete, let's execute the command. + + if (userId == UserHandle.USER_CURRENT) { + userId = ActivityManager.getCurrentUser(); + } + + final IPackageManager pm = ActivityThread.getPackageManager(); + final IAppOpsService appOpsService = IAppOpsService.Stub.asInterface( + ServiceManager.getService(Context.APP_OPS_SERVICE)); + final int uid = pm.getPackageUid(packageName, userId); + if (uid < 0) { + System.err.println("Error: No UID for " + packageName + " in user " + userId); + return; + } + List<AppOpsManager.PackageOps> ops = appOpsService.getOpsForPackage(uid, packageName, + op != null ? new int[] {opInt} : null); + if (ops == null || ops.size() <= 0) { + System.out.println("No operations."); + return; + } + final long now = System.currentTimeMillis(); + for (int i=0; i<ops.size(); i++) { + List<AppOpsManager.OpEntry> entries = ops.get(i).getOps(); + for (int j=0; j<entries.size(); j++) { + AppOpsManager.OpEntry ent = entries.get(j); + System.out.print(AppOpsManager.opToName(ent.getOp())); + System.out.print(": "); + switch (ent.getMode()) { + case AppOpsManager.MODE_ALLOWED: + System.out.print("allow"); + break; + case AppOpsManager.MODE_IGNORED: + System.out.print("ignore"); + break; + case AppOpsManager.MODE_ERRORED: + System.out.print("deny"); + break; + case AppOpsManager.MODE_DEFAULT: + System.out.print("default"); + break; + default: + System.out.print("mode="); + System.out.print(ent.getMode()); + break; + } + if (ent.getTime() != 0) { + System.out.print("; time="); + StringBuilder sb = new StringBuilder(); + TimeUtils.formatDuration(now - ent.getTime(), sb); + System.out.print(sb); + System.out.print(" ago"); + } + if (ent.getRejectTime() != 0) { + System.out.print("; rejectTime="); + StringBuilder sb = new StringBuilder(); + TimeUtils.formatDuration(now - ent.getRejectTime(), sb); + System.out.print(sb); + System.out.print(" ago"); + } + if (ent.getDuration() == -1) { + System.out.print(" (running)"); + } else if (ent.getDuration() != 0) { + System.out.print("; duration="); + StringBuilder sb = new StringBuilder(); + TimeUtils.formatDuration(ent.getDuration(), sb); + System.out.print(sb); + } + System.out.println(); + } + } + } + + private void runReset() throws Exception { + String packageName = null; + int userId = UserHandle.USER_CURRENT; + for (String argument; (argument = nextArg()) != null;) { + if (ARGUMENT_USER.equals(argument)) { + String userStr = nextArgRequired(); + if ("all".equals(userStr)) { + userId = UserHandle.USER_ALL; + } else if ("current".equals(userStr)) { + userId = UserHandle.USER_CURRENT; + } else if ("owner".equals(userStr)) { + userId = UserHandle.USER_OWNER; + } else { + userId = Integer.parseInt(nextArgRequired()); + } + } else { + if (packageName == null) { + packageName = argument; + } else { + System.err.println("Error: Unsupported argument: " + argument); + return; + } + } + } + + // Parsing complete, let's execute the command. + + if (userId == UserHandle.USER_CURRENT) { + userId = ActivityManager.getCurrentUser(); + } + + final IAppOpsService appOpsService = IAppOpsService.Stub.asInterface( + ServiceManager.getService(Context.APP_OPS_SERVICE)); + appOpsService.resetAllModes(userId, packageName); + System.out.print("Reset all modes for: "); + if (userId == UserHandle.USER_ALL) { + System.out.print("all users"); + } else { + System.out.print("user "); System.out.print(userId); + } + System.out.print(", "); + if (packageName == null) { + System.out.println("all packages"); + } else { + System.out.print("package "); System.out.println(packageName); + } + } } diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index ba9c9d644ef8..95870cf9675a 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -26,6 +26,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.Process; import android.os.RemoteException; +import android.os.UserHandle; import android.os.UserManager; import android.util.ArrayMap; @@ -734,6 +735,18 @@ public class AppOpsManager { } /** + * @hide + */ + public static int strDebugOpToOp(String op) { + for (int i=0; i<sOpNames.length; i++) { + if (sOpNames[i].equals(op)) { + return i; + } + } + throw new IllegalArgumentException("Unknown operation string: " + op); + } + + /** * Retrieve the permission associated with an operation, or null if there is not one. * @hide */ @@ -996,7 +1009,7 @@ public class AppOpsManager { /** @hide */ public void resetAllModes() { try { - mService.resetAllModes(); + mService.resetAllModes(UserHandle.myUserId(), null); } catch (RemoteException e) { } } diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl index a52dd484ae31..99bf9f316162 100644 --- a/core/java/com/android/internal/app/IAppOpsService.aidl +++ b/core/java/com/android/internal/app/IAppOpsService.aidl @@ -36,7 +36,7 @@ interface IAppOpsService { List<AppOpsManager.PackageOps> getPackagesForOps(in int[] ops); List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, in int[] ops); void setMode(int code, int uid, String packageName, int mode); - void resetAllModes(); + void resetAllModes(int reqUserId, String reqPackageName); int checkAudioOperation(int code, int usage, int uid, String packageName); void setAudioRestriction(int code, int usage, int uid, int mode, in String[] exceptionPackages); diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index c3465d1d62c4..42a5195ac646 100644 --- a/services/core/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -29,6 +29,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import android.app.ActivityManager; import android.app.ActivityThread; import android.app.AppOpsManager; import android.content.Context; @@ -53,7 +54,6 @@ import android.util.Log; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; -import android.util.SparseIntArray; import android.util.TimeUtils; import android.util.Xml; @@ -78,10 +78,12 @@ public class AppOpsService extends IAppOpsService.Stub { final Handler mHandler; boolean mWriteScheduled; + boolean mFastWriteScheduled; final Runnable mWriteRunner = new Runnable() { public void run() { synchronized (AppOpsService.this) { mWriteScheduled = false; + mFastWriteScheduled = false; AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { writeState(); @@ -237,7 +239,7 @@ public class AppOpsService extends IAppOpsService.Stub { } } if (changed) { - scheduleWriteLocked(); + scheduleFastWriteLocked(); } } } @@ -250,7 +252,7 @@ public class AppOpsService extends IAppOpsService.Stub { if (pkgs.size() <= 0) { mUidOps.remove(uid); } - scheduleWriteLocked(); + scheduleFastWriteLocked(); } } } @@ -260,7 +262,7 @@ public class AppOpsService extends IAppOpsService.Stub { synchronized (this) { if (mUidOps.indexOfKey(uid) >= 0) { mUidOps.remove(uid); - scheduleWriteLocked(); + scheduleFastWriteLocked(); } } } @@ -400,7 +402,7 @@ public class AppOpsService extends IAppOpsService.Stub { // if there is nothing else interesting in it. pruneOp(op, uid, packageName); } - scheduleWriteNowLocked(); + scheduleFastWriteLocked(); } } } @@ -436,16 +438,20 @@ public class AppOpsService extends IAppOpsService.Stub { } @Override - public void resetAllModes() { - int callingUid = Binder.getCallingUid(); + public void resetAllModes(int reqUserId, String reqPackageName) { + final int callingPid = Binder.getCallingPid(); + final int callingUid = Binder.getCallingUid(); mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS, - Binder.getCallingPid(), callingUid, null); + callingPid, callingUid, null); + reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId, + true, true, "resetAllModes", null); HashMap<Callback, ArrayList<Pair<String, Integer>>> callbacks = null; synchronized (this) { boolean changed = false; for (int i=mUidOps.size()-1; i>=0; i--) { HashMap<String, Ops> packages = mUidOps.valueAt(i); - if (UserHandle.getUserId(callingUid) != UserHandle.getUserId(mUidOps.keyAt(i))) { + if (reqUserId != UserHandle.USER_ALL + && reqUserId != UserHandle.getUserId(mUidOps.keyAt(i))) { // Skip any ops for a different user continue; } @@ -453,6 +459,10 @@ public class AppOpsService extends IAppOpsService.Stub { while (it.hasNext()) { Map.Entry<String, Ops> ent = it.next(); String packageName = ent.getKey(); + if (reqPackageName != null && !reqPackageName.equals(packageName)) { + // Skip any ops for a different package + continue; + } Ops pkgOps = ent.getValue(); for (int j=pkgOps.size()-1; j>=0; j--) { Op curOp = pkgOps.valueAt(j); @@ -478,7 +488,7 @@ public class AppOpsService extends IAppOpsService.Stub { } } if (changed) { - scheduleWriteNowLocked(); + scheduleFastWriteLocked(); } } if (callbacks != null) { @@ -837,12 +847,13 @@ public class AppOpsService extends IAppOpsService.Stub { } } - private void scheduleWriteNowLocked() { - if (!mWriteScheduled) { + private void scheduleFastWriteLocked() { + if (!mFastWriteScheduled) { mWriteScheduled = true; + mFastWriteScheduled = true; + mHandler.removeCallbacks(mWriteRunner); + mHandler.postDelayed(mWriteRunner, 10*1000); } - mHandler.removeCallbacks(mWriteRunner); - mHandler.post(mWriteRunner); } private Op getOpLocked(int code, int uid, String packageName, boolean edit) { @@ -1236,12 +1247,11 @@ public class AppOpsService extends IAppOpsService.Stub { pw.print(" ago"); } if (op.duration == -1) { - pw.println(" (running)"); - } else { - pw.print("; duration="); - TimeUtils.formatDuration(op.duration, pw); - pw.println(); + pw.print(" (running)"); + } else if (op.duration != 0) { + pw.print("; duration="); TimeUtils.formatDuration(op.duration, pw); } + pw.println(); } } } |