blob: 5d3dc5f19714a555a3d560e31a76dd0c5f8699c1 [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;
Jay Aliomer76e1f2722020-03-05 12:36:38 -050024import static android.os.UserHandle.USER_SYSTEM;
Felipe Lemea1b79bf2016-05-24 13:06:54 -070025
Ruben Brunke24b9a62016-02-16 21:38:24 -080026import android.annotation.NonNull;
John Spurlock7340fc82014-04-24 18:50:12 -040027import android.app.ActivityManager;
28import android.app.PendingIntent;
Esteban Talavera9c6458d2017-03-30 17:59:50 +010029import android.app.admin.DevicePolicyManager;
John Spurlock7340fc82014-04-24 18:50:12 -040030import android.content.ComponentName;
31import android.content.ContentResolver;
32import android.content.Context;
33import android.content.Intent;
34import android.content.ServiceConnection;
35import android.content.pm.ApplicationInfo;
Julia Reynoldsa75c7522017-03-21 17:34:25 -040036import android.content.pm.IPackageManager;
John Spurlock7340fc82014-04-24 18:50:12 -040037import android.content.pm.PackageManager;
38import android.content.pm.PackageManager.NameNotFoundException;
39import android.content.pm.ResolveInfo;
40import android.content.pm.ServiceInfo;
41import android.content.pm.UserInfo;
Esteban Talavera9c6458d2017-03-30 17:59:50 +010042import android.os.Binder;
John Spurlock7340fc82014-04-24 18:50:12 -040043import android.os.Build;
Ryan Lothian4a86a512017-12-04 11:56:58 -050044import android.os.Handler;
John Spurlock7340fc82014-04-24 18:50:12 -040045import android.os.IBinder;
46import android.os.IInterface;
Ryan Lothian4a86a512017-12-04 11:56:58 -050047import android.os.Looper;
John Spurlock7340fc82014-04-24 18:50:12 -040048import android.os.RemoteException;
49import android.os.UserHandle;
50import android.os.UserManager;
51import android.provider.Settings;
Kweku Adams93304b62017-09-20 17:03:00 -070052import android.service.notification.ManagedServiceInfoProto;
53import android.service.notification.ManagedServicesProto;
54import android.service.notification.ManagedServicesProto.ServiceProto;
John Spurlock7340fc82014-04-24 18:50:12 -040055import android.text.TextUtils;
Julia Reynoldsb852e562017-06-06 16:14:18 -040056import android.util.ArrayMap;
John Spurlock7340fc82014-04-24 18:50:12 -040057import android.util.ArraySet;
Julia Reynoldsca8e5352018-09-18 13:39:26 -040058import android.util.IntArray;
John Spurlock4db0d982014-08-13 09:19:03 -040059import android.util.Log;
Andrew Zeng190c0672018-06-28 15:15:05 -070060import android.util.Pair;
John Spurlock7340fc82014-04-24 18:50:12 -040061import android.util.Slog;
62import android.util.SparseArray;
Kweku Adams93304b62017-09-20 17:03:00 -070063import android.util.proto.ProtoOutputStream;
John Spurlock7340fc82014-04-24 18:50:12 -040064
Julia Reynoldsca8e5352018-09-18 13:39:26 -040065import com.android.internal.annotations.GuardedBy;
66import com.android.internal.annotations.VisibleForTesting;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -040067import com.android.internal.util.XmlUtils;
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -050068import com.android.internal.util.function.TriPredicate;
John Spurlock25e2d242014-06-27 13:58:23 -040069import com.android.server.notification.NotificationManagerService.DumpFilter;
70
Julia Reynoldsb852e562017-06-06 16:14:18 -040071import org.xmlpull.v1.XmlPullParser;
72import org.xmlpull.v1.XmlPullParserException;
73import org.xmlpull.v1.XmlSerializer;
74
75import java.io.IOException;
John Spurlock7340fc82014-04-24 18:50:12 -040076import java.io.PrintWriter;
77import java.util.ArrayList;
John Spurlocke77bb362014-04-26 10:24:59 -040078import java.util.Arrays;
Julia Reynolds9a86cc02016-02-10 15:38:15 -050079import java.util.HashSet;
John Spurlock7340fc82014-04-24 18:50:12 -040080import java.util.List;
Julia Reynoldsca8e5352018-09-18 13:39:26 -040081import java.util.Objects;
John Spurlock7340fc82014-04-24 18:50:12 -040082import java.util.Set;
83
84/**
85 * Manages the lifecycle of application-provided services bound by system server.
86 *
87 * Services managed by this helper must have:
88 * - An associated system settings value with a list of enabled component names.
89 * - A well-known action for services to use in their intent-filter.
90 * - A system permission for services to require in order to ensure system has exclusive binding.
91 * - A settings page for user configuration of enabled services, and associated intent action.
92 * - A remote interface definition (aidl) provided by the service used for communication.
93 */
94abstract public class ManagedServices {
95 protected final String TAG = getClass().getSimpleName();
John Spurlock4db0d982014-08-13 09:19:03 -040096 protected final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
John Spurlock7340fc82014-04-24 18:50:12 -040097
Ryan Lothian4a86a512017-12-04 11:56:58 -050098 private static final int ON_BINDING_DIED_REBIND_DELAY_MS = 10000;
Julia Reynoldsc279b992015-10-30 08:23:51 -040099 protected static final String ENABLED_SERVICES_SEPARATOR = ":";
Jay Aliomer76e1f2722020-03-05 12:36:38 -0500100 private static final String DB_VERSION_1 = "1";
101
John Spurlock7340fc82014-04-24 18:50:12 -0400102
Julia Reynoldsb852e562017-06-06 16:14:18 -0400103 /**
104 * List of components and apps that can have running {@link ManagedServices}.
105 */
106 static final String TAG_MANAGED_SERVICES = "service_listing";
107 static final String ATT_APPROVED_LIST = "approved";
108 static final String ATT_USER_ID = "user";
109 static final String ATT_IS_PRIMARY = "primary";
Julia Reynolds7380d872018-01-12 10:28:26 -0500110 static final String ATT_VERSION = "version";
Jay Aliomer4204f252019-08-26 11:36:53 -0400111 static final String ATT_DEFAULTS = "defaults";
Julia Reynolds7380d872018-01-12 10:28:26 -0500112
Jay Aliomer76e1f2722020-03-05 12:36:38 -0500113 static final int DB_VERSION = 2;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400114
115 static final int APPROVAL_BY_PACKAGE = 0;
116 static final int APPROVAL_BY_COMPONENT = 1;
117
John Spurlockaf8d6c42014-05-07 17:49:08 -0400118 protected final Context mContext;
John Spurlocke77bb362014-04-26 10:24:59 -0400119 protected final Object mMutex;
John Spurlock7340fc82014-04-24 18:50:12 -0400120 private final UserProfiles mUserProfiles;
Julia Reynoldsa75c7522017-03-21 17:34:25 -0400121 private final IPackageManager mPm;
Julia Reynoldsd6d5a592018-04-02 11:03:32 -0400122 protected final UserManager mUm;
John Spurlock7340fc82014-04-24 18:50:12 -0400123 private final Config mConfig;
Ryan Lothian4a86a512017-12-04 11:56:58 -0500124 private final Handler mHandler = new Handler(Looper.getMainLooper());
John Spurlock7340fc82014-04-24 18:50:12 -0400125
126 // contains connections to all connected services, including app services
127 // and system services
Julia Reynoldsb852e562017-06-06 16:14:18 -0400128 private final ArrayList<ManagedServiceInfo> mServices = new ArrayList<>();
Andrew Zeng190c0672018-06-28 15:15:05 -0700129 /**
130 * The services that have been bound by us. If the service is also connected, it will also
131 * be in {@link #mServices}.
132 */
133 private final ArrayList<Pair<ComponentName, Integer>> mServicesBound = new ArrayList<>();
134 private final ArraySet<Pair<ComponentName, Integer>> mServicesRebinding = new ArraySet<>();
Jay Aliomer4204f252019-08-26 11:36:53 -0400135 // we need these packages to be protected because classes that inherit from it need to see it
136 protected final Object mDefaultsLock = new Object();
137 protected final ArraySet<ComponentName> mDefaultComponents = new ArraySet<>();
138 protected final ArraySet<String> mDefaultPackages = new ArraySet<>();
Ryan Lothian4a86a512017-12-04 11:56:58 -0500139
Chris Wrenab41eec2016-01-04 18:01:27 -0500140 // lists the component names of all enabled (and therefore potentially connected)
John Spurlock7340fc82014-04-24 18:50:12 -0400141 // app services for current profiles.
142 private ArraySet<ComponentName> mEnabledServicesForCurrentProfiles
Julia Reynoldsb852e562017-06-06 16:14:18 -0400143 = new ArraySet<>();
John Spurlock7340fc82014-04-24 18:50:12 -0400144 // Just the packages from mEnabledServicesForCurrentProfiles
Julia Reynoldsb852e562017-06-06 16:14:18 -0400145 private ArraySet<String> mEnabledServicesPackageNames = new ArraySet<>();
Chris Wrenab41eec2016-01-04 18:01:27 -0500146 // List of enabled packages that have nevertheless asked not to be run
147 private ArraySet<ComponentName> mSnoozingForCurrentProfiles = new ArraySet<>();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200148
Julia Reynoldsb852e562017-06-06 16:14:18 -0400149 // List of approved packages or components (by user, then by primary/secondary) that are
150 // allowed to be bound as managed services. A package or component appearing in this list does
151 // not mean that we are currently bound to said package/component.
152 private ArrayMap<Integer, ArrayMap<Boolean, ArraySet<String>>> mApproved = new ArrayMap<>();
John Spurlock7340fc82014-04-24 18:50:12 -0400153
Julia Reynoldsb852e562017-06-06 16:14:18 -0400154 // True if approved services are stored in xml, not settings.
155 private boolean mUseXml;
Christopher Tate6597e342015-02-17 12:15:25 -0800156
Julia Reynoldsb852e562017-06-06 16:14:18 -0400157 // Whether managed services are approved individually or package wide
158 protected int mApprovalLevel;
159
160 public ManagedServices(Context context, Object mutex, UserProfiles userProfiles,
161 IPackageManager pm) {
John Spurlock7340fc82014-04-24 18:50:12 -0400162 mContext = context;
163 mMutex = mutex;
164 mUserProfiles = userProfiles;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400165 mPm = pm;
John Spurlock7340fc82014-04-24 18:50:12 -0400166 mConfig = getConfig();
Julia Reynoldsb852e562017-06-06 16:14:18 -0400167 mApprovalLevel = APPROVAL_BY_COMPONENT;
Julia Reynolds45523002017-09-12 09:43:57 -0400168 mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
John Spurlock7340fc82014-04-24 18:50:12 -0400169 }
170
171 abstract protected Config getConfig();
172
173 private String getCaption() {
174 return mConfig.caption;
175 }
176
177 abstract protected IInterface asInterface(IBinder binder);
178
Chris Wren51017d02015-12-15 15:34:46 -0500179 abstract protected boolean checkType(IInterface service);
180
John Spurlock3b98b3f2014-05-01 09:08:48 -0400181 abstract protected void onServiceAdded(ManagedServiceInfo info);
John Spurlock7340fc82014-04-24 18:50:12 -0400182
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400183 protected List<ManagedServiceInfo> getServices() {
184 synchronized (mMutex) {
185 List<ManagedServiceInfo> services = new ArrayList<>(mServices);
186 return services;
187 }
188 }
189
Jay Aliomer4204f252019-08-26 11:36:53 -0400190 protected void addDefaultComponentOrPackage(String packageOrComponent) {
Julia Reynolds57a974b2019-10-07 11:51:47 -0400191 if (!TextUtils.isEmpty(packageOrComponent)) {
Jay Aliomer4204f252019-08-26 11:36:53 -0400192 synchronized (mDefaultsLock) {
Jay Aliomer76e1f2722020-03-05 12:36:38 -0500193 if (mApprovalLevel == APPROVAL_BY_PACKAGE) {
Jay Aliomer4204f252019-08-26 11:36:53 -0400194 mDefaultPackages.add(packageOrComponent);
Jay Aliomer76e1f2722020-03-05 12:36:38 -0500195 return;
196 }
197 ComponentName cn = ComponentName.unflattenFromString(packageOrComponent);
198 if (cn != null && mApprovalLevel == APPROVAL_BY_COMPONENT) {
Jay Aliomer4204f252019-08-26 11:36:53 -0400199 mDefaultPackages.add(cn.getPackageName());
200 mDefaultComponents.add(cn);
Jay Aliomer76e1f2722020-03-05 12:36:38 -0500201 return;
Jay Aliomer4204f252019-08-26 11:36:53 -0400202 }
203 }
204 }
205 }
206
Jay Aliomer76e1f2722020-03-05 12:36:38 -0500207 protected abstract void loadDefaultsFromConfig();
208
Jay Aliomer4204f252019-08-26 11:36:53 -0400209 boolean isDefaultComponentOrPackage(String packageOrComponent) {
210 synchronized (mDefaultsLock) {
211 ComponentName cn = ComponentName.unflattenFromString(packageOrComponent);
212 if (cn == null) {
213 return mDefaultPackages.contains(packageOrComponent);
214 } else {
215 return mDefaultComponents.contains(cn);
216 }
217 }
218 }
219
220 ArraySet<ComponentName> getDefaultComponents() {
221 synchronized (mDefaultsLock) {
222 return new ArraySet<>(mDefaultComponents);
223 }
224 }
225
226 ArraySet<String> getDefaultPackages() {
227 synchronized (mDefaultsLock) {
228 return new ArraySet<>(mDefaultPackages);
229 }
230 }
231
232 /**
233 * When resetting a package, we need to enable default components that belong to that packages
234 * we also need to disable components that are not default to return the managed service state
235 * to when a new android device is first turned on for that package.
236 *
237 * @param packageName package to reset.
238 * @param userId the android user id
239 * @return a list of components that were permitted
240 */
241 @NonNull
242 ArrayMap<Boolean, ArrayList<ComponentName>> resetComponents(String packageName, int userId) {
243 // components that we want to enable
244 ArrayList<ComponentName> componentsToEnable =
245 new ArrayList<>(mDefaultComponents.size());
246
247 // components that were removed
248 ArrayList<ComponentName> disabledComponents =
249 new ArrayList<>(mDefaultComponents.size());
250
251 // all components that are enabled now
252 ArraySet<ComponentName> enabledComponents =
253 new ArraySet<>(getAllowedComponents(userId));
254
255 boolean changed = false;
256
257 synchronized (mDefaultsLock) {
258 // record all components that are enabled but should not be by default
259 for (int i = 0; i < mDefaultComponents.size() && enabledComponents.size() > 0; i++) {
260 ComponentName currentDefault = mDefaultComponents.valueAt(i);
261 if (packageName.equals(currentDefault.getPackageName())
262 && !enabledComponents.contains(currentDefault)) {
263 componentsToEnable.add(currentDefault);
264 }
265 }
266 synchronized (mApproved) {
267 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(
268 userId);
269 if (approvedByType != null) {
270 final int M = approvedByType.size();
271 for (int j = 0; j < M; j++) {
272 final ArraySet<String> approved = approvedByType.valueAt(j);
273 for (int i = 0; i < enabledComponents.size(); i++) {
274 ComponentName currentComponent = enabledComponents.valueAt(i);
275 if (packageName.equals(currentComponent.getPackageName())
276 && !mDefaultComponents.contains(currentComponent)) {
277 if (approved.remove(currentComponent.flattenToString())) {
278 disabledComponents.add(currentComponent);
279 changed = true;
280 }
281 }
282 }
283 for (int i = 0; i < componentsToEnable.size(); i++) {
284 ComponentName candidate = componentsToEnable.get(i);
285 changed |= approved.add(candidate.flattenToString());
286 }
287 }
288
289 }
290 }
291 }
292 if (changed) rebindServices(false, USER_ALL);
293
294 ArrayMap<Boolean, ArrayList<ComponentName>> changes = new ArrayMap<>();
295 changes.put(true, componentsToEnable);
296 changes.put(false, disabledComponents);
297
298 return changes;
299 }
300
Amith Yamasanie5bfeee2018-09-05 18:52:35 -0700301 protected int getBindFlags() {
302 return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE | BIND_ALLOW_WHITELIST_MANAGEMENT;
303 }
304
John Spurlocke77bb362014-04-26 10:24:59 -0400305 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { }
306
John Spurlock7340fc82014-04-24 18:50:12 -0400307 private ManagedServiceInfo newServiceInfo(IInterface service,
Julia Reynoldsb852e562017-06-06 16:14:18 -0400308 ComponentName component, int userId, boolean isSystem, ServiceConnection connection,
John Spurlock7340fc82014-04-24 18:50:12 -0400309 int targetSdkVersion) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400310 return new ManagedServiceInfo(service, component, userId, isSystem, connection,
John Spurlock7340fc82014-04-24 18:50:12 -0400311 targetSdkVersion);
312 }
313
Julia Reynoldsb852e562017-06-06 16:14:18 -0400314 public void onBootPhaseAppsCanStart() {}
John Spurlock7340fc82014-04-24 18:50:12 -0400315
John Spurlock25e2d242014-06-27 13:58:23 -0400316 public void dump(PrintWriter pw, DumpFilter filter) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400317 pw.println(" Allowed " + getCaption() + "s:");
Julia Reynoldsb776e392019-07-25 12:36:14 -0400318 synchronized (mApproved) {
319 final int N = mApproved.size();
320 for (int i = 0; i < N; i++) {
321 final int userId = mApproved.keyAt(i);
322 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
323 if (approvedByType != null) {
324 final int M = approvedByType.size();
325 for (int j = 0; j < M; j++) {
326 final boolean isPrimary = approvedByType.keyAt(j);
327 final ArraySet<String> approved = approvedByType.valueAt(j);
328 if (approvedByType != null && approvedByType.size() > 0) {
329 pw.println(" " + String.join(ENABLED_SERVICES_SEPARATOR, approved)
330 + " (user: " + userId + " isPrimary: " + isPrimary + ")");
331 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400332 }
333 }
334 }
335 }
336
John Spurlocke77bb362014-04-26 10:24:59 -0400337 pw.println(" All " + getCaption() + "s (" + mEnabledServicesForCurrentProfiles.size()
John Spurlock7340fc82014-04-24 18:50:12 -0400338 + ") enabled for current profiles:");
339 for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
John Spurlock25e2d242014-06-27 13:58:23 -0400340 if (filter != null && !filter.matches(cmpt)) continue;
John Spurlocke77bb362014-04-26 10:24:59 -0400341 pw.println(" " + cmpt);
John Spurlock7340fc82014-04-24 18:50:12 -0400342 }
343
John Spurlocke77bb362014-04-26 10:24:59 -0400344 pw.println(" Live " + getCaption() + "s (" + mServices.size() + "):");
Julia Reynolds3ff1fd92018-08-29 09:57:11 -0400345 synchronized (mMutex) {
346 for (ManagedServiceInfo info : mServices) {
347 if (filter != null && !filter.matches(info.component)) continue;
348 pw.println(" " + info.component
349 + " (user " + info.userid + "): " + info.service
350 + (info.isSystem ? " SYSTEM" : "")
351 + (info.isGuest(this) ? " GUEST" : ""));
352 }
John Spurlock7340fc82014-04-24 18:50:12 -0400353 }
Chris Wrenab41eec2016-01-04 18:01:27 -0500354
355 pw.println(" Snoozed " + getCaption() + "s (" +
356 mSnoozingForCurrentProfiles.size() + "):");
357 for (ComponentName name : mSnoozingForCurrentProfiles) {
358 pw.println(" " + name.flattenToShortString());
359 }
John Spurlock7340fc82014-04-24 18:50:12 -0400360 }
361
Kweku Adams93304b62017-09-20 17:03:00 -0700362 public void dump(ProtoOutputStream proto, DumpFilter filter) {
363 proto.write(ManagedServicesProto.CAPTION, getCaption());
Julia Reynoldsb776e392019-07-25 12:36:14 -0400364 synchronized (mApproved) {
365 final int N = mApproved.size();
366 for (int i = 0; i < N; i++) {
367 final int userId = mApproved.keyAt(i);
368 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
369 if (approvedByType != null) {
370 final int M = approvedByType.size();
371 for (int j = 0; j < M; j++) {
372 final boolean isPrimary = approvedByType.keyAt(j);
373 final ArraySet<String> approved = approvedByType.valueAt(j);
374 if (approvedByType != null && approvedByType.size() > 0) {
375 final long sToken = proto.start(ManagedServicesProto.APPROVED);
376 for (String s : approved) {
377 proto.write(ServiceProto.NAME, s);
378 }
379 proto.write(ServiceProto.USER_ID, userId);
380 proto.write(ServiceProto.IS_PRIMARY, isPrimary);
381 proto.end(sToken);
Kweku Adams93304b62017-09-20 17:03:00 -0700382 }
Kweku Adams93304b62017-09-20 17:03:00 -0700383 }
384 }
385 }
386 }
387
388 for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
389 if (filter != null && !filter.matches(cmpt)) continue;
Jeffrey Huangcb782852019-12-05 11:28:11 -0800390 cmpt.dumpDebug(proto, ManagedServicesProto.ENABLED);
Kweku Adams93304b62017-09-20 17:03:00 -0700391 }
392
Julia Reynolds3ff1fd92018-08-29 09:57:11 -0400393 synchronized (mMutex) {
394 for (ManagedServiceInfo info : mServices) {
395 if (filter != null && !filter.matches(info.component)) continue;
Jeffrey Huangcb782852019-12-05 11:28:11 -0800396 info.dumpDebug(proto, ManagedServicesProto.LIVE_SERVICES, this);
Julia Reynolds3ff1fd92018-08-29 09:57:11 -0400397 }
Kweku Adams93304b62017-09-20 17:03:00 -0700398 }
399
400 for (ComponentName name : mSnoozingForCurrentProfiles) {
Jeffrey Huangcb782852019-12-05 11:28:11 -0800401 name.dumpDebug(proto, ManagedServicesProto.SNOOZED);
Kweku Adams93304b62017-09-20 17:03:00 -0700402 }
403 }
404
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400405 protected void onSettingRestored(String element, String value, int backupSdkInt, int userId) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400406 if (!mUseXml) {
407 Slog.d(TAG, "Restored managed service setting: " + element);
408 if (mConfig.secureSettingName.equals(element) ||
409 (mConfig.secondarySettingName != null
410 && mConfig.secondarySettingName.equals(element))) {
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400411 if (backupSdkInt < Build.VERSION_CODES.O) {
412 // automatic system grants were added in O, so append the approved apps
413 // rather than wiping out the setting
414 String currentSetting =
415 getApproved(userId, mConfig.secureSettingName.equals(element));
416 if (!TextUtils.isEmpty(currentSetting)) {
417 if (!TextUtils.isEmpty(value)) {
418 value = value + ENABLED_SERVICES_SEPARATOR + currentSetting;
419 } else {
420 value = currentSetting;
421 }
422 }
423 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400424 Settings.Secure.putStringForUser(
425 mContext.getContentResolver(), element, value, userId);
426 loadAllowedComponentsFromSettings();
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400427 rebindServices(false, userId);
Christopher Tate6597e342015-02-17 12:15:25 -0800428 }
429 }
430 }
431
Jay Aliomer4204f252019-08-26 11:36:53 -0400432 void writeDefaults(XmlSerializer out) throws IOException {
433 synchronized (mDefaultsLock) {
434 List<String> componentStrings = new ArrayList<>(mDefaultComponents.size());
435 for (int i = 0; i < mDefaultComponents.size(); i++) {
436 componentStrings.add(mDefaultComponents.valueAt(i).flattenToString());
437 }
438 String defaults = String.join(ENABLED_SERVICES_SEPARATOR, componentStrings);
439 out.attribute(null, ATT_DEFAULTS, defaults);
440 }
441 }
442
Annie Meng8b646fd2019-02-01 18:46:42 +0000443 public void writeXml(XmlSerializer out, boolean forBackup, int userId) throws IOException {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400444 out.startTag(null, getConfig().xmlTag);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400445
Julia Reynolds7380d872018-01-12 10:28:26 -0500446 out.attribute(null, ATT_VERSION, String.valueOf(DB_VERSION));
447
Jay Aliomer4204f252019-08-26 11:36:53 -0400448 writeDefaults(out);
449
Julia Reynoldsb852e562017-06-06 16:14:18 -0400450 if (forBackup) {
Annie Meng8b646fd2019-02-01 18:46:42 +0000451 trimApprovedListsAccordingToInstalledServices(userId);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400452 }
453
Julia Reynoldsb776e392019-07-25 12:36:14 -0400454 synchronized (mApproved) {
455 final int N = mApproved.size();
456 for (int i = 0; i < N; i++) {
457 final int approvedUserId = mApproved.keyAt(i);
458 if (forBackup && approvedUserId != userId) {
459 continue;
460 }
461 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
462 if (approvedByType != null) {
463 final int M = approvedByType.size();
464 for (int j = 0; j < M; j++) {
465 final boolean isPrimary = approvedByType.keyAt(j);
466 final Set<String> approved = approvedByType.valueAt(j);
467 if (approved != null) {
468 String allowedItems = String.join(ENABLED_SERVICES_SEPARATOR, approved);
469 out.startTag(null, TAG_MANAGED_SERVICES);
470 out.attribute(null, ATT_APPROVED_LIST, allowedItems);
471 out.attribute(null, ATT_USER_ID, Integer.toString(approvedUserId));
472 out.attribute(null, ATT_IS_PRIMARY, Boolean.toString(isPrimary));
473 writeExtraAttributes(out, approvedUserId);
474 out.endTag(null, TAG_MANAGED_SERVICES);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400475
Julia Reynoldsb776e392019-07-25 12:36:14 -0400476 if (!forBackup && isPrimary) {
477 // Also write values to settings, for observers who haven't migrated yet
478 Settings.Secure.putStringForUser(mContext.getContentResolver(),
479 getConfig().secureSettingName, allowedItems,
480 approvedUserId);
481 }
482
Julia Reynoldsb852e562017-06-06 16:14:18 -0400483 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400484 }
485 }
486 }
487 }
Julia Reynoldsad6dd352019-03-07 16:46:22 -0500488
489 writeExtraXmlTags(out);
490
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400491 out.endTag(null, getConfig().xmlTag);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400492 }
493
Tony Mak9a3c1f12019-03-04 16:04:42 +0000494 /**
495 * Writes extra xml attributes to {@link #TAG_MANAGED_SERVICES} tag.
496 */
497 protected void writeExtraAttributes(XmlSerializer out, int userId) throws IOException {}
498
Julia Reynoldsad6dd352019-03-07 16:46:22 -0500499 /**
500 * Writes extra xml tags within the parent tag specified in {@link Config#xmlTag}.
501 */
502 protected void writeExtraXmlTags(XmlSerializer out) throws IOException {}
503
504 /**
505 * This is called to process tags other than {@link #TAG_MANAGED_SERVICES}.
506 */
507 protected void readExtraTag(String tag, XmlPullParser parser) throws IOException {}
508
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400509 protected void migrateToXml() {
510 loadAllowedComponentsFromSettings();
511 }
512
Jay Aliomer4204f252019-08-26 11:36:53 -0400513 void readDefaults(XmlPullParser parser) {
514 String defaultComponents = XmlUtils.readStringAttribute(parser, ATT_DEFAULTS);
Jay Aliomer76e1f2722020-03-05 12:36:38 -0500515
516 if (!TextUtils.isEmpty(defaultComponents)) {
517 String[] components = defaultComponents.split(ENABLED_SERVICES_SEPARATOR);
518 synchronized (mDefaultsLock) {
519 for (int i = 0; i < components.length; i++) {
520 if (!TextUtils.isEmpty(components[i])) {
521 ComponentName cn = ComponentName.unflattenFromString(components[i]);
522 if (cn != null) {
523 mDefaultPackages.add(cn.getPackageName());
524 mDefaultComponents.add(cn);
525 } else {
526 mDefaultPackages.add(components[i]);
527 }
Jay Aliomer4204f252019-08-26 11:36:53 -0400528 }
529 }
530 }
531 }
532 }
533
Annie Meng8b646fd2019-02-01 18:46:42 +0000534 public void readXml(
535 XmlPullParser parser,
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -0500536 TriPredicate<String, Integer, String> allowedManagedServicePackages,
Annie Meng8b646fd2019-02-01 18:46:42 +0000537 boolean forRestore,
538 int userId)
Julia Reynoldsb852e562017-06-06 16:14:18 -0400539 throws XmlPullParserException, IOException {
Julia Reynolds7380d872018-01-12 10:28:26 -0500540 // read grants
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400541 int type;
Jay Aliomer76e1f2722020-03-05 12:36:38 -0500542 String version = "";
Jay Aliomer4204f252019-08-26 11:36:53 -0400543 readDefaults(parser);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400544 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
545 String tag = parser.getName();
Jay Aliomer76e1f2722020-03-05 12:36:38 -0500546 version = XmlUtils.readStringAttribute(parser, ATT_VERSION);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400547 if (type == XmlPullParser.END_TAG
548 && getConfig().xmlTag.equals(tag)) {
549 break;
550 }
551 if (type == XmlPullParser.START_TAG) {
552 if (TAG_MANAGED_SERVICES.equals(tag)) {
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400553 Slog.i(TAG, "Read " + mConfig.caption + " permissions from xml");
Julia Reynolds7380d872018-01-12 10:28:26 -0500554
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400555 final String approved = XmlUtils.readStringAttribute(parser, ATT_APPROVED_LIST);
Annie Meng8b646fd2019-02-01 18:46:42 +0000556 // Ignore parser's user id for restore.
557 final int resolvedUserId = forRestore
558 ? userId : XmlUtils.readIntAttribute(parser, ATT_USER_ID, 0);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400559 final boolean isPrimary =
560 XmlUtils.readBooleanAttribute(parser, ATT_IS_PRIMARY, true);
Tony Mak9a3c1f12019-03-04 16:04:42 +0000561 readExtraAttributes(tag, parser, resolvedUserId);
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -0500562 if (allowedManagedServicePackages == null || allowedManagedServicePackages.test(
563 getPackageName(approved), resolvedUserId, getRequiredPermission())) {
Annie Meng8b646fd2019-02-01 18:46:42 +0000564 if (mUm.getUserInfo(resolvedUserId) != null) {
565 addApprovedList(approved, resolvedUserId, isPrimary);
Kristian Monsen05f34792018-04-09 10:27:16 +0200566 }
567 mUseXml = true;
Julia Reynolds45523002017-09-12 09:43:57 -0400568 }
Julia Reynoldsad6dd352019-03-07 16:46:22 -0500569 } else {
570 readExtraTag(tag, parser);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400571 }
572 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400573 }
Jay Aliomer76e1f2722020-03-05 12:36:38 -0500574 boolean isVersionOne = TextUtils.isEmpty(version) || DB_VERSION_1.equals(version);
575 if (isVersionOne) {
576 upgradeToVersionTwo();
577 }
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400578 rebindServices(false, USER_ALL);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400579 }
580
Jay Aliomer76e1f2722020-03-05 12:36:38 -0500581 private void upgradeToVersionTwo() {
582 // check if any defaults are loaded
583 int defaultsSize = mDefaultComponents.size() + mDefaultPackages.size();
584 if (defaultsSize == 0) {
585 // load defaults from current allowed
586 if (this.mApprovalLevel == APPROVAL_BY_COMPONENT) {
587 List<ComponentName> approvedComponents = getAllowedComponents(USER_SYSTEM);
588 for (int i = 0; i < approvedComponents.size(); i++) {
589 addDefaultComponentOrPackage(approvedComponents.get(i).flattenToString());
590 }
591 }
592 if (this.mApprovalLevel == APPROVAL_BY_PACKAGE) {
593 List<String> approvedPkgs = getAllowedPackages(USER_SYSTEM);
594 for (int i = 0; i < approvedPkgs.size(); i++) {
595 addDefaultComponentOrPackage(approvedPkgs.get(i));
596 }
597 }
598 }
599 // if no defaults are loaded, then load from config
600 defaultsSize = mDefaultComponents.size() + mDefaultPackages.size();
601 if (defaultsSize == 0) {
602 loadDefaultsFromConfig();
603 }
604 }
605
Tony Mak9a3c1f12019-03-04 16:04:42 +0000606 /**
607 * Read extra attributes in the {@link #TAG_MANAGED_SERVICES} tag.
608 */
609 protected void readExtraAttributes(String tag, XmlPullParser parser, int userId)
610 throws IOException {}
611
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -0500612 protected abstract String getRequiredPermission();
613
Julia Reynoldsb852e562017-06-06 16:14:18 -0400614 private void loadAllowedComponentsFromSettings() {
Julia Reynoldse0d711f2017-09-01 08:50:47 -0400615 for (UserInfo user : mUm.getUsers()) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400616 final ContentResolver cr = mContext.getContentResolver();
617 addApprovedList(Settings.Secure.getStringForUser(
618 cr,
619 getConfig().secureSettingName,
620 user.id), user.id, true);
621 if (!TextUtils.isEmpty(getConfig().secondarySettingName)) {
622 addApprovedList(Settings.Secure.getStringForUser(
623 cr,
624 getConfig().secondarySettingName,
625 user.id), user.id, false);
626 }
627 }
628 Slog.d(TAG, "Done loading approved values from settings");
629 }
630
Julia Reynolds7380d872018-01-12 10:28:26 -0500631 protected void addApprovedList(String approved, int userId, boolean isPrimary) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400632 if (TextUtils.isEmpty(approved)) {
633 approved = "";
634 }
Julia Reynoldsb776e392019-07-25 12:36:14 -0400635 synchronized (mApproved) {
636 ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
637 if (approvedByType == null) {
638 approvedByType = new ArrayMap<>();
639 mApproved.put(userId, approvedByType);
640 }
Artem Iglikovbec96172018-04-24 12:46:44 +0100641
Julia Reynoldsb776e392019-07-25 12:36:14 -0400642 ArraySet<String> approvedList = approvedByType.get(isPrimary);
643 if (approvedList == null) {
644 approvedList = new ArraySet<>();
645 approvedByType.put(isPrimary, approvedList);
646 }
Artem Iglikovbec96172018-04-24 12:46:44 +0100647
Julia Reynoldsb776e392019-07-25 12:36:14 -0400648 String[] approvedArray = approved.split(ENABLED_SERVICES_SEPARATOR);
649 for (String pkgOrComponent : approvedArray) {
650 String approvedItem = getApprovedValue(pkgOrComponent);
651 if (approvedItem != null) {
652 approvedList.add(approvedItem);
653 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400654 }
655 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400656 }
657
658 protected boolean isComponentEnabledForPackage(String pkg) {
John Spurlock80774932015-05-07 17:38:50 -0400659 return mEnabledServicesPackageNames.contains(pkg);
660 }
661
Julia Reynoldsb852e562017-06-06 16:14:18 -0400662 protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId,
663 boolean isPrimary, boolean enabled) {
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400664 Slog.i(TAG,
665 (enabled ? " Allowing " : "Disallowing ") + mConfig.caption + " " + pkgOrComponent);
Julia Reynoldsb776e392019-07-25 12:36:14 -0400666 synchronized (mApproved) {
667 ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.get(userId);
668 if (allowedByType == null) {
669 allowedByType = new ArrayMap<>();
670 mApproved.put(userId, allowedByType);
671 }
672 ArraySet<String> approved = allowedByType.get(isPrimary);
673 if (approved == null) {
674 approved = new ArraySet<>();
675 allowedByType.put(isPrimary, approved);
676 }
677 String approvedItem = getApprovedValue(pkgOrComponent);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200678
Julia Reynoldsb776e392019-07-25 12:36:14 -0400679 if (approvedItem != null) {
680 if (enabled) {
681 approved.add(approvedItem);
682 } else {
683 approved.remove(approvedItem);
684 }
John Spurlock7340fc82014-04-24 18:50:12 -0400685 }
686 }
687
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400688 rebindServices(false, userId);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400689 }
690
691 private String getApprovedValue(String pkgOrComponent) {
692 if (mApprovalLevel == APPROVAL_BY_COMPONENT) {
693 if(ComponentName.unflattenFromString(pkgOrComponent) != null) {
694 return pkgOrComponent;
John Spurlock7340fc82014-04-24 18:50:12 -0400695 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400696 return null;
697 } else {
698 return getPackageName(pkgOrComponent);
699 }
700 }
701
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400702 protected String getApproved(int userId, boolean primary) {
Julia Reynoldsb776e392019-07-25 12:36:14 -0400703 synchronized (mApproved) {
704 final ArrayMap<Boolean, ArraySet<String>> allowedByType =
705 mApproved.getOrDefault(userId, new ArrayMap<>());
706 ArraySet<String> approved = allowedByType.getOrDefault(primary, new ArraySet<>());
707 return String.join(ENABLED_SERVICES_SEPARATOR, approved);
708 }
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400709 }
710
Julia Reynoldsb852e562017-06-06 16:14:18 -0400711 protected List<ComponentName> getAllowedComponents(int userId) {
712 final List<ComponentName> allowedComponents = new ArrayList<>();
Julia Reynoldsb776e392019-07-25 12:36:14 -0400713 synchronized (mApproved) {
714 final ArrayMap<Boolean, ArraySet<String>> allowedByType =
715 mApproved.getOrDefault(userId, new ArrayMap<>());
716 for (int i = 0; i < allowedByType.size(); i++) {
717 final ArraySet<String> allowed = allowedByType.valueAt(i);
718 for (int j = 0; j < allowed.size(); j++) {
719 ComponentName cn = ComponentName.unflattenFromString(allowed.valueAt(j));
720 if (cn != null) {
721 allowedComponents.add(cn);
722 }
Julia Reynolds2f496962018-04-16 13:17:01 -0400723 }
724 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400725 }
726 return allowedComponents;
727 }
728
729 protected List<String> getAllowedPackages(int userId) {
730 final List<String> allowedPackages = new ArrayList<>();
Julia Reynoldsb776e392019-07-25 12:36:14 -0400731 synchronized (mApproved) {
732 final ArrayMap<Boolean, ArraySet<String>> allowedByType =
733 mApproved.getOrDefault(userId, new ArrayMap<>());
734 for (int i = 0; i < allowedByType.size(); i++) {
735 final ArraySet<String> allowed = allowedByType.valueAt(i);
736 for (int j = 0; j < allowed.size(); j++) {
737 String pkgName = getPackageName(allowed.valueAt(j));
738 if (!TextUtils.isEmpty(pkgName)) {
739 allowedPackages.add(pkgName);
740 }
Julia Reynolds2f496962018-04-16 13:17:01 -0400741 }
742 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400743 }
744 return allowedPackages;
745 }
746
747 protected boolean isPackageOrComponentAllowed(String pkgOrComponent, int userId) {
Julia Reynoldsb776e392019-07-25 12:36:14 -0400748 synchronized (mApproved) {
749 ArrayMap<Boolean, ArraySet<String>> allowedByType =
750 mApproved.getOrDefault(userId, new ArrayMap<>());
751 for (int i = 0; i < allowedByType.size(); i++) {
752 ArraySet<String> allowed = allowedByType.valueAt(i);
753 if (allowed.contains(pkgOrComponent)) {
754 return true;
755 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400756 }
757 }
758 return false;
759 }
760
Julia Reynolds14590742018-07-30 09:25:35 -0400761 protected boolean isPackageAllowed(String pkg, int userId) {
762 if (pkg == null) {
763 return false;
764 }
Julia Reynoldsb776e392019-07-25 12:36:14 -0400765 synchronized (mApproved) {
766 ArrayMap<Boolean, ArraySet<String>> allowedByType =
767 mApproved.getOrDefault(userId, new ArrayMap<>());
768 for (int i = 0; i < allowedByType.size(); i++) {
769 ArraySet<String> allowed = allowedByType.valueAt(i);
770 for (String allowedEntry : allowed) {
771 ComponentName component = ComponentName.unflattenFromString(allowedEntry);
772 if (component != null) {
773 if (pkg.equals(component.getPackageName())) {
774 return true;
775 }
776 } else {
777 if (pkg.equals(allowedEntry)) {
778 return true;
779 }
Julia Reynolds14590742018-07-30 09:25:35 -0400780 }
781 }
782 }
783 }
784 return false;
785 }
786
Julia Reynoldsb852e562017-06-06 16:14:18 -0400787 public void onPackagesChanged(boolean removingPackage, String[] pkgList, int[] uidList) {
788 if (DEBUG) Slog.d(TAG, "onPackagesChanged removingPackage=" + removingPackage
789 + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList))
790 + " mEnabledServicesPackageNames=" + mEnabledServicesPackageNames);
791
792 if (pkgList != null && (pkgList.length > 0)) {
793 boolean anyServicesInvolved = false;
794 // Remove notification settings for uninstalled package
Beverly42d01902019-01-03 12:47:57 -0500795 if (removingPackage && uidList != null) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400796 int size = Math.min(pkgList.length, uidList.length);
797 for (int i = 0; i < size; i++) {
798 final String pkg = pkgList[i];
799 final int userId = UserHandle.getUserId(uidList[i]);
800 anyServicesInvolved = removeUninstalledItemsFromApprovedLists(userId, pkg);
801 }
802 }
803 for (String pkgName : pkgList) {
804 if (mEnabledServicesPackageNames.contains(pkgName)) {
805 anyServicesInvolved = true;
806 }
Beverly42d01902019-01-03 12:47:57 -0500807 if (uidList != null && uidList.length > 0) {
808 for (int uid : uidList) {
809 if (isPackageAllowed(pkgName, UserHandle.getUserId(uid))) {
810 anyServicesInvolved = true;
811 }
Julia Reynolds14590742018-07-30 09:25:35 -0400812 }
813 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400814 }
815
816 if (anyServicesInvolved) {
817 // make sure we're still bound to any of our services who may have just upgraded
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400818 rebindServices(false, USER_ALL);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400819 }
John Spurlock7340fc82014-04-24 18:50:12 -0400820 }
821 }
822
Julia Reynolds5aa13a42017-08-24 09:10:23 -0400823 public void onUserRemoved(int user) {
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400824 Slog.i(TAG, "Removing approved services for removed user " + user);
Julia Reynoldsb776e392019-07-25 12:36:14 -0400825 synchronized (mApproved) {
826 mApproved.remove(user);
827 }
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400828 rebindServices(true, user);
Julia Reynolds5aa13a42017-08-24 09:10:23 -0400829 }
830
John Spurlock1b8b22b2015-05-20 09:47:13 -0400831 public void onUserSwitched(int user) {
832 if (DEBUG) Slog.d(TAG, "onUserSwitched u=" + user);
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400833 rebindServices(true, user);
Christoph Studerb53dfd42014-09-12 14:45:59 +0200834 }
835
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500836 public void onUserUnlocked(int user) {
837 if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400838 rebindServices(false, user);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500839 }
840
Julia Reynoldsb852e562017-06-06 16:14:18 -0400841 private ManagedServiceInfo getServiceFromTokenLocked(IInterface service) {
Chris Wrenab41eec2016-01-04 18:01:27 -0500842 if (service == null) {
843 return null;
844 }
John Spurlock7340fc82014-04-24 18:50:12 -0400845 final IBinder token = service.asBinder();
846 final int N = mServices.size();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200847 for (int i = 0; i < N; i++) {
John Spurlock7340fc82014-04-24 18:50:12 -0400848 final ManagedServiceInfo info = mServices.get(i);
849 if (info.service.asBinder() == token) return info;
850 }
Chris Wrenab41eec2016-01-04 18:01:27 -0500851 return null;
852 }
853
Julia Reynolds503ed942017-10-04 16:04:56 -0400854 protected boolean isServiceTokenValidLocked(IInterface service) {
855 if (service == null) {
856 return false;
857 }
858 ManagedServiceInfo info = getServiceFromTokenLocked(service);
859 if (info != null) {
860 return true;
861 }
862 return false;
863 }
864
Julia Reynoldsb852e562017-06-06 16:14:18 -0400865 protected ManagedServiceInfo checkServiceTokenLocked(IInterface service) {
Chris Wrenab41eec2016-01-04 18:01:27 -0500866 checkNotNull(service);
867 ManagedServiceInfo info = getServiceFromTokenLocked(service);
868 if (info != null) {
869 return info;
870 }
John Spurlock7340fc82014-04-24 18:50:12 -0400871 throw new SecurityException("Disallowed call from unknown " + getCaption() + ": "
Julia Reynoldscb507b82017-09-07 13:53:40 -0400872 + service + " " + service.getClass());
John Spurlock7340fc82014-04-24 18:50:12 -0400873 }
874
Julia Reynolds70aaea72018-07-13 13:38:34 -0400875 public boolean isSameUser(IInterface service, int userId) {
876 checkNotNull(service);
Julia Reynolds3ff1fd92018-08-29 09:57:11 -0400877 synchronized (mMutex) {
878 ManagedServiceInfo info = getServiceFromTokenLocked(service);
879 if (info != null) {
880 return info.isSameUser(userId);
881 }
882 return false;
Julia Reynolds70aaea72018-07-13 13:38:34 -0400883 }
Julia Reynolds70aaea72018-07-13 13:38:34 -0400884 }
885
John Spurlock7340fc82014-04-24 18:50:12 -0400886 public void unregisterService(IInterface service, int userid) {
887 checkNotNull(service);
888 // no need to check permissions; if your service binder is in the list,
889 // that's proof that you had permission to add it in the first place
890 unregisterServiceImpl(service, userid);
891 }
892
893 public void registerService(IInterface service, ComponentName component, int userid) {
894 checkNotNull(service);
Christoph Studer3e144d32014-05-22 16:48:40 +0200895 ManagedServiceInfo info = registerServiceImpl(service, component, userid);
896 if (info != null) {
897 onServiceAdded(info);
898 }
John Spurlock7340fc82014-04-24 18:50:12 -0400899 }
900
Chris Wren51017d02015-12-15 15:34:46 -0500901 /**
902 * Add a service to our callbacks. The lifecycle of this service is managed externally,
Julia Reynoldsb852e562017-06-06 16:14:18 -0400903 * but unlike a system service, it should not be considered privileged.
Chris Wren51017d02015-12-15 15:34:46 -0500904 * */
Julia Reynoldsb852e562017-06-06 16:14:18 -0400905 protected void registerGuestService(ManagedServiceInfo guest) {
Chris Wren51017d02015-12-15 15:34:46 -0500906 checkNotNull(guest.service);
Ruben Brunke24b9a62016-02-16 21:38:24 -0800907 if (!checkType(guest.service)) {
908 throw new IllegalArgumentException();
909 }
Chris Wren51017d02015-12-15 15:34:46 -0500910 if (registerServiceImpl(guest) != null) {
911 onServiceAdded(guest);
Chris Wrenab41eec2016-01-04 18:01:27 -0500912 }
913 }
914
Julia Reynoldsb852e562017-06-06 16:14:18 -0400915 protected void setComponentState(ComponentName component, boolean enabled) {
Chris Wrenab41eec2016-01-04 18:01:27 -0500916 boolean previous = !mSnoozingForCurrentProfiles.contains(component);
917 if (previous == enabled) {
918 return;
919 }
920
921 if (enabled) {
922 mSnoozingForCurrentProfiles.remove(component);
923 } else {
924 mSnoozingForCurrentProfiles.add(component);
925 }
926
927 // State changed
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400928 Slog.d(TAG, ((enabled) ? "Enabling " : "Disabling ") + "component " +
929 component.flattenToShortString());
Chris Wrenab41eec2016-01-04 18:01:27 -0500930
Chris Wren0efdb882016-03-01 17:17:47 -0500931 synchronized (mMutex) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400932 final IntArray userIds = mUserProfiles.getCurrentProfileIds();
Chris Wren0efdb882016-03-01 17:17:47 -0500933
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400934 for (int i = 0; i < userIds.size(); i++) {
935 final int userId = userIds.get(i);
Chris Wren0efdb882016-03-01 17:17:47 -0500936 if (enabled) {
Beverly363da782018-10-09 16:05:15 -0400937 if (isPackageOrComponentAllowed(component.flattenToString(), userId)
Beverly2d783fc2018-09-07 13:38:21 -0400938 || isPackageOrComponentAllowed(component.getPackageName(), userId)) {
Julia Reynolds00fa8402018-07-25 08:57:58 -0400939 registerServiceLocked(component, userId);
940 } else {
941 Slog.d(TAG, component + " no longer has permission to be bound");
942 }
Chris Wren0efdb882016-03-01 17:17:47 -0500943 } else {
944 unregisterServiceLocked(component, userId);
945 }
Chris Wrenab41eec2016-01-04 18:01:27 -0500946 }
Chris Wren51017d02015-12-15 15:34:46 -0500947 }
948 }
949
Julia Reynoldsb852e562017-06-06 16:14:18 -0400950 private @NonNull ArraySet<ComponentName> loadComponentNamesFromValues(
951 ArraySet<String> approved, int userId) {
952 if (approved == null || approved.size() == 0)
Julia Reynolds6e839b02016-04-13 10:01:17 -0400953 return new ArraySet<>();
Julia Reynoldsb852e562017-06-06 16:14:18 -0400954 ArraySet<ComponentName> result = new ArraySet<>(approved.size());
955 for (int i = 0; i < approved.size(); i++) {
956 final String packageOrComponent = approved.valueAt(i);
957 if (!TextUtils.isEmpty(packageOrComponent)) {
958 ComponentName component = ComponentName.unflattenFromString(packageOrComponent);
959 if (component != null) {
960 result.add(component);
961 } else {
962 result.addAll(queryPackageForServices(packageOrComponent, userId));
963 }
Christopher Tate6597e342015-02-17 12:15:25 -0800964 }
965 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200966 return result;
967 }
John Spurlock7340fc82014-04-24 18:50:12 -0400968
Julia Reynoldsc279b992015-10-30 08:23:51 -0400969 protected Set<ComponentName> queryPackageForServices(String packageName, int userId) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400970 return queryPackageForServices(packageName, 0, userId);
971 }
972
Jay Aliomer4204f252019-08-26 11:36:53 -0400973 protected ArraySet<ComponentName> queryPackageForServices(String packageName, int extraFlags,
Julia Reynoldsb852e562017-06-06 16:14:18 -0400974 int userId) {
Jay Aliomer4204f252019-08-26 11:36:53 -0400975 ArraySet<ComponentName> installed = new ArraySet<>();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200976 final PackageManager pm = mContext.getPackageManager();
Julia Reynoldsc279b992015-10-30 08:23:51 -0400977 Intent queryIntent = new Intent(mConfig.serviceInterface);
978 if (!TextUtils.isEmpty(packageName)) {
979 queryIntent.setPackage(packageName);
980 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200981 List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
Julia Reynoldsc279b992015-10-30 08:23:51 -0400982 queryIntent,
Julia Reynoldsb852e562017-06-06 16:14:18 -0400983 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA | extraFlags,
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200984 userId);
985 if (DEBUG)
986 Slog.v(TAG, mConfig.serviceInterface + " services: " + installedServices);
Julia Reynolds50f05142015-10-30 17:03:59 -0400987 if (installedServices != null) {
988 for (int i = 0, count = installedServices.size(); i < count; i++) {
989 ResolveInfo resolveInfo = installedServices.get(i);
990 ServiceInfo info = resolveInfo.serviceInfo;
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200991
Julia Reynolds50f05142015-10-30 17:03:59 -0400992 ComponentName component = new ComponentName(info.packageName, info.name);
993 if (!mConfig.bindPermission.equals(info.permission)) {
994 Slog.w(TAG, "Skipping " + getCaption() + " service "
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800995 + info.packageName + "/" + info.name
996 + ": it does not require the permission "
997 + mConfig.bindPermission);
Julia Reynolds50f05142015-10-30 17:03:59 -0400998 continue;
999 }
1000 installed.add(component);
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001001 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001002 }
Julia Reynoldsc279b992015-10-30 08:23:51 -04001003 return installed;
1004 }
1005
Julia Reynolds4c456dd2019-01-07 12:22:00 -05001006 protected Set<String> getAllowedPackages() {
1007 final Set<String> allowedPackages = new ArraySet<>();
Julia Reynoldsb776e392019-07-25 12:36:14 -04001008 synchronized (mApproved) {
1009 for (int k = 0; k < mApproved.size(); k++) {
1010 ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.valueAt(k);
1011 for (int i = 0; i < allowedByType.size(); i++) {
1012 final ArraySet<String> allowed = allowedByType.valueAt(i);
1013 for (int j = 0; j < allowed.size(); j++) {
1014 String pkgName = getPackageName(allowed.valueAt(j));
1015 if (!TextUtils.isEmpty(pkgName)) {
1016 allowedPackages.add(pkgName);
1017 }
Julia Reynolds4c456dd2019-01-07 12:22:00 -05001018 }
1019 }
1020 }
1021 }
1022 return allowedPackages;
1023 }
1024
Annie Meng8b646fd2019-02-01 18:46:42 +00001025 private void trimApprovedListsAccordingToInstalledServices(int userId) {
Julia Reynoldsb776e392019-07-25 12:36:14 -04001026 synchronized (mApproved) {
1027 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
1028 if (approvedByType == null) {
1029 return;
1030 }
1031 for (int i = 0; i < approvedByType.size(); i++) {
1032 final ArraySet<String> approved = approvedByType.valueAt(i);
1033 for (int j = approved.size() - 1; j >= 0; j--) {
1034 final String approvedPackageOrComponent = approved.valueAt(j);
1035 if (!isValidEntry(approvedPackageOrComponent, userId)) {
1036 approved.removeAt(j);
1037 Slog.v(TAG, "Removing " + approvedPackageOrComponent
1038 + " from approved list; no matching services found");
1039 } else {
1040 if (DEBUG) {
1041 Slog.v(TAG, "Keeping " + approvedPackageOrComponent
1042 + " on approved list; matching services found");
1043 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04001044 }
John Spurlock7340fc82014-04-24 18:50:12 -04001045 }
John Spurlock7340fc82014-04-24 18:50:12 -04001046 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04001047 }
1048 }
John Spurlock7340fc82014-04-24 18:50:12 -04001049
Julia Reynoldsb852e562017-06-06 16:14:18 -04001050 private boolean removeUninstalledItemsFromApprovedLists(int uninstalledUserId, String pkg) {
1051 boolean removed = false;
Julia Reynoldsb776e392019-07-25 12:36:14 -04001052 synchronized (mApproved) {
1053 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(
1054 uninstalledUserId);
1055 if (approvedByType != null) {
1056 int M = approvedByType.size();
1057 for (int j = 0; j < M; j++) {
1058 final ArraySet<String> approved = approvedByType.valueAt(j);
1059 int O = approved.size();
1060 for (int k = O - 1; k >= 0; k--) {
1061 final String packageOrComponent = approved.valueAt(k);
1062 final String packageName = getPackageName(packageOrComponent);
1063 if (TextUtils.equals(pkg, packageName)) {
1064 approved.removeAt(k);
1065 if (DEBUG) {
1066 Slog.v(TAG, "Removing " + packageOrComponent
1067 + " from approved list; uninstalled");
1068 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04001069 }
1070 }
1071 }
John Spurlock7340fc82014-04-24 18:50:12 -04001072 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001073 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04001074 return removed;
1075 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001076
Julia Reynoldsb852e562017-06-06 16:14:18 -04001077 protected String getPackageName(String packageOrComponent) {
1078 final ComponentName component = ComponentName.unflattenFromString(packageOrComponent);
1079 if (component != null) {
1080 return component.getPackageName();
1081 } else {
1082 return packageOrComponent;
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001083 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04001084 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001085
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -04001086 protected boolean isValidEntry(String packageOrComponent, int userId) {
1087 return hasMatchingServices(packageOrComponent, userId);
1088 }
1089
Julia Reynoldsb852e562017-06-06 16:14:18 -04001090 private boolean hasMatchingServices(String packageOrComponent, int userId) {
1091 if (!TextUtils.isEmpty(packageOrComponent)) {
1092 final String packageName = getPackageName(packageOrComponent);
1093 return queryPackageForServices(packageName, userId).size() > 0;
John Spurlock7340fc82014-04-24 18:50:12 -04001094 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04001095 return false;
John Spurlock7340fc82014-04-24 18:50:12 -04001096 }
1097
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001098 @VisibleForTesting
1099 protected SparseArray<ArraySet<ComponentName>> getAllowedComponents(IntArray userIds) {
1100 final int nUserIds = userIds.size();
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001101 final SparseArray<ArraySet<ComponentName>> componentsByUser = new SparseArray<>();
John Spurlock7340fc82014-04-24 18:50:12 -04001102
1103 for (int i = 0; i < nUserIds; ++i) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001104 final int userId = userIds.get(i);
Julia Reynoldsb776e392019-07-25 12:36:14 -04001105 synchronized (mApproved) {
1106 final ArrayMap<Boolean, ArraySet<String>> approvedLists = mApproved.get(userId);
1107 if (approvedLists != null) {
1108 final int N = approvedLists.size();
1109 for (int j = 0; j < N; j++) {
1110 ArraySet<ComponentName> approvedByUser = componentsByUser.get(userId);
1111 if (approvedByUser == null) {
1112 approvedByUser = new ArraySet<>();
1113 componentsByUser.put(userId, approvedByUser);
1114 }
1115 approvedByUser.addAll(
1116 loadComponentNamesFromValues(approvedLists.valueAt(j), userId));
Julia Reynoldsb852e562017-06-06 16:14:18 -04001117 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04001118 }
Julia Reynolds6e839b02016-04-13 10:01:17 -04001119 }
John Spurlock7340fc82014-04-24 18:50:12 -04001120 }
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001121 return componentsByUser;
1122 }
John Spurlock7340fc82014-04-24 18:50:12 -04001123
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001124 @GuardedBy("mMutex")
1125 protected void populateComponentsToBind(SparseArray<Set<ComponentName>> componentsToBind,
1126 final IntArray activeUsers,
1127 SparseArray<ArraySet<ComponentName>> approvedComponentsByUser) {
1128 mEnabledServicesForCurrentProfiles.clear();
1129 mEnabledServicesPackageNames.clear();
1130 final int nUserIds = activeUsers.size();
John Spurlock7340fc82014-04-24 18:50:12 -04001131
1132 for (int i = 0; i < nUserIds; ++i) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001133 // decode the list of components
1134 final int userId = activeUsers.get(i);
1135 final ArraySet<ComponentName> userComponents = approvedComponentsByUser.get(userId);
1136 if (null == userComponents) {
1137 componentsToBind.put(userId, new ArraySet<>());
1138 continue;
1139 }
1140
1141 final Set<ComponentName> add = new HashSet<>(userComponents);
1142 add.removeAll(mSnoozingForCurrentProfiles);
1143
1144 componentsToBind.put(userId, add);
1145
1146 mEnabledServicesForCurrentProfiles.addAll(userComponents);
1147
1148 for (int j = 0; j < userComponents.size(); j++) {
1149 final ComponentName component = userComponents.valueAt(j);
1150 mEnabledServicesPackageNames.add(component.getPackageName());
1151 }
1152 }
1153 }
1154
1155 @GuardedBy("mMutex")
1156 protected Set<ManagedServiceInfo> getRemovableConnectedServices() {
1157 final Set<ManagedServiceInfo> removableBoundServices = new ArraySet<>();
1158 for (ManagedServiceInfo service : mServices) {
1159 if (!service.isSystem && !service.isGuest(this)) {
1160 removableBoundServices.add(service);
1161 }
1162 }
1163 return removableBoundServices;
1164 }
1165
1166 protected void populateComponentsToUnbind(
1167 boolean forceRebind,
1168 Set<ManagedServiceInfo> removableBoundServices,
1169 SparseArray<Set<ComponentName>> allowedComponentsToBind,
1170 SparseArray<Set<ComponentName>> componentsToUnbind) {
1171 for (ManagedServiceInfo info : removableBoundServices) {
1172 final Set<ComponentName> allowedComponents = allowedComponentsToBind.get(info.userid);
1173 if (allowedComponents != null) {
1174 if (forceRebind || !allowedComponents.contains(info.component)) {
1175 Set<ComponentName> toUnbind =
1176 componentsToUnbind.get(info.userid, new ArraySet<>());
1177 toUnbind.add(info.component);
1178 componentsToUnbind.put(info.userid, toUnbind);
1179 }
1180 }
1181 }
1182 }
1183
1184 /**
1185 * Called whenever packages change, the user switches, or the secure setting
1186 * is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
1187 */
1188 protected void rebindServices(boolean forceRebind, int userToRebind) {
1189 if (DEBUG) Slog.d(TAG, "rebindServices " + forceRebind + " " + userToRebind);
1190 IntArray userIds = mUserProfiles.getCurrentProfileIds();
1191 if (userToRebind != USER_ALL) {
1192 userIds = new IntArray(1);
1193 userIds.add(userToRebind);
1194 }
1195
1196 final SparseArray<Set<ComponentName>> componentsToBind = new SparseArray<>();
1197 final SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>();
1198
1199 synchronized (mMutex) {
1200 final SparseArray<ArraySet<ComponentName>> approvedComponentsByUser =
1201 getAllowedComponents(userIds);
1202 final Set<ManagedServiceInfo> removableBoundServices = getRemovableConnectedServices();
1203
1204 // Filter approvedComponentsByUser to collect all of the components that are allowed
1205 // for the currently active user(s).
1206 populateComponentsToBind(componentsToBind, userIds, approvedComponentsByUser);
1207
1208 // For every current non-system connection, disconnect services that are no longer
1209 // approved, or ALL services if we are force rebinding
1210 populateComponentsToUnbind(
1211 forceRebind, removableBoundServices, componentsToBind, componentsToUnbind);
1212 }
1213
1214 unbindFromServices(componentsToUnbind);
1215 bindToServices(componentsToBind);
1216 }
1217
1218 protected void unbindFromServices(SparseArray<Set<ComponentName>> componentsToUnbind) {
1219 for (int i = 0; i < componentsToUnbind.size(); i++) {
1220 final int userId = componentsToUnbind.keyAt(i);
1221 final Set<ComponentName> removableComponents = componentsToUnbind.get(userId);
1222 for (ComponentName cn : removableComponents) {
1223 // No longer allowed to be bound, or must rebind.
1224 Slog.v(TAG, "disabling " + getCaption() + " for user " + userId + ": " + cn);
1225 unregisterService(cn, userId);
1226 }
1227 }
1228 }
1229
1230 // Attempt to bind to services, skipping those that cannot be found or lack the permission.
1231 private void bindToServices(SparseArray<Set<ComponentName>> componentsToBind) {
1232 for (int i = 0; i < componentsToBind.size(); i++) {
1233 final int userId = componentsToBind.keyAt(i);
1234 final Set<ComponentName> add = componentsToBind.get(userId);
Julia Reynolds9a86cc02016-02-10 15:38:15 -05001235 for (ComponentName component : add) {
Julia Reynoldsa75c7522017-03-21 17:34:25 -04001236 try {
1237 ServiceInfo info = mPm.getServiceInfo(component,
1238 PackageManager.MATCH_DIRECT_BOOT_AWARE
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001239 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
Julia Reynolds503ed942017-10-04 16:04:56 -04001240 if (info == null) {
1241 Slog.w(TAG, "Not binding " + getCaption() + " service " + component
1242 + ": service not found");
1243 continue;
1244 }
1245 if (!mConfig.bindPermission.equals(info.permission)) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04001246 Slog.w(TAG, "Not binding " + getCaption() + " service " + component
Julia Reynoldsa75c7522017-03-21 17:34:25 -04001247 + ": it does not require the permission " + mConfig.bindPermission);
1248 continue;
1249 }
1250 Slog.v(TAG,
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001251 "enabling " + getCaption() + " for " + userId + ": " + component);
1252 registerService(component, userId);
Julia Reynoldsa75c7522017-03-21 17:34:25 -04001253 } catch (RemoteException e) {
1254 e.rethrowFromSystemServer();
1255 }
John Spurlock7340fc82014-04-24 18:50:12 -04001256 }
1257 }
1258 }
1259
1260 /**
1261 * Version of registerService that takes the name of a service component to bind to.
1262 */
1263 private void registerService(final ComponentName name, final int userid) {
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001264 synchronized (mMutex) {
1265 registerServiceLocked(name, userid);
1266 }
1267 }
1268
Chris Wren0efdb882016-03-01 17:17:47 -05001269 /**
1270 * Inject a system service into the management list.
1271 */
1272 public void registerSystemService(final ComponentName name, final int userid) {
1273 synchronized (mMutex) {
1274 registerServiceLocked(name, userid, true /* isSystem */);
1275 }
1276 }
1277
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001278 private void registerServiceLocked(final ComponentName name, final int userid) {
Chris Wren0efdb882016-03-01 17:17:47 -05001279 registerServiceLocked(name, userid, false /* isSystem */);
1280 }
1281
1282 private void registerServiceLocked(final ComponentName name, final int userid,
1283 final boolean isSystem) {
John Spurlock7340fc82014-04-24 18:50:12 -04001284 if (DEBUG) Slog.v(TAG, "registerService: " + name + " u=" + userid);
1285
Andrew Zeng190c0672018-06-28 15:15:05 -07001286 final Pair<ComponentName, Integer> servicesBindingTag = Pair.create(name, userid);
1287 if (mServicesBound.contains(servicesBindingTag)) {
1288 Slog.v(TAG, "Not registering " + name + " is already bound");
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001289 // stop registering this thing already! we're working on it
1290 return;
1291 }
Andrew Zeng190c0672018-06-28 15:15:05 -07001292 mServicesBound.add(servicesBindingTag);
John Spurlock7340fc82014-04-24 18:50:12 -04001293
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001294 final int N = mServices.size();
1295 for (int i = N - 1; i >= 0; i--) {
1296 final ManagedServiceInfo info = mServices.get(i);
1297 if (name.equals(info.component)
1298 && info.userid == userid) {
1299 // cut old connections
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -04001300 Slog.v(TAG, " disconnecting old " + getCaption() + ": " + info.service);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001301 removeServiceLocked(i);
1302 if (info.connection != null) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001303 unbindService(info.connection, info.component, info.userid);
John Spurlock7340fc82014-04-24 18:50:12 -04001304 }
1305 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001306 }
John Spurlock7340fc82014-04-24 18:50:12 -04001307
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001308 Intent intent = new Intent(mConfig.serviceInterface);
1309 intent.setComponent(name);
John Spurlock7340fc82014-04-24 18:50:12 -04001310
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001311 intent.putExtra(Intent.EXTRA_CLIENT_LABEL, mConfig.clientLabel);
John Spurlock7340fc82014-04-24 18:50:12 -04001312
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001313 final PendingIntent pendingIntent = PendingIntent.getActivity(
1314 mContext, 0, new Intent(mConfig.settingsAction), 0);
1315 intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
John Spurlock7340fc82014-04-24 18:50:12 -04001316
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001317 ApplicationInfo appInfo = null;
1318 try {
1319 appInfo = mContext.getPackageManager().getApplicationInfo(
1320 name.getPackageName(), 0);
1321 } catch (NameNotFoundException e) {
1322 // Ignore if the package doesn't exist we won't be able to bind to the service.
1323 }
1324 final int targetSdkVersion =
1325 appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE;
John Spurlock7340fc82014-04-24 18:50:12 -04001326
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001327 try {
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -04001328 Slog.v(TAG, "binding: " + intent);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001329 ServiceConnection serviceConnection = new ServiceConnection() {
1330 IInterface mService;
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001331
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001332 @Override
1333 public void onServiceConnected(ComponentName name, IBinder binder) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001334 Slog.v(TAG, userid + " " + getCaption() + " service connected: " + name);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001335 boolean added = false;
1336 ManagedServiceInfo info = null;
1337 synchronized (mMutex) {
Ryan Lothian4a86a512017-12-04 11:56:58 -05001338 mServicesRebinding.remove(servicesBindingTag);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001339 try {
1340 mService = asInterface(binder);
1341 info = newServiceInfo(mService, name,
Chris Wren0efdb882016-03-01 17:17:47 -05001342 userid, isSystem, this, targetSdkVersion);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001343 binder.linkToDeath(info, 0);
1344 added = mServices.add(info);
1345 } catch (RemoteException e) {
Tony Mak180a9c42019-03-08 13:33:08 +00001346 Slog.e(TAG, "Failed to linkToDeath, already dead", e);
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001347 }
1348 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001349 if (added) {
1350 onServiceAdded(info);
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001351 }
John Spurlock7340fc82014-04-24 18:50:12 -04001352 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001353
1354 @Override
1355 public void onServiceDisconnected(ComponentName name) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001356 Slog.v(TAG, userid + " " + getCaption() + " connection lost: " + name);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001357 }
Ryan Lothian4a86a512017-12-04 11:56:58 -05001358
1359 @Override
1360 public void onBindingDied(ComponentName name) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001361 Slog.w(TAG, userid + " " + getCaption() + " binding died: " + name);
Ryan Lothian4a86a512017-12-04 11:56:58 -05001362 synchronized (mMutex) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001363 unbindService(this, name, userid);
Ryan Lothian4a86a512017-12-04 11:56:58 -05001364 if (!mServicesRebinding.contains(servicesBindingTag)) {
1365 mServicesRebinding.add(servicesBindingTag);
1366 mHandler.postDelayed(new Runnable() {
1367 @Override
1368 public void run() {
1369 registerService(name, userid);
1370 }
1371 }, ON_BINDING_DIED_REBIND_DELAY_MS);
1372 } else {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001373 Slog.v(TAG, getCaption() + " not rebinding in user " + userid
1374 + " as a previous rebind attempt was made: " + name);
Ryan Lothian4a86a512017-12-04 11:56:58 -05001375 }
1376 }
1377 }
Tony Mak180a9c42019-03-08 13:33:08 +00001378
1379 @Override
1380 public void onNullBinding(ComponentName name) {
1381 Slog.v(TAG, "onNullBinding() called with: name = [" + name + "]");
Julia Reynolds8a4f2ab2019-04-10 10:08:21 -04001382 mServicesBound.remove(servicesBindingTag);
Tony Mak180a9c42019-03-08 13:33:08 +00001383 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001384 };
1385 if (!mContext.bindServiceAsUser(intent,
Amith Yamasanie5bfeee2018-09-05 18:52:35 -07001386 serviceConnection,
1387 getBindFlags(),
1388 new UserHandle(userid))) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001389 mServicesBound.remove(servicesBindingTag);
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001390 Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent
1391 + " in user " + userid);
John Spurlock7340fc82014-04-24 18:50:12 -04001392 return;
1393 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001394 } catch (SecurityException ex) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001395 mServicesBound.remove(servicesBindingTag);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001396 Slog.e(TAG, "Unable to bind " + getCaption() + " service: " + intent, ex);
John Spurlock7340fc82014-04-24 18:50:12 -04001397 }
1398 }
1399
Julia Reynolds8a4f2ab2019-04-10 10:08:21 -04001400 boolean isBound(ComponentName cn, int userId) {
1401 final Pair<ComponentName, Integer> servicesBindingTag = Pair.create(cn, userId);
1402 return mServicesBound.contains(servicesBindingTag);
1403 }
1404
John Spurlock7340fc82014-04-24 18:50:12 -04001405 /**
1406 * Remove a service for the given user by ComponentName
1407 */
1408 private void unregisterService(ComponentName name, int userid) {
1409 synchronized (mMutex) {
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001410 unregisterServiceLocked(name, userid);
1411 }
1412 }
1413
1414 private void unregisterServiceLocked(ComponentName name, int userid) {
1415 final int N = mServices.size();
1416 for (int i = N - 1; i >= 0; i--) {
1417 final ManagedServiceInfo info = mServices.get(i);
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -04001418 if (name.equals(info.component) && info.userid == userid) {
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001419 removeServiceLocked(i);
1420 if (info.connection != null) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001421 unbindService(info.connection, info.component, info.userid);
John Spurlock7340fc82014-04-24 18:50:12 -04001422 }
1423 }
1424 }
1425 }
1426
1427 /**
1428 * Removes a service from the list but does not unbind
1429 *
1430 * @return the removed service.
1431 */
1432 private ManagedServiceInfo removeServiceImpl(IInterface service, final int userid) {
John Spurlocke77bb362014-04-26 10:24:59 -04001433 if (DEBUG) Slog.d(TAG, "removeServiceImpl service=" + service + " u=" + userid);
John Spurlock7340fc82014-04-24 18:50:12 -04001434 ManagedServiceInfo serviceInfo = null;
1435 synchronized (mMutex) {
1436 final int N = mServices.size();
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001437 for (int i = N - 1; i >= 0; i--) {
John Spurlock7340fc82014-04-24 18:50:12 -04001438 final ManagedServiceInfo info = mServices.get(i);
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -04001439 if (info.service.asBinder() == service.asBinder() && info.userid == userid) {
1440 Slog.d(TAG, "Removing active service " + info.component);
John Spurlocke77bb362014-04-26 10:24:59 -04001441 serviceInfo = removeServiceLocked(i);
John Spurlock7340fc82014-04-24 18:50:12 -04001442 }
1443 }
1444 }
1445 return serviceInfo;
1446 }
1447
John Spurlocke77bb362014-04-26 10:24:59 -04001448 private ManagedServiceInfo removeServiceLocked(int i) {
1449 final ManagedServiceInfo info = mServices.remove(i);
1450 onServiceRemovedLocked(info);
1451 return info;
1452 }
1453
John Spurlock7340fc82014-04-24 18:50:12 -04001454 private void checkNotNull(IInterface service) {
1455 if (service == null) {
1456 throw new IllegalArgumentException(getCaption() + " must not be null");
1457 }
1458 }
1459
Christoph Studer3e144d32014-05-22 16:48:40 +02001460 private ManagedServiceInfo registerServiceImpl(final IInterface service,
John Spurlock7340fc82014-04-24 18:50:12 -04001461 final ComponentName component, final int userid) {
Chris Wren51017d02015-12-15 15:34:46 -05001462 ManagedServiceInfo info = newServiceInfo(service, component, userid,
1463 true /*isSystem*/, null /*connection*/, Build.VERSION_CODES.LOLLIPOP);
1464 return registerServiceImpl(info);
1465 }
1466
1467 private ManagedServiceInfo registerServiceImpl(ManagedServiceInfo info) {
John Spurlock7340fc82014-04-24 18:50:12 -04001468 synchronized (mMutex) {
1469 try {
Chris Wren51017d02015-12-15 15:34:46 -05001470 info.service.asBinder().linkToDeath(info, 0);
John Spurlock7340fc82014-04-24 18:50:12 -04001471 mServices.add(info);
Christoph Studer3e144d32014-05-22 16:48:40 +02001472 return info;
John Spurlock7340fc82014-04-24 18:50:12 -04001473 } catch (RemoteException e) {
1474 // already dead
1475 }
1476 }
Christoph Studer3e144d32014-05-22 16:48:40 +02001477 return null;
John Spurlock7340fc82014-04-24 18:50:12 -04001478 }
1479
1480 /**
1481 * Removes a service from the list and unbinds.
1482 */
1483 private void unregisterServiceImpl(IInterface service, int userid) {
1484 ManagedServiceInfo info = removeServiceImpl(service, userid);
Chris Wren51017d02015-12-15 15:34:46 -05001485 if (info != null && info.connection != null && !info.isGuest(this)) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001486 unbindService(info.connection, info.component, info.userid);
1487 }
1488 }
1489
1490 private void unbindService(ServiceConnection connection, ComponentName component, int userId) {
1491 try {
1492 mContext.unbindService(connection);
1493 } catch (IllegalArgumentException e) {
1494 Slog.e(TAG, getCaption() + " " + component + " could not be unbound", e);
1495 }
1496 synchronized (mMutex) {
1497 mServicesBound.remove(Pair.create(component, userId));
John Spurlock7340fc82014-04-24 18:50:12 -04001498 }
1499 }
1500
John Spurlock7340fc82014-04-24 18:50:12 -04001501 public class ManagedServiceInfo implements IBinder.DeathRecipient {
1502 public IInterface service;
1503 public ComponentName component;
1504 public int userid;
1505 public boolean isSystem;
1506 public ServiceConnection connection;
1507 public int targetSdkVersion;
1508
1509 public ManagedServiceInfo(IInterface service, ComponentName component,
1510 int userid, boolean isSystem, ServiceConnection connection, int targetSdkVersion) {
1511 this.service = service;
1512 this.component = component;
1513 this.userid = userid;
1514 this.isSystem = isSystem;
1515 this.connection = connection;
1516 this.targetSdkVersion = targetSdkVersion;
1517 }
1518
Chris Wren51017d02015-12-15 15:34:46 -05001519 public boolean isGuest(ManagedServices host) {
1520 return ManagedServices.this != host;
1521 }
1522
Chris Wrenab41eec2016-01-04 18:01:27 -05001523 public ManagedServices getOwner() {
1524 return ManagedServices.this;
1525 }
1526
John Spurlocke77bb362014-04-26 10:24:59 -04001527 @Override
1528 public String toString() {
1529 return new StringBuilder("ManagedServiceInfo[")
1530 .append("component=").append(component)
1531 .append(",userid=").append(userid)
1532 .append(",isSystem=").append(isSystem)
1533 .append(",targetSdkVersion=").append(targetSdkVersion)
1534 .append(",connection=").append(connection == null ? null : "<connection>")
1535 .append(",service=").append(service)
1536 .append(']').toString();
1537 }
1538
Jeffrey Huangcb782852019-12-05 11:28:11 -08001539 public void dumpDebug(ProtoOutputStream proto, long fieldId, ManagedServices host) {
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001540 final long token = proto.start(fieldId);
Jeffrey Huangcb782852019-12-05 11:28:11 -08001541 component.dumpDebug(proto, ManagedServiceInfoProto.COMPONENT);
Kweku Adams93304b62017-09-20 17:03:00 -07001542 proto.write(ManagedServiceInfoProto.USER_ID, userid);
1543 proto.write(ManagedServiceInfoProto.SERVICE, service.getClass().getName());
1544 proto.write(ManagedServiceInfoProto.IS_SYSTEM, isSystem);
1545 proto.write(ManagedServiceInfoProto.IS_GUEST, isGuest(host));
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001546 proto.end(token);
Kweku Adams93304b62017-09-20 17:03:00 -07001547 }
1548
Julia Reynolds70aaea72018-07-13 13:38:34 -04001549 public boolean isSameUser(int userId) {
1550 if (!isEnabledForCurrentProfiles()) {
1551 return false;
1552 }
1553 return this.userid == userId;
1554 }
1555
John Spurlock7340fc82014-04-24 18:50:12 -04001556 public boolean enabledAndUserMatches(int nid) {
1557 if (!isEnabledForCurrentProfiles()) {
1558 return false;
1559 }
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001560 if (this.userid == USER_ALL) return true;
Chris Wren0c4eeb42016-05-12 13:21:08 -04001561 if (this.isSystem) return true;
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001562 if (nid == USER_ALL || nid == this.userid) return true;
Esteban Talavera9c6458d2017-03-30 17:59:50 +01001563 return supportsProfiles()
1564 && mUserProfiles.isCurrentProfile(nid)
1565 && isPermittedForProfile(nid);
John Spurlock7340fc82014-04-24 18:50:12 -04001566 }
1567
1568 public boolean supportsProfiles() {
Dianne Hackborn955d8d62014-10-07 20:17:19 -07001569 return targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP;
John Spurlock7340fc82014-04-24 18:50:12 -04001570 }
1571
1572 @Override
1573 public void binderDied() {
John Spurlocke77bb362014-04-26 10:24:59 -04001574 if (DEBUG) Slog.d(TAG, "binderDied");
John Spurlock7340fc82014-04-24 18:50:12 -04001575 // Remove the service, but don't unbind from the service. The system will bring the
Esteban Talavera9c6458d2017-03-30 17:59:50 +01001576 // service back up, and the onServiceConnected handler will read the service with the
John Spurlock7340fc82014-04-24 18:50:12 -04001577 // new binding. If this isn't a bound service, and is just a registered
1578 // service, just removing it from the list is all we need to do anyway.
1579 removeServiceImpl(this.service, this.userid);
1580 }
1581
1582 /** convenience method for looking in mEnabledServicesForCurrentProfiles */
1583 public boolean isEnabledForCurrentProfiles() {
1584 if (this.isSystem) return true;
1585 if (this.connection == null) return false;
1586 return mEnabledServicesForCurrentProfiles.contains(this.component);
1587 }
Esteban Talavera9c6458d2017-03-30 17:59:50 +01001588
1589 /**
1590 * Returns true if this service is allowed to receive events for the given userId. A
1591 * managed profile owner can disallow non-system services running outside of the profile
1592 * from receiving events from the profile.
1593 */
1594 public boolean isPermittedForProfile(int userId) {
1595 if (!mUserProfiles.isManagedProfile(userId)) {
1596 return true;
1597 }
1598 DevicePolicyManager dpm =
1599 (DevicePolicyManager) mContext.getSystemService(DEVICE_POLICY_SERVICE);
1600 final long identity = Binder.clearCallingIdentity();
1601 try {
1602 return dpm.isNotificationListenerServicePermitted(
1603 component.getPackageName(), userId);
1604 } finally {
1605 Binder.restoreCallingIdentity(identity);
1606 }
1607 }
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001608
1609 @Override
1610 public boolean equals(Object o) {
1611 if (this == o) return true;
1612 if (o == null || getClass() != o.getClass()) return false;
1613 ManagedServiceInfo that = (ManagedServiceInfo) o;
1614 return userid == that.userid
1615 && isSystem == that.isSystem
1616 && targetSdkVersion == that.targetSdkVersion
1617 && Objects.equals(service, that.service)
1618 && Objects.equals(component, that.component)
1619 && Objects.equals(connection, that.connection);
1620 }
1621
1622 @Override
1623 public int hashCode() {
1624 return Objects.hash(service, component, userid, isSystem, connection, targetSdkVersion);
1625 }
John Spurlock7340fc82014-04-24 18:50:12 -04001626 }
1627
Chris Wrenab41eec2016-01-04 18:01:27 -05001628 /** convenience method for looking in mEnabledServicesForCurrentProfiles */
1629 public boolean isComponentEnabledForCurrentProfiles(ComponentName component) {
1630 return mEnabledServicesForCurrentProfiles.contains(component);
1631 }
1632
John Spurlock7340fc82014-04-24 18:50:12 -04001633 public static class UserProfiles {
1634 // Profiles of the current user.
Ruben Brunke24b9a62016-02-16 21:38:24 -08001635 private final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
John Spurlock7340fc82014-04-24 18:50:12 -04001636
Ruben Brunke24b9a62016-02-16 21:38:24 -08001637 public void updateCache(@NonNull Context context) {
John Spurlock7340fc82014-04-24 18:50:12 -04001638 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
1639 if (userManager != null) {
1640 int currentUserId = ActivityManager.getCurrentUser();
1641 List<UserInfo> profiles = userManager.getProfiles(currentUserId);
1642 synchronized (mCurrentProfiles) {
1643 mCurrentProfiles.clear();
1644 for (UserInfo user : profiles) {
1645 mCurrentProfiles.put(user.id, user);
1646 }
1647 }
1648 }
1649 }
1650
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001651 /**
1652 * Returns the currently active users (generally one user and its work profile).
1653 */
1654 public IntArray getCurrentProfileIds() {
John Spurlock7340fc82014-04-24 18:50:12 -04001655 synchronized (mCurrentProfiles) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001656 IntArray users = new IntArray(mCurrentProfiles.size());
John Spurlock7340fc82014-04-24 18:50:12 -04001657 final int N = mCurrentProfiles.size();
1658 for (int i = 0; i < N; ++i) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001659 users.add(mCurrentProfiles.keyAt(i));
John Spurlock7340fc82014-04-24 18:50:12 -04001660 }
1661 return users;
1662 }
1663 }
1664
1665 public boolean isCurrentProfile(int userId) {
1666 synchronized (mCurrentProfiles) {
1667 return mCurrentProfiles.get(userId) != null;
1668 }
1669 }
Esteban Talavera9c6458d2017-03-30 17:59:50 +01001670
1671 public boolean isManagedProfile(int userId) {
1672 synchronized (mCurrentProfiles) {
1673 UserInfo user = mCurrentProfiles.get(userId);
1674 return user != null && user.isManagedProfile();
1675 }
1676 }
John Spurlock7340fc82014-04-24 18:50:12 -04001677 }
1678
Ruben Brunke24b9a62016-02-16 21:38:24 -08001679 public static class Config {
1680 public String caption;
1681 public String serviceInterface;
1682 public String secureSettingName;
Julia Reynolds6e839b02016-04-13 10:01:17 -04001683 public String secondarySettingName;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001684 public String xmlTag;
Ruben Brunke24b9a62016-02-16 21:38:24 -08001685 public String bindPermission;
1686 public String settingsAction;
1687 public int clientLabel;
John Spurlock7340fc82014-04-24 18:50:12 -04001688 }
1689}