blob: b8d633fc666f392169bdd89e2b90577ddc71b08a [file] [log] [blame]
John Spurlock7340fc82014-04-24 18:50:12 -04001/**
2 * Copyright (c) 2014, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.notification;
18
Felipe Lemea1b79bf2016-05-24 13:06:54 -070019import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT;
20import static android.content.Context.BIND_AUTO_CREATE;
21import static android.content.Context.BIND_FOREGROUND_SERVICE;
Esteban Talavera9c6458d2017-03-30 17:59:50 +010022import static android.content.Context.DEVICE_POLICY_SERVICE;
Felipe Lemea1b79bf2016-05-24 13:06:54 -070023
Ruben Brunke24b9a62016-02-16 21:38:24 -080024import android.annotation.NonNull;
John Spurlock7340fc82014-04-24 18:50:12 -040025import android.app.ActivityManager;
26import android.app.PendingIntent;
Esteban Talavera9c6458d2017-03-30 17:59:50 +010027import android.app.admin.DevicePolicyManager;
Christopher Tate6597e342015-02-17 12:15:25 -080028import android.content.BroadcastReceiver;
John Spurlock7340fc82014-04-24 18:50:12 -040029import android.content.ComponentName;
30import android.content.ContentResolver;
31import android.content.Context;
32import android.content.Intent;
Christopher Tate6597e342015-02-17 12:15:25 -080033import android.content.IntentFilter;
John Spurlock7340fc82014-04-24 18:50:12 -040034import 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;
42import android.database.ContentObserver;
43import android.net.Uri;
Esteban Talavera9c6458d2017-03-30 17:59:50 +010044import android.os.Binder;
John Spurlock7340fc82014-04-24 18:50:12 -040045import android.os.Build;
46import android.os.Handler;
47import android.os.IBinder;
48import android.os.IInterface;
49import android.os.RemoteException;
Julia Reynoldsa75c7522017-03-21 17:34:25 -040050import android.os.ServiceManager;
John Spurlock7340fc82014-04-24 18:50:12 -040051import android.os.UserHandle;
52import android.os.UserManager;
53import android.provider.Settings;
54import android.text.TextUtils;
55import android.util.ArraySet;
John Spurlock4db0d982014-08-13 09:19:03 -040056import android.util.Log;
John Spurlock7340fc82014-04-24 18:50:12 -040057import android.util.Slog;
58import android.util.SparseArray;
59
John Spurlock25e2d242014-06-27 13:58:23 -040060import com.android.server.notification.NotificationManagerService.DumpFilter;
61
John Spurlock7340fc82014-04-24 18:50:12 -040062import java.io.PrintWriter;
63import java.util.ArrayList;
John Spurlocke77bb362014-04-26 10:24:59 -040064import java.util.Arrays;
Julia Reynolds9a86cc02016-02-10 15:38:15 -050065import java.util.HashSet;
John Spurlock7340fc82014-04-24 18:50:12 -040066import java.util.List;
Christopher Tate6597e342015-02-17 12:15:25 -080067import java.util.Objects;
John Spurlock7340fc82014-04-24 18:50:12 -040068import java.util.Set;
69
70/**
71 * Manages the lifecycle of application-provided services bound by system server.
72 *
73 * Services managed by this helper must have:
74 * - An associated system settings value with a list of enabled component names.
75 * - A well-known action for services to use in their intent-filter.
76 * - A system permission for services to require in order to ensure system has exclusive binding.
77 * - A settings page for user configuration of enabled services, and associated intent action.
78 * - A remote interface definition (aidl) provided by the service used for communication.
79 */
80abstract public class ManagedServices {
81 protected final String TAG = getClass().getSimpleName();
John Spurlock4db0d982014-08-13 09:19:03 -040082 protected final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
John Spurlock7340fc82014-04-24 18:50:12 -040083
Julia Reynoldsc279b992015-10-30 08:23:51 -040084 protected static final String ENABLED_SERVICES_SEPARATOR = ":";
John Spurlock7340fc82014-04-24 18:50:12 -040085
John Spurlockaf8d6c42014-05-07 17:49:08 -040086 protected final Context mContext;
John Spurlocke77bb362014-04-26 10:24:59 -040087 protected final Object mMutex;
John Spurlock7340fc82014-04-24 18:50:12 -040088 private final UserProfiles mUserProfiles;
89 private final SettingsObserver mSettingsObserver;
Julia Reynoldsa75c7522017-03-21 17:34:25 -040090 private final IPackageManager mPm;
John Spurlock7340fc82014-04-24 18:50:12 -040091 private final Config mConfig;
Christopher Tate6597e342015-02-17 12:15:25 -080092 private ArraySet<String> mRestored;
John Spurlock7340fc82014-04-24 18:50:12 -040093
94 // contains connections to all connected services, including app services
95 // and system services
Julia Reynolds00314d92017-04-14 10:01:24 -040096 private final ArrayList<ManagedServiceInfo> mServices = new ArrayList<ManagedServiceInfo>();
John Spurlock7340fc82014-04-24 18:50:12 -040097 // things that will be put into mServices as soon as they're ready
98 private final ArrayList<String> mServicesBinding = new ArrayList<String>();
Chris Wrenab41eec2016-01-04 18:01:27 -050099 // lists the component names of all enabled (and therefore potentially connected)
John Spurlock7340fc82014-04-24 18:50:12 -0400100 // app services for current profiles.
101 private ArraySet<ComponentName> mEnabledServicesForCurrentProfiles
102 = new ArraySet<ComponentName>();
103 // Just the packages from mEnabledServicesForCurrentProfiles
104 private ArraySet<String> mEnabledServicesPackageNames = new ArraySet<String>();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200105 // List of packages in restored setting across all mUserProfiles, for quick
106 // filtering upon package updates.
107 private ArraySet<String> mRestoredPackages = new ArraySet<>();
Chris Wrenab41eec2016-01-04 18:01:27 -0500108 // List of enabled packages that have nevertheless asked not to be run
109 private ArraySet<ComponentName> mSnoozingForCurrentProfiles = new ArraySet<>();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200110
John Spurlock7340fc82014-04-24 18:50:12 -0400111
Christoph Studerb53dfd42014-09-12 14:45:59 +0200112 // Kept to de-dupe user change events (experienced after boot, when we receive a settings and a
113 // user change).
114 private int[] mLastSeenProfileIds;
115
Christopher Tate6597e342015-02-17 12:15:25 -0800116 private final BroadcastReceiver mRestoreReceiver;
117
John Spurlock7340fc82014-04-24 18:50:12 -0400118 public ManagedServices(Context context, Handler handler, Object mutex,
119 UserProfiles userProfiles) {
120 mContext = context;
121 mMutex = mutex;
122 mUserProfiles = userProfiles;
Julia Reynoldsa75c7522017-03-21 17:34:25 -0400123 mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
John Spurlock7340fc82014-04-24 18:50:12 -0400124 mConfig = getConfig();
125 mSettingsObserver = new SettingsObserver(handler);
Christopher Tate6597e342015-02-17 12:15:25 -0800126
127 mRestoreReceiver = new SettingRestoredReceiver();
128 IntentFilter filter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
129 context.registerReceiver(mRestoreReceiver, filter);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200130 rebuildRestoredPackages();
Christopher Tate6597e342015-02-17 12:15:25 -0800131 }
132
133 class SettingRestoredReceiver extends BroadcastReceiver {
134 @Override
135 public void onReceive(Context context, Intent intent) {
136 if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
137 String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
Julia Reynolds6e839b02016-04-13 10:01:17 -0400138 if (Objects.equals(element, mConfig.secureSettingName)
139 || Objects.equals(element, mConfig.secondarySettingName)) {
Christopher Tate6597e342015-02-17 12:15:25 -0800140 String prevValue = intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE);
141 String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
142 settingRestored(element, prevValue, newValue, getSendingUserId());
143 }
144 }
145 }
John Spurlock7340fc82014-04-24 18:50:12 -0400146 }
147
148 abstract protected Config getConfig();
149
150 private String getCaption() {
151 return mConfig.caption;
152 }
153
154 abstract protected IInterface asInterface(IBinder binder);
155
Chris Wren51017d02015-12-15 15:34:46 -0500156 abstract protected boolean checkType(IInterface service);
157
John Spurlock3b98b3f2014-05-01 09:08:48 -0400158 abstract protected void onServiceAdded(ManagedServiceInfo info);
John Spurlock7340fc82014-04-24 18:50:12 -0400159
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400160 protected List<ManagedServiceInfo> getServices() {
161 synchronized (mMutex) {
162 List<ManagedServiceInfo> services = new ArrayList<>(mServices);
163 return services;
164 }
165 }
166
John Spurlocke77bb362014-04-26 10:24:59 -0400167 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { }
168
John Spurlock7340fc82014-04-24 18:50:12 -0400169 private ManagedServiceInfo newServiceInfo(IInterface service,
170 ComponentName component, int userid, boolean isSystem, ServiceConnection connection,
171 int targetSdkVersion) {
172 return new ManagedServiceInfo(service, component, userid, isSystem, connection,
173 targetSdkVersion);
174 }
175
176 public void onBootPhaseAppsCanStart() {
177 mSettingsObserver.observe();
178 }
179
John Spurlock25e2d242014-06-27 13:58:23 -0400180 public void dump(PrintWriter pw, DumpFilter filter) {
John Spurlocke77bb362014-04-26 10:24:59 -0400181 pw.println(" All " + getCaption() + "s (" + mEnabledServicesForCurrentProfiles.size()
John Spurlock7340fc82014-04-24 18:50:12 -0400182 + ") enabled for current profiles:");
183 for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
John Spurlock25e2d242014-06-27 13:58:23 -0400184 if (filter != null && !filter.matches(cmpt)) continue;
John Spurlocke77bb362014-04-26 10:24:59 -0400185 pw.println(" " + cmpt);
John Spurlock7340fc82014-04-24 18:50:12 -0400186 }
187
John Spurlocke77bb362014-04-26 10:24:59 -0400188 pw.println(" Live " + getCaption() + "s (" + mServices.size() + "):");
John Spurlock7340fc82014-04-24 18:50:12 -0400189 for (ManagedServiceInfo info : mServices) {
John Spurlock25e2d242014-06-27 13:58:23 -0400190 if (filter != null && !filter.matches(info.component)) continue;
John Spurlocke77bb362014-04-26 10:24:59 -0400191 pw.println(" " + info.component
John Spurlock7340fc82014-04-24 18:50:12 -0400192 + " (user " + info.userid + "): " + info.service
Chris Wren51017d02015-12-15 15:34:46 -0500193 + (info.isSystem?" SYSTEM":"")
194 + (info.isGuest(this)?" GUEST":""));
John Spurlock7340fc82014-04-24 18:50:12 -0400195 }
Chris Wrenab41eec2016-01-04 18:01:27 -0500196
197 pw.println(" Snoozed " + getCaption() + "s (" +
198 mSnoozingForCurrentProfiles.size() + "):");
199 for (ComponentName name : mSnoozingForCurrentProfiles) {
200 pw.println(" " + name.flattenToShortString());
201 }
John Spurlock7340fc82014-04-24 18:50:12 -0400202 }
203
Christopher Tate6597e342015-02-17 12:15:25 -0800204 // By convention, restored settings are replicated to another settings
205 // entry, named similarly but with a disambiguation suffix.
Julia Reynolds6e839b02016-04-13 10:01:17 -0400206 public static String restoredSettingName(String setting) {
207 return setting + ":restored";
Christopher Tate6597e342015-02-17 12:15:25 -0800208 }
209
210 // The OS has done a restore of this service's saved state. We clone it to the
211 // 'restored' reserve, and then once we return and the actual write to settings is
212 // performed, our observer will do the work of maintaining the restored vs live
213 // settings data.
214 public void settingRestored(String element, String oldValue, String newValue, int userid) {
215 if (DEBUG) Slog.d(TAG, "Restored managed service setting: " + element
216 + " ovalue=" + oldValue + " nvalue=" + newValue);
Julia Reynolds6e839b02016-04-13 10:01:17 -0400217 if (mConfig.secureSettingName.equals(element) ||
218 mConfig.secondarySettingName.equals(element)) {
Christopher Tate6597e342015-02-17 12:15:25 -0800219 if (element != null) {
Christopher Tate6597e342015-02-17 12:15:25 -0800220 Settings.Secure.putStringForUser(mContext.getContentResolver(),
Julia Reynolds6e839b02016-04-13 10:01:17 -0400221 restoredSettingName(element),
Christopher Tate6597e342015-02-17 12:15:25 -0800222 newValue,
223 userid);
Julia Reynolds6e839b02016-04-13 10:01:17 -0400224 updateSettingsAccordingToInstalledServices(element, userid);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200225 rebuildRestoredPackages();
Christopher Tate6597e342015-02-17 12:15:25 -0800226 }
227 }
228 }
229
John Spurlock80774932015-05-07 17:38:50 -0400230 public boolean isComponentEnabledForPackage(String pkg) {
231 return mEnabledServicesPackageNames.contains(pkg);
232 }
233
Julia Reynolds6434eb22016-08-08 17:19:26 -0400234 public void onPackagesChanged(boolean removingPackage, String[] pkgList) {
235 if (DEBUG) Slog.d(TAG, "onPackagesChanged removingPackage=" + removingPackage
John Spurlocke77bb362014-04-26 10:24:59 -0400236 + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList))
237 + " mEnabledServicesPackageNames=" + mEnabledServicesPackageNames);
John Spurlock7340fc82014-04-24 18:50:12 -0400238 boolean anyServicesInvolved = false;
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200239
John Spurlock7340fc82014-04-24 18:50:12 -0400240 if (pkgList != null && (pkgList.length > 0)) {
241 for (String pkgName : pkgList) {
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200242 if (mEnabledServicesPackageNames.contains(pkgName) ||
243 mRestoredPackages.contains(pkgName)) {
John Spurlock7340fc82014-04-24 18:50:12 -0400244 anyServicesInvolved = true;
245 }
246 }
247 }
248
249 if (anyServicesInvolved) {
250 // if we're not replacing a package, clean up orphaned bits
Julia Reynolds6434eb22016-08-08 17:19:26 -0400251 if (removingPackage) {
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200252 updateSettingsAccordingToInstalledServices();
253 rebuildRestoredPackages();
John Spurlock7340fc82014-04-24 18:50:12 -0400254 }
255 // make sure we're still bound to any of our services who may have just upgraded
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400256 rebindServices(false);
John Spurlock7340fc82014-04-24 18:50:12 -0400257 }
258 }
259
John Spurlock1b8b22b2015-05-20 09:47:13 -0400260 public void onUserSwitched(int user) {
261 if (DEBUG) Slog.d(TAG, "onUserSwitched u=" + user);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200262 rebuildRestoredPackages();
Christoph Studerb53dfd42014-09-12 14:45:59 +0200263 if (Arrays.equals(mLastSeenProfileIds, mUserProfiles.getCurrentProfileIds())) {
264 if (DEBUG) Slog.d(TAG, "Current profile IDs didn't change, skipping rebindServices().");
265 return;
266 }
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400267 rebindServices(true);
Christoph Studerb53dfd42014-09-12 14:45:59 +0200268 }
269
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500270 public void onUserUnlocked(int user) {
271 if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
272 rebuildRestoredPackages();
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400273 rebindServices(false);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500274 }
275
Chris Wrenab41eec2016-01-04 18:01:27 -0500276 public ManagedServiceInfo getServiceFromTokenLocked(IInterface service) {
277 if (service == null) {
278 return null;
279 }
John Spurlock7340fc82014-04-24 18:50:12 -0400280 final IBinder token = service.asBinder();
281 final int N = mServices.size();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200282 for (int i = 0; i < N; i++) {
John Spurlock7340fc82014-04-24 18:50:12 -0400283 final ManagedServiceInfo info = mServices.get(i);
284 if (info.service.asBinder() == token) return info;
285 }
Chris Wrenab41eec2016-01-04 18:01:27 -0500286 return null;
287 }
288
289 public ManagedServiceInfo checkServiceTokenLocked(IInterface service) {
290 checkNotNull(service);
291 ManagedServiceInfo info = getServiceFromTokenLocked(service);
292 if (info != null) {
293 return info;
294 }
John Spurlock7340fc82014-04-24 18:50:12 -0400295 throw new SecurityException("Disallowed call from unknown " + getCaption() + ": "
296 + service);
297 }
298
299 public void unregisterService(IInterface service, int userid) {
300 checkNotNull(service);
301 // no need to check permissions; if your service binder is in the list,
302 // that's proof that you had permission to add it in the first place
303 unregisterServiceImpl(service, userid);
304 }
305
306 public void registerService(IInterface service, ComponentName component, int userid) {
307 checkNotNull(service);
Christoph Studer3e144d32014-05-22 16:48:40 +0200308 ManagedServiceInfo info = registerServiceImpl(service, component, userid);
309 if (info != null) {
310 onServiceAdded(info);
311 }
John Spurlock7340fc82014-04-24 18:50:12 -0400312 }
313
Chris Wren51017d02015-12-15 15:34:46 -0500314 /**
315 * Add a service to our callbacks. The lifecycle of this service is managed externally,
316 * but unlike a system service, it should not be considered privledged.
317 * */
318 public void registerGuestService(ManagedServiceInfo guest) {
319 checkNotNull(guest.service);
Ruben Brunke24b9a62016-02-16 21:38:24 -0800320 if (!checkType(guest.service)) {
321 throw new IllegalArgumentException();
322 }
Chris Wren51017d02015-12-15 15:34:46 -0500323 if (registerServiceImpl(guest) != null) {
324 onServiceAdded(guest);
Chris Wrenab41eec2016-01-04 18:01:27 -0500325 }
326 }
327
328 public void setComponentState(ComponentName component, boolean enabled) {
329 boolean previous = !mSnoozingForCurrentProfiles.contains(component);
330 if (previous == enabled) {
331 return;
332 }
333
334 if (enabled) {
335 mSnoozingForCurrentProfiles.remove(component);
336 } else {
337 mSnoozingForCurrentProfiles.add(component);
338 }
339
340 // State changed
341 if (DEBUG) {
342 Slog.d(TAG, ((enabled) ? "Enabling " : "Disabling ") + "component " +
343 component.flattenToShortString());
344 }
345
Chris Wren0efdb882016-03-01 17:17:47 -0500346
347 synchronized (mMutex) {
348 final int[] userIds = mUserProfiles.getCurrentProfileIds();
349
350 for (int userId : userIds) {
351 if (enabled) {
352 registerServiceLocked(component, userId);
353 } else {
354 unregisterServiceLocked(component, userId);
355 }
Chris Wrenab41eec2016-01-04 18:01:27 -0500356 }
Chris Wren51017d02015-12-15 15:34:46 -0500357 }
358 }
359
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200360 private void rebuildRestoredPackages() {
361 mRestoredPackages.clear();
Julia Reynolds6e839b02016-04-13 10:01:17 -0400362 String secureSettingName = restoredSettingName(mConfig.secureSettingName);
363 String secondarySettingName = mConfig.secondarySettingName == null
364 ? null : restoredSettingName(mConfig.secondarySettingName);
John Spurlock7340fc82014-04-24 18:50:12 -0400365 int[] userIds = mUserProfiles.getCurrentProfileIds();
366 final int N = userIds.length;
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200367 for (int i = 0; i < N; ++i) {
Julia Reynolds6e839b02016-04-13 10:01:17 -0400368 ArraySet<ComponentName> names =
369 loadComponentNamesFromSetting(secureSettingName, userIds[i]);
370 if (secondarySettingName != null) {
371 names.addAll(loadComponentNamesFromSetting(secondarySettingName, userIds[i]));
372 }
373 for (ComponentName name : names) {
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200374 mRestoredPackages.add(name.getPackageName());
375 }
John Spurlock7340fc82014-04-24 18:50:12 -0400376 }
377 }
378
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200379
Julia Reynolds6e839b02016-04-13 10:01:17 -0400380 protected @NonNull ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
Julia Reynoldsc279b992015-10-30 08:23:51 -0400381 int userId) {
Christopher Tate6597e342015-02-17 12:15:25 -0800382 final ContentResolver cr = mContext.getContentResolver();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200383 String settingValue = Settings.Secure.getStringForUser(
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800384 cr,
385 settingName,
386 userId);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200387 if (TextUtils.isEmpty(settingValue))
Julia Reynolds6e839b02016-04-13 10:01:17 -0400388 return new ArraySet<>();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200389 String[] restored = settingValue.split(ENABLED_SERVICES_SEPARATOR);
390 ArraySet<ComponentName> result = new ArraySet<>(restored.length);
391 for (int i = 0; i < restored.length; i++) {
392 ComponentName value = ComponentName.unflattenFromString(restored[i]);
393 if (null != value) {
394 result.add(value);
Christopher Tate6597e342015-02-17 12:15:25 -0800395 }
396 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200397 return result;
398 }
John Spurlock7340fc82014-04-24 18:50:12 -0400399
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200400 private void storeComponentsToSetting(Set<ComponentName> components,
401 String settingName,
402 int userId) {
403 String[] componentNames = null;
404 if (null != components) {
405 componentNames = new String[components.size()];
406 int index = 0;
407 for (ComponentName c: components) {
408 componentNames[index++] = c.flattenToString();
409 }
410 }
411 final String value = (componentNames == null) ? "" :
412 TextUtils.join(ENABLED_SERVICES_SEPARATOR, componentNames);
413 final ContentResolver cr = mContext.getContentResolver();
414 Settings.Secure.putStringForUser(
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800415 cr,
416 settingName,
417 value,
418 userId);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200419 }
420
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200421 /**
422 * Remove access for any services that no longer exist.
423 */
424 private void updateSettingsAccordingToInstalledServices() {
425 int[] userIds = mUserProfiles.getCurrentProfileIds();
426 final int N = userIds.length;
427 for (int i = 0; i < N; ++i) {
Julia Reynolds6e839b02016-04-13 10:01:17 -0400428 updateSettingsAccordingToInstalledServices(mConfig.secureSettingName, userIds[i]);
429 if (mConfig.secondarySettingName != null) {
430 updateSettingsAccordingToInstalledServices(
431 mConfig.secondarySettingName, userIds[i]);
432 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200433 }
434 rebuildRestoredPackages();
435 }
436
Julia Reynoldsc279b992015-10-30 08:23:51 -0400437 protected Set<ComponentName> queryPackageForServices(String packageName, int userId) {
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200438 Set<ComponentName> installed = new ArraySet<>();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200439 final PackageManager pm = mContext.getPackageManager();
Julia Reynoldsc279b992015-10-30 08:23:51 -0400440 Intent queryIntent = new Intent(mConfig.serviceInterface);
441 if (!TextUtils.isEmpty(packageName)) {
442 queryIntent.setPackage(packageName);
443 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200444 List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
Julia Reynoldsc279b992015-10-30 08:23:51 -0400445 queryIntent,
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200446 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
447 userId);
448 if (DEBUG)
449 Slog.v(TAG, mConfig.serviceInterface + " services: " + installedServices);
Julia Reynolds50f05142015-10-30 17:03:59 -0400450 if (installedServices != null) {
451 for (int i = 0, count = installedServices.size(); i < count; i++) {
452 ResolveInfo resolveInfo = installedServices.get(i);
453 ServiceInfo info = resolveInfo.serviceInfo;
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200454
Julia Reynolds50f05142015-10-30 17:03:59 -0400455 ComponentName component = new ComponentName(info.packageName, info.name);
456 if (!mConfig.bindPermission.equals(info.permission)) {
457 Slog.w(TAG, "Skipping " + getCaption() + " service "
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800458 + info.packageName + "/" + info.name
459 + ": it does not require the permission "
460 + mConfig.bindPermission);
Julia Reynolds50f05142015-10-30 17:03:59 -0400461 continue;
462 }
463 installed.add(component);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200464 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200465 }
Julia Reynoldsc279b992015-10-30 08:23:51 -0400466 return installed;
467 }
468
Julia Reynolds6e839b02016-04-13 10:01:17 -0400469 private void updateSettingsAccordingToInstalledServices(String setting, int userId) {
Julia Reynoldsc279b992015-10-30 08:23:51 -0400470 boolean restoredChanged = false;
471 boolean currentChanged = false;
472 Set<ComponentName> restored =
Julia Reynolds6e839b02016-04-13 10:01:17 -0400473 loadComponentNamesFromSetting(restoredSettingName(setting), userId);
Julia Reynoldsc279b992015-10-30 08:23:51 -0400474 Set<ComponentName> current =
Julia Reynolds6e839b02016-04-13 10:01:17 -0400475 loadComponentNamesFromSetting(setting, userId);
Julia Reynoldsc279b992015-10-30 08:23:51 -0400476 // Load all services for all packages.
477 Set<ComponentName> installed = queryPackageForServices(null, userId);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200478
479 ArraySet<ComponentName> retained = new ArraySet<>();
480
481 for (ComponentName component : installed) {
482 if (null != restored) {
483 boolean wasRestored = restored.remove(component);
484 if (wasRestored) {
485 // Freshly installed package has service that was mentioned in restored setting.
486 if (DEBUG)
487 Slog.v(TAG, "Restoring " + component + " for user " + userId);
488 restoredChanged = true;
489 currentChanged = true;
490 retained.add(component);
John Spurlock7340fc82014-04-24 18:50:12 -0400491 continue;
492 }
John Spurlock7340fc82014-04-24 18:50:12 -0400493 }
494
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200495 if (null != current) {
496 if (current.contains(component))
497 retained.add(component);
John Spurlock7340fc82014-04-24 18:50:12 -0400498 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200499 }
500
501 currentChanged |= ((current == null ? 0 : current.size()) != retained.size());
502
503 if (currentChanged) {
504 if (DEBUG) Slog.v(TAG, "List of " + getCaption() + " services was updated " + current);
Julia Reynolds6e839b02016-04-13 10:01:17 -0400505 storeComponentsToSetting(retained, setting, userId);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200506 }
507
508 if (restoredChanged) {
509 if (DEBUG) Slog.v(TAG,
510 "List of " + getCaption() + " restored services was updated " + restored);
Julia Reynolds6e839b02016-04-13 10:01:17 -0400511 storeComponentsToSetting(restored, restoredSettingName(setting), userId);
John Spurlock7340fc82014-04-24 18:50:12 -0400512 }
513 }
514
515 /**
516 * Called whenever packages change, the user switches, or the secure setting
517 * is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
518 */
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400519 private void rebindServices(boolean forceRebind) {
John Spurlock7340fc82014-04-24 18:50:12 -0400520 if (DEBUG) Slog.d(TAG, "rebindServices");
521 final int[] userIds = mUserProfiles.getCurrentProfileIds();
522 final int nUserIds = userIds.length;
523
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200524 final SparseArray<ArraySet<ComponentName>> componentsByUser = new SparseArray<>();
John Spurlock7340fc82014-04-24 18:50:12 -0400525
526 for (int i = 0; i < nUserIds; ++i) {
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200527 componentsByUser.put(userIds[i],
528 loadComponentNamesFromSetting(mConfig.secureSettingName, userIds[i]));
Julia Reynolds6e839b02016-04-13 10:01:17 -0400529 if (mConfig.secondarySettingName != null) {
530 componentsByUser.get(userIds[i]).addAll(
531 loadComponentNamesFromSetting(mConfig.secondarySettingName, userIds[i]));
532 }
John Spurlock7340fc82014-04-24 18:50:12 -0400533 }
534
Julia Reynolds9a86cc02016-02-10 15:38:15 -0500535 final ArrayList<ManagedServiceInfo> removableBoundServices = new ArrayList<>();
536 final SparseArray<Set<ComponentName>> toAdd = new SparseArray<>();
John Spurlock7340fc82014-04-24 18:50:12 -0400537
538 synchronized (mMutex) {
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400539 // Rebind to non-system services if user switched
Christoph Studer5d423842014-05-23 13:15:54 +0200540 for (ManagedServiceInfo service : mServices) {
Chris Wren51017d02015-12-15 15:34:46 -0500541 if (!service.isSystem && !service.isGuest(this)) {
Julia Reynolds9a86cc02016-02-10 15:38:15 -0500542 removableBoundServices.add(service);
Christoph Studer5d423842014-05-23 13:15:54 +0200543 }
544 }
John Spurlock7340fc82014-04-24 18:50:12 -0400545
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400546 mEnabledServicesForCurrentProfiles.clear();
547 mEnabledServicesPackageNames.clear();
John Spurlock7340fc82014-04-24 18:50:12 -0400548
549 for (int i = 0; i < nUserIds; ++i) {
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200550 // decode the list of components
551 final ArraySet<ComponentName> userComponents = componentsByUser.get(userIds[i]);
552 if (null == userComponents) {
Julia Reynolds6e839b02016-04-13 10:01:17 -0400553 toAdd.put(userIds[i], new ArraySet<ComponentName>());
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200554 continue;
555 }
556
Julia Reynolds9a86cc02016-02-10 15:38:15 -0500557 final Set<ComponentName> add = new HashSet<>(userComponents);
Chris Wrenab41eec2016-01-04 18:01:27 -0500558 add.removeAll(mSnoozingForCurrentProfiles);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800559
John Spurlock7340fc82014-04-24 18:50:12 -0400560 toAdd.put(userIds[i], add);
561
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400562 mEnabledServicesForCurrentProfiles.addAll(userComponents);
John Spurlock7340fc82014-04-24 18:50:12 -0400563
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200564 for (int j = 0; j < userComponents.size(); j++) {
Chris Wren083094c2015-12-15 16:25:07 -0500565 final ComponentName component = userComponents.valueAt(j);
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400566 mEnabledServicesPackageNames.add(component.getPackageName());
John Spurlock7340fc82014-04-24 18:50:12 -0400567 }
568 }
John Spurlock7340fc82014-04-24 18:50:12 -0400569 }
570
Julia Reynolds9a86cc02016-02-10 15:38:15 -0500571 for (ManagedServiceInfo info : removableBoundServices) {
John Spurlock7340fc82014-04-24 18:50:12 -0400572 final ComponentName component = info.component;
573 final int oldUser = info.userid;
Julia Reynolds9a86cc02016-02-10 15:38:15 -0500574 final Set<ComponentName> allowedComponents = toAdd.get(info.userid);
575 if (allowedComponents != null) {
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400576 if (allowedComponents.contains(component) && !forceRebind) {
Julia Reynolds9a86cc02016-02-10 15:38:15 -0500577 // Already bound, don't need to bind again.
578 allowedComponents.remove(component);
579 } else {
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400580 // No longer allowed to be bound, or must rebind.
Julia Reynolds9a86cc02016-02-10 15:38:15 -0500581 Slog.v(TAG, "disabling " + getCaption() + " for user "
582 + oldUser + ": " + component);
583 unregisterService(component, oldUser);
584 }
585 }
John Spurlock7340fc82014-04-24 18:50:12 -0400586 }
587
588 for (int i = 0; i < nUserIds; ++i) {
Julia Reynolds9a86cc02016-02-10 15:38:15 -0500589 final Set<ComponentName> add = toAdd.get(userIds[i]);
590 for (ComponentName component : add) {
Julia Reynoldsa75c7522017-03-21 17:34:25 -0400591 try {
592 ServiceInfo info = mPm.getServiceInfo(component,
593 PackageManager.MATCH_DIRECT_BOOT_AWARE
594 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userIds[i]);
Julia Reynolds8bb5c932017-03-23 14:09:06 -0400595 if (info == null || !mConfig.bindPermission.equals(info.permission)) {
Julia Reynoldsa75c7522017-03-21 17:34:25 -0400596 Slog.w(TAG, "Skipping " + getCaption() + " service " + component
597 + ": it does not require the permission " + mConfig.bindPermission);
598 continue;
599 }
600 Slog.v(TAG,
601 "enabling " + getCaption() + " for " + userIds[i] + ": " + component);
602 registerService(component, userIds[i]);
603 } catch (RemoteException e) {
604 e.rethrowFromSystemServer();
605 }
John Spurlock7340fc82014-04-24 18:50:12 -0400606 }
607 }
Christoph Studerb53dfd42014-09-12 14:45:59 +0200608
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200609 mLastSeenProfileIds = userIds;
John Spurlock7340fc82014-04-24 18:50:12 -0400610 }
611
612 /**
613 * Version of registerService that takes the name of a service component to bind to.
614 */
615 private void registerService(final ComponentName name, final int userid) {
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800616 synchronized (mMutex) {
617 registerServiceLocked(name, userid);
618 }
619 }
620
Chris Wren0efdb882016-03-01 17:17:47 -0500621 /**
622 * Inject a system service into the management list.
623 */
624 public void registerSystemService(final ComponentName name, final int userid) {
625 synchronized (mMutex) {
626 registerServiceLocked(name, userid, true /* isSystem */);
627 }
628 }
629
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800630 private void registerServiceLocked(final ComponentName name, final int userid) {
Chris Wren0efdb882016-03-01 17:17:47 -0500631 registerServiceLocked(name, userid, false /* isSystem */);
632 }
633
634 private void registerServiceLocked(final ComponentName name, final int userid,
635 final boolean isSystem) {
John Spurlock7340fc82014-04-24 18:50:12 -0400636 if (DEBUG) Slog.v(TAG, "registerService: " + name + " u=" + userid);
637
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800638 final String servicesBindingTag = name.toString() + "/" + userid;
639 if (mServicesBinding.contains(servicesBindingTag)) {
640 // stop registering this thing already! we're working on it
641 return;
642 }
643 mServicesBinding.add(servicesBindingTag);
John Spurlock7340fc82014-04-24 18:50:12 -0400644
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800645 final int N = mServices.size();
646 for (int i = N - 1; i >= 0; i--) {
647 final ManagedServiceInfo info = mServices.get(i);
648 if (name.equals(info.component)
649 && info.userid == userid) {
650 // cut old connections
651 if (DEBUG) Slog.v(TAG, " disconnecting old " + getCaption() + ": "
652 + info.service);
653 removeServiceLocked(i);
654 if (info.connection != null) {
655 mContext.unbindService(info.connection);
John Spurlock7340fc82014-04-24 18:50:12 -0400656 }
657 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800658 }
John Spurlock7340fc82014-04-24 18:50:12 -0400659
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800660 Intent intent = new Intent(mConfig.serviceInterface);
661 intent.setComponent(name);
John Spurlock7340fc82014-04-24 18:50:12 -0400662
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800663 intent.putExtra(Intent.EXTRA_CLIENT_LABEL, mConfig.clientLabel);
John Spurlock7340fc82014-04-24 18:50:12 -0400664
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800665 final PendingIntent pendingIntent = PendingIntent.getActivity(
666 mContext, 0, new Intent(mConfig.settingsAction), 0);
667 intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
John Spurlock7340fc82014-04-24 18:50:12 -0400668
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800669 ApplicationInfo appInfo = null;
670 try {
671 appInfo = mContext.getPackageManager().getApplicationInfo(
672 name.getPackageName(), 0);
673 } catch (NameNotFoundException e) {
674 // Ignore if the package doesn't exist we won't be able to bind to the service.
675 }
676 final int targetSdkVersion =
677 appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE;
John Spurlock7340fc82014-04-24 18:50:12 -0400678
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800679 try {
680 if (DEBUG) Slog.v(TAG, "binding: " + intent);
681 ServiceConnection serviceConnection = new ServiceConnection() {
682 IInterface mService;
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200683
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800684 @Override
685 public void onServiceConnected(ComponentName name, IBinder binder) {
686 boolean added = false;
687 ManagedServiceInfo info = null;
688 synchronized (mMutex) {
689 mServicesBinding.remove(servicesBindingTag);
690 try {
691 mService = asInterface(binder);
692 info = newServiceInfo(mService, name,
Chris Wren0efdb882016-03-01 17:17:47 -0500693 userid, isSystem, this, targetSdkVersion);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800694 binder.linkToDeath(info, 0);
695 added = mServices.add(info);
696 } catch (RemoteException e) {
697 // already dead
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200698 }
699 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800700 if (added) {
701 onServiceAdded(info);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200702 }
John Spurlock7340fc82014-04-24 18:50:12 -0400703 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800704
705 @Override
706 public void onServiceDisconnected(ComponentName name) {
707 Slog.v(TAG, getCaption() + " connection lost: " + name);
708 }
709 };
710 if (!mContext.bindServiceAsUser(intent,
711 serviceConnection,
Felipe Lemea1b79bf2016-05-24 13:06:54 -0700712 BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE | BIND_ALLOW_WHITELIST_MANAGEMENT,
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800713 new UserHandle(userid))) {
714 mServicesBinding.remove(servicesBindingTag);
715 Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent);
John Spurlock7340fc82014-04-24 18:50:12 -0400716 return;
717 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800718 } catch (SecurityException ex) {
719 Slog.e(TAG, "Unable to bind " + getCaption() + " service: " + intent, ex);
720 return;
John Spurlock7340fc82014-04-24 18:50:12 -0400721 }
722 }
723
724 /**
725 * Remove a service for the given user by ComponentName
726 */
727 private void unregisterService(ComponentName name, int userid) {
728 synchronized (mMutex) {
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800729 unregisterServiceLocked(name, userid);
730 }
731 }
732
733 private void unregisterServiceLocked(ComponentName name, int userid) {
734 final int N = mServices.size();
735 for (int i = N - 1; i >= 0; i--) {
736 final ManagedServiceInfo info = mServices.get(i);
737 if (name.equals(info.component)
738 && info.userid == userid) {
739 removeServiceLocked(i);
740 if (info.connection != null) {
741 try {
742 mContext.unbindService(info.connection);
743 } catch (IllegalArgumentException ex) {
744 // something happened to the service: we think we have a connection
745 // but it's bogus.
746 Slog.e(TAG, getCaption() + " " + name + " could not be unbound: " + ex);
John Spurlock7340fc82014-04-24 18:50:12 -0400747 }
748 }
749 }
750 }
751 }
752
753 /**
754 * Removes a service from the list but does not unbind
755 *
756 * @return the removed service.
757 */
758 private ManagedServiceInfo removeServiceImpl(IInterface service, final int userid) {
John Spurlocke77bb362014-04-26 10:24:59 -0400759 if (DEBUG) Slog.d(TAG, "removeServiceImpl service=" + service + " u=" + userid);
John Spurlock7340fc82014-04-24 18:50:12 -0400760 ManagedServiceInfo serviceInfo = null;
761 synchronized (mMutex) {
762 final int N = mServices.size();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200763 for (int i = N - 1; i >= 0; i--) {
John Spurlock7340fc82014-04-24 18:50:12 -0400764 final ManagedServiceInfo info = mServices.get(i);
765 if (info.service.asBinder() == service.asBinder()
766 && info.userid == userid) {
John Spurlocke77bb362014-04-26 10:24:59 -0400767 if (DEBUG) Slog.d(TAG, "Removing active service " + info.component);
768 serviceInfo = removeServiceLocked(i);
John Spurlock7340fc82014-04-24 18:50:12 -0400769 }
770 }
771 }
772 return serviceInfo;
773 }
774
John Spurlocke77bb362014-04-26 10:24:59 -0400775 private ManagedServiceInfo removeServiceLocked(int i) {
776 final ManagedServiceInfo info = mServices.remove(i);
777 onServiceRemovedLocked(info);
778 return info;
779 }
780
John Spurlock7340fc82014-04-24 18:50:12 -0400781 private void checkNotNull(IInterface service) {
782 if (service == null) {
783 throw new IllegalArgumentException(getCaption() + " must not be null");
784 }
785 }
786
Christoph Studer3e144d32014-05-22 16:48:40 +0200787 private ManagedServiceInfo registerServiceImpl(final IInterface service,
John Spurlock7340fc82014-04-24 18:50:12 -0400788 final ComponentName component, final int userid) {
Chris Wren51017d02015-12-15 15:34:46 -0500789 ManagedServiceInfo info = newServiceInfo(service, component, userid,
790 true /*isSystem*/, null /*connection*/, Build.VERSION_CODES.LOLLIPOP);
791 return registerServiceImpl(info);
792 }
793
794 private ManagedServiceInfo registerServiceImpl(ManagedServiceInfo info) {
John Spurlock7340fc82014-04-24 18:50:12 -0400795 synchronized (mMutex) {
796 try {
Chris Wren51017d02015-12-15 15:34:46 -0500797 info.service.asBinder().linkToDeath(info, 0);
John Spurlock7340fc82014-04-24 18:50:12 -0400798 mServices.add(info);
Christoph Studer3e144d32014-05-22 16:48:40 +0200799 return info;
John Spurlock7340fc82014-04-24 18:50:12 -0400800 } catch (RemoteException e) {
801 // already dead
802 }
803 }
Christoph Studer3e144d32014-05-22 16:48:40 +0200804 return null;
John Spurlock7340fc82014-04-24 18:50:12 -0400805 }
806
807 /**
808 * Removes a service from the list and unbinds.
809 */
810 private void unregisterServiceImpl(IInterface service, int userid) {
811 ManagedServiceInfo info = removeServiceImpl(service, userid);
Chris Wren51017d02015-12-15 15:34:46 -0500812 if (info != null && info.connection != null && !info.isGuest(this)) {
John Spurlock7340fc82014-04-24 18:50:12 -0400813 mContext.unbindService(info.connection);
814 }
815 }
816
817 private class SettingsObserver extends ContentObserver {
818 private final Uri mSecureSettingsUri = Settings.Secure.getUriFor(mConfig.secureSettingName);
Julia Reynolds6e839b02016-04-13 10:01:17 -0400819 private final Uri mSecondarySettingsUri;
John Spurlock7340fc82014-04-24 18:50:12 -0400820
821 private SettingsObserver(Handler handler) {
822 super(handler);
Julia Reynolds6e839b02016-04-13 10:01:17 -0400823 if (mConfig.secondarySettingName != null) {
824 mSecondarySettingsUri = Settings.Secure.getUriFor(mConfig.secondarySettingName);
825 } else {
826 mSecondarySettingsUri = null;
827 }
John Spurlock7340fc82014-04-24 18:50:12 -0400828 }
829
830 private void observe() {
831 ContentResolver resolver = mContext.getContentResolver();
832 resolver.registerContentObserver(mSecureSettingsUri,
833 false, this, UserHandle.USER_ALL);
Julia Reynolds6e839b02016-04-13 10:01:17 -0400834 if (mSecondarySettingsUri != null) {
835 resolver.registerContentObserver(mSecondarySettingsUri,
836 false, this, UserHandle.USER_ALL);
837 }
John Spurlock7340fc82014-04-24 18:50:12 -0400838 update(null);
839 }
840
841 @Override
842 public void onChange(boolean selfChange, Uri uri) {
843 update(uri);
844 }
845
846 private void update(Uri uri) {
Julia Reynolds6e839b02016-04-13 10:01:17 -0400847 if (uri == null || mSecureSettingsUri.equals(uri)
848 || uri.equals(mSecondarySettingsUri)) {
849 if (DEBUG) Slog.d(TAG, "Setting changed: uri=" + uri);
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400850 rebindServices(false);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200851 rebuildRestoredPackages();
John Spurlock7340fc82014-04-24 18:50:12 -0400852 }
853 }
854 }
855
856 public class ManagedServiceInfo implements IBinder.DeathRecipient {
857 public IInterface service;
858 public ComponentName component;
859 public int userid;
860 public boolean isSystem;
861 public ServiceConnection connection;
862 public int targetSdkVersion;
863
864 public ManagedServiceInfo(IInterface service, ComponentName component,
865 int userid, boolean isSystem, ServiceConnection connection, int targetSdkVersion) {
866 this.service = service;
867 this.component = component;
868 this.userid = userid;
869 this.isSystem = isSystem;
870 this.connection = connection;
871 this.targetSdkVersion = targetSdkVersion;
872 }
873
Chris Wren51017d02015-12-15 15:34:46 -0500874 public boolean isGuest(ManagedServices host) {
875 return ManagedServices.this != host;
876 }
877
Chris Wrenab41eec2016-01-04 18:01:27 -0500878 public ManagedServices getOwner() {
879 return ManagedServices.this;
880 }
881
John Spurlocke77bb362014-04-26 10:24:59 -0400882 @Override
883 public String toString() {
884 return new StringBuilder("ManagedServiceInfo[")
885 .append("component=").append(component)
886 .append(",userid=").append(userid)
887 .append(",isSystem=").append(isSystem)
888 .append(",targetSdkVersion=").append(targetSdkVersion)
889 .append(",connection=").append(connection == null ? null : "<connection>")
890 .append(",service=").append(service)
891 .append(']').toString();
892 }
893
John Spurlock7340fc82014-04-24 18:50:12 -0400894 public boolean enabledAndUserMatches(int nid) {
895 if (!isEnabledForCurrentProfiles()) {
896 return false;
897 }
898 if (this.userid == UserHandle.USER_ALL) return true;
Chris Wren0c4eeb42016-05-12 13:21:08 -0400899 if (this.isSystem) return true;
John Spurlock7340fc82014-04-24 18:50:12 -0400900 if (nid == UserHandle.USER_ALL || nid == this.userid) return true;
Esteban Talavera9c6458d2017-03-30 17:59:50 +0100901 return supportsProfiles()
902 && mUserProfiles.isCurrentProfile(nid)
903 && isPermittedForProfile(nid);
John Spurlock7340fc82014-04-24 18:50:12 -0400904 }
905
906 public boolean supportsProfiles() {
Dianne Hackborn955d8d62014-10-07 20:17:19 -0700907 return targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP;
John Spurlock7340fc82014-04-24 18:50:12 -0400908 }
909
910 @Override
911 public void binderDied() {
John Spurlocke77bb362014-04-26 10:24:59 -0400912 if (DEBUG) Slog.d(TAG, "binderDied");
John Spurlock7340fc82014-04-24 18:50:12 -0400913 // Remove the service, but don't unbind from the service. The system will bring the
Esteban Talavera9c6458d2017-03-30 17:59:50 +0100914 // service back up, and the onServiceConnected handler will read the service with the
John Spurlock7340fc82014-04-24 18:50:12 -0400915 // new binding. If this isn't a bound service, and is just a registered
916 // service, just removing it from the list is all we need to do anyway.
917 removeServiceImpl(this.service, this.userid);
918 }
919
920 /** convenience method for looking in mEnabledServicesForCurrentProfiles */
921 public boolean isEnabledForCurrentProfiles() {
922 if (this.isSystem) return true;
923 if (this.connection == null) return false;
924 return mEnabledServicesForCurrentProfiles.contains(this.component);
925 }
Esteban Talavera9c6458d2017-03-30 17:59:50 +0100926
927 /**
928 * Returns true if this service is allowed to receive events for the given userId. A
929 * managed profile owner can disallow non-system services running outside of the profile
930 * from receiving events from the profile.
931 */
932 public boolean isPermittedForProfile(int userId) {
933 if (!mUserProfiles.isManagedProfile(userId)) {
934 return true;
935 }
936 DevicePolicyManager dpm =
937 (DevicePolicyManager) mContext.getSystemService(DEVICE_POLICY_SERVICE);
938 final long identity = Binder.clearCallingIdentity();
939 try {
940 return dpm.isNotificationListenerServicePermitted(
941 component.getPackageName(), userId);
942 } finally {
943 Binder.restoreCallingIdentity(identity);
944 }
945 }
John Spurlock7340fc82014-04-24 18:50:12 -0400946 }
947
Chris Wrenab41eec2016-01-04 18:01:27 -0500948 /** convenience method for looking in mEnabledServicesForCurrentProfiles */
949 public boolean isComponentEnabledForCurrentProfiles(ComponentName component) {
950 return mEnabledServicesForCurrentProfiles.contains(component);
951 }
952
John Spurlock7340fc82014-04-24 18:50:12 -0400953 public static class UserProfiles {
954 // Profiles of the current user.
Ruben Brunke24b9a62016-02-16 21:38:24 -0800955 private final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
John Spurlock7340fc82014-04-24 18:50:12 -0400956
Ruben Brunke24b9a62016-02-16 21:38:24 -0800957 public void updateCache(@NonNull Context context) {
John Spurlock7340fc82014-04-24 18:50:12 -0400958 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
959 if (userManager != null) {
960 int currentUserId = ActivityManager.getCurrentUser();
961 List<UserInfo> profiles = userManager.getProfiles(currentUserId);
962 synchronized (mCurrentProfiles) {
963 mCurrentProfiles.clear();
964 for (UserInfo user : profiles) {
965 mCurrentProfiles.put(user.id, user);
966 }
967 }
968 }
969 }
970
971 public int[] getCurrentProfileIds() {
972 synchronized (mCurrentProfiles) {
973 int[] users = new int[mCurrentProfiles.size()];
974 final int N = mCurrentProfiles.size();
975 for (int i = 0; i < N; ++i) {
976 users[i] = mCurrentProfiles.keyAt(i);
977 }
978 return users;
979 }
980 }
981
982 public boolean isCurrentProfile(int userId) {
983 synchronized (mCurrentProfiles) {
984 return mCurrentProfiles.get(userId) != null;
985 }
986 }
Esteban Talavera9c6458d2017-03-30 17:59:50 +0100987
988 public boolean isManagedProfile(int userId) {
989 synchronized (mCurrentProfiles) {
990 UserInfo user = mCurrentProfiles.get(userId);
991 return user != null && user.isManagedProfile();
992 }
993 }
John Spurlock7340fc82014-04-24 18:50:12 -0400994 }
995
Ruben Brunke24b9a62016-02-16 21:38:24 -0800996 public static class Config {
997 public String caption;
998 public String serviceInterface;
999 public String secureSettingName;
Julia Reynolds6e839b02016-04-13 10:01:17 -04001000 public String secondarySettingName;
Ruben Brunke24b9a62016-02-16 21:38:24 -08001001 public String bindPermission;
1002 public String settingsAction;
1003 public int clientLabel;
John Spurlock7340fc82014-04-24 18:50:12 -04001004 }
1005}