blob: 58f6ba2fd67fc5269d6e5d13b3befa48179faef9 [file] [log] [blame]
Felipe Lemeea95a6d2018-10-15 10:45:01 -07001/*
2 * Copyright (C) 2018 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 */
Felipe Leme1e3de572018-12-05 15:44:17 -080016package com.android.server.infra;
Felipe Lemeea95a6d2018-10-15 10:45:01 -070017
Robert Berrye14120e2019-03-18 16:33:42 -040018import android.annotation.IntDef;
Felipe Lemeea95a6d2018-10-15 10:45:01 -070019import android.annotation.NonNull;
20import android.annotation.Nullable;
21import android.annotation.UserIdInt;
22import android.app.ActivityManager;
23import android.content.ComponentName;
24import android.content.ContentResolver;
25import android.content.Context;
26import android.content.Intent;
27import android.content.pm.UserInfo;
28import android.database.ContentObserver;
29import android.net.Uri;
30import android.os.Binder;
31import android.os.Handler;
32import android.os.UserHandle;
33import android.os.UserManager;
34import android.os.UserManagerInternal;
35import android.provider.Settings;
36import android.util.Slog;
37import android.util.SparseArray;
38import android.util.SparseBooleanArray;
39
40import com.android.internal.annotations.GuardedBy;
41import com.android.internal.content.PackageMonitor;
Felipe Leme50b33dc2018-12-20 16:01:39 -080042import com.android.internal.infra.AbstractRemoteService;
Felipe Lemeea95a6d2018-10-15 10:45:01 -070043import com.android.internal.os.BackgroundThread;
Felipe Leme658c8e42018-11-30 12:49:45 -080044import com.android.internal.util.Preconditions;
Felipe Leme1e3de572018-12-05 15:44:17 -080045import com.android.server.LocalServices;
46import com.android.server.SystemService;
Felipe Lemeea95a6d2018-10-15 10:45:01 -070047
48import java.io.PrintWriter;
Robert Berrye14120e2019-03-18 16:33:42 -040049import java.lang.annotation.Retention;
50import java.lang.annotation.RetentionPolicy;
Felipe Leme987655d2019-08-26 10:45:24 -070051import java.util.ArrayList;
Felipe Lemeea95a6d2018-10-15 10:45:01 -070052import java.util.List;
53
54/**
55 * Base class for {@link SystemService SystemServices} that support multi user.
56 *
57 * <p>Subclasses of this service are just a facade for the service binder calls - the "real" work
58 * is done by the {@link AbstractPerUserSystemService} subclasses, which are automatically managed
59 * through an user -> service cache.
60 *
61 * <p>It also takes care of other plumbing tasks such as:
62 *
63 * <ul>
64 * <li>Disabling the service when {@link UserManager} restrictions change.
65 * <li>Refreshing the service when its underlying
Felipe Leme749b8892018-12-03 16:30:30 -080066 * {@link #getServiceSettingsProperty() Settings property} changed.
Felipe Lemeea95a6d2018-10-15 10:45:01 -070067 * <li>Calling the service when other Settings properties changed.
68 * </ul>
69 *
70 * <p>See {@code com.android.server.autofill.AutofillManagerService} for a concrete
71 * (no pun intended) example of how to use it.
72 *
Felipe Lemee20bf9f2018-11-19 11:14:31 -080073 * @param <M> "master" service class.
Felipe Lemeea95a6d2018-10-15 10:45:01 -070074 * @param <S> "real" service class.
75 *
76 * @hide
77 */
78// TODO(b/117779333): improve javadoc above instead of using Autofill as an example
Felipe Lemee20bf9f2018-11-19 11:14:31 -080079public abstract class AbstractMasterSystemService<M extends AbstractMasterSystemService<M, S>,
80 S extends AbstractPerUserSystemService<S, M>> extends SystemService {
Felipe Lemeea95a6d2018-10-15 10:45:01 -070081
Robert Berrye14120e2019-03-18 16:33:42 -040082 /** On a package update, does not refresh the per-user service in the cache. */
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -070083 public static final int PACKAGE_UPDATE_POLICY_NO_REFRESH = 0x00000001;
Robert Berrye14120e2019-03-18 16:33:42 -040084
85 /**
86 * On a package update, removes any existing per-user services in the cache.
87 *
88 * <p>This does not immediately recreate these services. It is assumed they will be recreated
89 * for the next user request.
90 */
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -070091 public static final int PACKAGE_UPDATE_POLICY_REFRESH_LAZY = 0x00000002;
Robert Berrye14120e2019-03-18 16:33:42 -040092
93 /**
94 * On a package update, removes and recreates any existing per-user services in the cache.
95 */
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -070096 public static final int PACKAGE_UPDATE_POLICY_REFRESH_EAGER = 0x00000004;
Robert Berrye14120e2019-03-18 16:33:42 -040097
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -070098 /** On a package restart, does not refresh the per-user service in the cache. */
99 public static final int PACKAGE_RESTART_POLICY_NO_REFRESH = 0x00000010;
100
101 /**
102 * On a package restart, removes any existing per-user services in the cache.
103 *
104 * <p>This does not immediately recreate these services. It is assumed they will be recreated
105 * for the next user request.
106 */
107 public static final int PACKAGE_RESTART_POLICY_REFRESH_LAZY = 0x00000020;
108
109 /**
110 * On a package restart, removes and recreates any existing per-user services in the cache.
111 */
112 public static final int PACKAGE_RESTART_POLICY_REFRESH_EAGER = 0x00000040;
113
114 @IntDef(flag = true, prefix = { "PACKAGE_" }, value = {
Robert Berrye14120e2019-03-18 16:33:42 -0400115 PACKAGE_UPDATE_POLICY_NO_REFRESH,
116 PACKAGE_UPDATE_POLICY_REFRESH_LAZY,
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700117 PACKAGE_UPDATE_POLICY_REFRESH_EAGER,
118 PACKAGE_RESTART_POLICY_NO_REFRESH,
119 PACKAGE_RESTART_POLICY_REFRESH_LAZY,
120 PACKAGE_RESTART_POLICY_REFRESH_EAGER
Robert Berrye14120e2019-03-18 16:33:42 -0400121 })
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700122
Robert Berrye14120e2019-03-18 16:33:42 -0400123 @Retention(RetentionPolicy.SOURCE)
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700124 public @interface ServicePackagePolicyFlags {}
Robert Berrye14120e2019-03-18 16:33:42 -0400125
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700126 /**
127 * Log tag
128 */
129 protected final String mTag = getClass().getSimpleName();
130
131 /**
132 * Lock used to synchronize access to internal state; should be acquired before calling a
133 * method whose name ends with {@code locked}.
134 */
135 protected final Object mLock = new Object();
136
137 /**
Felipe Lemec28711c2018-12-20 11:17:02 -0800138 * Object used to define the name of the service component used to create
139 * {@link com.android.internal.infra.AbstractRemoteService} instances.
140 */
141 @Nullable
142 protected final ServiceNameResolver mServiceNameResolver;
143
144 /**
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700145 * Whether the service should log debug statements.
146 */
Felipe Lemec28711c2018-12-20 11:17:02 -0800147 //TODO(b/117779333): consider using constants for these guards
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700148 public boolean verbose = false;
149
150 /**
151 * Whether the service should log verbose statements.
152 */
Felipe Lemec28711c2018-12-20 11:17:02 -0800153 //TODO(b/117779333): consider using constants for these guards
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700154 public boolean debug = false;
155
156 /**
Felipe Leme5933efb2018-11-29 16:08:49 -0800157 * Whether the service is allowed to bind to an instant-app.
158 */
159 @GuardedBy("mLock")
160 protected boolean mAllowInstantService;
161
162 /**
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700163 * Users disabled due to {@link UserManager} restrictions, or {@code null} if the service cannot
164 * be disabled through {@link UserManager}.
165 */
166 @GuardedBy("mLock")
167 @Nullable
Felipe Leme91ddeca2019-01-24 18:01:58 -0800168 private final SparseBooleanArray mDisabledByUserRestriction;
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700169
170 /**
171 * Cache of services per user id.
172 */
173 @GuardedBy("mLock")
174 private final SparseArray<S> mServicesCache = new SparseArray<>();
175
176 /**
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700177 * Value that determines whether the per-user service should be removed from the cache when its
178 * apk is updated or restarted.
Felipe Leme73e65ba2019-03-13 10:57:09 -0700179 */
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700180 private final @ServicePackagePolicyFlags int mServicePackagePolicyFlags;
Felipe Leme73e65ba2019-03-13 10:57:09 -0700181
182 /**
Felipe Leme2f288432019-03-21 13:57:45 -0700183 * Name of the service packages whose APK are being updated, keyed by user id.
Felipe Leme73e65ba2019-03-13 10:57:09 -0700184 */
185 @GuardedBy("mLock")
Felipe Leme2f288432019-03-21 13:57:45 -0700186 private SparseArray<String> mUpdatingPackageNames;
Felipe Leme73e65ba2019-03-13 10:57:09 -0700187
188 /**
Felipe Leme987655d2019-08-26 10:45:24 -0700189 * Lazy-loadable reference to {@link UserManagerInternal}.
190 */
191 @Nullable
192 private UserManagerInternal mUm;
193
194 /**
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700195 * Default constructor.
196 *
Felipe Leme73e65ba2019-03-13 10:57:09 -0700197 * <p>When using this constructor, the {@link AbstractPerUserSystemService} is removed from
198 * the cache (and re-added) when the service package is updated.
199 *
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700200 * @param context system context.
Felipe Lemec28711c2018-12-20 11:17:02 -0800201 * @param serviceNameResolver resolver for
202 * {@link com.android.internal.infra.AbstractRemoteService} instances, or
203 * {@code null} when the service doesn't bind to remote services.
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700204 * @param disallowProperty when not {@code null}, defines a {@link UserManager} restriction that
Felipe Lemec0ac60b2019-02-25 09:17:16 -0800205 * disables the service. <b>NOTE: </b> you'll also need to add it to
206 * {@code UserRestrictionsUtils.USER_RESTRICTIONS}.
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700207 */
208 protected AbstractMasterSystemService(@NonNull Context context,
Felipe Lemec28711c2018-12-20 11:17:02 -0800209 @Nullable ServiceNameResolver serviceNameResolver,
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700210 @Nullable String disallowProperty) {
Felipe Leme73e65ba2019-03-13 10:57:09 -0700211 this(context, serviceNameResolver, disallowProperty,
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700212 PACKAGE_UPDATE_POLICY_REFRESH_LAZY | PACKAGE_RESTART_POLICY_REFRESH_LAZY);
Felipe Leme73e65ba2019-03-13 10:57:09 -0700213 }
214
215 /**
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700216 * Full Constructor.
Felipe Leme73e65ba2019-03-13 10:57:09 -0700217 *
218 * @param context system context.
219 * @param serviceNameResolver resolver for
220 * {@link com.android.internal.infra.AbstractRemoteService} instances, or
221 * {@code null} when the service doesn't bind to remote services.
222 * @param disallowProperty when not {@code null}, defines a {@link UserManager} restriction that
223 * disables the service. <b>NOTE: </b> you'll also need to add it to
224 * {@code UserRestrictionsUtils.USER_RESTRICTIONS}.
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700225 * @param servicePackagePolicyFlags a combination of
226 * {@link #PACKAGE_UPDATE_POLICY_NO_REFRESH},
227 * {@link #PACKAGE_UPDATE_POLICY_REFRESH_LAZY},
228 * {@link #PACKAGE_UPDATE_POLICY_REFRESH_EAGER},
229 * {@link #PACKAGE_RESTART_POLICY_NO_REFRESH},
230 * {@link #PACKAGE_RESTART_POLICY_REFRESH_LAZY} or
231 * {@link #PACKAGE_RESTART_POLICY_REFRESH_EAGER}
Felipe Leme73e65ba2019-03-13 10:57:09 -0700232 */
233 protected AbstractMasterSystemService(@NonNull Context context,
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700234 @Nullable ServiceNameResolver serviceNameResolver, @Nullable String disallowProperty,
235 @ServicePackagePolicyFlags int servicePackagePolicyFlags) {
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700236 super(context);
237
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700238 final int updatePolicyMask = PACKAGE_UPDATE_POLICY_NO_REFRESH
239 | PACKAGE_UPDATE_POLICY_REFRESH_LAZY | PACKAGE_UPDATE_POLICY_REFRESH_EAGER;
240 if ((servicePackagePolicyFlags & updatePolicyMask) == 0) {
241 // If the package update policy is not set, add the default flag
242 servicePackagePolicyFlags |= PACKAGE_UPDATE_POLICY_REFRESH_LAZY;
243 }
244 final int restartPolicyMask = PACKAGE_RESTART_POLICY_NO_REFRESH
245 | PACKAGE_RESTART_POLICY_REFRESH_LAZY | PACKAGE_RESTART_POLICY_REFRESH_EAGER;
246 if ((servicePackagePolicyFlags & restartPolicyMask) == 0) {
247 // If the package restart policy is not set, add the default flag
248 servicePackagePolicyFlags |= PACKAGE_RESTART_POLICY_REFRESH_LAZY;
249 }
250 mServicePackagePolicyFlags = servicePackagePolicyFlags;
Felipe Leme73e65ba2019-03-13 10:57:09 -0700251
Felipe Lemec28711c2018-12-20 11:17:02 -0800252 mServiceNameResolver = serviceNameResolver;
253 if (mServiceNameResolver != null) {
Felipe Leme9bee9442019-03-27 13:40:40 -0700254 mServiceNameResolver.setOnTemporaryServiceNameChangedCallback(
255 (u, s, t) -> onServiceNameChanged(u, s, t));
Felipe Lemec28711c2018-12-20 11:17:02 -0800256
257 }
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700258 if (disallowProperty == null) {
Felipe Leme91ddeca2019-01-24 18:01:58 -0800259 mDisabledByUserRestriction = null;
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700260 } else {
Felipe Leme91ddeca2019-01-24 18:01:58 -0800261 mDisabledByUserRestriction = new SparseBooleanArray();
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700262 // Hookup with UserManager to disable service when necessary.
Felipe Leme987655d2019-08-26 10:45:24 -0700263 final UserManagerInternal umi = getUserManagerInternal();
264 final List<UserInfo> users = getSupportedUsers();
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700265 for (int i = 0; i < users.size(); i++) {
266 final int userId = users.get(i).id;
267 final boolean disabled = umi.getUserRestriction(userId, disallowProperty);
268 if (disabled) {
Felipe Leme91ddeca2019-01-24 18:01:58 -0800269 Slog.i(mTag, "Disabling by restrictions user " + userId);
270 mDisabledByUserRestriction.put(userId, disabled);
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700271 }
272 }
273 umi.addUserRestrictionsListener((userId, newRestrictions, prevRestrictions) -> {
274 final boolean disabledNow =
275 newRestrictions.getBoolean(disallowProperty, false);
276 synchronized (mLock) {
Felipe Leme91ddeca2019-01-24 18:01:58 -0800277 final boolean disabledBefore = mDisabledByUserRestriction.get(userId);
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700278 if (disabledBefore == disabledNow) {
279 // Nothing changed, do nothing.
280 if (debug) {
281 Slog.d(mTag, "Restriction did not change for user " + userId);
282 return;
283 }
284 }
285 Slog.i(mTag, "Updating for user " + userId + ": disabled=" + disabledNow);
Felipe Leme91ddeca2019-01-24 18:01:58 -0800286 mDisabledByUserRestriction.put(userId, disabledNow);
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700287 updateCachedServiceLocked(userId, disabledNow);
288 }
289 });
290 }
291 startTrackingPackageChanges();
292 }
293
294 @Override // from SystemService
295 public void onBootPhase(int phase) {
296 if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
297 new SettingsObserver(BackgroundThread.getHandler());
298 }
299 }
300
301 @Override // from SystemService
302 public void onUnlockUser(int userId) {
303 synchronized (mLock) {
304 updateCachedServiceLocked(userId);
305 }
306 }
307
308 @Override // from SystemService
309 public void onCleanupUser(int userId) {
310 synchronized (mLock) {
311 removeCachedServiceLocked(userId);
312 }
313 }
314
315 /**
Felipe Leme5933efb2018-11-29 16:08:49 -0800316 * Gets whether the service is allowed to bind to an instant-app.
317 *
318 * <p>Typically called by {@code ShellCommand} during CTS tests.
319 *
320 * @throws SecurityException if caller is not allowed to manage this service's settings.
321 */
322 public final boolean getAllowInstantService() {
323 enforceCallingPermissionForManagement();
324 synchronized (mLock) {
325 return mAllowInstantService;
326 }
327 }
328
329 /**
Felipe Leme50b33dc2018-12-20 16:01:39 -0800330 * Checks whether the service is allowed to bind to an instant-app.
331 *
332 * <p>Typically called by subclasses when creating {@link AbstractRemoteService} instances.
333 *
334 * <p><b>NOTE: </b>must not be called by {@code ShellCommand} as it does not check for
335 * permission.
336 */
337 public final boolean isBindInstantServiceAllowed() {
338 synchronized (mLock) {
339 return mAllowInstantService;
340 }
341 }
342
343 /**
Felipe Leme5933efb2018-11-29 16:08:49 -0800344 * Sets whether the service is allowed to bind to an instant-app.
345 *
346 * <p>Typically called by {@code ShellCommand} during CTS tests.
347 *
348 * @throws SecurityException if caller is not allowed to manage this service's settings.
349 */
350 public final void setAllowInstantService(boolean mode) {
351 Slog.i(mTag, "setAllowInstantService(): " + mode);
352 enforceCallingPermissionForManagement();
353 synchronized (mLock) {
354 mAllowInstantService = mode;
355 }
356 }
357
358 /**
Felipe Leme0486d202018-12-04 09:47:39 -0800359 * Temporarily sets the service implementation.
Felipe Leme658c8e42018-11-30 12:49:45 -0800360 *
361 * <p>Typically used by Shell command and/or CTS tests.
362 *
363 * @param componentName name of the new component
364 * @param durationMs how long the change will be valid (the service will be automatically reset
365 * to the default component after this timeout expires).
366 * @throws SecurityException if caller is not allowed to manage this service's settings.
367 * @throws IllegalArgumentException if value of {@code durationMs} is higher than
368 * {@link #getMaximumTemporaryServiceDurationMs()}.
369 */
370 public final void setTemporaryService(@UserIdInt int userId, @NonNull String componentName,
371 int durationMs) {
372 Slog.i(mTag, "setTemporaryService(" + userId + ") to " + componentName + " for "
373 + durationMs + "ms");
374 enforceCallingPermissionForManagement();
375
376 Preconditions.checkNotNull(componentName);
377 final int maxDurationMs = getMaximumTemporaryServiceDurationMs();
378 if (durationMs > maxDurationMs) {
379 throw new IllegalArgumentException(
380 "Max duration is " + maxDurationMs + " (called with " + durationMs + ")");
381 }
382
383 synchronized (mLock) {
Felipe Leme18a9a4a2019-01-08 15:53:42 -0800384 final S oldService = peekServiceForUserLocked(userId);
385 if (oldService != null) {
386 oldService.removeSelfFromCacheLocked();
Felipe Leme658c8e42018-11-30 12:49:45 -0800387 }
Felipe Leme18a9a4a2019-01-08 15:53:42 -0800388 mServiceNameResolver.setTemporaryService(userId, componentName, durationMs);
Felipe Leme658c8e42018-11-30 12:49:45 -0800389 }
390 }
391
392 /**
Felipe Leme567df6a2019-02-05 15:00:05 -0800393 * Sets whether the default service should be used.
394 *
395 * <p>Typically used during CTS tests to make sure only the default service doesn't interfere
396 * with the test results.
397 *
398 * @throws SecurityException if caller is not allowed to manage this service's settings.
Felipe Lemea70dd8c2019-03-19 10:21:28 -0700399 *
400 * @return whether the enabled state changed.
Felipe Leme567df6a2019-02-05 15:00:05 -0800401 */
Felipe Lemea70dd8c2019-03-19 10:21:28 -0700402 public final boolean setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
Felipe Leme567df6a2019-02-05 15:00:05 -0800403 Slog.i(mTag, "setDefaultServiceEnabled() for userId " + userId + ": " + enabled);
404 enforceCallingPermissionForManagement();
405
406 synchronized (mLock) {
Felipe Lemea70dd8c2019-03-19 10:21:28 -0700407 final boolean changed = mServiceNameResolver.setDefaultServiceEnabled(userId, enabled);
408 if (!changed) {
409 if (verbose) {
410 Slog.v(mTag, "setDefaultServiceEnabled(" + userId + "): already " + enabled);
411 }
412 return false;
413 }
414
Felipe Leme567df6a2019-02-05 15:00:05 -0800415 final S oldService = peekServiceForUserLocked(userId);
416 if (oldService != null) {
417 oldService.removeSelfFromCacheLocked();
418 }
Felipe Leme567df6a2019-02-05 15:00:05 -0800419
420 // Must update the service on cache so its initialization code is triggered
421 updateCachedServiceLocked(userId);
422 }
Felipe Lemea70dd8c2019-03-19 10:21:28 -0700423 return true;
Felipe Leme567df6a2019-02-05 15:00:05 -0800424 }
425
426 /**
427 * Checks whether the default service should be used.
428 *
429 * <p>Typically used during CTS tests to make sure only the default service doesn't interfere
430 * with the test results.
431 *
432 * @throws SecurityException if caller is not allowed to manage this service's settings.
433 */
434 public final boolean isDefaultServiceEnabled(@UserIdInt int userId) {
435 enforceCallingPermissionForManagement();
436
437 synchronized (mLock) {
438 return mServiceNameResolver.isDefaultServiceEnabled(userId);
439 }
440 }
441
442 /**
Felipe Leme658c8e42018-11-30 12:49:45 -0800443 * Gets the maximum time the service implementation can be changed.
444 *
445 * @throws UnsupportedOperationException if subclass doesn't override it.
446 */
447 protected int getMaximumTemporaryServiceDurationMs() {
448 throw new UnsupportedOperationException("Not implemented by " + getClass());
449 }
450
451 /**
452 * Resets the temporary service implementation to the default component.
453 *
454 * <p>Typically used by Shell command and/or CTS tests.
455 *
456 * @throws SecurityException if caller is not allowed to manage this service's settings.
457 */
458 public final void resetTemporaryService(@UserIdInt int userId) {
459 Slog.i(mTag, "resetTemporaryService(): " + userId);
460 enforceCallingPermissionForManagement();
461 synchronized (mLock) {
462 final S service = getServiceForUserLocked(userId);
463 if (service != null) {
464 service.resetTemporaryServiceLocked();
465 }
466 }
467 }
468
469 /**
Felipe Leme5933efb2018-11-29 16:08:49 -0800470 * Asserts that the caller has permissions to manage this service.
471 *
472 * <p>Typically called by {@code ShellCommand} implementations.
473 *
474 * @throws UnsupportedOperationException if subclass doesn't override it.
475 * @throws SecurityException if caller is not allowed to manage this service's settings.
476 */
477 protected void enforceCallingPermissionForManagement() {
478 throw new UnsupportedOperationException("Not implemented by " + getClass());
479 }
480
481 /**
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700482 * Creates a new service that will be added to the cache.
483 *
484 * @param resolvedUserId the resolved user id for the service.
485 * @param disabled whether the service is currently disabled (due to {@link UserManager}
486 * restrictions).
487 *
488 * @return a new instance.
489 */
Felipe Leme50b33dc2018-12-20 16:01:39 -0800490 @Nullable
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700491 protected abstract S newServiceLocked(@UserIdInt int resolvedUserId, boolean disabled);
492
493 /**
494 * Register the service for extra Settings changes (i.e., other than
495 * {@link android.provider.Settings.Secure#USER_SETUP_COMPLETE} or
496 * {@link #getServiceSettingsProperty()}, which are automatically handled).
497 *
498 * <p> Example:
499 *
500 * <pre><code>
501 * resolver.registerContentObserver(Settings.Global.getUriFor(
502 * Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES), false, observer,
503 * UserHandle.USER_ALL);
504 * </code></pre>
505 *
506 * <p><b>NOTE: </p>it doesn't need to register for
507 * {@link android.provider.Settings.Secure#USER_SETUP_COMPLETE} or
508 * {@link #getServiceSettingsProperty()}.
509 *
510 */
511 @SuppressWarnings("unused")
512 protected void registerForExtraSettingsChanges(@NonNull ContentResolver resolver,
513 @NonNull ContentObserver observer) {
514 }
515
516 /**
517 * Callback for Settings changes that were registered though
518 * {@link #registerForExtraSettingsChanges(ContentResolver, ContentObserver)}.
519 *
520 * @param userId user associated with the change
521 * @param property Settings property changed.
522 */
523 protected void onSettingsChanged(@UserIdInt int userId, @NonNull String property) {
524 }
525
526 /**
527 * Gets the service instance for an user, creating an instance if not present in the cache.
528 */
529 @GuardedBy("mLock")
530 @NonNull
531 protected S getServiceForUserLocked(@UserIdInt int userId) {
532 final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
533 Binder.getCallingUid(), userId, false, false, null, null);
534 S service = mServicesCache.get(resolvedUserId);
535 if (service == null) {
536 final boolean disabled = isDisabledLocked(userId);
537 service = newServiceLocked(resolvedUserId, disabled);
538 if (!disabled) {
539 onServiceEnabledLocked(service, resolvedUserId);
540 }
541 mServicesCache.put(userId, service);
542 }
543 return service;
544 }
545
546 /**
547 * Gets the <b>existing</b> service instance for a user, returning {@code null} if not already
548 * present in the cache.
549 */
550 @GuardedBy("mLock")
551 @Nullable
Felipe Leme7ed7b2c2018-11-14 17:47:15 -0800552 protected S peekServiceForUserLocked(@UserIdInt int userId) {
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700553 final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
554 Binder.getCallingUid(), userId, false, false, null, null);
555 return mServicesCache.get(resolvedUserId);
556 }
557
558 /**
559 * Updates a cached service for a given user.
560 */
561 @GuardedBy("mLock")
Felipe Leme7ed7b2c2018-11-14 17:47:15 -0800562 protected void updateCachedServiceLocked(@UserIdInt int userId) {
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700563 updateCachedServiceLocked(userId, isDisabledLocked(userId));
564 }
565
566 /**
567 * Checks whether the service is disabled (through {@link UserManager} restrictions) for the
568 * given user.
569 */
Felipe Leme7ed7b2c2018-11-14 17:47:15 -0800570 protected boolean isDisabledLocked(@UserIdInt int userId) {
Felipe Leme91ddeca2019-01-24 18:01:58 -0800571 return mDisabledByUserRestriction == null ? false : mDisabledByUserRestriction.get(userId);
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700572 }
573
574 /**
575 * Updates a cached service for a given user.
576 *
577 * @param userId user handle.
578 * @param disabled whether the user is disabled.
579 * @return service for the user.
580 */
581 @GuardedBy("mLock")
Felipe Leme7ed7b2c2018-11-14 17:47:15 -0800582 protected S updateCachedServiceLocked(@UserIdInt int userId, boolean disabled) {
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700583 final S service = getServiceForUserLocked(userId);
584 if (service != null) {
585 service.updateLocked(disabled);
586 if (!service.isEnabledLocked()) {
587 removeCachedServiceLocked(userId);
588 } else {
589 onServiceEnabledLocked(service, userId);
590 }
591 }
592 return service;
593 }
594
595 /**
596 * Gets the Settings property that defines the name of the component name used to bind this
597 * service to an external service, or {@code null} when the service is not defined by such
598 * property (for example, if it's a system service defined by framework resources).
599 */
600 @Nullable
601 protected String getServiceSettingsProperty() {
602 return null;
603 }
604
605 /**
606 * Callback called after a new service was added to the cache, or an existing service that was
607 * previously disabled gets enabled.
608 *
609 * <p>By default doesn't do anything, but can be overridden by subclasses.
610 */
611 @SuppressWarnings("unused")
Felipe Leme7ed7b2c2018-11-14 17:47:15 -0800612 protected void onServiceEnabledLocked(@NonNull S service, @UserIdInt int userId) {
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700613 }
614
615 /**
616 * Removes a cached service for a given user.
617 *
Felipe Leme50b33dc2018-12-20 16:01:39 -0800618 * @return the removed service.
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700619 */
620 @GuardedBy("mLock")
621 @NonNull
Felipe Leme50b33dc2018-12-20 16:01:39 -0800622 protected final S removeCachedServiceLocked(@UserIdInt int userId) {
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700623 final S service = peekServiceForUserLocked(userId);
624 if (service != null) {
625 mServicesCache.delete(userId);
Felipe Leme7ed7b2c2018-11-14 17:47:15 -0800626 onServiceRemoved(service, userId);
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700627 }
628 return service;
629 }
630
631 /**
Felipe Leme2f288432019-03-21 13:57:45 -0700632 * Called before the package that provides the service for the given user is being updated.
633 */
634 protected void onServicePackageUpdatingLocked(@UserIdInt int userId) {
635 if (verbose) Slog.v(mTag, "onServicePackageUpdatingLocked(" + userId + ")");
636 }
637
638 /**
639 * Called after the package that provides the service for the given user is being updated.
640 */
641 protected void onServicePackageUpdatedLocked(@UserIdInt int userId) {
642 if (verbose) Slog.v(mTag, "onServicePackageUpdated(" + userId + ")");
643 }
644
645 /**
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700646 * Called after the package data that provides the service for the given user is cleared.
647 */
648 protected void onServicePackageDataClearedLocked(@UserIdInt int userId) {
649 if (verbose) Slog.v(mTag, "onServicePackageDataCleared(" + userId + ")");
650 }
651
652 /**
653 * Called after the package that provides the service for the given user is restarted.
654 */
655 protected void onServicePackageRestartedLocked(@UserIdInt int userId) {
656 if (verbose) Slog.v(mTag, "onServicePackageRestarted(" + userId + ")");
657 }
658
659 /**
Felipe Leme7ed7b2c2018-11-14 17:47:15 -0800660 * Called after the service is removed from the cache.
661 */
662 @SuppressWarnings("unused")
663 protected void onServiceRemoved(@NonNull S service, @UserIdInt int userId) {
664 }
665
666 /**
Felipe Leme9bee9442019-03-27 13:40:40 -0700667 * Called when the service name changed (typically when using temporary services).
668 *
669 * <p>By default, it calls {@link #updateCachedServiceLocked(int)}; subclasses must either call
670 * that same method, or {@code super.onServiceNameChanged()}.
671 *
672 * @param userId user handle.
673 * @param serviceName the new service name.
674 * @param isTemporary whether the new service is temporary.
675 */
676 protected void onServiceNameChanged(@UserIdInt int userId, @Nullable String serviceName,
677 boolean isTemporary) {
678 synchronized (mLock) {
679 updateCachedServiceLocked(userId);
680 }
681 }
682
683 /**
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700684 * Visits all services in the cache.
685 */
686 @GuardedBy("mLock")
687 protected void visitServicesLocked(@NonNull Visitor<S> visitor) {
688 final int size = mServicesCache.size();
689 for (int i = 0; i < size; i++) {
690 visitor.visit(mServicesCache.valueAt(i));
691 }
692 }
693
694 /**
695 * Clear the cache by removing all services.
696 */
697 @GuardedBy("mLock")
698 protected void clearCacheLocked() {
699 mServicesCache.clear();
700 }
701
Felipe Lemeafbba9f2019-03-26 14:02:25 -0700702 /**
Felipe Leme987655d2019-08-26 10:45:24 -0700703 * Gets a cached reference to {@link UserManagerInternal}.
704 */
705 @NonNull
706 protected UserManagerInternal getUserManagerInternal() {
707 if (mUm == null) {
708 if (verbose) Slog.v(mTag, "lazy-loading UserManagerInternal");
709 mUm = LocalServices.getService(UserManagerInternal.class);
710 }
711 return mUm;
712 }
713
714 /**
715 * Gets a list of all supported users (i.e., those that pass the {@link #isSupported(UserInfo)}
716 * check).
717 */
718 @NonNull
719 protected List<UserInfo> getSupportedUsers() {
720 final UserInfo[] allUsers = getUserManagerInternal().getUserInfos();
721 final int size = allUsers.length;
722 final List<UserInfo> supportedUsers = new ArrayList<>(size);
723 for (int i = 0; i < size; i++) {
724 final UserInfo userInfo = allUsers[i];
725 if (isSupported(userInfo)) {
726 supportedUsers.add(userInfo);
727 }
728 }
729 return supportedUsers;
730 }
731
732 /**
Felipe Lemeafbba9f2019-03-26 14:02:25 -0700733 * Asserts that the given package name is owned by the UID making this call.
734 *
735 * @throws SecurityException when it's not...
736 */
737 protected final void assertCalledByPackageOwner(@NonNull String packageName) {
738 Preconditions.checkNotNull(packageName);
739 final int uid = Binder.getCallingUid();
740 final String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
741 if (packages != null) {
742 for (String candidate : packages) {
743 if (packageName.equals(candidate)) return; // Found it
744 }
745 }
746 throw new SecurityException("UID " + uid + " does not own " + packageName);
747 }
748
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700749 // TODO(b/117779333): support proto
750 protected void dumpLocked(@NonNull String prefix, @NonNull PrintWriter pw) {
751 boolean realDebug = debug;
752 boolean realVerbose = verbose;
Felipe Leme18a9a4a2019-01-08 15:53:42 -0800753 final String prefix2 = " ";
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700754
755 try {
756 // Temporarily turn on full logging;
757 debug = verbose = true;
758 final int size = mServicesCache.size();
759 pw.print(prefix); pw.print("Debug: "); pw.print(realDebug);
760 pw.print(" Verbose: "); pw.println(realVerbose);
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700761 pw.print("Package policy flags: "); pw.println(mServicePackagePolicyFlags);
Felipe Leme2f288432019-03-21 13:57:45 -0700762 if (mUpdatingPackageNames != null) {
763 pw.print("Packages being updated: "); pw.println(mUpdatingPackageNames);
764 }
Felipe Lemee87735b2019-12-17 09:58:40 -0800765 dumpSupportedUsers(pw, prefix);
Felipe Lemec28711c2018-12-20 11:17:02 -0800766 if (mServiceNameResolver != null) {
767 pw.print(prefix); pw.print("Name resolver: ");
768 mServiceNameResolver.dumpShort(pw); pw.println();
Felipe Leme987655d2019-08-26 10:45:24 -0700769 final List<UserInfo> users = getSupportedUsers();
Felipe Leme18a9a4a2019-01-08 15:53:42 -0800770 for (int i = 0; i < users.size(); i++) {
771 final int userId = users.get(i).id;
772 pw.print(prefix2); pw.print(userId); pw.print(": ");
773 mServiceNameResolver.dumpShort(pw, userId); pw.println();
774 }
Felipe Lemec28711c2018-12-20 11:17:02 -0800775 }
Felipe Leme91ddeca2019-01-24 18:01:58 -0800776 pw.print(prefix); pw.print("Users disabled by restriction: ");
777 pw.println(mDisabledByUserRestriction);
Felipe Leme5933efb2018-11-29 16:08:49 -0800778 pw.print(prefix); pw.print("Allow instant service: "); pw.println(mAllowInstantService);
Felipe Leme0486d202018-12-04 09:47:39 -0800779 final String settingsProperty = getServiceSettingsProperty();
780 if (settingsProperty != null) {
781 pw.print(prefix); pw.print("Settings property: "); pw.println(settingsProperty);
782 }
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700783 pw.print(prefix); pw.print("Cached services: ");
784 if (size == 0) {
785 pw.println("none");
786 } else {
787 pw.println(size);
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700788 for (int i = 0; i < size; i++) {
789 pw.print(prefix); pw.print("Service at "); pw.print(i); pw.println(": ");
790 final S service = mServicesCache.valueAt(i);
791 service.dumpLocked(prefix2, pw);
792 pw.println();
793 }
794 }
795 } finally {
796 debug = realDebug;
797 verbose = realVerbose;
798 }
799 }
800
801 private void startTrackingPackageChanges() {
Felipe Leme73e65ba2019-03-13 10:57:09 -0700802 final PackageMonitor monitor = new PackageMonitor() {
803
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700804 @Override
Felipe Leme2f288432019-03-21 13:57:45 -0700805 public void onPackageUpdateStarted(@NonNull String packageName, int uid) {
806 if (verbose) Slog.v(mTag, "onPackageUpdateStarted(): " + packageName);
807 final String activePackageName = getActiveServicePackageNameLocked();
808 if (!packageName.equals(activePackageName)) return;
809
810 final int userId = getChangingUserId();
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700811 synchronized (mLock) {
Felipe Leme2f288432019-03-21 13:57:45 -0700812 if (mUpdatingPackageNames == null) {
813 mUpdatingPackageNames = new SparseArray<String>(mServicesCache.size());
814 }
815 mUpdatingPackageNames.put(userId, packageName);
816 onServicePackageUpdatingLocked(userId);
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700817 if ((mServicePackagePolicyFlags & PACKAGE_UPDATE_POLICY_NO_REFRESH) != 0) {
818 if (debug) {
819 Slog.d(mTag, "Holding service for user " + userId + " while package "
820 + activePackageName + " is being updated");
821 }
822 } else {
Felipe Leme2f288432019-03-21 13:57:45 -0700823 if (debug) {
Robert Berrye14120e2019-03-18 16:33:42 -0400824 Slog.d(mTag, "Removing service for user " + userId
825 + " because package " + activePackageName
826 + " is being updated");
Felipe Leme2f288432019-03-21 13:57:45 -0700827 }
828 removeCachedServiceLocked(userId);
Robert Berrye14120e2019-03-18 16:33:42 -0400829
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700830 if ((mServicePackagePolicyFlags & PACKAGE_UPDATE_POLICY_REFRESH_EAGER)
831 != 0) {
Robert Berrye14120e2019-03-18 16:33:42 -0400832 if (debug) {
833 Slog.d(mTag, "Eagerly recreating service for user "
834 + userId);
835 }
836 getServiceForUserLocked(userId);
837 }
Felipe Leme73e65ba2019-03-13 10:57:09 -0700838 }
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700839 }
840 }
841
842 @Override
Felipe Leme2f288432019-03-21 13:57:45 -0700843 public void onPackageUpdateFinished(@NonNull String packageName, int uid) {
844 if (verbose) Slog.v(mTag, "onPackageUpdateFinished(): " + packageName);
845 final int userId = getChangingUserId();
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700846 synchronized (mLock) {
Felipe Leme2f288432019-03-21 13:57:45 -0700847 final String activePackageName = mUpdatingPackageNames == null ? null
848 : mUpdatingPackageNames.get(userId);
849 if (packageName.equals(activePackageName)) {
850 if (mUpdatingPackageNames != null) {
851 mUpdatingPackageNames.remove(userId);
852 if (mUpdatingPackageNames.size() == 0) {
853 mUpdatingPackageNames = null;
854 }
855 }
856 onServicePackageUpdatedLocked(userId);
857 } else {
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700858 handlePackageUpdateLocked(packageName);
859 }
860 }
861 }
862
863 @Override
864 public void onPackageRemoved(String packageName, int uid) {
865 synchronized (mLock) {
866 final int userId = getChangingUserId();
867 final S service = peekServiceForUserLocked(userId);
868 if (service != null) {
869 final ComponentName componentName = service.getServiceComponentName();
870 if (componentName != null) {
871 if (packageName.equals(componentName.getPackageName())) {
872 handleActiveServiceRemoved(userId);
873 }
874 }
875 }
876 }
877 }
878
879 @Override
880 public boolean onHandleForceStop(Intent intent, String[] packages,
881 int uid, boolean doit) {
882 synchronized (mLock) {
Felipe Leme73e65ba2019-03-13 10:57:09 -0700883 final String activePackageName = getActiveServicePackageNameLocked();
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700884 for (String pkg : packages) {
885 if (pkg.equals(activePackageName)) {
886 if (!doit) {
887 return true;
888 }
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700889 final String action = intent.getAction();
890 final int userId = getChangingUserId();
891 if (Intent.ACTION_PACKAGE_RESTARTED.equals(action)) {
892 handleActiveServiceRestartedLocked(activePackageName, userId);
893 } else {
894 removeCachedServiceLocked(userId);
895 }
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700896 } else {
897 handlePackageUpdateLocked(pkg);
898 }
899 }
900 }
901 return false;
902 }
903
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700904 @Override
905 public void onPackageDataCleared(String packageName, int uid) {
906 if (verbose) Slog.v(mTag, "onPackageDataCleared(): " + packageName);
907 final int userId = getChangingUserId();
908 synchronized (mLock) {
909 final S service = peekServiceForUserLocked(userId);
910 if (service != null) {
911 final ComponentName componentName = service.getServiceComponentName();
912 if (componentName != null) {
913 if (packageName.equals(componentName.getPackageName())) {
914 onServicePackageDataClearedLocked(userId);
915 }
916 }
917 }
918 }
919 }
920
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700921 private void handleActiveServiceRemoved(@UserIdInt int userId) {
Felipe Leme73e65ba2019-03-13 10:57:09 -0700922 synchronized (mLock) {
923 removeCachedServiceLocked(userId);
924 }
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700925 final String serviceSettingsProperty = getServiceSettingsProperty();
926 if (serviceSettingsProperty != null) {
927 Settings.Secure.putStringForUser(getContext().getContentResolver(),
928 serviceSettingsProperty, null, userId);
929 }
930 }
931
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700932 private void handleActiveServiceRestartedLocked(String activePackageName,
933 @UserIdInt int userId) {
934 if ((mServicePackagePolicyFlags & PACKAGE_RESTART_POLICY_NO_REFRESH) != 0) {
935 if (debug) {
936 Slog.d(mTag, "Holding service for user " + userId + " while package "
937 + activePackageName + " is being restarted");
938 }
939 } else {
940 if (debug) {
941 Slog.d(mTag, "Removing service for user " + userId
942 + " because package " + activePackageName
943 + " is being restarted");
944 }
945 removeCachedServiceLocked(userId);
946
947 if ((mServicePackagePolicyFlags & PACKAGE_RESTART_POLICY_REFRESH_EAGER) != 0) {
948 if (debug) {
949 Slog.d(mTag, "Eagerly recreating service for user " + userId);
950 }
951 getServiceForUserLocked(userId);
952 }
953 }
954 onServicePackageRestartedLocked(userId);
955 }
956
Felipe Leme73e65ba2019-03-13 10:57:09 -0700957 private String getActiveServicePackageNameLocked() {
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700958 final int userId = getChangingUserId();
959 final S service = peekServiceForUserLocked(userId);
960 if (service == null) {
961 return null;
962 }
963 final ComponentName serviceComponent = service.getServiceComponentName();
964 if (serviceComponent == null) {
965 return null;
966 }
967 return serviceComponent.getPackageName();
968 }
969
970 @GuardedBy("mLock")
971 private void handlePackageUpdateLocked(String packageName) {
972 visitServicesLocked((s) -> s.handlePackageUpdateLocked(packageName));
973 }
974 };
975
976 // package changes
977 monitor.register(getContext(), null, UserHandle.ALL, true);
978 }
979
980 /**
981 * Visitor pattern.
982 *
983 * @param <S> visited class.
984 */
985 public interface Visitor<S> {
986 /**
987 * Visits a service.
988 *
989 * @param service the service to be visited.
990 */
991 void visit(@NonNull S service);
992 }
993
994 private final class SettingsObserver extends ContentObserver {
995 SettingsObserver(Handler handler) {
996 super(handler);
997 ContentResolver resolver = getContext().getContentResolver();
998 final String serviceProperty = getServiceSettingsProperty();
999 if (serviceProperty != null) {
1000 resolver.registerContentObserver(Settings.Secure.getUriFor(
1001 serviceProperty), false, this, UserHandle.USER_ALL);
1002 }
1003 resolver.registerContentObserver(Settings.Secure.getUriFor(
1004 Settings.Secure.USER_SETUP_COMPLETE), false, this, UserHandle.USER_ALL);
1005 registerForExtraSettingsChanges(resolver, this);
1006 }
1007
1008 @Override
1009 public void onChange(boolean selfChange, Uri uri, @UserIdInt int userId) {
1010 if (verbose) Slog.v(mTag, "onChange(): uri=" + uri + ", userId=" + userId);
1011 final String property = uri.getLastPathSegment();
1012 if (property.equals(getServiceSettingsProperty())
1013 || property.equals(Settings.Secure.USER_SETUP_COMPLETE)) {
1014 synchronized (mLock) {
1015 updateCachedServiceLocked(userId);
1016 }
1017 } else {
1018 onSettingsChanged(userId, property);
1019 }
1020 }
1021 }
1022}