blob: 90e9b927a4c773bc20644383610ad9cceb73e419 [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;
22
Ruben Brunke24b9a62016-02-16 21:38:24 -080023import android.annotation.NonNull;
John Spurlock7340fc82014-04-24 18:50:12 -040024import android.app.ActivityManager;
25import android.app.PendingIntent;
Christopher Tate6597e342015-02-17 12:15:25 -080026import android.content.BroadcastReceiver;
John Spurlock7340fc82014-04-24 18:50:12 -040027import android.content.ComponentName;
28import android.content.ContentResolver;
29import android.content.Context;
30import android.content.Intent;
Christopher Tate6597e342015-02-17 12:15:25 -080031import android.content.IntentFilter;
John Spurlock7340fc82014-04-24 18:50:12 -040032import android.content.ServiceConnection;
33import android.content.pm.ApplicationInfo;
Julia Reynoldsa75c7522017-03-21 17:34:25 -040034import android.content.pm.IPackageManager;
John Spurlock7340fc82014-04-24 18:50:12 -040035import android.content.pm.PackageManager;
36import android.content.pm.PackageManager.NameNotFoundException;
37import android.content.pm.ResolveInfo;
38import android.content.pm.ServiceInfo;
39import android.content.pm.UserInfo;
40import android.database.ContentObserver;
41import android.net.Uri;
42import android.os.Build;
43import android.os.Handler;
44import android.os.IBinder;
45import android.os.IInterface;
46import android.os.RemoteException;
Julia Reynoldsa75c7522017-03-21 17:34:25 -040047import android.os.ServiceManager;
John Spurlock7340fc82014-04-24 18:50:12 -040048import android.os.UserHandle;
49import android.os.UserManager;
50import android.provider.Settings;
51import android.text.TextUtils;
52import android.util.ArraySet;
John Spurlock4db0d982014-08-13 09:19:03 -040053import android.util.Log;
John Spurlock7340fc82014-04-24 18:50:12 -040054import android.util.Slog;
55import android.util.SparseArray;
56
John Spurlock25e2d242014-06-27 13:58:23 -040057import com.android.server.notification.NotificationManagerService.DumpFilter;
58
John Spurlock7340fc82014-04-24 18:50:12 -040059import java.io.PrintWriter;
60import java.util.ArrayList;
John Spurlocke77bb362014-04-26 10:24:59 -040061import java.util.Arrays;
Julia Reynolds9a86cc02016-02-10 15:38:15 -050062import java.util.HashSet;
John Spurlock7340fc82014-04-24 18:50:12 -040063import java.util.List;
Christopher Tate6597e342015-02-17 12:15:25 -080064import java.util.Objects;
John Spurlock7340fc82014-04-24 18:50:12 -040065import java.util.Set;
66
67/**
68 * Manages the lifecycle of application-provided services bound by system server.
69 *
70 * Services managed by this helper must have:
71 * - An associated system settings value with a list of enabled component names.
72 * - A well-known action for services to use in their intent-filter.
73 * - A system permission for services to require in order to ensure system has exclusive binding.
74 * - A settings page for user configuration of enabled services, and associated intent action.
75 * - A remote interface definition (aidl) provided by the service used for communication.
76 */
77abstract public class ManagedServices {
78 protected final String TAG = getClass().getSimpleName();
John Spurlock4db0d982014-08-13 09:19:03 -040079 protected final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
John Spurlock7340fc82014-04-24 18:50:12 -040080
Julia Reynoldsc279b992015-10-30 08:23:51 -040081 protected static final String ENABLED_SERVICES_SEPARATOR = ":";
John Spurlock7340fc82014-04-24 18:50:12 -040082
John Spurlockaf8d6c42014-05-07 17:49:08 -040083 protected final Context mContext;
John Spurlocke77bb362014-04-26 10:24:59 -040084 protected final Object mMutex;
John Spurlock7340fc82014-04-24 18:50:12 -040085 private final UserProfiles mUserProfiles;
86 private final SettingsObserver mSettingsObserver;
Julia Reynoldsa75c7522017-03-21 17:34:25 -040087 private final IPackageManager mPm;
John Spurlock7340fc82014-04-24 18:50:12 -040088 private final Config mConfig;
Christopher Tate6597e342015-02-17 12:15:25 -080089 private ArraySet<String> mRestored;
John Spurlock7340fc82014-04-24 18:50:12 -040090
91 // contains connections to all connected services, including app services
92 // and system services
Julia Reynolds00314d92017-04-14 10:01:24 -040093 private final ArrayList<ManagedServiceInfo> mServices = new ArrayList<ManagedServiceInfo>();
John Spurlock7340fc82014-04-24 18:50:12 -040094 // things that will be put into mServices as soon as they're ready
95 private final ArrayList<String> mServicesBinding = new ArrayList<String>();
Chris Wrenab41eec2016-01-04 18:01:27 -050096 // lists the component names of all enabled (and therefore potentially connected)
John Spurlock7340fc82014-04-24 18:50:12 -040097 // app services for current profiles.
98 private ArraySet<ComponentName> mEnabledServicesForCurrentProfiles
99 = new ArraySet<ComponentName>();
100 // Just the packages from mEnabledServicesForCurrentProfiles
101 private ArraySet<String> mEnabledServicesPackageNames = new ArraySet<String>();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200102 // List of packages in restored setting across all mUserProfiles, for quick
103 // filtering upon package updates.
104 private ArraySet<String> mRestoredPackages = new ArraySet<>();
Chris Wrenab41eec2016-01-04 18:01:27 -0500105 // List of enabled packages that have nevertheless asked not to be run
106 private ArraySet<ComponentName> mSnoozingForCurrentProfiles = new ArraySet<>();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200107
John Spurlock7340fc82014-04-24 18:50:12 -0400108
Christoph Studerb53dfd42014-09-12 14:45:59 +0200109 // Kept to de-dupe user change events (experienced after boot, when we receive a settings and a
110 // user change).
111 private int[] mLastSeenProfileIds;
112
Christopher Tate6597e342015-02-17 12:15:25 -0800113 private final BroadcastReceiver mRestoreReceiver;
114
John Spurlock7340fc82014-04-24 18:50:12 -0400115 public ManagedServices(Context context, Handler handler, Object mutex,
116 UserProfiles userProfiles) {
117 mContext = context;
118 mMutex = mutex;
119 mUserProfiles = userProfiles;
Julia Reynoldsa75c7522017-03-21 17:34:25 -0400120 mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
John Spurlock7340fc82014-04-24 18:50:12 -0400121 mConfig = getConfig();
122 mSettingsObserver = new SettingsObserver(handler);
Christopher Tate6597e342015-02-17 12:15:25 -0800123
124 mRestoreReceiver = new SettingRestoredReceiver();
125 IntentFilter filter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
126 context.registerReceiver(mRestoreReceiver, filter);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200127 rebuildRestoredPackages();
Christopher Tate6597e342015-02-17 12:15:25 -0800128 }
129
130 class SettingRestoredReceiver extends BroadcastReceiver {
131 @Override
132 public void onReceive(Context context, Intent intent) {
133 if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
134 String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
Julia Reynolds6e839b02016-04-13 10:01:17 -0400135 if (Objects.equals(element, mConfig.secureSettingName)
136 || Objects.equals(element, mConfig.secondarySettingName)) {
Christopher Tate6597e342015-02-17 12:15:25 -0800137 String prevValue = intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE);
138 String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
139 settingRestored(element, prevValue, newValue, getSendingUserId());
140 }
141 }
142 }
John Spurlock7340fc82014-04-24 18:50:12 -0400143 }
144
145 abstract protected Config getConfig();
146
147 private String getCaption() {
148 return mConfig.caption;
149 }
150
151 abstract protected IInterface asInterface(IBinder binder);
152
Chris Wren51017d02015-12-15 15:34:46 -0500153 abstract protected boolean checkType(IInterface service);
154
John Spurlock3b98b3f2014-05-01 09:08:48 -0400155 abstract protected void onServiceAdded(ManagedServiceInfo info);
John Spurlock7340fc82014-04-24 18:50:12 -0400156
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400157 protected List<ManagedServiceInfo> getServices() {
158 synchronized (mMutex) {
159 List<ManagedServiceInfo> services = new ArrayList<>(mServices);
160 return services;
161 }
162 }
163
John Spurlocke77bb362014-04-26 10:24:59 -0400164 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { }
165
John Spurlock7340fc82014-04-24 18:50:12 -0400166 private ManagedServiceInfo newServiceInfo(IInterface service,
167 ComponentName component, int userid, boolean isSystem, ServiceConnection connection,
168 int targetSdkVersion) {
169 return new ManagedServiceInfo(service, component, userid, isSystem, connection,
170 targetSdkVersion);
171 }
172
173 public void onBootPhaseAppsCanStart() {
174 mSettingsObserver.observe();
175 }
176
John Spurlock25e2d242014-06-27 13:58:23 -0400177 public void dump(PrintWriter pw, DumpFilter filter) {
John Spurlocke77bb362014-04-26 10:24:59 -0400178 pw.println(" All " + getCaption() + "s (" + mEnabledServicesForCurrentProfiles.size()
John Spurlock7340fc82014-04-24 18:50:12 -0400179 + ") enabled for current profiles:");
180 for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
John Spurlock25e2d242014-06-27 13:58:23 -0400181 if (filter != null && !filter.matches(cmpt)) continue;
John Spurlocke77bb362014-04-26 10:24:59 -0400182 pw.println(" " + cmpt);
John Spurlock7340fc82014-04-24 18:50:12 -0400183 }
184
John Spurlocke77bb362014-04-26 10:24:59 -0400185 pw.println(" Live " + getCaption() + "s (" + mServices.size() + "):");
John Spurlock7340fc82014-04-24 18:50:12 -0400186 for (ManagedServiceInfo info : mServices) {
John Spurlock25e2d242014-06-27 13:58:23 -0400187 if (filter != null && !filter.matches(info.component)) continue;
John Spurlocke77bb362014-04-26 10:24:59 -0400188 pw.println(" " + info.component
John Spurlock7340fc82014-04-24 18:50:12 -0400189 + " (user " + info.userid + "): " + info.service
Chris Wren51017d02015-12-15 15:34:46 -0500190 + (info.isSystem?" SYSTEM":"")
191 + (info.isGuest(this)?" GUEST":""));
John Spurlock7340fc82014-04-24 18:50:12 -0400192 }
Chris Wrenab41eec2016-01-04 18:01:27 -0500193
194 pw.println(" Snoozed " + getCaption() + "s (" +
195 mSnoozingForCurrentProfiles.size() + "):");
196 for (ComponentName name : mSnoozingForCurrentProfiles) {
197 pw.println(" " + name.flattenToShortString());
198 }
John Spurlock7340fc82014-04-24 18:50:12 -0400199 }
200
Christopher Tate6597e342015-02-17 12:15:25 -0800201 // By convention, restored settings are replicated to another settings
202 // entry, named similarly but with a disambiguation suffix.
Julia Reynolds6e839b02016-04-13 10:01:17 -0400203 public static String restoredSettingName(String setting) {
204 return setting + ":restored";
Christopher Tate6597e342015-02-17 12:15:25 -0800205 }
206
207 // The OS has done a restore of this service's saved state. We clone it to the
208 // 'restored' reserve, and then once we return and the actual write to settings is
209 // performed, our observer will do the work of maintaining the restored vs live
210 // settings data.
211 public void settingRestored(String element, String oldValue, String newValue, int userid) {
212 if (DEBUG) Slog.d(TAG, "Restored managed service setting: " + element
213 + " ovalue=" + oldValue + " nvalue=" + newValue);
Julia Reynolds6e839b02016-04-13 10:01:17 -0400214 if (mConfig.secureSettingName.equals(element) ||
215 mConfig.secondarySettingName.equals(element)) {
Christopher Tate6597e342015-02-17 12:15:25 -0800216 if (element != null) {
Christopher Tate6597e342015-02-17 12:15:25 -0800217 Settings.Secure.putStringForUser(mContext.getContentResolver(),
Julia Reynolds6e839b02016-04-13 10:01:17 -0400218 restoredSettingName(element),
Christopher Tate6597e342015-02-17 12:15:25 -0800219 newValue,
220 userid);
Julia Reynolds6e839b02016-04-13 10:01:17 -0400221 updateSettingsAccordingToInstalledServices(element, userid);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200222 rebuildRestoredPackages();
Christopher Tate6597e342015-02-17 12:15:25 -0800223 }
224 }
225 }
226
John Spurlock80774932015-05-07 17:38:50 -0400227 public boolean isComponentEnabledForPackage(String pkg) {
228 return mEnabledServicesPackageNames.contains(pkg);
229 }
230
Julia Reynolds6434eb22016-08-08 17:19:26 -0400231 public void onPackagesChanged(boolean removingPackage, String[] pkgList) {
232 if (DEBUG) Slog.d(TAG, "onPackagesChanged removingPackage=" + removingPackage
John Spurlocke77bb362014-04-26 10:24:59 -0400233 + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList))
234 + " mEnabledServicesPackageNames=" + mEnabledServicesPackageNames);
John Spurlock7340fc82014-04-24 18:50:12 -0400235 boolean anyServicesInvolved = false;
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200236
John Spurlock7340fc82014-04-24 18:50:12 -0400237 if (pkgList != null && (pkgList.length > 0)) {
238 for (String pkgName : pkgList) {
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200239 if (mEnabledServicesPackageNames.contains(pkgName) ||
240 mRestoredPackages.contains(pkgName)) {
John Spurlock7340fc82014-04-24 18:50:12 -0400241 anyServicesInvolved = true;
242 }
243 }
244 }
245
246 if (anyServicesInvolved) {
247 // if we're not replacing a package, clean up orphaned bits
Julia Reynolds6434eb22016-08-08 17:19:26 -0400248 if (removingPackage) {
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200249 updateSettingsAccordingToInstalledServices();
250 rebuildRestoredPackages();
John Spurlock7340fc82014-04-24 18:50:12 -0400251 }
252 // make sure we're still bound to any of our services who may have just upgraded
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400253 rebindServices(false);
John Spurlock7340fc82014-04-24 18:50:12 -0400254 }
255 }
256
John Spurlock1b8b22b2015-05-20 09:47:13 -0400257 public void onUserSwitched(int user) {
258 if (DEBUG) Slog.d(TAG, "onUserSwitched u=" + user);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200259 rebuildRestoredPackages();
Christoph Studerb53dfd42014-09-12 14:45:59 +0200260 if (Arrays.equals(mLastSeenProfileIds, mUserProfiles.getCurrentProfileIds())) {
261 if (DEBUG) Slog.d(TAG, "Current profile IDs didn't change, skipping rebindServices().");
262 return;
263 }
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400264 rebindServices(true);
Christoph Studerb53dfd42014-09-12 14:45:59 +0200265 }
266
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500267 public void onUserUnlocked(int user) {
268 if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
269 rebuildRestoredPackages();
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400270 rebindServices(false);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500271 }
272
Chris Wrenab41eec2016-01-04 18:01:27 -0500273 public ManagedServiceInfo getServiceFromTokenLocked(IInterface service) {
274 if (service == null) {
275 return null;
276 }
John Spurlock7340fc82014-04-24 18:50:12 -0400277 final IBinder token = service.asBinder();
278 final int N = mServices.size();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200279 for (int i = 0; i < N; i++) {
John Spurlock7340fc82014-04-24 18:50:12 -0400280 final ManagedServiceInfo info = mServices.get(i);
281 if (info.service.asBinder() == token) return info;
282 }
Chris Wrenab41eec2016-01-04 18:01:27 -0500283 return null;
284 }
285
286 public ManagedServiceInfo checkServiceTokenLocked(IInterface service) {
287 checkNotNull(service);
288 ManagedServiceInfo info = getServiceFromTokenLocked(service);
289 if (info != null) {
290 return info;
291 }
John Spurlock7340fc82014-04-24 18:50:12 -0400292 throw new SecurityException("Disallowed call from unknown " + getCaption() + ": "
293 + service);
294 }
295
296 public void unregisterService(IInterface service, int userid) {
297 checkNotNull(service);
298 // no need to check permissions; if your service binder is in the list,
299 // that's proof that you had permission to add it in the first place
300 unregisterServiceImpl(service, userid);
301 }
302
303 public void registerService(IInterface service, ComponentName component, int userid) {
304 checkNotNull(service);
Christoph Studer3e144d32014-05-22 16:48:40 +0200305 ManagedServiceInfo info = registerServiceImpl(service, component, userid);
306 if (info != null) {
307 onServiceAdded(info);
308 }
John Spurlock7340fc82014-04-24 18:50:12 -0400309 }
310
Chris Wren51017d02015-12-15 15:34:46 -0500311 /**
312 * Add a service to our callbacks. The lifecycle of this service is managed externally,
313 * but unlike a system service, it should not be considered privledged.
314 * */
315 public void registerGuestService(ManagedServiceInfo guest) {
316 checkNotNull(guest.service);
Ruben Brunke24b9a62016-02-16 21:38:24 -0800317 if (!checkType(guest.service)) {
318 throw new IllegalArgumentException();
319 }
Chris Wren51017d02015-12-15 15:34:46 -0500320 if (registerServiceImpl(guest) != null) {
321 onServiceAdded(guest);
Chris Wrenab41eec2016-01-04 18:01:27 -0500322 }
323 }
324
325 public void setComponentState(ComponentName component, boolean enabled) {
326 boolean previous = !mSnoozingForCurrentProfiles.contains(component);
327 if (previous == enabled) {
328 return;
329 }
330
331 if (enabled) {
332 mSnoozingForCurrentProfiles.remove(component);
333 } else {
334 mSnoozingForCurrentProfiles.add(component);
335 }
336
337 // State changed
338 if (DEBUG) {
339 Slog.d(TAG, ((enabled) ? "Enabling " : "Disabling ") + "component " +
340 component.flattenToShortString());
341 }
342
Chris Wren0efdb882016-03-01 17:17:47 -0500343
344 synchronized (mMutex) {
345 final int[] userIds = mUserProfiles.getCurrentProfileIds();
346
347 for (int userId : userIds) {
348 if (enabled) {
349 registerServiceLocked(component, userId);
350 } else {
351 unregisterServiceLocked(component, userId);
352 }
Chris Wrenab41eec2016-01-04 18:01:27 -0500353 }
Chris Wren51017d02015-12-15 15:34:46 -0500354 }
355 }
356
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200357 private void rebuildRestoredPackages() {
358 mRestoredPackages.clear();
Chris Wrenab41eec2016-01-04 18:01:27 -0500359 mSnoozingForCurrentProfiles.clear();
Julia Reynolds6e839b02016-04-13 10:01:17 -0400360 String secureSettingName = restoredSettingName(mConfig.secureSettingName);
361 String secondarySettingName = mConfig.secondarySettingName == null
362 ? null : restoredSettingName(mConfig.secondarySettingName);
John Spurlock7340fc82014-04-24 18:50:12 -0400363 int[] userIds = mUserProfiles.getCurrentProfileIds();
364 final int N = userIds.length;
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200365 for (int i = 0; i < N; ++i) {
Julia Reynolds6e839b02016-04-13 10:01:17 -0400366 ArraySet<ComponentName> names =
367 loadComponentNamesFromSetting(secureSettingName, userIds[i]);
368 if (secondarySettingName != null) {
369 names.addAll(loadComponentNamesFromSetting(secondarySettingName, userIds[i]));
370 }
371 for (ComponentName name : names) {
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200372 mRestoredPackages.add(name.getPackageName());
373 }
John Spurlock7340fc82014-04-24 18:50:12 -0400374 }
375 }
376
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200377
Julia Reynolds6e839b02016-04-13 10:01:17 -0400378 protected @NonNull ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
Julia Reynoldsc279b992015-10-30 08:23:51 -0400379 int userId) {
Christopher Tate6597e342015-02-17 12:15:25 -0800380 final ContentResolver cr = mContext.getContentResolver();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200381 String settingValue = Settings.Secure.getStringForUser(
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800382 cr,
383 settingName,
384 userId);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200385 if (TextUtils.isEmpty(settingValue))
Julia Reynolds6e839b02016-04-13 10:01:17 -0400386 return new ArraySet<>();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200387 String[] restored = settingValue.split(ENABLED_SERVICES_SEPARATOR);
388 ArraySet<ComponentName> result = new ArraySet<>(restored.length);
389 for (int i = 0; i < restored.length; i++) {
390 ComponentName value = ComponentName.unflattenFromString(restored[i]);
391 if (null != value) {
392 result.add(value);
Christopher Tate6597e342015-02-17 12:15:25 -0800393 }
394 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200395 return result;
396 }
John Spurlock7340fc82014-04-24 18:50:12 -0400397
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200398 private void storeComponentsToSetting(Set<ComponentName> components,
399 String settingName,
400 int userId) {
401 String[] componentNames = null;
402 if (null != components) {
403 componentNames = new String[components.size()];
404 int index = 0;
405 for (ComponentName c: components) {
406 componentNames[index++] = c.flattenToString();
407 }
408 }
409 final String value = (componentNames == null) ? "" :
410 TextUtils.join(ENABLED_SERVICES_SEPARATOR, componentNames);
411 final ContentResolver cr = mContext.getContentResolver();
412 Settings.Secure.putStringForUser(
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800413 cr,
414 settingName,
415 value,
416 userId);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200417 }
418
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200419 /**
420 * Remove access for any services that no longer exist.
421 */
422 private void updateSettingsAccordingToInstalledServices() {
423 int[] userIds = mUserProfiles.getCurrentProfileIds();
424 final int N = userIds.length;
425 for (int i = 0; i < N; ++i) {
Julia Reynolds6e839b02016-04-13 10:01:17 -0400426 updateSettingsAccordingToInstalledServices(mConfig.secureSettingName, userIds[i]);
427 if (mConfig.secondarySettingName != null) {
428 updateSettingsAccordingToInstalledServices(
429 mConfig.secondarySettingName, userIds[i]);
430 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200431 }
432 rebuildRestoredPackages();
433 }
434
Julia Reynoldsc279b992015-10-30 08:23:51 -0400435 protected Set<ComponentName> queryPackageForServices(String packageName, int userId) {
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200436 Set<ComponentName> installed = new ArraySet<>();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200437 final PackageManager pm = mContext.getPackageManager();
Julia Reynoldsc279b992015-10-30 08:23:51 -0400438 Intent queryIntent = new Intent(mConfig.serviceInterface);
439 if (!TextUtils.isEmpty(packageName)) {
440 queryIntent.setPackage(packageName);
441 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200442 List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
Julia Reynoldsc279b992015-10-30 08:23:51 -0400443 queryIntent,
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200444 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
445 userId);
446 if (DEBUG)
447 Slog.v(TAG, mConfig.serviceInterface + " services: " + installedServices);
Julia Reynolds50f05142015-10-30 17:03:59 -0400448 if (installedServices != null) {
449 for (int i = 0, count = installedServices.size(); i < count; i++) {
450 ResolveInfo resolveInfo = installedServices.get(i);
451 ServiceInfo info = resolveInfo.serviceInfo;
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200452
Julia Reynolds50f05142015-10-30 17:03:59 -0400453 ComponentName component = new ComponentName(info.packageName, info.name);
454 if (!mConfig.bindPermission.equals(info.permission)) {
455 Slog.w(TAG, "Skipping " + getCaption() + " service "
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800456 + info.packageName + "/" + info.name
457 + ": it does not require the permission "
458 + mConfig.bindPermission);
Julia Reynolds50f05142015-10-30 17:03:59 -0400459 continue;
460 }
461 installed.add(component);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200462 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200463 }
Julia Reynoldsc279b992015-10-30 08:23:51 -0400464 return installed;
465 }
466
Julia Reynolds6e839b02016-04-13 10:01:17 -0400467 private void updateSettingsAccordingToInstalledServices(String setting, int userId) {
Julia Reynoldsc279b992015-10-30 08:23:51 -0400468 boolean restoredChanged = false;
469 boolean currentChanged = false;
470 Set<ComponentName> restored =
Julia Reynolds6e839b02016-04-13 10:01:17 -0400471 loadComponentNamesFromSetting(restoredSettingName(setting), userId);
Julia Reynoldsc279b992015-10-30 08:23:51 -0400472 Set<ComponentName> current =
Julia Reynolds6e839b02016-04-13 10:01:17 -0400473 loadComponentNamesFromSetting(setting, userId);
Julia Reynoldsc279b992015-10-30 08:23:51 -0400474 // Load all services for all packages.
475 Set<ComponentName> installed = queryPackageForServices(null, userId);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200476
477 ArraySet<ComponentName> retained = new ArraySet<>();
478
479 for (ComponentName component : installed) {
480 if (null != restored) {
481 boolean wasRestored = restored.remove(component);
482 if (wasRestored) {
483 // Freshly installed package has service that was mentioned in restored setting.
484 if (DEBUG)
485 Slog.v(TAG, "Restoring " + component + " for user " + userId);
486 restoredChanged = true;
487 currentChanged = true;
488 retained.add(component);
John Spurlock7340fc82014-04-24 18:50:12 -0400489 continue;
490 }
John Spurlock7340fc82014-04-24 18:50:12 -0400491 }
492
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200493 if (null != current) {
494 if (current.contains(component))
495 retained.add(component);
John Spurlock7340fc82014-04-24 18:50:12 -0400496 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200497 }
498
499 currentChanged |= ((current == null ? 0 : current.size()) != retained.size());
500
501 if (currentChanged) {
502 if (DEBUG) Slog.v(TAG, "List of " + getCaption() + " services was updated " + current);
Julia Reynolds6e839b02016-04-13 10:01:17 -0400503 storeComponentsToSetting(retained, setting, userId);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200504 }
505
506 if (restoredChanged) {
507 if (DEBUG) Slog.v(TAG,
508 "List of " + getCaption() + " restored services was updated " + restored);
Julia Reynolds6e839b02016-04-13 10:01:17 -0400509 storeComponentsToSetting(restored, restoredSettingName(setting), userId);
John Spurlock7340fc82014-04-24 18:50:12 -0400510 }
511 }
512
513 /**
514 * Called whenever packages change, the user switches, or the secure setting
515 * is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
516 */
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400517 private void rebindServices(boolean forceRebind) {
John Spurlock7340fc82014-04-24 18:50:12 -0400518 if (DEBUG) Slog.d(TAG, "rebindServices");
519 final int[] userIds = mUserProfiles.getCurrentProfileIds();
520 final int nUserIds = userIds.length;
521
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200522 final SparseArray<ArraySet<ComponentName>> componentsByUser = new SparseArray<>();
John Spurlock7340fc82014-04-24 18:50:12 -0400523
524 for (int i = 0; i < nUserIds; ++i) {
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200525 componentsByUser.put(userIds[i],
526 loadComponentNamesFromSetting(mConfig.secureSettingName, userIds[i]));
Julia Reynolds6e839b02016-04-13 10:01:17 -0400527 if (mConfig.secondarySettingName != null) {
528 componentsByUser.get(userIds[i]).addAll(
529 loadComponentNamesFromSetting(mConfig.secondarySettingName, userIds[i]));
530 }
John Spurlock7340fc82014-04-24 18:50:12 -0400531 }
532
Julia Reynolds9a86cc02016-02-10 15:38:15 -0500533 final ArrayList<ManagedServiceInfo> removableBoundServices = new ArrayList<>();
534 final SparseArray<Set<ComponentName>> toAdd = new SparseArray<>();
John Spurlock7340fc82014-04-24 18:50:12 -0400535
536 synchronized (mMutex) {
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400537 // Rebind to non-system services if user switched
Christoph Studer5d423842014-05-23 13:15:54 +0200538 for (ManagedServiceInfo service : mServices) {
Chris Wren51017d02015-12-15 15:34:46 -0500539 if (!service.isSystem && !service.isGuest(this)) {
Julia Reynolds9a86cc02016-02-10 15:38:15 -0500540 removableBoundServices.add(service);
Christoph Studer5d423842014-05-23 13:15:54 +0200541 }
542 }
John Spurlock7340fc82014-04-24 18:50:12 -0400543
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400544 mEnabledServicesForCurrentProfiles.clear();
545 mEnabledServicesPackageNames.clear();
John Spurlock7340fc82014-04-24 18:50:12 -0400546
547 for (int i = 0; i < nUserIds; ++i) {
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200548 // decode the list of components
549 final ArraySet<ComponentName> userComponents = componentsByUser.get(userIds[i]);
550 if (null == userComponents) {
Julia Reynolds6e839b02016-04-13 10:01:17 -0400551 toAdd.put(userIds[i], new ArraySet<ComponentName>());
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200552 continue;
553 }
554
Julia Reynolds9a86cc02016-02-10 15:38:15 -0500555 final Set<ComponentName> add = new HashSet<>(userComponents);
Chris Wrenab41eec2016-01-04 18:01:27 -0500556 add.removeAll(mSnoozingForCurrentProfiles);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800557
John Spurlock7340fc82014-04-24 18:50:12 -0400558 toAdd.put(userIds[i], add);
559
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400560 mEnabledServicesForCurrentProfiles.addAll(userComponents);
John Spurlock7340fc82014-04-24 18:50:12 -0400561
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200562 for (int j = 0; j < userComponents.size(); j++) {
Chris Wren083094c2015-12-15 16:25:07 -0500563 final ComponentName component = userComponents.valueAt(j);
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400564 mEnabledServicesPackageNames.add(component.getPackageName());
John Spurlock7340fc82014-04-24 18:50:12 -0400565 }
566 }
John Spurlock7340fc82014-04-24 18:50:12 -0400567 }
568
Julia Reynolds9a86cc02016-02-10 15:38:15 -0500569 for (ManagedServiceInfo info : removableBoundServices) {
John Spurlock7340fc82014-04-24 18:50:12 -0400570 final ComponentName component = info.component;
571 final int oldUser = info.userid;
Julia Reynolds9a86cc02016-02-10 15:38:15 -0500572 final Set<ComponentName> allowedComponents = toAdd.get(info.userid);
573 if (allowedComponents != null) {
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400574 if (allowedComponents.contains(component) && !forceRebind) {
Julia Reynolds9a86cc02016-02-10 15:38:15 -0500575 // Already bound, don't need to bind again.
576 allowedComponents.remove(component);
577 } else {
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400578 // No longer allowed to be bound, or must rebind.
Julia Reynolds9a86cc02016-02-10 15:38:15 -0500579 Slog.v(TAG, "disabling " + getCaption() + " for user "
580 + oldUser + ": " + component);
581 unregisterService(component, oldUser);
582 }
583 }
John Spurlock7340fc82014-04-24 18:50:12 -0400584 }
585
586 for (int i = 0; i < nUserIds; ++i) {
Julia Reynolds9a86cc02016-02-10 15:38:15 -0500587 final Set<ComponentName> add = toAdd.get(userIds[i]);
588 for (ComponentName component : add) {
Julia Reynoldsa75c7522017-03-21 17:34:25 -0400589 try {
590 ServiceInfo info = mPm.getServiceInfo(component,
591 PackageManager.MATCH_DIRECT_BOOT_AWARE
592 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userIds[i]);
Julia Reynolds8bb5c932017-03-23 14:09:06 -0400593 if (info == null || !mConfig.bindPermission.equals(info.permission)) {
Julia Reynoldsa75c7522017-03-21 17:34:25 -0400594 Slog.w(TAG, "Skipping " + getCaption() + " service " + component
595 + ": it does not require the permission " + mConfig.bindPermission);
596 continue;
597 }
598 Slog.v(TAG,
599 "enabling " + getCaption() + " for " + userIds[i] + ": " + component);
600 registerService(component, userIds[i]);
601 } catch (RemoteException e) {
602 e.rethrowFromSystemServer();
603 }
John Spurlock7340fc82014-04-24 18:50:12 -0400604 }
605 }
Christoph Studerb53dfd42014-09-12 14:45:59 +0200606
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200607 mLastSeenProfileIds = userIds;
John Spurlock7340fc82014-04-24 18:50:12 -0400608 }
609
610 /**
611 * Version of registerService that takes the name of a service component to bind to.
612 */
613 private void registerService(final ComponentName name, final int userid) {
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800614 synchronized (mMutex) {
615 registerServiceLocked(name, userid);
616 }
617 }
618
Chris Wren0efdb882016-03-01 17:17:47 -0500619 /**
620 * Inject a system service into the management list.
621 */
622 public void registerSystemService(final ComponentName name, final int userid) {
623 synchronized (mMutex) {
624 registerServiceLocked(name, userid, true /* isSystem */);
625 }
626 }
627
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800628 private void registerServiceLocked(final ComponentName name, final int userid) {
Chris Wren0efdb882016-03-01 17:17:47 -0500629 registerServiceLocked(name, userid, false /* isSystem */);
630 }
631
632 private void registerServiceLocked(final ComponentName name, final int userid,
633 final boolean isSystem) {
John Spurlock7340fc82014-04-24 18:50:12 -0400634 if (DEBUG) Slog.v(TAG, "registerService: " + name + " u=" + userid);
635
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800636 final String servicesBindingTag = name.toString() + "/" + userid;
637 if (mServicesBinding.contains(servicesBindingTag)) {
638 // stop registering this thing already! we're working on it
639 return;
640 }
641 mServicesBinding.add(servicesBindingTag);
John Spurlock7340fc82014-04-24 18:50:12 -0400642
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800643 final int N = mServices.size();
644 for (int i = N - 1; i >= 0; i--) {
645 final ManagedServiceInfo info = mServices.get(i);
646 if (name.equals(info.component)
647 && info.userid == userid) {
648 // cut old connections
649 if (DEBUG) Slog.v(TAG, " disconnecting old " + getCaption() + ": "
650 + info.service);
651 removeServiceLocked(i);
652 if (info.connection != null) {
653 mContext.unbindService(info.connection);
John Spurlock7340fc82014-04-24 18:50:12 -0400654 }
655 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800656 }
John Spurlock7340fc82014-04-24 18:50:12 -0400657
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800658 Intent intent = new Intent(mConfig.serviceInterface);
659 intent.setComponent(name);
John Spurlock7340fc82014-04-24 18:50:12 -0400660
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800661 intent.putExtra(Intent.EXTRA_CLIENT_LABEL, mConfig.clientLabel);
John Spurlock7340fc82014-04-24 18:50:12 -0400662
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800663 final PendingIntent pendingIntent = PendingIntent.getActivity(
664 mContext, 0, new Intent(mConfig.settingsAction), 0);
665 intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
John Spurlock7340fc82014-04-24 18:50:12 -0400666
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800667 ApplicationInfo appInfo = null;
668 try {
669 appInfo = mContext.getPackageManager().getApplicationInfo(
670 name.getPackageName(), 0);
671 } catch (NameNotFoundException e) {
672 // Ignore if the package doesn't exist we won't be able to bind to the service.
673 }
674 final int targetSdkVersion =
675 appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE;
John Spurlock7340fc82014-04-24 18:50:12 -0400676
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800677 try {
678 if (DEBUG) Slog.v(TAG, "binding: " + intent);
679 ServiceConnection serviceConnection = new ServiceConnection() {
680 IInterface mService;
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200681
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800682 @Override
683 public void onServiceConnected(ComponentName name, IBinder binder) {
684 boolean added = false;
685 ManagedServiceInfo info = null;
686 synchronized (mMutex) {
687 mServicesBinding.remove(servicesBindingTag);
688 try {
689 mService = asInterface(binder);
690 info = newServiceInfo(mService, name,
Chris Wren0efdb882016-03-01 17:17:47 -0500691 userid, isSystem, this, targetSdkVersion);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800692 binder.linkToDeath(info, 0);
693 added = mServices.add(info);
694 } catch (RemoteException e) {
695 // already dead
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200696 }
697 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800698 if (added) {
699 onServiceAdded(info);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200700 }
John Spurlock7340fc82014-04-24 18:50:12 -0400701 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800702
703 @Override
704 public void onServiceDisconnected(ComponentName name) {
705 Slog.v(TAG, getCaption() + " connection lost: " + name);
706 }
707 };
708 if (!mContext.bindServiceAsUser(intent,
709 serviceConnection,
Felipe Lemea1b79bf2016-05-24 13:06:54 -0700710 BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE | BIND_ALLOW_WHITELIST_MANAGEMENT,
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800711 new UserHandle(userid))) {
712 mServicesBinding.remove(servicesBindingTag);
713 Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent);
John Spurlock7340fc82014-04-24 18:50:12 -0400714 return;
715 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800716 } catch (SecurityException ex) {
717 Slog.e(TAG, "Unable to bind " + getCaption() + " service: " + intent, ex);
718 return;
John Spurlock7340fc82014-04-24 18:50:12 -0400719 }
720 }
721
722 /**
723 * Remove a service for the given user by ComponentName
724 */
725 private void unregisterService(ComponentName name, int userid) {
726 synchronized (mMutex) {
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800727 unregisterServiceLocked(name, userid);
728 }
729 }
730
731 private void unregisterServiceLocked(ComponentName name, int userid) {
732 final int N = mServices.size();
733 for (int i = N - 1; i >= 0; i--) {
734 final ManagedServiceInfo info = mServices.get(i);
735 if (name.equals(info.component)
736 && info.userid == userid) {
737 removeServiceLocked(i);
738 if (info.connection != null) {
739 try {
740 mContext.unbindService(info.connection);
741 } catch (IllegalArgumentException ex) {
742 // something happened to the service: we think we have a connection
743 // but it's bogus.
744 Slog.e(TAG, getCaption() + " " + name + " could not be unbound: " + ex);
John Spurlock7340fc82014-04-24 18:50:12 -0400745 }
746 }
747 }
748 }
749 }
750
751 /**
752 * Removes a service from the list but does not unbind
753 *
754 * @return the removed service.
755 */
756 private ManagedServiceInfo removeServiceImpl(IInterface service, final int userid) {
John Spurlocke77bb362014-04-26 10:24:59 -0400757 if (DEBUG) Slog.d(TAG, "removeServiceImpl service=" + service + " u=" + userid);
John Spurlock7340fc82014-04-24 18:50:12 -0400758 ManagedServiceInfo serviceInfo = null;
759 synchronized (mMutex) {
760 final int N = mServices.size();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200761 for (int i = N - 1; i >= 0; i--) {
John Spurlock7340fc82014-04-24 18:50:12 -0400762 final ManagedServiceInfo info = mServices.get(i);
763 if (info.service.asBinder() == service.asBinder()
764 && info.userid == userid) {
John Spurlocke77bb362014-04-26 10:24:59 -0400765 if (DEBUG) Slog.d(TAG, "Removing active service " + info.component);
766 serviceInfo = removeServiceLocked(i);
John Spurlock7340fc82014-04-24 18:50:12 -0400767 }
768 }
769 }
770 return serviceInfo;
771 }
772
John Spurlocke77bb362014-04-26 10:24:59 -0400773 private ManagedServiceInfo removeServiceLocked(int i) {
774 final ManagedServiceInfo info = mServices.remove(i);
775 onServiceRemovedLocked(info);
776 return info;
777 }
778
John Spurlock7340fc82014-04-24 18:50:12 -0400779 private void checkNotNull(IInterface service) {
780 if (service == null) {
781 throw new IllegalArgumentException(getCaption() + " must not be null");
782 }
783 }
784
Christoph Studer3e144d32014-05-22 16:48:40 +0200785 private ManagedServiceInfo registerServiceImpl(final IInterface service,
John Spurlock7340fc82014-04-24 18:50:12 -0400786 final ComponentName component, final int userid) {
Chris Wren51017d02015-12-15 15:34:46 -0500787 ManagedServiceInfo info = newServiceInfo(service, component, userid,
788 true /*isSystem*/, null /*connection*/, Build.VERSION_CODES.LOLLIPOP);
789 return registerServiceImpl(info);
790 }
791
792 private ManagedServiceInfo registerServiceImpl(ManagedServiceInfo info) {
John Spurlock7340fc82014-04-24 18:50:12 -0400793 synchronized (mMutex) {
794 try {
Chris Wren51017d02015-12-15 15:34:46 -0500795 info.service.asBinder().linkToDeath(info, 0);
John Spurlock7340fc82014-04-24 18:50:12 -0400796 mServices.add(info);
Christoph Studer3e144d32014-05-22 16:48:40 +0200797 return info;
John Spurlock7340fc82014-04-24 18:50:12 -0400798 } catch (RemoteException e) {
799 // already dead
800 }
801 }
Christoph Studer3e144d32014-05-22 16:48:40 +0200802 return null;
John Spurlock7340fc82014-04-24 18:50:12 -0400803 }
804
805 /**
806 * Removes a service from the list and unbinds.
807 */
808 private void unregisterServiceImpl(IInterface service, int userid) {
809 ManagedServiceInfo info = removeServiceImpl(service, userid);
Chris Wren51017d02015-12-15 15:34:46 -0500810 if (info != null && info.connection != null && !info.isGuest(this)) {
John Spurlock7340fc82014-04-24 18:50:12 -0400811 mContext.unbindService(info.connection);
812 }
813 }
814
815 private class SettingsObserver extends ContentObserver {
816 private final Uri mSecureSettingsUri = Settings.Secure.getUriFor(mConfig.secureSettingName);
Julia Reynolds6e839b02016-04-13 10:01:17 -0400817 private final Uri mSecondarySettingsUri;
John Spurlock7340fc82014-04-24 18:50:12 -0400818
819 private SettingsObserver(Handler handler) {
820 super(handler);
Julia Reynolds6e839b02016-04-13 10:01:17 -0400821 if (mConfig.secondarySettingName != null) {
822 mSecondarySettingsUri = Settings.Secure.getUriFor(mConfig.secondarySettingName);
823 } else {
824 mSecondarySettingsUri = null;
825 }
John Spurlock7340fc82014-04-24 18:50:12 -0400826 }
827
828 private void observe() {
829 ContentResolver resolver = mContext.getContentResolver();
830 resolver.registerContentObserver(mSecureSettingsUri,
831 false, this, UserHandle.USER_ALL);
Julia Reynolds6e839b02016-04-13 10:01:17 -0400832 if (mSecondarySettingsUri != null) {
833 resolver.registerContentObserver(mSecondarySettingsUri,
834 false, this, UserHandle.USER_ALL);
835 }
John Spurlock7340fc82014-04-24 18:50:12 -0400836 update(null);
837 }
838
839 @Override
840 public void onChange(boolean selfChange, Uri uri) {
841 update(uri);
842 }
843
844 private void update(Uri uri) {
Julia Reynolds6e839b02016-04-13 10:01:17 -0400845 if (uri == null || mSecureSettingsUri.equals(uri)
846 || uri.equals(mSecondarySettingsUri)) {
847 if (DEBUG) Slog.d(TAG, "Setting changed: uri=" + uri);
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400848 rebindServices(false);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200849 rebuildRestoredPackages();
John Spurlock7340fc82014-04-24 18:50:12 -0400850 }
851 }
852 }
853
854 public class ManagedServiceInfo implements IBinder.DeathRecipient {
855 public IInterface service;
856 public ComponentName component;
857 public int userid;
858 public boolean isSystem;
859 public ServiceConnection connection;
860 public int targetSdkVersion;
861
862 public ManagedServiceInfo(IInterface service, ComponentName component,
863 int userid, boolean isSystem, ServiceConnection connection, int targetSdkVersion) {
864 this.service = service;
865 this.component = component;
866 this.userid = userid;
867 this.isSystem = isSystem;
868 this.connection = connection;
869 this.targetSdkVersion = targetSdkVersion;
870 }
871
Chris Wren51017d02015-12-15 15:34:46 -0500872 public boolean isGuest(ManagedServices host) {
873 return ManagedServices.this != host;
874 }
875
Chris Wrenab41eec2016-01-04 18:01:27 -0500876 public ManagedServices getOwner() {
877 return ManagedServices.this;
878 }
879
John Spurlocke77bb362014-04-26 10:24:59 -0400880 @Override
881 public String toString() {
882 return new StringBuilder("ManagedServiceInfo[")
883 .append("component=").append(component)
884 .append(",userid=").append(userid)
885 .append(",isSystem=").append(isSystem)
886 .append(",targetSdkVersion=").append(targetSdkVersion)
887 .append(",connection=").append(connection == null ? null : "<connection>")
888 .append(",service=").append(service)
889 .append(']').toString();
890 }
891
John Spurlock7340fc82014-04-24 18:50:12 -0400892 public boolean enabledAndUserMatches(int nid) {
893 if (!isEnabledForCurrentProfiles()) {
894 return false;
895 }
896 if (this.userid == UserHandle.USER_ALL) return true;
Chris Wren0c4eeb42016-05-12 13:21:08 -0400897 if (this.isSystem) return true;
John Spurlock7340fc82014-04-24 18:50:12 -0400898 if (nid == UserHandle.USER_ALL || nid == this.userid) return true;
899 return supportsProfiles() && mUserProfiles.isCurrentProfile(nid);
900 }
901
902 public boolean supportsProfiles() {
Dianne Hackborn955d8d62014-10-07 20:17:19 -0700903 return targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP;
John Spurlock7340fc82014-04-24 18:50:12 -0400904 }
905
906 @Override
907 public void binderDied() {
John Spurlocke77bb362014-04-26 10:24:59 -0400908 if (DEBUG) Slog.d(TAG, "binderDied");
John Spurlock7340fc82014-04-24 18:50:12 -0400909 // Remove the service, but don't unbind from the service. The system will bring the
910 // service back up, and the onServiceConnected handler will readd the service with the
911 // new binding. If this isn't a bound service, and is just a registered
912 // service, just removing it from the list is all we need to do anyway.
913 removeServiceImpl(this.service, this.userid);
914 }
915
916 /** convenience method for looking in mEnabledServicesForCurrentProfiles */
917 public boolean isEnabledForCurrentProfiles() {
918 if (this.isSystem) return true;
919 if (this.connection == null) return false;
920 return mEnabledServicesForCurrentProfiles.contains(this.component);
921 }
922 }
923
Chris Wrenab41eec2016-01-04 18:01:27 -0500924 /** convenience method for looking in mEnabledServicesForCurrentProfiles */
925 public boolean isComponentEnabledForCurrentProfiles(ComponentName component) {
926 return mEnabledServicesForCurrentProfiles.contains(component);
927 }
928
John Spurlock7340fc82014-04-24 18:50:12 -0400929 public static class UserProfiles {
930 // Profiles of the current user.
Ruben Brunke24b9a62016-02-16 21:38:24 -0800931 private final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
John Spurlock7340fc82014-04-24 18:50:12 -0400932
Ruben Brunke24b9a62016-02-16 21:38:24 -0800933 public void updateCache(@NonNull Context context) {
John Spurlock7340fc82014-04-24 18:50:12 -0400934 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
935 if (userManager != null) {
936 int currentUserId = ActivityManager.getCurrentUser();
937 List<UserInfo> profiles = userManager.getProfiles(currentUserId);
938 synchronized (mCurrentProfiles) {
939 mCurrentProfiles.clear();
940 for (UserInfo user : profiles) {
941 mCurrentProfiles.put(user.id, user);
942 }
943 }
944 }
945 }
946
947 public int[] getCurrentProfileIds() {
948 synchronized (mCurrentProfiles) {
949 int[] users = new int[mCurrentProfiles.size()];
950 final int N = mCurrentProfiles.size();
951 for (int i = 0; i < N; ++i) {
952 users[i] = mCurrentProfiles.keyAt(i);
953 }
954 return users;
955 }
956 }
957
958 public boolean isCurrentProfile(int userId) {
959 synchronized (mCurrentProfiles) {
960 return mCurrentProfiles.get(userId) != null;
961 }
962 }
963 }
964
Ruben Brunke24b9a62016-02-16 21:38:24 -0800965 public static class Config {
966 public String caption;
967 public String serviceInterface;
968 public String secureSettingName;
Julia Reynolds6e839b02016-04-13 10:01:17 -0400969 public String secondarySettingName;
Ruben Brunke24b9a62016-02-16 21:38:24 -0800970 public String bindPermission;
971 public String settingsAction;
972 public int clientLabel;
John Spurlock7340fc82014-04-24 18:50:12 -0400973 }
974}