• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.packageinstaller.permission.model;
18 
19 import android.app.LoaderManager;
20 import android.app.LoaderManager.LoaderCallbacks;
21 import android.content.AsyncTaskLoader;
22 import android.content.Context;
23 import android.content.Loader;
24 import android.content.pm.PackageInfo;
25 import android.content.pm.PackageItemInfo;
26 import android.content.pm.PackageManager;
27 import android.content.pm.PermissionGroupInfo;
28 import android.content.pm.PermissionInfo;
29 import android.graphics.drawable.Drawable;
30 import android.os.Bundle;
31 import android.util.ArraySet;
32 
33 import com.android.packageinstaller.R;
34 import com.android.packageinstaller.permission.utils.Utils;
35 
36 import java.util.ArrayList;
37 import java.util.Collections;
38 import java.util.List;
39 import java.util.Set;
40 
41 public final class PermissionGroups implements LoaderCallbacks<List<PermissionGroup>> {
42     private final ArrayList<PermissionGroup> mGroups = new ArrayList<>();
43     private final Context mContext;
44     private final LoaderManager mLoaderManager;
45     private final PermissionsGroupsChangeCallback mCallback;
46 
47     public interface PermissionsGroupsChangeCallback {
onPermissionGroupsChanged()48         public void onPermissionGroupsChanged();
49     }
50 
PermissionGroups(Context context, LoaderManager loaderManager, PermissionsGroupsChangeCallback callback)51     public PermissionGroups(Context context, LoaderManager loaderManager,
52             PermissionsGroupsChangeCallback callback) {
53         mContext = context;
54         mLoaderManager = loaderManager;
55         mCallback = callback;
56     }
57 
58     @Override
onCreateLoader(int id, Bundle args)59     public Loader<List<PermissionGroup>> onCreateLoader(int id, Bundle args) {
60         return new PermissionsLoader(mContext);
61     }
62 
63     @Override
onLoadFinished(Loader<List<PermissionGroup>> loader, List<PermissionGroup> groups)64     public void onLoadFinished(Loader<List<PermissionGroup>> loader,
65             List<PermissionGroup> groups) {
66         if (mGroups.equals(groups)) {
67             return;
68         }
69         mGroups.clear();
70         mGroups.addAll(groups);
71         mCallback.onPermissionGroupsChanged();
72     }
73 
74     @Override
onLoaderReset(Loader<List<PermissionGroup>> loader)75     public void onLoaderReset(Loader<List<PermissionGroup>> loader) {
76         mGroups.clear();
77         mCallback.onPermissionGroupsChanged();
78     }
79 
refresh()80     public void refresh() {
81         mLoaderManager.restartLoader(0, null, this);
82         mLoaderManager.getLoader(0).forceLoad();
83     }
84 
getGroups()85     public List<PermissionGroup> getGroups() {
86         return mGroups;
87     }
88 
getGroup(String name)89     public PermissionGroup getGroup(String name) {
90         for (PermissionGroup group : mGroups) {
91             if (group.getName().equals(name)) {
92                 return group;
93             }
94         }
95         return null;
96     }
97 
98     private static final class PermissionsLoader extends AsyncTaskLoader<List<PermissionGroup>> {
99 
PermissionsLoader(Context context)100         public PermissionsLoader(Context context) {
101             super(context);
102         }
103 
104         @Override
loadInBackground()105         public List<PermissionGroup> loadInBackground() {
106             List<PermissionGroup> groups = new ArrayList<>();
107             Set<String> seenPermissions = new ArraySet<>();
108 
109 
110             PackageManager packageManager = getContext().getPackageManager();
111             List<PermissionGroupInfo> groupInfos = packageManager.getAllPermissionGroups(0);
112 
113             for (PermissionGroupInfo groupInfo : groupInfos) {
114                 // Mare sure we respond to cancellation.
115                 if (isLoadInBackgroundCanceled()) {
116                     return Collections.emptyList();
117                 }
118 
119                 // Get the permissions in this group.
120                 final List<PermissionInfo> groupPermissions;
121                 try {
122                     groupPermissions = packageManager.queryPermissionsByGroup(groupInfo.name, 0);
123                 } catch (PackageManager.NameNotFoundException e) {
124                     continue;
125                 }
126 
127                 boolean hasRuntimePermissions = false;
128 
129                 // Cache seen permissions and see if group has runtime permissions.
130                 for (PermissionInfo groupPermission : groupPermissions) {
131                     seenPermissions.add(groupPermission.name);
132                     if (groupPermission.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS
133                             && (groupPermission.flags & PermissionInfo.FLAG_INSTALLED) != 0
134                             && (groupPermission.flags & PermissionInfo.FLAG_REMOVED) == 0) {
135                         hasRuntimePermissions = true;
136                     }
137                 }
138 
139                 // No runtime permissions - not interesting for us.
140                 if (!hasRuntimePermissions) {
141                     continue;
142                 }
143 
144                 CharSequence label = loadItemInfoLabel(groupInfo);
145                 Drawable icon = loadItemInfoIcon(groupInfo);
146 
147                 // Create the group and add to the list.
148                 PermissionGroup group = new PermissionGroup(groupInfo.name,
149                         groupInfo.packageName, label, icon);
150                 groups.add(group);
151             }
152 
153 
154             // Make sure we add groups for lone runtime permissions.
155             List<PackageInfo> installedPackages = getContext().getPackageManager()
156                     .getInstalledPackages(PackageManager.GET_PERMISSIONS);
157 
158 
159             // We will filter out permissions that no package requests.
160             Set<String> requestedPermissions = new ArraySet<>();
161             for (PackageInfo installedPackage : installedPackages) {
162                 if (installedPackage.requestedPermissions == null) {
163                     continue;
164                 }
165                 for (String requestedPermission : installedPackage.requestedPermissions) {
166                     requestedPermissions.add(requestedPermission);
167                 }
168             }
169 
170             for (PackageInfo installedPackage : installedPackages) {
171                 if (installedPackage.permissions == null) {
172                     continue;
173                 }
174 
175                 for (PermissionInfo permissionInfo : installedPackage.permissions) {
176                     // If we have handled this permission, no more work to do.
177                     if (!seenPermissions.add(permissionInfo.name)) {
178                         continue;
179                     }
180 
181                     // We care only about installed runtime permissions.
182                     if (permissionInfo.protectionLevel != PermissionInfo.PROTECTION_DANGEROUS
183                             || (permissionInfo.flags & PermissionInfo.FLAG_INSTALLED) == 0) {
184                         continue;
185                     }
186 
187                     // If no app uses this permission,
188                     if (!requestedPermissions.contains(permissionInfo.name)) {
189                         continue;
190                     }
191 
192                     CharSequence label = loadItemInfoLabel(permissionInfo);
193                     Drawable icon = loadItemInfoIcon(permissionInfo);
194 
195                     // Create the group and add to the list.
196                     PermissionGroup group = new PermissionGroup(permissionInfo.name,
197                             permissionInfo.packageName, label, icon);
198                     groups.add(group);
199                 }
200             }
201 
202             Collections.sort(groups);
203             return groups;
204         }
205 
loadItemInfoLabel(PackageItemInfo itemInfo)206         private CharSequence loadItemInfoLabel(PackageItemInfo itemInfo) {
207             CharSequence label = itemInfo.loadLabel(getContext().getPackageManager());
208             if (label == null) {
209                 label = itemInfo.name;
210             }
211             return label;
212         }
213 
loadItemInfoIcon(PackageItemInfo itemInfo)214         private Drawable loadItemInfoIcon(PackageItemInfo itemInfo) {
215             Drawable icon = null;
216             if (itemInfo.icon > 0) {
217                 icon = Utils.loadDrawable(getContext().getPackageManager(),
218                         itemInfo.packageName, itemInfo.icon);
219             }
220             if (icon == null) {
221                 icon = getContext().getDrawable(R.drawable.ic_perm_device_info);
222             }
223             return icon;
224         }
225     }
226 }
227