Am.java revision c62a216a2bb877b3b8c968cc90ab6c1f10605edc
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
19package com.android.commands.am;
20
21import android.app.ActivityManagerNative;
22import android.app.IActivityManager;
23import android.app.IInstrumentationWatcher;
24import android.app.Instrumentation;
25import android.content.ComponentName;
26import android.content.Intent;
27import android.net.Uri;
28import android.os.Bundle;
29import android.os.RemoteException;
30import android.os.ServiceManager;
31import android.view.IWindowManager;
32
33import java.util.Iterator;
34import java.util.Set;
35
36public class Am {
37
38    private IActivityManager mAm;
39    private String[] mArgs;
40    private int mNextArg;
41    private String mCurArgData;
42
43    private boolean mDebugOption = false;
44
45    /**
46     * Command-line entry point.
47     *
48     * @param args The command-line arguments
49     */
50    public static void main(String[] args) {
51        (new Am()).run(args);
52    }
53
54    private void run(String[] args) {
55        if (args.length < 1) {
56            showUsage();
57            return;
58        }
59
60        mAm = ActivityManagerNative.getDefault();
61        if (mAm == null) {
62            System.err.println("Error type 2");
63            System.err.println("Error: Unable to connect to activity manager; is the system running?");
64            showUsage();
65            return;
66        }
67
68        mArgs = args;
69
70        String op = args[0];
71        mNextArg = 1;
72        if (op.equals("start")) {
73            runStart();
74        } else if (op.equals("instrument")) {
75            runInstrument();
76        } else if (op.equals("broadcast")) {
77            sendBroadcast();
78        } else if (op.equals("profile")) {
79            runProfile();
80        } else {
81            System.err.println("Error: Unknown command: " + op);
82            showUsage();
83            return;
84        }
85    }
86
87    private Intent makeIntent() {
88        Intent intent = new Intent();
89        boolean hasIntentInfo = false;
90
91        mDebugOption = false;
92        Uri data = null;
93        String type = null;
94
95        try {
96            String opt;
97            while ((opt=nextOption()) != null) {
98                if (opt.equals("-a")) {
99                    intent.setAction(nextOptionData());
100                    hasIntentInfo = true;
101                } else if (opt.equals("-d")) {
102                    data = Uri.parse(nextOptionData());
103                    hasIntentInfo = true;
104                } else if (opt.equals("-t")) {
105                    type = nextOptionData();
106                    hasIntentInfo = true;
107                } else if (opt.equals("-c")) {
108                    intent.addCategory(nextOptionData());
109                    hasIntentInfo = true;
110                } else if (opt.equals("-e") || opt.equals("--es")) {
111                    String key = nextOptionData();
112                    String value = nextOptionData();
113                    intent.putExtra(key, value);
114                    hasIntentInfo = true;
115                } else if (opt.equals("--ei")) {
116                    String key = nextOptionData();
117                    String value = nextOptionData();
118                    intent.putExtra(key, Integer.valueOf(value));
119                    hasIntentInfo = true;
120                } else if (opt.equals("--ez")) {
121                    String key = nextOptionData();
122                    String value = nextOptionData();
123                    intent.putExtra(key, Boolean.valueOf(value));
124                    hasIntentInfo = true;
125                } else if (opt.equals("-n")) {
126                    String str = nextOptionData();
127                    ComponentName cn = ComponentName.unflattenFromString(str);
128                    if (cn == null) {
129                        System.err.println("Error: Bad component name: " + str);
130                        showUsage();
131                        return null;
132                    }
133                    intent.setComponent(cn);
134                    hasIntentInfo = true;
135                } else if (opt.equals("-f")) {
136                    String str = nextOptionData();
137                    intent.setFlags(Integer.decode(str).intValue());
138                } else if (opt.equals("-D")) {
139                    mDebugOption = true;
140                } else {
141                    System.err.println("Error: Unknown option: " + opt);
142                    showUsage();
143                    return null;
144                }
145            }
146        } catch (RuntimeException ex) {
147            System.err.println("Error: " + ex.toString());
148            showUsage();
149            return null;
150        }
151        intent.setDataAndType(data, type);
152
153        String uri = nextArg();
154        if (uri != null) {
155            try {
156                Intent oldIntent = intent;
157                try {
158                    intent = Intent.getIntent(uri);
159                } catch (java.net.URISyntaxException ex) {
160                    System.err.println("Bad URI: " + uri);
161                    showUsage();
162                    return null;
163                }
164                if (oldIntent.getAction() != null) {
165                    intent.setAction(oldIntent.getAction());
166                }
167                if (oldIntent.getData() != null || oldIntent.getType() != null) {
168                    intent.setDataAndType(oldIntent.getData(), oldIntent.getType());
169                }
170                Set cats = oldIntent.getCategories();
171                if (cats != null) {
172                    Iterator it = cats.iterator();
173                    while (it.hasNext()) {
174                        intent.addCategory((String)it.next());
175                    }
176                }
177            } catch (RuntimeException ex) {
178                System.err.println("Error creating from URI: " + ex.toString());
179                showUsage();
180                return null;
181            }
182        } else if (!hasIntentInfo) {
183            System.err.println("Error: No intent supplied");
184            showUsage();
185            return null;
186        }
187
188        return intent;
189    }
190
191    private void runStart() {
192        Intent intent = makeIntent();
193
194        if (intent != null) {
195            System.out.println("Starting: " + intent);
196            try {
197                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
198                // XXX should do something to determine the MIME type.
199                int res = mAm.startActivity(null, intent, intent.getType(),
200                        null, 0, null, null, 0, false, mDebugOption);
201                switch (res) {
202                    case IActivityManager.START_SUCCESS:
203                        break;
204                    case IActivityManager.START_SWITCHES_CANCELED:
205                        System.err.println(
206                                "Warning: Activity not started because the "
207                                + " current activity is being kept for the user.");
208                        break;
209                    case IActivityManager.START_DELIVERED_TO_TOP:
210                        System.err.println(
211                                "Warning: Activity not started, intent has "
212                                + "been delivered to currently running "
213                                + "top-most instance.");
214                        break;
215                    case IActivityManager.START_RETURN_INTENT_TO_CALLER:
216                        System.err.println(
217                                "Warning: Activity not started because intent "
218                                + "should be handled by the caller");
219                        break;
220                    case IActivityManager.START_TASK_TO_FRONT:
221                        System.err.println(
222                                "Warning: Activity not started, its current "
223                                + "task has been brought to the front");
224                        break;
225                    case IActivityManager.START_INTENT_NOT_RESOLVED:
226                        System.err.println(
227                                "Error: Activity not started, unable to "
228                                + "resolve " + intent.toString());
229                        break;
230                    case IActivityManager.START_CLASS_NOT_FOUND:
231                        System.err.println("Error type 3");
232                        System.err.println("Error: Activity class " +
233                                intent.getComponent().toShortString()
234                                + " does not exist.");
235                        break;
236                    case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
237                        System.err.println(
238                                "Error: Activity not started, you requested to "
239                                + "both forward and receive its result");
240                        break;
241                    case IActivityManager.START_PERMISSION_DENIED:
242                        System.err.println(
243                                "Error: Activity not started, you do not "
244                                + "have permission to access it.");
245                        break;
246                    default:
247                        System.err.println(
248                                "Error: Activity not started, unknown error "
249                                + "code " + res);
250                        break;
251                }
252            } catch (RemoteException e) {
253                System.err.println("Error type 1");
254                System.err.println(
255                        "Error: Activity not started, unable to "
256                        + "call on to activity manager service");
257            }
258        }
259    }
260
261    private void sendBroadcast() {
262        Intent intent = makeIntent();
263
264        if (intent != null) {
265            System.out.println("Broadcasting: " + intent);
266            try {
267                mAm.broadcastIntent(null, intent, null, null, 0, null, null,
268                        null, true, false);
269            } catch (RemoteException e) {
270            }
271        }
272    }
273
274    private void runInstrument() {
275        String profileFile = null;
276        boolean wait = false;
277        boolean rawMode = false;
278        boolean no_window_animation = false;
279        Bundle args = new Bundle();
280        String argKey = null, argValue = null;
281        IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
282
283        try {
284            String opt;
285            while ((opt=nextOption()) != null) {
286                if (opt.equals("-p")) {
287                    profileFile = nextOptionData();
288                } else if (opt.equals("-w")) {
289                    wait = true;
290                } else if (opt.equals("-r")) {
291                    rawMode = true;
292                } else if (opt.equals("-e")) {
293                    argKey = nextOptionData();
294                    argValue = nextOptionData();
295                    args.putString(argKey, argValue);
296                } else if (opt.equals("--no_window_animation")) {
297                    no_window_animation = true;
298                } else {
299                    System.err.println("Error: Unknown option: " + opt);
300                    showUsage();
301                    return;
302                }
303            }
304        } catch (RuntimeException ex) {
305            System.err.println("Error: " + ex.toString());
306            showUsage();
307            return;
308        }
309
310        String cnArg = nextArg();
311        if (cnArg == null) {
312            System.err.println("Error: No instrumentation component supplied");
313            showUsage();
314            return;
315        }
316
317        ComponentName cn = ComponentName.unflattenFromString(cnArg);
318        if (cn == null) {
319            System.err.println("Error: Bad component name: " + cnArg);
320            showUsage();
321            return;
322        }
323
324        InstrumentationWatcher watcher = null;
325        if (wait) {
326            watcher = new InstrumentationWatcher();
327            watcher.setRawOutput(rawMode);
328        }
329        float[] oldAnims = null;
330        if (no_window_animation) {
331            try {
332                oldAnims = wm.getAnimationScales();
333                wm.setAnimationScale(0, 0.0f);
334                wm.setAnimationScale(1, 0.0f);
335            } catch (RemoteException e) {
336            }
337        }
338
339        try {
340            if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher)) {
341                System.out.println("INSTRUMENTATION_FAILED: " +
342                        cn.flattenToString());
343                showUsage();
344                return;
345            }
346        } catch (RemoteException e) {
347        }
348
349        if (watcher != null) {
350            if (!watcher.waitForFinish()) {
351                System.out.println("INSTRUMENTATION_ABORTED: System has crashed.");
352            }
353        }
354
355        if (oldAnims != null) {
356            try {
357                wm.setAnimationScales(oldAnims);
358            } catch (RemoteException e) {
359            }
360        }
361    }
362
363    private class InstrumentationWatcher extends IInstrumentationWatcher.Stub {
364        private boolean mFinished = false;
365        private boolean mRawMode = false;
366
367        /**
368         * Set or reset "raw mode".  In "raw mode", all bundles are dumped.  In "pretty mode",
369         * if a bundle includes Instrumentation.REPORT_KEY_STREAMRESULT, just print that.
370         * @param rawMode true for raw mode, false for pretty mode.
371         */
372        public void setRawOutput(boolean rawMode) {
373            mRawMode = rawMode;
374        }
375
376        public void instrumentationStatus(ComponentName name, int resultCode, Bundle results) {
377            synchronized (this) {
378                // pretty printer mode?
379                String pretty = null;
380                if (!mRawMode && results != null) {
381                    pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT);
382                }
383                if (pretty != null) {
384                    System.out.print(pretty);
385                } else {
386                    if (results != null) {
387                        for (String key : results.keySet()) {
388                            System.out.println(
389                                    "INSTRUMENTATION_STATUS: " + key + "=" + results.get(key));
390                        }
391                    }
392                    System.out.println("INSTRUMENTATION_STATUS_CODE: " + resultCode);
393                }
394                notifyAll();
395            }
396        }
397
398        public void instrumentationFinished(ComponentName name, int resultCode,
399                Bundle results) {
400            synchronized (this) {
401                // pretty printer mode?
402                String pretty = null;
403                if (!mRawMode && results != null) {
404                    pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT);
405                }
406                if (pretty != null) {
407                    System.out.println(pretty);
408                } else {
409                    if (results != null) {
410                        for (String key : results.keySet()) {
411                            System.out.println(
412                                    "INSTRUMENTATION_RESULT: " + key + "=" + results.get(key));
413                        }
414                    }
415                    System.out.println("INSTRUMENTATION_CODE: " + resultCode);
416                }
417                mFinished = true;
418                notifyAll();
419            }
420        }
421
422        public boolean waitForFinish() {
423            synchronized (this) {
424                while (!mFinished) {
425                    try {
426                        if (!mAm.asBinder().pingBinder()) {
427                            return false;
428                        }
429                        wait(1000);
430                    } catch (InterruptedException e) {
431                    }
432                }
433            }
434            return true;
435        }
436    }
437
438    private void runProfile() {
439        String profileFile = null;
440        boolean start = false;
441
442        String process = nextArg();
443        if (process == null) {
444            System.err.println("Error: No profile process supplied");
445            showUsage();
446            return;
447        }
448
449        String cmd = nextArg();
450        if ("start".equals(cmd)) {
451            start = true;
452            profileFile = nextArg();
453            if (profileFile == null) {
454                System.err.println("Error: No profile file path supplied");
455                showUsage();
456                return;
457            }
458        } else if (!"stop".equals(cmd)) {
459            System.err.println("Error: Profile command " + cmd + " not valid");
460            showUsage();
461            return;
462        }
463
464        try {
465            if (!mAm.profileControl(process, start, profileFile)) {
466                System.out.println("PROFILE FAILED on process " + process);
467                return;
468            }
469        } catch (IllegalArgumentException e) {
470            System.out.println("PROFILE FAILED: " + e.getMessage());
471            return;
472        } catch (IllegalStateException e) {
473            System.out.println("PROFILE FAILED: " + e.getMessage());
474            return;
475        } catch (RemoteException e) {
476            System.out.println("PROFILE FAILED: activity manager gone");
477            return;
478        }
479    }
480
481    private String nextOption() {
482        if (mNextArg >= mArgs.length) {
483            return null;
484        }
485        String arg = mArgs[mNextArg];
486        if (!arg.startsWith("-")) {
487            return null;
488        }
489        mNextArg++;
490        if (arg.equals("--")) {
491            return null;
492        }
493        if (arg.length() > 1 && arg.charAt(1) != '-') {
494            if (arg.length() > 2) {
495                mCurArgData = arg.substring(2);
496                return arg.substring(0, 2);
497            } else {
498                mCurArgData = null;
499                return arg;
500            }
501        }
502        mCurArgData = null;
503        return arg;
504    }
505
506    private String nextOptionData() {
507        if (mCurArgData != null) {
508            return mCurArgData;
509        }
510        if (mNextArg >= mArgs.length) {
511            return null;
512        }
513        String data = mArgs[mNextArg];
514        mNextArg++;
515        return data;
516    }
517
518    private String nextArg() {
519        if (mNextArg >= mArgs.length) {
520            return null;
521        }
522        String arg = mArgs[mNextArg];
523        mNextArg++;
524        return arg;
525    }
526
527    private void showUsage() {
528        System.err.println("usage: am [start|broadcast|instrument|profile]");
529        System.err.println("       am start [-D] INTENT");
530        System.err.println("       am broadcast INTENT");
531        System.err.println("       am instrument [-r] [-e <ARG_NAME> <ARG_VALUE>] [-p <PROF_FILE>]");
532        System.err.println("                [-w] <COMPONENT> ");
533        System.err.println("       am profile <PROCESS> [start <PROF_FILE>|stop]");
534        System.err.println("");
535        System.err.println("       INTENT is described with:");
536        System.err.println("                [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]");
537        System.err.println("                [-c <CATEGORY> [-c <CATEGORY>] ...]");
538        System.err.println("                [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]");
539        System.err.println("                [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]");
540        System.err.println("                [-e|--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]");
541        System.err.println("                [-n <COMPONENT>] [-f <FLAGS>] [<URI>]");
542    }
543}
544