1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.commands.am;
18
19import static android.app.ActivityManager.RESIZE_MODE_SYSTEM;
20import static android.app.ActivityManager.RESIZE_MODE_USER;
21import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
22import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
23
24import android.app.ActivityManager;
25import android.app.ActivityManager.StackInfo;
26import android.app.IActivityContainer;
27import android.app.IActivityController;
28import android.app.IActivityManager;
29import android.app.IInstrumentationWatcher;
30import android.app.Instrumentation;
31import android.app.IStopUserCallback;
32import android.app.ProfilerInfo;
33import android.app.UiAutomationConnection;
34import android.app.usage.ConfigurationStats;
35import android.app.usage.IUsageStatsManager;
36import android.app.usage.UsageStatsManager;
37import android.content.ComponentCallbacks2;
38import android.content.ComponentName;
39import android.content.Context;
40import android.content.IIntentReceiver;
41import android.content.Intent;
42import android.content.pm.IPackageManager;
43import android.content.pm.InstrumentationInfo;
44import android.content.pm.ParceledListSlice;
45import android.content.pm.UserInfo;
46import android.content.res.Configuration;
47import android.graphics.Rect;
48import android.os.Binder;
49import android.os.Build;
50import android.os.Bundle;
51import android.os.ParcelFileDescriptor;
52import android.os.RemoteException;
53import android.os.ResultReceiver;
54import android.os.SELinux;
55import android.os.ServiceManager;
56import android.os.ShellCallback;
57import android.os.ShellCommand;
58import android.os.SystemProperties;
59import android.os.UserHandle;
60import android.text.TextUtils;
61import android.util.AndroidException;
62import android.util.ArrayMap;
63import android.util.Log;
64import android.view.IWindowManager;
65
66import com.android.internal.os.BaseCommand;
67import com.android.internal.util.HexDump;
68import com.android.internal.util.Preconditions;
69
70import java.io.BufferedReader;
71import java.io.File;
72import java.io.FileDescriptor;
73import java.io.FileNotFoundException;
74import java.io.IOException;
75import java.io.InputStreamReader;
76import java.io.PrintStream;
77import java.io.PrintWriter;
78import java.net.URISyntaxException;
79import java.util.ArrayList;
80import java.util.Collections;
81import java.util.Comparator;
82import java.util.List;
83
84public class Am extends BaseCommand {
85
86    private IActivityManager mAm;
87    private IPackageManager mPm;
88
89    /**
90     * Command-line entry point.
91     *
92     * @param args The command-line arguments
93     */
94    public static void main(String[] args) {
95        (new Am()).run(args);
96    }
97
98    @Override
99    public void onShowUsage(PrintStream out) {
100        try {
101            runAmCmd(new String[] { "help" });
102        } catch (AndroidException e) {
103            e.printStackTrace(System.err);
104        }
105    }
106
107    @Override
108    public void onRun() throws Exception {
109
110        mAm = ActivityManager.getService();
111        if (mAm == null) {
112            System.err.println(NO_SYSTEM_ERROR_CODE);
113            throw new AndroidException("Can't connect to activity manager; is the system running?");
114        }
115
116        mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
117        if (mPm == null) {
118            System.err.println(NO_SYSTEM_ERROR_CODE);
119            throw new AndroidException("Can't connect to package manager; is the system running?");
120        }
121
122        String op = nextArgRequired();
123
124        if (op.equals("instrument")) {
125            runInstrument();
126        } else {
127            runAmCmd(getRawArgs());
128        }
129    }
130
131    int parseUserArg(String arg) {
132        int userId;
133        if ("all".equals(arg)) {
134            userId = UserHandle.USER_ALL;
135        } else if ("current".equals(arg) || "cur".equals(arg)) {
136            userId = UserHandle.USER_CURRENT;
137        } else {
138            userId = Integer.parseInt(arg);
139        }
140        return userId;
141    }
142
143    static final class MyShellCallback extends ShellCallback {
144        boolean mActive = true;
145
146        @Override public ParcelFileDescriptor onOpenOutputFile(String path, String seLinuxContext) {
147            if (!mActive) {
148                System.err.println("Open attempt after active for: " + path);
149                return null;
150            }
151            File file = new File(path);
152            //System.err.println("Opening file: " + file.getAbsolutePath());
153            //Log.i("Am", "Opening file: " + file.getAbsolutePath());
154            final ParcelFileDescriptor fd;
155            try {
156                fd = ParcelFileDescriptor.open(file,
157                        ParcelFileDescriptor.MODE_CREATE |
158                        ParcelFileDescriptor.MODE_TRUNCATE |
159                        ParcelFileDescriptor.MODE_WRITE_ONLY);
160            } catch (FileNotFoundException e) {
161                String msg = "Unable to open file " + path + ": " + e;
162                System.err.println(msg);
163                throw new IllegalArgumentException(msg);
164            }
165            if (seLinuxContext != null) {
166                final String tcon = SELinux.getFileContext(file.getAbsolutePath());
167                if (!SELinux.checkSELinuxAccess(seLinuxContext, tcon, "file", "write")) {
168                    try {
169                        fd.close();
170                    } catch (IOException e) {
171                    }
172                    String msg = "System server has no access to file context " + tcon;
173                    System.err.println(msg + " (from path " + file.getAbsolutePath()
174                            + ", context " + seLinuxContext + ")");
175                    throw new IllegalArgumentException(msg);
176                }
177            }
178            return fd;
179        }
180    }
181
182    void runAmCmd(String[] args) throws AndroidException {
183        final MyShellCallback cb = new MyShellCallback();
184        try {
185            mAm.asBinder().shellCommand(FileDescriptor.in, FileDescriptor.out, FileDescriptor.err,
186                    args, cb, new ResultReceiver(null) { });
187        } catch (RemoteException e) {
188            System.err.println(NO_SYSTEM_ERROR_CODE);
189            throw new AndroidException("Can't call activity manager; is the system running?");
190        } finally {
191            cb.mActive = false;
192        }
193    }
194
195    public void runInstrument() throws Exception {
196        Instrument instrument = new Instrument(mAm, mPm);
197
198        String opt;
199        while ((opt=nextOption()) != null) {
200            if (opt.equals("-p")) {
201                instrument.profileFile = nextArgRequired();
202            } else if (opt.equals("-w")) {
203                instrument.wait = true;
204            } else if (opt.equals("-r")) {
205                instrument.rawMode = true;
206            } else if (opt.equals("-m")) {
207                instrument.proto = true;
208            } else if (opt.equals("-e")) {
209                final String argKey = nextArgRequired();
210                final String argValue = nextArgRequired();
211                instrument.args.putString(argKey, argValue);
212            } else if (opt.equals("--no_window_animation")
213                    || opt.equals("--no-window-animation")) {
214                instrument.noWindowAnimation = true;
215            } else if (opt.equals("--user")) {
216                instrument.userId = parseUserArg(nextArgRequired());
217            } else if (opt.equals("--abi")) {
218                instrument.abi = nextArgRequired();
219            } else {
220                System.err.println("Error: Unknown option: " + opt);
221                return;
222            }
223        }
224
225        if (instrument.userId == UserHandle.USER_ALL) {
226            System.err.println("Error: Can't start instrumentation with user 'all'");
227            return;
228        }
229
230        instrument.componentNameArg = nextArgRequired();
231
232        instrument.run();
233    }
234}
235