PermissionMonitorpublic class PermissionMonitor extends Object A utility class to inform Netd of UID permisisons.
Does a mass update at boot and then monitors for app install/remove. |
Fields Summary |
---|
private static final String | TAG | private static final boolean | DBG | private static final boolean | SYSTEM | private static final boolean | NETWORK | private final android.content.Context | mContext | private final android.content.pm.PackageManager | mPackageManager | private final android.os.UserManager | mUserManager | private final android.os.INetworkManagementService | mNetd | private final android.content.BroadcastReceiver | mIntentReceiver | private final Set | mUsers | private final Map | mApps |
Constructors Summary |
---|
public PermissionMonitor(android.content.Context context, android.os.INetworkManagementService netd)
mContext = context;
mPackageManager = context.getPackageManager();
mUserManager = UserManager.get(context);
mNetd = netd;
mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
int appUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
Uri appData = intent.getData();
String appName = appData != null ? appData.getSchemeSpecificPart() : null;
if (Intent.ACTION_USER_ADDED.equals(action)) {
onUserAdded(user);
} else if (Intent.ACTION_USER_REMOVED.equals(action)) {
onUserRemoved(user);
} else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
onAppAdded(appName, appUid);
} else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
onAppRemoved(appUid);
}
}
};
|
Methods Summary |
---|
private boolean | hasNetworkPermission(android.content.pm.PackageInfo app)
return hasPermission(app, CHANGE_NETWORK_STATE);
| private boolean | hasPermission(android.content.pm.PackageInfo app, java.lang.String permission)
if (app.requestedPermissions != null) {
for (String p : app.requestedPermissions) {
if (permission.equals(p)) {
return true;
}
}
}
return false;
| private boolean | hasSystemPermission(android.content.pm.PackageInfo app)
int flags = app.applicationInfo != null ? app.applicationInfo.flags : 0;
if ((flags & FLAG_SYSTEM) != 0 || (flags & FLAG_UPDATED_SYSTEM_APP) != 0) {
return true;
}
return hasPermission(app, CONNECTIVITY_INTERNAL);
| private static void | log(java.lang.String s)
if (DBG) {
Log.d(TAG, s);
}
| private static void | loge(java.lang.String s)
Log.e(TAG, s);
| private synchronized void | onAppAdded(java.lang.String appName, int appUid)
if (TextUtils.isEmpty(appName) || appUid < 0) {
loge("Invalid app in onAppAdded: " + appName + " | " + appUid);
return;
}
try {
PackageInfo app = mPackageManager.getPackageInfo(appName, GET_PERMISSIONS);
boolean isNetwork = hasNetworkPermission(app);
boolean isSystem = hasSystemPermission(app);
if (isNetwork || isSystem) {
Boolean permission = mApps.get(appUid);
// If multiple packages share a UID (cf: android:sharedUserId) and ask for different
// permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
if (permission == null || permission == NETWORK) {
mApps.put(appUid, isSystem);
Map<Integer, Boolean> apps = new HashMap<Integer, Boolean>();
apps.put(appUid, isSystem);
update(mUsers, apps, true);
}
}
} catch (NameNotFoundException e) {
loge("NameNotFoundException in onAppAdded: " + e);
}
| private synchronized void | onAppRemoved(int appUid)
if (appUid < 0) {
loge("Invalid app in onAppRemoved: " + appUid);
return;
}
mApps.remove(appUid);
Map<Integer, Boolean> apps = new HashMap<Integer, Boolean>();
apps.put(appUid, NETWORK); // doesn't matter which permission we pick here
update(mUsers, apps, false);
| private synchronized void | onUserAdded(int user)
if (user < 0) {
loge("Invalid user in onUserAdded: " + user);
return;
}
mUsers.add(user);
Set<Integer> users = new HashSet<Integer>();
users.add(user);
update(users, mApps, true);
| private synchronized void | onUserRemoved(int user)
if (user < 0) {
loge("Invalid user in onUserRemoved: " + user);
return;
}
mUsers.remove(user);
Set<Integer> users = new HashSet<Integer>();
users.add(user);
update(users, mApps, false);
| public synchronized void | startMonitoring()
log("Monitoring");
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_USER_ADDED);
intentFilter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, intentFilter, null, null);
intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
intentFilter.addDataScheme("package");
mContext.registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, intentFilter, null, null);
List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS);
if (apps == null) {
loge("No apps");
return;
}
for (PackageInfo app : apps) {
int uid = app.applicationInfo != null ? app.applicationInfo.uid : -1;
if (uid < 0) {
continue;
}
boolean isNetwork = hasNetworkPermission(app);
boolean isSystem = hasSystemPermission(app);
if (isNetwork || isSystem) {
Boolean permission = mApps.get(uid);
// If multiple packages share a UID (cf: android:sharedUserId) and ask for different
// permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
if (permission == null || permission == NETWORK) {
mApps.put(uid, isSystem);
}
}
}
List<UserInfo> users = mUserManager.getUsers(true); // exclude dying users
if (users != null) {
for (UserInfo user : users) {
mUsers.add(user.id);
}
}
log("Users: " + mUsers.size() + ", Apps: " + mApps.size());
update(mUsers, mApps, true);
| private int[] | toIntArray(java.util.List list)
int[] array = new int[list.size()];
for (int i = 0; i < list.size(); i++) {
array[i] = list.get(i);
}
return array;
| private void | update(java.util.Set users, java.util.Map apps, boolean add)
List<Integer> network = new ArrayList<Integer>();
List<Integer> system = new ArrayList<Integer>();
for (Entry<Integer, Boolean> app : apps.entrySet()) {
List<Integer> list = app.getValue() ? system : network;
for (int user : users) {
list.add(UserHandle.getUid(user, app.getKey()));
}
}
try {
if (add) {
mNetd.setPermission("NETWORK", toIntArray(network));
mNetd.setPermission("SYSTEM", toIntArray(system));
} else {
mNetd.clearPermission(toIntArray(network));
mNetd.clearPermission(toIntArray(system));
}
} catch (RemoteException e) {
loge("Exception when updating permissions: " + e);
}
|
|