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