diff --git a/cmds/appops/src/com/android/commands/appops/AppOpsCommand.java b/cmds/appops/src/com/android/commands/appops/AppOpsCommand.java index c414f58300c33..3ec63b429a28e 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 " - + " [--user ]\n" + out.println("usage: appops set [--user ] \n" + + " appops get [--user ] []\n" + + " appops reset [--user ] []\n" + " an Android package name.\n" + " an AppOps operation.\n" + + " one of allow, ignore, deny, or default\n" + " 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 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 entries = ops.get(i).getOps(); + for (int j=0; j getPackagesForOps(in int[] ops); List 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 c3465d1d62c45..42a5195ac6467 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 task = new AsyncTask() { @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>> callbacks = null; synchronized (this) { boolean changed = false; for (int i=mUidOps.size()-1; i>=0; i--) { HashMap 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 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(); } } }