1 /* 2 * Copyright (C) 2018 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.AppOpsManager; 20 import android.app.AppOpsManager.HistoricalOp; 21 import android.app.AppOpsManager.HistoricalPackageOps; 22 import android.app.AppOpsManager.OpEntry; 23 import android.app.AppOpsManager.PackageOps; 24 25 import androidx.annotation.NonNull; 26 import androidx.annotation.Nullable; 27 28 import com.android.packageinstaller.permission.model.PermissionApps.PermissionApp; 29 30 import java.util.ArrayList; 31 import java.util.List; 32 import java.util.function.Function; 33 34 /** 35 * Stats for permission usage of an app. This data is for a given time period, 36 * i.e. does not contain the full history. 37 */ 38 public final class AppPermissionUsage { 39 private final @NonNull List<GroupUsage> mGroupUsages = new ArrayList<>(); 40 private final @NonNull PermissionApp mPermissionApp; 41 AppPermissionUsage(@onNull PermissionApp permissionApp, @NonNull List<AppPermissionGroup> groups, @Nullable PackageOps lastUsage, @Nullable HistoricalPackageOps historicalUsage)42 private AppPermissionUsage(@NonNull PermissionApp permissionApp, 43 @NonNull List<AppPermissionGroup> groups, @Nullable PackageOps lastUsage, 44 @Nullable HistoricalPackageOps historicalUsage) { 45 mPermissionApp = permissionApp; 46 final int groupCount = groups.size(); 47 for (int i = 0; i < groupCount; i++) { 48 final AppPermissionGroup group = groups.get(i); 49 mGroupUsages.add(new GroupUsage(group, lastUsage, historicalUsage)); 50 } 51 } 52 getApp()53 public @NonNull PermissionApp getApp() { 54 return mPermissionApp; 55 } 56 getPackageName()57 public @NonNull String getPackageName() { 58 return mPermissionApp.getPackageName(); 59 } 60 getUid()61 public int getUid() { 62 return mPermissionApp.getUid(); 63 } 64 getLastAccessTime()65 public long getLastAccessTime() { 66 long lastAccessTime = 0; 67 final int permissionCount = mGroupUsages.size(); 68 for (int i = 0; i < permissionCount; i++) { 69 final GroupUsage groupUsage = mGroupUsages.get(i); 70 lastAccessTime = Math.max(lastAccessTime, groupUsage.getLastAccessTime()); 71 } 72 return lastAccessTime; 73 } 74 getAccessCount()75 public long getAccessCount() { 76 long accessCount = 0; 77 final int permissionCount = mGroupUsages.size(); 78 for (int i = 0; i < permissionCount; i++) { 79 final GroupUsage permission = mGroupUsages.get(i); 80 accessCount += permission.getAccessCount(); 81 } 82 return accessCount; 83 } 84 getGroupUsages()85 public @NonNull List<GroupUsage> getGroupUsages() { 86 return mGroupUsages; 87 } 88 89 /** 90 * Stats for permission usage of a permission group. This data is for a 91 * given time period, i.e. does not contain the full history. 92 */ 93 public static class GroupUsage { 94 private final @NonNull AppPermissionGroup mGroup; 95 private final @Nullable PackageOps mLastUsage; 96 private final @Nullable HistoricalPackageOps mHistoricalUsage; 97 GroupUsage(@onNull AppPermissionGroup group, @Nullable PackageOps lastUsage, @Nullable HistoricalPackageOps historicalUsage)98 GroupUsage(@NonNull AppPermissionGroup group, @Nullable PackageOps lastUsage, 99 @Nullable HistoricalPackageOps historicalUsage) { 100 mGroup = group; 101 mLastUsage = lastUsage; 102 mHistoricalUsage = historicalUsage; 103 } 104 getLastAccessTime()105 public long getLastAccessTime() { 106 if (mLastUsage == null) { 107 return 0; 108 } 109 return lastAccessAggregate( 110 (op) -> op.getLastAccessTime(AppOpsManager.OP_FLAGS_ALL_TRUSTED)); 111 } 112 getLastAccessForegroundTime()113 public long getLastAccessForegroundTime() { 114 if (mLastUsage == null) { 115 return 0; 116 } 117 return lastAccessAggregate( 118 (op) -> op.getLastAccessForegroundTime(AppOpsManager.OP_FLAGS_ALL_TRUSTED)); 119 } 120 getLastAccessBackgroundTime()121 public long getLastAccessBackgroundTime() { 122 if (mLastUsage == null) { 123 return 0; 124 } 125 return lastAccessAggregate( 126 (op) -> op.getLastAccessBackgroundTime(AppOpsManager.OP_FLAGS_ALL_TRUSTED)); 127 } 128 getForegroundAccessCount()129 public long getForegroundAccessCount() { 130 if (mHistoricalUsage == null) { 131 return 0; 132 } 133 return extractAggregate((HistoricalOp op) 134 -> op.getForegroundAccessCount(AppOpsManager.OP_FLAGS_ALL_TRUSTED)); 135 } 136 getBackgroundAccessCount()137 public long getBackgroundAccessCount() { 138 if (mHistoricalUsage == null) { 139 return 0; 140 } 141 return extractAggregate((HistoricalOp op) 142 -> op.getBackgroundAccessCount(AppOpsManager.OP_FLAGS_ALL_TRUSTED)); 143 } 144 getAccessCount()145 public long getAccessCount() { 146 if (mHistoricalUsage == null) { 147 return 0; 148 } 149 return extractAggregate((HistoricalOp op) -> 150 op.getForegroundAccessCount(AppOpsManager.OP_FLAGS_ALL_TRUSTED) 151 + op.getBackgroundAccessCount(AppOpsManager.OP_FLAGS_ALL_TRUSTED) 152 ); 153 } 154 getAccessDuration()155 public long getAccessDuration() { 156 if (mHistoricalUsage == null) { 157 return 0; 158 } 159 return extractAggregate((HistoricalOp op) -> 160 op.getForegroundAccessDuration(AppOpsManager.OP_FLAGS_ALL_TRUSTED) 161 + op.getBackgroundAccessDuration(AppOpsManager.OP_FLAGS_ALL_TRUSTED) 162 ); 163 } 164 isRunning()165 public boolean isRunning() { 166 if (mLastUsage == null) { 167 return false; 168 } 169 final ArrayList<Permission> permissions = mGroup.getPermissions(); 170 final int permissionCount = permissions.size(); 171 for (int i = 0; i < permissionCount; i++) { 172 final Permission permission = permissions.get(i); 173 final String opName = permission.getAppOp(); 174 final List<OpEntry> ops = mLastUsage.getOps(); 175 final int opCount = ops.size(); 176 for (int j = 0; j < opCount; j++) { 177 final OpEntry op = ops.get(j); 178 if (op.getOpStr().equals(opName) && op.isRunning()) { 179 return true; 180 } 181 } 182 } 183 return false; 184 } 185 extractAggregate(@onNull Function<HistoricalOp, Long> extractor)186 private long extractAggregate(@NonNull Function<HistoricalOp, Long> extractor) { 187 long aggregate = 0; 188 final ArrayList<Permission> permissions = mGroup.getPermissions(); 189 final int permissionCount = permissions.size(); 190 for (int i = 0; i < permissionCount; i++) { 191 final Permission permission = permissions.get(i); 192 final String opName = permission.getAppOp(); 193 final HistoricalOp historicalOp = mHistoricalUsage.getOp(opName); 194 if (historicalOp != null) { 195 aggregate += extractor.apply(historicalOp); 196 } 197 } 198 return aggregate; 199 } 200 lastAccessAggregate(@onNull Function<OpEntry, Long> extractor)201 private long lastAccessAggregate(@NonNull Function<OpEntry, Long> extractor) { 202 long aggregate = 0; 203 final ArrayList<Permission> permissions = mGroup.getPermissions(); 204 final int permissionCount = permissions.size(); 205 for (int permissionNum = 0; permissionNum < permissionCount; permissionNum++) { 206 final Permission permission = permissions.get(permissionNum); 207 final String opName = permission.getAppOp(); 208 final List<OpEntry> ops = mLastUsage.getOps(); 209 final int opCount = ops.size(); 210 for (int opNum = 0; opNum < opCount; opNum++) { 211 final OpEntry op = ops.get(opNum); 212 if (op.getOpStr().equals(opName)) { 213 aggregate = Math.max(aggregate, extractor.apply(op)); 214 } 215 } 216 } 217 return aggregate; 218 } 219 getGroup()220 public @NonNull AppPermissionGroup getGroup() { 221 return mGroup; 222 } 223 } 224 225 public static class Builder { 226 private final @NonNull List<AppPermissionGroup> mGroups = new ArrayList<>(); 227 private final @NonNull PermissionApp mPermissionApp; 228 private @Nullable PackageOps mLastUsage; 229 private @Nullable HistoricalPackageOps mHistoricalUsage; 230 Builder(@onNull PermissionApp permissionApp)231 public Builder(@NonNull PermissionApp permissionApp) { 232 mPermissionApp = permissionApp; 233 } 234 addGroup(@onNull AppPermissionGroup group)235 public @NonNull Builder addGroup(@NonNull AppPermissionGroup group) { 236 mGroups.add(group); 237 return this; 238 } 239 setLastUsage(@ullable PackageOps lastUsage)240 public @NonNull Builder setLastUsage(@Nullable PackageOps lastUsage) { 241 mLastUsage = lastUsage; 242 return this; 243 } 244 setHistoricalUsage(@ullable HistoricalPackageOps historicalUsage)245 public @NonNull Builder setHistoricalUsage(@Nullable HistoricalPackageOps historicalUsage) { 246 mHistoricalUsage = historicalUsage; 247 return this; 248 } 249 build()250 public @NonNull AppPermissionUsage build() { 251 if (mGroups.isEmpty()) { 252 throw new IllegalStateException("mGroups cannot be empty."); 253 } 254 return new AppPermissionUsage(mPermissionApp, mGroups, mLastUsage, mHistoricalUsage); 255 } 256 } 257 } 258