blob: 9eb97c5a734bf366ae8a019a4a6e64b1aca069e2 [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.compatibility.common.deviceinfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PermissionInfo;
import com.android.compatibility.common.util.DeviceInfoStore;
import java.io.IOException;
import java.util.*;
/**
* PackageDeviceInfo collector.
*/
public class PackageDeviceInfo extends DeviceInfo {
private static final String PACKAGE = "package";
private static final String NAME = "name";
private static final String VERSION_NAME = "version_name";
private static final String SYSTEM_PRIV = "system_priv";
private static final String PRIV_APP_DIR = "/system/priv-app";
private static final String MIN_SDK = "min_sdk";
private static final String TARGET_SDK = "target_sdk";
private static final String REQUESTED_PERMISSIONS = "requested_permissions";
private static final String PERMISSION_NAME = "name";
private static final String PERMISSION_FLAGS = "flags";
private static final String PERMISSION_GROUP = "permission_group";
private static final String PERMISSION_PROTECTION = "protection_level";
private static final String PERMISSION_PROTECTION_FLAGS = "protection_level_flags";
private static final String HAS_SYSTEM_UID = "has_system_uid";
private static final String SHARES_INSTALL_PERMISSION = "shares_install_packages_permission";
private static final String INSTALL_PACKAGES_PERMISSION = "android.permission.INSTALL_PACKAGES";
@Override
protected void collectDeviceInfo(DeviceInfoStore store) throws Exception {
final PackageManager pm = getContext().getPackageManager();
final ApplicationInfo system = pm.getApplicationInfo("android", 0);
final List<PackageInfo> allPackages = pm.getInstalledPackages(PackageManager.GET_PERMISSIONS);
store.startArray(PACKAGE);
for (PackageInfo pkg : allPackages) {
store.startGroup();
store.addResult(NAME, pkg.packageName);
store.addResult(VERSION_NAME, pkg.versionName);
store.startArray(REQUESTED_PERMISSIONS);
if (pkg.requestedPermissions != null && pkg.requestedPermissions.length > 0) {
for (String permission : pkg.requestedPermissions) {
try {
final PermissionInfo pi = pm.getPermissionInfo(permission, 0);
store.startGroup();
store.addResult(PERMISSION_NAME, permission);
store.addResult(PERMISSION_FLAGS, pi.flags);
store.addResult(PERMISSION_GROUP, pi.group);
store.addResult(PERMISSION_PROTECTION, pi.getProtection());
store.addResult(PERMISSION_PROTECTION_FLAGS, pi.getProtectionFlags());
store.endGroup();
} catch (PackageManager.NameNotFoundException e) {
// ignore unrecognized permission and continue
}
}
}
store.endArray();
final ApplicationInfo appInfo = pkg.applicationInfo;
if (appInfo != null) {
String dir = appInfo.sourceDir;
store.addResult(SYSTEM_PRIV, dir != null && dir.startsWith(PRIV_APP_DIR));
store.addResult(MIN_SDK, appInfo.minSdkVersion);
store.addResult(TARGET_SDK, appInfo.targetSdkVersion);
store.addResult(HAS_SYSTEM_UID, appInfo.uid == system.uid);
final boolean canInstall = sharesUidWithPackageHolding(pm, appInfo.uid, INSTALL_PACKAGES_PERMISSION);
store.addResult(SHARES_INSTALL_PERMISSION, canInstall);
}
store.endGroup();
}
store.endArray(); // "package"
}
private static boolean sharesUidWithPackageHolding(PackageManager pm, int uid, String permission) {
final String[] sharesUidWith = pm.getPackagesForUid(uid);
if (sharesUidWith == null) {
return false;
}
// Approx 20 permissions per package for rough estimate of sizing
final List<String> sharedPermissions = new ArrayList<>(sharesUidWith.length * 20);
for (String pkg :sharesUidWith){
try {
final PackageInfo info = pm.getPackageInfo(pkg, PackageManager.GET_PERMISSIONS);
if (info.requestedPermissions == null) {
continue;
}
for (String p : info.requestedPermissions) {
if (p != null) {
sharedPermissions.add(p);
}
}
} catch (PackageManager.NameNotFoundException e) {
// ignore, continue
}
}
return sharedPermissions.contains(permission);
}
}