Am.java revision f5b4b98fada53d91c4c2ebeb5a1d33ccc95c94d2
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_CLASS_NOT_FOUND:
205                        System.err.println("Error type 3");
206                        System.err.println("Error: Activity class " +
207                                intent.getComponent().toShortString()
208                                + " does not exist.");
209                        break;
210                    case IActivityManager.START_DELIVERED_TO_TOP:
211                        System.err.println(
212                                "Warning: Activity not started, intent has "
213                                + "been delivered to currently running "
214                                + "top-most instance.");
215                        break;
216                    case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
217                        System.err.println(
218                                "Error: Activity not started, you requested to "
219                                + "both forward and receive its result");
220                        break;
221                    case IActivityManager.START_INTENT_NOT_RESOLVED:
222                        System.err.println(
223                                "Error: Activity not started, unable to "
224                                + "resolve " + intent.toString());
225                        break;
226                    case IActivityManager.START_RETURN_INTENT_TO_CALLER:
227                        System.err.println(
228                                "Warning: Activity not started because intent "
229                                + "should be handled by the caller");
230                        break;
231                    case IActivityManager.START_TASK_TO_FRONT:
232                        System.err.println(
233                                "Warning: Activity not started, its current "
234                                + "task has been brought to the front");
235                        break;
236                    default:
237                        System.err.println(
238                                "Error: Activity not started, unknown error "
239                                + "code " + res);
240                        break;
241                }
242            } catch (RemoteException e) {
243                System.err.println("Error type 1");
244                System.err.println(
245                        "Error: Activity not started, unable to "
246                        + "call on to activity manager service");
247            }
248        }
249    }
250
251    private void sendBroadcast() {
252        Intent intent = makeIntent();
253
254        if (intent != null) {
255            System.out.println("Broadcasting: " + intent);
256            try {
257                mAm.broadcastIntent(null, intent, null, null, 0, null, null,
258                        null, true, false);
259            } catch (RemoteException e) {
260            }
261        }
262    }
263
264    private void runInstrument() {
265        String profileFile = null;
266        boolean wait = false;
267        boolean rawMode = false;
268        boolean no_window_animation = false;
269        Bundle args = new Bundle();
270        String argKey = null, argValue = null;
271        IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
272
273        try {
274            String opt;
275            while ((opt=nextOption()) != null) {
276                if (opt.equals("-p")) {
277                    profileFile = nextOptionData();
278                } else if (opt.equals("-w")) {
279                    wait = true;
280                } else if (opt.equals("-r")) {
281                    rawMode = true;
282                } else if (opt.equals("-e")) {
283                    argKey = nextOptionData();
284                    argValue = nextOptionData();
285                    args.putString(argKey, argValue);
286                } else if (opt.equals("--no_window_animation")) {
287                    no_window_animation = true;
288                } else {
289                    System.err.println("Error: Unknown option: " + opt);
290                    showUsage();
291                    return;
292                }
293            }
294        } catch (RuntimeException ex) {
295            System.err.println("Error: " + ex.toString());
296            showUsage();
297            return;
298        }
299
300        String cnArg = nextArg();
301        if (cnArg == null) {
302            System.err.println("Error: No instrumentation component supplied");
303            showUsage();
304            return;
305        }
306
307        ComponentName cn = ComponentName.unflattenFromString(cnArg);
308        if (cn == null) {
309            System.err.println("Error: Bad component name: " + cnArg);
310            showUsage();
311            return;
312        }
313
314        InstrumentationWatcher watcher = null;
315        if (wait) {
316            watcher = new InstrumentationWatcher();
317            watcher.setRawOutput(rawMode);
318        }
319        float[] oldAnims = null;
320        if (no_window_animation) {
321            try {
322                oldAnims = wm.getAnimationScales();
323                wm.setAnimationScale(0, 0.0f);
324                wm.setAnimationScale(1, 0.0f);
325            } catch (RemoteException e) {
326            }
327        }
328
329        try {
330            if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher)) {
331                System.out.println("INSTRUMENTATION_FAILED: " +
332                        cn.flattenToString());
333                showUsage();
334                return;
335            }
336        } catch (RemoteException e) {
337        }
338
339        if (watcher != null) {
340            if (!watcher.waitForFinish()) {
341                System.out.println("INSTRUMENTATION_ABORTED: System has crashed.");
342            }
343        }
344
345        if (oldAnims != null) {
346            try {
347                wm.setAnimationScales(oldAnims);
348            } catch (RemoteException e) {
349            }
350        }
351    }
352
353    private class InstrumentationWatcher extends IInstrumentationWatcher.Stub {
354        private boolean mFinished = false;
355        private boolean mRawMode = false;
356
357        /**
358         * Set or reset "raw mode".  In "raw mode", all bundles are dumped.  In "pretty mode",
359         * if a bundle includes Instrumentation.REPORT_KEY_STREAMRESULT, just print that.
360         * @param rawMode true for raw mode, false for pretty mode.
361         */
362        public void setRawOutput(boolean rawMode) {
363            mRawMode = rawMode;
364        }
365
366        public void instrumentationStatus(ComponentName name, int resultCode, Bundle results) {
367            synchronized (this) {
368                // pretty printer mode?
369                String pretty = null;
370                if (!mRawMode && results != null) {
371                    pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT);
372                }
373                if (pretty != null) {
374                    System.out.print(pretty);
375                } else {
376                    if (results != null) {
377                        for (String key : results.keySet()) {
378                            System.out.println(
379                                    "INSTRUMENTATION_STATUS: " + key + "=" + results.get(key));
380                        }
381                    }
382                    System.out.println("INSTRUMENTATION_STATUS_CODE: " + resultCode);
383                }
384                notifyAll();
385            }
386        }
387
388        public void instrumentationFinished(ComponentName name, int resultCode,
389                Bundle results) {
390            synchronized (this) {
391                // pretty printer mode?
392                String pretty = null;
393                if (!mRawMode && results != null) {
394                    pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT);
395                }
396                if (pretty != null) {
397                    System.out.println(pretty);
398                } else {
399                    if (results != null) {
400                        for (String key : results.keySet()) {
401                            System.out.println(
402                                    "INSTRUMENTATION_RESULT: " + key + "=" + results.get(key));
403                        }
404                    }
405                    System.out.println("INSTRUMENTATION_CODE: " + resultCode);
406                }
407                mFinished = true;
408                notifyAll();
409            }
410        }
411
412        public boolean waitForFinish() {
413            synchronized (this) {
414                while (!mFinished) {
415                    try {
416                        if (!mAm.asBinder().pingBinder()) {
417                            return false;
418                        }
419                        wait(1000);
420                    } catch (InterruptedException e) {
421                    }
422                }
423            }
424            return true;
425        }
426    }
427
428    private void runProfile() {
429        String profileFile = null;
430        boolean start = false;
431
432        String process = nextArg();
433        if (process == null) {
434            System.err.println("Error: No profile process supplied");
435            showUsage();
436            return;
437        }
438
439        String cmd = nextArg();
440        if ("start".equals(cmd)) {
441            start = true;
442            profileFile = nextArg();
443            if (profileFile == null) {
444                System.err.println("Error: No profile file path supplied");
445                showUsage();
446                return;
447            }
448        } else if (!"stop".equals(cmd)) {
449            System.err.println("Error: Profile command " + cmd + " not valid");
450            showUsage();
451            return;
452        }
453
454        try {
455            if (!mAm.profileControl(process, start, profileFile)) {
456                System.out.println("PROFILE FAILED on process " + process);
457                return;
458            }
459        } catch (IllegalArgumentException e) {
460            System.out.println("PROFILE FAILED: " + e.getMessage());
461            return;
462        } catch (IllegalStateException e) {
463            System.out.println("PROFILE FAILED: " + e.getMessage());
464            return;
465        } catch (RemoteException e) {
466            System.out.println("PROFILE FAILED: activity manager gone");
467            return;
468        }
469    }
470
471    private String nextOption() {
472        if (mNextArg >= mArgs.length) {
473            return null;
474        }
475        String arg = mArgs[mNextArg];
476        if (!arg.startsWith("-")) {
477            return null;
478        }
479        mNextArg++;
480        if (arg.equals("--")) {
481            return null;
482        }
483        if (arg.length() > 1 && arg.charAt(1) != '-') {
484            if (arg.length() > 2) {
485                mCurArgData = arg.substring(2);
486                return arg.substring(0, 2);
487            } else {
488                mCurArgData = null;
489                return arg;
490            }
491        }
492        mCurArgData = null;
493        return arg;
494    }
495
496    private String nextOptionData() {
497        if (mCurArgData != null) {
498            return mCurArgData;
499        }
500        if (mNextArg >= mArgs.length) {
501            return null;
502        }
503        String data = mArgs[mNextArg];
504        mNextArg++;
505        return data;
506    }
507
508    private String nextArg() {
509        if (mNextArg >= mArgs.length) {
510            return null;
511        }
512        String arg = mArgs[mNextArg];
513        mNextArg++;
514        return arg;
515    }
516
517    private void showUsage() {
518        System.err.println("usage: am [start|broadcast|instrument|profile]");
519        System.err.println("       am start -D INTENT");
520        System.err.println("       am broadcast INTENT");
521        System.err.println("       am instrument [-r] [-e <ARG_NAME> <ARG_VALUE>] [-p <PROF_FILE>]");
522        System.err.println("                [-w] <COMPONENT> ");
523        System.err.println("       am profile <PROCESS> [start <PROF_FILE>|stop]");
524        System.err.println("");
525        System.err.println("       INTENT is described with:");
526        System.err.println("                [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]");
527        System.err.println("                [-c <CATEGORY> [-c <CATEGORY>] ...]");
528        System.err.println("                [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]");
529        System.err.println("                [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]");
530        System.err.println("                [-e|--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]");
531        System.err.println("                [-n <COMPONENT>] [-f <FLAGS>] [<URI>]");
532    }
533}
534