1 /*
2  * Copyright (C) 2023 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 
17 package com.android.server.pm.permission;
18 
19 import android.annotation.NonNull;
20 import android.content.pm.PackageManagerInternal;
21 import android.util.ArrayMap;
22 import android.util.Log;
23 
24 import com.android.permission.persistence.RuntimePermissionsState;
25 import com.android.server.LocalManagerRegistry;
26 import com.android.server.LocalServices;
27 import com.android.server.pm.PackageManagerLocal;
28 import com.android.server.pm.pkg.PackageState;
29 import com.android.server.pm.pkg.SharedUserApi;
30 
31 import java.util.List;
32 import java.util.Map;
33 
34 /**
35  * Provider of legacy permissions data for new permission subsystem.
36  *
37  * @hide
38  */
39 public class PermissionMigrationHelperImpl implements PermissionMigrationHelper {
40     private static final String LOG_TAG = PermissionMigrationHelperImpl.class.getSimpleName();
41 
42     @Override
hasLegacyPermission()43     public boolean hasLegacyPermission() {
44         PackageManagerInternal packageManagerInternal =
45                 LocalServices.getService(PackageManagerInternal.class);
46         LegacyPermissionSettings legacySettings = packageManagerInternal.getLegacyPermissions();
47         return !(legacySettings.getPermissions().isEmpty()
48                 && legacySettings.getPermissionTrees().isEmpty());
49     }
50 
51     /**
52      * @return legacy permission definitions.
53      */
54     @NonNull
getLegacyPermissions()55     public Map<String, LegacyPermission> getLegacyPermissions() {
56         PackageManagerInternal mPackageManagerInternal =
57                 LocalServices.getService(PackageManagerInternal.class);
58         return toLegacyPermissions(
59                 mPackageManagerInternal.getLegacyPermissions().getPermissions());
60     }
61 
62     /**
63      * @return legacy permission trees.
64      */
65     @NonNull
getLegacyPermissionTrees()66     public Map<String, LegacyPermission> getLegacyPermissionTrees() {
67         PackageManagerInternal mPackageManagerInternal =
68                 LocalServices.getService(PackageManagerInternal.class);
69         return toLegacyPermissions(
70                 mPackageManagerInternal.getLegacyPermissions().getPermissionTrees());
71     }
72 
73     @NonNull
toLegacyPermissions( List<com.android.server.pm.permission.LegacyPermission> legacyPermissions)74     private Map<String, LegacyPermission> toLegacyPermissions(
75             List<com.android.server.pm.permission.LegacyPermission> legacyPermissions) {
76         Map<String, LegacyPermission> permissions = new ArrayMap<>();
77         legacyPermissions.forEach(legacyPermission -> {
78             LegacyPermission permission = new LegacyPermission(legacyPermission.getPermissionInfo(),
79                     legacyPermission.getType());
80             permissions.put(legacyPermission.getPermissionInfo().name, permission);
81         });
82 
83         return permissions;
84     }
85 
86     /**
87      * @return permissions state for a user, i.e. map of appId to map of permission name and state.
88      */
89     @NonNull
getLegacyPermissionStates(int userId)90     public Map<Integer, Map<String, LegacyPermissionState>> getLegacyPermissionStates(int userId) {
91         PackageManagerInternal mPackageManagerInternal =
92                 LocalServices.getService(PackageManagerInternal.class);
93         Map<Integer, Map<String, LegacyPermissionState>> appIdPermissionStates = new ArrayMap<>();
94 
95         RuntimePermissionsState legacyState =
96                 (RuntimePermissionsState) mPackageManagerInternal.getLegacyPermissionsState(userId);
97         PackageManagerLocal packageManagerLocal =
98                 LocalManagerRegistry.getManager(PackageManagerLocal.class);
99 
100         try (PackageManagerLocal.UnfilteredSnapshot snapshot =
101                      packageManagerLocal.withUnfilteredSnapshot()) {
102             Map<String, PackageState> packageStates = snapshot.getPackageStates();
103             legacyState.getPackagePermissions().forEach((packageName, permissionStates) -> {
104                 if (!permissionStates.isEmpty()) {
105                     PackageState packageState = packageStates.get(packageName);
106                     if (packageState != null) {
107                         int appId = packageState.getAppId();
108                         appIdPermissionStates.put(appId,
109                                 toLegacyPermissionStates(permissionStates));
110                     } else {
111                         Log.w(LOG_TAG, "Package " + packageName + " not found.");
112                     }
113                 }
114             });
115 
116             Map<String, SharedUserApi> sharedUsers = snapshot.getSharedUsers();
117             legacyState.getSharedUserPermissions().forEach((sharedUserName, permissionStates) -> {
118                 if (!permissionStates.isEmpty()) {
119                     SharedUserApi sharedUser = sharedUsers.get(sharedUserName);
120                     if (sharedUser != null) {
121                         int appId = sharedUser.getAppId();
122                         appIdPermissionStates.put(appId,
123                                 toLegacyPermissionStates(permissionStates));
124                     } else {
125                         Log.w(LOG_TAG, "Shared user " + sharedUserName + " not found.");
126                     }
127                 }
128             });
129         }
130         return appIdPermissionStates;
131     }
132 
133     @Override
getLegacyPermissionStateVersion(int userId)134     public int getLegacyPermissionStateVersion(int userId) {
135         PackageManagerInternal packageManagerInternal =
136                 LocalServices.getService(PackageManagerInternal.class);
137         int version = packageManagerInternal.getLegacyPermissionsVersion(userId);
138         // -1 No permission data available
139         // 0 runtime-permissions.xml exist w/o any version
140         switch (version) {
141             case -1:
142                 return 0;
143             case 0:
144                 return -1;
145             default:
146                 return version;
147         }
148     }
149 
150     @Override
hasLegacyPermissionState(int userId)151     public boolean hasLegacyPermissionState(int userId) {
152         return getLegacyPermissionStateVersion(userId) > -1;
153     }
154 
155     @NonNull
toLegacyPermissionStates( List<RuntimePermissionsState.PermissionState> permissions)156     private Map<String, LegacyPermissionState> toLegacyPermissionStates(
157             List<RuntimePermissionsState.PermissionState> permissions) {
158         Map<String, LegacyPermissionState> legacyPermissions = new ArrayMap<>();
159 
160         final int size = permissions.size();
161         for (int i = 0; i < size; i++) {
162             RuntimePermissionsState.PermissionState permState = permissions.get(i);
163             legacyPermissions.put(permState.getName(), new LegacyPermissionState(
164                     permState.isGranted(), permState.getFlags()));
165         }
166 
167         return legacyPermissions;
168     }
169 }
170