diff options
Diffstat (limited to 'cmds')
24 files changed, 974 insertions, 2871 deletions
diff --git a/cmds/am/Android.mk b/cmds/am/Android.mk index f8350dce7f50..5586dd4e5b18 100644 --- a/cmds/am/Android.mk +++ b/cmds/am/Android.mk @@ -3,8 +3,11 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES := $(call all-subdir-java-files) +LOCAL_SRC_FILES := \ + $(call all-java-files-under, src) \ + $(call all-proto-files-under, proto) LOCAL_MODULE := am +LOCAL_PROTOC_OPTIMIZE_TYPE := stream include $(BUILD_JAVA_LIBRARY) include $(CLEAR_VARS) @@ -13,3 +16,14 @@ LOCAL_SRC_FILES := am LOCAL_MODULE_CLASS := EXECUTABLES LOCAL_MODULE_TAGS := optional include $(BUILD_PREBUILT) + + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := \ + $(call all-proto-files-under, proto) +LOCAL_MODULE := libinstrumentation +LOCAL_PROTOC_OPTIMIZE_TYPE := full +LOCAL_EXPORT_C_INCLUDE_DIRS := \ + $(call intermediates-dir-for,STATIC_LIBRARIES,libinstrumentation,HOST,,,)/proto/$(LOCAL_PATH)/proto +include $(BUILD_HOST_STATIC_LIBRARY) + diff --git a/cmds/am/am b/cmds/am/am index 1d426bc8c8e1..54c2d394be2c 100755 --- a/cmds/am/am +++ b/cmds/am/am @@ -1,9 +1,9 @@ #!/system/bin/sh -# -# Script to start "am" on the device, which has a very rudimentary -# shell. -# -base=/system -export CLASSPATH=$base/framework/am.jar -exec app_process $base/bin com.android.commands.am.Am "$@" +if [ "$1" != "instrument" ] ; then + cmd activity "$@" +else + base=/system + export CLASSPATH=$base/framework/am.jar + exec app_process $base/bin com.android.commands.am.Am "$@" +fi diff --git a/cmds/am/proto/instrumentation_data.proto b/cmds/am/proto/instrumentation_data.proto new file mode 100644 index 000000000000..12a18a2a035f --- /dev/null +++ b/cmds/am/proto/instrumentation_data.proto @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2016 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. + */ + +syntax = "proto2"; +package android.am; + +option java_package = "com.android.commands.am"; + +message ResultsBundleEntry { + optional string key = 1; + + optional string value_string = 2; + optional sint32 value_int = 3; + optional float value_float = 4; + optional double value_double = 5; + optional sint64 value_long = 6; + optional ResultsBundle value_bundle = 7; +} + +message ResultsBundle { + repeated ResultsBundleEntry entries = 1; +} + +message TestStatus { + optional sint32 result_code = 3; + optional ResultsBundle results = 4; +} + +enum SessionStatusCode { + /** + * The command ran successfully. This does not imply that the tests passed. + */ + SESSION_FINISHED = 0; + + /** + * There was an unrecoverable error running the tests. + */ + SESSION_ABORTED = 1; +} + +message SessionStatus { + optional SessionStatusCode status_code = 1; + optional string error_text = 2; + optional sint32 result_code = 3; + optional ResultsBundle results = 4; +} + +message Session { + repeated TestStatus test_status = 1; + optional SessionStatus session_status = 2; +} + + diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index d6c00589e7c2..f003061cec3a 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -1,20 +1,18 @@ /* -** -** Copyright 2007, 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. -*/ - + * Copyright (C) 2007 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.am; @@ -25,8 +23,6 @@ import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import android.app.ActivityManager; import android.app.ActivityManager.StackInfo; -import android.app.ActivityManagerNative; -import android.app.ActivityOptions; import android.app.IActivityContainer; import android.app.IActivityController; import android.app.IActivityManager; @@ -46,7 +42,6 @@ import android.content.Intent; import android.content.pm.IPackageManager; import android.content.pm.InstrumentationInfo; import android.content.pm.ParceledListSlice; -import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.content.res.Configuration; import android.graphics.Rect; @@ -55,15 +50,17 @@ import android.os.Build; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.os.ResultReceiver; import android.os.SELinux; import android.os.ServiceManager; +import android.os.ShellCallback; import android.os.ShellCommand; -import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.text.TextUtils; import android.util.AndroidException; import android.util.ArrayMap; +import android.util.Log; import android.view.IWindowManager; import com.android.internal.os.BaseCommand; @@ -72,6 +69,7 @@ import com.android.internal.util.Preconditions; import java.io.BufferedReader; import java.io.File; +import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; @@ -85,33 +83,9 @@ import java.util.List; public class Am extends BaseCommand { - private static final String SHELL_PACKAGE_NAME = "com.android.shell"; - - // Is the object moving in a positive direction? - private static final boolean MOVING_FORWARD = true; - // Is the object moving in the horizontal plan? - private static final boolean MOVING_HORIZONTALLY = true; - // Is the object current point great then its target point? - private static final boolean GREATER_THAN_TARGET = true; - // Amount we reduce the stack size by when testing a task re-size. - private static final int STACK_BOUNDS_INSET = 10; - private IActivityManager mAm; private IPackageManager mPm; - private int mStartFlags = 0; - private boolean mWaitOption = false; - private boolean mStopOption = false; - - private int mRepeat = 0; - private int mUserId; - private String mReceiverPermission; - - private String mProfileFile; - private int mSamplingInterval; - private boolean mAutoStop; - private int mStackId; - /** * Command-line entry point. * @@ -123,254 +97,17 @@ public class Am extends BaseCommand { @Override public void onShowUsage(PrintStream out) { - PrintWriter pw = new PrintWriter(out); - pw.println( - "usage: am [subcommand] [options]\n" + - "usage: am start [-D] [-N] [-W] [-P <FILE>] [--start-profiler <FILE>]\n" + - " [--sampling INTERVAL] [-R COUNT] [-S]\n" + - " [--track-allocation] [--user <USER_ID> | current] <INTENT>\n" + - " am startservice [--user <USER_ID> | current] <INTENT>\n" + - " am stopservice [--user <USER_ID> | current] <INTENT>\n" + - " am force-stop [--user <USER_ID> | all | current] <PACKAGE>\n" + - " am kill [--user <USER_ID> | all | current] <PACKAGE>\n" + - " am kill-all\n" + - " am broadcast [--user <USER_ID> | all | current] <INTENT>\n" + - " am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]\n" + - " [--user <USER_ID> | current]\n" + - " [--no-window-animation] [--abi <ABI>] <COMPONENT>\n" + - " am profile start [--user <USER_ID> current] [--sampling INTERVAL] <PROCESS> <FILE>\n" + - " am profile stop [--user <USER_ID> current] [<PROCESS>]\n" + - " am dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>\n" + - " am set-debug-app [-w] [--persistent] <PACKAGE>\n" + - " am clear-debug-app\n" + - " am set-watch-heap <PROCESS> <MEM-LIMIT>\n" + - " am clear-watch-heap\n" + - " am bug-report [--progress]\n" + - " am monitor [--gdb <port>]\n" + - " am hang [--allow-restart]\n" + - " am restart\n" + - " am idle-maintenance\n" + - " am screen-compat [on|off] <PACKAGE>\n" + - " am package-importance <PACKAGE>\n" + - " am to-uri [INTENT]\n" + - " am to-intent-uri [INTENT]\n" + - " am to-app-uri [INTENT]\n" + - " am switch-user <USER_ID>\n" + - " am start-user <USER_ID>\n" + - " am unlock-user <USER_ID> [TOKEN_HEX]\n" + - " am stop-user [-w] [-f] <USER_ID>\n" + - " am stack start <DISPLAY_ID> <INTENT>\n" + - " am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" + - " am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" + - " am stack resize-animated <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" + - " am stack resize-docked-stack <LEFT,TOP,RIGHT,BOTTOM> [<TASK_LEFT,TASK_TOP,TASK_RIGHT,TASK_BOTTOM>]\n" + - " am stack size-docked-stack-test: <STEP_SIZE> <l|t|r|b> [DELAY_MS]\n" + - " am stack move-top-activity-to-pinned-stack: <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" + - " am stack positiontask <TASK_ID> <STACK_ID> <POSITION>\n" + - " am stack list\n" + - " am stack info <STACK_ID>\n" + - " am stack remove <STACK_ID>\n" + - " am task lock <TASK_ID>\n" + - " am task lock stop\n" + - " am task resizeable <TASK_ID> [0 (unresizeable) | 1 (crop_windows) | 2 (resizeable) | 3 (resizeable_and_pipable)]\n" + - " am task resize <TASK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" + - " am task drag-task-test <TASK_ID> <STEP_SIZE> [DELAY_MS] \n" + - " am task size-task-test <TASK_ID> <STEP_SIZE> [DELAY_MS] \n" + - " am get-config\n" + - " am suppress-resize-config-changes <true|false>\n" + - " am set-inactive [--user <USER_ID>] <PACKAGE> true|false\n" + - " am get-inactive [--user <USER_ID>] <PACKAGE>\n" + - " am send-trim-memory [--user <USER_ID>] <PROCESS>\n" + - " [HIDDEN|RUNNING_MODERATE|BACKGROUND|RUNNING_LOW|MODERATE|RUNNING_CRITICAL|COMPLETE]\n" + - " am get-current-user\n" + - "\n" + - "am start: start an Activity. Options are:\n" + - " -D: enable debugging\n" + - " -N: enable native debugging\n" + - " -W: wait for launch to complete\n" + - " --start-profiler <FILE>: start profiler and send results to <FILE>\n" + - " --sampling INTERVAL: use sample profiling with INTERVAL microseconds\n" + - " between samples (use with --start-profiler)\n" + - " -P <FILE>: like above, but profiling stops when app goes idle\n" + - " -R: repeat the activity launch <COUNT> times. Prior to each repeat,\n" + - " the top activity will be finished.\n" + - " -S: force stop the target app before starting the activity\n" + - " --track-allocation: enable tracking of object allocations\n" + - " --user <USER_ID> | current: Specify which user to run as; if not\n" + - " specified then run as the current user.\n" + - " --stack <STACK_ID>: Specify into which stack should the activity be put." + - "\n" + - "am startservice: start a Service. Options are:\n" + - " --user <USER_ID> | current: Specify which user to run as; if not\n" + - " specified then run as the current user.\n" + - "\n" + - "am stopservice: stop a Service. Options are:\n" + - " --user <USER_ID> | current: Specify which user to run as; if not\n" + - " specified then run as the current user.\n" + - "\n" + - "am force-stop: force stop everything associated with <PACKAGE>.\n" + - " --user <USER_ID> | all | current: Specify user to force stop;\n" + - " all users if not specified.\n" + - "\n" + - "am kill: Kill all processes associated with <PACKAGE>. Only kills.\n" + - " processes that are safe to kill -- that is, will not impact the user\n" + - " experience.\n" + - " --user <USER_ID> | all | current: Specify user whose processes to kill;\n" + - " all users if not specified.\n" + - "\n" + - "am kill-all: Kill all background processes.\n" + - "\n" + - "am broadcast: send a broadcast Intent. Options are:\n" + - " --user <USER_ID> | all | current: Specify which user to send to; if not\n" + - " specified then send to all users.\n" + - " --receiver-permission <PERMISSION>: Require receiver to hold permission.\n" + - "\n" + - "am instrument: start an Instrumentation. Typically this target <COMPONENT>\n" + - " is the form <TEST_PACKAGE>/<RUNNER_CLASS> or only <TEST_PACKAGE> if there \n" + - " is only one instrumentation. Options are:\n" + - " -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT). Use with\n" + - " [-e perf true] to generate raw output for performance measurements.\n" + - " -e <NAME> <VALUE>: set argument <NAME> to <VALUE>. For test runners a\n" + - " common form is [-e <testrunner_flag> <value>[,<value>...]].\n" + - " -p <FILE>: write profiling data to <FILE>\n" + - " -w: wait for instrumentation to finish before returning. Required for\n" + - " test runners.\n" + - " --user <USER_ID> | current: Specify user instrumentation runs in;\n" + - " current user if not specified.\n" + - " --no-window-animation: turn off window animations while running.\n" + - " --abi <ABI>: Launch the instrumented process with the selected ABI.\n" + - " This assumes that the process supports the selected ABI.\n" + - "\n" + - "am trace-ipc: Trace IPC transactions.\n" + - " start: start tracing IPC transactions.\n" + - " stop: stop tracing IPC transactions and dump the results to file.\n" + - " --dump-file <FILE>: Specify the file the trace should be dumped to.\n" + - "\n" + - "am profile: start and stop profiler on a process. The given <PROCESS> argument\n" + - " may be either a process name or pid. Options are:\n" + - " --user <USER_ID> | current: When supplying a process name,\n" + - " specify user of process to profile; uses current user if not specified.\n" + - "\n" + - "am dumpheap: dump the heap of a process. The given <PROCESS> argument may\n" + - " be either a process name or pid. Options are:\n" + - " -n: dump native heap instead of managed heap\n" + - " --user <USER_ID> | current: When supplying a process name,\n" + - " specify user of process to dump; uses current user if not specified.\n" + - "\n" + - "am set-debug-app: set application <PACKAGE> to debug. Options are:\n" + - " -w: wait for debugger when application starts\n" + - " --persistent: retain this value\n" + - "\n" + - "am clear-debug-app: clear the previously set-debug-app.\n" + - "\n" + - "am set-watch-heap: start monitoring pss size of <PROCESS>, if it is at or\n" + - " above <HEAP-LIMIT> then a heap dump is collected for the user to report\n" + - "\n" + - "am clear-watch-heap: clear the previously set-watch-heap.\n" + - "\n" + - "am bug-report: request bug report generation; will launch a notification\n" + - " when done to select where it should be delivered. Options are: \n" + - " --progress: will launch a notification right away to show its progress.\n" + - "\n" + - "am monitor: start monitoring for crashes or ANRs.\n" + - " --gdb: start gdbserv on the given port at crash/ANR\n" + - "\n" + - "am hang: hang the system.\n" + - " --allow-restart: allow watchdog to perform normal system restart\n" + - "\n" + - "am restart: restart the user-space system.\n" + - "\n" + - "am idle-maintenance: perform idle maintenance now.\n" + - "\n" + - "am screen-compat: control screen compatibility mode of <PACKAGE>.\n" + - "\n" + - "am package-importance: print current importance of <PACKAGE>.\n" + - "\n" + - "am to-uri: print the given Intent specification as a URI.\n" + - "\n" + - "am to-intent-uri: print the given Intent specification as an intent: URI.\n" + - "\n" + - "am to-app-uri: print the given Intent specification as an android-app: URI.\n" + - "\n" + - "am switch-user: switch to put USER_ID in the foreground, starting\n" + - " execution of that user if it is currently stopped.\n" + - "\n" + - "am start-user: start USER_ID in background if it is currently stopped,\n" + - " use switch-user if you want to start the user in foreground.\n" + - "\n" + - "am stop-user: stop execution of USER_ID, not allowing it to run any\n" + - " code until a later explicit start or switch to it.\n" + - " -w: wait for stop-user to complete.\n" + - " -f: force stop even if there are related users that cannot be stopped.\n" + - "\n" + - "am stack start: start a new activity on <DISPLAY_ID> using <INTENT>.\n" + - "\n" + - "am stack movetask: move <TASK_ID> from its current stack to the top (true) or" + - " bottom (false) of <STACK_ID>.\n" + - "\n" + - "am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>.\n" + - "\n" + - "am stack resize-docked-stack: change docked stack to <LEFT,TOP,RIGHT,BOTTOM>\n" + - " and supplying temporary different task bounds indicated by\n" + - " <TASK_LEFT,TOP,RIGHT,BOTTOM>\n" + - "\n" + - "am stack size-docked-stack-test: test command for sizing docked stack by\n" + - " <STEP_SIZE> increments from the side <l>eft, <t>op, <r>ight, or <b>ottom\n" + - " applying the optional [DELAY_MS] between each step.\n" + - "\n" + - "am stack move-top-activity-to-pinned-stack: moves the top activity from\n" + - " <STACK_ID> to the pinned stack using <LEFT,TOP,RIGHT,BOTTOM> for the\n" + - " bounds of the pinned stack.\n" + - "\n" + - "am stack positiontask: place <TASK_ID> in <STACK_ID> at <POSITION>" + - "\n" + - "am stack list: list all of the activity stacks and their sizes.\n" + - "\n" + - "am stack info: display the information about activity stack <STACK_ID>.\n" + - "\n" + - "am stack remove: remove stack <STACK_ID>.\n" + - "\n" + - "am task lock: bring <TASK_ID> to the front and don't allow other tasks to run.\n" + - "\n" + - "am task lock stop: end the current task lock.\n" + - "\n" + - "am task resizeable: change resizeable mode of <TASK_ID>.\n" + - " 0 (unresizeable) | 1 (crop_windows) | 2 (resizeable) | 3 (resizeable_and_pipable)\n" + - "\n" + - "am task resize: makes sure <TASK_ID> is in a stack with the specified bounds.\n" + - " Forces the task to be resizeable and creates a stack if no existing stack\n" + - " has the specified bounds.\n" + - "\n" + - "am task drag-task-test: test command for dragging/moving <TASK_ID> by\n" + - " <STEP_SIZE> increments around the screen applying the optional [DELAY_MS]\n" + - " between each step.\n" + - "\n" + - "am task size-task-test: test command for sizing <TASK_ID> by <STEP_SIZE>" + - " increments within the screen applying the optional [DELAY_MS] between\n" + - " each step.\n" + - "\n" + - "am get-config: retrieve the configuration and any recent configurations\n" + - " of the device.\n" + - "am suppress-resize-config-changes: suppresses configuration changes due to\n" + - " user resizing an activity/task.\n" + - "\n" + - "am set-inactive: sets the inactive state of an app.\n" + - "\n" + - "am get-inactive: returns the inactive state of an app.\n" + - "\n" + - "am send-trim-memory: send a memory trim event to a <PROCESS>.\n" + - "\n" + - "am get-current-user: returns id of the current foreground user.\n" + - "\n" - ); - Intent.printIntentArgsHelp(pw, ""); - pw.flush(); + try { + runAmCmd(new String[] { "help" }); + } catch (AndroidException e) { + e.printStackTrace(System.err); + } } @Override public void onRun() throws Exception { - mAm = ActivityManagerNative.getDefault(); + mAm = ActivityManager.getService(); if (mAm == null) { System.err.println(NO_SYSTEM_ERROR_CODE); throw new AndroidException("Can't connect to activity manager; is the system running?"); @@ -384,82 +121,10 @@ public class Am extends BaseCommand { String op = nextArgRequired(); - if (op.equals("start")) { - runStart(); - } else if (op.equals("startservice")) { - runStartService(); - } else if (op.equals("stopservice")) { - runStopService(); - } else if (op.equals("force-stop")) { - runForceStop(); - } else if (op.equals("kill")) { - runKill(); - } else if (op.equals("kill-all")) { - runKillAll(); - } else if (op.equals("instrument")) { + if (op.equals("instrument")) { runInstrument(); - } else if (op.equals("trace-ipc")) { - runTraceIpc(); - } else if (op.equals("broadcast")) { - sendBroadcast(); - } else if (op.equals("profile")) { - runProfile(); - } else if (op.equals("dumpheap")) { - runDumpHeap(); - } else if (op.equals("set-debug-app")) { - runSetDebugApp(); - } else if (op.equals("clear-debug-app")) { - runClearDebugApp(); - } else if (op.equals("set-watch-heap")) { - runSetWatchHeap(); - } else if (op.equals("clear-watch-heap")) { - runClearWatchHeap(); - } else if (op.equals("bug-report")) { - runBugReport(); - } else if (op.equals("monitor")) { - runMonitor(); - } else if (op.equals("hang")) { - runHang(); - } else if (op.equals("restart")) { - runRestart(); - } else if (op.equals("idle-maintenance")) { - runIdleMaintenance(); - } else if (op.equals("screen-compat")) { - runScreenCompat(); - } else if (op.equals("package-importance")) { - runPackageImportance(); - } else if (op.equals("to-uri")) { - runToUri(0); - } else if (op.equals("to-intent-uri")) { - runToUri(Intent.URI_INTENT_SCHEME); - } else if (op.equals("to-app-uri")) { - runToUri(Intent.URI_ANDROID_APP_SCHEME); - } else if (op.equals("switch-user")) { - runSwitchUser(); - } else if (op.equals("start-user")) { - runStartUserInBackground(); - } else if (op.equals("unlock-user")) { - runUnlockUser(); - } else if (op.equals("stop-user")) { - runStopUser(); - } else if (op.equals("stack")) { - runStack(); - } else if (op.equals("task")) { - runTask(); - } else if (op.equals("get-config")) { - runGetConfig(); - } else if (op.equals("suppress-resize-config-changes")) { - runSuppressResizeConfigChanges(); - } else if (op.equals("set-inactive")) { - runSetInactive(); - } else if (op.equals("get-inactive")) { - runGetInactive(); - } else if (op.equals("send-trim-memory")) { - runSendTrimMemory(); - } else if (op.equals("get-current-user")) { - runGetCurrentUser(); } else { - showError("Error: unknown command '" + op + "'"); + runAmCmd(getRawArgs()); } } @@ -475,2104 +140,95 @@ public class Am extends BaseCommand { return userId; } - private Intent makeIntent(int defUser) throws URISyntaxException { - mStartFlags = 0; - mWaitOption = false; - mStopOption = false; - mRepeat = 0; - mProfileFile = null; - mSamplingInterval = 0; - mAutoStop = false; - mUserId = defUser; - mStackId = INVALID_STACK_ID; - - return Intent.parseCommandArgs(mArgs, new Intent.CommandOptionHandler() { - @Override - public boolean handleOption(String opt, ShellCommand cmd) { - if (opt.equals("-D")) { - mStartFlags |= ActivityManager.START_FLAG_DEBUG; - } else if (opt.equals("-N")) { - mStartFlags |= ActivityManager.START_FLAG_NATIVE_DEBUGGING; - } else if (opt.equals("-W")) { - mWaitOption = true; - } else if (opt.equals("-P")) { - mProfileFile = nextArgRequired(); - mAutoStop = true; - } else if (opt.equals("--start-profiler")) { - mProfileFile = nextArgRequired(); - mAutoStop = false; - } else if (opt.equals("--sampling")) { - mSamplingInterval = Integer.parseInt(nextArgRequired()); - } else if (opt.equals("-R")) { - mRepeat = Integer.parseInt(nextArgRequired()); - } else if (opt.equals("-S")) { - mStopOption = true; - } else if (opt.equals("--track-allocation")) { - mStartFlags |= ActivityManager.START_FLAG_TRACK_ALLOCATION; - } else if (opt.equals("--user")) { - mUserId = parseUserArg(nextArgRequired()); - } else if (opt.equals("--receiver-permission")) { - mReceiverPermission = nextArgRequired(); - } else if (opt.equals("--stack")) { - mStackId = Integer.parseInt(nextArgRequired()); - } else { - return false; - } - return true; - } - }); - } - - private void runStartService() throws Exception { - Intent intent = makeIntent(UserHandle.USER_CURRENT); - if (mUserId == UserHandle.USER_ALL) { - System.err.println("Error: Can't start activity with user 'all'"); - return; - } - System.out.println("Starting service: " + intent); - ComponentName cn = mAm.startService(null, intent, intent.getType(), - SHELL_PACKAGE_NAME, mUserId); - if (cn == null) { - System.err.println("Error: Not found; no service started."); - } else if (cn.getPackageName().equals("!")) { - System.err.println("Error: Requires permission " + cn.getClassName()); - } else if (cn.getPackageName().equals("!!")) { - System.err.println("Error: " + cn.getClassName()); - } - } - - private void runStopService() throws Exception { - Intent intent = makeIntent(UserHandle.USER_CURRENT); - if (mUserId == UserHandle.USER_ALL) { - System.err.println("Error: Can't stop activity with user 'all'"); - return; - } - System.out.println("Stopping service: " + intent); - int result = mAm.stopService(null, intent, intent.getType(), mUserId); - if (result == 0) { - System.err.println("Service not stopped: was not running."); - } else if (result == 1) { - System.err.println("Service stopped"); - } else if (result == -1) { - System.err.println("Error stopping service"); - } - } - - private void runStart() throws Exception { - Intent intent = makeIntent(UserHandle.USER_CURRENT); - - if (mUserId == UserHandle.USER_ALL) { - System.err.println("Error: Can't start service with user 'all'"); - return; - } + static final class MyShellCallback extends ShellCallback { + boolean mActive = true; - String mimeType = intent.getType(); - if (mimeType == null && intent.getData() != null - && "content".equals(intent.getData().getScheme())) { - mimeType = mAm.getProviderMimeType(intent.getData(), mUserId); - } - - - do { - if (mStopOption) { - String packageName; - if (intent.getComponent() != null) { - packageName = intent.getComponent().getPackageName(); - } else { - List<ResolveInfo> activities = mPm.queryIntentActivities(intent, mimeType, 0, - mUserId).getList(); - if (activities == null || activities.size() <= 0) { - System.err.println("Error: Intent does not match any activities: " - + intent); - return; - } else if (activities.size() > 1) { - System.err.println("Error: Intent matches multiple activities; can't stop: " - + intent); - return; - } - packageName = activities.get(0).activityInfo.packageName; - } - System.out.println("Stopping: " + packageName); - mAm.forceStopPackage(packageName, mUserId); - Thread.sleep(250); + @Override public ParcelFileDescriptor onOpenOutputFile(String path, String seLinuxContext) { + if (!mActive) { + System.err.println("Open attempt after active for: " + path); + return null; } - - System.out.println("Starting: " + intent); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - - ParcelFileDescriptor fd = null; - ProfilerInfo profilerInfo = null; - - if (mProfileFile != null) { - try { - fd = openForSystemServer( - new File(mProfileFile), - ParcelFileDescriptor.MODE_CREATE | - ParcelFileDescriptor.MODE_TRUNCATE | - ParcelFileDescriptor.MODE_WRITE_ONLY); - } catch (FileNotFoundException e) { - System.err.println("Error: Unable to open file: " + mProfileFile); - System.err.println("Consider using a file under /data/local/tmp/"); - return; - } - profilerInfo = new ProfilerInfo(mProfileFile, fd, mSamplingInterval, mAutoStop); - } - - IActivityManager.WaitResult result = null; - int res; - final long startTime = SystemClock.uptimeMillis(); - ActivityOptions options = null; - if (mStackId != INVALID_STACK_ID) { - options = ActivityOptions.makeBasic(); - options.setLaunchStackId(mStackId); - } - if (mWaitOption) { - result = mAm.startActivityAndWait(null, null, intent, mimeType, - null, null, 0, mStartFlags, profilerInfo, - options != null ? options.toBundle() : null, mUserId); - res = result.result; - } else { - res = mAm.startActivityAsUser(null, null, intent, mimeType, - null, null, 0, mStartFlags, profilerInfo, - options != null ? options.toBundle() : null, mUserId); - } - final long endTime = SystemClock.uptimeMillis(); - PrintStream out = mWaitOption ? System.out : System.err; - boolean launched = false; - switch (res) { - case ActivityManager.START_SUCCESS: - launched = true; - break; - case ActivityManager.START_SWITCHES_CANCELED: - launched = true; - out.println( - "Warning: Activity not started because the " - + " current activity is being kept for the user."); - break; - case ActivityManager.START_DELIVERED_TO_TOP: - launched = true; - out.println( - "Warning: Activity not started, intent has " - + "been delivered to currently running " - + "top-most instance."); - break; - case ActivityManager.START_RETURN_INTENT_TO_CALLER: - launched = true; - out.println( - "Warning: Activity not started because intent " - + "should be handled by the caller"); - break; - case ActivityManager.START_TASK_TO_FRONT: - launched = true; - out.println( - "Warning: Activity not started, its current " - + "task has been brought to the front"); - break; - case ActivityManager.START_INTENT_NOT_RESOLVED: - out.println( - "Error: Activity not started, unable to " - + "resolve " + intent.toString()); - break; - case ActivityManager.START_CLASS_NOT_FOUND: - out.println(NO_CLASS_ERROR_CODE); - out.println("Error: Activity class " + - intent.getComponent().toShortString() - + " does not exist."); - break; - case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT: - out.println( - "Error: Activity not started, you requested to " - + "both forward and receive its result"); - break; - case ActivityManager.START_PERMISSION_DENIED: - out.println( - "Error: Activity not started, you do not " - + "have permission to access it."); - break; - case ActivityManager.START_NOT_VOICE_COMPATIBLE: - out.println( - "Error: Activity not started, voice control not allowed for: " - + intent); - break; - case ActivityManager.START_NOT_CURRENT_USER_ACTIVITY: - out.println( - "Error: Not allowed to start background user activity" - + " that shouldn't be displayed for all users."); - break; - default: - out.println( - "Error: Activity not started, unknown error code " + res); - break; + File file = new File(path); + //System.err.println("Opening file: " + file.getAbsolutePath()); + //Log.i("Am", "Opening file: " + file.getAbsolutePath()); + final ParcelFileDescriptor fd; + try { + fd = ParcelFileDescriptor.open(file, + ParcelFileDescriptor.MODE_CREATE | + ParcelFileDescriptor.MODE_TRUNCATE | + ParcelFileDescriptor.MODE_WRITE_ONLY); + } catch (FileNotFoundException e) { + String msg = "Unable to open file " + path + ": " + e; + System.err.println(msg); + throw new IllegalArgumentException(msg); } - if (mWaitOption && launched) { - if (result == null) { - result = new IActivityManager.WaitResult(); - result.who = intent.getComponent(); - } - System.out.println("Status: " + (result.timeout ? "timeout" : "ok")); - if (result.who != null) { - System.out.println("Activity: " + result.who.flattenToShortString()); - } - if (result.thisTime >= 0) { - System.out.println("ThisTime: " + result.thisTime); - } - if (result.totalTime >= 0) { - System.out.println("TotalTime: " + result.totalTime); + if (seLinuxContext != null) { + final String tcon = SELinux.getFileContext(file.getAbsolutePath()); + if (!SELinux.checkSELinuxAccess(seLinuxContext, tcon, "file", "write")) { + try { + fd.close(); + } catch (IOException e) { + } + String msg = "System server has no access to file context " + tcon; + System.err.println(msg + " (from path " + file.getAbsolutePath() + + ", context " + seLinuxContext + ")"); + throw new IllegalArgumentException(msg); } - System.out.println("WaitTime: " + (endTime-startTime)); - System.out.println("Complete"); - } - mRepeat--; - if (mRepeat > 0) { - mAm.unhandledBack(); - } - } while (mRepeat > 0); - } - - private void runForceStop() throws Exception { - int userId = UserHandle.USER_ALL; - - String opt; - while ((opt=nextOption()) != null) { - if (opt.equals("--user")) { - userId = parseUserArg(nextArgRequired()); - } else { - System.err.println("Error: Unknown option: " + opt); - return; } + return fd; } - mAm.forceStopPackage(nextArgRequired(), userId); } - private void runKill() throws Exception { - int userId = UserHandle.USER_ALL; - - String opt; - while ((opt=nextOption()) != null) { - if (opt.equals("--user")) { - userId = parseUserArg(nextArgRequired()); - } else { - System.err.println("Error: Unknown option: " + opt); - return; - } + void runAmCmd(String[] args) throws AndroidException { + final MyShellCallback cb = new MyShellCallback(); + try { + mAm.asBinder().shellCommand(FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, + args, cb, new ResultReceiver(null) { }); + } catch (RemoteException e) { + System.err.println(NO_SYSTEM_ERROR_CODE); + throw new AndroidException("Can't call activity manager; is the system running?"); + } finally { + cb.mActive = false; } - mAm.killBackgroundProcesses(nextArgRequired(), userId); } - private void runKillAll() throws Exception { - mAm.killAllBackgroundProcesses(); - } - - private void sendBroadcast() throws Exception { - Intent intent = makeIntent(UserHandle.USER_CURRENT); - IntentReceiver receiver = new IntentReceiver(); - String[] requiredPermissions = mReceiverPermission == null ? null - : new String[] {mReceiverPermission}; - System.out.println("Broadcasting: " + intent); - mAm.broadcastIntent(null, intent, null, receiver, 0, null, null, requiredPermissions, - android.app.AppOpsManager.OP_NONE, null, true, false, mUserId); - receiver.waitForFinish(); - } - - private void runInstrument() throws Exception { - String profileFile = null; - boolean wait = false; - boolean rawMode = false; - boolean no_window_animation = false; - int userId = UserHandle.USER_CURRENT; - Bundle args = new Bundle(); - String argKey = null, argValue = null; - IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window")); - String abi = null; + public void runInstrument() throws Exception { + Instrument instrument = new Instrument(mAm, mPm); String opt; while ((opt=nextOption()) != null) { if (opt.equals("-p")) { - profileFile = nextArgRequired(); + instrument.profileFile = nextArgRequired(); } else if (opt.equals("-w")) { - wait = true; + instrument.wait = true; } else if (opt.equals("-r")) { - rawMode = true; + instrument.rawMode = true; + } else if (opt.equals("-m")) { + instrument.proto = true; } else if (opt.equals("-e")) { - argKey = nextArgRequired(); - argValue = nextArgRequired(); - args.putString(argKey, argValue); + final String argKey = nextArgRequired(); + final String argValue = nextArgRequired(); + instrument.args.putString(argKey, argValue); } else if (opt.equals("--no_window_animation") || opt.equals("--no-window-animation")) { - no_window_animation = true; + instrument.noWindowAnimation = true; } else if (opt.equals("--user")) { - userId = parseUserArg(nextArgRequired()); + instrument.userId = parseUserArg(nextArgRequired()); } else if (opt.equals("--abi")) { - abi = nextArgRequired(); + instrument.abi = nextArgRequired(); } else { System.err.println("Error: Unknown option: " + opt); return; } } - if (userId == UserHandle.USER_ALL) { + if (instrument.userId == UserHandle.USER_ALL) { System.err.println("Error: Can't start instrumentation with user 'all'"); return; } - String cnArg = nextArgRequired(); - - ComponentName cn; - if (cnArg.contains("/")) { - cn = ComponentName.unflattenFromString(cnArg); - if (cn == null) throw new IllegalArgumentException("Bad component name: " + cnArg); - } else { - List<InstrumentationInfo> infos = mPm.queryInstrumentation(null, 0).getList(); - - final int numInfos = infos == null ? 0: infos.size(); - List<ComponentName> cns = new ArrayList<>(); - for (int i = 0; i < numInfos; i++) { - InstrumentationInfo info = infos.get(i); - - ComponentName c = new ComponentName(info.packageName, info.name); - if (cnArg.equals(info.packageName)) { - cns.add(c); - } - } - - if (cns.size() == 0) { - throw new IllegalArgumentException("No instrumentation found for: " + cnArg); - } else if (cns.size() == 1) { - cn = cns.get(0); - } else { - StringBuilder cnsStr = new StringBuilder(); - final int numCns = cns.size(); - for (int i = 0; i < numCns; i++) { - cnsStr.append(cns.get(i).flattenToString()); - cnsStr.append(", "); - } - - // Remove last ", " - cnsStr.setLength(cnsStr.length() - 2); - - throw new IllegalArgumentException("Found multiple instrumentations: " - + cnsStr.toString()); - } - } - - InstrumentationWatcher watcher = null; - UiAutomationConnection connection = null; - if (wait) { - watcher = new InstrumentationWatcher(); - watcher.setRawOutput(rawMode); - connection = new UiAutomationConnection(); - } - - float[] oldAnims = null; - if (no_window_animation) { - oldAnims = wm.getAnimationScales(); - wm.setAnimationScale(0, 0.0f); - wm.setAnimationScale(1, 0.0f); - } - - if (abi != null) { - final String[] supportedAbis = Build.SUPPORTED_ABIS; - boolean matched = false; - for (String supportedAbi : supportedAbis) { - if (supportedAbi.equals(abi)) { - matched = true; - break; - } - } - - if (!matched) { - throw new AndroidException( - "INSTRUMENTATION_FAILED: Unsupported instruction set " + abi); - } - } - - if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher, connection, userId, abi)) { - throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString()); - } - - if (watcher != null) { - if (!watcher.waitForFinish()) { - System.out.println("INSTRUMENTATION_ABORTED: System has crashed."); - } - } - - if (oldAnims != null) { - wm.setAnimationScales(oldAnims); - } - } - - private void runTraceIpc() throws Exception { - String op = nextArgRequired(); - if (op.equals("start")) { - runTraceIpcStart(); - } else if (op.equals("stop")) { - runTraceIpcStop(); - } else { - showError("Error: unknown command '" + op + "'"); - return; - } - } - - private void runTraceIpcStart() throws Exception { - System.out.println("Starting IPC tracing."); - mAm.startBinderTracking(); - } - - private void runTraceIpcStop() throws Exception { - String opt; - String filename = null; - while ((opt=nextOption()) != null) { - if (opt.equals("--dump-file")) { - filename = nextArgRequired(); - } else { - System.err.println("Error: Unknown option: " + opt); - return; - } - } - if (filename == null) { - System.err.println("Error: Specify filename to dump logs to."); - return; - } - - ParcelFileDescriptor fd = null; - - try { - File file = new File(filename); - file.delete(); - fd = openForSystemServer(file, - ParcelFileDescriptor.MODE_CREATE | - ParcelFileDescriptor.MODE_TRUNCATE | - ParcelFileDescriptor.MODE_WRITE_ONLY); - } catch (FileNotFoundException e) { - System.err.println("Error: Unable to open file: " + filename); - System.err.println("Consider using a file under /data/local/tmp/"); - return; - } - - ; - if (!mAm.stopBinderTrackingAndDump(fd)) { - throw new AndroidException("STOP TRACE FAILED."); - } - - System.out.println("Stopped IPC tracing. Dumping logs to: " + filename); - } - - static void removeWallOption() { - String props = SystemProperties.get("dalvik.vm.extra-opts"); - if (props != null && props.contains("-Xprofile:wallclock")) { - props = props.replace("-Xprofile:wallclock", ""); - props = props.trim(); - SystemProperties.set("dalvik.vm.extra-opts", props); - } - } - - private void runProfile() throws Exception { - String profileFile = null; - boolean start = false; - boolean wall = false; - int userId = UserHandle.USER_CURRENT; - int profileType = 0; - mSamplingInterval = 0; - - String process = null; - - String cmd = nextArgRequired(); - - if ("start".equals(cmd)) { - start = true; - String opt; - while ((opt=nextOption()) != null) { - if (opt.equals("--user")) { - userId = parseUserArg(nextArgRequired()); - } else if (opt.equals("--wall")) { - wall = true; - } else if (opt.equals("--sampling")) { - mSamplingInterval = Integer.parseInt(nextArgRequired()); - } else { - System.err.println("Error: Unknown option: " + opt); - return; - } - } - process = nextArgRequired(); - } else if ("stop".equals(cmd)) { - String opt; - while ((opt=nextOption()) != null) { - if (opt.equals("--user")) { - userId = parseUserArg(nextArgRequired()); - } else { - System.err.println("Error: Unknown option: " + opt); - return; - } - } - process = nextArg(); - } else { - // Compatibility with old syntax: process is specified first. - process = cmd; - cmd = nextArgRequired(); - if ("start".equals(cmd)) { - start = true; - } else if (!"stop".equals(cmd)) { - throw new IllegalArgumentException("Profile command " + process + " not valid"); - } - } - - if (userId == UserHandle.USER_ALL) { - System.err.println("Error: Can't profile with user 'all'"); - return; - } - - ParcelFileDescriptor fd = null; - ProfilerInfo profilerInfo = null; - - if (start) { - profileFile = nextArgRequired(); - try { - fd = openForSystemServer( - new File(profileFile), - ParcelFileDescriptor.MODE_CREATE | - ParcelFileDescriptor.MODE_TRUNCATE | - ParcelFileDescriptor.MODE_WRITE_ONLY); - } catch (FileNotFoundException e) { - System.err.println("Error: Unable to open file: " + profileFile); - System.err.println("Consider using a file under /data/local/tmp/"); - return; - } - profilerInfo = new ProfilerInfo(profileFile, fd, mSamplingInterval, false); - } - - try { - if (wall) { - // XXX doesn't work -- this needs to be set before booting. - String props = SystemProperties.get("dalvik.vm.extra-opts"); - if (props == null || !props.contains("-Xprofile:wallclock")) { - props = props + " -Xprofile:wallclock"; - //SystemProperties.set("dalvik.vm.extra-opts", props); - } - } else if (start) { - //removeWallOption(); - } - if (!mAm.profileControl(process, userId, start, profilerInfo, profileType)) { - wall = false; - throw new AndroidException("PROFILE FAILED on process " + process); - } - } finally { - if (!wall) { - //removeWallOption(); - } - } - } - - private void runDumpHeap() throws Exception { - boolean managed = true; - int userId = UserHandle.USER_CURRENT; - - String opt; - while ((opt=nextOption()) != null) { - if (opt.equals("--user")) { - userId = parseUserArg(nextArgRequired()); - if (userId == UserHandle.USER_ALL) { - System.err.println("Error: Can't dump heap with user 'all'"); - return; - } - } else if (opt.equals("-n")) { - managed = false; - } else { - System.err.println("Error: Unknown option: " + opt); - return; - } - } - String process = nextArgRequired(); - String heapFile = nextArgRequired(); - ParcelFileDescriptor fd = null; - - try { - File file = new File(heapFile); - file.delete(); - fd = openForSystemServer(file, - ParcelFileDescriptor.MODE_CREATE | - ParcelFileDescriptor.MODE_TRUNCATE | - ParcelFileDescriptor.MODE_WRITE_ONLY); - } catch (FileNotFoundException e) { - System.err.println("Error: Unable to open file: " + heapFile); - System.err.println("Consider using a file under /data/local/tmp/"); - return; - } - - if (!mAm.dumpHeap(process, userId, managed, heapFile, fd)) { - throw new AndroidException("HEAP DUMP FAILED on process " + process); - } - } - - private void runSetDebugApp() throws Exception { - boolean wait = false; - boolean persistent = false; - - String opt; - while ((opt=nextOption()) != null) { - if (opt.equals("-w")) { - wait = true; - } else if (opt.equals("--persistent")) { - persistent = true; - } else { - System.err.println("Error: Unknown option: " + opt); - return; - } - } - - String pkg = nextArgRequired(); - mAm.setDebugApp(pkg, wait, persistent); - } - - private void runClearDebugApp() throws Exception { - mAm.setDebugApp(null, false, true); - } - - private void runSetWatchHeap() throws Exception { - String proc = nextArgRequired(); - String limit = nextArgRequired(); - mAm.setDumpHeapDebugLimit(proc, 0, Long.parseLong(limit), null); - } - - private void runClearWatchHeap() throws Exception { - String proc = nextArgRequired(); - mAm.setDumpHeapDebugLimit(proc, 0, -1, null); - } - - private void runBugReport() throws Exception { - String opt; - int bugreportType = ActivityManager.BUGREPORT_OPTION_FULL; - while ((opt=nextOption()) != null) { - if (opt.equals("--progress")) { - bugreportType = ActivityManager.BUGREPORT_OPTION_INTERACTIVE; - } else { - System.err.println("Error: Unknown option: " + opt); - return; - } - } - mAm.requestBugReport(bugreportType); - System.out.println("Your lovely bug report is being created; please be patient."); - } - - private void runSwitchUser() throws Exception { - String user = nextArgRequired(); - mAm.switchUser(Integer.parseInt(user)); - } - - private void runStartUserInBackground() throws Exception { - String user = nextArgRequired(); - boolean success = mAm.startUserInBackground(Integer.parseInt(user)); - if (success) { - System.out.println("Success: user started"); - } else { - System.err.println("Error: could not start user"); - } - } - - private byte[] argToBytes(String arg) { - if (arg.equals("!")) { - return null; - } else { - return HexDump.hexStringToByteArray(arg); - } - } - - private void runUnlockUser() throws Exception { - int userId = Integer.parseInt(nextArgRequired()); - byte[] token = argToBytes(nextArgRequired()); - byte[] secret = argToBytes(nextArgRequired()); - boolean success = mAm.unlockUser(userId, token, secret, null); - if (success) { - System.out.println("Success: user unlocked"); - } else { - System.err.println("Error: could not unlock user"); - } - } - - private static class StopUserCallback extends IStopUserCallback.Stub { - private boolean mFinished = false; - - public synchronized void waitForFinish() { - try { - while (!mFinished) wait(); - } catch (InterruptedException e) { - throw new IllegalStateException(e); - } - } - - @Override - public synchronized void userStopped(int userId) { - mFinished = true; - notifyAll(); - } - - @Override - public synchronized void userStopAborted(int userId) { - mFinished = true; - notifyAll(); - } - } - - private void runStopUser() throws Exception { - boolean wait = false; - boolean force = false; - String opt; - while ((opt = nextOption()) != null) { - if ("-w".equals(opt)) { - wait = true; - } else if ("-f".equals(opt)) { - force = true; - } else { - System.err.println("Error: unknown option: " + opt); - return; - } - } - int user = Integer.parseInt(nextArgRequired()); - StopUserCallback callback = wait ? new StopUserCallback() : null; - - int res = mAm.stopUser(user, force, callback); - if (res != ActivityManager.USER_OP_SUCCESS) { - String txt = ""; - switch (res) { - case ActivityManager.USER_OP_IS_CURRENT: - txt = " (Can't stop current user)"; - break; - case ActivityManager.USER_OP_UNKNOWN_USER: - txt = " (Unknown user " + user + ")"; - break; - case ActivityManager.USER_OP_ERROR_IS_SYSTEM: - txt = " (System user cannot be stopped)"; - break; - case ActivityManager.USER_OP_ERROR_RELATED_USERS_CANNOT_STOP: - txt = " (Can't stop user " + user - + " - one of its related users can't be stopped)"; - break; - } - System.err.println("Switch failed: " + res + txt); - } else if (callback != null) { - callback.waitForFinish(); - } - } - - class MyActivityController extends IActivityController.Stub { - final String mGdbPort; - final boolean mMonkey; - - static final int STATE_NORMAL = 0; - static final int STATE_CRASHED = 1; - static final int STATE_EARLY_ANR = 2; - static final int STATE_ANR = 3; - - int mState; - - static final int RESULT_DEFAULT = 0; + instrument.componentNameArg = nextArgRequired(); - static final int RESULT_CRASH_DIALOG = 0; - static final int RESULT_CRASH_KILL = 1; - - static final int RESULT_EARLY_ANR_CONTINUE = 0; - static final int RESULT_EARLY_ANR_KILL = 1; - - static final int RESULT_ANR_DIALOG = 0; - static final int RESULT_ANR_KILL = 1; - static final int RESULT_ANR_WAIT = 1; - - int mResult; - - Process mGdbProcess; - Thread mGdbThread; - boolean mGotGdbPrint; - - MyActivityController(String gdbPort, boolean monkey) { - mGdbPort = gdbPort; - mMonkey = monkey; - } - - @Override - public boolean activityResuming(String pkg) { - synchronized (this) { - System.out.println("** Activity resuming: " + pkg); - } - return true; - } - - @Override - public boolean activityStarting(Intent intent, String pkg) { - synchronized (this) { - System.out.println("** Activity starting: " + pkg); - } - return true; - } - - @Override - public boolean appCrashed(String processName, int pid, String shortMsg, String longMsg, - long timeMillis, String stackTrace) { - synchronized (this) { - System.out.println("** ERROR: PROCESS CRASHED"); - System.out.println("processName: " + processName); - System.out.println("processPid: " + pid); - System.out.println("shortMsg: " + shortMsg); - System.out.println("longMsg: " + longMsg); - System.out.println("timeMillis: " + timeMillis); - System.out.println("stack:"); - System.out.print(stackTrace); - System.out.println("#"); - int result = waitControllerLocked(pid, STATE_CRASHED); - return result == RESULT_CRASH_KILL ? false : true; - } - } - - @Override - public int appEarlyNotResponding(String processName, int pid, String annotation) { - synchronized (this) { - System.out.println("** ERROR: EARLY PROCESS NOT RESPONDING"); - System.out.println("processName: " + processName); - System.out.println("processPid: " + pid); - System.out.println("annotation: " + annotation); - int result = waitControllerLocked(pid, STATE_EARLY_ANR); - if (result == RESULT_EARLY_ANR_KILL) return -1; - return 0; - } - } - - @Override - public int appNotResponding(String processName, int pid, String processStats) { - synchronized (this) { - System.out.println("** ERROR: PROCESS NOT RESPONDING"); - System.out.println("processName: " + processName); - System.out.println("processPid: " + pid); - System.out.println("processStats:"); - System.out.print(processStats); - System.out.println("#"); - int result = waitControllerLocked(pid, STATE_ANR); - if (result == RESULT_ANR_KILL) return -1; - if (result == RESULT_ANR_WAIT) return 1; - return 0; - } - } - - @Override - public int systemNotResponding(String message) { - synchronized (this) { - System.out.println("** ERROR: PROCESS NOT RESPONDING"); - System.out.println("message: " + message); - System.out.println("#"); - System.out.println("Allowing system to die."); - return -1; - } - } - - void killGdbLocked() { - mGotGdbPrint = false; - if (mGdbProcess != null) { - System.out.println("Stopping gdbserver"); - mGdbProcess.destroy(); - mGdbProcess = null; - } - if (mGdbThread != null) { - mGdbThread.interrupt(); - mGdbThread = null; - } - } - - int waitControllerLocked(int pid, int state) { - if (mGdbPort != null) { - killGdbLocked(); - - try { - System.out.println("Starting gdbserver on port " + mGdbPort); - System.out.println("Do the following:"); - System.out.println(" adb forward tcp:" + mGdbPort + " tcp:" + mGdbPort); - System.out.println(" gdbclient app_process :" + mGdbPort); - - mGdbProcess = Runtime.getRuntime().exec(new String[] { - "gdbserver", ":" + mGdbPort, "--attach", Integer.toString(pid) - }); - final InputStreamReader converter = new InputStreamReader( - mGdbProcess.getInputStream()); - mGdbThread = new Thread() { - @Override - public void run() { - BufferedReader in = new BufferedReader(converter); - String line; - int count = 0; - while (true) { - synchronized (MyActivityController.this) { - if (mGdbThread == null) { - return; - } - if (count == 2) { - mGotGdbPrint = true; - MyActivityController.this.notifyAll(); - } - } - try { - line = in.readLine(); - if (line == null) { - return; - } - System.out.println("GDB: " + line); - count++; - } catch (IOException e) { - return; - } - } - } - }; - mGdbThread.start(); - - // Stupid waiting for .5s. Doesn't matter if we end early. - try { - this.wait(500); - } catch (InterruptedException e) { - } - - } catch (IOException e) { - System.err.println("Failure starting gdbserver: " + e); - killGdbLocked(); - } - } - mState = state; - System.out.println(""); - printMessageForState(); - - while (mState != STATE_NORMAL) { - try { - wait(); - } catch (InterruptedException e) { - } - } - - killGdbLocked(); - - return mResult; - } - - void resumeController(int result) { - synchronized (this) { - mState = STATE_NORMAL; - mResult = result; - notifyAll(); - } - } - - void printMessageForState() { - switch (mState) { - case STATE_NORMAL: - System.out.println("Monitoring activity manager... available commands:"); - break; - case STATE_CRASHED: - System.out.println("Waiting after crash... available commands:"); - System.out.println("(c)ontinue: show crash dialog"); - System.out.println("(k)ill: immediately kill app"); - break; - case STATE_EARLY_ANR: - System.out.println("Waiting after early ANR... available commands:"); - System.out.println("(c)ontinue: standard ANR processing"); - System.out.println("(k)ill: immediately kill app"); - break; - case STATE_ANR: - System.out.println("Waiting after ANR... available commands:"); - System.out.println("(c)ontinue: show ANR dialog"); - System.out.println("(k)ill: immediately kill app"); - System.out.println("(w)ait: wait some more"); - break; - } - System.out.println("(q)uit: finish monitoring"); - } - - void run() throws RemoteException { - try { - printMessageForState(); - - mAm.setActivityController(this, mMonkey); - mState = STATE_NORMAL; - - InputStreamReader converter = new InputStreamReader(System.in); - BufferedReader in = new BufferedReader(converter); - String line; - - while ((line = in.readLine()) != null) { - boolean addNewline = true; - if (line.length() <= 0) { - addNewline = false; - } else if ("q".equals(line) || "quit".equals(line)) { - resumeController(RESULT_DEFAULT); - break; - } else if (mState == STATE_CRASHED) { - if ("c".equals(line) || "continue".equals(line)) { - resumeController(RESULT_CRASH_DIALOG); - } else if ("k".equals(line) || "kill".equals(line)) { - resumeController(RESULT_CRASH_KILL); - } else { - System.out.println("Invalid command: " + line); - } - } else if (mState == STATE_ANR) { - if ("c".equals(line) || "continue".equals(line)) { - resumeController(RESULT_ANR_DIALOG); - } else if ("k".equals(line) || "kill".equals(line)) { - resumeController(RESULT_ANR_KILL); - } else if ("w".equals(line) || "wait".equals(line)) { - resumeController(RESULT_ANR_WAIT); - } else { - System.out.println("Invalid command: " + line); - } - } else if (mState == STATE_EARLY_ANR) { - if ("c".equals(line) || "continue".equals(line)) { - resumeController(RESULT_EARLY_ANR_CONTINUE); - } else if ("k".equals(line) || "kill".equals(line)) { - resumeController(RESULT_EARLY_ANR_KILL); - } else { - System.out.println("Invalid command: " + line); - } - } else { - System.out.println("Invalid command: " + line); - } - - synchronized (this) { - if (addNewline) { - System.out.println(""); - } - printMessageForState(); - } - } - - } catch (IOException e) { - e.printStackTrace(); - } finally { - mAm.setActivityController(null, mMonkey); - } - } - } - - private void runMonitor() throws Exception { - String opt; - String gdbPort = null; - boolean monkey = false; - while ((opt=nextOption()) != null) { - if (opt.equals("--gdb")) { - gdbPort = nextArgRequired(); - } else if (opt.equals("-m")) { - monkey = true; - } else { - System.err.println("Error: Unknown option: " + opt); - return; - } - } - - MyActivityController controller = new MyActivityController(gdbPort, monkey); - controller.run(); - } - - private void runHang() throws Exception { - String opt; - boolean allowRestart = false; - while ((opt=nextOption()) != null) { - if (opt.equals("--allow-restart")) { - allowRestart = true; - } else { - System.err.println("Error: Unknown option: " + opt); - return; - } - } - - System.out.println("Hanging the system..."); - mAm.hang(new Binder(), allowRestart); - } - - private void runRestart() throws Exception { - String opt; - while ((opt=nextOption()) != null) { - System.err.println("Error: Unknown option: " + opt); - return; - } - - System.out.println("Restart the system..."); - mAm.restart(); - } - - private void runIdleMaintenance() throws Exception { - String opt; - while ((opt=nextOption()) != null) { - System.err.println("Error: Unknown option: " + opt); - return; - } - - System.out.println("Performing idle maintenance..."); - try { - mAm.sendIdleJobTrigger(); - } catch (RemoteException e) { - } - } - - private void runScreenCompat() throws Exception { - String mode = nextArgRequired(); - boolean enabled; - if ("on".equals(mode)) { - enabled = true; - } else if ("off".equals(mode)) { - enabled = false; - } else { - System.err.println("Error: enabled mode must be 'on' or 'off' at " + mode); - return; - } - - String packageName = nextArgRequired(); - do { - try { - mAm.setPackageScreenCompatMode(packageName, enabled - ? ActivityManager.COMPAT_MODE_ENABLED - : ActivityManager.COMPAT_MODE_DISABLED); - } catch (RemoteException e) { - } - packageName = nextArg(); - } while (packageName != null); - } - - private void runPackageImportance() throws Exception { - String packageName = nextArgRequired(); - try { - int procState = mAm.getPackageProcessState(packageName, "com.android.shell"); - System.out.println( - ActivityManager.RunningAppProcessInfo.procStateToImportance(procState)); - } catch (RemoteException e) { - } - } - - private void runToUri(int flags) throws Exception { - Intent intent = makeIntent(UserHandle.USER_CURRENT); - System.out.println(intent.toUri(flags)); - } - - private class IntentReceiver extends IIntentReceiver.Stub { - private boolean mFinished = false; - - @Override - public void performReceive(Intent intent, int resultCode, String data, Bundle extras, - boolean ordered, boolean sticky, int sendingUser) { - String line = "Broadcast completed: result=" + resultCode; - if (data != null) line = line + ", data=\"" + data + "\""; - if (extras != null) line = line + ", extras: " + extras; - System.out.println(line); - synchronized (this) { - mFinished = true; - notifyAll(); - } - } - - public synchronized void waitForFinish() { - try { - while (!mFinished) wait(); - } catch (InterruptedException e) { - throw new IllegalStateException(e); - } - } - } - - private class InstrumentationWatcher extends IInstrumentationWatcher.Stub { - private boolean mFinished = false; - private boolean mRawMode = false; - - /** - * Set or reset "raw mode". In "raw mode", all bundles are dumped. In "pretty mode", - * if a bundle includes Instrumentation.REPORT_KEY_STREAMRESULT, just print that. - * @param rawMode true for raw mode, false for pretty mode. - */ - public void setRawOutput(boolean rawMode) { - mRawMode = rawMode; - } - - @Override - public void instrumentationStatus(ComponentName name, int resultCode, Bundle results) { - synchronized (this) { - // pretty printer mode? - String pretty = null; - if (!mRawMode && results != null) { - pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT); - } - if (pretty != null) { - System.out.print(pretty); - } else { - if (results != null) { - for (String key : results.keySet()) { - System.out.println( - "INSTRUMENTATION_STATUS: " + key + "=" + results.get(key)); - } - } - System.out.println("INSTRUMENTATION_STATUS_CODE: " + resultCode); - } - notifyAll(); - } - } - - @Override - public void instrumentationFinished(ComponentName name, int resultCode, - Bundle results) { - synchronized (this) { - // pretty printer mode? - String pretty = null; - if (!mRawMode && results != null) { - pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT); - } - if (pretty != null) { - System.out.println(pretty); - } else { - if (results != null) { - for (String key : results.keySet()) { - System.out.println( - "INSTRUMENTATION_RESULT: " + key + "=" + results.get(key)); - } - } - System.out.println("INSTRUMENTATION_CODE: " + resultCode); - } - mFinished = true; - notifyAll(); - } - } - - public boolean waitForFinish() { - synchronized (this) { - while (!mFinished) { - try { - if (!mAm.asBinder().pingBinder()) { - return false; - } - wait(1000); - } catch (InterruptedException e) { - throw new IllegalStateException(e); - } - } - } - return true; - } - } - - private void runStack() throws Exception { - String op = nextArgRequired(); - switch (op) { - case "start": - runStackStart(); - break; - case "movetask": - runStackMoveTask(); - break; - case "resize": - runStackResize(); - break; - case "resize-animated": - runStackResizeAnimated(); - break; - case "resize-docked-stack": - runStackResizeDocked(); - break; - case "positiontask": - runStackPositionTask(); - break; - case "list": - runStackList(); - break; - case "info": - runStackInfo(); - break; - case "move-top-activity-to-pinned-stack": - runMoveTopActivityToPinnedStack(); - break; - case "size-docked-stack-test": - runStackSizeDockedStackTest(); - break; - case "remove": - runStackRemove(); - break; - default: - showError("Error: unknown command '" + op + "'"); - break; - } - } - - private void runStackStart() throws Exception { - String displayIdStr = nextArgRequired(); - int displayId = Integer.parseInt(displayIdStr); - Intent intent = makeIntent(UserHandle.USER_CURRENT); - - try { - IActivityContainer container = mAm.createStackOnDisplay(displayId); - if (container != null) { - container.startActivity(intent); - } - } catch (RemoteException e) { - } - } - - private void runStackMoveTask() throws Exception { - String taskIdStr = nextArgRequired(); - int taskId = Integer.parseInt(taskIdStr); - String stackIdStr = nextArgRequired(); - int stackId = Integer.parseInt(stackIdStr); - String toTopStr = nextArgRequired(); - final boolean toTop; - if ("true".equals(toTopStr)) { - toTop = true; - } else if ("false".equals(toTopStr)) { - toTop = false; - } else { - System.err.println("Error: bad toTop arg: " + toTopStr); - return; - } - - try { - mAm.moveTaskToStack(taskId, stackId, toTop); - } catch (RemoteException e) { - } - } - - private void runStackResize() throws Exception { - String stackIdStr = nextArgRequired(); - int stackId = Integer.parseInt(stackIdStr); - final Rect bounds = getBounds(); - if (bounds == null) { - System.err.println("Error: invalid input bounds"); - return; - } - resizeStack(stackId, bounds, 0); - } - - private void runStackResizeAnimated() throws Exception { - String stackIdStr = nextArgRequired(); - int stackId = Integer.parseInt(stackIdStr); - final Rect bounds; - if ("null".equals(mArgs.peekNextArg())) { - bounds = null; - } else { - bounds = getBounds(); - if (bounds == null) { - System.err.println("Error: invalid input bounds"); - return; - } - } - resizeStackUnchecked(stackId, bounds, 0, true); - } - - private void resizeStackUnchecked(int stackId, Rect bounds, int delayMs, boolean animate) { - try { - mAm.resizeStack(stackId, bounds, false, false, animate, -1); - Thread.sleep(delayMs); - } catch (RemoteException e) { - showError("Error: resizing stack " + e); - } catch (InterruptedException e) { - } - } - - private void runStackResizeDocked() throws Exception { - final Rect bounds = getBounds(); - final Rect taskBounds = getBounds(); - if (bounds == null || taskBounds == null) { - System.err.println("Error: invalid input bounds"); - return; - } - try { - mAm.resizeDockedStack(bounds, taskBounds, null, null, null); - } catch (RemoteException e) { - showError("Error: resizing docked stack " + e); - } - } - - private void resizeStack(int stackId, Rect bounds, int delayMs) - throws Exception { - if (bounds == null) { - showError("Error: invalid input bounds"); - return; - } - resizeStackUnchecked(stackId, bounds, delayMs, false); - } - - private void runStackPositionTask() throws Exception { - String taskIdStr = nextArgRequired(); - int taskId = Integer.parseInt(taskIdStr); - String stackIdStr = nextArgRequired(); - int stackId = Integer.parseInt(stackIdStr); - String positionStr = nextArgRequired(); - int position = Integer.parseInt(positionStr); - - try { - mAm.positionTaskInStack(taskId, stackId, position); - } catch (RemoteException e) { - } - } - - private void runStackList() throws Exception { - try { - List<StackInfo> stacks = mAm.getAllStackInfos(); - for (StackInfo info : stacks) { - System.out.println(info); - } - } catch (RemoteException e) { - } - } - - private void runStackInfo() throws Exception { - try { - String stackIdStr = nextArgRequired(); - int stackId = Integer.parseInt(stackIdStr); - StackInfo info = mAm.getStackInfo(stackId); - System.out.println(info); - } catch (RemoteException e) { - } - } - - private void runStackRemove() throws Exception { - String stackIdStr = nextArgRequired(); - int stackId = Integer.parseInt(stackIdStr); - mAm.removeStack(stackId); - } - - private void runMoveTopActivityToPinnedStack() throws Exception { - int stackId = Integer.parseInt(nextArgRequired()); - final Rect bounds = getBounds(); - if (bounds == null) { - System.err.println("Error: invalid input bounds"); - return; - } - - try { - if (!mAm.moveTopActivityToPinnedStack(stackId, bounds)) { - showError("Didn't move top activity to pinned stack."); - } - } catch (RemoteException e) { - showError("Unable to move top activity: " + e); - return; - } - } - - private void runStackSizeDockedStackTest() throws Exception { - final int stepSize = Integer.parseInt(nextArgRequired()); - final String side = nextArgRequired(); - final String delayStr = nextArg(); - final int delayMs = (delayStr != null) ? Integer.parseInt(delayStr) : 0; - - Rect bounds; - try { - StackInfo info = mAm.getStackInfo(DOCKED_STACK_ID); - if (info == null) { - showError("Docked stack doesn't exist"); - return; - } - if (info.bounds == null) { - showError("Docked stack doesn't have a bounds"); - return; - } - bounds = info.bounds; - } catch (RemoteException e) { - showError("Unable to get docked stack info:" + e); - return; - } - - final boolean horizontalGrowth = "l".equals(side) || "r".equals(side); - final int changeSize = (horizontalGrowth ? bounds.width() : bounds.height()) / 2; - int currentPoint; - switch (side) { - case "l": - currentPoint = bounds.left; - break; - case "r": - currentPoint = bounds.right; - break; - case "t": - currentPoint = bounds.top; - break; - case "b": - currentPoint = bounds.bottom; - break; - default: - showError("Unknown growth side: " + side); - return; - } - - final int startPoint = currentPoint; - final int minPoint = currentPoint - changeSize; - final int maxPoint = currentPoint + changeSize; - - int maxChange; - System.out.println("Shrinking docked stack side=" + side); - while (currentPoint > minPoint) { - maxChange = Math.min(stepSize, currentPoint - minPoint); - currentPoint -= maxChange; - setBoundsSide(bounds, side, currentPoint); - resizeStack(DOCKED_STACK_ID, bounds, delayMs); - } - - System.out.println("Growing docked stack side=" + side); - while (currentPoint < maxPoint) { - maxChange = Math.min(stepSize, maxPoint - currentPoint); - currentPoint += maxChange; - setBoundsSide(bounds, side, currentPoint); - resizeStack(DOCKED_STACK_ID, bounds, delayMs); - } - - System.out.println("Back to Original size side=" + side); - while (currentPoint > startPoint) { - maxChange = Math.min(stepSize, currentPoint - startPoint); - currentPoint -= maxChange; - setBoundsSide(bounds, side, currentPoint); - resizeStack(DOCKED_STACK_ID, bounds, delayMs); - } - } - - private void setBoundsSide(Rect bounds, String side, int value) { - switch (side) { - case "l": - bounds.left = value; - break; - case "r": - bounds.right = value; - break; - case "t": - bounds.top = value; - break; - case "b": - bounds.bottom = value; - break; - default: - showError("Unknown set side: " + side); - break; - } - } - - private void runTask() throws Exception { - String op = nextArgRequired(); - if (op.equals("lock")) { - runTaskLock(); - } else if (op.equals("resizeable")) { - runTaskResizeable(); - } else if (op.equals("resize")) { - runTaskResize(); - } else if (op.equals("drag-task-test")) { - runTaskDragTaskTest(); - } else if (op.equals("size-task-test")) { - runTaskSizeTaskTest(); - } else { - showError("Error: unknown command '" + op + "'"); - return; - } - } - - private void runTaskLock() throws Exception { - String taskIdStr = nextArgRequired(); - try { - if (taskIdStr.equals("stop")) { - mAm.stopLockTaskMode(); - } else { - int taskId = Integer.parseInt(taskIdStr); - mAm.startLockTaskMode(taskId); - } - System.err.println("Activity manager is " + (mAm.isInLockTaskMode() ? "" : "not ") + - "in lockTaskMode"); - } catch (RemoteException e) { - } - } - - private void runTaskResizeable() throws Exception { - final String taskIdStr = nextArgRequired(); - final int taskId = Integer.parseInt(taskIdStr); - final String resizeableStr = nextArgRequired(); - final int resizeableMode = Integer.parseInt(resizeableStr); - - try { - mAm.setTaskResizeable(taskId, resizeableMode); - } catch (RemoteException e) { - } - } - - private void runTaskResize() throws Exception { - final String taskIdStr = nextArgRequired(); - final int taskId = Integer.parseInt(taskIdStr); - final Rect bounds = getBounds(); - if (bounds == null) { - System.err.println("Error: invalid input bounds"); - return; - } - taskResize(taskId, bounds, 0, false); - } - - private void taskResize(int taskId, Rect bounds, int delay_ms, boolean pretendUserResize) { - try { - final int resizeMode = pretendUserResize ? RESIZE_MODE_USER : RESIZE_MODE_SYSTEM; - mAm.resizeTask(taskId, bounds, resizeMode); - Thread.sleep(delay_ms); - } catch (RemoteException e) { - System.err.println("Error changing task bounds: " + e); - } catch (InterruptedException e) { - } - } - - private void runTaskDragTaskTest() { - final int taskId = Integer.parseInt(nextArgRequired()); - final int stepSize = Integer.parseInt(nextArgRequired()); - final String delayStr = nextArg(); - final int delay_ms = (delayStr != null) ? Integer.parseInt(delayStr) : 0; - final StackInfo stackInfo; - Rect taskBounds; - try { - stackInfo = mAm.getStackInfo(mAm.getFocusedStackId()); - taskBounds = mAm.getTaskBounds(taskId); - } catch (RemoteException e) { - System.err.println("Error getting focus stack info or task bounds: " + e); - return; - } - final Rect stackBounds = stackInfo.bounds; - int travelRight = stackBounds.width() - taskBounds.width(); - int travelLeft = -travelRight; - int travelDown = stackBounds.height() - taskBounds.height(); - int travelUp = -travelDown; - int passes = 0; - - // We do 2 passes to get back to the original location of the task. - while (passes < 2) { - // Move right - System.out.println("Moving right..."); - travelRight = moveTask(taskId, taskBounds, stackBounds, stepSize, - travelRight, MOVING_FORWARD, MOVING_HORIZONTALLY, delay_ms); - System.out.println("Still need to travel right by " + travelRight); - - // Move down - System.out.println("Moving down..."); - travelDown = moveTask(taskId, taskBounds, stackBounds, stepSize, - travelDown, MOVING_FORWARD, !MOVING_HORIZONTALLY, delay_ms); - System.out.println("Still need to travel down by " + travelDown); - - // Move left - System.out.println("Moving left..."); - travelLeft = moveTask(taskId, taskBounds, stackBounds, stepSize, - travelLeft, !MOVING_FORWARD, MOVING_HORIZONTALLY, delay_ms); - System.out.println("Still need to travel left by " + travelLeft); - - // Move up - System.out.println("Moving up..."); - travelUp = moveTask(taskId, taskBounds, stackBounds, stepSize, - travelUp, !MOVING_FORWARD, !MOVING_HORIZONTALLY, delay_ms); - System.out.println("Still need to travel up by " + travelUp); - - try { - taskBounds = mAm.getTaskBounds(taskId); - } catch (RemoteException e) { - System.err.println("Error getting task bounds: " + e); - return; - } - passes++; - } - } - - private int moveTask(int taskId, Rect taskRect, Rect stackRect, int stepSize, - int maxToTravel, boolean movingForward, boolean horizontal, int delay_ms) { - int maxMove; - if (movingForward) { - while (maxToTravel > 0 - && ((horizontal && taskRect.right < stackRect.right) - ||(!horizontal && taskRect.bottom < stackRect.bottom))) { - if (horizontal) { - maxMove = Math.min(stepSize, stackRect.right - taskRect.right); - maxToTravel -= maxMove; - taskRect.right += maxMove; - taskRect.left += maxMove; - } else { - maxMove = Math.min(stepSize, stackRect.bottom - taskRect.bottom); - maxToTravel -= maxMove; - taskRect.top += maxMove; - taskRect.bottom += maxMove; - } - taskResize(taskId, taskRect, delay_ms, false); - } - } else { - while (maxToTravel < 0 - && ((horizontal && taskRect.left > stackRect.left) - ||(!horizontal && taskRect.top > stackRect.top))) { - if (horizontal) { - maxMove = Math.min(stepSize, taskRect.left - stackRect.left); - maxToTravel -= maxMove; - taskRect.right -= maxMove; - taskRect.left -= maxMove; - } else { - maxMove = Math.min(stepSize, taskRect.top - stackRect.top); - maxToTravel -= maxMove; - taskRect.top -= maxMove; - taskRect.bottom -= maxMove; - } - taskResize(taskId, taskRect, delay_ms, false); - } - } - // Return the remaining distance we didn't travel because we reached the target location. - return maxToTravel; - } - - private void runTaskSizeTaskTest() { - final int taskId = Integer.parseInt(nextArgRequired()); - final int stepSize = Integer.parseInt(nextArgRequired()); - final String delayStr = nextArg(); - final int delay_ms = (delayStr != null) ? Integer.parseInt(delayStr) : 0; - final StackInfo stackInfo; - final Rect initialTaskBounds; - try { - stackInfo = mAm.getStackInfo(mAm.getFocusedStackId()); - initialTaskBounds = mAm.getTaskBounds(taskId); - } catch (RemoteException e) { - System.err.println("Error getting focus stack info or task bounds: " + e); - return; - } - final Rect stackBounds = stackInfo.bounds; - stackBounds.inset(STACK_BOUNDS_INSET, STACK_BOUNDS_INSET); - final Rect currentTaskBounds = new Rect(initialTaskBounds); - - // Size by top-left - System.out.println("Growing top-left"); - do { - currentTaskBounds.top -= getStepSize( - currentTaskBounds.top, stackBounds.top, stepSize, GREATER_THAN_TARGET); - - currentTaskBounds.left -= getStepSize( - currentTaskBounds.left, stackBounds.left, stepSize, GREATER_THAN_TARGET); - - taskResize(taskId, currentTaskBounds, delay_ms, true); - } while (stackBounds.top < currentTaskBounds.top - || stackBounds.left < currentTaskBounds.left); - - // Back to original size - System.out.println("Shrinking top-left"); - do { - currentTaskBounds.top += getStepSize( - currentTaskBounds.top, initialTaskBounds.top, stepSize, !GREATER_THAN_TARGET); - - currentTaskBounds.left += getStepSize( - currentTaskBounds.left, initialTaskBounds.left, stepSize, !GREATER_THAN_TARGET); - - taskResize(taskId, currentTaskBounds, delay_ms, true); - } while (initialTaskBounds.top > currentTaskBounds.top - || initialTaskBounds.left > currentTaskBounds.left); - - // Size by top-right - System.out.println("Growing top-right"); - do { - currentTaskBounds.top -= getStepSize( - currentTaskBounds.top, stackBounds.top, stepSize, GREATER_THAN_TARGET); - - currentTaskBounds.right += getStepSize( - currentTaskBounds.right, stackBounds.right, stepSize, !GREATER_THAN_TARGET); - - taskResize(taskId, currentTaskBounds, delay_ms, true); - } while (stackBounds.top < currentTaskBounds.top - || stackBounds.right > currentTaskBounds.right); - - // Back to original size - System.out.println("Shrinking top-right"); - do { - currentTaskBounds.top += getStepSize( - currentTaskBounds.top, initialTaskBounds.top, stepSize, !GREATER_THAN_TARGET); - - currentTaskBounds.right -= getStepSize(currentTaskBounds.right, initialTaskBounds.right, - stepSize, GREATER_THAN_TARGET); - - taskResize(taskId, currentTaskBounds, delay_ms, true); - } while (initialTaskBounds.top > currentTaskBounds.top - || initialTaskBounds.right < currentTaskBounds.right); - - // Size by bottom-left - System.out.println("Growing bottom-left"); - do { - currentTaskBounds.bottom += getStepSize( - currentTaskBounds.bottom, stackBounds.bottom, stepSize, !GREATER_THAN_TARGET); - - currentTaskBounds.left -= getStepSize( - currentTaskBounds.left, stackBounds.left, stepSize, GREATER_THAN_TARGET); - - taskResize(taskId, currentTaskBounds, delay_ms, true); - } while (stackBounds.bottom > currentTaskBounds.bottom - || stackBounds.left < currentTaskBounds.left); - - // Back to original size - System.out.println("Shrinking bottom-left"); - do { - currentTaskBounds.bottom -= getStepSize(currentTaskBounds.bottom, - initialTaskBounds.bottom, stepSize, GREATER_THAN_TARGET); - - currentTaskBounds.left += getStepSize( - currentTaskBounds.left, initialTaskBounds.left, stepSize, !GREATER_THAN_TARGET); - - taskResize(taskId, currentTaskBounds, delay_ms, true); - } while (initialTaskBounds.bottom < currentTaskBounds.bottom - || initialTaskBounds.left > currentTaskBounds.left); - - // Size by bottom-right - System.out.println("Growing bottom-right"); - do { - currentTaskBounds.bottom += getStepSize( - currentTaskBounds.bottom, stackBounds.bottom, stepSize, !GREATER_THAN_TARGET); - - currentTaskBounds.right += getStepSize( - currentTaskBounds.right, stackBounds.right, stepSize, !GREATER_THAN_TARGET); - - taskResize(taskId, currentTaskBounds, delay_ms, true); - } while (stackBounds.bottom > currentTaskBounds.bottom - || stackBounds.right > currentTaskBounds.right); - - // Back to original size - System.out.println("Shrinking bottom-right"); - do { - currentTaskBounds.bottom -= getStepSize(currentTaskBounds.bottom, - initialTaskBounds.bottom, stepSize, GREATER_THAN_TARGET); - - currentTaskBounds.right -= getStepSize(currentTaskBounds.right, initialTaskBounds.right, - stepSize, GREATER_THAN_TARGET); - - taskResize(taskId, currentTaskBounds, delay_ms, true); - } while (initialTaskBounds.bottom < currentTaskBounds.bottom - || initialTaskBounds.right < currentTaskBounds.right); - } - - private int getStepSize(int current, int target, int inStepSize, boolean greaterThanTarget) { - int stepSize = 0; - if (greaterThanTarget && target < current) { - current -= inStepSize; - stepSize = inStepSize; - if (target > current) { - stepSize -= (target - current); - } - } - if (!greaterThanTarget && target > current) { - current += inStepSize; - stepSize = inStepSize; - if (target < current) { - stepSize += (current - target); - } - } - return stepSize; - } - - private List<Configuration> getRecentConfigurations(int days) { - IUsageStatsManager usm = IUsageStatsManager.Stub.asInterface(ServiceManager.getService( - Context.USAGE_STATS_SERVICE)); - final long now = System.currentTimeMillis(); - final long nDaysAgo = now - (days * 24 * 60 * 60 * 1000); - try { - @SuppressWarnings("unchecked") - ParceledListSlice<ConfigurationStats> configStatsSlice = usm.queryConfigurationStats( - UsageStatsManager.INTERVAL_BEST, nDaysAgo, now, "com.android.shell"); - if (configStatsSlice == null) { - return Collections.emptyList(); - } - - final ArrayMap<Configuration, Integer> recentConfigs = new ArrayMap<>(); - final List<ConfigurationStats> configStatsList = configStatsSlice.getList(); - final int configStatsListSize = configStatsList.size(); - for (int i = 0; i < configStatsListSize; i++) { - final ConfigurationStats stats = configStatsList.get(i); - final int indexOfKey = recentConfigs.indexOfKey(stats.getConfiguration()); - if (indexOfKey < 0) { - recentConfigs.put(stats.getConfiguration(), stats.getActivationCount()); - } else { - recentConfigs.setValueAt(indexOfKey, - recentConfigs.valueAt(indexOfKey) + stats.getActivationCount()); - } - } - - final Comparator<Configuration> comparator = new Comparator<Configuration>() { - @Override - public int compare(Configuration a, Configuration b) { - return recentConfigs.get(b).compareTo(recentConfigs.get(a)); - } - }; - - ArrayList<Configuration> configs = new ArrayList<>(recentConfigs.size()); - configs.addAll(recentConfigs.keySet()); - Collections.sort(configs, comparator); - return configs; - - } catch (RemoteException e) { - return Collections.emptyList(); - } - } - - private void runGetConfig() throws Exception { - int days = 14; - String option = nextOption(); - if (option != null) { - if (!option.equals("--days")) { - throw new IllegalArgumentException("unrecognized option " + option); - } - - days = Integer.parseInt(nextArgRequired()); - if (days <= 0) { - throw new IllegalArgumentException("--days must be a positive integer"); - } - } - - try { - Configuration config = mAm.getConfiguration(); - if (config == null) { - System.err.println("Activity manager has no configuration"); - return; - } - - System.out.println("config: " + Configuration.resourceQualifierString(config)); - System.out.println("abi: " + TextUtils.join(",", Build.SUPPORTED_ABIS)); - - final List<Configuration> recentConfigs = getRecentConfigurations(days); - final int recentConfigSize = recentConfigs.size(); - if (recentConfigSize > 0) { - System.out.println("recentConfigs:"); - } - - for (int i = 0; i < recentConfigSize; i++) { - System.out.println(" config: " + Configuration.resourceQualifierString( - recentConfigs.get(i))); - } - - } catch (RemoteException e) { - } - } - - private void runSuppressResizeConfigChanges() throws Exception { - boolean suppress = Boolean.valueOf(nextArgRequired()); - - try { - mAm.suppressResizeConfigChanges(suppress); - } catch (RemoteException e) { - System.err.println("Error suppressing resize config changes: " + e); - } - } - - private void runSetInactive() throws Exception { - int userId = UserHandle.USER_CURRENT; - - String opt; - while ((opt=nextOption()) != null) { - if (opt.equals("--user")) { - userId = parseUserArg(nextArgRequired()); - } else { - System.err.println("Error: Unknown option: " + opt); - return; - } - } - String packageName = nextArgRequired(); - String value = nextArgRequired(); - - IUsageStatsManager usm = IUsageStatsManager.Stub.asInterface(ServiceManager.getService( - Context.USAGE_STATS_SERVICE)); - usm.setAppInactive(packageName, Boolean.parseBoolean(value), userId); - } - - private void runGetInactive() throws Exception { - int userId = UserHandle.USER_CURRENT; - - String opt; - while ((opt=nextOption()) != null) { - if (opt.equals("--user")) { - userId = parseUserArg(nextArgRequired()); - } else { - System.err.println("Error: Unknown option: " + opt); - return; - } - } - String packageName = nextArgRequired(); - - IUsageStatsManager usm = IUsageStatsManager.Stub.asInterface(ServiceManager.getService( - Context.USAGE_STATS_SERVICE)); - boolean isIdle = usm.isAppInactive(packageName, userId); - System.out.println("Idle=" + isIdle); - } - - private void runSendTrimMemory() throws Exception { - int userId = UserHandle.USER_CURRENT; - String opt; - while ((opt = nextOption()) != null) { - if (opt.equals("--user")) { - userId = parseUserArg(nextArgRequired()); - if (userId == UserHandle.USER_ALL) { - System.err.println("Error: Can't use user 'all'"); - return; - } - } else { - System.err.println("Error: Unknown option: " + opt); - return; - } - } - - String proc = nextArgRequired(); - String levelArg = nextArgRequired(); - int level; - switch (levelArg) { - case "HIDDEN": - level = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN; - break; - case "RUNNING_MODERATE": - level = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE; - break; - case "BACKGROUND": - level = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND; - break; - case "RUNNING_LOW": - level = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW; - break; - case "MODERATE": - level = ComponentCallbacks2.TRIM_MEMORY_MODERATE; - break; - case "RUNNING_CRITICAL": - level = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL; - break; - case "COMPLETE": - level = ComponentCallbacks2.TRIM_MEMORY_COMPLETE; - break; - default: - System.err.println("Error: Unknown level option: " + levelArg); - return; - } - if (!mAm.setProcessMemoryTrimLevel(proc, userId, level)) { - System.err.println("Error: Failure to set the level - probably Unknown Process: " + - proc); - } - } - - private void runGetCurrentUser() throws Exception { - UserInfo currentUser = Preconditions.checkNotNull(mAm.getCurrentUser(), - "Current user not set"); - System.out.println(currentUser.id); - } - - /** - * Open the given file for sending into the system process. This verifies - * with SELinux that the system will have access to the file. - */ - private static ParcelFileDescriptor openForSystemServer(File file, int mode) - throws FileNotFoundException { - final ParcelFileDescriptor fd = ParcelFileDescriptor.open(file, mode); - final String tcon = SELinux.getFileContext(file.getAbsolutePath()); - if (!SELinux.checkSELinuxAccess("u:r:system_server:s0", tcon, "file", "read")) { - throw new FileNotFoundException("System server has no access to file context " + tcon); - } - return fd; - } - - private Rect getBounds() { - String leftStr = nextArgRequired(); - int left = Integer.parseInt(leftStr); - String topStr = nextArgRequired(); - int top = Integer.parseInt(topStr); - String rightStr = nextArgRequired(); - int right = Integer.parseInt(rightStr); - String bottomStr = nextArgRequired(); - int bottom = Integer.parseInt(bottomStr); - if (left < 0) { - System.err.println("Error: bad left arg: " + leftStr); - return null; - } - if (top < 0) { - System.err.println("Error: bad top arg: " + topStr); - return null; - } - if (right <= 0) { - System.err.println("Error: bad right arg: " + rightStr); - return null; - } - if (bottom <= 0) { - System.err.println("Error: bad bottom arg: " + bottomStr); - return null; - } - return new Rect(left, top, right, bottom); + instrument.run(); } } diff --git a/cmds/am/src/com/android/commands/am/Instrument.java b/cmds/am/src/com/android/commands/am/Instrument.java new file mode 100644 index 000000000000..8eefd256a69d --- /dev/null +++ b/cmds/am/src/com/android/commands/am/Instrument.java @@ -0,0 +1,435 @@ +/* + * Copyright (C) 2007 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.am; + +import android.app.IActivityManager; +import android.app.IInstrumentationWatcher; +import android.app.Instrumentation; +import android.app.UiAutomationConnection; +import android.content.ComponentName; +import android.content.pm.IPackageManager; +import android.content.pm.InstrumentationInfo; +import android.os.Build; +import android.os.Bundle; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.UserHandle; +import android.util.AndroidException; +import android.util.proto.ProtoOutputStream; +import android.view.IWindowManager; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + + +/** + * Runs the am instrument command + */ +public class Instrument { + private final IActivityManager mAm; + private final IPackageManager mPm; + private final IWindowManager mWm; + + // Command line arguments + public String profileFile = null; + public boolean wait = false; + public boolean rawMode = false; + public boolean proto = false; + public boolean noWindowAnimation = false; + public String abi = null; + public int userId = UserHandle.USER_CURRENT; + public Bundle args = new Bundle(); + // Required + public String componentNameArg; + + /** + * Construct the instrument command runner. + */ + public Instrument(IActivityManager am, IPackageManager pm) { + mAm = am; + mPm = pm; + mWm = IWindowManager.Stub.asInterface(ServiceManager.getService("window")); + } + + /** + * Base class for status reporting. + * + * All the methods on this interface are called within the synchronized block + * of the InstrumentationWatcher, so calls are in order. However, that means + * you must be careful not to do blocking operations because you don't know + * exactly the locking dependencies. + */ + private interface StatusReporter { + /** + * Status update for tests. + */ + public void onInstrumentationStatusLocked(ComponentName name, int resultCode, + Bundle results); + + /** + * The tests finished. + */ + public void onInstrumentationFinishedLocked(ComponentName name, int resultCode, + Bundle results); + + /** + * @param errorText a description of the error + * @param commandError True if the error is related to the commandline, as opposed + * to a test failing. + */ + public void onError(String errorText, boolean commandError); + } + + /** + * Printer for the 'classic' text based status reporting. + */ + private class TextStatusReporter implements StatusReporter { + private boolean mRawMode; + + /** + * Human-ish readable output. + * + * @param rawMode In "raw mode" (true), all bundles are dumped. + * In "pretty mode" (false), if a bundle includes + * Instrumentation.REPORT_KEY_STREAMRESULT, just print that. + */ + public TextStatusReporter(boolean rawMode) { + mRawMode = rawMode; + } + + @Override + public void onInstrumentationStatusLocked(ComponentName name, int resultCode, + Bundle results) { + // pretty printer mode? + String pretty = null; + if (!mRawMode && results != null) { + pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT); + } + if (pretty != null) { + System.out.print(pretty); + } else { + if (results != null) { + for (String key : results.keySet()) { + System.out.println( + "INSTRUMENTATION_STATUS: " + key + "=" + results.get(key)); + } + } + System.out.println("INSTRUMENTATION_STATUS_CODE: " + resultCode); + } + } + + @Override + public void onInstrumentationFinishedLocked(ComponentName name, int resultCode, + Bundle results) { + // pretty printer mode? + String pretty = null; + if (!mRawMode && results != null) { + pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT); + } + if (pretty != null) { + System.out.println(pretty); + } else { + if (results != null) { + for (String key : results.keySet()) { + System.out.println( + "INSTRUMENTATION_RESULT: " + key + "=" + results.get(key)); + } + } + System.out.println("INSTRUMENTATION_CODE: " + resultCode); + } + } + + @Override + public void onError(String errorText, boolean commandError) { + // The regular BaseCommand error printing will print the commandErrors. + if (!commandError) { + System.out.println(errorText); + } + } + } + + /** + * Printer for the protobuf based status reporting. + */ + private class ProtoStatusReporter implements StatusReporter { + @Override + public void onInstrumentationStatusLocked(ComponentName name, int resultCode, + Bundle results) { + final ProtoOutputStream proto = new ProtoOutputStream(); + + final long token = proto.startRepeatedObject(InstrumentationData.Session.TEST_STATUS); + + proto.writeSInt32(InstrumentationData.TestStatus.RESULT_CODE, resultCode); + writeBundle(proto, InstrumentationData.TestStatus.RESULTS, results); + + proto.endRepeatedObject(token); + writeProtoToStdout(proto); + } + + @Override + public void onInstrumentationFinishedLocked(ComponentName name, int resultCode, + Bundle results) { + final ProtoOutputStream proto = new ProtoOutputStream(); + + final long token = proto.startObject(InstrumentationData.Session.SESSION_STATUS); + + proto.writeEnum(InstrumentationData.SessionStatus.STATUS_CODE, + InstrumentationData.SESSION_FINISHED); + proto.writeSInt32(InstrumentationData.SessionStatus.RESULT_CODE, resultCode); + writeBundle(proto, InstrumentationData.SessionStatus.RESULTS, results); + + proto.endObject(token); + writeProtoToStdout(proto); + } + + @Override + public void onError(String errorText, boolean commandError) { + final ProtoOutputStream proto = new ProtoOutputStream(); + + final long token = proto.startObject(InstrumentationData.Session.SESSION_STATUS); + + proto.writeEnum(InstrumentationData.SessionStatus.STATUS_CODE, + InstrumentationData.SESSION_ABORTED); + proto.writeString(InstrumentationData.SessionStatus.ERROR_TEXT, errorText); + + proto.endObject(token); + writeProtoToStdout(proto); + } + + private void writeBundle(ProtoOutputStream proto, long fieldId, Bundle bundle) { + final long bundleToken = proto.startObject(fieldId); + + for (final String key: bundle.keySet()) { + final long entryToken = proto.startRepeatedObject( + InstrumentationData.ResultsBundle.ENTRIES); + + proto.writeString(InstrumentationData.ResultsBundleEntry.KEY, key); + + final Object val = bundle.get(key); + if (val instanceof String) { + proto.writeString(InstrumentationData.ResultsBundleEntry.VALUE_STRING, + (String)val); + } else if (val instanceof Byte) { + proto.writeSInt32(InstrumentationData.ResultsBundleEntry.VALUE_INT, + ((Byte)val).intValue()); + } else if (val instanceof Double) { + proto.writeDouble(InstrumentationData.ResultsBundleEntry.VALUE_DOUBLE, + ((Double)val).doubleValue()); + } else if (val instanceof Float) { + proto.writeFloat(InstrumentationData.ResultsBundleEntry.VALUE_FLOAT, + ((Float)val).floatValue()); + } else if (val instanceof Integer) { + proto.writeSInt32(InstrumentationData.ResultsBundleEntry.VALUE_INT, + ((Integer)val).intValue()); + } else if (val instanceof Long) { + proto.writeSInt64(InstrumentationData.ResultsBundleEntry.VALUE_LONG, + ((Long)val).longValue()); + } else if (val instanceof Short) { + proto.writeSInt32(InstrumentationData.ResultsBundleEntry.VALUE_INT, + ((Short)val).intValue()); + } else if (val instanceof Bundle) { + writeBundle(proto, InstrumentationData.ResultsBundleEntry.VALUE_BUNDLE, + (Bundle)val); + } + + proto.endRepeatedObject(entryToken); + } + + proto.endObject(bundleToken); + } + + private void writeProtoToStdout(ProtoOutputStream proto) { + try { + System.out.write(proto.getBytes()); + System.out.flush(); + } catch (IOException ex) { + System.err.println("Error writing finished response: "); + ex.printStackTrace(System.err); + } + } + } + + + /** + * Callbacks from the remote instrumentation instance. + */ + private class InstrumentationWatcher extends IInstrumentationWatcher.Stub { + private final StatusReporter mReporter; + + private boolean mFinished = false; + + public InstrumentationWatcher(StatusReporter reporter) { + mReporter = reporter; + } + + @Override + public void instrumentationStatus(ComponentName name, int resultCode, Bundle results) { + synchronized (this) { + mReporter.onInstrumentationStatusLocked(name, resultCode, results); + notifyAll(); + } + } + + @Override + public void instrumentationFinished(ComponentName name, int resultCode, Bundle results) { + synchronized (this) { + mReporter.onInstrumentationFinishedLocked(name, resultCode, results); + mFinished = true; + notifyAll(); + } + } + + public boolean waitForFinish() { + synchronized (this) { + while (!mFinished) { + try { + if (!mAm.asBinder().pingBinder()) { + return false; + } + wait(1000); + } catch (InterruptedException e) { + throw new IllegalStateException(e); + } + } + } + return true; + } + } + + /** + * Figure out which component they really meant. + */ + private ComponentName parseComponentName(String cnArg) throws Exception { + if (cnArg.contains("/")) { + ComponentName cn = ComponentName.unflattenFromString(cnArg); + if (cn == null) throw new IllegalArgumentException("Bad component name: " + cnArg); + return cn; + } else { + List<InstrumentationInfo> infos = mPm.queryInstrumentation(null, 0).getList(); + + final int numInfos = infos == null ? 0: infos.size(); + ArrayList<ComponentName> cns = new ArrayList<>(); + for (int i = 0; i < numInfos; i++) { + InstrumentationInfo info = infos.get(i); + + ComponentName c = new ComponentName(info.packageName, info.name); + if (cnArg.equals(info.packageName)) { + cns.add(c); + } + } + + if (cns.size() == 0) { + throw new IllegalArgumentException("No instrumentation found for: " + cnArg); + } else if (cns.size() == 1) { + return cns.get(0); + } else { + StringBuilder cnsStr = new StringBuilder(); + final int numCns = cns.size(); + for (int i = 0; i < numCns; i++) { + cnsStr.append(cns.get(i).flattenToString()); + cnsStr.append(", "); + } + + // Remove last ", " + cnsStr.setLength(cnsStr.length() - 2); + + throw new IllegalArgumentException("Found multiple instrumentations: " + + cnsStr.toString()); + } + } + } + + /** + * Run the instrumentation. + */ + public void run() throws Exception { + StatusReporter reporter = null; + float[] oldAnims = null; + + try { + // Choose which output we will do. + if (proto) { + reporter = new ProtoStatusReporter(); + } else if (wait) { + reporter = new TextStatusReporter(rawMode); + } + + // Choose whether we have to wait for the results. + InstrumentationWatcher watcher = null; + UiAutomationConnection connection = null; + if (reporter != null) { + watcher = new InstrumentationWatcher(reporter); + connection = new UiAutomationConnection(); + } + + // Set the window animation if necessary + if (noWindowAnimation) { + oldAnims = mWm.getAnimationScales(); + mWm.setAnimationScale(0, 0.0f); + mWm.setAnimationScale(1, 0.0f); + } + + // Figure out which component we are tring to do. + final ComponentName cn = parseComponentName(componentNameArg); + + // Choose an ABI if necessary + if (abi != null) { + final String[] supportedAbis = Build.SUPPORTED_ABIS; + boolean matched = false; + for (String supportedAbi : supportedAbis) { + if (supportedAbi.equals(abi)) { + matched = true; + break; + } + } + if (!matched) { + throw new AndroidException( + "INSTRUMENTATION_FAILED: Unsupported instruction set " + abi); + } + } + + // Start the instrumentation + if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher, connection, userId, + abi)) { + throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString()); + } + + // If we have been requested to wait, do so until the instrumentation is finished. + if (watcher != null) { + if (!watcher.waitForFinish()) { + reporter.onError("INSTRUMENTATION_ABORTED: System has crashed.", false); + return; + } + } + } catch (Exception ex) { + // Report failures + if (reporter != null) { + reporter.onError(ex.getMessage(), true); + } + + // And re-throw the exception + throw ex; + } finally { + // Clean up + if (oldAnims != null) { + mWm.setAnimationScales(oldAnims); + } + } + } +} + diff --git a/cmds/appops/appops b/cmds/appops/appops index 25d20311aae2..5dc85aa0979c 100755 --- a/cmds/appops/appops +++ b/cmds/appops/appops @@ -1 +1,2 @@ -cmd appops $@ +#!/system/bin/sh +cmd appops "$@" diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 5fe8ba06f536..7967e2a8da87 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -49,8 +49,8 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #include <SkBitmap.h> +#include <SkImage.h> #include <SkStream.h> -#include <SkImageDecoder.h> #pragma GCC diagnostic pop #include <GLES/gl.h> @@ -140,8 +140,10 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets, if (asset == NULL) return NO_INIT; SkBitmap bitmap; - SkImageDecoder::DecodeMemory(asset->getBuffer(false), asset->getLength(), - &bitmap, kUnknown_SkColorType, SkImageDecoder::kDecodePixels_Mode); + sk_sp<SkData> data = SkData::MakeWithoutCopy(asset->getBuffer(false), + asset->getLength()); + sk_sp<SkImage> image = SkImage::MakeFromEncoded(data); + image->asLegacyBitmap(&bitmap, SkImage::kRO_LegacyBitmapMode); asset->close(); delete asset; @@ -193,15 +195,10 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets, status_t BootAnimation::initTexture(FileMap* map, int* width, int* height) { SkBitmap bitmap; - SkMemoryStream stream(map->getDataPtr(), map->getDataLength()); - SkImageDecoder* codec = SkImageDecoder::Factory(&stream); - if (codec != NULL) { - codec->setDitherImage(false); - codec->decode(&stream, &bitmap, - kN32_SkColorType, - SkImageDecoder::kDecodePixels_Mode); - delete codec; - } + sk_sp<SkData> data = SkData::MakeWithoutCopy(map->getDataPtr(), + map->getDataLength()); + sk_sp<SkImage> image = SkImage::MakeFromEncoded(data); + image->asLegacyBitmap(&bitmap, SkImage::kRO_LegacyBitmapMode); // FileMap memory is never released until application exit. // Release it now as the texture is already loaded and the memory used for diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java index d43b8c564e96..63641a8e38f4 100644 --- a/cmds/content/src/com/android/commands/content/Content.java +++ b/cmds/content/src/com/android/commands/content/Content.java @@ -16,9 +16,9 @@ package com.android.commands.content; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; +import android.app.ContentProviderHolder; import android.app.IActivityManager; -import android.app.IActivityManager.ContentProviderHolder; import android.content.ContentValues; import android.content.IContentProvider; import android.database.Cursor; @@ -72,59 +72,64 @@ import libcore.io.IoUtils; public class Content { private static final String USAGE = - "usage: adb shell content [subcommand] [options]\n" - + "\n" - + "usage: adb shell content insert --uri <URI> [--user <USER_ID>]" - + " --bind <BINDING> [--bind <BINDING>...]\n" - + " <URI> a content provider URI.\n" - + " <BINDING> binds a typed value to a column and is formatted:\n" - + " <COLUMN_NAME>:<TYPE>:<COLUMN_VALUE> where:\n" - + " <TYPE> specifies data type such as:\n" - + " b - boolean, s - string, i - integer, l - long, f - float, d - double\n" - + " Note: Omit the value for passing an empty string, e.g column:s:\n" - + " Example:\n" - + " # Add \"new_setting\" secure setting with value \"new_value\".\n" - + " adb shell content insert --uri content://settings/secure --bind name:s:new_setting" - + " --bind value:s:new_value\n" - + "\n" - + "usage: adb shell content update --uri <URI> [--user <USER_ID>] [--where <WHERE>]\n" - + " <WHERE> is a SQL style where clause in quotes (You have to escape single quotes" - + " - see example below).\n" - + " Example:\n" - + " # Change \"new_setting\" secure setting to \"newer_value\".\n" - + " adb shell content update --uri content://settings/secure --bind" - + " value:s:newer_value --where \"name=\'new_setting\'\"\n" - + "\n" - + "usage: adb shell content delete --uri <URI> [--user <USER_ID>] --bind <BINDING>" - + " [--bind <BINDING>...] [--where <WHERE>]\n" - + " Example:\n" - + " # Remove \"new_setting\" secure setting.\n" - + " adb shell content delete --uri content://settings/secure " - + "--where \"name=\'new_setting\'\"\n" - + "\n" - + "usage: adb shell content query --uri <URI> [--user <USER_ID>]" - + " [--projection <PROJECTION>] [--where <WHERE>] [--sort <SORT_ORDER>]\n" - + " <PROJECTION> is a list of colon separated column names and is formatted:\n" - + " <COLUMN_NAME>[:<COLUMN_NAME>...]\n" - + " <SORT_ORDER> is the order in which rows in the result should be sorted.\n" - + " Example:\n" - + " # Select \"name\" and \"value\" columns from secure settings where \"name\" is " - + "equal to \"new_setting\" and sort the result by name in ascending order.\n" - + " adb shell content query --uri content://settings/secure --projection name:value" - + " --where \"name=\'new_setting\'\" --sort \"name ASC\"\n" - + "\n" - + "usage: adb shell content call --uri <URI> --method <METHOD> [--arg <ARG>]\n" - + " [--extra <BINDING> ...]\n" - + " <METHOD> is the name of a provider-defined method\n" - + " <ARG> is an optional string argument\n" - + " <BINDING> is like --bind above, typed data of the form <KEY>:{b,s,i,l,f,d}:<VAL>\n" - + "\n" - + "usage: adb shell content read --uri <URI> [--user <USER_ID>]\n" - + " Example:\n" - + " # cat default ringtone to a file, then pull to host\n" - + " adb shell 'content read --uri content://settings/system/ringtone >" - + " /mnt/sdcard/tmp.ogg' && adb pull /mnt/sdcard/tmp.ogg\n" - + "\n"; + "usage: adb shell content [subcommand] [options]\n" + + "\n" + + "usage: adb shell content insert --uri <URI> [--user <USER_ID>]" + + " --bind <BINDING> [--bind <BINDING>...]\n" + + " <URI> a content provider URI.\n" + + " <BINDING> binds a typed value to a column and is formatted:\n" + + " <COLUMN_NAME>:<TYPE>:<COLUMN_VALUE> where:\n" + + " <TYPE> specifies data type such as:\n" + + " b - boolean, s - string, i - integer, l - long, f - float, d - double\n" + + " Note: Omit the value for passing an empty string, e.g column:s:\n" + + " Example:\n" + + " # Add \"new_setting\" secure setting with value \"new_value\".\n" + + " adb shell content insert --uri content://settings/secure --bind name:s:new_setting" + + " --bind value:s:new_value\n" + + "\n" + + "usage: adb shell content update --uri <URI> [--user <USER_ID>] [--where <WHERE>]\n" + + " <WHERE> is a SQL style where clause in quotes (You have to escape single quotes" + + " - see example below).\n" + + " Example:\n" + + " # Change \"new_setting\" secure setting to \"newer_value\".\n" + + " adb shell content update --uri content://settings/secure --bind" + + " value:s:newer_value --where \"name=\'new_setting\'\"\n" + + "\n" + + "usage: adb shell content delete --uri <URI> [--user <USER_ID>] --bind <BINDING>" + + " [--bind <BINDING>...] [--where <WHERE>]\n" + + " Example:\n" + + " # Remove \"new_setting\" secure setting.\n" + + " adb shell content delete --uri content://settings/secure " + + "--where \"name=\'new_setting\'\"\n" + + "\n" + + "usage: adb shell content query --uri <URI> [--user <USER_ID>]" + + " [--projection <PROJECTION>] [--where <WHERE>] [--sort <SORT_ORDER>]\n" + + " <PROJECTION> is a list of colon separated column names and is formatted:\n" + + " <COLUMN_NAME>[:<COLUMN_NAME>...]\n" + + " <SORT_ORDER> is the order in which rows in the result should be sorted.\n" + + " Example:\n" + + " # Select \"name\" and \"value\" columns from secure settings where \"name\" is " + + "equal to \"new_setting\" and sort the result by name in ascending order.\n" + + " adb shell content query --uri content://settings/secure --projection name:value" + + " --where \"name=\'new_setting\'\" --sort \"name ASC\"\n" + + "\n" + + "usage: adb shell content call --uri <URI> --method <METHOD> [--arg <ARG>]\n" + + " [--extra <BINDING> ...]\n" + + " <METHOD> is the name of a provider-defined method\n" + + " <ARG> is an optional string argument\n" + + " <BINDING> is like --bind above, typed data of the form <KEY>:{b,s,i,l,f,d}:<VAL>\n" + + "\n" + + "usage: adb shell content read --uri <URI> [--user <USER_ID>]\n" + + " Example:\n" + + " # cat default ringtone to a file, then pull to host\n" + + " adb shell 'content read --uri content://settings/system/ringtone >" + + " /mnt/sdcard/tmp.ogg' && adb pull /mnt/sdcard/tmp.ogg\n" + + "\n" + + "usage: adb shell content gettype --uri <URI> [--user <USER_ID>]\n" + + " Example:\n" + + " # Show the mime-type of the URI\n" + + " adb shell content gettype --uri content://media/internal/audio/media/\n" + + "\n"; private static class Parser { private static final String ARGUMENT_INSERT = "insert"; @@ -133,6 +138,7 @@ public class Content { private static final String ARGUMENT_QUERY = "query"; private static final String ARGUMENT_CALL = "call"; private static final String ARGUMENT_READ = "read"; + private static final String ARGUMENT_GET_TYPE = "gettype"; private static final String ARGUMENT_WHERE = "--where"; private static final String ARGUMENT_BIND = "--bind"; private static final String ARGUMENT_URI = "--uri"; @@ -172,6 +178,8 @@ public class Content { return parseCallCommand(); } else if (ARGUMENT_READ.equals(operation)) { return parseReadCommand(); + } else if (ARGUMENT_GET_TYPE.equals(operation)) { + return parseGetTypeCommand(); } else { throw new IllegalArgumentException("Unsupported operation: " + operation); } @@ -291,6 +299,26 @@ public class Content { return new CallCommand(uri, userId, method, arg, values); } + private GetTypeCommand parseGetTypeCommand() { + Uri uri = null; + int userId = UserHandle.USER_SYSTEM; + + for (String argument; (argument = mTokenizer.nextArg()) != null;) { + if (ARGUMENT_URI.equals(argument)) { + uri = Uri.parse(argumentValueRequired(argument)); + } else if (ARGUMENT_USER.equals(argument)) { + userId = Integer.parseInt(argumentValueRequired(argument)); + } else { + throw new IllegalArgumentException("Unsupported argument: " + argument); + } + } + if (uri == null) { + throw new IllegalArgumentException("Content provider URI not specified." + + " Did you specify --uri argument?"); + } + return new GetTypeCommand(uri, userId); + } + private ReadCommand parseReadCommand() { Uri uri = null; int userId = UserHandle.USER_SYSTEM; @@ -405,7 +433,7 @@ public class Content { public final void execute() { String providerName = mUri.getAuthority(); try { - IActivityManager activityManager = ActivityManagerNative.getDefault(); + IActivityManager activityManager = ActivityManager.getService(); IContentProvider provider = null; IBinder token = new Binder(); try { @@ -511,6 +539,18 @@ public class Content { } } + private static class GetTypeCommand extends Command { + public GetTypeCommand(Uri uri, int userId) { + super(uri, userId); + } + + @Override + public void onExecute(IContentProvider provider) throws Exception { + String type = provider.getType(mUri); + System.out.println("Result: " + type); + } + } + private static class ReadCommand extends Command { public ReadCommand(Uri uri, int userId) { super(uri, userId); diff --git a/cmds/dpm/src/com/android/commands/dpm/Dpm.java b/cmds/dpm/src/com/android/commands/dpm/Dpm.java index 31c742153f24..3ac70d668198 100644 --- a/cmds/dpm/src/com/android/commands/dpm/Dpm.java +++ b/cmds/dpm/src/com/android/commands/dpm/Dpm.java @@ -16,7 +16,7 @@ package com.android.commands.dpm; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.IActivityManager; import android.app.admin.DevicePolicyManager; import android.app.admin.IDevicePolicyManager; @@ -117,7 +117,7 @@ public final class Dpm extends BaseCommand { mUserId = parseInt(arg); } if (mUserId == UserHandle.USER_CURRENT) { - IActivityManager activityManager = ActivityManagerNative.getDefault(); + IActivityManager activityManager = ActivityManager.getService(); try { mUserId = activityManager.getCurrentUser().id; } catch (RemoteException e) { diff --git a/cmds/idmap/inspect.cpp b/cmds/idmap/inspect.cpp index f6afc8594309..154cb25a02a1 100644 --- a/cmds/idmap/inspect.cpp +++ b/cmds/idmap/inspect.cpp @@ -2,6 +2,7 @@ #include <androidfw/AssetManager.h> #include <androidfw/ResourceTypes.h> +#include <utils/ByteOrder.h> #include <utils/String8.h> #include <fcntl.h> diff --git a/cmds/input/src/com/android/commands/input/Input.java b/cmds/input/src/com/android/commands/input/Input.java index 754d3f510bbd..9ee11f8571e2 100644 --- a/cmds/input/src/com/android/commands/input/Input.java +++ b/cmds/input/src/com/android/commands/input/Input.java @@ -23,6 +23,7 @@ import android.view.InputDevice; import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.MotionEvent; +import android.view.ViewConfiguration; import java.util.HashMap; import java.util.Map; @@ -118,6 +119,19 @@ public class Input { duration); return; } + } else if (command.equals("draganddrop")) { + int duration = -1; + inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN); + switch (length) { + case 6: + duration = Integer.parseInt(args[index+5]); + case 5: + sendDragAndDrop(inputSource, + Float.parseFloat(args[index+1]), Float.parseFloat(args[index+2]), + Float.parseFloat(args[index+3]), Float.parseFloat(args[index+4]), + duration); + return; + } } else if (command.equals("press")) { inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL); if (length == 1) { @@ -216,6 +230,31 @@ public class Input { injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x2, y2, 0.0f); } + private void sendDragAndDrop(int inputSource, float x1, float y1, float x2, float y2, + int dragDuration) { + if (dragDuration < 0) { + dragDuration = 300; + } + long now = SystemClock.uptimeMillis(); + injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x1, y1, 1.0f); + try { + Thread.sleep(ViewConfiguration.getLongPressTimeout()); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + now = SystemClock.uptimeMillis(); + long startTime = now; + long endTime = startTime + dragDuration; + while (now < endTime) { + long elapsedTime = now - startTime; + float alpha = (float) elapsedTime / dragDuration; + injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, lerp(x1, x2, alpha), + lerp(y1, y2, alpha), 1.0f); + now = SystemClock.uptimeMillis(); + } + injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x2, y2, 0.0f); + } + /** * Sends a simple zero-pressure move event. * @@ -294,6 +333,8 @@ public class Input { System.err.println(" tap <x> <y> (Default: touchscreen)"); System.err.println(" swipe <x1> <y1> <x2> <y2> [duration(ms)]" + " (Default: touchscreen)"); + System.err.println(" draganddrop <x1> <y1> <x2> <y2> [duration(ms)]" + + " (Default: touchscreen)"); System.err.println(" press (Default: trackball)"); System.err.println(" roll <dx> <dy> (Default: trackball)"); } diff --git a/cmds/locksettings/Android.mk b/cmds/locksettings/Android.mk new file mode 100644 index 000000000000..76766c7c6955 --- /dev/null +++ b/cmds/locksettings/Android.mk @@ -0,0 +1,30 @@ +# Copyright (C) 2016 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. + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) +LOCAL_MODULE := locksettings +LOCAL_MODULE_TAGS := optional +include $(BUILD_JAVA_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := locksettings +LOCAL_SRC_FILES := locksettings +LOCAL_MODULE_CLASS := EXECUTABLES +LOCAL_MODULE_TAGS := optional +include $(BUILD_PREBUILT) + + diff --git a/cmds/locksettings/locksettings b/cmds/locksettings/locksettings new file mode 100755 index 000000000000..c963b238726b --- /dev/null +++ b/cmds/locksettings/locksettings @@ -0,0 +1,5 @@ +# Script to start "locksettings" on the device +# +base=/system +export CLASSPATH=$base/framework/locksettings.jar +exec app_process $base/bin com.android.commands.locksettings.LockSettingsCmd "$@" diff --git a/cmds/locksettings/src/com/android/commands/locksettings/LockSettingsCmd.java b/cmds/locksettings/src/com/android/commands/locksettings/LockSettingsCmd.java new file mode 100644 index 000000000000..1e426d62e4e0 --- /dev/null +++ b/cmds/locksettings/src/com/android/commands/locksettings/LockSettingsCmd.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2016 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.locksettings; + +import android.os.ResultReceiver; +import android.os.ServiceManager; +import android.os.ShellCallback; + +import com.android.internal.os.BaseCommand; +import com.android.internal.widget.ILockSettings; + +import java.io.FileDescriptor; +import java.io.PrintStream; + +public final class LockSettingsCmd extends BaseCommand { + + private static final String USAGE = + "usage: locksettings set-pattern [--old OLD_CREDENTIAL] NEW_PATTERN\n" + + " locksettings set-pin [--old OLD_CREDENTIAL] NEW_PIN\n" + + " locksettings set-password [--old OLD_CREDENTIAL] NEW_PASSWORD\n" + + " locksettings clear [--old OLD_CREDENTIAL]\n" + + "\n" + + "locksettings set-pattern: sets a pattern\n" + + " A pattern is specified by a non-separated list of numbers that index the cell\n" + + " on the pattern in a 1-based manner in left to right and top to bottom order,\n" + + " i.e. the top-left cell is indexed with 1, whereas the bottom-right cell\n" + + " is indexed with 9. Example: 1234\n" + + "\n" + + "locksettings set-pin: sets a PIN\n" + + "\n" + + "locksettings set-password: sets a password\n" + + "\n" + + "locksettings clear: clears the unlock credential\n"; + + public static void main(String[] args) { + (new LockSettingsCmd()).run(args); + } + + @Override + public void onShowUsage(PrintStream out) { + out.println(USAGE); + } + + @Override + public void onRun() throws Exception { + ILockSettings lockSettings = ILockSettings.Stub.asInterface( + ServiceManager.getService("lock_settings")); + lockSettings.asBinder().shellCommand(FileDescriptor.in, FileDescriptor.out, + FileDescriptor.err, getRawArgs(), new ShellCallback(), new ResultReceiver(null) {}); + } +} diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java index d7f23cb44098..0e0ecd0ba068 100644 --- a/cmds/media/src/com/android/commands/media/Media.java +++ b/cmds/media/src/com/android/commands/media/Media.java @@ -57,6 +57,7 @@ public class Media extends BaseCommand { (new Media()).run(args); } + @Override public void onShowUsage(PrintStream out) { out.println( "usage: media [subcommand] [options]\n" + @@ -73,6 +74,7 @@ public class Media extends BaseCommand { ); } + @Override public void onRun() throws Exception { mSessionService = ISessionManager.Stub.asInterface(ServiceManager.checkService( Context.MEDIA_SESSION_SERVICE)); @@ -222,6 +224,16 @@ public class Media extends BaseCommand { System.out.println("onVolumeInfoChanged " + info); } + @Override + public void onRepeatModeChanged(int repeatMode) throws RemoteException { + System.out.println("onRepeatModeChanged " + repeatMode); + } + + @Override + public void onShuffleModeChanged(boolean enabled) throws RemoteException { + System.out.println("onShuffleModeChanged " + enabled); + } + void printUsageMessage() { try { System.out.println("V2Monitoring session " + mController.getTag() diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index 1b4eda804312..50f46f4007d3 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -24,7 +24,6 @@ import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATIO import android.accounts.IAccountManager; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.PackageInstallObserver; import android.content.ComponentName; import android.content.Context; @@ -53,9 +52,12 @@ import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.IUserManager; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ResultReceiver; +import android.os.SELinux; import android.os.ServiceManager; +import android.os.ShellCallback; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; @@ -72,6 +74,7 @@ import libcore.io.IoUtils; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -80,6 +83,7 @@ import java.util.concurrent.TimeUnit; public final class Pm { private static final String TAG = "Pm"; + private static final String STDIN_PATH = "-"; IPackageManager mPm; IPackageInstaller mInstaller; @@ -288,13 +292,45 @@ public final class Pm { } } + static final class MyShellCallback extends ShellCallback { + @Override public ParcelFileDescriptor onOpenOutputFile(String path, String seLinuxContext) { + File file = new File(path); + final ParcelFileDescriptor fd; + try { + fd = ParcelFileDescriptor.open(file, + ParcelFileDescriptor.MODE_CREATE | + ParcelFileDescriptor.MODE_TRUNCATE | + ParcelFileDescriptor.MODE_WRITE_ONLY); + } catch (FileNotFoundException e) { + String msg = "Unable to open file " + path + ": " + e; + System.err.println(msg); + throw new IllegalArgumentException(msg); + } + if (seLinuxContext != null) { + final String tcon = SELinux.getFileContext(file.getAbsolutePath()); + if (!SELinux.checkSELinuxAccess(seLinuxContext, tcon, "file", "write")) { + try { + fd.close(); + } catch (IOException e) { + } + String msg = "System server has no access to file context " + tcon; + System.err.println(msg + " (from path " + file.getAbsolutePath() + + ", context " + seLinuxContext + ")"); + throw new IllegalArgumentException(msg); + } + } + return fd; + } + } + private int runShellCommand(String serviceName, String[] args) { final HandlerThread handlerThread = new HandlerThread("results"); handlerThread.start(); try { ServiceManager.getService(serviceName).shellCommand( FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, - args, new ResultReceiver(new Handler(handlerThread.getLooper()))); + args, new MyShellCallback(), + new ResultReceiver(new Handler(handlerThread.getLooper()))); return 0; } catch (RemoteException e) { e.printStackTrace(); @@ -367,25 +403,22 @@ public final class Pm { private int runInstall() throws RemoteException { final InstallParams params = makeInstallParams(); final String inPath = nextArg(); - boolean installExternal = - (params.sessionParams.installFlags & PackageManager.INSTALL_EXTERNAL) != 0; - if (params.sessionParams.sizeBytes < 0 && inPath != null) { + if (params.sessionParams.sizeBytes == -1 && !STDIN_PATH.equals(inPath)) { File file = new File(inPath); if (file.isFile()) { - if (installExternal) { - try { - ApkLite baseApk = PackageParser.parseApkLite(file, 0); - PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null); - params.sessionParams.setSize( - PackageHelper.calculateInstalledSize(pkgLite, false, - params.sessionParams.abiOverride)); - } catch (PackageParserException | IOException e) { - System.err.println("Error: Failed to parse APK file : " + e); - return 1; - } - } else { - params.sessionParams.setSize(file.length()); + try { + ApkLite baseApk = PackageParser.parseApkLite(file, 0); + PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null); + params.sessionParams.setSize( + PackageHelper.calculateInstalledSize(pkgLite, false, + params.sessionParams.abiOverride)); + } catch (PackageParserException | IOException e) { + System.err.println("Error: Failed to parse APK file: " + e); + return 1; } + } else { + System.err.println("Error: Can't open non-file: " + inPath); + return 1; } } @@ -393,7 +426,7 @@ public final class Pm { params.installerPackageName, params.userId); try { - if (inPath == null && params.sessionParams.sizeBytes == 0) { + if (inPath == null && params.sessionParams.sizeBytes == -1) { System.err.println("Error: must either specify a package size or an APK file"); return 1; } @@ -510,7 +543,11 @@ public final class Pm { } break; case "-S": - sessionParams.setSize(Long.parseLong(nextOptionData())); + final long sizeBytes = Long.parseLong(nextOptionData()); + if (sizeBytes <= 0) { + throw new IllegalArgumentException("Size must be positive"); + } + sessionParams.setSize(sizeBytes); break; case "--abi": sessionParams.abiOverride = checkAbiArgument(nextOptionData()); @@ -555,7 +592,7 @@ public final class Pm { private int doWriteSession(int sessionId, String inPath, long sizeBytes, String splitName, boolean logSuccess) throws RemoteException { - if ("-".equals(inPath)) { + if (STDIN_PATH.equals(inPath)) { inPath = null; } else if (inPath != null) { final File file = new File(inPath); @@ -971,7 +1008,7 @@ public final class Pm { } else if (userId < 0) { info = mUm.createUser(name, flags); } else { - info = mUm.createProfileForUser(name, flags, userId); + info = mUm.createProfileForUser(name, flags, userId, null); } if (info != null) { @@ -1153,7 +1190,7 @@ public final class Pm { ClearDataObserver obs = new ClearDataObserver(); try { - ActivityManagerNative.getDefault().clearApplicationUserData(pkg, obs, userId); + ActivityManager.getService().clearApplicationUserData(pkg, obs, userId); synchronized (obs) { while (!obs.finished) { try { diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp index 7bf073b4b1a1..a41f1224f9ec 100644 --- a/cmds/screencap/screencap.cpp +++ b/cmds/screencap/screencap.cpp @@ -177,7 +177,7 @@ int main(int argc, char** argv) if (png) { const SkImageInfo info = SkImageInfo::Make(w, h, flinger2skia(f), kPremul_SkAlphaType); - SkAutoTUnref<SkData> data(SkImageEncoder::EncodeData(info, base, s*bytesPerPixel(f), + sk_sp<SkData> data(SkImageEncoder::EncodeData(info, base, s*bytesPerPixel(f), SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality)); if (data.get()) { write(fd, data->data(), data->size()); diff --git a/cmds/settings/Android.mk b/cmds/settings/Android.mk index 05deb99f7228..8a8d1bb95c66 100644 --- a/cmds/settings/Android.mk +++ b/cmds/settings/Android.mk @@ -3,11 +3,6 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES := $(call all-subdir-java-files) -LOCAL_MODULE := settings -LOCAL_MODULE_TAGS := optional -include $(BUILD_JAVA_LIBRARY) - include $(CLEAR_VARS) LOCAL_MODULE := settings LOCAL_SRC_FILES := settings diff --git a/cmds/settings/settings b/cmds/settings/settings index ef459ca7d4c4..d41ccc62811a 100755 --- a/cmds/settings/settings +++ b/cmds/settings/settings @@ -1,5 +1,2 @@ -# Script to start "settings" on the device -# -base=/system -export CLASSPATH=$base/framework/settings.jar -exec app_process $base/bin com.android.commands.settings.SettingsCmd "$@" +#!/system/bin/sh +cmd settings "$@" diff --git a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java b/cmds/settings/src/com/android/commands/settings/SettingsCmd.java deleted file mode 100644 index e63a1f58f8fc..000000000000 --- a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright (C) 2012 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.settings; - -import android.app.ActivityManagerNative; -import android.app.IActivityManager; -import android.app.IActivityManager.ContentProviderHolder; -import android.content.IContentProvider; -import android.database.Cursor; -import android.net.Uri; -import android.os.Binder; -import android.os.Bundle; -import android.os.IBinder; -import android.os.Process; -import android.os.RemoteException; -import android.os.UserHandle; -import android.provider.Settings; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public final class SettingsCmd { - - enum CommandVerb { - UNSPECIFIED, - GET, - PUT, - DELETE, - LIST, - } - - static String[] mArgs; - int mNextArg; - int mUser = -1; // unspecified - CommandVerb mVerb = CommandVerb.UNSPECIFIED; - String mTable = null; - String mKey = null; - String mValue = null; - - public static void main(String[] args) { - if (args == null || args.length < 2) { - printUsage(); - return; - } - - mArgs = args; - try { - new SettingsCmd().run(); - } catch (Exception e) { - System.err.println("Unable to run settings command"); - } - } - - public void run() { - boolean valid = false; - String arg; - try { - while ((arg = nextArg()) != null) { - if ("--user".equals(arg)) { - if (mUser != -1) { - // --user specified more than once; invalid - break; - } - arg = nextArg(); - if ("current".equals(arg) || "cur".equals(arg)) { - mUser = UserHandle.USER_CURRENT; - } else { - mUser = Integer.parseInt(arg); - } - } else if (mVerb == CommandVerb.UNSPECIFIED) { - if ("get".equalsIgnoreCase(arg)) { - mVerb = CommandVerb.GET; - } else if ("put".equalsIgnoreCase(arg)) { - mVerb = CommandVerb.PUT; - } else if ("delete".equalsIgnoreCase(arg)) { - mVerb = CommandVerb.DELETE; - } else if ("list".equalsIgnoreCase(arg)) { - mVerb = CommandVerb.LIST; - } else { - // invalid - System.err.println("Invalid command: " + arg); - break; - } - } else if (mTable == null) { - if (!"system".equalsIgnoreCase(arg) - && !"secure".equalsIgnoreCase(arg) - && !"global".equalsIgnoreCase(arg)) { - System.err.println("Invalid namespace '" + arg + "'"); - break; // invalid - } - mTable = arg.toLowerCase(); - if (mVerb == CommandVerb.LIST) { - valid = true; - break; - } - } else if (mVerb == CommandVerb.GET || mVerb == CommandVerb.DELETE) { - mKey = arg; - if (mNextArg >= mArgs.length) { - valid = true; - } else { - System.err.println("Too many arguments"); - } - break; - } else if (mKey == null) { - mKey = arg; - // keep going; there's another PUT arg - } else { // PUT, final arg - mValue = arg; - if (mNextArg >= mArgs.length) { - valid = true; - } else { - System.err.println("Too many arguments"); - } - break; - } - } - } catch (Exception e) { - valid = false; - } - - if (valid) { - try { - IActivityManager activityManager = ActivityManagerNative.getDefault(); - if (mUser == UserHandle.USER_CURRENT) { - mUser = activityManager.getCurrentUser().id; - } - if (mUser < 0) { - mUser = UserHandle.USER_SYSTEM; - } - IContentProvider provider = null; - IBinder token = new Binder(); - try { - ContentProviderHolder holder = activityManager.getContentProviderExternal( - "settings", UserHandle.USER_SYSTEM, token); - if (holder == null) { - throw new IllegalStateException("Could not find settings provider"); - } - provider = holder.provider; - - switch (mVerb) { - case GET: - System.out.println(getForUser(provider, mUser, mTable, mKey)); - break; - case PUT: - putForUser(provider, mUser, mTable, mKey, mValue); - break; - case DELETE: - System.out.println("Deleted " - + deleteForUser(provider, mUser, mTable, mKey) + " rows"); - break; - case LIST: - for (String line : listForUser(provider, mUser, mTable)) { - System.out.println(line); - } - break; - default: - System.err.println("Unspecified command"); - break; - } - - } finally { - if (provider != null) { - activityManager.removeContentProviderExternal("settings", token); - } - } - } catch (Exception e) { - System.err.println("Error while accessing settings provider"); - e.printStackTrace(); - } - - } else { - printUsage(); - } - } - - private List<String> listForUser(IContentProvider provider, int userHandle, String table) { - final Uri uri = "system".equals(table) ? Settings.System.CONTENT_URI - : "secure".equals(table) ? Settings.Secure.CONTENT_URI - : "global".equals(table) ? Settings.Global.CONTENT_URI - : null; - final ArrayList<String> lines = new ArrayList<String>(); - if (uri == null) { - return lines; - } - try { - final Cursor cursor = provider.query(resolveCallingPackage(), uri, null, null, null, - null, null); - try { - while (cursor != null && cursor.moveToNext()) { - lines.add(cursor.getString(1) + "=" + cursor.getString(2)); - } - } finally { - if (cursor != null) { - cursor.close(); - } - } - Collections.sort(lines); - } catch (RemoteException e) { - System.err.println("List failed in " + table + " for user " + userHandle); - } - return lines; - } - - private String nextArg() { - if (mNextArg >= mArgs.length) { - return null; - } - String arg = mArgs[mNextArg]; - mNextArg++; - return arg; - } - - String getForUser(IContentProvider provider, int userHandle, - final String table, final String key) { - final String callGetCommand; - if ("system".equals(table)) callGetCommand = Settings.CALL_METHOD_GET_SYSTEM; - else if ("secure".equals(table)) callGetCommand = Settings.CALL_METHOD_GET_SECURE; - else if ("global".equals(table)) callGetCommand = Settings.CALL_METHOD_GET_GLOBAL; - else { - System.err.println("Invalid table; no put performed"); - throw new IllegalArgumentException("Invalid table " + table); - } - - String result = null; - try { - Bundle arg = new Bundle(); - arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle); - Bundle b = provider.call(resolveCallingPackage(), callGetCommand, key, arg); - if (b != null) { - result = b.getPairValue(); - } - } catch (RemoteException e) { - System.err.println("Can't read key " + key + " in " + table + " for user " + userHandle); - } - return result; - } - - void putForUser(IContentProvider provider, int userHandle, - final String table, final String key, final String value) { - final String callPutCommand; - if ("system".equals(table)) callPutCommand = Settings.CALL_METHOD_PUT_SYSTEM; - else if ("secure".equals(table)) callPutCommand = Settings.CALL_METHOD_PUT_SECURE; - else if ("global".equals(table)) callPutCommand = Settings.CALL_METHOD_PUT_GLOBAL; - else { - System.err.println("Invalid table; no put performed"); - return; - } - - try { - Bundle arg = new Bundle(); - arg.putString(Settings.NameValueTable.VALUE, value); - arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle); - provider.call(resolveCallingPackage(), callPutCommand, key, arg); - } catch (RemoteException e) { - System.err.println("Can't set key " + key + " in " + table + " for user " + userHandle); - } - } - - int deleteForUser(IContentProvider provider, int userHandle, - final String table, final String key) { - Uri targetUri; - if ("system".equals(table)) targetUri = Settings.System.getUriFor(key); - else if ("secure".equals(table)) targetUri = Settings.Secure.getUriFor(key); - else if ("global".equals(table)) targetUri = Settings.Global.getUriFor(key); - else { - System.err.println("Invalid table; no delete performed"); - throw new IllegalArgumentException("Invalid table " + table); - } - - int num = 0; - try { - num = provider.delete(resolveCallingPackage(), targetUri, null, null); - } catch (RemoteException e) { - System.err.println("Can't clear key " + key + " in " + table + " for user " - + userHandle); - } - return num; - } - - private static void printUsage() { - System.err.println("usage: settings [--user <USER_ID> | current] get namespace key"); - System.err.println(" settings [--user <USER_ID> | current] put namespace key value"); - System.err.println(" settings [--user <USER_ID> | current] delete namespace key"); - System.err.println(" settings [--user <USER_ID> | current] list namespace"); - System.err.println("\n'namespace' is one of {system, secure, global}, case-insensitive"); - System.err.println("If '--user <USER_ID> | current' is not given, the operations are " - + "performed on the system user."); - } - - public static String resolveCallingPackage() { - switch (android.os.Process.myUid()) { - case Process.ROOT_UID: { - return "root"; - } - - case Process.SHELL_UID: { - return "com.android.shell"; - } - - default: { - return null; - } - } - } -} diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java index d527ad73b787..db3772da9e4f 100644 --- a/cmds/sm/src/com/android/commands/sm/Sm.java +++ b/cmds/sm/src/com/android/commands/sm/Sm.java @@ -20,7 +20,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; import android.os.storage.DiskInfo; -import android.os.storage.IMountService; +import android.os.storage.IStorageManager; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; import android.util.Log; @@ -28,7 +28,7 @@ import android.util.Log; public final class Sm { private static final String TAG = "Sm"; - IMountService mSm; + IStorageManager mSm; private String[] mArgs; private int mNextArg; @@ -55,7 +55,7 @@ public final class Sm { throw new IllegalArgumentException(); } - mSm = IMountService.Stub.asInterface(ServiceManager.getService("mount")); + mSm = IStorageManager.Stub.asInterface(ServiceManager.getService("mount")); if (mSm == null) { throw new RemoteException("Failed to find running mount service"); } @@ -92,6 +92,8 @@ public final class Sm { runSetEmulateFbe(); } else if ("get-fbe-mode".equals(op)) { runGetFbeMode(); + } else if ("fstrim".equals(op)) { + runFstrim(); } else { throw new IllegalArgumentException(); } @@ -210,7 +212,7 @@ public final class Sm { mSm.benchmark(volId); } - public void runForget() throws RemoteException{ + public void runForget() throws RemoteException { final String fsUuid = nextArg(); if ("all".equals(fsUuid)) { mSm.forgetAllVolumes(); @@ -219,6 +221,10 @@ public final class Sm { } } + public void runFstrim() throws RemoteException { + mSm.fstrim(0); + } + private String nextArg() { if (mNextArg >= mArgs.length) { return null; @@ -240,6 +246,7 @@ public final class Sm { System.err.println(" sm unmount VOLUME"); System.err.println(" sm format VOLUME"); System.err.println(" sm benchmark VOLUME"); + System.err.println(" sm fstrim"); System.err.println(""); System.err.println(" sm forget [UUID|all]"); System.err.println(""); diff --git a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java index cb39e375d307..32b45953fc77 100644 --- a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java +++ b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java @@ -16,9 +16,9 @@ package com.android.uiautomator.core; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; +import android.app.ContentProviderHolder; import android.app.IActivityManager; -import android.app.IActivityManager.ContentProviderHolder; import android.app.UiAutomation; import android.content.Context; import android.content.IContentProvider; @@ -56,7 +56,7 @@ public class ShellUiAutomatorBridge extends UiAutomatorBridge { try { IContentProvider provider = null; Cursor cursor = null; - IActivityManager activityManager = ActivityManagerNative.getDefault(); + IActivityManager activityManager = ActivityManager.getService(); String providerName = Settings.Secure.CONTENT_URI.getAuthority(); IBinder token = new Binder(); try { diff --git a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java index ddeb8e786271..d98b4ff3e69a 100644 --- a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java +++ b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java @@ -2,7 +2,6 @@ package com.android.uiautomator.core; import android.accessibilityservice.AccessibilityServiceInfo; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.IActivityController; import android.app.IActivityManager; import android.app.UiAutomation; @@ -44,7 +43,7 @@ public class UiAutomationShellWrapper { * @see {@link ActivityManager#isUserAMonkey()} */ public void setRunAsMonkey(boolean isSet) { - IActivityManager am = ActivityManagerNative.getDefault(); + IActivityManager am = ActivityManager.getService(); if (am == null) { throw new RuntimeException("Can't manage monkey status; is the system running?"); } diff --git a/cmds/wm/src/com/android/commands/wm/Wm.java b/cmds/wm/src/com/android/commands/wm/Wm.java index 383cd01ddcd6..8defb331e289 100644 --- a/cmds/wm/src/com/android/commands/wm/Wm.java +++ b/cmds/wm/src/com/android/commands/wm/Wm.java @@ -21,16 +21,22 @@ package com.android.commands.wm; import android.content.Context; import android.graphics.Point; import android.graphics.Rect; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.util.AndroidException; import android.util.DisplayMetrics; +import android.system.Os; import android.view.Display; import android.view.IWindowManager; import com.android.internal.os.BaseCommand; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.DataInputStream; import java.io.PrintStream; +import java.lang.Runtime; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -69,7 +75,9 @@ public class Wm extends BaseCommand { "wm screen-capture: enable/disable screen capture.\n" + "\n" + "wm dismiss-keyguard: dismiss the keyguard, prompting the user for auth if " + - "necessary.\n" + "necessary.\n" + + "\n" + + "wm surface-trace: log surface commands to stdout in a binary format.\n" ); } @@ -96,12 +104,29 @@ public class Wm extends BaseCommand { runSetScreenCapture(); } else if (op.equals("dismiss-keyguard")) { runDismissKeyguard(); + } else if (op.equals("surface-trace")) { + runSurfaceTrace(); } else { showError("Error: unknown command '" + op + "'"); return; } } + private void runSurfaceTrace() throws Exception { + ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(FileDescriptor.out); + mWm.enableSurfaceTrace(pfd); + + try { + // No one is going to wake us up, we are just waiting on SIGINT. Otherwise + // the WM can happily continue writing to our stdout. + synchronized (this) { + this.wait(); + } + } finally { + mWm.disableSurfaceTrace(); + } + } + private void runSetScreenCapture() throws Exception { String userIdStr = nextArg(); String enableStr = nextArg(); @@ -249,7 +274,7 @@ public class Wm extends BaseCommand { } private void runDismissKeyguard() throws Exception { - mWm.dismissKeyguard(); + mWm.dismissKeyguard(null /* callback */); } private int parseDimension(String s) throws NumberFormatException { |