1c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav/*
2c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav * Copyright (C) 2015 The Android Open Source Project
3c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav *
4c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav * Licensed under the Apache License, Version 2.0 (the "License");
5c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav * you may not use this file except in compliance with the License.
6c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav * You may obtain a copy of the License at
7c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav *
8c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav *      http://www.apache.org/licenses/LICENSE-2.0
9c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav *
10c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav * Unless required by applicable law or agreed to in writing, software
11c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav * distributed under the License is distributed on an "AS IS" BASIS,
12c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav * See the License for the specific language governing permissions and
14c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav * limitations under the License.
15c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav */
16c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
1782b0842051a93764e96a68072da1a220f00c2c27Todd Kennedypackage com.android.server.pm.permission;
18c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
199c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganovimport android.content.pm.PackageManager;
20c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslavimport android.os.UserHandle;
21c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslavimport android.util.ArrayMap;
22c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslavimport android.util.ArraySet;
2300f3904629ef89192e061c1995801ef322fc0bcfJeff Sharkey
248c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganovimport android.util.SparseArray;
259c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganovimport android.util.SparseBooleanArray;
26c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslavimport com.android.internal.util.ArrayUtils;
27c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
288c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganovimport java.util.ArrayList;
29c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslavimport java.util.Arrays;
30c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslavimport java.util.Collections;
318c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganovimport java.util.List;
32c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslavimport java.util.Set;
33c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
34c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav/**
35c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav * This class encapsulates the permissions for a package or a shared user.
36c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav * <p>
37c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav * There are two types of permissions: install (granted at installation)
38c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav * and runtime (granted at runtime). Install permissions are granted to
39c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav * all device users while runtime permissions are granted explicitly to
40c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav * specific users.
41c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav * </p>
42c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav * <p>
43c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav * The permissions are kept on a per device user basis. For example, an
44c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav * application may have some runtime permissions granted under the device
45c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav * owner but not granted under the secondary user.
46c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav * <p>
47c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav * This class is also responsible for keeping track of the Linux gids per
48c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav * user for a package or a shared user. The gids are computed as a set of
49c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav * the gids for all granted permissions' gids on a per user basis.
50c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav * </p>
51c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav */
52c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslavpublic final class PermissionsState {
53c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
54b3f22b48bbd4e4816212e596e3cb612457d48fe5Svet Ganov    /** The permission operation failed. */
55b3f22b48bbd4e4816212e596e3cb612457d48fe5Svet Ganov    public static final int PERMISSION_OPERATION_FAILURE = -1;
56b3f22b48bbd4e4816212e596e3cb612457d48fe5Svet Ganov
57c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    /** The permission operation succeeded and no gids changed. */
58b3f22b48bbd4e4816212e596e3cb612457d48fe5Svet Ganov    public static final int PERMISSION_OPERATION_SUCCESS = 0;
59c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
60c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    /** The permission operation succeeded and gids changed. */
61b3f22b48bbd4e4816212e596e3cb612457d48fe5Svet Ganov    public static final int PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED = 1;
62c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
63c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    private static final int[] NO_GIDS = {};
64c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
65c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    private ArrayMap<String, PermissionData> mPermissions;
66c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
67c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    private int[] mGlobalGids = NO_GIDS;
68c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
699c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov    private SparseBooleanArray mPermissionReviewRequired;
709c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov
71c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    public PermissionsState() {
72c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        /* do nothing */
73c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    }
74c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
75c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    public PermissionsState(PermissionsState prototype) {
76c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        copyFrom(prototype);
77c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    }
78c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
79c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    /**
80c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * Sets the global gids, applicable to all users.
81c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     *
82c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * @param globalGids The global gids.
83c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     */
84c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    public void setGlobalGids(int[] globalGids) {
85c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        if (!ArrayUtils.isEmpty(globalGids)) {
86c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            mGlobalGids = Arrays.copyOf(globalGids, globalGids.length);
87c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        }
88c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    }
89c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
90c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    /**
91c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * Initialized this instance from another one.
92c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     *
93c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * @param other The other instance.
94c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     */
95c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    public void copyFrom(PermissionsState other) {
964f2dcfd48010a338dc9a2f5870ed12b382c30cd7Svet Ganov        if (other == this) {
974f2dcfd48010a338dc9a2f5870ed12b382c30cd7Svet Ganov            return;
984f2dcfd48010a338dc9a2f5870ed12b382c30cd7Svet Ganov        }
99c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        if (mPermissions != null) {
100c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            if (other.mPermissions == null) {
101c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav                mPermissions = null;
102c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            } else {
103c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav                mPermissions.clear();
104c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            }
105c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        }
106c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        if (other.mPermissions != null) {
107c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            if (mPermissions == null) {
108c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav                mPermissions = new ArrayMap<>();
109c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            }
110c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            final int permissionCount = other.mPermissions.size();
111c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            for (int i = 0; i < permissionCount; i++) {
112c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav                String name = other.mPermissions.keyAt(i);
113c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav                PermissionData permissionData = other.mPermissions.valueAt(i);
114c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav                mPermissions.put(name, new PermissionData(permissionData));
115c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            }
116c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        }
117c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
118c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        mGlobalGids = NO_GIDS;
119c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        if (other.mGlobalGids != NO_GIDS) {
120c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            mGlobalGids = Arrays.copyOf(other.mGlobalGids,
121c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav                    other.mGlobalGids.length);
122c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        }
1239c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov
1249c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov        if (mPermissionReviewRequired != null) {
1259c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov            if (other.mPermissionReviewRequired == null) {
1269c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov                mPermissionReviewRequired = null;
1279c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov            } else {
1289c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov                mPermissionReviewRequired.clear();
1299c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov            }
1309c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov        }
1319c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov        if (other.mPermissionReviewRequired != null) {
1329c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov            if (mPermissionReviewRequired == null) {
1339c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov                mPermissionReviewRequired = new SparseBooleanArray();
1349c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov            }
1359c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov            final int userCount = other.mPermissionReviewRequired.size();
1369c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov            for (int i = 0; i < userCount; i++) {
1379c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov                final boolean reviewRequired = other.mPermissionReviewRequired.valueAt(i);
1389c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov                mPermissionReviewRequired.put(i, reviewRequired);
1399c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov            }
1409c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov        }
1419c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov    }
1429c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov
1433cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy    @Override
1443cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy    public boolean equals(Object obj) {
1453cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy        if (this == obj) {
1463cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy            return true;
1473cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy        }
1483cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy        if (obj == null) {
1493cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy            return false;
1503cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy        }
1513cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy        if (getClass() != obj.getClass()) {
1523cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy            return false;
1533cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy        }
1543cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy        final PermissionsState other = (PermissionsState) obj;
1553cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy
1563cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy        if (mPermissions == null) {
1573cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy            if (other.mPermissions != null) {
1583cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy                return false;
1593cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy            }
1603cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy        } else if (!mPermissions.equals(other.mPermissions)) {
1613cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy            return false;
1623cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy        }
1633cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy        if (mPermissionReviewRequired == null) {
1643cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy            if (other.mPermissionReviewRequired != null) {
1653cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy                return false;
1663cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy            }
1673cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy        } else if (!mPermissionReviewRequired.equals(other.mPermissionReviewRequired)) {
1683cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy            return false;
1693cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy        }
1703cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy        return Arrays.equals(mGlobalGids, other.mGlobalGids);
1713cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy    }
1723cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy
1739c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov    public boolean isPermissionReviewRequired(int userId) {
1749c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov        return mPermissionReviewRequired != null && mPermissionReviewRequired.get(userId);
175c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    }
176c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
177c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    /**
178c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * Grant an install permission.
179c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     *
180c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * @param permission The permission to grant.
181c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
182c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     *     or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
183c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     *     #PERMISSION_OPERATION_FAILURE}.
184c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     */
185c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    public int grantInstallPermission(BasePermission permission) {
186c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        return grantPermission(permission, UserHandle.USER_ALL);
187c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    }
188c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
189c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    /**
190c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * Revoke an install permission.
191c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     *
192c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * @param permission The permission to revoke.
193c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
194c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     *     or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
195c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     *     #PERMISSION_OPERATION_FAILURE}.
196c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     */
197c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    public int revokeInstallPermission(BasePermission permission) {
198c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        return revokePermission(permission, UserHandle.USER_ALL);
199c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    }
200c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
201c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    /**
2028c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     * Grant a runtime permission for a given device user.
203c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     *
204c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * @param permission The permission to grant.
2058c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     * @param userId The device user id.
206c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
207c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     *     or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
208c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     *     #PERMISSION_OPERATION_FAILURE}.
209c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     */
210c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    public int grantRuntimePermission(BasePermission permission, int userId) {
2118c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        enforceValidUserId(userId);
212d5752bdc8fd39d4f0a508f9088c538e30e73044aSvet Ganov        if (userId == UserHandle.USER_ALL) {
213d5752bdc8fd39d4f0a508f9088c538e30e73044aSvet Ganov            return PERMISSION_OPERATION_FAILURE;
214d5752bdc8fd39d4f0a508f9088c538e30e73044aSvet Ganov        }
215c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        return grantPermission(permission, userId);
216c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    }
217c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
218c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    /**
2198c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     *  Revoke a runtime permission for a given device user.
220c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     *
221c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * @param permission The permission to revoke.
222c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * @param userId The device user id.
223c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
224c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     *     or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
225c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     *     #PERMISSION_OPERATION_FAILURE}.
226c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     */
227c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    public int revokeRuntimePermission(BasePermission permission, int userId) {
2288c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        enforceValidUserId(userId);
229d5752bdc8fd39d4f0a508f9088c538e30e73044aSvet Ganov        if (userId == UserHandle.USER_ALL) {
230d5752bdc8fd39d4f0a508f9088c538e30e73044aSvet Ganov            return PERMISSION_OPERATION_FAILURE;
231d5752bdc8fd39d4f0a508f9088c538e30e73044aSvet Ganov        }
232c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        return revokePermission(permission, userId);
233c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    }
234c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
235c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    /**
236c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * Gets whether this state has a given runtime permission for a
237c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * given device user id.
238c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     *
239c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * @param name The permission name.
240c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * @param userId The device user id.
241c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * @return Whether this state has the permission.
242c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     */
243c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    public boolean hasRuntimePermission(String name, int userId) {
2448c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        enforceValidUserId(userId);
245c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        return !hasInstallPermission(name) && hasPermission(name, userId);
246c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    }
247c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
248c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    /**
249c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * Gets whether this state has a given install permission.
250c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     *
251c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * @param name The permission name.
252c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * @return Whether this state has the permission.
253c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     */
254c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    public boolean hasInstallPermission(String name) {
255c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        return hasPermission(name, UserHandle.USER_ALL);
256c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    }
257c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
258c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    /**
259c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * Gets whether the state has a given permission for the specified
260c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * user, regardless if this is an install or a runtime permission.
261c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     *
262c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * @param name The permission name.
263c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * @param userId The device user id.
264c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * @return Whether the user has the permission.
265c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     */
266c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    public boolean hasPermission(String name, int userId) {
267c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        enforceValidUserId(userId);
268c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
269c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        if (mPermissions == null) {
270c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            return false;
271c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        }
272c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
273c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        PermissionData permissionData = mPermissions.get(name);
2748c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        return permissionData != null && permissionData.isGranted(userId);
275c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    }
276c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
277c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    /**
278ca8e6da41c6e63e3ed17eb461171f1ef2e1d29c6Dianne Hackborn     * Returns whether the state has any known request for the given permission name,
279ca8e6da41c6e63e3ed17eb461171f1ef2e1d29c6Dianne Hackborn     * whether or not it has been granted.
280ca8e6da41c6e63e3ed17eb461171f1ef2e1d29c6Dianne Hackborn     */
281ca8e6da41c6e63e3ed17eb461171f1ef2e1d29c6Dianne Hackborn    public boolean hasRequestedPermission(ArraySet<String> names) {
282ca8e6da41c6e63e3ed17eb461171f1ef2e1d29c6Dianne Hackborn        if (mPermissions == null) {
283ca8e6da41c6e63e3ed17eb461171f1ef2e1d29c6Dianne Hackborn            return false;
284ca8e6da41c6e63e3ed17eb461171f1ef2e1d29c6Dianne Hackborn        }
285ca8e6da41c6e63e3ed17eb461171f1ef2e1d29c6Dianne Hackborn        for (int i=names.size()-1; i>=0; i--) {
286ca8e6da41c6e63e3ed17eb461171f1ef2e1d29c6Dianne Hackborn            if (mPermissions.get(names.valueAt(i)) != null) {
287ca8e6da41c6e63e3ed17eb461171f1ef2e1d29c6Dianne Hackborn                return true;
288ca8e6da41c6e63e3ed17eb461171f1ef2e1d29c6Dianne Hackborn            }
289ca8e6da41c6e63e3ed17eb461171f1ef2e1d29c6Dianne Hackborn        }
290ca8e6da41c6e63e3ed17eb461171f1ef2e1d29c6Dianne Hackborn        return false;
291ca8e6da41c6e63e3ed17eb461171f1ef2e1d29c6Dianne Hackborn    }
292ca8e6da41c6e63e3ed17eb461171f1ef2e1d29c6Dianne Hackborn
293ca8e6da41c6e63e3ed17eb461171f1ef2e1d29c6Dianne Hackborn    /**
2948c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     * Gets all permissions for a given device user id regardless if they
2958c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     * are install time or runtime permissions.
296c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     *
2978c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     * @param userId The device user id.
298c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * @return The permissions or an empty set.
299c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     */
3008c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov    public Set<String> getPermissions(int userId) {
3018c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        enforceValidUserId(userId);
3028c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
3038c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        if (mPermissions == null) {
3048c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            return Collections.emptySet();
305c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        }
306c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
3075e57a20c09512c676bc1ac938c5a2516ba260f72Fyodor Kupolov        Set<String> permissions = new ArraySet<>(mPermissions.size());
3088c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
3098c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        final int permissionCount = mPermissions.size();
3108c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        for (int i = 0; i < permissionCount; i++) {
3118c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            String permission = mPermissions.keyAt(i);
3128c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
3138c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            if (hasInstallPermission(permission)) {
3148c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                permissions.add(permission);
3155e57a20c09512c676bc1ac938c5a2516ba260f72Fyodor Kupolov                continue;
3168c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            }
3178c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
3188c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            if (userId != UserHandle.USER_ALL) {
3198c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                if (hasRuntimePermission(permission, userId)) {
3208c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                    permissions.add(permission);
3218c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                }
3228c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            }
3238c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        }
3248c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
3258c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        return permissions;
326c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    }
327c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
328c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    /**
3298c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     * Gets the state for an install permission or null if no such.
330c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     *
3318c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     * @param name The permission name.
3328c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     * @return The permission state.
3338c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     */
3348c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov    public PermissionState getInstallPermissionState(String name) {
3358c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        return getPermissionState(name, UserHandle.USER_ALL);
3368c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov    }
3378c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
3388c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov    /**
3398c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     * Gets the state for a runtime permission or null if no such.
3408c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     *
3418c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     * @param name The permission name.
342c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * @param userId The device user id.
3438c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     * @return The permission state.
344c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     */
3458c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov    public PermissionState getRuntimePermissionState(String name, int userId) {
3468c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        enforceValidUserId(userId);
3478c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        return getPermissionState(name, userId);
348c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    }
349c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
350c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    /**
3518c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     * Gets all install permission states.
352c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     *
3538c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     * @return The permission states or an empty set.
354c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     */
3558c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov    public List<PermissionState> getInstallPermissionStates() {
3568c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        return getPermissionStatesInternal(UserHandle.USER_ALL);
357c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    }
358c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
359c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    /**
3608c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     * Gets all runtime permission states.
361c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     *
3628c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     * @return The permission states or an empty set.
3638c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     */
3648c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov    public List<PermissionState> getRuntimePermissionStates(int userId) {
3658c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        enforceValidUserId(userId);
3668c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        return getPermissionStatesInternal(userId);
3678c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov    }
3688c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
3698c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov    /**
3708c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     * Gets the flags for a permission regardless if it is install or
3718c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     * runtime permission.
3728c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     *
3738c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     * @param name The permission name.
3748c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     * @return The permission state or null if no such.
375c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     */
3768c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov    public int getPermissionFlags(String name, int userId) {
3778c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        PermissionState installPermState = getInstallPermissionState(name);
3788c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        if (installPermState != null) {
3798c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            return installPermState.getFlags();
3808c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        }
3818c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        PermissionState runtimePermState = getRuntimePermissionState(name, userId);
3828c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        if (runtimePermState != null) {
3838c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            return runtimePermState.getFlags();
3848c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        }
3858c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        return 0;
3868c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov    }
3878c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
3888c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov    /**
3898c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     * Update the flags associated with a given permission.
3908c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     * @param permission The permission whose flags to update.
3918c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     * @param userId The user for which to update.
3928c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     * @param flagMask Mask for which flags to change.
3938c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     * @param flagValues New values for the mask flags.
3948c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     * @return Whether the permission flags changed.
3958c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov     */
3968c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov    public boolean updatePermissionFlags(BasePermission permission, int userId,
3978c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            int flagMask, int flagValues) {
3988c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        enforceValidUserId(userId);
3998c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
4008c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        final boolean mayChangeFlags = flagValues != 0 || flagMask != 0;
4018c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
4028c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        if (mPermissions == null) {
4038c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            if (!mayChangeFlags) {
4048c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                return false;
4058c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            }
4068c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            ensurePermissionData(permission);
4078c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        }
4088c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
40991a39d126d1f6efa47948ca1039ca347c1bd19e6Todd Kennedy        PermissionData permissionData = mPermissions.get(permission.getName());
4108c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        if (permissionData == null) {
4118c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            if (!mayChangeFlags) {
4128c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                return false;
4138c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            }
4148c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            permissionData = ensurePermissionData(permission);
4158c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        }
4168c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
4179c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov        final int oldFlags = permissionData.getFlags(userId);
4189c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov
4199c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov        final boolean updated = permissionData.updateFlags(userId, flagMask, flagValues);
4209c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov        if (updated) {
4219c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov            final int newFlags = permissionData.getFlags(userId);
4229c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov            if ((oldFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) == 0
4239c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov                    && (newFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
4249c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov                if (mPermissionReviewRequired == null) {
4259c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov                    mPermissionReviewRequired = new SparseBooleanArray();
4269c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov                }
4279c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov                mPermissionReviewRequired.put(userId, true);
4289c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov            } else if ((oldFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0
4299c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov                    && (newFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
430587512a0cfc88ba2e114a30554fc232d9b2c5a4fSvet Ganov                if (mPermissionReviewRequired != null && !hasPermissionRequiringReview(userId)) {
4319c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov                    mPermissionReviewRequired.delete(userId);
4329c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov                    if (mPermissionReviewRequired.size() <= 0) {
4339c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov                        mPermissionReviewRequired = null;
4349c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov                    }
4359c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov                }
4369c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov            }
4379c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov        }
4389c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov        return updated;
439c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    }
440c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
441587512a0cfc88ba2e114a30554fc232d9b2c5a4fSvet Ganov    private boolean hasPermissionRequiringReview(int userId) {
442587512a0cfc88ba2e114a30554fc232d9b2c5a4fSvet Ganov        final int permissionCount = mPermissions.size();
443587512a0cfc88ba2e114a30554fc232d9b2c5a4fSvet Ganov        for (int i = 0; i < permissionCount; i++) {
444587512a0cfc88ba2e114a30554fc232d9b2c5a4fSvet Ganov            final PermissionData permission = mPermissions.valueAt(i);
445587512a0cfc88ba2e114a30554fc232d9b2c5a4fSvet Ganov            if ((permission.getFlags(userId)
446587512a0cfc88ba2e114a30554fc232d9b2c5a4fSvet Ganov                    & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
447587512a0cfc88ba2e114a30554fc232d9b2c5a4fSvet Ganov                return true;
448587512a0cfc88ba2e114a30554fc232d9b2c5a4fSvet Ganov            }
449587512a0cfc88ba2e114a30554fc232d9b2c5a4fSvet Ganov        }
450587512a0cfc88ba2e114a30554fc232d9b2c5a4fSvet Ganov        return false;
451587512a0cfc88ba2e114a30554fc232d9b2c5a4fSvet Ganov    }
452587512a0cfc88ba2e114a30554fc232d9b2c5a4fSvet Ganov
4530bf8f7cc3982164a9e11ea4a25ed930e466f1dd8Amith Yamasani    public boolean updatePermissionFlagsForAllPermissions(
4540bf8f7cc3982164a9e11ea4a25ed930e466f1dd8Amith Yamasani            int userId, int flagMask, int flagValues) {
4550bf8f7cc3982164a9e11ea4a25ed930e466f1dd8Amith Yamasani        enforceValidUserId(userId);
4560bf8f7cc3982164a9e11ea4a25ed930e466f1dd8Amith Yamasani
4570bf8f7cc3982164a9e11ea4a25ed930e466f1dd8Amith Yamasani        if (mPermissions == null) {
4580bf8f7cc3982164a9e11ea4a25ed930e466f1dd8Amith Yamasani            return false;
4590bf8f7cc3982164a9e11ea4a25ed930e466f1dd8Amith Yamasani        }
4600bf8f7cc3982164a9e11ea4a25ed930e466f1dd8Amith Yamasani        boolean changed = false;
4610bf8f7cc3982164a9e11ea4a25ed930e466f1dd8Amith Yamasani        final int permissionCount = mPermissions.size();
4620bf8f7cc3982164a9e11ea4a25ed930e466f1dd8Amith Yamasani        for (int i = 0; i < permissionCount; i++) {
4630bf8f7cc3982164a9e11ea4a25ed930e466f1dd8Amith Yamasani            PermissionData permissionData = mPermissions.valueAt(i);
4640bf8f7cc3982164a9e11ea4a25ed930e466f1dd8Amith Yamasani            changed |= permissionData.updateFlags(userId, flagMask, flagValues);
4650bf8f7cc3982164a9e11ea4a25ed930e466f1dd8Amith Yamasani        }
4660bf8f7cc3982164a9e11ea4a25ed930e466f1dd8Amith Yamasani        return changed;
4670bf8f7cc3982164a9e11ea4a25ed930e466f1dd8Amith Yamasani    }
4680bf8f7cc3982164a9e11ea4a25ed930e466f1dd8Amith Yamasani
469c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    /**
470c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * Compute the Linux gids for a given device user from the permissions
471c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * granted to this user. Note that these are computed to avoid additional
472c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * state as they are rarely accessed.
473c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     *
474c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * @param userId The device user id.
475c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * @return The gids for the device user.
476c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     */
477c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    public int[] computeGids(int userId) {
478c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        enforceValidUserId(userId);
479c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
480c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        int[] gids = mGlobalGids;
481c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
482c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        if (mPermissions != null) {
483c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            final int permissionCount = mPermissions.size();
484c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            for (int i = 0; i < permissionCount; i++) {
485c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav                String permission = mPermissions.keyAt(i);
486c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav                if (!hasPermission(permission, userId)) {
487c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav                    continue;
488c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav                }
489c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav                PermissionData permissionData = mPermissions.valueAt(i);
49000f3904629ef89192e061c1995801ef322fc0bcfJeff Sharkey                final int[] permGids = permissionData.computeGids(userId);
491c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav                if (permGids != NO_GIDS) {
492c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav                    gids = appendInts(gids, permGids);
493c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav                }
494c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            }
495c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        }
496c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
497c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        return gids;
498c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    }
499c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
500c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    /**
501c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * Compute the Linux gids for all device users from the permissions
502c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * granted to these users.
503c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     *
504c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * @return The gids for all device users.
505c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     */
50691edde24ffa5d78df18bf752de88dfe2bc8c4119Jeff Sharkey    public int[] computeGids(int[] userIds) {
507c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        int[] gids = mGlobalGids;
508c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
50991edde24ffa5d78df18bf752de88dfe2bc8c4119Jeff Sharkey        for (int userId : userIds) {
510c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            final int[] userGids = computeGids(userId);
511c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            gids = appendInts(gids, userGids);
512c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        }
513c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
514c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        return gids;
515c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    }
516c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
517c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    /**
518c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     * Resets the internal state of this object.
519c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav     */
520c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    public void reset() {
521c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        mGlobalGids = NO_GIDS;
522c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        mPermissions = null;
5239c165d76010d9f79f5cd71978742a335b6b8d1b4Svet Ganov        mPermissionReviewRequired = null;
524c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    }
525c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
5268c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov    private PermissionState getPermissionState(String name, int userId) {
5271b7025f264fd811ab27470867f8e65eeebf092e9Svetoslav        if (mPermissions == null) {
5288c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            return null;
5291b7025f264fd811ab27470867f8e65eeebf092e9Svetoslav        }
5308c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        PermissionData permissionData = mPermissions.get(name);
5318c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        if (permissionData == null) {
5328c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            return null;
5338c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        }
5348c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        return permissionData.getPermissionState(userId);
5358c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov    }
5361b7025f264fd811ab27470867f8e65eeebf092e9Svetoslav
5378c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov    private List<PermissionState> getPermissionStatesInternal(int userId) {
5388c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        enforceValidUserId(userId);
5398c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
5408c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        if (mPermissions == null) {
5418c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            return Collections.emptyList();
5421b7025f264fd811ab27470867f8e65eeebf092e9Svetoslav        }
5431b7025f264fd811ab27470867f8e65eeebf092e9Svetoslav
5448c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        List<PermissionState> permissionStates = new ArrayList<>();
5451b7025f264fd811ab27470867f8e65eeebf092e9Svetoslav
5461b7025f264fd811ab27470867f8e65eeebf092e9Svetoslav        final int permissionCount = mPermissions.size();
5471b7025f264fd811ab27470867f8e65eeebf092e9Svetoslav        for (int i = 0; i < permissionCount; i++) {
5488c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            PermissionData permissionData = mPermissions.valueAt(i);
5491b7025f264fd811ab27470867f8e65eeebf092e9Svetoslav
5508c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            PermissionState permissionState = permissionData.getPermissionState(userId);
5518c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            if (permissionState != null) {
5528c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                permissionStates.add(permissionState);
5531b7025f264fd811ab27470867f8e65eeebf092e9Svetoslav            }
5541b7025f264fd811ab27470867f8e65eeebf092e9Svetoslav        }
5551b7025f264fd811ab27470867f8e65eeebf092e9Svetoslav
556ca8e6da41c6e63e3ed17eb461171f1ef2e1d29c6Dianne Hackborn        return permissionStates;
5571b7025f264fd811ab27470867f8e65eeebf092e9Svetoslav    }
5581b7025f264fd811ab27470867f8e65eeebf092e9Svetoslav
559c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    private int grantPermission(BasePermission permission, int userId) {
56091a39d126d1f6efa47948ca1039ca347c1bd19e6Todd Kennedy        if (hasPermission(permission.getName(), userId)) {
561c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            return PERMISSION_OPERATION_FAILURE;
562c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        }
563c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
564b3a6defec84ab1d420b049c575cb37b1151e095aSvetoslav        final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
565c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;
566c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
5678c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        PermissionData permissionData = ensurePermissionData(permission);
568c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
5698c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        if (!permissionData.grant(userId)) {
570c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            return PERMISSION_OPERATION_FAILURE;
571c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        }
572c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
573c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        if (hasGids) {
574c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            final int[] newGids = computeGids(userId);
575c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            if (oldGids.length != newGids.length) {
576c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav                return PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
577c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            }
578c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        }
579c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
580c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        return PERMISSION_OPERATION_SUCCESS;
581c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    }
582c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
583c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    private int revokePermission(BasePermission permission, int userId) {
58491a39d126d1f6efa47948ca1039ca347c1bd19e6Todd Kennedy        final String permName = permission.getName();
58591a39d126d1f6efa47948ca1039ca347c1bd19e6Todd Kennedy        if (!hasPermission(permName, userId)) {
586c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            return PERMISSION_OPERATION_FAILURE;
587c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        }
588c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
589b3a6defec84ab1d420b049c575cb37b1151e095aSvetoslav        final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
590c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;
591c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
59291a39d126d1f6efa47948ca1039ca347c1bd19e6Todd Kennedy        PermissionData permissionData = mPermissions.get(permName);
593c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
5948c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        if (!permissionData.revoke(userId)) {
595c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            return PERMISSION_OPERATION_FAILURE;
596c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        }
597c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
5988c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        if (permissionData.isDefault()) {
59991a39d126d1f6efa47948ca1039ca347c1bd19e6Todd Kennedy            ensureNoPermissionData(permName);
600c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        }
601c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
602c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        if (hasGids) {
603c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            final int[] newGids = computeGids(userId);
604c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            if (oldGids.length != newGids.length) {
605c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav                return PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
606c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            }
607c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        }
608c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
609c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        return PERMISSION_OPERATION_SUCCESS;
610c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    }
611c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
6123cd658e1a598e59738bc129c35eecf4cd0f20680Todd Kennedy    // TODO: fix this to use arraycopy and append all ints in one go
613c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    private static int[] appendInts(int[] current, int[] added) {
614c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        if (current != null && added != null) {
615c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            for (int guid : added) {
616c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav                current = ArrayUtils.appendInt(current, guid);
617c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            }
618c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        }
619c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        return current;
620c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    }
621c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
622c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    private static void enforceValidUserId(int userId) {
623c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        if (userId != UserHandle.USER_ALL && userId < 0) {
624c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            throw new IllegalArgumentException("Invalid userId:" + userId);
625c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        }
626c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    }
627c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
6288c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov    private PermissionData ensurePermissionData(BasePermission permission) {
62991a39d126d1f6efa47948ca1039ca347c1bd19e6Todd Kennedy        final String permName = permission.getName();
6308c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        if (mPermissions == null) {
6318c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            mPermissions = new ArrayMap<>();
6328c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        }
63391a39d126d1f6efa47948ca1039ca347c1bd19e6Todd Kennedy        PermissionData permissionData = mPermissions.get(permName);
6348c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        if (permissionData == null) {
6358c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            permissionData = new PermissionData(permission);
63691a39d126d1f6efa47948ca1039ca347c1bd19e6Todd Kennedy            mPermissions.put(permName, permissionData);
6378c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        }
6388c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        return permissionData;
6398c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov    }
6408c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
6418c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov    private void ensureNoPermissionData(String name) {
6428c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        if (mPermissions == null) {
6438c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            return;
6448c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        }
6458c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        mPermissions.remove(name);
6468c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        if (mPermissions.isEmpty()) {
6478c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            mPermissions = null;
6488c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        }
6498c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov    }
6508c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
651c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    private static final class PermissionData {
65200f3904629ef89192e061c1995801ef322fc0bcfJeff Sharkey        private final BasePermission mPerm;
6538c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        private SparseArray<PermissionState> mUserStates = new SparseArray<>();
654c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
65500f3904629ef89192e061c1995801ef322fc0bcfJeff Sharkey        public PermissionData(BasePermission perm) {
65600f3904629ef89192e061c1995801ef322fc0bcfJeff Sharkey            mPerm = perm;
657c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        }
658c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
659c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        public PermissionData(PermissionData other) {
66000f3904629ef89192e061c1995801ef322fc0bcfJeff Sharkey            this(other.mPerm);
6618c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            final int otherStateCount = other.mUserStates.size();
6628c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            for (int i = 0; i < otherStateCount; i++) {
6638c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                final int otherUserId = other.mUserStates.keyAt(i);
6648c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                PermissionState otherState = other.mUserStates.valueAt(i);
6658c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                mUserStates.put(otherUserId, new PermissionState(otherState));
666c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            }
667c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        }
668c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
66900f3904629ef89192e061c1995801ef322fc0bcfJeff Sharkey        public int[] computeGids(int userId) {
67000f3904629ef89192e061c1995801ef322fc0bcfJeff Sharkey            return mPerm.computeGids(userId);
671c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        }
672c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
6738c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        public boolean isGranted(int userId) {
6748c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            if (isInstallPermission()) {
6758c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                userId = UserHandle.USER_ALL;
676c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            }
677c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
6788c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            PermissionState userState = mUserStates.get(userId);
6798c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            if (userState == null) {
6808c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                return false;
681c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            }
682c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
6838c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            return userState.mGranted;
684c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        }
685c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
6868c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        public boolean grant(int userId) {
6878c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            if (!isCompatibleUserId(userId)) {
688c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav                return false;
689c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            }
690c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
6918c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            if (isGranted(userId)) {
6928c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                return false;
693c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            }
694c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
6958c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            PermissionState userState = mUserStates.get(userId);
6968c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            if (userState == null) {
69791a39d126d1f6efa47948ca1039ca347c1bd19e6Todd Kennedy                userState = new PermissionState(mPerm.getName());
6988c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                mUserStates.put(userId, userState);
6998c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            }
7008c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
7018c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            userState.mGranted = true;
702c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
703c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            return true;
704c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        }
705c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
7068c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        public boolean revoke(int userId) {
7078c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            if (!isCompatibleUserId(userId)) {
708c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav                return false;
709c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            }
710c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
7118c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            if (!isGranted(userId)) {
7128c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                return false;
713c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            }
714c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
7158c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            PermissionState userState = mUserStates.get(userId);
7168c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            userState.mGranted = false;
717c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
7188c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            if (userState.isDefault()) {
7198c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                mUserStates.remove(userId);
720c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            }
721c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav
722c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav            return true;
723c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav        }
7248c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
7258c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        public PermissionState getPermissionState(int userId) {
7268c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            return mUserStates.get(userId);
7278c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        }
7288c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
7298c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        public int getFlags(int userId) {
7308c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            PermissionState userState = mUserStates.get(userId);
7318c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            if (userState != null) {
7328c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                return userState.mFlags;
7338c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            }
7348c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            return 0;
7358c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        }
7368c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
7378c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        public boolean isDefault() {
7388c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            return mUserStates.size() <= 0;
7398c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        }
7408c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
7418c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        public static boolean isInstallPermissionKey(int userId) {
7428c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            return userId == UserHandle.USER_ALL;
7438c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        }
7448c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
7458c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        public boolean updateFlags(int userId, int flagMask, int flagValues) {
7468c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            if (isInstallPermission()) {
7478c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                userId = UserHandle.USER_ALL;
7488c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            }
7498c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
7508c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            if (!isCompatibleUserId(userId)) {
7518c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                return false;
7528c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            }
7538c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
7548c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            final int newFlags = flagValues & flagMask;
7558c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
7568c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            PermissionState userState = mUserStates.get(userId);
7578c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            if (userState != null) {
7588c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                final int oldFlags = userState.mFlags;
7598c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                userState.mFlags = (userState.mFlags & ~flagMask) | newFlags;
7608c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                if (userState.isDefault()) {
7618c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                    mUserStates.remove(userId);
7628c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                }
7638c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                return userState.mFlags != oldFlags;
7648c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            } else if (newFlags != 0) {
76591a39d126d1f6efa47948ca1039ca347c1bd19e6Todd Kennedy                userState = new PermissionState(mPerm.getName());
7668c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                userState.mFlags = newFlags;
7678c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                mUserStates.put(userId, userState);
7688c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                return true;
7698c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            }
7708c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
7718c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            return false;
7728c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        }
7738c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
7748c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        private boolean isCompatibleUserId(int userId) {
7758c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            return isDefault() || !(isInstallPermission() ^ isInstallPermissionKey(userId));
7768c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        }
7778c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
7788c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        private boolean isInstallPermission() {
7798c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            return mUserStates.size() == 1
7808c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov                    && mUserStates.get(UserHandle.USER_ALL) != null;
7818c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        }
7828c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov    }
7838c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
7848c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov    public static final class PermissionState {
7858c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        private final String mName;
7868c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        private boolean mGranted;
7878c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        private int mFlags;
7888c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
7898c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        public PermissionState(String name) {
7908c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            mName = name;
7918c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        }
7928c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
7938c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        public PermissionState(PermissionState other) {
7948c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            mName = other.mName;
7958c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            mGranted = other.mGranted;
7968c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            mFlags = other.mFlags;
7978c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        }
7988c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
7998c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        public boolean isDefault() {
8008c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            return !mGranted && mFlags == 0;
8018c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        }
8028c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
8038c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        public String getName() {
8048c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            return mName;
8058c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        }
8068c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
8078c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        public boolean isGranted() {
8088c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            return mGranted;
8098c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        }
8108c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov
8118c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        public int getFlags() {
8128c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov            return mFlags;
8138c7f700a59ad26e75c9791335d78f14322cad49aSvet Ganov        }
814c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav    }
815c6d1c345f41cf817bf2c07c97b97107d94296064Svetoslav}
816