Merge "Send special permission information to netd"
am: c60e99de22
Change-Id: I35aa015a9448b5f8563da0aee40afd3101df29ff
This commit is contained in:
@@ -19,10 +19,11 @@ package com.android.server.connectivity;
|
|||||||
import static android.Manifest.permission.CHANGE_NETWORK_STATE;
|
import static android.Manifest.permission.CHANGE_NETWORK_STATE;
|
||||||
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
|
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
|
||||||
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
|
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
|
||||||
|
import static android.Manifest.permission.INTERNET;
|
||||||
import static android.Manifest.permission.NETWORK_STACK;
|
import static android.Manifest.permission.NETWORK_STACK;
|
||||||
import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
|
import static android.Manifest.permission.UPDATE_DEVICE_STATS;
|
||||||
import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
|
|
||||||
import static android.content.pm.PackageManager.GET_PERMISSIONS;
|
import static android.content.pm.PackageManager.GET_PERMISSIONS;
|
||||||
|
import static android.content.pm.PackageManager.MATCH_ANY_USER;
|
||||||
import static android.os.Process.INVALID_UID;
|
import static android.os.Process.INVALID_UID;
|
||||||
import static android.os.Process.SYSTEM_UID;
|
import static android.os.Process.SYSTEM_UID;
|
||||||
|
|
||||||
@@ -32,23 +33,31 @@ import android.content.pm.ApplicationInfo;
|
|||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
|
import android.content.pm.PackageManagerInternal;
|
||||||
import android.content.pm.UserInfo;
|
import android.content.pm.UserInfo;
|
||||||
import android.net.Uri;
|
import android.net.INetd;
|
||||||
|
import android.net.util.NetdService;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.INetworkManagementService;
|
import android.os.INetworkManagementService;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.Slog;
|
||||||
|
import android.util.SparseIntArray;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.GuardedBy;
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
import com.android.internal.util.ArrayUtils;
|
||||||
|
import com.android.server.LocalServices;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -75,6 +84,59 @@ public class PermissionMonitor {
|
|||||||
// Keys are App IDs. Values are true for SYSTEM permission and false for NETWORK permission.
|
// Keys are App IDs. Values are true for SYSTEM permission and false for NETWORK permission.
|
||||||
private final Map<Integer, Boolean> mApps = new HashMap<>();
|
private final Map<Integer, Boolean> mApps = new HashMap<>();
|
||||||
|
|
||||||
|
// Keys are App packageNames, Values are app uids. . We need to keep track of this information
|
||||||
|
// because PackageListObserver#onPackageRemoved does not pass the UID.
|
||||||
|
@GuardedBy("mPackageNameUidMap")
|
||||||
|
private final Map<String, Integer> mPackageNameUidMap = new HashMap<>();
|
||||||
|
|
||||||
|
private class PackageListObserver implements PackageManagerInternal.PackageListObserver {
|
||||||
|
@Override
|
||||||
|
public void onPackageAdded(String packageName) {
|
||||||
|
final PackageInfo app = getPackageInfo(packageName);
|
||||||
|
if (app == null) {
|
||||||
|
Slog.wtf(TAG, "Failed to get information of installed package: " + packageName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int uid = (app.applicationInfo != null) ? app.applicationInfo.uid : INVALID_UID;
|
||||||
|
if (uid == INVALID_UID) {
|
||||||
|
Slog.wtf(TAG, "Failed to get the uid of installed package: " + packageName
|
||||||
|
+ "uid: " + uid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (app.requestedPermissions == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendPackagePermissionsForUid(uid,
|
||||||
|
filterPermission(Arrays.asList(app.requestedPermissions)));
|
||||||
|
synchronized (mPackageNameUidMap) {
|
||||||
|
mPackageNameUidMap.put(packageName, uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPackageRemoved(String packageName) {
|
||||||
|
int uid;
|
||||||
|
synchronized (mPackageNameUidMap) {
|
||||||
|
if (!mPackageNameUidMap.containsKey(packageName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uid = mPackageNameUidMap.get(packageName);
|
||||||
|
mPackageNameUidMap.remove(packageName);
|
||||||
|
}
|
||||||
|
int permission = 0;
|
||||||
|
String[] packages = mPackageManager.getPackagesForUid(uid);
|
||||||
|
if (packages != null && packages.length > 0) {
|
||||||
|
for (String name : packages) {
|
||||||
|
final PackageInfo app = getPackageInfo(name);
|
||||||
|
if (app != null && app.requestedPermissions != null) {
|
||||||
|
permission |= filterPermission(Arrays.asList(app.requestedPermissions));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sendPackagePermissionsForUid(uid, permission);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public PermissionMonitor(Context context, INetworkManagementService netd) {
|
public PermissionMonitor(Context context, INetworkManagementService netd) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mPackageManager = context.getPackageManager();
|
mPackageManager = context.getPackageManager();
|
||||||
@@ -87,12 +149,21 @@ public class PermissionMonitor {
|
|||||||
public synchronized void startMonitoring() {
|
public synchronized void startMonitoring() {
|
||||||
log("Monitoring");
|
log("Monitoring");
|
||||||
|
|
||||||
List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS);
|
PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
|
||||||
|
if (pmi != null) {
|
||||||
|
pmi.getPackageList(new PackageListObserver());
|
||||||
|
} else {
|
||||||
|
loge("failed to get the PackageManagerInternal service");
|
||||||
|
}
|
||||||
|
List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS
|
||||||
|
| MATCH_ANY_USER);
|
||||||
if (apps == null) {
|
if (apps == null) {
|
||||||
loge("No apps");
|
loge("No apps");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SparseIntArray netdPermsUids = new SparseIntArray();
|
||||||
|
|
||||||
for (PackageInfo app : apps) {
|
for (PackageInfo app : apps) {
|
||||||
int uid = app.applicationInfo != null ? app.applicationInfo.uid : INVALID_UID;
|
int uid = app.applicationInfo != null ? app.applicationInfo.uid : INVALID_UID;
|
||||||
if (uid < 0) {
|
if (uid < 0) {
|
||||||
@@ -110,6 +181,17 @@ public class PermissionMonitor {
|
|||||||
mApps.put(uid, hasRestrictedPermission);
|
mApps.put(uid, hasRestrictedPermission);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: unify the management of the permissions into one codepath.
|
||||||
|
if (app.requestedPermissions != null) {
|
||||||
|
int otherNetdPerms = filterPermission(Arrays.asList(app.requestedPermissions));
|
||||||
|
if (otherNetdPerms != 0) {
|
||||||
|
netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms);
|
||||||
|
synchronized (mPackageNameUidMap) {
|
||||||
|
mPackageNameUidMap.put(app.applicationInfo.packageName, uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<UserInfo> users = mUserManager.getUsers(true); // exclude dying users
|
List<UserInfo> users = mUserManager.getUsers(true); // exclude dying users
|
||||||
@@ -121,6 +203,7 @@ public class PermissionMonitor {
|
|||||||
|
|
||||||
log("Users: " + mUsers.size() + ", Apps: " + mApps.size());
|
log("Users: " + mUsers.size() + ", Apps: " + mApps.size());
|
||||||
update(mUsers, mApps, true);
|
update(mUsers, mApps, true);
|
||||||
|
sendPackagePermissionsToNetd(netdPermsUids);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -339,6 +422,107 @@ public class PermissionMonitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int filterPermission(List<String> requestedPermissions) {
|
||||||
|
int permissions = 0;
|
||||||
|
if (requestedPermissions.contains(INTERNET)) {
|
||||||
|
permissions |= INetd.PERMISSION_INTERNET;
|
||||||
|
}
|
||||||
|
if (requestedPermissions.contains(UPDATE_DEVICE_STATS)) {
|
||||||
|
permissions |= INetd.PERMISSION_UPDATE_DEVICE_STATS;
|
||||||
|
}
|
||||||
|
return permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PackageInfo getPackageInfo(String packageName) {
|
||||||
|
try {
|
||||||
|
PackageInfo app = mPackageManager.getPackageInfo(packageName, GET_PERMISSIONS
|
||||||
|
| MATCH_ANY_USER);
|
||||||
|
return app;
|
||||||
|
} catch (NameNotFoundException e) {
|
||||||
|
// App not found.
|
||||||
|
loge("NameNotFoundException " + packageName);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by PackageListObserver when a package is installed/uninstalled. Send the updated
|
||||||
|
* permission information to netd.
|
||||||
|
*
|
||||||
|
* @param uid the app uid of the package installed
|
||||||
|
* @param permissions the permissions the app requested and netd cares about.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
private void sendPackagePermissionsForUid(int uid, int permissions) {
|
||||||
|
SparseIntArray netdPermissionsAppIds = new SparseIntArray();
|
||||||
|
netdPermissionsAppIds.put(uid, permissions);
|
||||||
|
sendPackagePermissionsToNetd(netdPermissionsAppIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by packageManagerService to send IPC to netd. Grant or revoke the INTERNET
|
||||||
|
* and/or UPDATE_DEVICE_STATS permission of the uids in array.
|
||||||
|
*
|
||||||
|
* @param netdPermissionsAppIds integer pairs of uids and the permission granted to it. If the
|
||||||
|
* permission is 0, revoke all permissions of that uid.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
private void sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds) {
|
||||||
|
INetd netdService = NetdService.getInstance();
|
||||||
|
if (netdService == null) {
|
||||||
|
Log.e(TAG, "Failed to get the netd service");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ArrayList<Integer> allPermissionAppIds = new ArrayList<>();
|
||||||
|
ArrayList<Integer> internetPermissionAppIds = new ArrayList<>();
|
||||||
|
ArrayList<Integer> updateStatsPermissionAppIds = new ArrayList<>();
|
||||||
|
ArrayList<Integer> uninstalledAppIds = new ArrayList<>();
|
||||||
|
for (int i = 0; i < netdPermissionsAppIds.size(); i++) {
|
||||||
|
int permissions = netdPermissionsAppIds.valueAt(i);
|
||||||
|
switch(permissions) {
|
||||||
|
case (INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS):
|
||||||
|
allPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
|
||||||
|
break;
|
||||||
|
case INetd.PERMISSION_INTERNET:
|
||||||
|
internetPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
|
||||||
|
break;
|
||||||
|
case INetd.PERMISSION_UPDATE_DEVICE_STATS:
|
||||||
|
updateStatsPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
|
||||||
|
break;
|
||||||
|
case INetd.NO_PERMISSIONS:
|
||||||
|
uninstalledAppIds.add(netdPermissionsAppIds.keyAt(i));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.e(TAG, "unknown permission type: " + permissions + "for uid: "
|
||||||
|
+ netdPermissionsAppIds.keyAt(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// TODO: add a lock inside netd to protect IPC trafficSetNetPermForUids()
|
||||||
|
if (allPermissionAppIds.size() != 0) {
|
||||||
|
netdService.trafficSetNetPermForUids(
|
||||||
|
INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
|
||||||
|
ArrayUtils.convertToIntArray(allPermissionAppIds));
|
||||||
|
}
|
||||||
|
if (internetPermissionAppIds.size() != 0) {
|
||||||
|
netdService.trafficSetNetPermForUids(INetd.PERMISSION_INTERNET,
|
||||||
|
ArrayUtils.convertToIntArray(internetPermissionAppIds));
|
||||||
|
}
|
||||||
|
if (updateStatsPermissionAppIds.size() != 0) {
|
||||||
|
netdService.trafficSetNetPermForUids(INetd.PERMISSION_UPDATE_DEVICE_STATS,
|
||||||
|
ArrayUtils.convertToIntArray(updateStatsPermissionAppIds));
|
||||||
|
}
|
||||||
|
if (uninstalledAppIds.size() != 0) {
|
||||||
|
netdService.trafficSetNetPermForUids(INetd.NO_PERMISSIONS,
|
||||||
|
ArrayUtils.convertToIntArray(uninstalledAppIds));
|
||||||
|
}
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, "Pass appId list of special permission failed." + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void log(String s) {
|
private static void log(String s) {
|
||||||
if (DBG) {
|
if (DBG) {
|
||||||
Log.d(TAG, s);
|
Log.d(TAG, s);
|
||||||
|
|||||||
Reference in New Issue
Block a user