• 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.commands.monkey;
18 
19 import android.Manifest;
20 import android.companion.virtual.VirtualDeviceManager;
21 import android.content.pm.ApplicationInfo;
22 import android.content.pm.IPackageManager;
23 import android.content.pm.PackageInfo;
24 import android.content.pm.PackageManager;
25 import android.content.pm.PermissionInfo;
26 import android.os.Build;
27 import android.os.RemoteException;
28 import android.os.ServiceManager;
29 import android.os.UserHandle;
30 import android.permission.IPermissionManager;
31 
32 import java.util.ArrayList;
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Random;
37 
38 /**
39  * Utility class that encapsulates runtime permission related methods for monkey
40  *
41  */
42 public class MonkeyPermissionUtil {
43 
44     private static final String PERMISSION_PREFIX = "android.permission.";
45     private static final String PERMISSION_GROUP_PREFIX = "android.permission-group.";
46 
47     // from com.android.packageinstaller.permission.utils
48     private static final String[] MODERN_PERMISSION_GROUPS = {
49             Manifest.permission_group.CALENDAR, Manifest.permission_group.CAMERA,
50             Manifest.permission_group.CONTACTS, Manifest.permission_group.LOCATION,
51             Manifest.permission_group.SENSORS, Manifest.permission_group.SMS,
52             Manifest.permission_group.PHONE, Manifest.permission_group.MICROPHONE,
53             Manifest.permission_group.STORAGE
54     };
55 
56     // from com.android.packageinstaller.permission.utils
isModernPermissionGroup(String name)57     private static boolean isModernPermissionGroup(String name) {
58         for (String modernGroup : MODERN_PERMISSION_GROUPS) {
59             if (modernGroup.equals(name)) {
60                 return true;
61             }
62         }
63         return false;
64     }
65 
66     /**
67      * actual list of packages to target, with invalid packages excluded, and may optionally include
68      * system packages
69      */
70     private List<String> mTargetedPackages;
71     /** if we should target system packages regardless if they are listed */
72     private boolean mTargetSystemPackages;
73     private IPackageManager mPm;
74     private final IPermissionManager mPermManager;
75 
76     /** keep track of runtime permissions requested for each package targeted */
77     private Map<String, List<PermissionInfo>> mPermissionMap;
78 
MonkeyPermissionUtil()79     public MonkeyPermissionUtil() {
80         mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
81         mPermManager =
82                 IPermissionManager.Stub.asInterface(ServiceManager.getService("permissionmgr"));
83     }
84 
setTargetSystemPackages(boolean targetSystemPackages)85     public void setTargetSystemPackages(boolean targetSystemPackages) {
86         mTargetSystemPackages = targetSystemPackages;
87     }
88 
89     /**
90      * Decide if a package should be targeted by permission monkey
91      * @param info
92      * @return
93      */
shouldTargetPackage(PackageInfo info)94     private boolean shouldTargetPackage(PackageInfo info) {
95         // target if permitted by white listing / black listing rules
96         if (MonkeyUtils.getPackageFilter().checkEnteringPackage(info.packageName)) {
97             return true;
98         }
99         if (mTargetSystemPackages
100                 // not explicitly black listed
101                 && !MonkeyUtils.getPackageFilter().isPackageInvalid(info.packageName)
102                 // is a system app
103                 && (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
104             return true;
105         }
106         return false;
107     }
108 
shouldTargetPermission(String pkg, PermissionInfo pi)109     private boolean shouldTargetPermission(String pkg, PermissionInfo pi) throws RemoteException {
110         int flags = mPermManager.getPermissionFlags(pkg, pi.name,
111                 VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT,
112                 UserHandle.myUserId());
113         int fixedPermFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
114                 | PackageManager.FLAG_PERMISSION_POLICY_FIXED;
115         return pi.group != null && pi.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS
116                 && ((flags & fixedPermFlags) == 0)
117                 && isModernPermissionGroup(pi.group);
118     }
119 
populatePermissionsMapping()120     public boolean populatePermissionsMapping() {
121         mPermissionMap = new HashMap<>();
122         try {
123             List<?> pkgInfos = mPm.getInstalledPackages(
124                     PackageManager.GET_PERMISSIONS, UserHandle.myUserId()).getList();
125             for (Object o : pkgInfos) {
126                 PackageInfo info = (PackageInfo)o;
127                 if (!shouldTargetPackage(info)) {
128                     continue;
129                 }
130                 List<PermissionInfo> permissions = new ArrayList<>();
131                 if (info.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1) {
132                     // skip apps targetting lower API level
133                     continue;
134                 }
135                 if (info.requestedPermissions == null) {
136                     continue;
137                 }
138                 for (String perm : info.requestedPermissions) {
139                     PermissionInfo pi = mPermManager.getPermissionInfo(perm, "shell", 0);
140                     if (pi != null && shouldTargetPermission(info.packageName, pi)) {
141                         permissions.add(pi);
142                     }
143                 }
144                 if (!permissions.isEmpty()) {
145                     mPermissionMap.put(info.packageName, permissions);
146                 }
147             }
148         } catch (RemoteException re) {
149             Logger.err.println("** Failed talking with package manager!");
150             return false;
151         }
152         if (!mPermissionMap.isEmpty()) {
153             mTargetedPackages = new ArrayList<>(mPermissionMap.keySet());
154         }
155         return true;
156     }
157 
dump()158     public void dump() {
159         Logger.out.println("// Targeted packages and permissions:");
160         for (Map.Entry<String, List<PermissionInfo>> e : mPermissionMap.entrySet()) {
161             Logger.out.println(String.format("//  + Using %s", e.getKey()));
162             for (PermissionInfo pi : e.getValue()) {
163                 String name = pi.name;
164                 if (name != null) {
165                     if (name.startsWith(PERMISSION_PREFIX)) {
166                         name = name.substring(PERMISSION_PREFIX.length());
167                     }
168                 }
169                 String group = pi.group;
170                 if (group != null) {
171                     if (group.startsWith(PERMISSION_GROUP_PREFIX)) {
172                         group = group.substring(PERMISSION_GROUP_PREFIX.length());
173                     }
174                 }
175                 Logger.out.println(String.format("//    Permission: %s [%s]", name, group));
176             }
177         }
178     }
179 
generateRandomPermissionEvent(Random random)180     public MonkeyPermissionEvent generateRandomPermissionEvent(Random random) {
181         String pkg = mTargetedPackages.get(random.nextInt(mTargetedPackages.size()));
182         List<PermissionInfo> infos = mPermissionMap.get(pkg);
183         return new MonkeyPermissionEvent(pkg, infos.get(random.nextInt(infos.size())));
184     }
185 }
186