OSDN Git Service

[automerger skipped] resolve merge conflicts of 88c651eab144bf64acb1d99f11aabe983f236...
[android-x86/frameworks-base.git] / services / core / java / com / android / server / connectivity / PermissionMonitor.java
1 /*
2  * Copyright (C) 2014 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.server.connectivity;
18
19 import static android.Manifest.permission.CHANGE_NETWORK_STATE;
20 import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
21 import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
22 import static android.Manifest.permission.NETWORK_STACK;
23 import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
24 import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
25 import static android.content.pm.PackageManager.GET_PERMISSIONS;
26
27 import android.content.BroadcastReceiver;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.content.IntentFilter;
31 import android.content.pm.ApplicationInfo;
32 import android.content.pm.PackageInfo;
33 import android.content.pm.PackageManager;
34 import android.content.pm.PackageManager.NameNotFoundException;
35 import android.content.pm.UserInfo;
36 import android.net.Uri;
37 import android.os.INetworkManagementService;
38 import android.os.RemoteException;
39 import android.os.UserHandle;
40 import android.os.UserManager;
41 import android.text.TextUtils;
42 import android.util.Log;
43
44 import com.android.internal.annotations.VisibleForTesting;
45
46 import java.util.ArrayList;
47 import java.util.HashMap;
48 import java.util.HashSet;
49 import java.util.List;
50 import java.util.Map.Entry;
51 import java.util.Map;
52 import java.util.Set;
53
54 /**
55  * A utility class to inform Netd of UID permisisons.
56  * Does a mass update at boot and then monitors for app install/remove.
57  *
58  * @hide
59  */
60 public class PermissionMonitor {
61     private static final String TAG = "PermissionMonitor";
62     private static final boolean DBG = true;
63     private static final Boolean SYSTEM = Boolean.TRUE;
64     private static final Boolean NETWORK = Boolean.FALSE;
65
66     private final Context mContext;
67     private final PackageManager mPackageManager;
68     private final UserManager mUserManager;
69     private final INetworkManagementService mNetd;
70     private final BroadcastReceiver mIntentReceiver;
71
72     // Values are User IDs.
73     private final Set<Integer> mUsers = new HashSet<>();
74
75     // Keys are App IDs. Values are true for SYSTEM permission and false for NETWORK permission.
76     private final Map<Integer, Boolean> mApps = new HashMap<>();
77
78     public PermissionMonitor(Context context, INetworkManagementService netd) {
79         mContext = context;
80         mPackageManager = context.getPackageManager();
81         mUserManager = UserManager.get(context);
82         mNetd = netd;
83         mIntentReceiver = new BroadcastReceiver() {
84             @Override
85             public void onReceive(Context context, Intent intent) {
86                 String action = intent.getAction();
87                 int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
88                 int appUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
89                 Uri appData = intent.getData();
90                 String appName = appData != null ? appData.getSchemeSpecificPart() : null;
91
92                 if (Intent.ACTION_USER_ADDED.equals(action)) {
93                     onUserAdded(user);
94                 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
95                     onUserRemoved(user);
96                 } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
97                     onAppAdded(appName, appUid);
98                 } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
99                     onAppRemoved(appUid);
100                 }
101             }
102         };
103     }
104
105     // Intended to be called only once at startup, after the system is ready. Installs a broadcast
106     // receiver to monitor ongoing UID changes, so this shouldn't/needn't be called again.
107     public synchronized void startMonitoring() {
108         log("Monitoring");
109
110         IntentFilter intentFilter = new IntentFilter();
111         intentFilter.addAction(Intent.ACTION_USER_ADDED);
112         intentFilter.addAction(Intent.ACTION_USER_REMOVED);
113         mContext.registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, intentFilter, null, null);
114
115         intentFilter = new IntentFilter();
116         intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
117         intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
118         intentFilter.addDataScheme("package");
119         mContext.registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, intentFilter, null, null);
120
121         List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS);
122         if (apps == null) {
123             loge("No apps");
124             return;
125         }
126
127         for (PackageInfo app : apps) {
128             int uid = app.applicationInfo != null ? app.applicationInfo.uid : -1;
129             if (uid < 0) {
130                 continue;
131             }
132
133             boolean isNetwork = hasNetworkPermission(app);
134             boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
135
136             if (isNetwork || hasRestrictedPermission) {
137                 Boolean permission = mApps.get(uid);
138                 // If multiple packages share a UID (cf: android:sharedUserId) and ask for different
139                 // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
140                 if (permission == null || permission == NETWORK) {
141                     mApps.put(uid, hasRestrictedPermission);
142                 }
143             }
144         }
145
146         List<UserInfo> users = mUserManager.getUsers(true);  // exclude dying users
147         if (users != null) {
148             for (UserInfo user : users) {
149                 mUsers.add(user.id);
150             }
151         }
152
153         log("Users: " + mUsers.size() + ", Apps: " + mApps.size());
154         update(mUsers, mApps, true);
155     }
156
157     @VisibleForTesting
158     boolean isPreinstalledSystemApp(PackageInfo app) {
159         int flags = app.applicationInfo != null ? app.applicationInfo.flags : 0;
160         return (flags & (FLAG_SYSTEM | FLAG_UPDATED_SYSTEM_APP)) != 0;
161     }
162
163     @VisibleForTesting
164     boolean hasPermission(PackageInfo app, String permission) {
165         if (app.requestedPermissions != null) {
166             for (String p : app.requestedPermissions) {
167                 if (permission.equals(p)) {
168                     return true;
169                 }
170             }
171         }
172         return false;
173     }
174
175     private boolean hasNetworkPermission(PackageInfo app) {
176         return hasPermission(app, CHANGE_NETWORK_STATE);
177     }
178
179     private boolean hasRestrictedNetworkPermission(PackageInfo app) {
180         if (isPreinstalledSystemApp(app)) return true;
181         return hasPermission(app, CONNECTIVITY_INTERNAL)
182                 || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
183     }
184
185     private boolean hasUseBackgroundNetworksPermission(PackageInfo app) {
186         // This function defines what it means to hold the permission to use
187         // background networks.
188         return hasPermission(app, CHANGE_NETWORK_STATE)
189                 || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS)
190                 || hasPermission(app, CONNECTIVITY_INTERNAL)
191                 || hasPermission(app, NETWORK_STACK)
192                 // TODO : remove this check (b/31479477). Not all preinstalled apps should
193                 // have access to background networks, they should just request the appropriate
194                 // permission for their use case from the list above.
195                 || isPreinstalledSystemApp(app);
196     }
197
198     public boolean hasUseBackgroundNetworksPermission(int uid) {
199         final String[] names = mPackageManager.getPackagesForUid(uid);
200         if (null == names || names.length == 0) return false;
201         try {
202             // Only using the first package name. There may be multiple names if multiple
203             // apps share the same UID, but in that case they also share permissions so
204             // querying with any of the names will return the same results.
205             int userId = UserHandle.getUserId(uid);
206             final PackageInfo app = mPackageManager.getPackageInfoAsUser(
207                     names[0], GET_PERMISSIONS, userId);
208             return hasUseBackgroundNetworksPermission(app);
209         } catch (NameNotFoundException e) {
210             // App not found.
211             loge("NameNotFoundException " + names[0], e);
212             return false;
213         }
214     }
215
216     private int[] toIntArray(List<Integer> list) {
217         int[] array = new int[list.size()];
218         for (int i = 0; i < list.size(); i++) {
219             array[i] = list.get(i);
220         }
221         return array;
222     }
223
224     private void update(Set<Integer> users, Map<Integer, Boolean> apps, boolean add) {
225         List<Integer> network = new ArrayList<>();
226         List<Integer> system = new ArrayList<>();
227         for (Entry<Integer, Boolean> app : apps.entrySet()) {
228             List<Integer> list = app.getValue() ? system : network;
229             for (int user : users) {
230                 list.add(UserHandle.getUid(user, app.getKey()));
231             }
232         }
233         try {
234             if (add) {
235                 mNetd.setPermission("NETWORK", toIntArray(network));
236                 mNetd.setPermission("SYSTEM", toIntArray(system));
237             } else {
238                 mNetd.clearPermission(toIntArray(network));
239                 mNetd.clearPermission(toIntArray(system));
240             }
241         } catch (RemoteException e) {
242             loge("Exception when updating permissions: " + e);
243         }
244     }
245
246     private synchronized void onUserAdded(int user) {
247         if (user < 0) {
248             loge("Invalid user in onUserAdded: " + user);
249             return;
250         }
251         mUsers.add(user);
252
253         Set<Integer> users = new HashSet<>();
254         users.add(user);
255         update(users, mApps, true);
256     }
257
258     private synchronized void onUserRemoved(int user) {
259         if (user < 0) {
260             loge("Invalid user in onUserRemoved: " + user);
261             return;
262         }
263         mUsers.remove(user);
264
265         Set<Integer> users = new HashSet<>();
266         users.add(user);
267         update(users, mApps, false);
268     }
269
270
271     private Boolean highestPermissionForUid(Boolean currentPermission, String name) {
272         if (currentPermission == SYSTEM) {
273             return currentPermission;
274         }
275         try {
276             final PackageInfo app = mPackageManager.getPackageInfo(name, GET_PERMISSIONS);
277             final boolean isNetwork = hasNetworkPermission(app);
278             final boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
279             if (isNetwork || hasRestrictedPermission) {
280                 currentPermission = hasRestrictedPermission;
281             }
282         } catch (NameNotFoundException e) {
283             // App not found.
284             loge("NameNotFoundException " + name);
285         }
286         return currentPermission;
287     }
288
289     private synchronized void onAppAdded(String appName, int appUid) {
290         if (TextUtils.isEmpty(appName) || appUid < 0) {
291             loge("Invalid app in onAppAdded: " + appName + " | " + appUid);
292             return;
293         }
294
295         // If multiple packages share a UID (cf: android:sharedUserId) and ask for different
296         // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
297         final Boolean permission = highestPermissionForUid(mApps.get(appUid), appName);
298         if (permission != mApps.get(appUid)) {
299             mApps.put(appUid, permission);
300
301             Map<Integer, Boolean> apps = new HashMap<>();
302             apps.put(appUid, permission);
303             update(mUsers, apps, true);
304         }
305     }
306
307     private synchronized void onAppRemoved(int appUid) {
308         if (appUid < 0) {
309             loge("Invalid app in onAppRemoved: " + appUid);
310             return;
311         }
312         Map<Integer, Boolean> apps = new HashMap<>();
313
314         Boolean permission = null;
315         String[] packages = mPackageManager.getPackagesForUid(appUid);
316         if (packages != null && packages.length > 0) {
317             for (String name : packages) {
318                 permission = highestPermissionForUid(permission, name);
319                 if (permission == SYSTEM) {
320                     // An app with this UID still has the SYSTEM permission.
321                     // Therefore, this UID must already have the SYSTEM permission.
322                     // Nothing to do.
323                     return;
324                 }
325             }
326         }
327         if (permission == mApps.get(appUid)) {
328             // The permissions of this UID have not changed. Nothing to do.
329             return;
330         } else if (permission != null) {
331             mApps.put(appUid, permission);
332             apps.put(appUid, permission);
333             update(mUsers, apps, true);
334         } else {
335             mApps.remove(appUid);
336             apps.put(appUid, NETWORK);  // doesn't matter which permission we pick here
337             update(mUsers, apps, false);
338         }
339     }
340
341     private static void log(String s) {
342         if (DBG) {
343             Log.d(TAG, s);
344         }
345     }
346
347     private static void loge(String s) {
348         Log.e(TAG, s);
349     }
350
351     private static void loge(String s, Throwable e) {
352         Log.e(TAG, s, e);
353     }
354 }