1b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera/*
2b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera * Copyright (C) 2014 The Android Open Source Project
3b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera *
4b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera * Licensed under the Apache License, Version 2.0 (the "License");
5b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera * you may not use this file except in compliance with the License.
6b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera * You may obtain a copy of the License at
7b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera *
8b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera *      http://www.apache.org/licenses/LICENSE-2.0
9b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera *
10b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera * Unless required by applicable law or agreed to in writing, software
11b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera * distributed under the License is distributed on an "AS IS" BASIS,
12b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera * See the License for the specific language governing permissions and
14b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera * limitations under the License.
15b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera */
16b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera
17b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talaverapackage com.android.commands.dpm;
18b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera
19b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talaveraimport android.app.admin.IDevicePolicyManager;
209c17388cff98fba9679ce6457ac5003a660c6013Esteban Talaveraimport android.content.ComponentName;
21b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talaveraimport android.content.Context;
22b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talaveraimport android.os.RemoteException;
23b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talaveraimport android.os.ServiceManager;
249c17388cff98fba9679ce6457ac5003a660c6013Esteban Talaveraimport android.os.UserHandle;
25b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera
26b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talaveraimport com.android.internal.os.BaseCommand;
27b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera
28b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talaveraimport java.io.PrintStream;
29b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera
30b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talaverapublic final class Dpm extends BaseCommand {
31b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera
32b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera    /**
33b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera     * Command-line entry point.
34b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera     *
35b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera     * @param args The command-line arguments
36b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera     */
37b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera    public static void main(String[] args) {
38b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera      (new Dpm()).run(args);
39b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera    }
40b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera
41e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban    private static final String COMMAND_SET_ACTIVE_ADMIN = "set-active-admin";
42b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera    private static final String COMMAND_SET_DEVICE_OWNER = "set-device-owner";
4341de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera    private static final String COMMAND_SET_PROFILE_OWNER = "set-profile-owner";
44b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera
45b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera    private IDevicePolicyManager mDevicePolicyManager;
46e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban    private int mUserId = UserHandle.USER_OWNER;
47e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban    private ComponentName mComponent = null;
48b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera
49b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera    @Override
50b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera    public void onShowUsage(PrintStream out) {
519c17388cff98fba9679ce6457ac5003a660c6013Esteban Talavera        out.println(
529c17388cff98fba9679ce6457ac5003a660c6013Esteban Talavera                "usage: dpm [subcommand] [options]\n" +
53e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban                "usage: dpm set-active-admin [ --user <USER_ID> ] <COMPONENT>\n" +
549c17388cff98fba9679ce6457ac5003a660c6013Esteban Talavera                "usage: dpm set-device-owner <COMPONENT>\n" +
5541de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera                "usage: dpm set-profile-owner <COMPONENT> <USER_ID>\n" +
56b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera                "\n" +
57e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban                "dpm set-active-admin: Sets the given component as active admin" +
58e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban                " for an existing user.\n" +
59e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban                "\n" +
609c17388cff98fba9679ce6457ac5003a660c6013Esteban Talavera                "dpm set-device-owner: Sets the given component as active admin, and its\n" +
6141de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera                "  package as device owner.\n" +
6241de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera                "\n" +
6341de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera                "dpm set-profile-owner: Sets the given component as active admin and profile" +
6441de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera                "  owner for an existing user.\n");
65b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera    }
66b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera
67b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera    @Override
68b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera    public void onRun() throws Exception {
69b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera        mDevicePolicyManager = IDevicePolicyManager.Stub.asInterface(
70b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera                ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
71b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera        if (mDevicePolicyManager == null) {
72b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera            showError("Error: Could not access the Device Policy Manager. Is the system running?");
73b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera            return;
74b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera        }
75b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera
76b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera        String command = nextArgRequired();
77b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera        switch (command) {
78e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban            case COMMAND_SET_ACTIVE_ADMIN:
79e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban                runSetActiveAdmin();
80e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban                break;
81b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera            case COMMAND_SET_DEVICE_OWNER:
8241de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera                runSetDeviceOwner();
8341de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera                break;
8441de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera            case COMMAND_SET_PROFILE_OWNER:
8541de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera                runSetProfileOwner();
86b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera                break;
87b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera            default:
889c17388cff98fba9679ce6457ac5003a660c6013Esteban Talavera                throw new IllegalArgumentException ("unknown command '" + command + "'");
89b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera        }
90b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera    }
91b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera
92e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban    private void parseArgs(boolean canHaveUser) {
93e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban        String nextArg = nextArgRequired();
94e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban        if (canHaveUser && "--user".equals(nextArg)) {
95e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban            mUserId = parseInt(nextArgRequired());
96e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban            nextArg = nextArgRequired();
97e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban        }
98e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban        mComponent = parseComponentName(nextArg);
99e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban    }
100e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban
101e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban    private void runSetActiveAdmin() throws RemoteException {
102e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban        parseArgs(true);
103e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban        mDevicePolicyManager.setActiveAdmin(mComponent, true /*refreshing*/, mUserId);
104e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban
105e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban        System.out.println("Success: Active admin set to component " + mComponent.toShortString());
106e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban    }
107e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban
10841de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera    private void runSetDeviceOwner() throws RemoteException {
10941de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera        ComponentName component = parseComponentName(nextArgRequired());
11041de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera        mDevicePolicyManager.setActiveAdmin(component, true /*refreshing*/, UserHandle.USER_OWNER);
1119c17388cff98fba9679ce6457ac5003a660c6013Esteban Talavera
1129c17388cff98fba9679ce6457ac5003a660c6013Esteban Talavera        String packageName = component.getPackageName();
1139c17388cff98fba9679ce6457ac5003a660c6013Esteban Talavera        try {
11441de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera            if (!mDevicePolicyManager.setDeviceOwner(packageName, null /*ownerName*/)) {
11541de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera                throw new RuntimeException(
11641de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera                        "Can't set package " + packageName + " as device owner.");
1179c17388cff98fba9679ce6457ac5003a660c6013Esteban Talavera            }
1189c17388cff98fba9679ce6457ac5003a660c6013Esteban Talavera        } catch (Exception e) {
1199c17388cff98fba9679ce6457ac5003a660c6013Esteban Talavera            // Need to remove the admin that we just added.
1209c17388cff98fba9679ce6457ac5003a660c6013Esteban Talavera            mDevicePolicyManager.removeActiveAdmin(component, UserHandle.USER_OWNER);
1219c17388cff98fba9679ce6457ac5003a660c6013Esteban Talavera            throw e;
1229c17388cff98fba9679ce6457ac5003a660c6013Esteban Talavera        }
123c48bca50fa64765d3019b0bf82511e030cabcc7aEsteban Talavera        System.out.println("Success: Device owner set to package " + packageName);
1249c17388cff98fba9679ce6457ac5003a660c6013Esteban Talavera        System.out.println("Active admin set to component " + component.toShortString());
125b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera    }
12641de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera
12741de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera    private void runSetProfileOwner() throws RemoteException {
128e9119876a21575ee7a7d058da85d04c4c4b8a971Zoltan Szatmary-Ban        // To be refactored later to use parseArgs(boolean). Currently in use by existing tests.
12941de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera        ComponentName component = parseComponentName(nextArgRequired());
13041de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera        int userId = parseInt(nextArgRequired());
13141de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera        mDevicePolicyManager.setActiveAdmin(component, true /*refreshing*/, userId);
13241de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera
13341de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera        try {
13441de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera            if (!mDevicePolicyManager.setProfileOwner(component, "" /*ownerName*/, userId)) {
13541de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera                throw new RuntimeException("Can't set component " + component.toShortString() +
13641de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera                        " as profile owner for user " + userId);
13741de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera            }
13841de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera        } catch (Exception e) {
13941de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera            // Need to remove the admin that we just added.
14041de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera            mDevicePolicyManager.removeActiveAdmin(component, userId);
14141de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera            throw e;
14241de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera        }
143c48bca50fa64765d3019b0bf82511e030cabcc7aEsteban Talavera        System.out.println("Success: Active admin and profile owner set to "
144c48bca50fa64765d3019b0bf82511e030cabcc7aEsteban Talavera                + component.toShortString() + " for user " + userId);
14541de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera    }
14641de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera
14741de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera    private ComponentName parseComponentName(String component) {
14841de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera        ComponentName cn = ComponentName.unflattenFromString(component);
14941de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera        if (cn == null) {
15041de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera            throw new IllegalArgumentException ("Invalid component " + component);
15141de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera        }
15241de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera        return cn;
15341de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera    }
15441de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera
15541de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera    private int parseInt(String argument) {
15641de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera        try {
15741de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera            return Integer.parseInt(argument);
15841de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera        } catch (NumberFormatException e) {
15941de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera            throw new IllegalArgumentException ("Invalid integer argument '" + argument + "'", e);
16041de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera        }
16141de9bb6fda113f7cfb8b7b8d64d07d3809f8f20Esteban Talavera    }
162b5ef162129ced7e9636052af6b7f08d677a01f13Esteban Talavera}