diff options
author | Dianne Hackborn <hackbod@google.com> | 2015-11-18 16:29:56 -0800 |
---|---|---|
committer | Dianne Hackborn <hackbod@google.com> | 2015-11-18 16:29:56 -0800 |
commit | 268e4e3d00df6ea0eae6fca321e474a3d512fb7e (patch) | |
tree | 6682d336e545dc11a9923f9c657f8b9c3d6a9b57 | |
parent | f91e74d9a945f59cdb714a80a2a87953d72dbd99 (diff) |
Move appops command to the service.
The "appops" shell command is now just a wrapper around doing
"cmd appops", no more need to launch a Java VM!
Change-Id: I06fc68762d0ab95a016fb24db0affb0d91197588
-rw-r--r-- | cmds/appops/Android.mk | 6 | ||||
-rwxr-xr-x | cmds/appops/appops | 6 | ||||
-rw-r--r-- | cmds/appops/src/com/android/commands/appops/AppOpsCommand.java | 334 | ||||
-rw-r--r-- | services/core/java/com/android/server/AppOpsService.java | 318 |
4 files changed, 293 insertions, 371 deletions
diff --git a/cmds/appops/Android.mk b/cmds/appops/Android.mk index 1e15204a221d..6801ce9cd3af 100644 --- a/cmds/appops/Android.mk +++ b/cmds/appops/Android.mk @@ -3,14 +3,8 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES := $(call all-subdir-java-files) -LOCAL_MODULE := appops -include $(BUILD_JAVA_LIBRARY) - -include $(CLEAR_VARS) LOCAL_MODULE := appops LOCAL_SRC_FILES := appops LOCAL_MODULE_CLASS := EXECUTABLES LOCAL_MODULE_TAGS := optional include $(BUILD_PREBUILT) - diff --git a/cmds/appops/appops b/cmds/appops/appops index 407e5511ad75..25d20311aae2 100755 --- a/cmds/appops/appops +++ b/cmds/appops/appops @@ -1,5 +1 @@ -# Script to start "appwidget" on the device, which has a very rudimentary shell. -base=/system -export CLASSPATH=$base/framework/appops.jar -exec app_process $base/bin com.android.commands.appops.AppOpsCommand "$@" - +cmd appops $@ diff --git a/cmds/appops/src/com/android/commands/appops/AppOpsCommand.java b/cmds/appops/src/com/android/commands/appops/AppOpsCommand.java deleted file mode 100644 index c9b9e5862a48..000000000000 --- a/cmds/appops/src/com/android/commands/appops/AppOpsCommand.java +++ /dev/null @@ -1,334 +0,0 @@ -/* -** Copyright 2014, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -package com.android.commands.appops; - -import android.app.ActivityManager; -import android.app.ActivityThread; -import android.app.AppOpsManager; -import android.content.Context; -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. - */ -public class AppOpsCommand extends BaseCommand { - - public static void main(String[] args) { - new AppOpsCommand().run(args); - } - - @Override - public void onShowUsage(PrintStream out) { - 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 { - String command = nextArgRequired(); - switch (command) { - case COMMAND_SET: - runSet(); - break; - - case COMMAND_GET: - runGet(); - break; - - case COMMAND_RESET: - runReset(); - break; - - default: - System.err.println("Error: Unknown command: '" + command + "'."); - break; - } - } - - private static final String ARGUMENT_USER = "--user"; - - // Modes - private static final String MODE_ALLOW = "allow"; - private static final String MODE_DENY = "deny"; - 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; - String mode = 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 if (mode == null) { - mode = argument; - } else { - System.err.println("Error: Unsupported argument: " + argument); - return; - } - } - } - - if (packageName == null) { - System.err.println("Error: Package name not specified."); - return; - } else if (op == null) { - System.err.println("Error: Operation not specified."); - return; - } else if (mode == null) { - System.err.println("Error: Mode not specified."); - return; - } - - final int opInt = strOpToOp(op); - if (opInt < 0) { - return; - } - final int modeInt; - switch (mode) { - case MODE_ALLOW: - modeInt = AppOpsManager.MODE_ALLOWED; - break; - case MODE_DENY: - modeInt = AppOpsManager.MODE_ERRORED; - break; - case MODE_IGNORE: - modeInt = AppOpsManager.MODE_IGNORED; - break; - case MODE_DEFAULT: - modeInt = AppOpsManager.MODE_DEFAULT; - break; - default: - System.err.println("Error: Mode " + mode + " is not valid,"); - return; - } - - // 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; - if ("root".equals(packageName)) { - uid = 0; - } else { - uid = pm.getPackageUid(packageName, userId); - } - if (uid < 0) { - 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; - if ("root".equals(packageName)) { - uid = 0; - } else { - 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) || "system".equals(userStr)) { - userId = UserHandle.USER_SYSTEM; - } 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/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index c131628f2854..a5cef1a36ef0 100644 --- a/services/core/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -47,7 +47,9 @@ import android.os.Handler; import android.os.IBinder; import android.os.Process; import android.os.RemoteException; +import android.os.ResultReceiver; import android.os.ServiceManager; +import android.os.ShellCommand; import android.os.UserHandle; import android.os.storage.MountServiceInternal; import android.util.ArrayMap; @@ -1554,15 +1556,300 @@ public class AppOpsService extends IAppOpsService.Stub { } } - private void dumpHelp(PrintWriter pw) { - pw.println("AppOps service (appops) dump options:"); - pw.println(" [-h] [CMD]"); - pw.println(" -h: print this help text."); - pw.println("Commands:"); + static class Shell extends ShellCommand { + final IAppOpsService mInterface; + final AppOpsService mInternal; + + int userId = UserHandle.USER_SYSTEM; + String packageName; + String opStr; + int op; + int packageUid; + + Shell(IAppOpsService iface, AppOpsService internal) { + mInterface = iface; + mInternal = internal; + } + + @Override + public int onCommand(String cmd) { + return onShellCommand(this, cmd); + } + + @Override + public void onHelp() { + PrintWriter pw = getOutPrintWriter(); + dumpCommandHelp(pw); + } + + private int strOpToOp(String op, PrintWriter err) { + try { + return AppOpsManager.strOpToOp(op); + } catch (IllegalArgumentException e) { + } + try { + return Integer.parseInt(op); + } catch (NumberFormatException e) { + } + try { + return AppOpsManager.strDebugOpToOp(op); + } catch (IllegalArgumentException e) { + err.println("Error: " + e.getMessage()); + return -1; + } + } + + int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException { + userId = UserHandle.USER_CURRENT; + packageName = null; + opStr = null; + for (String argument; (argument = getNextArg()) != null;) { + if ("--user".equals(argument)) { + userId = UserHandle.parseUserArg(getNextArgRequired()); + } else { + if (packageName == null) { + packageName = argument; + } else if (opStr == null) { + opStr = argument; + break; + } + } + } + if (packageName == null) { + err.println("Error: Package name not specified."); + return -1; + } else if (opStr == null && reqOp) { + err.println("Error: Operation not specified."); + return -1; + } + if (opStr != null) { + op = strOpToOp(opStr, err); + if (op < 0) { + return -1; + } + } else { + op = AppOpsManager.OP_NONE; + } + if (userId == UserHandle.USER_CURRENT) { + userId = ActivityManager.getCurrentUser(); + } + if ("root".equals(packageName)) { + packageUid = 0; + } else { + packageUid = AppGlobals.getPackageManager().getPackageUid(packageName, userId); + } + if (packageUid < 0) { + err.println("Error: No UID for " + packageName + " in user " + userId); + return -1; + } + return 0; + } + } + + @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, + FileDescriptor err, String[] args, ResultReceiver resultReceiver) { + (new Shell(this, this)).exec(this, in, out, err, args, resultReceiver); + } + + static void dumpCommandHelp(PrintWriter pw) { + pw.println("AppOps service (appops) commands:"); + pw.println(" help"); + pw.println(" Print this help text."); + pw.println(" set [--user <USER_ID>] <PACKAGE> <OP> <MODE>"); + pw.println(" Set the mode for a particular application and operation."); + pw.println(" get [--user <USER_ID>] <PACKAGE> [<OP>]"); + pw.println(" Return the mode for a particular application and optional operation."); + pw.println(" reset [--user <USER_ID>] [<PACKAGE>]"); + pw.println(" Reset the given application or all applications to default modes."); pw.println(" write-settings"); pw.println(" Immediately write pending changes to storage."); pw.println(" read-settings"); pw.println(" Read the last written settings, replacing current state in RAM."); + pw.println(" options:"); + pw.println(" <PACKAGE> an Android package name."); + pw.println(" <OP> an AppOps operation."); + pw.println(" <MODE> one of allow, ignore, deny, or default"); + pw.println(" <USER_ID> the user id under which the package is installed. If --user is not"); + pw.println(" specified, the current user is assumed."); + } + + static int onShellCommand(Shell shell, String cmd) { + if (cmd == null) { + return shell.handleDefaultCommands(cmd); + } + PrintWriter pw = shell.getOutPrintWriter(); + PrintWriter err = shell.getErrPrintWriter(); + try { + switch (cmd) { + case "set": { + int res = shell.parseUserPackageOp(true, err); + if (res < 0) { + return res; + } + String modeStr = shell.getNextArg(); + if (modeStr == null) { + err.println("Error: Mode not specified."); + return -1; + } + + final int mode; + switch (modeStr) { + case "allow": + mode = AppOpsManager.MODE_ALLOWED; + break; + case "deny": + mode = AppOpsManager.MODE_ERRORED; + break; + case "ignore": + mode = AppOpsManager.MODE_IGNORED; + break; + case "default": + mode = AppOpsManager.MODE_DEFAULT; + break; + default: + err.println("Error: Mode " + modeStr + " is not valid,"); + return -1; + } + + shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName, mode); + return 0; + } + case "get": { + int res = shell.parseUserPackageOp(false, err); + if (res < 0) { + return res; + } + + List<AppOpsManager.PackageOps> ops = shell.mInterface.getOpsForPackage( + shell.packageUid, shell.packageName, + shell.op != AppOpsManager.OP_NONE ? new int[] {shell.op} : null); + if (ops == null || ops.size() <= 0) { + pw.println("No operations."); + return 0; + } + 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); + pw.print(AppOpsManager.opToName(ent.getOp())); + pw.print(": "); + switch (ent.getMode()) { + case AppOpsManager.MODE_ALLOWED: + pw.print("allow"); + break; + case AppOpsManager.MODE_IGNORED: + pw.print("ignore"); + break; + case AppOpsManager.MODE_ERRORED: + pw.print("deny"); + break; + case AppOpsManager.MODE_DEFAULT: + pw.print("default"); + break; + default: + pw.print("mode="); + pw.print(ent.getMode()); + break; + } + if (ent.getTime() != 0) { + pw.print("; time="); + TimeUtils.formatDuration(now - ent.getTime(), pw); + pw.print(" ago"); + } + if (ent.getRejectTime() != 0) { + pw.print("; rejectTime="); + TimeUtils.formatDuration(now - ent.getRejectTime(), pw); + pw.print(" ago"); + } + if (ent.getDuration() == -1) { + pw.print(" (running)"); + } else if (ent.getDuration() != 0) { + pw.print("; duration="); + TimeUtils.formatDuration(ent.getDuration(), pw); + } + pw.println(); + } + } + return 0; + } + case "reset": { + String packageName = null; + int userId = UserHandle.USER_CURRENT; + for (String argument; (argument = shell.getNextArg()) != null;) { + if ("--user".equals(argument)) { + String userStr = shell.getNextArgRequired(); + userId = UserHandle.parseUserArg(userStr); + } else { + if (packageName == null) { + packageName = argument; + } else { + err.println("Error: Unsupported argument: " + argument); + return -1; + } + } + } + + if (userId == UserHandle.USER_CURRENT) { + userId = ActivityManager.getCurrentUser(); + } + + shell.mInterface.resetAllModes(userId, packageName); + pw.print("Reset all modes for: "); + if (userId == UserHandle.USER_ALL) { + pw.print("all users"); + } else { + pw.print("user "); pw.print(userId); + } + pw.print(", "); + if (packageName == null) { + pw.println("all packages"); + } else { + pw.print("package "); pw.println(packageName); + } + return 0; + } + case "write-settings": { + shell.mInternal.mContext.enforcePermission( + android.Manifest.permission.UPDATE_APP_OPS_STATS, + Binder.getCallingPid(), Binder.getCallingUid(), null); + long token = Binder.clearCallingIdentity(); + try { + synchronized (shell.mInternal) { + shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner); + } + shell.mInternal.writeState(); + pw.println("Current settings written."); + } finally { + Binder.restoreCallingIdentity(token); + } + return 0; + } + case "read-settings": { + shell.mInternal.mContext.enforcePermission( + android.Manifest.permission.UPDATE_APP_OPS_STATS, + Binder.getCallingPid(), Binder.getCallingUid(), null); + long token = Binder.clearCallingIdentity(); + try { + shell.mInternal.readState(); + pw.println("Last settings read."); + } finally { + Binder.restoreCallingIdentity(token); + } + return 0; + } + default: + return shell.handleDefaultCommands(cmd); + } + } catch (RemoteException e) { + pw.println("Remote exception: " + e); + } + return -1; + } + + private void dumpHelp(PrintWriter pw) { + pw.println("AppOps service (appops) dump options:"); + pw.println(" none"); } @Override @@ -1583,27 +1870,6 @@ public class AppOpsService extends IAppOpsService.Stub { return; } else if ("-a".equals(arg)) { // dump all data - } else if ("write-settings".equals(arg)) { - long token = Binder.clearCallingIdentity(); - try { - synchronized (this) { - mHandler.removeCallbacks(mWriteRunner); - } - writeState(); - pw.println("Current settings written."); - } finally { - Binder.restoreCallingIdentity(token); - } - return; - } else if ("read-settings".equals(arg)) { - long token = Binder.clearCallingIdentity(); - try { - readState(); - pw.println("Last settings read."); - } finally { - Binder.restoreCallingIdentity(token); - } - return; } else if (arg.length() > 0 && arg.charAt(0) == '-'){ pw.println("Unknown option: " + arg); return; |