blob: 45df3686d056f099eb5705b502d6d2b141565271 [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;
Julia Reynoldsca8e5352018-09-18 13:39:26 -040023import static android.os.UserHandle.USER_ALL;
Felipe Lemea1b79bf2016-05-24 13:06:54 -070024
Ruben Brunke24b9a62016-02-16 21:38:24 -080025import android.annotation.NonNull;
John Spurlock7340fc82014-04-24 18:50:12 -040026import android.app.ActivityManager;
27import android.app.PendingIntent;
Esteban Talavera9c6458d2017-03-30 17:59:50 +010028import android.app.admin.DevicePolicyManager;
John Spurlock7340fc82014-04-24 18:50:12 -040029import android.content.ComponentName;
30import android.content.ContentResolver;
31import android.content.Context;
32import android.content.Intent;
33import android.content.ServiceConnection;
34import android.content.pm.ApplicationInfo;
Julia Reynoldsa75c7522017-03-21 17:34:25 -040035import android.content.pm.IPackageManager;
John Spurlock7340fc82014-04-24 18:50:12 -040036import android.content.pm.PackageManager;
37import android.content.pm.PackageManager.NameNotFoundException;
38import android.content.pm.ResolveInfo;
39import android.content.pm.ServiceInfo;
40import android.content.pm.UserInfo;
Esteban Talavera9c6458d2017-03-30 17:59:50 +010041import android.os.Binder;
John Spurlock7340fc82014-04-24 18:50:12 -040042import android.os.Build;
Ryan Lothian4a86a512017-12-04 11:56:58 -050043import android.os.Handler;
John Spurlock7340fc82014-04-24 18:50:12 -040044import android.os.IBinder;
45import android.os.IInterface;
Ryan Lothian4a86a512017-12-04 11:56:58 -050046import android.os.Looper;
John Spurlock7340fc82014-04-24 18:50:12 -040047import android.os.RemoteException;
48import android.os.UserHandle;
49import android.os.UserManager;
50import android.provider.Settings;
Kweku Adams93304b62017-09-20 17:03:00 -070051import android.service.notification.ManagedServiceInfoProto;
52import android.service.notification.ManagedServicesProto;
53import android.service.notification.ManagedServicesProto.ServiceProto;
John Spurlock7340fc82014-04-24 18:50:12 -040054import android.text.TextUtils;
Julia Reynoldsb852e562017-06-06 16:14:18 -040055import android.util.ArrayMap;
John Spurlock7340fc82014-04-24 18:50:12 -040056import android.util.ArraySet;
Julia Reynoldsca8e5352018-09-18 13:39:26 -040057import android.util.IntArray;
John Spurlock4db0d982014-08-13 09:19:03 -040058import android.util.Log;
Andrew Zeng190c0672018-06-28 15:15:05 -070059import android.util.Pair;
John Spurlock7340fc82014-04-24 18:50:12 -040060import android.util.Slog;
61import android.util.SparseArray;
Kweku Adams93304b62017-09-20 17:03:00 -070062import android.util.proto.ProtoOutputStream;
John Spurlock7340fc82014-04-24 18:50:12 -040063
Julia Reynoldsca8e5352018-09-18 13:39:26 -040064import com.android.internal.annotations.GuardedBy;
65import com.android.internal.annotations.VisibleForTesting;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -040066import com.android.internal.util.XmlUtils;
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -050067import com.android.internal.util.function.TriPredicate;
John Spurlock25e2d242014-06-27 13:58:23 -040068import com.android.server.notification.NotificationManagerService.DumpFilter;
69
Julia Reynoldsb852e562017-06-06 16:14:18 -040070import org.xmlpull.v1.XmlPullParser;
71import org.xmlpull.v1.XmlPullParserException;
72import org.xmlpull.v1.XmlSerializer;
73
74import java.io.IOException;
John Spurlock7340fc82014-04-24 18:50:12 -040075import java.io.PrintWriter;
76import java.util.ArrayList;
John Spurlocke77bb362014-04-26 10:24:59 -040077import java.util.Arrays;
Julia Reynolds9a86cc02016-02-10 15:38:15 -050078import java.util.HashSet;
John Spurlock7340fc82014-04-24 18:50:12 -040079import java.util.List;
Julia Reynoldsca8e5352018-09-18 13:39:26 -040080import java.util.Objects;
John Spurlock7340fc82014-04-24 18:50:12 -040081import java.util.Set;
82
83/**
84 * Manages the lifecycle of application-provided services bound by system server.
85 *
86 * Services managed by this helper must have:
87 * - An associated system settings value with a list of enabled component names.
88 * - A well-known action for services to use in their intent-filter.
89 * - A system permission for services to require in order to ensure system has exclusive binding.
90 * - A settings page for user configuration of enabled services, and associated intent action.
91 * - A remote interface definition (aidl) provided by the service used for communication.
92 */
93abstract public class ManagedServices {
94 protected final String TAG = getClass().getSimpleName();
John Spurlock4db0d982014-08-13 09:19:03 -040095 protected final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
John Spurlock7340fc82014-04-24 18:50:12 -040096
Ryan Lothian4a86a512017-12-04 11:56:58 -050097 private static final int ON_BINDING_DIED_REBIND_DELAY_MS = 10000;
Julia Reynoldsc279b992015-10-30 08:23:51 -040098 protected static final String ENABLED_SERVICES_SEPARATOR = ":";
John Spurlock7340fc82014-04-24 18:50:12 -040099
Julia Reynoldsb852e562017-06-06 16:14:18 -0400100 /**
101 * List of components and apps that can have running {@link ManagedServices}.
102 */
103 static final String TAG_MANAGED_SERVICES = "service_listing";
104 static final String ATT_APPROVED_LIST = "approved";
105 static final String ATT_USER_ID = "user";
106 static final String ATT_IS_PRIMARY = "primary";
Julia Reynolds7380d872018-01-12 10:28:26 -0500107 static final String ATT_VERSION = "version";
Jay Aliomer4204f252019-08-26 11:36:53 -0400108 static final String ATT_DEFAULTS = "defaults";
Julia Reynolds7380d872018-01-12 10:28:26 -0500109
110 static final int DB_VERSION = 1;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400111
112 static final int APPROVAL_BY_PACKAGE = 0;
113 static final int APPROVAL_BY_COMPONENT = 1;
114
John Spurlockaf8d6c42014-05-07 17:49:08 -0400115 protected final Context mContext;
John Spurlocke77bb362014-04-26 10:24:59 -0400116 protected final Object mMutex;
John Spurlock7340fc82014-04-24 18:50:12 -0400117 private final UserProfiles mUserProfiles;
Julia Reynoldsa75c7522017-03-21 17:34:25 -0400118 private final IPackageManager mPm;
Julia Reynoldsd6d5a592018-04-02 11:03:32 -0400119 protected final UserManager mUm;
John Spurlock7340fc82014-04-24 18:50:12 -0400120 private final Config mConfig;
Ryan Lothian4a86a512017-12-04 11:56:58 -0500121 private final Handler mHandler = new Handler(Looper.getMainLooper());
John Spurlock7340fc82014-04-24 18:50:12 -0400122
123 // contains connections to all connected services, including app services
124 // and system services
Julia Reynoldsb852e562017-06-06 16:14:18 -0400125 private final ArrayList<ManagedServiceInfo> mServices = new ArrayList<>();
Andrew Zeng190c0672018-06-28 15:15:05 -0700126 /**
127 * The services that have been bound by us. If the service is also connected, it will also
128 * be in {@link #mServices}.
129 */
130 private final ArrayList<Pair<ComponentName, Integer>> mServicesBound = new ArrayList<>();
131 private final ArraySet<Pair<ComponentName, Integer>> mServicesRebinding = new ArraySet<>();
Jay Aliomer4204f252019-08-26 11:36:53 -0400132 // we need these packages to be protected because classes that inherit from it need to see it
133 protected final Object mDefaultsLock = new Object();
134 protected final ArraySet<ComponentName> mDefaultComponents = new ArraySet<>();
135 protected final ArraySet<String> mDefaultPackages = new ArraySet<>();
Ryan Lothian4a86a512017-12-04 11:56:58 -0500136
Chris Wrenab41eec2016-01-04 18:01:27 -0500137 // lists the component names of all enabled (and therefore potentially connected)
John Spurlock7340fc82014-04-24 18:50:12 -0400138 // app services for current profiles.
139 private ArraySet<ComponentName> mEnabledServicesForCurrentProfiles
Julia Reynoldsb852e562017-06-06 16:14:18 -0400140 = new ArraySet<>();
John Spurlock7340fc82014-04-24 18:50:12 -0400141 // Just the packages from mEnabledServicesForCurrentProfiles
Julia Reynoldsb852e562017-06-06 16:14:18 -0400142 private ArraySet<String> mEnabledServicesPackageNames = new ArraySet<>();
Chris Wrenab41eec2016-01-04 18:01:27 -0500143 // List of enabled packages that have nevertheless asked not to be run
144 private ArraySet<ComponentName> mSnoozingForCurrentProfiles = new ArraySet<>();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200145
Julia Reynoldsb852e562017-06-06 16:14:18 -0400146 // List of approved packages or components (by user, then by primary/secondary) that are
147 // allowed to be bound as managed services. A package or component appearing in this list does
148 // not mean that we are currently bound to said package/component.
149 private ArrayMap<Integer, ArrayMap<Boolean, ArraySet<String>>> mApproved = new ArrayMap<>();
John Spurlock7340fc82014-04-24 18:50:12 -0400150
Julia Reynoldsb852e562017-06-06 16:14:18 -0400151 // True if approved services are stored in xml, not settings.
152 private boolean mUseXml;
Christopher Tate6597e342015-02-17 12:15:25 -0800153
Julia Reynoldsb852e562017-06-06 16:14:18 -0400154 // Whether managed services are approved individually or package wide
155 protected int mApprovalLevel;
156
157 public ManagedServices(Context context, Object mutex, UserProfiles userProfiles,
158 IPackageManager pm) {
John Spurlock7340fc82014-04-24 18:50:12 -0400159 mContext = context;
160 mMutex = mutex;
161 mUserProfiles = userProfiles;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400162 mPm = pm;
John Spurlock7340fc82014-04-24 18:50:12 -0400163 mConfig = getConfig();
Julia Reynoldsb852e562017-06-06 16:14:18 -0400164 mApprovalLevel = APPROVAL_BY_COMPONENT;
Julia Reynolds45523002017-09-12 09:43:57 -0400165 mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
John Spurlock7340fc82014-04-24 18:50:12 -0400166 }
167
168 abstract protected Config getConfig();
169
170 private String getCaption() {
171 return mConfig.caption;
172 }
173
174 abstract protected IInterface asInterface(IBinder binder);
175
Chris Wren51017d02015-12-15 15:34:46 -0500176 abstract protected boolean checkType(IInterface service);
177
John Spurlock3b98b3f2014-05-01 09:08:48 -0400178 abstract protected void onServiceAdded(ManagedServiceInfo info);
John Spurlock7340fc82014-04-24 18:50:12 -0400179
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400180 protected List<ManagedServiceInfo> getServices() {
181 synchronized (mMutex) {
182 List<ManagedServiceInfo> services = new ArrayList<>(mServices);
183 return services;
184 }
185 }
186
Jay Aliomer4204f252019-08-26 11:36:53 -0400187 protected void addDefaultComponentOrPackage(String packageOrComponent) {
Julia Reynolds57a974b2019-10-07 11:51:47 -0400188 if (!TextUtils.isEmpty(packageOrComponent)) {
Jay Aliomer4204f252019-08-26 11:36:53 -0400189 synchronized (mDefaultsLock) {
190 ComponentName cn = ComponentName.unflattenFromString(packageOrComponent);
191 if (cn == null) {
192 mDefaultPackages.add(packageOrComponent);
193 } else {
194 mDefaultPackages.add(cn.getPackageName());
195 mDefaultComponents.add(cn);
196 }
197 }
198 }
199 }
200
201 boolean isDefaultComponentOrPackage(String packageOrComponent) {
202 synchronized (mDefaultsLock) {
203 ComponentName cn = ComponentName.unflattenFromString(packageOrComponent);
204 if (cn == null) {
205 return mDefaultPackages.contains(packageOrComponent);
206 } else {
207 return mDefaultComponents.contains(cn);
208 }
209 }
210 }
211
212 ArraySet<ComponentName> getDefaultComponents() {
213 synchronized (mDefaultsLock) {
214 return new ArraySet<>(mDefaultComponents);
215 }
216 }
217
218 ArraySet<String> getDefaultPackages() {
219 synchronized (mDefaultsLock) {
220 return new ArraySet<>(mDefaultPackages);
221 }
222 }
223
224 /**
225 * When resetting a package, we need to enable default components that belong to that packages
226 * we also need to disable components that are not default to return the managed service state
227 * to when a new android device is first turned on for that package.
228 *
229 * @param packageName package to reset.
230 * @param userId the android user id
231 * @return a list of components that were permitted
232 */
233 @NonNull
234 ArrayMap<Boolean, ArrayList<ComponentName>> resetComponents(String packageName, int userId) {
235 // components that we want to enable
236 ArrayList<ComponentName> componentsToEnable =
237 new ArrayList<>(mDefaultComponents.size());
238
239 // components that were removed
240 ArrayList<ComponentName> disabledComponents =
241 new ArrayList<>(mDefaultComponents.size());
242
243 // all components that are enabled now
244 ArraySet<ComponentName> enabledComponents =
245 new ArraySet<>(getAllowedComponents(userId));
246
247 boolean changed = false;
248
249 synchronized (mDefaultsLock) {
250 // record all components that are enabled but should not be by default
251 for (int i = 0; i < mDefaultComponents.size() && enabledComponents.size() > 0; i++) {
252 ComponentName currentDefault = mDefaultComponents.valueAt(i);
253 if (packageName.equals(currentDefault.getPackageName())
254 && !enabledComponents.contains(currentDefault)) {
255 componentsToEnable.add(currentDefault);
256 }
257 }
258 synchronized (mApproved) {
259 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(
260 userId);
261 if (approvedByType != null) {
262 final int M = approvedByType.size();
263 for (int j = 0; j < M; j++) {
264 final ArraySet<String> approved = approvedByType.valueAt(j);
265 for (int i = 0; i < enabledComponents.size(); i++) {
266 ComponentName currentComponent = enabledComponents.valueAt(i);
267 if (packageName.equals(currentComponent.getPackageName())
268 && !mDefaultComponents.contains(currentComponent)) {
269 if (approved.remove(currentComponent.flattenToString())) {
270 disabledComponents.add(currentComponent);
271 changed = true;
272 }
273 }
274 }
275 for (int i = 0; i < componentsToEnable.size(); i++) {
276 ComponentName candidate = componentsToEnable.get(i);
277 changed |= approved.add(candidate.flattenToString());
278 }
279 }
280
281 }
282 }
283 }
284 if (changed) rebindServices(false, USER_ALL);
285
286 ArrayMap<Boolean, ArrayList<ComponentName>> changes = new ArrayMap<>();
287 changes.put(true, componentsToEnable);
288 changes.put(false, disabledComponents);
289
290 return changes;
291 }
292
Amith Yamasanie5bfeee2018-09-05 18:52:35 -0700293 protected int getBindFlags() {
294 return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE | BIND_ALLOW_WHITELIST_MANAGEMENT;
295 }
296
John Spurlocke77bb362014-04-26 10:24:59 -0400297 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { }
298
John Spurlock7340fc82014-04-24 18:50:12 -0400299 private ManagedServiceInfo newServiceInfo(IInterface service,
Julia Reynoldsb852e562017-06-06 16:14:18 -0400300 ComponentName component, int userId, boolean isSystem, ServiceConnection connection,
John Spurlock7340fc82014-04-24 18:50:12 -0400301 int targetSdkVersion) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400302 return new ManagedServiceInfo(service, component, userId, isSystem, connection,
John Spurlock7340fc82014-04-24 18:50:12 -0400303 targetSdkVersion);
304 }
305
Julia Reynoldsb852e562017-06-06 16:14:18 -0400306 public void onBootPhaseAppsCanStart() {}
John Spurlock7340fc82014-04-24 18:50:12 -0400307
John Spurlock25e2d242014-06-27 13:58:23 -0400308 public void dump(PrintWriter pw, DumpFilter filter) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400309 pw.println(" Allowed " + getCaption() + "s:");
Julia Reynoldsb776e392019-07-25 12:36:14 -0400310 synchronized (mApproved) {
311 final int N = mApproved.size();
312 for (int i = 0; i < N; i++) {
313 final int userId = mApproved.keyAt(i);
314 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
315 if (approvedByType != null) {
316 final int M = approvedByType.size();
317 for (int j = 0; j < M; j++) {
318 final boolean isPrimary = approvedByType.keyAt(j);
319 final ArraySet<String> approved = approvedByType.valueAt(j);
320 if (approvedByType != null && approvedByType.size() > 0) {
321 pw.println(" " + String.join(ENABLED_SERVICES_SEPARATOR, approved)
322 + " (user: " + userId + " isPrimary: " + isPrimary + ")");
323 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400324 }
325 }
326 }
327 }
328
John Spurlocke77bb362014-04-26 10:24:59 -0400329 pw.println(" All " + getCaption() + "s (" + mEnabledServicesForCurrentProfiles.size()
John Spurlock7340fc82014-04-24 18:50:12 -0400330 + ") enabled for current profiles:");
331 for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
John Spurlock25e2d242014-06-27 13:58:23 -0400332 if (filter != null && !filter.matches(cmpt)) continue;
John Spurlocke77bb362014-04-26 10:24:59 -0400333 pw.println(" " + cmpt);
John Spurlock7340fc82014-04-24 18:50:12 -0400334 }
335
John Spurlocke77bb362014-04-26 10:24:59 -0400336 pw.println(" Live " + getCaption() + "s (" + mServices.size() + "):");
Julia Reynolds3ff1fd92018-08-29 09:57:11 -0400337 synchronized (mMutex) {
338 for (ManagedServiceInfo info : mServices) {
339 if (filter != null && !filter.matches(info.component)) continue;
340 pw.println(" " + info.component
341 + " (user " + info.userid + "): " + info.service
342 + (info.isSystem ? " SYSTEM" : "")
343 + (info.isGuest(this) ? " GUEST" : ""));
344 }
John Spurlock7340fc82014-04-24 18:50:12 -0400345 }
Chris Wrenab41eec2016-01-04 18:01:27 -0500346
347 pw.println(" Snoozed " + getCaption() + "s (" +
348 mSnoozingForCurrentProfiles.size() + "):");
349 for (ComponentName name : mSnoozingForCurrentProfiles) {
350 pw.println(" " + name.flattenToShortString());
351 }
John Spurlock7340fc82014-04-24 18:50:12 -0400352 }
353
Kweku Adams93304b62017-09-20 17:03:00 -0700354 public void dump(ProtoOutputStream proto, DumpFilter filter) {
355 proto.write(ManagedServicesProto.CAPTION, getCaption());
Julia Reynoldsb776e392019-07-25 12:36:14 -0400356 synchronized (mApproved) {
357 final int N = mApproved.size();
358 for (int i = 0; i < N; i++) {
359 final int userId = mApproved.keyAt(i);
360 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
361 if (approvedByType != null) {
362 final int M = approvedByType.size();
363 for (int j = 0; j < M; j++) {
364 final boolean isPrimary = approvedByType.keyAt(j);
365 final ArraySet<String> approved = approvedByType.valueAt(j);
366 if (approvedByType != null && approvedByType.size() > 0) {
367 final long sToken = proto.start(ManagedServicesProto.APPROVED);
368 for (String s : approved) {
369 proto.write(ServiceProto.NAME, s);
370 }
371 proto.write(ServiceProto.USER_ID, userId);
372 proto.write(ServiceProto.IS_PRIMARY, isPrimary);
373 proto.end(sToken);
Kweku Adams93304b62017-09-20 17:03:00 -0700374 }
Kweku Adams93304b62017-09-20 17:03:00 -0700375 }
376 }
377 }
378 }
379
380 for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
381 if (filter != null && !filter.matches(cmpt)) continue;
Jeffrey Huangcb782852019-12-05 11:28:11 -0800382 cmpt.dumpDebug(proto, ManagedServicesProto.ENABLED);
Kweku Adams93304b62017-09-20 17:03:00 -0700383 }
384
Julia Reynolds3ff1fd92018-08-29 09:57:11 -0400385 synchronized (mMutex) {
386 for (ManagedServiceInfo info : mServices) {
387 if (filter != null && !filter.matches(info.component)) continue;
Jeffrey Huangcb782852019-12-05 11:28:11 -0800388 info.dumpDebug(proto, ManagedServicesProto.LIVE_SERVICES, this);
Julia Reynolds3ff1fd92018-08-29 09:57:11 -0400389 }
Kweku Adams93304b62017-09-20 17:03:00 -0700390 }
391
392 for (ComponentName name : mSnoozingForCurrentProfiles) {
Jeffrey Huangcb782852019-12-05 11:28:11 -0800393 name.dumpDebug(proto, ManagedServicesProto.SNOOZED);
Kweku Adams93304b62017-09-20 17:03:00 -0700394 }
395 }
396
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400397 protected void onSettingRestored(String element, String value, int backupSdkInt, int userId) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400398 if (!mUseXml) {
399 Slog.d(TAG, "Restored managed service setting: " + element);
400 if (mConfig.secureSettingName.equals(element) ||
401 (mConfig.secondarySettingName != null
402 && mConfig.secondarySettingName.equals(element))) {
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400403 if (backupSdkInt < Build.VERSION_CODES.O) {
404 // automatic system grants were added in O, so append the approved apps
405 // rather than wiping out the setting
406 String currentSetting =
407 getApproved(userId, mConfig.secureSettingName.equals(element));
408 if (!TextUtils.isEmpty(currentSetting)) {
409 if (!TextUtils.isEmpty(value)) {
410 value = value + ENABLED_SERVICES_SEPARATOR + currentSetting;
411 } else {
412 value = currentSetting;
413 }
414 }
415 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400416 Settings.Secure.putStringForUser(
417 mContext.getContentResolver(), element, value, userId);
418 loadAllowedComponentsFromSettings();
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400419 rebindServices(false, userId);
Christopher Tate6597e342015-02-17 12:15:25 -0800420 }
421 }
422 }
423
Jay Aliomer4204f252019-08-26 11:36:53 -0400424 void writeDefaults(XmlSerializer out) throws IOException {
425 synchronized (mDefaultsLock) {
426 List<String> componentStrings = new ArrayList<>(mDefaultComponents.size());
427 for (int i = 0; i < mDefaultComponents.size(); i++) {
428 componentStrings.add(mDefaultComponents.valueAt(i).flattenToString());
429 }
430 String defaults = String.join(ENABLED_SERVICES_SEPARATOR, componentStrings);
431 out.attribute(null, ATT_DEFAULTS, defaults);
432 }
433 }
434
Annie Meng8b646fd2019-02-01 18:46:42 +0000435 public void writeXml(XmlSerializer out, boolean forBackup, int userId) throws IOException {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400436 out.startTag(null, getConfig().xmlTag);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400437
Julia Reynolds7380d872018-01-12 10:28:26 -0500438 out.attribute(null, ATT_VERSION, String.valueOf(DB_VERSION));
439
Jay Aliomer4204f252019-08-26 11:36:53 -0400440 writeDefaults(out);
441
Julia Reynoldsb852e562017-06-06 16:14:18 -0400442 if (forBackup) {
Annie Meng8b646fd2019-02-01 18:46:42 +0000443 trimApprovedListsAccordingToInstalledServices(userId);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400444 }
445
Julia Reynoldsb776e392019-07-25 12:36:14 -0400446 synchronized (mApproved) {
447 final int N = mApproved.size();
448 for (int i = 0; i < N; i++) {
449 final int approvedUserId = mApproved.keyAt(i);
450 if (forBackup && approvedUserId != userId) {
451 continue;
452 }
453 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
454 if (approvedByType != null) {
455 final int M = approvedByType.size();
456 for (int j = 0; j < M; j++) {
457 final boolean isPrimary = approvedByType.keyAt(j);
458 final Set<String> approved = approvedByType.valueAt(j);
459 if (approved != null) {
460 String allowedItems = String.join(ENABLED_SERVICES_SEPARATOR, approved);
461 out.startTag(null, TAG_MANAGED_SERVICES);
462 out.attribute(null, ATT_APPROVED_LIST, allowedItems);
463 out.attribute(null, ATT_USER_ID, Integer.toString(approvedUserId));
464 out.attribute(null, ATT_IS_PRIMARY, Boolean.toString(isPrimary));
465 writeExtraAttributes(out, approvedUserId);
466 out.endTag(null, TAG_MANAGED_SERVICES);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400467
Julia Reynoldsb776e392019-07-25 12:36:14 -0400468 if (!forBackup && isPrimary) {
469 // Also write values to settings, for observers who haven't migrated yet
470 Settings.Secure.putStringForUser(mContext.getContentResolver(),
471 getConfig().secureSettingName, allowedItems,
472 approvedUserId);
473 }
474
Julia Reynoldsb852e562017-06-06 16:14:18 -0400475 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400476 }
477 }
478 }
479 }
Julia Reynoldsad6dd352019-03-07 16:46:22 -0500480
481 writeExtraXmlTags(out);
482
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400483 out.endTag(null, getConfig().xmlTag);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400484 }
485
Tony Mak9a3c1f12019-03-04 16:04:42 +0000486 /**
487 * Writes extra xml attributes to {@link #TAG_MANAGED_SERVICES} tag.
488 */
489 protected void writeExtraAttributes(XmlSerializer out, int userId) throws IOException {}
490
Julia Reynoldsad6dd352019-03-07 16:46:22 -0500491 /**
492 * Writes extra xml tags within the parent tag specified in {@link Config#xmlTag}.
493 */
494 protected void writeExtraXmlTags(XmlSerializer out) throws IOException {}
495
496 /**
497 * This is called to process tags other than {@link #TAG_MANAGED_SERVICES}.
498 */
499 protected void readExtraTag(String tag, XmlPullParser parser) throws IOException {}
500
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400501 protected void migrateToXml() {
502 loadAllowedComponentsFromSettings();
503 }
504
Jay Aliomer4204f252019-08-26 11:36:53 -0400505 void readDefaults(XmlPullParser parser) {
506 String defaultComponents = XmlUtils.readStringAttribute(parser, ATT_DEFAULTS);
507 if (defaultComponents == null) {
508 return;
509 }
510 String[] components = defaultComponents.split(ENABLED_SERVICES_SEPARATOR);
511 synchronized (mDefaultsLock) {
512 for (int i = 0; i < components.length; i++) {
513 if (!TextUtils.isEmpty(components[i])) {
514 ComponentName cn = ComponentName.unflattenFromString(components[i]);
515 if (cn != null) {
516 mDefaultPackages.add(cn.getPackageName());
517 mDefaultComponents.add(cn);
518 } else {
519 mDefaultPackages.add(components[i]);
520 }
521 }
522 }
523 }
524 }
525
Annie Meng8b646fd2019-02-01 18:46:42 +0000526 public void readXml(
527 XmlPullParser parser,
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -0500528 TriPredicate<String, Integer, String> allowedManagedServicePackages,
Annie Meng8b646fd2019-02-01 18:46:42 +0000529 boolean forRestore,
530 int userId)
Julia Reynoldsb852e562017-06-06 16:14:18 -0400531 throws XmlPullParserException, IOException {
Julia Reynolds7380d872018-01-12 10:28:26 -0500532 // read grants
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400533 int type;
Jay Aliomer4204f252019-08-26 11:36:53 -0400534 readDefaults(parser);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400535 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
536 String tag = parser.getName();
537 if (type == XmlPullParser.END_TAG
538 && getConfig().xmlTag.equals(tag)) {
539 break;
540 }
541 if (type == XmlPullParser.START_TAG) {
542 if (TAG_MANAGED_SERVICES.equals(tag)) {
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400543 Slog.i(TAG, "Read " + mConfig.caption + " permissions from xml");
Julia Reynolds7380d872018-01-12 10:28:26 -0500544
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400545 final String approved = XmlUtils.readStringAttribute(parser, ATT_APPROVED_LIST);
Annie Meng8b646fd2019-02-01 18:46:42 +0000546 // Ignore parser's user id for restore.
547 final int resolvedUserId = forRestore
548 ? userId : XmlUtils.readIntAttribute(parser, ATT_USER_ID, 0);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400549 final boolean isPrimary =
550 XmlUtils.readBooleanAttribute(parser, ATT_IS_PRIMARY, true);
Tony Mak9a3c1f12019-03-04 16:04:42 +0000551 readExtraAttributes(tag, parser, resolvedUserId);
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -0500552 if (allowedManagedServicePackages == null || allowedManagedServicePackages.test(
553 getPackageName(approved), resolvedUserId, getRequiredPermission())) {
Annie Meng8b646fd2019-02-01 18:46:42 +0000554 if (mUm.getUserInfo(resolvedUserId) != null) {
555 addApprovedList(approved, resolvedUserId, isPrimary);
Kristian Monsen05f34792018-04-09 10:27:16 +0200556 }
557 mUseXml = true;
Julia Reynolds45523002017-09-12 09:43:57 -0400558 }
Julia Reynoldsad6dd352019-03-07 16:46:22 -0500559 } else {
560 readExtraTag(tag, parser);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400561 }
562 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400563 }
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400564 rebindServices(false, USER_ALL);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400565 }
566
Tony Mak9a3c1f12019-03-04 16:04:42 +0000567 /**
568 * Read extra attributes in the {@link #TAG_MANAGED_SERVICES} tag.
569 */
570 protected void readExtraAttributes(String tag, XmlPullParser parser, int userId)
571 throws IOException {}
572
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -0500573 protected abstract String getRequiredPermission();
574
Julia Reynoldsb852e562017-06-06 16:14:18 -0400575 private void loadAllowedComponentsFromSettings() {
Julia Reynoldse0d711f2017-09-01 08:50:47 -0400576 for (UserInfo user : mUm.getUsers()) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400577 final ContentResolver cr = mContext.getContentResolver();
578 addApprovedList(Settings.Secure.getStringForUser(
579 cr,
580 getConfig().secureSettingName,
581 user.id), user.id, true);
582 if (!TextUtils.isEmpty(getConfig().secondarySettingName)) {
583 addApprovedList(Settings.Secure.getStringForUser(
584 cr,
585 getConfig().secondarySettingName,
586 user.id), user.id, false);
587 }
588 }
589 Slog.d(TAG, "Done loading approved values from settings");
590 }
591
Julia Reynolds7380d872018-01-12 10:28:26 -0500592 protected void addApprovedList(String approved, int userId, boolean isPrimary) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400593 if (TextUtils.isEmpty(approved)) {
594 approved = "";
595 }
Julia Reynoldsb776e392019-07-25 12:36:14 -0400596 synchronized (mApproved) {
597 ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
598 if (approvedByType == null) {
599 approvedByType = new ArrayMap<>();
600 mApproved.put(userId, approvedByType);
601 }
Artem Iglikovbec96172018-04-24 12:46:44 +0100602
Julia Reynoldsb776e392019-07-25 12:36:14 -0400603 ArraySet<String> approvedList = approvedByType.get(isPrimary);
604 if (approvedList == null) {
605 approvedList = new ArraySet<>();
606 approvedByType.put(isPrimary, approvedList);
607 }
Artem Iglikovbec96172018-04-24 12:46:44 +0100608
Julia Reynoldsb776e392019-07-25 12:36:14 -0400609 String[] approvedArray = approved.split(ENABLED_SERVICES_SEPARATOR);
610 for (String pkgOrComponent : approvedArray) {
611 String approvedItem = getApprovedValue(pkgOrComponent);
612 if (approvedItem != null) {
613 approvedList.add(approvedItem);
614 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400615 }
616 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400617 }
618
619 protected boolean isComponentEnabledForPackage(String pkg) {
John Spurlock80774932015-05-07 17:38:50 -0400620 return mEnabledServicesPackageNames.contains(pkg);
621 }
622
Julia Reynoldsb852e562017-06-06 16:14:18 -0400623 protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId,
624 boolean isPrimary, boolean enabled) {
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400625 Slog.i(TAG,
626 (enabled ? " Allowing " : "Disallowing ") + mConfig.caption + " " + pkgOrComponent);
Julia Reynoldsb776e392019-07-25 12:36:14 -0400627 synchronized (mApproved) {
628 ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.get(userId);
629 if (allowedByType == null) {
630 allowedByType = new ArrayMap<>();
631 mApproved.put(userId, allowedByType);
632 }
633 ArraySet<String> approved = allowedByType.get(isPrimary);
634 if (approved == null) {
635 approved = new ArraySet<>();
636 allowedByType.put(isPrimary, approved);
637 }
638 String approvedItem = getApprovedValue(pkgOrComponent);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200639
Julia Reynoldsb776e392019-07-25 12:36:14 -0400640 if (approvedItem != null) {
641 if (enabled) {
642 approved.add(approvedItem);
643 } else {
644 approved.remove(approvedItem);
645 }
John Spurlock7340fc82014-04-24 18:50:12 -0400646 }
647 }
648
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400649 rebindServices(false, userId);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400650 }
651
652 private String getApprovedValue(String pkgOrComponent) {
653 if (mApprovalLevel == APPROVAL_BY_COMPONENT) {
654 if(ComponentName.unflattenFromString(pkgOrComponent) != null) {
655 return pkgOrComponent;
John Spurlock7340fc82014-04-24 18:50:12 -0400656 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400657 return null;
658 } else {
659 return getPackageName(pkgOrComponent);
660 }
661 }
662
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400663 protected String getApproved(int userId, boolean primary) {
Julia Reynoldsb776e392019-07-25 12:36:14 -0400664 synchronized (mApproved) {
665 final ArrayMap<Boolean, ArraySet<String>> allowedByType =
666 mApproved.getOrDefault(userId, new ArrayMap<>());
667 ArraySet<String> approved = allowedByType.getOrDefault(primary, new ArraySet<>());
668 return String.join(ENABLED_SERVICES_SEPARATOR, approved);
669 }
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400670 }
671
Julia Reynoldsb852e562017-06-06 16:14:18 -0400672 protected List<ComponentName> getAllowedComponents(int userId) {
673 final List<ComponentName> allowedComponents = new ArrayList<>();
Julia Reynoldsb776e392019-07-25 12:36:14 -0400674 synchronized (mApproved) {
675 final ArrayMap<Boolean, ArraySet<String>> allowedByType =
676 mApproved.getOrDefault(userId, new ArrayMap<>());
677 for (int i = 0; i < allowedByType.size(); i++) {
678 final ArraySet<String> allowed = allowedByType.valueAt(i);
679 for (int j = 0; j < allowed.size(); j++) {
680 ComponentName cn = ComponentName.unflattenFromString(allowed.valueAt(j));
681 if (cn != null) {
682 allowedComponents.add(cn);
683 }
Julia Reynolds2f496962018-04-16 13:17:01 -0400684 }
685 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400686 }
687 return allowedComponents;
688 }
689
690 protected List<String> getAllowedPackages(int userId) {
691 final List<String> allowedPackages = new ArrayList<>();
Julia Reynoldsb776e392019-07-25 12:36:14 -0400692 synchronized (mApproved) {
693 final ArrayMap<Boolean, ArraySet<String>> allowedByType =
694 mApproved.getOrDefault(userId, new ArrayMap<>());
695 for (int i = 0; i < allowedByType.size(); i++) {
696 final ArraySet<String> allowed = allowedByType.valueAt(i);
697 for (int j = 0; j < allowed.size(); j++) {
698 String pkgName = getPackageName(allowed.valueAt(j));
699 if (!TextUtils.isEmpty(pkgName)) {
700 allowedPackages.add(pkgName);
701 }
Julia Reynolds2f496962018-04-16 13:17:01 -0400702 }
703 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400704 }
705 return allowedPackages;
706 }
707
708 protected boolean isPackageOrComponentAllowed(String pkgOrComponent, int userId) {
Julia Reynoldsb776e392019-07-25 12:36:14 -0400709 synchronized (mApproved) {
710 ArrayMap<Boolean, ArraySet<String>> allowedByType =
711 mApproved.getOrDefault(userId, new ArrayMap<>());
712 for (int i = 0; i < allowedByType.size(); i++) {
713 ArraySet<String> allowed = allowedByType.valueAt(i);
714 if (allowed.contains(pkgOrComponent)) {
715 return true;
716 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400717 }
718 }
719 return false;
720 }
721
Julia Reynolds14590742018-07-30 09:25:35 -0400722 protected boolean isPackageAllowed(String pkg, int userId) {
723 if (pkg == null) {
724 return false;
725 }
Julia Reynoldsb776e392019-07-25 12:36:14 -0400726 synchronized (mApproved) {
727 ArrayMap<Boolean, ArraySet<String>> allowedByType =
728 mApproved.getOrDefault(userId, new ArrayMap<>());
729 for (int i = 0; i < allowedByType.size(); i++) {
730 ArraySet<String> allowed = allowedByType.valueAt(i);
731 for (String allowedEntry : allowed) {
732 ComponentName component = ComponentName.unflattenFromString(allowedEntry);
733 if (component != null) {
734 if (pkg.equals(component.getPackageName())) {
735 return true;
736 }
737 } else {
738 if (pkg.equals(allowedEntry)) {
739 return true;
740 }
Julia Reynolds14590742018-07-30 09:25:35 -0400741 }
742 }
743 }
744 }
745 return false;
746 }
747
Julia Reynoldsb852e562017-06-06 16:14:18 -0400748 public void onPackagesChanged(boolean removingPackage, String[] pkgList, int[] uidList) {
749 if (DEBUG) Slog.d(TAG, "onPackagesChanged removingPackage=" + removingPackage
750 + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList))
751 + " mEnabledServicesPackageNames=" + mEnabledServicesPackageNames);
752
753 if (pkgList != null && (pkgList.length > 0)) {
754 boolean anyServicesInvolved = false;
755 // Remove notification settings for uninstalled package
Beverly42d01902019-01-03 12:47:57 -0500756 if (removingPackage && uidList != null) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400757 int size = Math.min(pkgList.length, uidList.length);
758 for (int i = 0; i < size; i++) {
759 final String pkg = pkgList[i];
760 final int userId = UserHandle.getUserId(uidList[i]);
761 anyServicesInvolved = removeUninstalledItemsFromApprovedLists(userId, pkg);
762 }
763 }
764 for (String pkgName : pkgList) {
765 if (mEnabledServicesPackageNames.contains(pkgName)) {
766 anyServicesInvolved = true;
767 }
Beverly42d01902019-01-03 12:47:57 -0500768 if (uidList != null && uidList.length > 0) {
769 for (int uid : uidList) {
770 if (isPackageAllowed(pkgName, UserHandle.getUserId(uid))) {
771 anyServicesInvolved = true;
772 }
Julia Reynolds14590742018-07-30 09:25:35 -0400773 }
774 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400775 }
776
777 if (anyServicesInvolved) {
778 // make sure we're still bound to any of our services who may have just upgraded
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400779 rebindServices(false, USER_ALL);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400780 }
John Spurlock7340fc82014-04-24 18:50:12 -0400781 }
782 }
783
Julia Reynolds5aa13a42017-08-24 09:10:23 -0400784 public void onUserRemoved(int user) {
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400785 Slog.i(TAG, "Removing approved services for removed user " + user);
Julia Reynoldsb776e392019-07-25 12:36:14 -0400786 synchronized (mApproved) {
787 mApproved.remove(user);
788 }
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400789 rebindServices(true, user);
Julia Reynolds5aa13a42017-08-24 09:10:23 -0400790 }
791
John Spurlock1b8b22b2015-05-20 09:47:13 -0400792 public void onUserSwitched(int user) {
793 if (DEBUG) Slog.d(TAG, "onUserSwitched u=" + user);
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400794 rebindServices(true, user);
Christoph Studerb53dfd42014-09-12 14:45:59 +0200795 }
796
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500797 public void onUserUnlocked(int user) {
798 if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400799 rebindServices(false, user);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500800 }
801
Julia Reynoldsb852e562017-06-06 16:14:18 -0400802 private ManagedServiceInfo getServiceFromTokenLocked(IInterface service) {
Chris Wrenab41eec2016-01-04 18:01:27 -0500803 if (service == null) {
804 return null;
805 }
John Spurlock7340fc82014-04-24 18:50:12 -0400806 final IBinder token = service.asBinder();
807 final int N = mServices.size();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200808 for (int i = 0; i < N; i++) {
John Spurlock7340fc82014-04-24 18:50:12 -0400809 final ManagedServiceInfo info = mServices.get(i);
810 if (info.service.asBinder() == token) return info;
811 }
Chris Wrenab41eec2016-01-04 18:01:27 -0500812 return null;
813 }
814
Julia Reynolds503ed942017-10-04 16:04:56 -0400815 protected boolean isServiceTokenValidLocked(IInterface service) {
816 if (service == null) {
817 return false;
818 }
819 ManagedServiceInfo info = getServiceFromTokenLocked(service);
820 if (info != null) {
821 return true;
822 }
823 return false;
824 }
825
Julia Reynoldsb852e562017-06-06 16:14:18 -0400826 protected ManagedServiceInfo checkServiceTokenLocked(IInterface service) {
Chris Wrenab41eec2016-01-04 18:01:27 -0500827 checkNotNull(service);
828 ManagedServiceInfo info = getServiceFromTokenLocked(service);
829 if (info != null) {
830 return info;
831 }
John Spurlock7340fc82014-04-24 18:50:12 -0400832 throw new SecurityException("Disallowed call from unknown " + getCaption() + ": "
Julia Reynoldscb507b82017-09-07 13:53:40 -0400833 + service + " " + service.getClass());
John Spurlock7340fc82014-04-24 18:50:12 -0400834 }
835
Julia Reynolds70aaea72018-07-13 13:38:34 -0400836 public boolean isSameUser(IInterface service, int userId) {
837 checkNotNull(service);
Julia Reynolds3ff1fd92018-08-29 09:57:11 -0400838 synchronized (mMutex) {
839 ManagedServiceInfo info = getServiceFromTokenLocked(service);
840 if (info != null) {
841 return info.isSameUser(userId);
842 }
843 return false;
Julia Reynolds70aaea72018-07-13 13:38:34 -0400844 }
Julia Reynolds70aaea72018-07-13 13:38:34 -0400845 }
846
John Spurlock7340fc82014-04-24 18:50:12 -0400847 public void unregisterService(IInterface service, int userid) {
848 checkNotNull(service);
849 // no need to check permissions; if your service binder is in the list,
850 // that's proof that you had permission to add it in the first place
851 unregisterServiceImpl(service, userid);
852 }
853
854 public void registerService(IInterface service, ComponentName component, int userid) {
855 checkNotNull(service);
Christoph Studer3e144d32014-05-22 16:48:40 +0200856 ManagedServiceInfo info = registerServiceImpl(service, component, userid);
857 if (info != null) {
858 onServiceAdded(info);
859 }
John Spurlock7340fc82014-04-24 18:50:12 -0400860 }
861
Chris Wren51017d02015-12-15 15:34:46 -0500862 /**
863 * Add a service to our callbacks. The lifecycle of this service is managed externally,
Julia Reynoldsb852e562017-06-06 16:14:18 -0400864 * but unlike a system service, it should not be considered privileged.
Chris Wren51017d02015-12-15 15:34:46 -0500865 * */
Julia Reynoldsb852e562017-06-06 16:14:18 -0400866 protected void registerGuestService(ManagedServiceInfo guest) {
Chris Wren51017d02015-12-15 15:34:46 -0500867 checkNotNull(guest.service);
Ruben Brunke24b9a62016-02-16 21:38:24 -0800868 if (!checkType(guest.service)) {
869 throw new IllegalArgumentException();
870 }
Chris Wren51017d02015-12-15 15:34:46 -0500871 if (registerServiceImpl(guest) != null) {
872 onServiceAdded(guest);
Chris Wrenab41eec2016-01-04 18:01:27 -0500873 }
874 }
875
Julia Reynoldsb852e562017-06-06 16:14:18 -0400876 protected void setComponentState(ComponentName component, boolean enabled) {
Chris Wrenab41eec2016-01-04 18:01:27 -0500877 boolean previous = !mSnoozingForCurrentProfiles.contains(component);
878 if (previous == enabled) {
879 return;
880 }
881
882 if (enabled) {
883 mSnoozingForCurrentProfiles.remove(component);
884 } else {
885 mSnoozingForCurrentProfiles.add(component);
886 }
887
888 // State changed
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400889 Slog.d(TAG, ((enabled) ? "Enabling " : "Disabling ") + "component " +
890 component.flattenToShortString());
Chris Wrenab41eec2016-01-04 18:01:27 -0500891
Chris Wren0efdb882016-03-01 17:17:47 -0500892 synchronized (mMutex) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400893 final IntArray userIds = mUserProfiles.getCurrentProfileIds();
Chris Wren0efdb882016-03-01 17:17:47 -0500894
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400895 for (int i = 0; i < userIds.size(); i++) {
896 final int userId = userIds.get(i);
Chris Wren0efdb882016-03-01 17:17:47 -0500897 if (enabled) {
Beverly363da782018-10-09 16:05:15 -0400898 if (isPackageOrComponentAllowed(component.flattenToString(), userId)
Beverly2d783fc2018-09-07 13:38:21 -0400899 || isPackageOrComponentAllowed(component.getPackageName(), userId)) {
Julia Reynolds00fa8402018-07-25 08:57:58 -0400900 registerServiceLocked(component, userId);
901 } else {
902 Slog.d(TAG, component + " no longer has permission to be bound");
903 }
Chris Wren0efdb882016-03-01 17:17:47 -0500904 } else {
905 unregisterServiceLocked(component, userId);
906 }
Chris Wrenab41eec2016-01-04 18:01:27 -0500907 }
Chris Wren51017d02015-12-15 15:34:46 -0500908 }
909 }
910
Julia Reynoldsb852e562017-06-06 16:14:18 -0400911 private @NonNull ArraySet<ComponentName> loadComponentNamesFromValues(
912 ArraySet<String> approved, int userId) {
913 if (approved == null || approved.size() == 0)
Julia Reynolds6e839b02016-04-13 10:01:17 -0400914 return new ArraySet<>();
Julia Reynoldsb852e562017-06-06 16:14:18 -0400915 ArraySet<ComponentName> result = new ArraySet<>(approved.size());
916 for (int i = 0; i < approved.size(); i++) {
917 final String packageOrComponent = approved.valueAt(i);
918 if (!TextUtils.isEmpty(packageOrComponent)) {
919 ComponentName component = ComponentName.unflattenFromString(packageOrComponent);
920 if (component != null) {
921 result.add(component);
922 } else {
923 result.addAll(queryPackageForServices(packageOrComponent, userId));
924 }
Christopher Tate6597e342015-02-17 12:15:25 -0800925 }
926 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200927 return result;
928 }
John Spurlock7340fc82014-04-24 18:50:12 -0400929
Julia Reynoldsc279b992015-10-30 08:23:51 -0400930 protected Set<ComponentName> queryPackageForServices(String packageName, int userId) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400931 return queryPackageForServices(packageName, 0, userId);
932 }
933
Jay Aliomer4204f252019-08-26 11:36:53 -0400934 protected ArraySet<ComponentName> queryPackageForServices(String packageName, int extraFlags,
Julia Reynoldsb852e562017-06-06 16:14:18 -0400935 int userId) {
Jay Aliomer4204f252019-08-26 11:36:53 -0400936 ArraySet<ComponentName> installed = new ArraySet<>();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200937 final PackageManager pm = mContext.getPackageManager();
Julia Reynoldsc279b992015-10-30 08:23:51 -0400938 Intent queryIntent = new Intent(mConfig.serviceInterface);
939 if (!TextUtils.isEmpty(packageName)) {
940 queryIntent.setPackage(packageName);
941 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200942 List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
Julia Reynoldsc279b992015-10-30 08:23:51 -0400943 queryIntent,
Julia Reynoldsb852e562017-06-06 16:14:18 -0400944 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA | extraFlags,
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200945 userId);
946 if (DEBUG)
947 Slog.v(TAG, mConfig.serviceInterface + " services: " + installedServices);
Julia Reynolds50f05142015-10-30 17:03:59 -0400948 if (installedServices != null) {
949 for (int i = 0, count = installedServices.size(); i < count; i++) {
950 ResolveInfo resolveInfo = installedServices.get(i);
951 ServiceInfo info = resolveInfo.serviceInfo;
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200952
Julia Reynolds50f05142015-10-30 17:03:59 -0400953 ComponentName component = new ComponentName(info.packageName, info.name);
954 if (!mConfig.bindPermission.equals(info.permission)) {
955 Slog.w(TAG, "Skipping " + getCaption() + " service "
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800956 + info.packageName + "/" + info.name
957 + ": it does not require the permission "
958 + mConfig.bindPermission);
Julia Reynolds50f05142015-10-30 17:03:59 -0400959 continue;
960 }
961 installed.add(component);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200962 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200963 }
Julia Reynoldsc279b992015-10-30 08:23:51 -0400964 return installed;
965 }
966
Julia Reynolds4c456dd2019-01-07 12:22:00 -0500967 protected Set<String> getAllowedPackages() {
968 final Set<String> allowedPackages = new ArraySet<>();
Julia Reynoldsb776e392019-07-25 12:36:14 -0400969 synchronized (mApproved) {
970 for (int k = 0; k < mApproved.size(); k++) {
971 ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.valueAt(k);
972 for (int i = 0; i < allowedByType.size(); i++) {
973 final ArraySet<String> allowed = allowedByType.valueAt(i);
974 for (int j = 0; j < allowed.size(); j++) {
975 String pkgName = getPackageName(allowed.valueAt(j));
976 if (!TextUtils.isEmpty(pkgName)) {
977 allowedPackages.add(pkgName);
978 }
Julia Reynolds4c456dd2019-01-07 12:22:00 -0500979 }
980 }
981 }
982 }
983 return allowedPackages;
984 }
985
Annie Meng8b646fd2019-02-01 18:46:42 +0000986 private void trimApprovedListsAccordingToInstalledServices(int userId) {
Julia Reynoldsb776e392019-07-25 12:36:14 -0400987 synchronized (mApproved) {
988 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
989 if (approvedByType == null) {
990 return;
991 }
992 for (int i = 0; i < approvedByType.size(); i++) {
993 final ArraySet<String> approved = approvedByType.valueAt(i);
994 for (int j = approved.size() - 1; j >= 0; j--) {
995 final String approvedPackageOrComponent = approved.valueAt(j);
996 if (!isValidEntry(approvedPackageOrComponent, userId)) {
997 approved.removeAt(j);
998 Slog.v(TAG, "Removing " + approvedPackageOrComponent
999 + " from approved list; no matching services found");
1000 } else {
1001 if (DEBUG) {
1002 Slog.v(TAG, "Keeping " + approvedPackageOrComponent
1003 + " on approved list; matching services found");
1004 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04001005 }
John Spurlock7340fc82014-04-24 18:50:12 -04001006 }
John Spurlock7340fc82014-04-24 18:50:12 -04001007 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04001008 }
1009 }
John Spurlock7340fc82014-04-24 18:50:12 -04001010
Julia Reynoldsb852e562017-06-06 16:14:18 -04001011 private boolean removeUninstalledItemsFromApprovedLists(int uninstalledUserId, String pkg) {
1012 boolean removed = false;
Julia Reynoldsb776e392019-07-25 12:36:14 -04001013 synchronized (mApproved) {
1014 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(
1015 uninstalledUserId);
1016 if (approvedByType != null) {
1017 int M = approvedByType.size();
1018 for (int j = 0; j < M; j++) {
1019 final ArraySet<String> approved = approvedByType.valueAt(j);
1020 int O = approved.size();
1021 for (int k = O - 1; k >= 0; k--) {
1022 final String packageOrComponent = approved.valueAt(k);
1023 final String packageName = getPackageName(packageOrComponent);
1024 if (TextUtils.equals(pkg, packageName)) {
1025 approved.removeAt(k);
1026 if (DEBUG) {
1027 Slog.v(TAG, "Removing " + packageOrComponent
1028 + " from approved list; uninstalled");
1029 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04001030 }
1031 }
1032 }
John Spurlock7340fc82014-04-24 18:50:12 -04001033 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001034 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04001035 return removed;
1036 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001037
Julia Reynoldsb852e562017-06-06 16:14:18 -04001038 protected String getPackageName(String packageOrComponent) {
1039 final ComponentName component = ComponentName.unflattenFromString(packageOrComponent);
1040 if (component != null) {
1041 return component.getPackageName();
1042 } else {
1043 return packageOrComponent;
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001044 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04001045 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001046
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -04001047 protected boolean isValidEntry(String packageOrComponent, int userId) {
1048 return hasMatchingServices(packageOrComponent, userId);
1049 }
1050
Julia Reynoldsb852e562017-06-06 16:14:18 -04001051 private boolean hasMatchingServices(String packageOrComponent, int userId) {
1052 if (!TextUtils.isEmpty(packageOrComponent)) {
1053 final String packageName = getPackageName(packageOrComponent);
1054 return queryPackageForServices(packageName, userId).size() > 0;
John Spurlock7340fc82014-04-24 18:50:12 -04001055 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04001056 return false;
John Spurlock7340fc82014-04-24 18:50:12 -04001057 }
1058
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001059 @VisibleForTesting
1060 protected SparseArray<ArraySet<ComponentName>> getAllowedComponents(IntArray userIds) {
1061 final int nUserIds = userIds.size();
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001062 final SparseArray<ArraySet<ComponentName>> componentsByUser = new SparseArray<>();
John Spurlock7340fc82014-04-24 18:50:12 -04001063
1064 for (int i = 0; i < nUserIds; ++i) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001065 final int userId = userIds.get(i);
Julia Reynoldsb776e392019-07-25 12:36:14 -04001066 synchronized (mApproved) {
1067 final ArrayMap<Boolean, ArraySet<String>> approvedLists = mApproved.get(userId);
1068 if (approvedLists != null) {
1069 final int N = approvedLists.size();
1070 for (int j = 0; j < N; j++) {
1071 ArraySet<ComponentName> approvedByUser = componentsByUser.get(userId);
1072 if (approvedByUser == null) {
1073 approvedByUser = new ArraySet<>();
1074 componentsByUser.put(userId, approvedByUser);
1075 }
1076 approvedByUser.addAll(
1077 loadComponentNamesFromValues(approvedLists.valueAt(j), userId));
Julia Reynoldsb852e562017-06-06 16:14:18 -04001078 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04001079 }
Julia Reynolds6e839b02016-04-13 10:01:17 -04001080 }
John Spurlock7340fc82014-04-24 18:50:12 -04001081 }
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001082 return componentsByUser;
1083 }
John Spurlock7340fc82014-04-24 18:50:12 -04001084
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001085 @GuardedBy("mMutex")
1086 protected void populateComponentsToBind(SparseArray<Set<ComponentName>> componentsToBind,
1087 final IntArray activeUsers,
1088 SparseArray<ArraySet<ComponentName>> approvedComponentsByUser) {
1089 mEnabledServicesForCurrentProfiles.clear();
1090 mEnabledServicesPackageNames.clear();
1091 final int nUserIds = activeUsers.size();
John Spurlock7340fc82014-04-24 18:50:12 -04001092
1093 for (int i = 0; i < nUserIds; ++i) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001094 // decode the list of components
1095 final int userId = activeUsers.get(i);
1096 final ArraySet<ComponentName> userComponents = approvedComponentsByUser.get(userId);
1097 if (null == userComponents) {
1098 componentsToBind.put(userId, new ArraySet<>());
1099 continue;
1100 }
1101
1102 final Set<ComponentName> add = new HashSet<>(userComponents);
1103 add.removeAll(mSnoozingForCurrentProfiles);
1104
1105 componentsToBind.put(userId, add);
1106
1107 mEnabledServicesForCurrentProfiles.addAll(userComponents);
1108
1109 for (int j = 0; j < userComponents.size(); j++) {
1110 final ComponentName component = userComponents.valueAt(j);
1111 mEnabledServicesPackageNames.add(component.getPackageName());
1112 }
1113 }
1114 }
1115
1116 @GuardedBy("mMutex")
1117 protected Set<ManagedServiceInfo> getRemovableConnectedServices() {
1118 final Set<ManagedServiceInfo> removableBoundServices = new ArraySet<>();
1119 for (ManagedServiceInfo service : mServices) {
1120 if (!service.isSystem && !service.isGuest(this)) {
1121 removableBoundServices.add(service);
1122 }
1123 }
1124 return removableBoundServices;
1125 }
1126
1127 protected void populateComponentsToUnbind(
1128 boolean forceRebind,
1129 Set<ManagedServiceInfo> removableBoundServices,
1130 SparseArray<Set<ComponentName>> allowedComponentsToBind,
1131 SparseArray<Set<ComponentName>> componentsToUnbind) {
1132 for (ManagedServiceInfo info : removableBoundServices) {
1133 final Set<ComponentName> allowedComponents = allowedComponentsToBind.get(info.userid);
1134 if (allowedComponents != null) {
1135 if (forceRebind || !allowedComponents.contains(info.component)) {
1136 Set<ComponentName> toUnbind =
1137 componentsToUnbind.get(info.userid, new ArraySet<>());
1138 toUnbind.add(info.component);
1139 componentsToUnbind.put(info.userid, toUnbind);
1140 }
1141 }
1142 }
1143 }
1144
1145 /**
1146 * Called whenever packages change, the user switches, or the secure setting
1147 * is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
1148 */
1149 protected void rebindServices(boolean forceRebind, int userToRebind) {
1150 if (DEBUG) Slog.d(TAG, "rebindServices " + forceRebind + " " + userToRebind);
1151 IntArray userIds = mUserProfiles.getCurrentProfileIds();
1152 if (userToRebind != USER_ALL) {
1153 userIds = new IntArray(1);
1154 userIds.add(userToRebind);
1155 }
1156
1157 final SparseArray<Set<ComponentName>> componentsToBind = new SparseArray<>();
1158 final SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>();
1159
1160 synchronized (mMutex) {
1161 final SparseArray<ArraySet<ComponentName>> approvedComponentsByUser =
1162 getAllowedComponents(userIds);
1163 final Set<ManagedServiceInfo> removableBoundServices = getRemovableConnectedServices();
1164
1165 // Filter approvedComponentsByUser to collect all of the components that are allowed
1166 // for the currently active user(s).
1167 populateComponentsToBind(componentsToBind, userIds, approvedComponentsByUser);
1168
1169 // For every current non-system connection, disconnect services that are no longer
1170 // approved, or ALL services if we are force rebinding
1171 populateComponentsToUnbind(
1172 forceRebind, removableBoundServices, componentsToBind, componentsToUnbind);
1173 }
1174
1175 unbindFromServices(componentsToUnbind);
1176 bindToServices(componentsToBind);
1177 }
1178
1179 protected void unbindFromServices(SparseArray<Set<ComponentName>> componentsToUnbind) {
1180 for (int i = 0; i < componentsToUnbind.size(); i++) {
1181 final int userId = componentsToUnbind.keyAt(i);
1182 final Set<ComponentName> removableComponents = componentsToUnbind.get(userId);
1183 for (ComponentName cn : removableComponents) {
1184 // No longer allowed to be bound, or must rebind.
1185 Slog.v(TAG, "disabling " + getCaption() + " for user " + userId + ": " + cn);
1186 unregisterService(cn, userId);
1187 }
1188 }
1189 }
1190
1191 // Attempt to bind to services, skipping those that cannot be found or lack the permission.
1192 private void bindToServices(SparseArray<Set<ComponentName>> componentsToBind) {
1193 for (int i = 0; i < componentsToBind.size(); i++) {
1194 final int userId = componentsToBind.keyAt(i);
1195 final Set<ComponentName> add = componentsToBind.get(userId);
Julia Reynolds9a86cc02016-02-10 15:38:15 -05001196 for (ComponentName component : add) {
Julia Reynoldsa75c7522017-03-21 17:34:25 -04001197 try {
1198 ServiceInfo info = mPm.getServiceInfo(component,
1199 PackageManager.MATCH_DIRECT_BOOT_AWARE
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001200 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
Julia Reynolds503ed942017-10-04 16:04:56 -04001201 if (info == null) {
1202 Slog.w(TAG, "Not binding " + getCaption() + " service " + component
1203 + ": service not found");
1204 continue;
1205 }
1206 if (!mConfig.bindPermission.equals(info.permission)) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04001207 Slog.w(TAG, "Not binding " + getCaption() + " service " + component
Julia Reynoldsa75c7522017-03-21 17:34:25 -04001208 + ": it does not require the permission " + mConfig.bindPermission);
1209 continue;
1210 }
1211 Slog.v(TAG,
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001212 "enabling " + getCaption() + " for " + userId + ": " + component);
1213 registerService(component, userId);
Julia Reynoldsa75c7522017-03-21 17:34:25 -04001214 } catch (RemoteException e) {
1215 e.rethrowFromSystemServer();
1216 }
John Spurlock7340fc82014-04-24 18:50:12 -04001217 }
1218 }
1219 }
1220
1221 /**
1222 * Version of registerService that takes the name of a service component to bind to.
1223 */
1224 private void registerService(final ComponentName name, final int userid) {
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001225 synchronized (mMutex) {
1226 registerServiceLocked(name, userid);
1227 }
1228 }
1229
Chris Wren0efdb882016-03-01 17:17:47 -05001230 /**
1231 * Inject a system service into the management list.
1232 */
1233 public void registerSystemService(final ComponentName name, final int userid) {
1234 synchronized (mMutex) {
1235 registerServiceLocked(name, userid, true /* isSystem */);
1236 }
1237 }
1238
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001239 private void registerServiceLocked(final ComponentName name, final int userid) {
Chris Wren0efdb882016-03-01 17:17:47 -05001240 registerServiceLocked(name, userid, false /* isSystem */);
1241 }
1242
1243 private void registerServiceLocked(final ComponentName name, final int userid,
1244 final boolean isSystem) {
John Spurlock7340fc82014-04-24 18:50:12 -04001245 if (DEBUG) Slog.v(TAG, "registerService: " + name + " u=" + userid);
1246
Andrew Zeng190c0672018-06-28 15:15:05 -07001247 final Pair<ComponentName, Integer> servicesBindingTag = Pair.create(name, userid);
1248 if (mServicesBound.contains(servicesBindingTag)) {
1249 Slog.v(TAG, "Not registering " + name + " is already bound");
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001250 // stop registering this thing already! we're working on it
1251 return;
1252 }
Andrew Zeng190c0672018-06-28 15:15:05 -07001253 mServicesBound.add(servicesBindingTag);
John Spurlock7340fc82014-04-24 18:50:12 -04001254
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001255 final int N = mServices.size();
1256 for (int i = N - 1; i >= 0; i--) {
1257 final ManagedServiceInfo info = mServices.get(i);
1258 if (name.equals(info.component)
1259 && info.userid == userid) {
1260 // cut old connections
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -04001261 Slog.v(TAG, " disconnecting old " + getCaption() + ": " + info.service);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001262 removeServiceLocked(i);
1263 if (info.connection != null) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001264 unbindService(info.connection, info.component, info.userid);
John Spurlock7340fc82014-04-24 18:50:12 -04001265 }
1266 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001267 }
John Spurlock7340fc82014-04-24 18:50:12 -04001268
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001269 Intent intent = new Intent(mConfig.serviceInterface);
1270 intent.setComponent(name);
John Spurlock7340fc82014-04-24 18:50:12 -04001271
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001272 intent.putExtra(Intent.EXTRA_CLIENT_LABEL, mConfig.clientLabel);
John Spurlock7340fc82014-04-24 18:50:12 -04001273
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001274 final PendingIntent pendingIntent = PendingIntent.getActivity(
1275 mContext, 0, new Intent(mConfig.settingsAction), 0);
1276 intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
John Spurlock7340fc82014-04-24 18:50:12 -04001277
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001278 ApplicationInfo appInfo = null;
1279 try {
1280 appInfo = mContext.getPackageManager().getApplicationInfo(
1281 name.getPackageName(), 0);
1282 } catch (NameNotFoundException e) {
1283 // Ignore if the package doesn't exist we won't be able to bind to the service.
1284 }
1285 final int targetSdkVersion =
1286 appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE;
John Spurlock7340fc82014-04-24 18:50:12 -04001287
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001288 try {
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -04001289 Slog.v(TAG, "binding: " + intent);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001290 ServiceConnection serviceConnection = new ServiceConnection() {
1291 IInterface mService;
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001292
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001293 @Override
1294 public void onServiceConnected(ComponentName name, IBinder binder) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001295 Slog.v(TAG, userid + " " + getCaption() + " service connected: " + name);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001296 boolean added = false;
1297 ManagedServiceInfo info = null;
1298 synchronized (mMutex) {
Ryan Lothian4a86a512017-12-04 11:56:58 -05001299 mServicesRebinding.remove(servicesBindingTag);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001300 try {
1301 mService = asInterface(binder);
1302 info = newServiceInfo(mService, name,
Chris Wren0efdb882016-03-01 17:17:47 -05001303 userid, isSystem, this, targetSdkVersion);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001304 binder.linkToDeath(info, 0);
1305 added = mServices.add(info);
1306 } catch (RemoteException e) {
Tony Mak180a9c42019-03-08 13:33:08 +00001307 Slog.e(TAG, "Failed to linkToDeath, already dead", e);
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001308 }
1309 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001310 if (added) {
1311 onServiceAdded(info);
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001312 }
John Spurlock7340fc82014-04-24 18:50:12 -04001313 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001314
1315 @Override
1316 public void onServiceDisconnected(ComponentName name) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001317 Slog.v(TAG, userid + " " + getCaption() + " connection lost: " + name);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001318 }
Ryan Lothian4a86a512017-12-04 11:56:58 -05001319
1320 @Override
1321 public void onBindingDied(ComponentName name) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001322 Slog.w(TAG, userid + " " + getCaption() + " binding died: " + name);
Ryan Lothian4a86a512017-12-04 11:56:58 -05001323 synchronized (mMutex) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001324 unbindService(this, name, userid);
Ryan Lothian4a86a512017-12-04 11:56:58 -05001325 if (!mServicesRebinding.contains(servicesBindingTag)) {
1326 mServicesRebinding.add(servicesBindingTag);
1327 mHandler.postDelayed(new Runnable() {
1328 @Override
1329 public void run() {
1330 registerService(name, userid);
1331 }
1332 }, ON_BINDING_DIED_REBIND_DELAY_MS);
1333 } else {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001334 Slog.v(TAG, getCaption() + " not rebinding in user " + userid
1335 + " as a previous rebind attempt was made: " + name);
Ryan Lothian4a86a512017-12-04 11:56:58 -05001336 }
1337 }
1338 }
Tony Mak180a9c42019-03-08 13:33:08 +00001339
1340 @Override
1341 public void onNullBinding(ComponentName name) {
1342 Slog.v(TAG, "onNullBinding() called with: name = [" + name + "]");
Julia Reynolds8a4f2ab2019-04-10 10:08:21 -04001343 mServicesBound.remove(servicesBindingTag);
Tony Mak180a9c42019-03-08 13:33:08 +00001344 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001345 };
1346 if (!mContext.bindServiceAsUser(intent,
Amith Yamasanie5bfeee2018-09-05 18:52:35 -07001347 serviceConnection,
1348 getBindFlags(),
1349 new UserHandle(userid))) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001350 mServicesBound.remove(servicesBindingTag);
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001351 Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent
1352 + " in user " + userid);
John Spurlock7340fc82014-04-24 18:50:12 -04001353 return;
1354 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001355 } catch (SecurityException ex) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001356 mServicesBound.remove(servicesBindingTag);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001357 Slog.e(TAG, "Unable to bind " + getCaption() + " service: " + intent, ex);
John Spurlock7340fc82014-04-24 18:50:12 -04001358 }
1359 }
1360
Julia Reynolds8a4f2ab2019-04-10 10:08:21 -04001361 boolean isBound(ComponentName cn, int userId) {
1362 final Pair<ComponentName, Integer> servicesBindingTag = Pair.create(cn, userId);
1363 return mServicesBound.contains(servicesBindingTag);
1364 }
1365
John Spurlock7340fc82014-04-24 18:50:12 -04001366 /**
1367 * Remove a service for the given user by ComponentName
1368 */
1369 private void unregisterService(ComponentName name, int userid) {
1370 synchronized (mMutex) {
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001371 unregisterServiceLocked(name, userid);
1372 }
1373 }
1374
1375 private void unregisterServiceLocked(ComponentName name, int userid) {
1376 final int N = mServices.size();
1377 for (int i = N - 1; i >= 0; i--) {
1378 final ManagedServiceInfo info = mServices.get(i);
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -04001379 if (name.equals(info.component) && info.userid == userid) {
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001380 removeServiceLocked(i);
1381 if (info.connection != null) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001382 unbindService(info.connection, info.component, info.userid);
John Spurlock7340fc82014-04-24 18:50:12 -04001383 }
1384 }
1385 }
1386 }
1387
1388 /**
1389 * Removes a service from the list but does not unbind
1390 *
1391 * @return the removed service.
1392 */
1393 private ManagedServiceInfo removeServiceImpl(IInterface service, final int userid) {
John Spurlocke77bb362014-04-26 10:24:59 -04001394 if (DEBUG) Slog.d(TAG, "removeServiceImpl service=" + service + " u=" + userid);
John Spurlock7340fc82014-04-24 18:50:12 -04001395 ManagedServiceInfo serviceInfo = null;
1396 synchronized (mMutex) {
1397 final int N = mServices.size();
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001398 for (int i = N - 1; i >= 0; i--) {
John Spurlock7340fc82014-04-24 18:50:12 -04001399 final ManagedServiceInfo info = mServices.get(i);
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -04001400 if (info.service.asBinder() == service.asBinder() && info.userid == userid) {
1401 Slog.d(TAG, "Removing active service " + info.component);
John Spurlocke77bb362014-04-26 10:24:59 -04001402 serviceInfo = removeServiceLocked(i);
John Spurlock7340fc82014-04-24 18:50:12 -04001403 }
1404 }
1405 }
1406 return serviceInfo;
1407 }
1408
John Spurlocke77bb362014-04-26 10:24:59 -04001409 private ManagedServiceInfo removeServiceLocked(int i) {
1410 final ManagedServiceInfo info = mServices.remove(i);
1411 onServiceRemovedLocked(info);
1412 return info;
1413 }
1414
John Spurlock7340fc82014-04-24 18:50:12 -04001415 private void checkNotNull(IInterface service) {
1416 if (service == null) {
1417 throw new IllegalArgumentException(getCaption() + " must not be null");
1418 }
1419 }
1420
Christoph Studer3e144d32014-05-22 16:48:40 +02001421 private ManagedServiceInfo registerServiceImpl(final IInterface service,
John Spurlock7340fc82014-04-24 18:50:12 -04001422 final ComponentName component, final int userid) {
Chris Wren51017d02015-12-15 15:34:46 -05001423 ManagedServiceInfo info = newServiceInfo(service, component, userid,
1424 true /*isSystem*/, null /*connection*/, Build.VERSION_CODES.LOLLIPOP);
1425 return registerServiceImpl(info);
1426 }
1427
1428 private ManagedServiceInfo registerServiceImpl(ManagedServiceInfo info) {
John Spurlock7340fc82014-04-24 18:50:12 -04001429 synchronized (mMutex) {
1430 try {
Chris Wren51017d02015-12-15 15:34:46 -05001431 info.service.asBinder().linkToDeath(info, 0);
John Spurlock7340fc82014-04-24 18:50:12 -04001432 mServices.add(info);
Christoph Studer3e144d32014-05-22 16:48:40 +02001433 return info;
John Spurlock7340fc82014-04-24 18:50:12 -04001434 } catch (RemoteException e) {
1435 // already dead
1436 }
1437 }
Christoph Studer3e144d32014-05-22 16:48:40 +02001438 return null;
John Spurlock7340fc82014-04-24 18:50:12 -04001439 }
1440
1441 /**
1442 * Removes a service from the list and unbinds.
1443 */
1444 private void unregisterServiceImpl(IInterface service, int userid) {
1445 ManagedServiceInfo info = removeServiceImpl(service, userid);
Chris Wren51017d02015-12-15 15:34:46 -05001446 if (info != null && info.connection != null && !info.isGuest(this)) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001447 unbindService(info.connection, info.component, info.userid);
1448 }
1449 }
1450
1451 private void unbindService(ServiceConnection connection, ComponentName component, int userId) {
1452 try {
1453 mContext.unbindService(connection);
1454 } catch (IllegalArgumentException e) {
1455 Slog.e(TAG, getCaption() + " " + component + " could not be unbound", e);
1456 }
1457 synchronized (mMutex) {
1458 mServicesBound.remove(Pair.create(component, userId));
John Spurlock7340fc82014-04-24 18:50:12 -04001459 }
1460 }
1461
John Spurlock7340fc82014-04-24 18:50:12 -04001462 public class ManagedServiceInfo implements IBinder.DeathRecipient {
1463 public IInterface service;
1464 public ComponentName component;
1465 public int userid;
1466 public boolean isSystem;
1467 public ServiceConnection connection;
1468 public int targetSdkVersion;
1469
1470 public ManagedServiceInfo(IInterface service, ComponentName component,
1471 int userid, boolean isSystem, ServiceConnection connection, int targetSdkVersion) {
1472 this.service = service;
1473 this.component = component;
1474 this.userid = userid;
1475 this.isSystem = isSystem;
1476 this.connection = connection;
1477 this.targetSdkVersion = targetSdkVersion;
1478 }
1479
Chris Wren51017d02015-12-15 15:34:46 -05001480 public boolean isGuest(ManagedServices host) {
1481 return ManagedServices.this != host;
1482 }
1483
Chris Wrenab41eec2016-01-04 18:01:27 -05001484 public ManagedServices getOwner() {
1485 return ManagedServices.this;
1486 }
1487
John Spurlocke77bb362014-04-26 10:24:59 -04001488 @Override
1489 public String toString() {
1490 return new StringBuilder("ManagedServiceInfo[")
1491 .append("component=").append(component)
1492 .append(",userid=").append(userid)
1493 .append(",isSystem=").append(isSystem)
1494 .append(",targetSdkVersion=").append(targetSdkVersion)
1495 .append(",connection=").append(connection == null ? null : "<connection>")
1496 .append(",service=").append(service)
1497 .append(']').toString();
1498 }
1499
Jeffrey Huangcb782852019-12-05 11:28:11 -08001500 public void dumpDebug(ProtoOutputStream proto, long fieldId, ManagedServices host) {
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001501 final long token = proto.start(fieldId);
Jeffrey Huangcb782852019-12-05 11:28:11 -08001502 component.dumpDebug(proto, ManagedServiceInfoProto.COMPONENT);
Kweku Adams93304b62017-09-20 17:03:00 -07001503 proto.write(ManagedServiceInfoProto.USER_ID, userid);
1504 proto.write(ManagedServiceInfoProto.SERVICE, service.getClass().getName());
1505 proto.write(ManagedServiceInfoProto.IS_SYSTEM, isSystem);
1506 proto.write(ManagedServiceInfoProto.IS_GUEST, isGuest(host));
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001507 proto.end(token);
Kweku Adams93304b62017-09-20 17:03:00 -07001508 }
1509
Julia Reynolds70aaea72018-07-13 13:38:34 -04001510 public boolean isSameUser(int userId) {
1511 if (!isEnabledForCurrentProfiles()) {
1512 return false;
1513 }
1514 return this.userid == userId;
1515 }
1516
John Spurlock7340fc82014-04-24 18:50:12 -04001517 public boolean enabledAndUserMatches(int nid) {
1518 if (!isEnabledForCurrentProfiles()) {
1519 return false;
1520 }
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001521 if (this.userid == USER_ALL) return true;
Chris Wren0c4eeb42016-05-12 13:21:08 -04001522 if (this.isSystem) return true;
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001523 if (nid == USER_ALL || nid == this.userid) return true;
Esteban Talavera9c6458d2017-03-30 17:59:50 +01001524 return supportsProfiles()
1525 && mUserProfiles.isCurrentProfile(nid)
1526 && isPermittedForProfile(nid);
John Spurlock7340fc82014-04-24 18:50:12 -04001527 }
1528
1529 public boolean supportsProfiles() {
Dianne Hackborn955d8d62014-10-07 20:17:19 -07001530 return targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP;
John Spurlock7340fc82014-04-24 18:50:12 -04001531 }
1532
1533 @Override
1534 public void binderDied() {
John Spurlocke77bb362014-04-26 10:24:59 -04001535 if (DEBUG) Slog.d(TAG, "binderDied");
John Spurlock7340fc82014-04-24 18:50:12 -04001536 // Remove the service, but don't unbind from the service. The system will bring the
Esteban Talavera9c6458d2017-03-30 17:59:50 +01001537 // service back up, and the onServiceConnected handler will read the service with the
John Spurlock7340fc82014-04-24 18:50:12 -04001538 // new binding. If this isn't a bound service, and is just a registered
1539 // service, just removing it from the list is all we need to do anyway.
1540 removeServiceImpl(this.service, this.userid);
1541 }
1542
1543 /** convenience method for looking in mEnabledServicesForCurrentProfiles */
1544 public boolean isEnabledForCurrentProfiles() {
1545 if (this.isSystem) return true;
1546 if (this.connection == null) return false;
1547 return mEnabledServicesForCurrentProfiles.contains(this.component);
1548 }
Esteban Talavera9c6458d2017-03-30 17:59:50 +01001549
1550 /**
1551 * Returns true if this service is allowed to receive events for the given userId. A
1552 * managed profile owner can disallow non-system services running outside of the profile
1553 * from receiving events from the profile.
1554 */
1555 public boolean isPermittedForProfile(int userId) {
1556 if (!mUserProfiles.isManagedProfile(userId)) {
1557 return true;
1558 }
1559 DevicePolicyManager dpm =
1560 (DevicePolicyManager) mContext.getSystemService(DEVICE_POLICY_SERVICE);
1561 final long identity = Binder.clearCallingIdentity();
1562 try {
1563 return dpm.isNotificationListenerServicePermitted(
1564 component.getPackageName(), userId);
1565 } finally {
1566 Binder.restoreCallingIdentity(identity);
1567 }
1568 }
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001569
1570 @Override
1571 public boolean equals(Object o) {
1572 if (this == o) return true;
1573 if (o == null || getClass() != o.getClass()) return false;
1574 ManagedServiceInfo that = (ManagedServiceInfo) o;
1575 return userid == that.userid
1576 && isSystem == that.isSystem
1577 && targetSdkVersion == that.targetSdkVersion
1578 && Objects.equals(service, that.service)
1579 && Objects.equals(component, that.component)
1580 && Objects.equals(connection, that.connection);
1581 }
1582
1583 @Override
1584 public int hashCode() {
1585 return Objects.hash(service, component, userid, isSystem, connection, targetSdkVersion);
1586 }
John Spurlock7340fc82014-04-24 18:50:12 -04001587 }
1588
Chris Wrenab41eec2016-01-04 18:01:27 -05001589 /** convenience method for looking in mEnabledServicesForCurrentProfiles */
1590 public boolean isComponentEnabledForCurrentProfiles(ComponentName component) {
1591 return mEnabledServicesForCurrentProfiles.contains(component);
1592 }
1593
John Spurlock7340fc82014-04-24 18:50:12 -04001594 public static class UserProfiles {
1595 // Profiles of the current user.
Ruben Brunke24b9a62016-02-16 21:38:24 -08001596 private final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
John Spurlock7340fc82014-04-24 18:50:12 -04001597
Ruben Brunke24b9a62016-02-16 21:38:24 -08001598 public void updateCache(@NonNull Context context) {
John Spurlock7340fc82014-04-24 18:50:12 -04001599 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
1600 if (userManager != null) {
1601 int currentUserId = ActivityManager.getCurrentUser();
1602 List<UserInfo> profiles = userManager.getProfiles(currentUserId);
1603 synchronized (mCurrentProfiles) {
1604 mCurrentProfiles.clear();
1605 for (UserInfo user : profiles) {
1606 mCurrentProfiles.put(user.id, user);
1607 }
1608 }
1609 }
1610 }
1611
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001612 /**
1613 * Returns the currently active users (generally one user and its work profile).
1614 */
1615 public IntArray getCurrentProfileIds() {
John Spurlock7340fc82014-04-24 18:50:12 -04001616 synchronized (mCurrentProfiles) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001617 IntArray users = new IntArray(mCurrentProfiles.size());
John Spurlock7340fc82014-04-24 18:50:12 -04001618 final int N = mCurrentProfiles.size();
1619 for (int i = 0; i < N; ++i) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001620 users.add(mCurrentProfiles.keyAt(i));
John Spurlock7340fc82014-04-24 18:50:12 -04001621 }
1622 return users;
1623 }
1624 }
1625
1626 public boolean isCurrentProfile(int userId) {
1627 synchronized (mCurrentProfiles) {
1628 return mCurrentProfiles.get(userId) != null;
1629 }
1630 }
Esteban Talavera9c6458d2017-03-30 17:59:50 +01001631
1632 public boolean isManagedProfile(int userId) {
1633 synchronized (mCurrentProfiles) {
1634 UserInfo user = mCurrentProfiles.get(userId);
1635 return user != null && user.isManagedProfile();
1636 }
1637 }
John Spurlock7340fc82014-04-24 18:50:12 -04001638 }
1639
Ruben Brunke24b9a62016-02-16 21:38:24 -08001640 public static class Config {
1641 public String caption;
1642 public String serviceInterface;
1643 public String secureSettingName;
Julia Reynolds6e839b02016-04-13 10:01:17 -04001644 public String secondarySettingName;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001645 public String xmlTag;
Ruben Brunke24b9a62016-02-16 21:38:24 -08001646 public String bindPermission;
1647 public String settingsAction;
1648 public int clientLabel;
John Spurlock7340fc82014-04-24 18:50:12 -04001649 }
1650}