blob: 37e6ae98cb0a1274772c183ed23c55f0af5d32f6 [file] [log] [blame]
John Spurlock7340fc82014-04-24 18:50:12 -04001/**
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
17package com.android.server.notification;
18
Felipe Lemea1b79bf2016-05-24 13:06:54 -070019import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT;
20import static android.content.Context.BIND_AUTO_CREATE;
21import static android.content.Context.BIND_FOREGROUND_SERVICE;
Esteban Talavera9c6458d2017-03-30 17:59:50 +010022import static android.content.Context.DEVICE_POLICY_SERVICE;
Felipe Lemea1b79bf2016-05-24 13:06:54 -070023
Ruben Brunke24b9a62016-02-16 21:38:24 -080024import android.annotation.NonNull;
John Spurlock7340fc82014-04-24 18:50:12 -040025import android.app.ActivityManager;
26import android.app.PendingIntent;
Esteban Talavera9c6458d2017-03-30 17:59:50 +010027import android.app.admin.DevicePolicyManager;
John Spurlock7340fc82014-04-24 18:50:12 -040028import android.content.ComponentName;
29import android.content.ContentResolver;
30import android.content.Context;
31import android.content.Intent;
32import android.content.ServiceConnection;
33import android.content.pm.ApplicationInfo;
Julia Reynoldsa75c7522017-03-21 17:34:25 -040034import android.content.pm.IPackageManager;
John Spurlock7340fc82014-04-24 18:50:12 -040035import android.content.pm.PackageManager;
36import android.content.pm.PackageManager.NameNotFoundException;
37import android.content.pm.ResolveInfo;
38import android.content.pm.ServiceInfo;
39import android.content.pm.UserInfo;
Esteban Talavera9c6458d2017-03-30 17:59:50 +010040import android.os.Binder;
John Spurlock7340fc82014-04-24 18:50:12 -040041import android.os.Build;
Ryan Lothian4a86a512017-12-04 11:56:58 -050042import android.os.Handler;
John Spurlock7340fc82014-04-24 18:50:12 -040043import android.os.IBinder;
44import android.os.IInterface;
Ryan Lothian4a86a512017-12-04 11:56:58 -050045import android.os.Looper;
John Spurlock7340fc82014-04-24 18:50:12 -040046import android.os.RemoteException;
47import android.os.UserHandle;
48import android.os.UserManager;
49import android.provider.Settings;
Kweku Adams93304b62017-09-20 17:03:00 -070050import android.service.notification.ManagedServiceInfoProto;
51import android.service.notification.ManagedServicesProto;
52import android.service.notification.ManagedServicesProto.ServiceProto;
John Spurlock7340fc82014-04-24 18:50:12 -040053import android.text.TextUtils;
Julia Reynoldsb852e562017-06-06 16:14:18 -040054import android.util.ArrayMap;
John Spurlock7340fc82014-04-24 18:50:12 -040055import android.util.ArraySet;
John Spurlock4db0d982014-08-13 09:19:03 -040056import android.util.Log;
John Spurlock7340fc82014-04-24 18:50:12 -040057import android.util.Slog;
58import android.util.SparseArray;
Kweku Adams93304b62017-09-20 17:03:00 -070059import android.util.proto.ProtoOutputStream;
John Spurlock7340fc82014-04-24 18:50:12 -040060
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -040061import com.android.internal.util.XmlUtils;
John Spurlock25e2d242014-06-27 13:58:23 -040062import com.android.server.notification.NotificationManagerService.DumpFilter;
63
Julia Reynoldsb852e562017-06-06 16:14:18 -040064import org.xmlpull.v1.XmlPullParser;
65import org.xmlpull.v1.XmlPullParserException;
66import org.xmlpull.v1.XmlSerializer;
67
68import java.io.IOException;
John Spurlock7340fc82014-04-24 18:50:12 -040069import java.io.PrintWriter;
70import java.util.ArrayList;
John Spurlocke77bb362014-04-26 10:24:59 -040071import java.util.Arrays;
Julia Reynolds9a86cc02016-02-10 15:38:15 -050072import java.util.HashSet;
John Spurlock7340fc82014-04-24 18:50:12 -040073import java.util.List;
74import java.util.Set;
Julia Reynoldsb852e562017-06-06 16:14:18 -040075import java.util.stream.Collectors;
John Spurlock7340fc82014-04-24 18:50:12 -040076
77/**
78 * Manages the lifecycle of application-provided services bound by system server.
79 *
80 * Services managed by this helper must have:
81 * - An associated system settings value with a list of enabled component names.
82 * - A well-known action for services to use in their intent-filter.
83 * - A system permission for services to require in order to ensure system has exclusive binding.
84 * - A settings page for user configuration of enabled services, and associated intent action.
85 * - A remote interface definition (aidl) provided by the service used for communication.
86 */
87abstract public class ManagedServices {
88 protected final String TAG = getClass().getSimpleName();
John Spurlock4db0d982014-08-13 09:19:03 -040089 protected final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
John Spurlock7340fc82014-04-24 18:50:12 -040090
Ryan Lothian4a86a512017-12-04 11:56:58 -050091 private static final int ON_BINDING_DIED_REBIND_DELAY_MS = 10000;
Julia Reynoldsc279b992015-10-30 08:23:51 -040092 protected static final String ENABLED_SERVICES_SEPARATOR = ":";
John Spurlock7340fc82014-04-24 18:50:12 -040093
Julia Reynoldsb852e562017-06-06 16:14:18 -040094 /**
95 * List of components and apps that can have running {@link ManagedServices}.
96 */
97 static final String TAG_MANAGED_SERVICES = "service_listing";
98 static final String ATT_APPROVED_LIST = "approved";
99 static final String ATT_USER_ID = "user";
100 static final String ATT_IS_PRIMARY = "primary";
101
102 static final int APPROVAL_BY_PACKAGE = 0;
103 static final int APPROVAL_BY_COMPONENT = 1;
104
John Spurlockaf8d6c42014-05-07 17:49:08 -0400105 protected final Context mContext;
John Spurlocke77bb362014-04-26 10:24:59 -0400106 protected final Object mMutex;
John Spurlock7340fc82014-04-24 18:50:12 -0400107 private final UserProfiles mUserProfiles;
Julia Reynoldsa75c7522017-03-21 17:34:25 -0400108 private final IPackageManager mPm;
Julia Reynolds45523002017-09-12 09:43:57 -0400109 private final UserManager mUm;
John Spurlock7340fc82014-04-24 18:50:12 -0400110 private final Config mConfig;
Ryan Lothian4a86a512017-12-04 11:56:58 -0500111 private final Handler mHandler = new Handler(Looper.getMainLooper());
John Spurlock7340fc82014-04-24 18:50:12 -0400112
113 // contains connections to all connected services, including app services
114 // and system services
Julia Reynoldsb852e562017-06-06 16:14:18 -0400115 private final ArrayList<ManagedServiceInfo> mServices = new ArrayList<>();
John Spurlock7340fc82014-04-24 18:50:12 -0400116 // things that will be put into mServices as soon as they're ready
Julia Reynoldsb852e562017-06-06 16:14:18 -0400117 private final ArrayList<String> mServicesBinding = new ArrayList<>();
Ryan Lothian4a86a512017-12-04 11:56:58 -0500118 private final ArraySet<String> mServicesRebinding = new ArraySet<>();
119
Chris Wrenab41eec2016-01-04 18:01:27 -0500120 // lists the component names of all enabled (and therefore potentially connected)
John Spurlock7340fc82014-04-24 18:50:12 -0400121 // app services for current profiles.
122 private ArraySet<ComponentName> mEnabledServicesForCurrentProfiles
Julia Reynoldsb852e562017-06-06 16:14:18 -0400123 = new ArraySet<>();
John Spurlock7340fc82014-04-24 18:50:12 -0400124 // Just the packages from mEnabledServicesForCurrentProfiles
Julia Reynoldsb852e562017-06-06 16:14:18 -0400125 private ArraySet<String> mEnabledServicesPackageNames = new ArraySet<>();
Chris Wrenab41eec2016-01-04 18:01:27 -0500126 // List of enabled packages that have nevertheless asked not to be run
127 private ArraySet<ComponentName> mSnoozingForCurrentProfiles = new ArraySet<>();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200128
Julia Reynoldsb852e562017-06-06 16:14:18 -0400129 // List of approved packages or components (by user, then by primary/secondary) that are
130 // allowed to be bound as managed services. A package or component appearing in this list does
131 // not mean that we are currently bound to said package/component.
132 private ArrayMap<Integer, ArrayMap<Boolean, ArraySet<String>>> mApproved = new ArrayMap<>();
John Spurlock7340fc82014-04-24 18:50:12 -0400133
Christoph Studerb53dfd42014-09-12 14:45:59 +0200134 // Kept to de-dupe user change events (experienced after boot, when we receive a settings and a
135 // user change).
136 private int[] mLastSeenProfileIds;
137
Julia Reynoldsb852e562017-06-06 16:14:18 -0400138 // True if approved services are stored in xml, not settings.
139 private boolean mUseXml;
Christopher Tate6597e342015-02-17 12:15:25 -0800140
Julia Reynoldsb852e562017-06-06 16:14:18 -0400141 // Whether managed services are approved individually or package wide
142 protected int mApprovalLevel;
143
144 public ManagedServices(Context context, Object mutex, UserProfiles userProfiles,
145 IPackageManager pm) {
John Spurlock7340fc82014-04-24 18:50:12 -0400146 mContext = context;
147 mMutex = mutex;
148 mUserProfiles = userProfiles;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400149 mPm = pm;
John Spurlock7340fc82014-04-24 18:50:12 -0400150 mConfig = getConfig();
Julia Reynoldsb852e562017-06-06 16:14:18 -0400151 mApprovalLevel = APPROVAL_BY_COMPONENT;
Julia Reynolds45523002017-09-12 09:43:57 -0400152 mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
John Spurlock7340fc82014-04-24 18:50:12 -0400153 }
154
155 abstract protected Config getConfig();
156
157 private String getCaption() {
158 return mConfig.caption;
159 }
160
161 abstract protected IInterface asInterface(IBinder binder);
162
Chris Wren51017d02015-12-15 15:34:46 -0500163 abstract protected boolean checkType(IInterface service);
164
John Spurlock3b98b3f2014-05-01 09:08:48 -0400165 abstract protected void onServiceAdded(ManagedServiceInfo info);
John Spurlock7340fc82014-04-24 18:50:12 -0400166
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400167 protected List<ManagedServiceInfo> getServices() {
168 synchronized (mMutex) {
169 List<ManagedServiceInfo> services = new ArrayList<>(mServices);
170 return services;
171 }
172 }
173
John Spurlocke77bb362014-04-26 10:24:59 -0400174 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { }
175
John Spurlock7340fc82014-04-24 18:50:12 -0400176 private ManagedServiceInfo newServiceInfo(IInterface service,
Julia Reynoldsb852e562017-06-06 16:14:18 -0400177 ComponentName component, int userId, boolean isSystem, ServiceConnection connection,
John Spurlock7340fc82014-04-24 18:50:12 -0400178 int targetSdkVersion) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400179 return new ManagedServiceInfo(service, component, userId, isSystem, connection,
John Spurlock7340fc82014-04-24 18:50:12 -0400180 targetSdkVersion);
181 }
182
Julia Reynoldsb852e562017-06-06 16:14:18 -0400183 public void onBootPhaseAppsCanStart() {}
John Spurlock7340fc82014-04-24 18:50:12 -0400184
John Spurlock25e2d242014-06-27 13:58:23 -0400185 public void dump(PrintWriter pw, DumpFilter filter) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400186 pw.println(" Allowed " + getCaption() + "s:");
187 final int N = mApproved.size();
188 for (int i = 0 ; i < N; i++) {
189 final int userId = mApproved.keyAt(i);
190 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
191 if (approvedByType != null) {
192 final int M = approvedByType.size();
193 for (int j = 0; j < M; j++) {
194 final boolean isPrimary = approvedByType.keyAt(j);
195 final ArraySet<String> approved = approvedByType.valueAt(j);
196 if (approvedByType != null && approvedByType.size() > 0) {
197 pw.println(" " + String.join(ENABLED_SERVICES_SEPARATOR, approved)
198 + " (user: " + userId + " isPrimary: " + isPrimary + ")");
199 }
200 }
201 }
202 }
203
John Spurlocke77bb362014-04-26 10:24:59 -0400204 pw.println(" All " + getCaption() + "s (" + mEnabledServicesForCurrentProfiles.size()
John Spurlock7340fc82014-04-24 18:50:12 -0400205 + ") enabled for current profiles:");
206 for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
John Spurlock25e2d242014-06-27 13:58:23 -0400207 if (filter != null && !filter.matches(cmpt)) continue;
John Spurlocke77bb362014-04-26 10:24:59 -0400208 pw.println(" " + cmpt);
John Spurlock7340fc82014-04-24 18:50:12 -0400209 }
210
John Spurlocke77bb362014-04-26 10:24:59 -0400211 pw.println(" Live " + getCaption() + "s (" + mServices.size() + "):");
John Spurlock7340fc82014-04-24 18:50:12 -0400212 for (ManagedServiceInfo info : mServices) {
John Spurlock25e2d242014-06-27 13:58:23 -0400213 if (filter != null && !filter.matches(info.component)) continue;
John Spurlocke77bb362014-04-26 10:24:59 -0400214 pw.println(" " + info.component
John Spurlock7340fc82014-04-24 18:50:12 -0400215 + " (user " + info.userid + "): " + info.service
Chris Wren51017d02015-12-15 15:34:46 -0500216 + (info.isSystem?" SYSTEM":"")
217 + (info.isGuest(this)?" GUEST":""));
John Spurlock7340fc82014-04-24 18:50:12 -0400218 }
Chris Wrenab41eec2016-01-04 18:01:27 -0500219
220 pw.println(" Snoozed " + getCaption() + "s (" +
221 mSnoozingForCurrentProfiles.size() + "):");
222 for (ComponentName name : mSnoozingForCurrentProfiles) {
223 pw.println(" " + name.flattenToShortString());
224 }
John Spurlock7340fc82014-04-24 18:50:12 -0400225 }
226
Kweku Adams93304b62017-09-20 17:03:00 -0700227 public void dump(ProtoOutputStream proto, DumpFilter filter) {
228 proto.write(ManagedServicesProto.CAPTION, getCaption());
229 final int N = mApproved.size();
230 for (int i = 0 ; i < N; i++) {
231 final int userId = mApproved.keyAt(i);
232 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
233 if (approvedByType != null) {
234 final int M = approvedByType.size();
235 for (int j = 0; j < M; j++) {
236 final boolean isPrimary = approvedByType.keyAt(j);
237 final ArraySet<String> approved = approvedByType.valueAt(j);
238 if (approvedByType != null && approvedByType.size() > 0) {
239 final long sToken = proto.start(ManagedServicesProto.APPROVED);
240 for (String s : approved) {
241 proto.write(ServiceProto.NAME, s);
242 }
243 proto.write(ServiceProto.USER_ID, userId);
244 proto.write(ServiceProto.IS_PRIMARY, isPrimary);
245 proto.end(sToken);
246 }
247 }
248 }
249 }
250
251 for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
252 if (filter != null && !filter.matches(cmpt)) continue;
253
Kweku Adams85f2fbc2017-12-18 12:04:12 -0800254 cmpt.writeToProto(proto, ManagedServicesProto.ENABLED);
Kweku Adams93304b62017-09-20 17:03:00 -0700255 }
256
257 for (ManagedServiceInfo info : mServices) {
258 if (filter != null && !filter.matches(info.component)) continue;
259
Kweku Adams85f2fbc2017-12-18 12:04:12 -0800260 info.writeToProto(proto, ManagedServicesProto.LIVE_SERVICES, this);
Kweku Adams93304b62017-09-20 17:03:00 -0700261 }
262
263 for (ComponentName name : mSnoozingForCurrentProfiles) {
Kweku Adams85f2fbc2017-12-18 12:04:12 -0800264 name.writeToProto(proto, ManagedServicesProto.SNOOZED);
Kweku Adams93304b62017-09-20 17:03:00 -0700265 }
266 }
267
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400268 protected void onSettingRestored(String element, String value, int backupSdkInt, int userId) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400269 if (!mUseXml) {
270 Slog.d(TAG, "Restored managed service setting: " + element);
271 if (mConfig.secureSettingName.equals(element) ||
272 (mConfig.secondarySettingName != null
273 && mConfig.secondarySettingName.equals(element))) {
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400274 if (backupSdkInt < Build.VERSION_CODES.O) {
275 // automatic system grants were added in O, so append the approved apps
276 // rather than wiping out the setting
277 String currentSetting =
278 getApproved(userId, mConfig.secureSettingName.equals(element));
279 if (!TextUtils.isEmpty(currentSetting)) {
280 if (!TextUtils.isEmpty(value)) {
281 value = value + ENABLED_SERVICES_SEPARATOR + currentSetting;
282 } else {
283 value = currentSetting;
284 }
285 }
286 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400287 Settings.Secure.putStringForUser(
288 mContext.getContentResolver(), element, value, userId);
289 loadAllowedComponentsFromSettings();
290 rebindServices(false);
Christopher Tate6597e342015-02-17 12:15:25 -0800291 }
292 }
293 }
294
Julia Reynoldsb852e562017-06-06 16:14:18 -0400295 public void writeXml(XmlSerializer out, boolean forBackup) throws IOException {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400296 out.startTag(null, getConfig().xmlTag);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400297
298 if (forBackup) {
299 trimApprovedListsAccordingToInstalledServices();
300 }
301
302 final int N = mApproved.size();
303 for (int i = 0 ; i < N; i++) {
304 final int userId = mApproved.keyAt(i);
305 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
306 if (approvedByType != null) {
307 final int M = approvedByType.size();
308 for (int j = 0; j < M; j++) {
309 final boolean isPrimary = approvedByType.keyAt(j);
310 final Set<String> approved = approvedByType.valueAt(j);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400311 if (approved != null) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400312 String allowedItems = String.join(ENABLED_SERVICES_SEPARATOR, approved);
313 out.startTag(null, TAG_MANAGED_SERVICES);
314 out.attribute(null, ATT_APPROVED_LIST, allowedItems);
315 out.attribute(null, ATT_USER_ID, Integer.toString(userId));
316 out.attribute(null, ATT_IS_PRIMARY, Boolean.toString(isPrimary));
317 out.endTag(null, TAG_MANAGED_SERVICES);
318
319 if (!forBackup && isPrimary) {
320 // Also write values to settings, for observers who haven't migrated yet
321 Settings.Secure.putStringForUser(mContext.getContentResolver(),
322 getConfig().secureSettingName, allowedItems, userId);
323 }
324
325 }
326 }
327 }
328 }
329
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400330 out.endTag(null, getConfig().xmlTag);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400331 }
332
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400333 protected void migrateToXml() {
334 loadAllowedComponentsFromSettings();
335 }
336
337 public void readXml(XmlPullParser parser)
Julia Reynoldsb852e562017-06-06 16:14:18 -0400338 throws XmlPullParserException, IOException {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400339 int type;
340 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
341 String tag = parser.getName();
342 if (type == XmlPullParser.END_TAG
343 && getConfig().xmlTag.equals(tag)) {
344 break;
345 }
346 if (type == XmlPullParser.START_TAG) {
347 if (TAG_MANAGED_SERVICES.equals(tag)) {
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400348 Slog.i(TAG, "Read " + mConfig.caption + " permissions from xml");
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400349 final String approved = XmlUtils.readStringAttribute(parser, ATT_APPROVED_LIST);
350 final int userId = XmlUtils.readIntAttribute(parser, ATT_USER_ID, 0);
351 final boolean isPrimary =
352 XmlUtils.readBooleanAttribute(parser, ATT_IS_PRIMARY, true);
Julia Reynolds45523002017-09-12 09:43:57 -0400353 if (mUm.getUserInfo(userId) != null) {
354 addApprovedList(approved, userId, isPrimary);
355 }
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400356 mUseXml = true;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400357 }
358 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400359 }
360 rebindServices(false);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400361 }
362
363 private void loadAllowedComponentsFromSettings() {
364
365 UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
366 for (UserInfo user : userManager.getUsers()) {
367 final ContentResolver cr = mContext.getContentResolver();
368 addApprovedList(Settings.Secure.getStringForUser(
369 cr,
370 getConfig().secureSettingName,
371 user.id), user.id, true);
372 if (!TextUtils.isEmpty(getConfig().secondarySettingName)) {
373 addApprovedList(Settings.Secure.getStringForUser(
374 cr,
375 getConfig().secondarySettingName,
376 user.id), user.id, false);
377 }
378 }
379 Slog.d(TAG, "Done loading approved values from settings");
380 }
381
382 private void addApprovedList(String approved, int userId, boolean isPrimary) {
383 if (TextUtils.isEmpty(approved)) {
384 approved = "";
385 }
386 ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
387 if (approvedByType == null) {
388 approvedByType = new ArrayMap<>();
389 mApproved.put(userId, approvedByType);
390 }
391 String[] approvedArray = approved.split(ENABLED_SERVICES_SEPARATOR);
392 final ArraySet<String> approvedList = new ArraySet<>();
393 for (String pkgOrComponent : approvedArray) {
394 String approvedItem = getApprovedValue(pkgOrComponent);
395 if (approvedItem != null) {
396 approvedList.add(approvedItem);
397 }
398 }
399 approvedByType.put(isPrimary, approvedList);
400 }
401
402 protected boolean isComponentEnabledForPackage(String pkg) {
John Spurlock80774932015-05-07 17:38:50 -0400403 return mEnabledServicesPackageNames.contains(pkg);
404 }
405
Julia Reynoldsb852e562017-06-06 16:14:18 -0400406 protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId,
407 boolean isPrimary, boolean enabled) {
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400408 Slog.i(TAG,
409 (enabled ? " Allowing " : "Disallowing ") + mConfig.caption + " " + pkgOrComponent);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400410 ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.get(userId);
411 if (allowedByType == null) {
412 allowedByType = new ArrayMap<>();
413 mApproved.put(userId, allowedByType);
414 }
415 ArraySet<String> approved = allowedByType.get(isPrimary);
416 if (approved == null) {
417 approved = new ArraySet<>();
418 allowedByType.put(isPrimary, approved);
419 }
420 String approvedItem = getApprovedValue(pkgOrComponent);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200421
Julia Reynoldsb852e562017-06-06 16:14:18 -0400422 if (approvedItem != null) {
423 if (enabled) {
424 approved.add(approvedItem);
425 } else {
426 approved.remove(approvedItem);
John Spurlock7340fc82014-04-24 18:50:12 -0400427 }
428 }
429
Julia Reynoldsb852e562017-06-06 16:14:18 -0400430 rebindServices(false);
431 }
432
433 private String getApprovedValue(String pkgOrComponent) {
434 if (mApprovalLevel == APPROVAL_BY_COMPONENT) {
435 if(ComponentName.unflattenFromString(pkgOrComponent) != null) {
436 return pkgOrComponent;
John Spurlock7340fc82014-04-24 18:50:12 -0400437 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400438 return null;
439 } else {
440 return getPackageName(pkgOrComponent);
441 }
442 }
443
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400444 protected String getApproved(int userId, boolean primary) {
445 final ArrayMap<Boolean, ArraySet<String>> allowedByType =
446 mApproved.getOrDefault(userId, new ArrayMap<>());
447 ArraySet<String> approved = allowedByType.getOrDefault(primary, new ArraySet<>());
448 return String.join(ENABLED_SERVICES_SEPARATOR, approved);
449 }
450
Julia Reynoldsb852e562017-06-06 16:14:18 -0400451 protected List<ComponentName> getAllowedComponents(int userId) {
452 final List<ComponentName> allowedComponents = new ArrayList<>();
453 final ArrayMap<Boolean, ArraySet<String>> allowedByType =
454 mApproved.getOrDefault(userId, new ArrayMap<>());
455 for (int i = 0; i < allowedByType.size(); i++) {
456 final ArraySet<String> allowed = allowedByType.valueAt(i);
457 allowedComponents.addAll(allowed.stream().map(ComponentName::unflattenFromString)
458 .filter(out -> out != null).collect(Collectors.toList()));
459 }
460 return allowedComponents;
461 }
462
463 protected List<String> getAllowedPackages(int userId) {
464 final List<String> allowedPackages = new ArrayList<>();
465 final ArrayMap<Boolean, ArraySet<String>> allowedByType =
466 mApproved.getOrDefault(userId, new ArrayMap<>());
467 for (int i = 0; i < allowedByType.size(); i++) {
468 final ArraySet<String> allowed = allowedByType.valueAt(i);
469 allowedPackages.addAll(
470 allowed.stream().map(this::getPackageName).collect(Collectors.toList()));
471 }
472 return allowedPackages;
473 }
474
475 protected boolean isPackageOrComponentAllowed(String pkgOrComponent, int userId) {
476 ArrayMap<Boolean, ArraySet<String>> allowedByType =
477 mApproved.getOrDefault(userId, new ArrayMap<>());
478 for (int i = 0; i < allowedByType.size(); i++) {
479 ArraySet<String> allowed = allowedByType.valueAt(i);
480 if (allowed.contains(pkgOrComponent)) {
481 return true;
482 }
483 }
484 return false;
485 }
486
487 public void onPackagesChanged(boolean removingPackage, String[] pkgList, int[] uidList) {
488 if (DEBUG) Slog.d(TAG, "onPackagesChanged removingPackage=" + removingPackage
489 + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList))
490 + " mEnabledServicesPackageNames=" + mEnabledServicesPackageNames);
491
492 if (pkgList != null && (pkgList.length > 0)) {
493 boolean anyServicesInvolved = false;
494 // Remove notification settings for uninstalled package
495 if (removingPackage) {
496 int size = Math.min(pkgList.length, uidList.length);
497 for (int i = 0; i < size; i++) {
498 final String pkg = pkgList[i];
499 final int userId = UserHandle.getUserId(uidList[i]);
500 anyServicesInvolved = removeUninstalledItemsFromApprovedLists(userId, pkg);
501 }
502 }
503 for (String pkgName : pkgList) {
504 if (mEnabledServicesPackageNames.contains(pkgName)) {
505 anyServicesInvolved = true;
506 }
507 }
508
509 if (anyServicesInvolved) {
510 // make sure we're still bound to any of our services who may have just upgraded
511 rebindServices(false);
512 }
John Spurlock7340fc82014-04-24 18:50:12 -0400513 }
514 }
515
Julia Reynolds5aa13a42017-08-24 09:10:23 -0400516 public void onUserRemoved(int user) {
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400517 Slog.i(TAG, "Removing approved services for removed user " + user);
Julia Reynolds5aa13a42017-08-24 09:10:23 -0400518 mApproved.remove(user);
519 rebindServices(true);
520 }
521
John Spurlock1b8b22b2015-05-20 09:47:13 -0400522 public void onUserSwitched(int user) {
523 if (DEBUG) Slog.d(TAG, "onUserSwitched u=" + user);
Christoph Studerb53dfd42014-09-12 14:45:59 +0200524 if (Arrays.equals(mLastSeenProfileIds, mUserProfiles.getCurrentProfileIds())) {
525 if (DEBUG) Slog.d(TAG, "Current profile IDs didn't change, skipping rebindServices().");
526 return;
527 }
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400528 rebindServices(true);
Christoph Studerb53dfd42014-09-12 14:45:59 +0200529 }
530
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500531 public void onUserUnlocked(int user) {
532 if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400533 rebindServices(false);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500534 }
535
Julia Reynoldsb852e562017-06-06 16:14:18 -0400536 private ManagedServiceInfo getServiceFromTokenLocked(IInterface service) {
Chris Wrenab41eec2016-01-04 18:01:27 -0500537 if (service == null) {
538 return null;
539 }
John Spurlock7340fc82014-04-24 18:50:12 -0400540 final IBinder token = service.asBinder();
541 final int N = mServices.size();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200542 for (int i = 0; i < N; i++) {
John Spurlock7340fc82014-04-24 18:50:12 -0400543 final ManagedServiceInfo info = mServices.get(i);
544 if (info.service.asBinder() == token) return info;
545 }
Chris Wrenab41eec2016-01-04 18:01:27 -0500546 return null;
547 }
548
Julia Reynolds503ed942017-10-04 16:04:56 -0400549 protected boolean isServiceTokenValidLocked(IInterface service) {
550 if (service == null) {
551 return false;
552 }
553 ManagedServiceInfo info = getServiceFromTokenLocked(service);
554 if (info != null) {
555 return true;
556 }
557 return false;
558 }
559
Julia Reynoldsb852e562017-06-06 16:14:18 -0400560 protected ManagedServiceInfo checkServiceTokenLocked(IInterface service) {
Chris Wrenab41eec2016-01-04 18:01:27 -0500561 checkNotNull(service);
562 ManagedServiceInfo info = getServiceFromTokenLocked(service);
563 if (info != null) {
564 return info;
565 }
John Spurlock7340fc82014-04-24 18:50:12 -0400566 throw new SecurityException("Disallowed call from unknown " + getCaption() + ": "
Julia Reynoldscb507b82017-09-07 13:53:40 -0400567 + service + " " + service.getClass());
John Spurlock7340fc82014-04-24 18:50:12 -0400568 }
569
570 public void unregisterService(IInterface service, int userid) {
571 checkNotNull(service);
572 // no need to check permissions; if your service binder is in the list,
573 // that's proof that you had permission to add it in the first place
574 unregisterServiceImpl(service, userid);
575 }
576
577 public void registerService(IInterface service, ComponentName component, int userid) {
578 checkNotNull(service);
Christoph Studer3e144d32014-05-22 16:48:40 +0200579 ManagedServiceInfo info = registerServiceImpl(service, component, userid);
580 if (info != null) {
581 onServiceAdded(info);
582 }
John Spurlock7340fc82014-04-24 18:50:12 -0400583 }
584
Chris Wren51017d02015-12-15 15:34:46 -0500585 /**
586 * Add a service to our callbacks. The lifecycle of this service is managed externally,
Julia Reynoldsb852e562017-06-06 16:14:18 -0400587 * but unlike a system service, it should not be considered privileged.
Chris Wren51017d02015-12-15 15:34:46 -0500588 * */
Julia Reynoldsb852e562017-06-06 16:14:18 -0400589 protected void registerGuestService(ManagedServiceInfo guest) {
Chris Wren51017d02015-12-15 15:34:46 -0500590 checkNotNull(guest.service);
Ruben Brunke24b9a62016-02-16 21:38:24 -0800591 if (!checkType(guest.service)) {
592 throw new IllegalArgumentException();
593 }
Chris Wren51017d02015-12-15 15:34:46 -0500594 if (registerServiceImpl(guest) != null) {
595 onServiceAdded(guest);
Chris Wrenab41eec2016-01-04 18:01:27 -0500596 }
597 }
598
Julia Reynoldsb852e562017-06-06 16:14:18 -0400599 protected void setComponentState(ComponentName component, boolean enabled) {
Chris Wrenab41eec2016-01-04 18:01:27 -0500600 boolean previous = !mSnoozingForCurrentProfiles.contains(component);
601 if (previous == enabled) {
602 return;
603 }
604
605 if (enabled) {
606 mSnoozingForCurrentProfiles.remove(component);
607 } else {
608 mSnoozingForCurrentProfiles.add(component);
609 }
610
611 // State changed
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400612 Slog.d(TAG, ((enabled) ? "Enabling " : "Disabling ") + "component " +
613 component.flattenToShortString());
Chris Wrenab41eec2016-01-04 18:01:27 -0500614
Chris Wren0efdb882016-03-01 17:17:47 -0500615 synchronized (mMutex) {
616 final int[] userIds = mUserProfiles.getCurrentProfileIds();
617
618 for (int userId : userIds) {
619 if (enabled) {
620 registerServiceLocked(component, userId);
621 } else {
622 unregisterServiceLocked(component, userId);
623 }
Chris Wrenab41eec2016-01-04 18:01:27 -0500624 }
Chris Wren51017d02015-12-15 15:34:46 -0500625 }
626 }
627
Julia Reynoldsb852e562017-06-06 16:14:18 -0400628 private @NonNull ArraySet<ComponentName> loadComponentNamesFromValues(
629 ArraySet<String> approved, int userId) {
630 if (approved == null || approved.size() == 0)
Julia Reynolds6e839b02016-04-13 10:01:17 -0400631 return new ArraySet<>();
Julia Reynoldsb852e562017-06-06 16:14:18 -0400632 ArraySet<ComponentName> result = new ArraySet<>(approved.size());
633 for (int i = 0; i < approved.size(); i++) {
634 final String packageOrComponent = approved.valueAt(i);
635 if (!TextUtils.isEmpty(packageOrComponent)) {
636 ComponentName component = ComponentName.unflattenFromString(packageOrComponent);
637 if (component != null) {
638 result.add(component);
639 } else {
640 result.addAll(queryPackageForServices(packageOrComponent, userId));
641 }
Christopher Tate6597e342015-02-17 12:15:25 -0800642 }
643 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200644 return result;
645 }
John Spurlock7340fc82014-04-24 18:50:12 -0400646
Julia Reynoldsc279b992015-10-30 08:23:51 -0400647 protected Set<ComponentName> queryPackageForServices(String packageName, int userId) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400648 return queryPackageForServices(packageName, 0, userId);
649 }
650
651 protected Set<ComponentName> queryPackageForServices(String packageName, int extraFlags,
652 int userId) {
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200653 Set<ComponentName> installed = new ArraySet<>();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200654 final PackageManager pm = mContext.getPackageManager();
Julia Reynoldsc279b992015-10-30 08:23:51 -0400655 Intent queryIntent = new Intent(mConfig.serviceInterface);
656 if (!TextUtils.isEmpty(packageName)) {
657 queryIntent.setPackage(packageName);
658 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200659 List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
Julia Reynoldsc279b992015-10-30 08:23:51 -0400660 queryIntent,
Julia Reynoldsb852e562017-06-06 16:14:18 -0400661 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA | extraFlags,
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200662 userId);
663 if (DEBUG)
664 Slog.v(TAG, mConfig.serviceInterface + " services: " + installedServices);
Julia Reynolds50f05142015-10-30 17:03:59 -0400665 if (installedServices != null) {
666 for (int i = 0, count = installedServices.size(); i < count; i++) {
667 ResolveInfo resolveInfo = installedServices.get(i);
668 ServiceInfo info = resolveInfo.serviceInfo;
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200669
Julia Reynolds50f05142015-10-30 17:03:59 -0400670 ComponentName component = new ComponentName(info.packageName, info.name);
671 if (!mConfig.bindPermission.equals(info.permission)) {
672 Slog.w(TAG, "Skipping " + getCaption() + " service "
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800673 + info.packageName + "/" + info.name
674 + ": it does not require the permission "
675 + mConfig.bindPermission);
Julia Reynolds50f05142015-10-30 17:03:59 -0400676 continue;
677 }
678 installed.add(component);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200679 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200680 }
Julia Reynoldsc279b992015-10-30 08:23:51 -0400681 return installed;
682 }
683
Julia Reynoldsb852e562017-06-06 16:14:18 -0400684 private void trimApprovedListsAccordingToInstalledServices() {
685 int N = mApproved.size();
686 for (int i = 0 ; i < N; i++) {
687 final int userId = mApproved.keyAt(i);
688 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
689 int M = approvedByType.size();
690 for (int j = 0; j < M; j++) {
691 final ArraySet<String> approved = approvedByType.valueAt(j);
692 int P = approved.size();
693 for (int k = P - 1; k >= 0; k--) {
694 final String approvedPackageOrComponent = approved.valueAt(k);
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400695 if (!isValidEntry(approvedPackageOrComponent, userId)){
Julia Reynoldsb852e562017-06-06 16:14:18 -0400696 approved.removeAt(k);
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400697 Slog.v(TAG, "Removing " + approvedPackageOrComponent
698 + " from approved list; no matching services found");
Julia Reynoldsb852e562017-06-06 16:14:18 -0400699 } else {
700 if (DEBUG) {
701 Slog.v(TAG, "Keeping " + approvedPackageOrComponent
702 + " on approved list; matching services found");
703 }
704 }
John Spurlock7340fc82014-04-24 18:50:12 -0400705 }
John Spurlock7340fc82014-04-24 18:50:12 -0400706 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400707 }
708 }
John Spurlock7340fc82014-04-24 18:50:12 -0400709
Julia Reynoldsb852e562017-06-06 16:14:18 -0400710 private boolean removeUninstalledItemsFromApprovedLists(int uninstalledUserId, String pkg) {
711 boolean removed = false;
712 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(uninstalledUserId);
713 if (approvedByType != null) {
714 int M = approvedByType.size();
715 for (int j = 0; j < M; j++) {
716 final ArraySet<String> approved = approvedByType.valueAt(j);
717 int O = approved.size();
718 for (int k = O - 1; k >= 0; k--) {
719 final String packageOrComponent = approved.valueAt(k);
720 final String packageName = getPackageName(packageOrComponent);
721 if (TextUtils.equals(pkg, packageName)) {
722 approved.removeAt(k);
723 if (DEBUG) {
724 Slog.v(TAG, "Removing " + packageOrComponent
725 + " from approved list; uninstalled");
726 }
727 }
728 }
John Spurlock7340fc82014-04-24 18:50:12 -0400729 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200730 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400731 return removed;
732 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200733
Julia Reynoldsb852e562017-06-06 16:14:18 -0400734 protected String getPackageName(String packageOrComponent) {
735 final ComponentName component = ComponentName.unflattenFromString(packageOrComponent);
736 if (component != null) {
737 return component.getPackageName();
738 } else {
739 return packageOrComponent;
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200740 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400741 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200742
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400743 protected boolean isValidEntry(String packageOrComponent, int userId) {
744 return hasMatchingServices(packageOrComponent, userId);
745 }
746
Julia Reynoldsb852e562017-06-06 16:14:18 -0400747 private boolean hasMatchingServices(String packageOrComponent, int userId) {
748 if (!TextUtils.isEmpty(packageOrComponent)) {
749 final String packageName = getPackageName(packageOrComponent);
750 return queryPackageForServices(packageName, userId).size() > 0;
John Spurlock7340fc82014-04-24 18:50:12 -0400751 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400752 return false;
John Spurlock7340fc82014-04-24 18:50:12 -0400753 }
754
755 /**
756 * Called whenever packages change, the user switches, or the secure setting
757 * is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
758 */
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400759 private void rebindServices(boolean forceRebind) {
John Spurlock7340fc82014-04-24 18:50:12 -0400760 if (DEBUG) Slog.d(TAG, "rebindServices");
761 final int[] userIds = mUserProfiles.getCurrentProfileIds();
762 final int nUserIds = userIds.length;
763
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200764 final SparseArray<ArraySet<ComponentName>> componentsByUser = new SparseArray<>();
John Spurlock7340fc82014-04-24 18:50:12 -0400765
766 for (int i = 0; i < nUserIds; ++i) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400767 final int userId = userIds[i];
768 final ArrayMap<Boolean, ArraySet<String>> approvedLists = mApproved.get(userIds[i]);
769 if (approvedLists != null) {
770 final int N = approvedLists.size();
771 for (int j = 0; j < N; j++) {
772 ArraySet<ComponentName> approvedByUser = componentsByUser.get(userId);
773 if (approvedByUser == null) {
774 approvedByUser = new ArraySet<>();
775 componentsByUser.put(userId, approvedByUser);
776 }
777 approvedByUser.addAll(
778 loadComponentNamesFromValues(approvedLists.valueAt(j), userId));
779 }
Julia Reynolds6e839b02016-04-13 10:01:17 -0400780 }
John Spurlock7340fc82014-04-24 18:50:12 -0400781 }
782
Julia Reynolds9a86cc02016-02-10 15:38:15 -0500783 final ArrayList<ManagedServiceInfo> removableBoundServices = new ArrayList<>();
784 final SparseArray<Set<ComponentName>> toAdd = new SparseArray<>();
John Spurlock7340fc82014-04-24 18:50:12 -0400785
786 synchronized (mMutex) {
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400787 // Rebind to non-system services if user switched
Christoph Studer5d423842014-05-23 13:15:54 +0200788 for (ManagedServiceInfo service : mServices) {
Chris Wren51017d02015-12-15 15:34:46 -0500789 if (!service.isSystem && !service.isGuest(this)) {
Julia Reynolds9a86cc02016-02-10 15:38:15 -0500790 removableBoundServices.add(service);
Christoph Studer5d423842014-05-23 13:15:54 +0200791 }
792 }
John Spurlock7340fc82014-04-24 18:50:12 -0400793
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400794 mEnabledServicesForCurrentProfiles.clear();
795 mEnabledServicesPackageNames.clear();
John Spurlock7340fc82014-04-24 18:50:12 -0400796
797 for (int i = 0; i < nUserIds; ++i) {
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200798 // decode the list of components
799 final ArraySet<ComponentName> userComponents = componentsByUser.get(userIds[i]);
800 if (null == userComponents) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400801 toAdd.put(userIds[i], new ArraySet<>());
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200802 continue;
803 }
804
Julia Reynolds9a86cc02016-02-10 15:38:15 -0500805 final Set<ComponentName> add = new HashSet<>(userComponents);
Chris Wrenab41eec2016-01-04 18:01:27 -0500806 add.removeAll(mSnoozingForCurrentProfiles);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800807
John Spurlock7340fc82014-04-24 18:50:12 -0400808 toAdd.put(userIds[i], add);
809
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400810 mEnabledServicesForCurrentProfiles.addAll(userComponents);
John Spurlock7340fc82014-04-24 18:50:12 -0400811
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200812 for (int j = 0; j < userComponents.size(); j++) {
Chris Wren083094c2015-12-15 16:25:07 -0500813 final ComponentName component = userComponents.valueAt(j);
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400814 mEnabledServicesPackageNames.add(component.getPackageName());
John Spurlock7340fc82014-04-24 18:50:12 -0400815 }
816 }
John Spurlock7340fc82014-04-24 18:50:12 -0400817 }
818
Julia Reynolds9a86cc02016-02-10 15:38:15 -0500819 for (ManagedServiceInfo info : removableBoundServices) {
John Spurlock7340fc82014-04-24 18:50:12 -0400820 final ComponentName component = info.component;
821 final int oldUser = info.userid;
Julia Reynolds9a86cc02016-02-10 15:38:15 -0500822 final Set<ComponentName> allowedComponents = toAdd.get(info.userid);
823 if (allowedComponents != null) {
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400824 if (allowedComponents.contains(component) && !forceRebind) {
Julia Reynolds9a86cc02016-02-10 15:38:15 -0500825 // Already bound, don't need to bind again.
826 allowedComponents.remove(component);
827 } else {
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400828 // No longer allowed to be bound, or must rebind.
Julia Reynolds9a86cc02016-02-10 15:38:15 -0500829 Slog.v(TAG, "disabling " + getCaption() + " for user "
830 + oldUser + ": " + component);
831 unregisterService(component, oldUser);
832 }
833 }
John Spurlock7340fc82014-04-24 18:50:12 -0400834 }
835
836 for (int i = 0; i < nUserIds; ++i) {
Julia Reynolds9a86cc02016-02-10 15:38:15 -0500837 final Set<ComponentName> add = toAdd.get(userIds[i]);
838 for (ComponentName component : add) {
Julia Reynoldsa75c7522017-03-21 17:34:25 -0400839 try {
840 ServiceInfo info = mPm.getServiceInfo(component,
841 PackageManager.MATCH_DIRECT_BOOT_AWARE
842 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userIds[i]);
Julia Reynolds503ed942017-10-04 16:04:56 -0400843 if (info == null) {
844 Slog.w(TAG, "Not binding " + getCaption() + " service " + component
845 + ": service not found");
846 continue;
847 }
848 if (!mConfig.bindPermission.equals(info.permission)) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400849 Slog.w(TAG, "Not binding " + getCaption() + " service " + component
Julia Reynoldsa75c7522017-03-21 17:34:25 -0400850 + ": it does not require the permission " + mConfig.bindPermission);
851 continue;
852 }
853 Slog.v(TAG,
854 "enabling " + getCaption() + " for " + userIds[i] + ": " + component);
855 registerService(component, userIds[i]);
856 } catch (RemoteException e) {
857 e.rethrowFromSystemServer();
858 }
John Spurlock7340fc82014-04-24 18:50:12 -0400859 }
860 }
Christoph Studerb53dfd42014-09-12 14:45:59 +0200861
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200862 mLastSeenProfileIds = userIds;
John Spurlock7340fc82014-04-24 18:50:12 -0400863 }
864
865 /**
866 * Version of registerService that takes the name of a service component to bind to.
867 */
868 private void registerService(final ComponentName name, final int userid) {
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800869 synchronized (mMutex) {
870 registerServiceLocked(name, userid);
871 }
872 }
873
Chris Wren0efdb882016-03-01 17:17:47 -0500874 /**
875 * Inject a system service into the management list.
876 */
877 public void registerSystemService(final ComponentName name, final int userid) {
878 synchronized (mMutex) {
879 registerServiceLocked(name, userid, true /* isSystem */);
880 }
881 }
882
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800883 private void registerServiceLocked(final ComponentName name, final int userid) {
Chris Wren0efdb882016-03-01 17:17:47 -0500884 registerServiceLocked(name, userid, false /* isSystem */);
885 }
886
887 private void registerServiceLocked(final ComponentName name, final int userid,
888 final boolean isSystem) {
John Spurlock7340fc82014-04-24 18:50:12 -0400889 if (DEBUG) Slog.v(TAG, "registerService: " + name + " u=" + userid);
890
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800891 final String servicesBindingTag = name.toString() + "/" + userid;
892 if (mServicesBinding.contains(servicesBindingTag)) {
Ryan Lothian4a86a512017-12-04 11:56:58 -0500893 Slog.v(TAG, "Not registering " + name + " as bind is already in progress");
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800894 // stop registering this thing already! we're working on it
895 return;
896 }
897 mServicesBinding.add(servicesBindingTag);
John Spurlock7340fc82014-04-24 18:50:12 -0400898
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800899 final int N = mServices.size();
900 for (int i = N - 1; i >= 0; i--) {
901 final ManagedServiceInfo info = mServices.get(i);
902 if (name.equals(info.component)
903 && info.userid == userid) {
904 // cut old connections
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400905 Slog.v(TAG, " disconnecting old " + getCaption() + ": " + info.service);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800906 removeServiceLocked(i);
907 if (info.connection != null) {
908 mContext.unbindService(info.connection);
John Spurlock7340fc82014-04-24 18:50:12 -0400909 }
910 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800911 }
John Spurlock7340fc82014-04-24 18:50:12 -0400912
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800913 Intent intent = new Intent(mConfig.serviceInterface);
914 intent.setComponent(name);
John Spurlock7340fc82014-04-24 18:50:12 -0400915
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800916 intent.putExtra(Intent.EXTRA_CLIENT_LABEL, mConfig.clientLabel);
John Spurlock7340fc82014-04-24 18:50:12 -0400917
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800918 final PendingIntent pendingIntent = PendingIntent.getActivity(
919 mContext, 0, new Intent(mConfig.settingsAction), 0);
920 intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
John Spurlock7340fc82014-04-24 18:50:12 -0400921
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800922 ApplicationInfo appInfo = null;
923 try {
924 appInfo = mContext.getPackageManager().getApplicationInfo(
925 name.getPackageName(), 0);
926 } catch (NameNotFoundException e) {
927 // Ignore if the package doesn't exist we won't be able to bind to the service.
928 }
929 final int targetSdkVersion =
930 appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE;
John Spurlock7340fc82014-04-24 18:50:12 -0400931
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800932 try {
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400933 Slog.v(TAG, "binding: " + intent);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800934 ServiceConnection serviceConnection = new ServiceConnection() {
935 IInterface mService;
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200936
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800937 @Override
938 public void onServiceConnected(ComponentName name, IBinder binder) {
939 boolean added = false;
940 ManagedServiceInfo info = null;
941 synchronized (mMutex) {
Ryan Lothian4a86a512017-12-04 11:56:58 -0500942 mServicesRebinding.remove(servicesBindingTag);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800943 mServicesBinding.remove(servicesBindingTag);
944 try {
945 mService = asInterface(binder);
946 info = newServiceInfo(mService, name,
Chris Wren0efdb882016-03-01 17:17:47 -0500947 userid, isSystem, this, targetSdkVersion);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800948 binder.linkToDeath(info, 0);
949 added = mServices.add(info);
950 } catch (RemoteException e) {
951 // already dead
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200952 }
953 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800954 if (added) {
955 onServiceAdded(info);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200956 }
John Spurlock7340fc82014-04-24 18:50:12 -0400957 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800958
959 @Override
960 public void onServiceDisconnected(ComponentName name) {
Julia Reynolds72b41172017-08-18 09:21:36 -0400961 mServicesBinding.remove(servicesBindingTag);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800962 Slog.v(TAG, getCaption() + " connection lost: " + name);
963 }
Ryan Lothian4a86a512017-12-04 11:56:58 -0500964
965 @Override
966 public void onBindingDied(ComponentName name) {
967 Slog.w(TAG, getCaption() + " binding died: " + name);
968 synchronized (mMutex) {
969 mServicesBinding.remove(servicesBindingTag);
970 mContext.unbindService(this);
971 if (!mServicesRebinding.contains(servicesBindingTag)) {
972 mServicesRebinding.add(servicesBindingTag);
973 mHandler.postDelayed(new Runnable() {
974 @Override
975 public void run() {
976 registerService(name, userid);
977 }
978 }, ON_BINDING_DIED_REBIND_DELAY_MS);
979 } else {
980 Slog.v(TAG, getCaption() + " not rebinding as "
981 + "a previous rebind attempt was made: " + name);
982 }
983 }
984 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800985 };
986 if (!mContext.bindServiceAsUser(intent,
987 serviceConnection,
Felipe Lemea1b79bf2016-05-24 13:06:54 -0700988 BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE | BIND_ALLOW_WHITELIST_MANAGEMENT,
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800989 new UserHandle(userid))) {
990 mServicesBinding.remove(servicesBindingTag);
991 Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent);
John Spurlock7340fc82014-04-24 18:50:12 -0400992 return;
993 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800994 } catch (SecurityException ex) {
Julia Reynolds72b41172017-08-18 09:21:36 -0400995 mServicesBinding.remove(servicesBindingTag);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800996 Slog.e(TAG, "Unable to bind " + getCaption() + " service: " + intent, ex);
John Spurlock7340fc82014-04-24 18:50:12 -0400997 }
998 }
999
1000 /**
1001 * Remove a service for the given user by ComponentName
1002 */
1003 private void unregisterService(ComponentName name, int userid) {
1004 synchronized (mMutex) {
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001005 unregisterServiceLocked(name, userid);
1006 }
1007 }
1008
1009 private void unregisterServiceLocked(ComponentName name, int userid) {
1010 final int N = mServices.size();
1011 for (int i = N - 1; i >= 0; i--) {
1012 final ManagedServiceInfo info = mServices.get(i);
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -04001013 if (name.equals(info.component) && info.userid == userid) {
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001014 removeServiceLocked(i);
1015 if (info.connection != null) {
1016 try {
1017 mContext.unbindService(info.connection);
1018 } catch (IllegalArgumentException ex) {
1019 // something happened to the service: we think we have a connection
1020 // but it's bogus.
1021 Slog.e(TAG, getCaption() + " " + name + " could not be unbound: " + ex);
John Spurlock7340fc82014-04-24 18:50:12 -04001022 }
1023 }
1024 }
1025 }
1026 }
1027
1028 /**
1029 * Removes a service from the list but does not unbind
1030 *
1031 * @return the removed service.
1032 */
1033 private ManagedServiceInfo removeServiceImpl(IInterface service, final int userid) {
John Spurlocke77bb362014-04-26 10:24:59 -04001034 if (DEBUG) Slog.d(TAG, "removeServiceImpl service=" + service + " u=" + userid);
John Spurlock7340fc82014-04-24 18:50:12 -04001035 ManagedServiceInfo serviceInfo = null;
1036 synchronized (mMutex) {
1037 final int N = mServices.size();
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001038 for (int i = N - 1; i >= 0; i--) {
John Spurlock7340fc82014-04-24 18:50:12 -04001039 final ManagedServiceInfo info = mServices.get(i);
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -04001040 if (info.service.asBinder() == service.asBinder() && info.userid == userid) {
1041 Slog.d(TAG, "Removing active service " + info.component);
John Spurlocke77bb362014-04-26 10:24:59 -04001042 serviceInfo = removeServiceLocked(i);
John Spurlock7340fc82014-04-24 18:50:12 -04001043 }
1044 }
1045 }
1046 return serviceInfo;
1047 }
1048
John Spurlocke77bb362014-04-26 10:24:59 -04001049 private ManagedServiceInfo removeServiceLocked(int i) {
1050 final ManagedServiceInfo info = mServices.remove(i);
1051 onServiceRemovedLocked(info);
1052 return info;
1053 }
1054
John Spurlock7340fc82014-04-24 18:50:12 -04001055 private void checkNotNull(IInterface service) {
1056 if (service == null) {
1057 throw new IllegalArgumentException(getCaption() + " must not be null");
1058 }
1059 }
1060
Christoph Studer3e144d32014-05-22 16:48:40 +02001061 private ManagedServiceInfo registerServiceImpl(final IInterface service,
John Spurlock7340fc82014-04-24 18:50:12 -04001062 final ComponentName component, final int userid) {
Chris Wren51017d02015-12-15 15:34:46 -05001063 ManagedServiceInfo info = newServiceInfo(service, component, userid,
1064 true /*isSystem*/, null /*connection*/, Build.VERSION_CODES.LOLLIPOP);
1065 return registerServiceImpl(info);
1066 }
1067
1068 private ManagedServiceInfo registerServiceImpl(ManagedServiceInfo info) {
John Spurlock7340fc82014-04-24 18:50:12 -04001069 synchronized (mMutex) {
1070 try {
Chris Wren51017d02015-12-15 15:34:46 -05001071 info.service.asBinder().linkToDeath(info, 0);
John Spurlock7340fc82014-04-24 18:50:12 -04001072 mServices.add(info);
Christoph Studer3e144d32014-05-22 16:48:40 +02001073 return info;
John Spurlock7340fc82014-04-24 18:50:12 -04001074 } catch (RemoteException e) {
1075 // already dead
1076 }
1077 }
Christoph Studer3e144d32014-05-22 16:48:40 +02001078 return null;
John Spurlock7340fc82014-04-24 18:50:12 -04001079 }
1080
1081 /**
1082 * Removes a service from the list and unbinds.
1083 */
1084 private void unregisterServiceImpl(IInterface service, int userid) {
1085 ManagedServiceInfo info = removeServiceImpl(service, userid);
Chris Wren51017d02015-12-15 15:34:46 -05001086 if (info != null && info.connection != null && !info.isGuest(this)) {
John Spurlock7340fc82014-04-24 18:50:12 -04001087 mContext.unbindService(info.connection);
1088 }
1089 }
1090
John Spurlock7340fc82014-04-24 18:50:12 -04001091 public class ManagedServiceInfo implements IBinder.DeathRecipient {
1092 public IInterface service;
1093 public ComponentName component;
1094 public int userid;
1095 public boolean isSystem;
1096 public ServiceConnection connection;
1097 public int targetSdkVersion;
1098
1099 public ManagedServiceInfo(IInterface service, ComponentName component,
1100 int userid, boolean isSystem, ServiceConnection connection, int targetSdkVersion) {
1101 this.service = service;
1102 this.component = component;
1103 this.userid = userid;
1104 this.isSystem = isSystem;
1105 this.connection = connection;
1106 this.targetSdkVersion = targetSdkVersion;
1107 }
1108
Chris Wren51017d02015-12-15 15:34:46 -05001109 public boolean isGuest(ManagedServices host) {
1110 return ManagedServices.this != host;
1111 }
1112
Chris Wrenab41eec2016-01-04 18:01:27 -05001113 public ManagedServices getOwner() {
1114 return ManagedServices.this;
1115 }
1116
John Spurlocke77bb362014-04-26 10:24:59 -04001117 @Override
1118 public String toString() {
1119 return new StringBuilder("ManagedServiceInfo[")
1120 .append("component=").append(component)
1121 .append(",userid=").append(userid)
1122 .append(",isSystem=").append(isSystem)
1123 .append(",targetSdkVersion=").append(targetSdkVersion)
1124 .append(",connection=").append(connection == null ? null : "<connection>")
1125 .append(",service=").append(service)
1126 .append(']').toString();
1127 }
1128
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001129 public void writeToProto(ProtoOutputStream proto, long fieldId, ManagedServices host) {
1130 final long token = proto.start(fieldId);
1131
1132 component.writeToProto(proto, ManagedServiceInfoProto.COMPONENT);
Kweku Adams93304b62017-09-20 17:03:00 -07001133 proto.write(ManagedServiceInfoProto.USER_ID, userid);
1134 proto.write(ManagedServiceInfoProto.SERVICE, service.getClass().getName());
1135 proto.write(ManagedServiceInfoProto.IS_SYSTEM, isSystem);
1136 proto.write(ManagedServiceInfoProto.IS_GUEST, isGuest(host));
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001137
1138 proto.end(token);
Kweku Adams93304b62017-09-20 17:03:00 -07001139 }
1140
John Spurlock7340fc82014-04-24 18:50:12 -04001141 public boolean enabledAndUserMatches(int nid) {
1142 if (!isEnabledForCurrentProfiles()) {
1143 return false;
1144 }
1145 if (this.userid == UserHandle.USER_ALL) return true;
Chris Wren0c4eeb42016-05-12 13:21:08 -04001146 if (this.isSystem) return true;
John Spurlock7340fc82014-04-24 18:50:12 -04001147 if (nid == UserHandle.USER_ALL || nid == this.userid) return true;
Esteban Talavera9c6458d2017-03-30 17:59:50 +01001148 return supportsProfiles()
1149 && mUserProfiles.isCurrentProfile(nid)
1150 && isPermittedForProfile(nid);
John Spurlock7340fc82014-04-24 18:50:12 -04001151 }
1152
1153 public boolean supportsProfiles() {
Dianne Hackborn955d8d62014-10-07 20:17:19 -07001154 return targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP;
John Spurlock7340fc82014-04-24 18:50:12 -04001155 }
1156
1157 @Override
1158 public void binderDied() {
John Spurlocke77bb362014-04-26 10:24:59 -04001159 if (DEBUG) Slog.d(TAG, "binderDied");
John Spurlock7340fc82014-04-24 18:50:12 -04001160 // Remove the service, but don't unbind from the service. The system will bring the
Esteban Talavera9c6458d2017-03-30 17:59:50 +01001161 // service back up, and the onServiceConnected handler will read the service with the
John Spurlock7340fc82014-04-24 18:50:12 -04001162 // new binding. If this isn't a bound service, and is just a registered
1163 // service, just removing it from the list is all we need to do anyway.
1164 removeServiceImpl(this.service, this.userid);
1165 }
1166
1167 /** convenience method for looking in mEnabledServicesForCurrentProfiles */
1168 public boolean isEnabledForCurrentProfiles() {
1169 if (this.isSystem) return true;
1170 if (this.connection == null) return false;
1171 return mEnabledServicesForCurrentProfiles.contains(this.component);
1172 }
Esteban Talavera9c6458d2017-03-30 17:59:50 +01001173
1174 /**
1175 * Returns true if this service is allowed to receive events for the given userId. A
1176 * managed profile owner can disallow non-system services running outside of the profile
1177 * from receiving events from the profile.
1178 */
1179 public boolean isPermittedForProfile(int userId) {
1180 if (!mUserProfiles.isManagedProfile(userId)) {
1181 return true;
1182 }
1183 DevicePolicyManager dpm =
1184 (DevicePolicyManager) mContext.getSystemService(DEVICE_POLICY_SERVICE);
1185 final long identity = Binder.clearCallingIdentity();
1186 try {
1187 return dpm.isNotificationListenerServicePermitted(
1188 component.getPackageName(), userId);
1189 } finally {
1190 Binder.restoreCallingIdentity(identity);
1191 }
1192 }
John Spurlock7340fc82014-04-24 18:50:12 -04001193 }
1194
Chris Wrenab41eec2016-01-04 18:01:27 -05001195 /** convenience method for looking in mEnabledServicesForCurrentProfiles */
1196 public boolean isComponentEnabledForCurrentProfiles(ComponentName component) {
1197 return mEnabledServicesForCurrentProfiles.contains(component);
1198 }
1199
John Spurlock7340fc82014-04-24 18:50:12 -04001200 public static class UserProfiles {
1201 // Profiles of the current user.
Ruben Brunke24b9a62016-02-16 21:38:24 -08001202 private final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
John Spurlock7340fc82014-04-24 18:50:12 -04001203
Ruben Brunke24b9a62016-02-16 21:38:24 -08001204 public void updateCache(@NonNull Context context) {
John Spurlock7340fc82014-04-24 18:50:12 -04001205 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
1206 if (userManager != null) {
1207 int currentUserId = ActivityManager.getCurrentUser();
1208 List<UserInfo> profiles = userManager.getProfiles(currentUserId);
1209 synchronized (mCurrentProfiles) {
1210 mCurrentProfiles.clear();
1211 for (UserInfo user : profiles) {
1212 mCurrentProfiles.put(user.id, user);
1213 }
1214 }
1215 }
1216 }
1217
1218 public int[] getCurrentProfileIds() {
1219 synchronized (mCurrentProfiles) {
1220 int[] users = new int[mCurrentProfiles.size()];
1221 final int N = mCurrentProfiles.size();
1222 for (int i = 0; i < N; ++i) {
1223 users[i] = mCurrentProfiles.keyAt(i);
1224 }
1225 return users;
1226 }
1227 }
1228
1229 public boolean isCurrentProfile(int userId) {
1230 synchronized (mCurrentProfiles) {
1231 return mCurrentProfiles.get(userId) != null;
1232 }
1233 }
Esteban Talavera9c6458d2017-03-30 17:59:50 +01001234
1235 public boolean isManagedProfile(int userId) {
1236 synchronized (mCurrentProfiles) {
1237 UserInfo user = mCurrentProfiles.get(userId);
1238 return user != null && user.isManagedProfile();
1239 }
1240 }
John Spurlock7340fc82014-04-24 18:50:12 -04001241 }
1242
Ruben Brunke24b9a62016-02-16 21:38:24 -08001243 public static class Config {
1244 public String caption;
1245 public String serviceInterface;
1246 public String secureSettingName;
Julia Reynolds6e839b02016-04-13 10:01:17 -04001247 public String secondarySettingName;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001248 public String xmlTag;
Ruben Brunke24b9a62016-02-16 21:38:24 -08001249 public String bindPermission;
1250 public String settingsAction;
1251 public int clientLabel;
John Spurlock7340fc82014-04-24 18:50:12 -04001252 }
1253}