• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 **
3 ** Copyright 2007, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 **     http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17 
18 
19 package com.android.commands.am;
20 
21 import android.app.ActivityManager;
22 import android.app.ActivityManagerNative;
23 import android.app.IActivityController;
24 import android.app.IActivityManager;
25 import android.app.IInstrumentationWatcher;
26 import android.app.Instrumentation;
27 import android.content.ComponentName;
28 import android.content.Context;
29 import android.content.IIntentReceiver;
30 import android.content.Intent;
31 import android.content.pm.IPackageManager;
32 import android.content.pm.ResolveInfo;
33 import android.net.Uri;
34 import android.os.Bundle;
35 import android.os.ParcelFileDescriptor;
36 import android.os.RemoteException;
37 import android.os.ServiceManager;
38 import android.os.SystemProperties;
39 import android.util.AndroidException;
40 import android.view.IWindowManager;
41 
42 import java.io.BufferedReader;
43 import java.io.File;
44 import java.io.FileNotFoundException;
45 import java.io.IOException;
46 import java.io.InputStreamReader;
47 import java.io.PrintStream;
48 import java.net.URISyntaxException;
49 import java.util.HashSet;
50 import java.util.List;
51 
52 public class Am {
53 
54     private IActivityManager mAm;
55     private String[] mArgs;
56     private int mNextArg;
57     private String mCurArgData;
58 
59     private boolean mDebugOption = false;
60     private boolean mWaitOption = false;
61     private boolean mStopOption = false;
62 
63     private String mProfileFile;
64     private boolean mProfileAutoStop;
65 
66     // These are magic strings understood by the Eclipse plugin.
67     private static final String FATAL_ERROR_CODE = "Error type 1";
68     private static final String NO_SYSTEM_ERROR_CODE = "Error type 2";
69     private static final String NO_CLASS_ERROR_CODE = "Error type 3";
70 
71     /**
72      * Command-line entry point.
73      *
74      * @param args The command-line arguments
75      */
main(String[] args)76     public static void main(String[] args) {
77         try {
78             (new Am()).run(args);
79         } catch (IllegalArgumentException e) {
80             showUsage();
81             System.err.println("Error: " + e.getMessage());
82         } catch (Exception e) {
83             e.printStackTrace(System.err);
84             System.exit(1);
85         }
86     }
87 
run(String[] args)88     private void run(String[] args) throws Exception {
89         if (args.length < 1) {
90             showUsage();
91             return;
92         }
93 
94         mAm = ActivityManagerNative.getDefault();
95         if (mAm == null) {
96             System.err.println(NO_SYSTEM_ERROR_CODE);
97             throw new AndroidException("Can't connect to activity manager; is the system running?");
98         }
99 
100         mArgs = args;
101         String op = args[0];
102         mNextArg = 1;
103 
104         if (op.equals("start")) {
105             runStart();
106         } else if (op.equals("startservice")) {
107             runStartService();
108         } else if (op.equals("force-stop")) {
109             runForceStop();
110         } else if (op.equals("instrument")) {
111             runInstrument();
112         } else if (op.equals("broadcast")) {
113             sendBroadcast();
114         } else if (op.equals("profile")) {
115             runProfile();
116         } else if (op.equals("dumpheap")) {
117             runDumpHeap();
118         } else if (op.equals("monitor")) {
119             runMonitor();
120         } else if (op.equals("screen-compat")) {
121             runScreenCompat();
122         } else if (op.equals("display-size")) {
123             runDisplaySize();
124         } else {
125             throw new IllegalArgumentException("Unknown command: " + op);
126         }
127     }
128 
makeIntent()129     private Intent makeIntent() throws URISyntaxException {
130         Intent intent = new Intent();
131         boolean hasIntentInfo = false;
132 
133         mDebugOption = false;
134         mWaitOption = false;
135         mStopOption = false;
136         mProfileFile = null;
137         Uri data = null;
138         String type = null;
139 
140         String opt;
141         while ((opt=nextOption()) != null) {
142             if (opt.equals("-a")) {
143                 intent.setAction(nextArgRequired());
144                 hasIntentInfo = true;
145             } else if (opt.equals("-d")) {
146                 data = Uri.parse(nextArgRequired());
147                 hasIntentInfo = true;
148             } else if (opt.equals("-t")) {
149                 type = nextArgRequired();
150                 hasIntentInfo = true;
151             } else if (opt.equals("-c")) {
152                 intent.addCategory(nextArgRequired());
153                 hasIntentInfo = true;
154             } else if (opt.equals("-e") || opt.equals("--es")) {
155                 String key = nextArgRequired();
156                 String value = nextArgRequired();
157                 intent.putExtra(key, value);
158                 hasIntentInfo = true;
159             } else if (opt.equals("--esn")) {
160                 String key = nextArgRequired();
161                 intent.putExtra(key, (String) null);
162                 hasIntentInfo = true;
163             } else if (opt.equals("--ei")) {
164                 String key = nextArgRequired();
165                 String value = nextArgRequired();
166                 intent.putExtra(key, Integer.valueOf(value));
167                 hasIntentInfo = true;
168             } else if (opt.equals("--eu")) {
169                 String key = nextArgRequired();
170                 String value = nextArgRequired();
171                 intent.putExtra(key, Uri.parse(value));
172                 hasIntentInfo = true;
173             } else if (opt.equals("--eia")) {
174                 String key = nextArgRequired();
175                 String value = nextArgRequired();
176                 String[] strings = value.split(",");
177                 int[] list = new int[strings.length];
178                 for (int i = 0; i < strings.length; i++) {
179                     list[i] = Integer.valueOf(strings[i]);
180                 }
181                 intent.putExtra(key, list);
182                 hasIntentInfo = true;
183             } else if (opt.equals("--el")) {
184                 String key = nextArgRequired();
185                 String value = nextArgRequired();
186                 intent.putExtra(key, Long.valueOf(value));
187                 hasIntentInfo = true;
188             } else if (opt.equals("--ela")) {
189                 String key = nextArgRequired();
190                 String value = nextArgRequired();
191                 String[] strings = value.split(",");
192                 long[] list = new long[strings.length];
193                 for (int i = 0; i < strings.length; i++) {
194                     list[i] = Long.valueOf(strings[i]);
195                 }
196                 intent.putExtra(key, list);
197                 hasIntentInfo = true;
198             } else if (opt.equals("--ez")) {
199                 String key = nextArgRequired();
200                 String value = nextArgRequired();
201                 intent.putExtra(key, Boolean.valueOf(value));
202                 hasIntentInfo = true;
203             } else if (opt.equals("-n")) {
204                 String str = nextArgRequired();
205                 ComponentName cn = ComponentName.unflattenFromString(str);
206                 if (cn == null) throw new IllegalArgumentException("Bad component name: " + str);
207                 intent.setComponent(cn);
208                 hasIntentInfo = true;
209             } else if (opt.equals("-f")) {
210                 String str = nextArgRequired();
211                 intent.setFlags(Integer.decode(str).intValue());
212             } else if (opt.equals("--grant-read-uri-permission")) {
213                 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
214             } else if (opt.equals("--grant-write-uri-permission")) {
215                 intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
216             } else if (opt.equals("--exclude-stopped-packages")) {
217                 intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
218             } else if (opt.equals("--include-stopped-packages")) {
219                 intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
220             } else if (opt.equals("--debug-log-resolution")) {
221                 intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
222             } else if (opt.equals("--activity-brought-to-front")) {
223                 intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
224             } else if (opt.equals("--activity-clear-top")) {
225                 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
226             } else if (opt.equals("--activity-clear-when-task-reset")) {
227                 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
228             } else if (opt.equals("--activity-exclude-from-recents")) {
229                 intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
230             } else if (opt.equals("--activity-launched-from-history")) {
231                 intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
232             } else if (opt.equals("--activity-multiple-task")) {
233                 intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
234             } else if (opt.equals("--activity-no-animation")) {
235                 intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
236             } else if (opt.equals("--activity-no-history")) {
237                 intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
238             } else if (opt.equals("--activity-no-user-action")) {
239                 intent.addFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION);
240             } else if (opt.equals("--activity-previous-is-top")) {
241                 intent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
242             } else if (opt.equals("--activity-reorder-to-front")) {
243                 intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
244             } else if (opt.equals("--activity-reset-task-if-needed")) {
245                 intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
246             } else if (opt.equals("--activity-single-top")) {
247                 intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
248             } else if (opt.equals("--activity-clear-task")) {
249                 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
250             } else if (opt.equals("--activity-task-on-home")) {
251                 intent.addFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME);
252             } else if (opt.equals("--receiver-registered-only")) {
253                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
254             } else if (opt.equals("--receiver-replace-pending")) {
255                 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
256             } else if (opt.equals("-D")) {
257                 mDebugOption = true;
258             } else if (opt.equals("-W")) {
259                 mWaitOption = true;
260             } else if (opt.equals("-P")) {
261                 mProfileFile = nextArgRequired();
262                 mProfileAutoStop = true;
263             } else if (opt.equals("--start-profiler")) {
264                 mProfileFile = nextArgRequired();
265                 mProfileAutoStop = false;
266             } else if (opt.equals("-S")) {
267                 mStopOption = true;
268             } else {
269                 System.err.println("Error: Unknown option: " + opt);
270                 showUsage();
271                 return null;
272             }
273         }
274         intent.setDataAndType(data, type);
275 
276         String arg = nextArg();
277         if (arg != null) {
278             Intent baseIntent;
279             if (arg.indexOf(':') >= 0) {
280                 // The argument is a URI.  Fully parse it, and use that result
281                 // to fill in any data not specified so far.
282                 baseIntent = Intent.parseUri(arg, Intent.URI_INTENT_SCHEME);
283             } else if (arg.indexOf('/') >= 0) {
284                 // The argument is a component name.  Build an Intent to launch
285                 // it.
286                 baseIntent = new Intent(Intent.ACTION_MAIN);
287                 baseIntent.addCategory(Intent.CATEGORY_LAUNCHER);
288                 baseIntent.setComponent(ComponentName.unflattenFromString(arg));
289             } else {
290                 // Assume the argument is a package name.
291                 baseIntent = new Intent(Intent.ACTION_MAIN);
292                 baseIntent.addCategory(Intent.CATEGORY_LAUNCHER);
293                 baseIntent.setPackage(arg);
294             }
295             Bundle extras = intent.getExtras();
296             intent.replaceExtras((Bundle)null);
297             Bundle uriExtras = baseIntent.getExtras();
298             baseIntent.replaceExtras((Bundle)null);
299             if (intent.getAction() != null && baseIntent.getCategories() != null) {
300                 HashSet<String> cats = new HashSet<String>(baseIntent.getCategories());
301                 for (String c : cats) {
302                     baseIntent.removeCategory(c);
303                 }
304             }
305             intent.fillIn(baseIntent, Intent.FILL_IN_COMPONENT);
306             if (extras == null) {
307                 extras = uriExtras;
308             } else if (uriExtras != null) {
309                 uriExtras.putAll(extras);
310                 extras = uriExtras;
311             }
312             intent.replaceExtras(extras);
313             hasIntentInfo = true;
314         }
315 
316         if (!hasIntentInfo) throw new IllegalArgumentException("No intent supplied");
317         return intent;
318     }
319 
runStartService()320     private void runStartService() throws Exception {
321         Intent intent = makeIntent();
322         System.out.println("Starting service: " + intent);
323         ComponentName cn = mAm.startService(null, intent, intent.getType());
324         if (cn == null) {
325             System.err.println("Error: Not found; no service started.");
326         }
327     }
328 
runStart()329     private void runStart() throws Exception {
330         Intent intent = makeIntent();
331 
332         String mimeType = intent.getType();
333         if (mimeType == null && intent.getData() != null
334                 && "content".equals(intent.getData().getScheme())) {
335             mimeType = mAm.getProviderMimeType(intent.getData());
336         }
337 
338         if (mStopOption) {
339             String packageName;
340             if (intent.getComponent() != null) {
341                 packageName = intent.getComponent().getPackageName();
342             } else {
343                 IPackageManager pm = IPackageManager.Stub.asInterface(
344                         ServiceManager.getService("package"));
345                 if (pm == null) {
346                     System.err.println("Error: Package manager not running; aborting");
347                     return;
348                 }
349                 List<ResolveInfo> activities = pm.queryIntentActivities(intent, mimeType, 0);
350                 if (activities == null || activities.size() <= 0) {
351                     System.err.println("Error: Intent does not match any activities: "
352                             + intent);
353                     return;
354                 } else if (activities.size() > 1) {
355                     System.err.println("Error: Intent matches multiple activities; can't stop: "
356                             + intent);
357                     return;
358                 }
359                 packageName = activities.get(0).activityInfo.packageName;
360             }
361             System.out.println("Stopping: " + packageName);
362             mAm.forceStopPackage(packageName);
363             Thread.sleep(250);
364         }
365 
366         System.out.println("Starting: " + intent);
367         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
368 
369         ParcelFileDescriptor fd = null;
370 
371         if (mProfileFile != null) {
372             try {
373                 fd = ParcelFileDescriptor.open(
374                         new File(mProfileFile),
375                         ParcelFileDescriptor.MODE_CREATE |
376                         ParcelFileDescriptor.MODE_TRUNCATE |
377                         ParcelFileDescriptor.MODE_READ_WRITE);
378             } catch (FileNotFoundException e) {
379                 System.err.println("Error: Unable to open file: " + mProfileFile);
380                 return;
381             }
382         }
383 
384         IActivityManager.WaitResult result = null;
385         int res;
386         if (mWaitOption) {
387             result = mAm.startActivityAndWait(null, intent, mimeType,
388                         null, 0, null, null, 0, false, mDebugOption,
389                         mProfileFile, fd, mProfileAutoStop);
390             res = result.result;
391         } else {
392             res = mAm.startActivity(null, intent, mimeType,
393                     null, 0, null, null, 0, false, mDebugOption,
394                     mProfileFile, fd, mProfileAutoStop);
395         }
396         PrintStream out = mWaitOption ? System.out : System.err;
397         boolean launched = false;
398         switch (res) {
399             case IActivityManager.START_SUCCESS:
400                 launched = true;
401                 break;
402             case IActivityManager.START_SWITCHES_CANCELED:
403                 launched = true;
404                 out.println(
405                         "Warning: Activity not started because the "
406                         + " current activity is being kept for the user.");
407                 break;
408             case IActivityManager.START_DELIVERED_TO_TOP:
409                 launched = true;
410                 out.println(
411                         "Warning: Activity not started, intent has "
412                         + "been delivered to currently running "
413                         + "top-most instance.");
414                 break;
415             case IActivityManager.START_RETURN_INTENT_TO_CALLER:
416                 launched = true;
417                 out.println(
418                         "Warning: Activity not started because intent "
419                         + "should be handled by the caller");
420                 break;
421             case IActivityManager.START_TASK_TO_FRONT:
422                 launched = true;
423                 out.println(
424                         "Warning: Activity not started, its current "
425                         + "task has been brought to the front");
426                 break;
427             case IActivityManager.START_INTENT_NOT_RESOLVED:
428                 out.println(
429                         "Error: Activity not started, unable to "
430                         + "resolve " + intent.toString());
431                 break;
432             case IActivityManager.START_CLASS_NOT_FOUND:
433                 out.println(NO_CLASS_ERROR_CODE);
434                 out.println("Error: Activity class " +
435                         intent.getComponent().toShortString()
436                         + " does not exist.");
437                 break;
438             case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
439                 out.println(
440                         "Error: Activity not started, you requested to "
441                         + "both forward and receive its result");
442                 break;
443             case IActivityManager.START_PERMISSION_DENIED:
444                 out.println(
445                         "Error: Activity not started, you do not "
446                         + "have permission to access it.");
447                 break;
448             default:
449                 out.println(
450                         "Error: Activity not started, unknown error code " + res);
451                 break;
452         }
453         if (mWaitOption && launched) {
454             if (result == null) {
455                 result = new IActivityManager.WaitResult();
456                 result.who = intent.getComponent();
457             }
458             System.out.println("Status: " + (result.timeout ? "timeout" : "ok"));
459             if (result.who != null) {
460                 System.out.println("Activity: " + result.who.flattenToShortString());
461             }
462             if (result.thisTime >= 0) {
463                 System.out.println("ThisTime: " + result.thisTime);
464             }
465             if (result.totalTime >= 0) {
466                 System.out.println("TotalTime: " + result.totalTime);
467             }
468             System.out.println("Complete");
469         }
470     }
471 
runForceStop()472     private void runForceStop() throws Exception {
473         mAm.forceStopPackage(nextArgRequired());
474     }
475 
sendBroadcast()476     private void sendBroadcast() throws Exception {
477         Intent intent = makeIntent();
478         IntentReceiver receiver = new IntentReceiver();
479         System.out.println("Broadcasting: " + intent);
480         mAm.broadcastIntent(null, intent, null, receiver, 0, null, null, null, true, false);
481         receiver.waitForFinish();
482     }
483 
runInstrument()484     private void runInstrument() throws Exception {
485         String profileFile = null;
486         boolean wait = false;
487         boolean rawMode = false;
488         boolean no_window_animation = false;
489         Bundle args = new Bundle();
490         String argKey = null, argValue = null;
491         IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
492 
493         String opt;
494         while ((opt=nextOption()) != null) {
495             if (opt.equals("-p")) {
496                 profileFile = nextArgRequired();
497             } else if (opt.equals("-w")) {
498                 wait = true;
499             } else if (opt.equals("-r")) {
500                 rawMode = true;
501             } else if (opt.equals("-e")) {
502                 argKey = nextArgRequired();
503                 argValue = nextArgRequired();
504                 args.putString(argKey, argValue);
505             } else if (opt.equals("--no_window_animation")
506                     || opt.equals("--no-window-animation")) {
507                 no_window_animation = true;
508             } else {
509                 System.err.println("Error: Unknown option: " + opt);
510                 showUsage();
511                 return;
512             }
513         }
514 
515         String cnArg = nextArgRequired();
516         ComponentName cn = ComponentName.unflattenFromString(cnArg);
517         if (cn == null) throw new IllegalArgumentException("Bad component name: " + cnArg);
518 
519         InstrumentationWatcher watcher = null;
520         if (wait) {
521             watcher = new InstrumentationWatcher();
522             watcher.setRawOutput(rawMode);
523         }
524         float[] oldAnims = null;
525         if (no_window_animation) {
526             oldAnims = wm.getAnimationScales();
527             wm.setAnimationScale(0, 0.0f);
528             wm.setAnimationScale(1, 0.0f);
529         }
530 
531         if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher)) {
532             throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
533         }
534 
535         if (watcher != null) {
536             if (!watcher.waitForFinish()) {
537                 System.out.println("INSTRUMENTATION_ABORTED: System has crashed.");
538             }
539         }
540 
541         if (oldAnims != null) {
542             wm.setAnimationScales(oldAnims);
543         }
544     }
545 
removeWallOption()546     static void removeWallOption() {
547         String props = SystemProperties.get("dalvik.vm.extra-opts");
548         if (props != null && props.contains("-Xprofile:wallclock")) {
549             props = props.replace("-Xprofile:wallclock", "");
550             props = props.trim();
551             SystemProperties.set("dalvik.vm.extra-opts", props);
552         }
553     }
554 
runProfile()555     private void runProfile() throws Exception {
556         String profileFile = null;
557         boolean start = false;
558         boolean wall = false;
559         int profileType = 0;
560 
561         String process = null;
562 
563         String cmd = nextArgRequired();
564         if ("looper".equals(cmd)) {
565             cmd = nextArgRequired();
566             profileType = 1;
567         }
568 
569         if ("start".equals(cmd)) {
570             start = true;
571             wall = "--wall".equals(nextOption());
572             process = nextArgRequired();
573         } else if ("stop".equals(cmd)) {
574             process = nextArg();
575         } else {
576             // Compatibility with old syntax: process is specified first.
577             process = cmd;
578             cmd = nextArgRequired();
579             if ("start".equals(cmd)) {
580                 start = true;
581             } else if (!"stop".equals(cmd)) {
582                 throw new IllegalArgumentException("Profile command " + process + " not valid");
583             }
584         }
585 
586         ParcelFileDescriptor fd = null;
587 
588         if (start) {
589             profileFile = nextArgRequired();
590             try {
591                 fd = ParcelFileDescriptor.open(
592                         new File(profileFile),
593                         ParcelFileDescriptor.MODE_CREATE |
594                         ParcelFileDescriptor.MODE_TRUNCATE |
595                         ParcelFileDescriptor.MODE_READ_WRITE);
596             } catch (FileNotFoundException e) {
597                 System.err.println("Error: Unable to open file: " + profileFile);
598                 return;
599             }
600         }
601 
602         try {
603             if (wall) {
604                 // XXX doesn't work -- this needs to be set before booting.
605                 String props = SystemProperties.get("dalvik.vm.extra-opts");
606                 if (props == null || !props.contains("-Xprofile:wallclock")) {
607                     props = props + " -Xprofile:wallclock";
608                     //SystemProperties.set("dalvik.vm.extra-opts", props);
609                 }
610             } else if (start) {
611                 //removeWallOption();
612             }
613             if (!mAm.profileControl(process, start, profileFile, fd, profileType)) {
614                 wall = false;
615                 throw new AndroidException("PROFILE FAILED on process " + process);
616             }
617         } finally {
618             if (!wall) {
619                 //removeWallOption();
620             }
621         }
622     }
623 
runDumpHeap()624     private void runDumpHeap() throws Exception {
625         boolean managed = !"-n".equals(nextOption());
626         String process = nextArgRequired();
627         String heapFile = nextArgRequired();
628         ParcelFileDescriptor fd = null;
629 
630         try {
631             fd = ParcelFileDescriptor.open(
632                     new File(heapFile),
633                     ParcelFileDescriptor.MODE_CREATE |
634                     ParcelFileDescriptor.MODE_TRUNCATE |
635                     ParcelFileDescriptor.MODE_READ_WRITE);
636         } catch (FileNotFoundException e) {
637             System.err.println("Error: Unable to open file: " + heapFile);
638             return;
639         }
640 
641         if (!mAm.dumpHeap(process, managed, heapFile, fd)) {
642             throw new AndroidException("HEAP DUMP FAILED on process " + process);
643         }
644     }
645 
646     class MyActivityController extends IActivityController.Stub {
647         final String mGdbPort;
648 
649         static final int STATE_NORMAL = 0;
650         static final int STATE_CRASHED = 1;
651         static final int STATE_EARLY_ANR = 2;
652         static final int STATE_ANR = 3;
653 
654         int mState;
655 
656         static final int RESULT_DEFAULT = 0;
657 
658         static final int RESULT_CRASH_DIALOG = 0;
659         static final int RESULT_CRASH_KILL = 1;
660 
661         static final int RESULT_EARLY_ANR_CONTINUE = 0;
662         static final int RESULT_EARLY_ANR_KILL = 1;
663 
664         static final int RESULT_ANR_DIALOG = 0;
665         static final int RESULT_ANR_KILL = 1;
666         static final int RESULT_ANR_WAIT = 1;
667 
668         int mResult;
669 
670         Process mGdbProcess;
671         Thread mGdbThread;
672         boolean mGotGdbPrint;
673 
MyActivityController(String gdbPort)674         MyActivityController(String gdbPort) {
675             mGdbPort = gdbPort;
676         }
677 
678         @Override
activityResuming(String pkg)679         public boolean activityResuming(String pkg) throws RemoteException {
680             synchronized (this) {
681                 System.out.println("** Activity resuming: " + pkg);
682             }
683             return true;
684         }
685 
686         @Override
activityStarting(Intent intent, String pkg)687         public boolean activityStarting(Intent intent, String pkg) throws RemoteException {
688             synchronized (this) {
689                 System.out.println("** Activity starting: " + pkg);
690             }
691             return true;
692         }
693 
694         @Override
appCrashed(String processName, int pid, String shortMsg, String longMsg, long timeMillis, String stackTrace)695         public boolean appCrashed(String processName, int pid, String shortMsg, String longMsg,
696                 long timeMillis, String stackTrace) throws RemoteException {
697             synchronized (this) {
698                 System.out.println("** ERROR: PROCESS CRASHED");
699                 System.out.println("processName: " + processName);
700                 System.out.println("processPid: " + pid);
701                 System.out.println("shortMsg: " + shortMsg);
702                 System.out.println("longMsg: " + longMsg);
703                 System.out.println("timeMillis: " + timeMillis);
704                 System.out.println("stack:");
705                 System.out.print(stackTrace);
706                 System.out.println("#");
707                 int result = waitControllerLocked(pid, STATE_CRASHED);
708                 return result == RESULT_CRASH_KILL ? false : true;
709             }
710         }
711 
712         @Override
appEarlyNotResponding(String processName, int pid, String annotation)713         public int appEarlyNotResponding(String processName, int pid, String annotation)
714                 throws RemoteException {
715             synchronized (this) {
716                 System.out.println("** ERROR: EARLY PROCESS NOT RESPONDING");
717                 System.out.println("processName: " + processName);
718                 System.out.println("processPid: " + pid);
719                 System.out.println("annotation: " + annotation);
720                 int result = waitControllerLocked(pid, STATE_EARLY_ANR);
721                 if (result == RESULT_EARLY_ANR_KILL) return -1;
722                 return 0;
723             }
724         }
725 
726         @Override
appNotResponding(String processName, int pid, String processStats)727         public int appNotResponding(String processName, int pid, String processStats)
728                 throws RemoteException {
729             synchronized (this) {
730                 System.out.println("** ERROR: PROCESS NOT RESPONDING");
731                 System.out.println("processName: " + processName);
732                 System.out.println("processPid: " + pid);
733                 System.out.println("processStats:");
734                 System.out.print(processStats);
735                 System.out.println("#");
736                 int result = waitControllerLocked(pid, STATE_ANR);
737                 if (result == RESULT_ANR_KILL) return -1;
738                 if (result == RESULT_ANR_WAIT) return 1;
739                 return 0;
740             }
741         }
742 
killGdbLocked()743         void killGdbLocked() {
744             mGotGdbPrint = false;
745             if (mGdbProcess != null) {
746                 System.out.println("Stopping gdbserver");
747                 mGdbProcess.destroy();
748                 mGdbProcess = null;
749             }
750             if (mGdbThread != null) {
751                 mGdbThread.interrupt();
752                 mGdbThread = null;
753             }
754         }
755 
waitControllerLocked(int pid, int state)756         int waitControllerLocked(int pid, int state) {
757             if (mGdbPort != null) {
758                 killGdbLocked();
759 
760                 try {
761                     System.out.println("Starting gdbserver on port " + mGdbPort);
762                     System.out.println("Do the following:");
763                     System.out.println("  adb forward tcp:" + mGdbPort + " tcp:" + mGdbPort);
764                     System.out.println("  gdbclient app_process :" + mGdbPort);
765 
766                     mGdbProcess = Runtime.getRuntime().exec(new String[] {
767                             "gdbserver", ":" + mGdbPort, "--attach", Integer.toString(pid)
768                     });
769                     final InputStreamReader converter = new InputStreamReader(
770                             mGdbProcess.getInputStream());
771                     mGdbThread = new Thread() {
772                         @Override
773                         public void run() {
774                             BufferedReader in = new BufferedReader(converter);
775                             String line;
776                             int count = 0;
777                             while (true) {
778                                 synchronized (MyActivityController.this) {
779                                     if (mGdbThread == null) {
780                                         return;
781                                     }
782                                     if (count == 2) {
783                                         mGotGdbPrint = true;
784                                         MyActivityController.this.notifyAll();
785                                     }
786                                 }
787                                 try {
788                                     line = in.readLine();
789                                     if (line == null) {
790                                         return;
791                                     }
792                                     System.out.println("GDB: " + line);
793                                     count++;
794                                 } catch (IOException e) {
795                                     return;
796                                 }
797                             }
798                         }
799                     };
800                     mGdbThread.start();
801 
802                     // Stupid waiting for .5s.  Doesn't matter if we end early.
803                     try {
804                         this.wait(500);
805                     } catch (InterruptedException e) {
806                     }
807 
808                 } catch (IOException e) {
809                     System.err.println("Failure starting gdbserver: " + e);
810                     killGdbLocked();
811                 }
812             }
813             mState = state;
814             System.out.println("");
815             printMessageForState();
816 
817             while (mState != STATE_NORMAL) {
818                 try {
819                     wait();
820                 } catch (InterruptedException e) {
821                 }
822             }
823 
824             killGdbLocked();
825 
826             return mResult;
827         }
828 
resumeController(int result)829         void resumeController(int result) {
830             synchronized (this) {
831                 mState = STATE_NORMAL;
832                 mResult = result;
833                 notifyAll();
834             }
835         }
836 
printMessageForState()837         void printMessageForState() {
838             switch (mState) {
839                 case STATE_NORMAL:
840                     System.out.println("Monitoring activity manager...  available commands:");
841                     break;
842                 case STATE_CRASHED:
843                     System.out.println("Waiting after crash...  available commands:");
844                     System.out.println("(c)ontinue: show crash dialog");
845                     System.out.println("(k)ill: immediately kill app");
846                     break;
847                 case STATE_EARLY_ANR:
848                     System.out.println("Waiting after early ANR...  available commands:");
849                     System.out.println("(c)ontinue: standard ANR processing");
850                     System.out.println("(k)ill: immediately kill app");
851                     break;
852                 case STATE_ANR:
853                     System.out.println("Waiting after ANR...  available commands:");
854                     System.out.println("(c)ontinue: show ANR dialog");
855                     System.out.println("(k)ill: immediately kill app");
856                     System.out.println("(w)ait: wait some more");
857                     break;
858             }
859             System.out.println("(q)uit: finish monitoring");
860         }
861 
run()862         void run() throws RemoteException {
863             try {
864                 printMessageForState();
865 
866                 mAm.setActivityController(this);
867                 mState = STATE_NORMAL;
868 
869                 InputStreamReader converter = new InputStreamReader(System.in);
870                 BufferedReader in = new BufferedReader(converter);
871                 String line;
872 
873                 while ((line = in.readLine()) != null) {
874                     boolean addNewline = true;
875                     if (line.length() <= 0) {
876                         addNewline = false;
877                     } else if ("q".equals(line) || "quit".equals(line)) {
878                         resumeController(RESULT_DEFAULT);
879                         break;
880                     } else if (mState == STATE_CRASHED) {
881                         if ("c".equals(line) || "continue".equals(line)) {
882                             resumeController(RESULT_CRASH_DIALOG);
883                         } else if ("k".equals(line) || "kill".equals(line)) {
884                             resumeController(RESULT_CRASH_KILL);
885                         } else {
886                             System.out.println("Invalid command: " + line);
887                         }
888                     } else if (mState == STATE_ANR) {
889                         if ("c".equals(line) || "continue".equals(line)) {
890                             resumeController(RESULT_ANR_DIALOG);
891                         } else if ("k".equals(line) || "kill".equals(line)) {
892                             resumeController(RESULT_ANR_KILL);
893                         } else if ("w".equals(line) || "wait".equals(line)) {
894                             resumeController(RESULT_ANR_WAIT);
895                         } else {
896                             System.out.println("Invalid command: " + line);
897                         }
898                     } else if (mState == STATE_EARLY_ANR) {
899                         if ("c".equals(line) || "continue".equals(line)) {
900                             resumeController(RESULT_EARLY_ANR_CONTINUE);
901                         } else if ("k".equals(line) || "kill".equals(line)) {
902                             resumeController(RESULT_EARLY_ANR_KILL);
903                         } else {
904                             System.out.println("Invalid command: " + line);
905                         }
906                     } else {
907                         System.out.println("Invalid command: " + line);
908                     }
909 
910                     synchronized (this) {
911                         if (addNewline) {
912                             System.out.println("");
913                         }
914                         printMessageForState();
915                     }
916                 }
917 
918             } catch (IOException e) {
919                 e.printStackTrace();
920             } finally {
921                 mAm.setActivityController(null);
922             }
923         }
924     }
925 
runMonitor()926     private void runMonitor() throws Exception {
927         String opt;
928         String gdbPort = null;
929         while ((opt=nextOption()) != null) {
930             if (opt.equals("--gdb")) {
931                 gdbPort = nextArgRequired();
932             } else {
933                 System.err.println("Error: Unknown option: " + opt);
934                 showUsage();
935                 return;
936             }
937         }
938 
939         MyActivityController controller = new MyActivityController(gdbPort);
940         controller.run();
941     }
942 
runScreenCompat()943     private void runScreenCompat() throws Exception {
944         String mode = nextArgRequired();
945         boolean enabled;
946         if ("on".equals(mode)) {
947             enabled = true;
948         } else if ("off".equals(mode)) {
949             enabled = false;
950         } else {
951             System.err.println("Error: enabled mode must be 'on' or 'off' at " + mode);
952             showUsage();
953             return;
954         }
955 
956         String packageName = nextArgRequired();
957         do {
958             try {
959                 mAm.setPackageScreenCompatMode(packageName, enabled
960                         ? ActivityManager.COMPAT_MODE_ENABLED
961                         : ActivityManager.COMPAT_MODE_DISABLED);
962             } catch (RemoteException e) {
963             }
964             packageName = nextArg();
965         } while (packageName != null);
966     }
967 
runDisplaySize()968     private void runDisplaySize() throws Exception {
969         String size = nextArgRequired();
970         int m, n;
971         if ("reset".equals(size)) {
972             m = n = -1;
973         } else {
974             int div = size.indexOf('x');
975             if (div <= 0 || div >= (size.length()-1)) {
976                 System.err.println("Error: bad size " + size);
977                 showUsage();
978                 return;
979             }
980             String mstr = size.substring(0, div);
981             String nstr = size.substring(div+1);
982             try {
983                 m = Integer.parseInt(mstr);
984                 n = Integer.parseInt(nstr);
985             } catch (NumberFormatException e) {
986                 System.err.println("Error: bad number " + e);
987                 showUsage();
988                 return;
989             }
990         }
991 
992         if (m < n) {
993             int tmp = m;
994             m = n;
995             n = tmp;
996         }
997 
998         IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.checkService(
999                 Context.WINDOW_SERVICE));
1000         if (wm == null) {
1001             System.err.println(NO_SYSTEM_ERROR_CODE);
1002             throw new AndroidException("Can't connect to window manager; is the system running?");
1003         }
1004 
1005         try {
1006             if (m >= 0 && n >= 0) {
1007                 wm.setForcedDisplaySize(m, n);
1008             } else {
1009                 wm.clearForcedDisplaySize();
1010             }
1011         } catch (RemoteException e) {
1012         }
1013     }
1014 
1015     private class IntentReceiver extends IIntentReceiver.Stub {
1016         private boolean mFinished = false;
1017 
performReceive( Intent intent, int rc, String data, Bundle ext, boolean ord, boolean sticky)1018         public synchronized void performReceive(
1019                 Intent intent, int rc, String data, Bundle ext, boolean ord,
1020                 boolean sticky) {
1021             String line = "Broadcast completed: result=" + rc;
1022             if (data != null) line = line + ", data=\"" + data + "\"";
1023             if (ext != null) line = line + ", extras: " + ext;
1024             System.out.println(line);
1025             mFinished = true;
1026             notifyAll();
1027         }
1028 
waitForFinish()1029         public synchronized void waitForFinish() {
1030             try {
1031                 while (!mFinished) wait();
1032             } catch (InterruptedException e) {
1033                 throw new IllegalStateException(e);
1034             }
1035         }
1036     }
1037 
1038     private class InstrumentationWatcher extends IInstrumentationWatcher.Stub {
1039         private boolean mFinished = false;
1040         private boolean mRawMode = false;
1041 
1042         /**
1043          * Set or reset "raw mode".  In "raw mode", all bundles are dumped.  In "pretty mode",
1044          * if a bundle includes Instrumentation.REPORT_KEY_STREAMRESULT, just print that.
1045          * @param rawMode true for raw mode, false for pretty mode.
1046          */
setRawOutput(boolean rawMode)1047         public void setRawOutput(boolean rawMode) {
1048             mRawMode = rawMode;
1049         }
1050 
instrumentationStatus(ComponentName name, int resultCode, Bundle results)1051         public void instrumentationStatus(ComponentName name, int resultCode, Bundle results) {
1052             synchronized (this) {
1053                 // pretty printer mode?
1054                 String pretty = null;
1055                 if (!mRawMode && results != null) {
1056                     pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT);
1057                 }
1058                 if (pretty != null) {
1059                     System.out.print(pretty);
1060                 } else {
1061                     if (results != null) {
1062                         for (String key : results.keySet()) {
1063                             System.out.println(
1064                                     "INSTRUMENTATION_STATUS: " + key + "=" + results.get(key));
1065                         }
1066                     }
1067                     System.out.println("INSTRUMENTATION_STATUS_CODE: " + resultCode);
1068                 }
1069                 notifyAll();
1070             }
1071         }
1072 
instrumentationFinished(ComponentName name, int resultCode, Bundle results)1073         public void instrumentationFinished(ComponentName name, int resultCode,
1074                 Bundle results) {
1075             synchronized (this) {
1076                 // pretty printer mode?
1077                 String pretty = null;
1078                 if (!mRawMode && results != null) {
1079                     pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT);
1080                 }
1081                 if (pretty != null) {
1082                     System.out.println(pretty);
1083                 } else {
1084                     if (results != null) {
1085                         for (String key : results.keySet()) {
1086                             System.out.println(
1087                                     "INSTRUMENTATION_RESULT: " + key + "=" + results.get(key));
1088                         }
1089                     }
1090                     System.out.println("INSTRUMENTATION_CODE: " + resultCode);
1091                 }
1092                 mFinished = true;
1093                 notifyAll();
1094             }
1095         }
1096 
waitForFinish()1097         public boolean waitForFinish() {
1098             synchronized (this) {
1099                 while (!mFinished) {
1100                     try {
1101                         if (!mAm.asBinder().pingBinder()) {
1102                             return false;
1103                         }
1104                         wait(1000);
1105                     } catch (InterruptedException e) {
1106                         throw new IllegalStateException(e);
1107                     }
1108                 }
1109             }
1110             return true;
1111         }
1112     }
1113 
nextOption()1114     private String nextOption() {
1115         if (mCurArgData != null) {
1116             String prev = mArgs[mNextArg - 1];
1117             throw new IllegalArgumentException("No argument expected after \"" + prev + "\"");
1118         }
1119         if (mNextArg >= mArgs.length) {
1120             return null;
1121         }
1122         String arg = mArgs[mNextArg];
1123         if (!arg.startsWith("-")) {
1124             return null;
1125         }
1126         mNextArg++;
1127         if (arg.equals("--")) {
1128             return null;
1129         }
1130         if (arg.length() > 1 && arg.charAt(1) != '-') {
1131             if (arg.length() > 2) {
1132                 mCurArgData = arg.substring(2);
1133                 return arg.substring(0, 2);
1134             } else {
1135                 mCurArgData = null;
1136                 return arg;
1137             }
1138         }
1139         mCurArgData = null;
1140         return arg;
1141     }
1142 
nextArg()1143     private String nextArg() {
1144         if (mCurArgData != null) {
1145             String arg = mCurArgData;
1146             mCurArgData = null;
1147             return arg;
1148         } else if (mNextArg < mArgs.length) {
1149             return mArgs[mNextArg++];
1150         } else {
1151             return null;
1152         }
1153     }
1154 
nextArgRequired()1155     private String nextArgRequired() {
1156         String arg = nextArg();
1157         if (arg == null) {
1158             String prev = mArgs[mNextArg - 1];
1159             throw new IllegalArgumentException("Argument expected after \"" + prev + "\"");
1160         }
1161         return arg;
1162     }
1163 
showUsage()1164     private static void showUsage() {
1165         System.err.println(
1166                 "usage: am [subcommand] [options]\n" +
1167                 "usage: am start [-D] [-W] [-P <FILE>] [--start-profiler <FILE>] [-S] <INTENT>\n" +
1168                 "       am startservice <INTENT>\n" +
1169                 "       am force-stop <PACKAGE>\n" +
1170                 "       am broadcast <INTENT>\n" +
1171                 "       am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]\n" +
1172                 "               [--no-window-animation] <COMPONENT>\n" +
1173                 "       am profile [looper] start <PROCESS> <FILE>\n" +
1174                 "       am profile [looper] stop [<PROCESS>]\n" +
1175                 "       am dumpheap [flags] <PROCESS> <FILE>\n" +
1176                 "       am monitor [--gdb <port>]\n" +
1177                 "       am screen-compat [on|off] <PACKAGE>\n" +
1178                 "       am display-size [reset|MxN]\n" +
1179                 "\n" +
1180                 "am start: start an Activity.  Options are:\n" +
1181                 "    -D: enable debugging\n" +
1182                 "    -W: wait for launch to complete\n" +
1183                 "    --start-profiler <FILE>: start profiler and send results to <FILE>\n" +
1184                 "    -P <FILE>: like above, but profiling stops when app goes idle\n" +
1185                 "    -S: force stop the target app before starting the activity\n" +
1186                 "\n" +
1187                 "am startservice: start a Service.\n" +
1188                 "\n" +
1189                 "am force-stop: force stop everything associated with <PACKAGE>.\n" +
1190                 "\n" +
1191                 "am broadcast: send a broadcast Intent.\n" +
1192                 "\n" +
1193                 "am instrument: start an Instrumentation.  Typically this target <COMPONENT>\n" +
1194                 "  is the form <TEST_PACKAGE>/<RUNNER_CLASS>.  Options are:\n" +
1195                 "    -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT).  Use with\n" +
1196                 "        [-e perf true] to generate raw output for performance measurements.\n" +
1197                 "    -e <NAME> <VALUE>: set argument <NAME> to <VALUE>.  For test runners a\n" +
1198                 "        common form is [-e <testrunner_flag> <value>[,<value>...]].\n" +
1199                 "    -p <FILE>: write profiling data to <FILE>\n" +
1200                 "    -w: wait for instrumentation to finish before returning.  Required for\n" +
1201                 "        test runners.\n" +
1202                 "    --no-window-animation: turn off window animations will running.\n" +
1203                 "\n" +
1204                 "am profile: start and stop profiler on a process.\n" +
1205                 "\n" +
1206                 "am dumpheap: dump the heap of a process.  Options are:\n" +
1207                 "    -n: dump native heap instead of managed heap\n" +
1208                 "\n" +
1209                 "am monitor: start monitoring for crashes or ANRs.\n" +
1210                 "    --gdb: start gdbserv on the given port at crash/ANR\n" +
1211                 "\n" +
1212                 "am screen-compat: control screen compatibility mode of <PACKAGE>.\n" +
1213                 "\n" +
1214                 "am display-size: override display size.\n" +
1215                 "\n" +
1216                 "<INTENT> specifications include these flags and arguments:\n" +
1217                 "    [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
1218                 "    [-c <CATEGORY> [-c <CATEGORY>] ...]\n" +
1219                 "    [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]\n" +
1220                 "    [--esn <EXTRA_KEY> ...]\n" +
1221                 "    [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" +
1222                 "    [--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" +
1223                 "    [--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]\n" +
1224                 "    [--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]\n" +
1225                 "    [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" +
1226                 "    [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" +
1227                 "    [-n <COMPONENT>] [-f <FLAGS>]\n" +
1228                 "    [--grant-read-uri-permission] [--grant-write-uri-permission]\n" +
1229                 "    [--debug-log-resolution] [--exclude-stopped-packages]\n" +
1230                 "    [--include-stopped-packages]\n" +
1231                 "    [--activity-brought-to-front] [--activity-clear-top]\n" +
1232                 "    [--activity-clear-when-task-reset] [--activity-exclude-from-recents]\n" +
1233                 "    [--activity-launched-from-history] [--activity-multiple-task]\n" +
1234                 "    [--activity-no-animation] [--activity-no-history]\n" +
1235                 "    [--activity-no-user-action] [--activity-previous-is-top]\n" +
1236                 "    [--activity-reorder-to-front] [--activity-reset-task-if-needed]\n" +
1237                 "    [--activity-single-top] [--activity-clear-task]\n" +
1238                 "    [--activity-task-on-home]\n" +
1239                 "    [--receiver-registered-only] [--receiver-replace-pending]\n" +
1240                 "    [<URI> | <PACKAGE> | <COMPONENT>]\n"
1241                 );
1242     }
1243 }
1244