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