1/*
2 * Copyright (C) 2014 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.dpm;
18
19import android.app.ActivityManager;
20import android.app.IActivityManager;
21import android.app.admin.DevicePolicyManager;
22import android.app.admin.IDevicePolicyManager;
23import android.content.ComponentName;
24import android.content.Context;
25import android.os.RemoteException;
26import android.os.ServiceManager;
27import android.os.UserHandle;
28
29import com.android.internal.os.BaseCommand;
30
31import java.io.PrintStream;
32
33public final class Dpm extends BaseCommand {
34
35    /**
36     * Command-line entry point.
37     *
38     * @param args The command-line arguments
39     */
40    public static void main(String[] args) {
41      (new Dpm()).run(args);
42    }
43
44    private static final String COMMAND_SET_ACTIVE_ADMIN = "set-active-admin";
45    private static final String COMMAND_SET_DEVICE_OWNER = "set-device-owner";
46    private static final String COMMAND_SET_PROFILE_OWNER = "set-profile-owner";
47    private static final String COMMAND_REMOVE_ACTIVE_ADMIN = "remove-active-admin";
48
49    private IDevicePolicyManager mDevicePolicyManager;
50    private int mUserId = UserHandle.USER_SYSTEM;
51    private String mName = "";
52    private ComponentName mComponent = null;
53
54    @Override
55    public void onShowUsage(PrintStream out) {
56        out.println(
57                "usage: dpm [subcommand] [options]\n" +
58                "usage: dpm set-active-admin [ --user <USER_ID> | current ] <COMPONENT>\n" +
59                // STOPSHIP Finalize it
60                "usage: dpm set-device-owner [ --user <USER_ID> | current *EXPERIMENTAL* ] " +
61                "[ --name <NAME> ] <COMPONENT>\n" +
62                "usage: dpm set-profile-owner [ --user <USER_ID> | current ] [ --name <NAME> ] " +
63                "<COMPONENT>\n" +
64                "usage: dpm remove-active-admin [ --user <USER_ID> | current ] [ --name <NAME> ] " +
65                "<COMPONENT>\n" +
66                "\n" +
67                "dpm set-active-admin: Sets the given component as active admin" +
68                " for an existing user.\n" +
69                "\n" +
70                "dpm set-device-owner: Sets the given component as active admin, and its" +
71                " package as device owner.\n" +
72                "\n" +
73                "dpm set-profile-owner: Sets the given component as active admin and profile" +
74                " owner for an existing user.\n" +
75                "\n" +
76                "dpm remove-active-admin: Disables an active admin, the admin must have declared" +
77                " android:testOnly in the application in its manifest. This will also remove" +
78                " device and profile owners\n");
79    }
80
81    @Override
82    public void onRun() throws Exception {
83        mDevicePolicyManager = IDevicePolicyManager.Stub.asInterface(
84                ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
85        if (mDevicePolicyManager == null) {
86            showError("Error: Could not access the Device Policy Manager. Is the system running?");
87            return;
88        }
89
90        String command = nextArgRequired();
91        switch (command) {
92            case COMMAND_SET_ACTIVE_ADMIN:
93                runSetActiveAdmin();
94                break;
95            case COMMAND_SET_DEVICE_OWNER:
96                runSetDeviceOwner();
97                break;
98            case COMMAND_SET_PROFILE_OWNER:
99                runSetProfileOwner();
100                break;
101            case COMMAND_REMOVE_ACTIVE_ADMIN:
102                runRemoveActiveAdmin();
103                break;
104            default:
105                throw new IllegalArgumentException ("unknown command '" + command + "'");
106        }
107    }
108
109    private void parseArgs(boolean canHaveName) {
110        String opt;
111        while ((opt = nextOption()) != null) {
112            if ("--user".equals(opt)) {
113                String arg = nextArgRequired();
114                if ("current".equals(arg) || "cur".equals(arg)) {
115                    mUserId = UserHandle.USER_CURRENT;
116                } else {
117                    mUserId = parseInt(arg);
118                }
119                if (mUserId == UserHandle.USER_CURRENT) {
120                    IActivityManager activityManager = ActivityManager.getService();
121                    try {
122                        mUserId = activityManager.getCurrentUser().id;
123                    } catch (RemoteException e) {
124                        e.rethrowAsRuntimeException();
125                    }
126                }
127            } else if (canHaveName && "--name".equals(opt)) {
128                mName = nextArgRequired();
129            } else {
130                throw new IllegalArgumentException("Unknown option: " + opt);
131            }
132        }
133        mComponent = parseComponentName(nextArgRequired());
134    }
135
136    private void runSetActiveAdmin() throws RemoteException {
137        parseArgs(/*canHaveName=*/ false);
138        mDevicePolicyManager.setActiveAdmin(mComponent, true /*refreshing*/, mUserId);
139
140        System.out.println("Success: Active admin set to component " + mComponent.toShortString());
141    }
142
143    private void runSetDeviceOwner() throws RemoteException {
144        parseArgs(/*canHaveName=*/ true);
145        mDevicePolicyManager.setActiveAdmin(mComponent, true /*refreshing*/, mUserId);
146
147        try {
148            if (!mDevicePolicyManager.setDeviceOwner(mComponent, mName, mUserId)) {
149                throw new RuntimeException(
150                        "Can't set package " + mComponent + " as device owner.");
151            }
152        } catch (Exception e) {
153            // Need to remove the admin that we just added.
154            mDevicePolicyManager.removeActiveAdmin(mComponent, UserHandle.USER_SYSTEM);
155            throw e;
156        }
157
158        mDevicePolicyManager.setUserProvisioningState(
159                DevicePolicyManager.STATE_USER_SETUP_FINALIZED, mUserId);
160
161        System.out.println("Success: Device owner set to package " + mComponent);
162        System.out.println("Active admin set to component " + mComponent.toShortString());
163    }
164
165    private void runRemoveActiveAdmin() throws RemoteException {
166        parseArgs(/*canHaveName=*/ false);
167        mDevicePolicyManager.forceRemoveActiveAdmin(mComponent, mUserId);
168        System.out.println("Success: Admin removed " + mComponent);
169    }
170
171    private void runSetProfileOwner() throws RemoteException {
172        parseArgs(/*canHaveName=*/ true);
173        mDevicePolicyManager.setActiveAdmin(mComponent, true /*refreshing*/, mUserId);
174
175        try {
176            if (!mDevicePolicyManager.setProfileOwner(mComponent, mName, mUserId)) {
177                throw new RuntimeException("Can't set component " + mComponent.toShortString() +
178                        " as profile owner for user " + mUserId);
179            }
180        } catch (Exception e) {
181            // Need to remove the admin that we just added.
182            mDevicePolicyManager.removeActiveAdmin(mComponent, mUserId);
183            throw e;
184        }
185
186        mDevicePolicyManager.setUserProvisioningState(
187                DevicePolicyManager.STATE_USER_SETUP_FINALIZED, mUserId);
188
189        System.out.println("Success: Active admin and profile owner set to "
190                + mComponent.toShortString() + " for user " + mUserId);
191    }
192
193    private ComponentName parseComponentName(String component) {
194        ComponentName cn = ComponentName.unflattenFromString(component);
195        if (cn == null) {
196            throw new IllegalArgumentException ("Invalid component " + component);
197        }
198        return cn;
199    }
200
201    private int parseInt(String argument) {
202        try {
203            return Integer.parseInt(argument);
204        } catch (NumberFormatException e) {
205            throw new IllegalArgumentException ("Invalid integer argument '" + argument + "'", e);
206        }
207    }
208}
209