blob: 9782f30d30743e091e31638e042442b42fe6b693 [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 Berry835123d2019-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 Berry835123d2019-03-18 16:33:42 -040049import java.lang.annotation.Retention;
50import java.lang.annotation.RetentionPolicy;
Felipe Lemeea95a6d2018-10-15 10:45:01 -070051import java.util.List;
52
53/**
54 * Base class for {@link SystemService SystemServices} that support multi user.
55 *
56 * <p>Subclasses of this service are just a facade for the service binder calls - the "real" work
57 * is done by the {@link AbstractPerUserSystemService} subclasses, which are automatically managed
58 * through an user -> service cache.
59 *
60 * <p>It also takes care of other plumbing tasks such as:
61 *
62 * <ul>
63 * <li>Disabling the service when {@link UserManager} restrictions change.
64 * <li>Refreshing the service when its underlying
Felipe Leme749b8892018-12-03 16:30:30 -080065 * {@link #getServiceSettingsProperty() Settings property} changed.
Felipe Lemeea95a6d2018-10-15 10:45:01 -070066 * <li>Calling the service when other Settings properties changed.
67 * </ul>
68 *
69 * <p>See {@code com.android.server.autofill.AutofillManagerService} for a concrete
70 * (no pun intended) example of how to use it.
71 *
Felipe Lemee20bf9f2018-11-19 11:14:31 -080072 * @param <M> "master" service class.
Felipe Lemeea95a6d2018-10-15 10:45:01 -070073 * @param <S> "real" service class.
74 *
75 * @hide
76 */
77// TODO(b/117779333): improve javadoc above instead of using Autofill as an example
Felipe Lemee20bf9f2018-11-19 11:14:31 -080078public abstract class AbstractMasterSystemService<M extends AbstractMasterSystemService<M, S>,
79 S extends AbstractPerUserSystemService<S, M>> extends SystemService {
Felipe Lemeea95a6d2018-10-15 10:45:01 -070080
Robert Berry835123d2019-03-18 16:33:42 -040081 /** On a package update, does not refresh the per-user service in the cache. */
82 public static final int PACKAGE_UPDATE_POLICY_NO_REFRESH = 0;
83
84 /**
85 * On a package update, removes any existing per-user services in the cache.
86 *
87 * <p>This does not immediately recreate these services. It is assumed they will be recreated
88 * for the next user request.
89 */
90 public static final int PACKAGE_UPDATE_POLICY_REFRESH_LAZY = 1;
91
92 /**
93 * On a package update, removes and recreates any existing per-user services in the cache.
94 */
95 public static final int PACKAGE_UPDATE_POLICY_REFRESH_EAGER = 2;
96
97 @IntDef(flag = true, prefix = { "PACKAGE_UPDATE_POLICY_" }, value = {
98 PACKAGE_UPDATE_POLICY_NO_REFRESH,
99 PACKAGE_UPDATE_POLICY_REFRESH_LAZY,
100 PACKAGE_UPDATE_POLICY_REFRESH_EAGER
101 })
102 @Retention(RetentionPolicy.SOURCE)
103 public @interface PackageUpdatePolicy {}
104
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700105 /**
106 * Log tag
107 */
108 protected final String mTag = getClass().getSimpleName();
109
110 /**
111 * Lock used to synchronize access to internal state; should be acquired before calling a
112 * method whose name ends with {@code locked}.
113 */
114 protected final Object mLock = new Object();
115
116 /**
Felipe Lemec28711c2018-12-20 11:17:02 -0800117 * Object used to define the name of the service component used to create
118 * {@link com.android.internal.infra.AbstractRemoteService} instances.
119 */
120 @Nullable
121 protected final ServiceNameResolver mServiceNameResolver;
122
123 /**
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700124 * Whether the service should log debug statements.
125 */
Felipe Lemec28711c2018-12-20 11:17:02 -0800126 //TODO(b/117779333): consider using constants for these guards
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700127 public boolean verbose = false;
128
129 /**
130 * Whether the service should log verbose statements.
131 */
Felipe Lemec28711c2018-12-20 11:17:02 -0800132 //TODO(b/117779333): consider using constants for these guards
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700133 public boolean debug = false;
134
135 /**
Felipe Leme5933efb2018-11-29 16:08:49 -0800136 * Whether the service is allowed to bind to an instant-app.
137 */
138 @GuardedBy("mLock")
139 protected boolean mAllowInstantService;
140
141 /**
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700142 * Users disabled due to {@link UserManager} restrictions, or {@code null} if the service cannot
143 * be disabled through {@link UserManager}.
144 */
145 @GuardedBy("mLock")
146 @Nullable
Felipe Leme91ddeca2019-01-24 18:01:58 -0800147 private final SparseBooleanArray mDisabledByUserRestriction;
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700148
149 /**
150 * Cache of services per user id.
151 */
152 @GuardedBy("mLock")
153 private final SparseArray<S> mServicesCache = new SparseArray<>();
154
155 /**
Felipe Leme73e65ba2019-03-13 10:57:09 -0700156 * Whether the per-user service should be removed from the cache when its apk is updated.
Robert Berry835123d2019-03-18 16:33:42 -0400157 *
158 * <p>One of {@link #PACKAGE_UPDATE_POLICY_NO_REFRESH},
159 * {@link #PACKAGE_UPDATE_POLICY_REFRESH_LAZY} or {@link #PACKAGE_UPDATE_POLICY_REFRESH_EAGER}.
Felipe Leme73e65ba2019-03-13 10:57:09 -0700160 */
Robert Berry835123d2019-03-18 16:33:42 -0400161 private final @PackageUpdatePolicy int mPackageUpdatePolicy;
Felipe Leme73e65ba2019-03-13 10:57:09 -0700162
163 /**
Felipe Leme2f288432019-03-21 13:57:45 -0700164 * Name of the service packages whose APK are being updated, keyed by user id.
Felipe Leme73e65ba2019-03-13 10:57:09 -0700165 */
166 @GuardedBy("mLock")
Felipe Leme2f288432019-03-21 13:57:45 -0700167 private SparseArray<String> mUpdatingPackageNames;
Felipe Leme73e65ba2019-03-13 10:57:09 -0700168
169 /**
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700170 * Default constructor.
171 *
Felipe Leme73e65ba2019-03-13 10:57:09 -0700172 * <p>When using this constructor, the {@link AbstractPerUserSystemService} is removed from
173 * the cache (and re-added) when the service package is updated.
174 *
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700175 * @param context system context.
Felipe Lemec28711c2018-12-20 11:17:02 -0800176 * @param serviceNameResolver resolver for
177 * {@link com.android.internal.infra.AbstractRemoteService} instances, or
178 * {@code null} when the service doesn't bind to remote services.
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700179 * @param disallowProperty when not {@code null}, defines a {@link UserManager} restriction that
Felipe Lemec0ac60b2019-02-25 09:17:16 -0800180 * disables the service. <b>NOTE: </b> you'll also need to add it to
181 * {@code UserRestrictionsUtils.USER_RESTRICTIONS}.
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700182 */
183 protected AbstractMasterSystemService(@NonNull Context context,
Felipe Lemec28711c2018-12-20 11:17:02 -0800184 @Nullable ServiceNameResolver serviceNameResolver,
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700185 @Nullable String disallowProperty) {
Felipe Leme73e65ba2019-03-13 10:57:09 -0700186 this(context, serviceNameResolver, disallowProperty,
Robert Berry835123d2019-03-18 16:33:42 -0400187 /*packageUpdatePolicy=*/ PACKAGE_UPDATE_POLICY_REFRESH_LAZY);
Felipe Leme73e65ba2019-03-13 10:57:09 -0700188 }
189
190 /**
191 * Full constructor.
192 *
193 * @param context system context.
194 * @param serviceNameResolver resolver for
195 * {@link com.android.internal.infra.AbstractRemoteService} instances, or
196 * {@code null} when the service doesn't bind to remote services.
197 * @param disallowProperty when not {@code null}, defines a {@link UserManager} restriction that
198 * disables the service. <b>NOTE: </b> you'll also need to add it to
199 * {@code UserRestrictionsUtils.USER_RESTRICTIONS}.
Robert Berry835123d2019-03-18 16:33:42 -0400200 * @param packageUpdatePolicy when {@link #PACKAGE_UPDATE_POLICY_REFRESH_LAZY}, the
201 * {@link AbstractPerUserSystemService} is removed from the cache when the service
202 * package is updated; when {@link #PACKAGE_UPDATE_POLICY_REFRESH_EAGER}, the
203 * {@link AbstractPerUserSystemService} is removed from the cache and immediately
204 * re-added when the service package is updated; when
205 * {@link #PACKAGE_UPDATE_POLICY_NO_REFRESH}, the service is untouched during the update.
Felipe Leme73e65ba2019-03-13 10:57:09 -0700206 */
207 protected AbstractMasterSystemService(@NonNull Context context,
208 @Nullable ServiceNameResolver serviceNameResolver,
Robert Berry835123d2019-03-18 16:33:42 -0400209 @Nullable String disallowProperty, @PackageUpdatePolicy int packageUpdatePolicy) {
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700210 super(context);
211
Robert Berry835123d2019-03-18 16:33:42 -0400212 mPackageUpdatePolicy = packageUpdatePolicy;
Felipe Leme73e65ba2019-03-13 10:57:09 -0700213
Felipe Lemec28711c2018-12-20 11:17:02 -0800214 mServiceNameResolver = serviceNameResolver;
215 if (mServiceNameResolver != null) {
Felipe Leme9bee9442019-03-27 13:40:40 -0700216 mServiceNameResolver.setOnTemporaryServiceNameChangedCallback(
217 (u, s, t) -> onServiceNameChanged(u, s, t));
Felipe Lemec28711c2018-12-20 11:17:02 -0800218
219 }
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700220 if (disallowProperty == null) {
Felipe Leme91ddeca2019-01-24 18:01:58 -0800221 mDisabledByUserRestriction = null;
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700222 } else {
Felipe Leme91ddeca2019-01-24 18:01:58 -0800223 mDisabledByUserRestriction = new SparseBooleanArray();
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700224 // Hookup with UserManager to disable service when necessary.
225 final UserManager um = context.getSystemService(UserManager.class);
226 final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
227 final List<UserInfo> users = um.getUsers();
228 for (int i = 0; i < users.size(); i++) {
229 final int userId = users.get(i).id;
230 final boolean disabled = umi.getUserRestriction(userId, disallowProperty);
231 if (disabled) {
Felipe Leme91ddeca2019-01-24 18:01:58 -0800232 Slog.i(mTag, "Disabling by restrictions user " + userId);
233 mDisabledByUserRestriction.put(userId, disabled);
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700234 }
235 }
236 umi.addUserRestrictionsListener((userId, newRestrictions, prevRestrictions) -> {
237 final boolean disabledNow =
238 newRestrictions.getBoolean(disallowProperty, false);
239 synchronized (mLock) {
Felipe Leme91ddeca2019-01-24 18:01:58 -0800240 final boolean disabledBefore = mDisabledByUserRestriction.get(userId);
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700241 if (disabledBefore == disabledNow) {
242 // Nothing changed, do nothing.
243 if (debug) {
244 Slog.d(mTag, "Restriction did not change for user " + userId);
245 return;
246 }
247 }
248 Slog.i(mTag, "Updating for user " + userId + ": disabled=" + disabledNow);
Felipe Leme91ddeca2019-01-24 18:01:58 -0800249 mDisabledByUserRestriction.put(userId, disabledNow);
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700250 updateCachedServiceLocked(userId, disabledNow);
251 }
252 });
253 }
254 startTrackingPackageChanges();
255 }
256
257 @Override // from SystemService
258 public void onBootPhase(int phase) {
259 if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
260 new SettingsObserver(BackgroundThread.getHandler());
261 }
262 }
263
264 @Override // from SystemService
265 public void onUnlockUser(int userId) {
266 synchronized (mLock) {
267 updateCachedServiceLocked(userId);
268 }
269 }
270
271 @Override // from SystemService
272 public void onCleanupUser(int userId) {
273 synchronized (mLock) {
274 removeCachedServiceLocked(userId);
275 }
276 }
277
278 /**
Felipe Leme5933efb2018-11-29 16:08:49 -0800279 * Gets whether the service is allowed to bind to an instant-app.
280 *
281 * <p>Typically called by {@code ShellCommand} during CTS tests.
282 *
283 * @throws SecurityException if caller is not allowed to manage this service's settings.
284 */
285 public final boolean getAllowInstantService() {
286 enforceCallingPermissionForManagement();
287 synchronized (mLock) {
288 return mAllowInstantService;
289 }
290 }
291
292 /**
Felipe Leme50b33dc2018-12-20 16:01:39 -0800293 * Checks whether the service is allowed to bind to an instant-app.
294 *
295 * <p>Typically called by subclasses when creating {@link AbstractRemoteService} instances.
296 *
297 * <p><b>NOTE: </b>must not be called by {@code ShellCommand} as it does not check for
298 * permission.
299 */
300 public final boolean isBindInstantServiceAllowed() {
301 synchronized (mLock) {
302 return mAllowInstantService;
303 }
304 }
305
306 /**
Felipe Leme5933efb2018-11-29 16:08:49 -0800307 * Sets whether the service is allowed to bind to an instant-app.
308 *
309 * <p>Typically called by {@code ShellCommand} during CTS tests.
310 *
311 * @throws SecurityException if caller is not allowed to manage this service's settings.
312 */
313 public final void setAllowInstantService(boolean mode) {
314 Slog.i(mTag, "setAllowInstantService(): " + mode);
315 enforceCallingPermissionForManagement();
316 synchronized (mLock) {
317 mAllowInstantService = mode;
318 }
319 }
320
321 /**
Felipe Leme0486d202018-12-04 09:47:39 -0800322 * Temporarily sets the service implementation.
Felipe Leme658c8e42018-11-30 12:49:45 -0800323 *
324 * <p>Typically used by Shell command and/or CTS tests.
325 *
326 * @param componentName name of the new component
327 * @param durationMs how long the change will be valid (the service will be automatically reset
328 * to the default component after this timeout expires).
329 * @throws SecurityException if caller is not allowed to manage this service's settings.
330 * @throws IllegalArgumentException if value of {@code durationMs} is higher than
331 * {@link #getMaximumTemporaryServiceDurationMs()}.
332 */
333 public final void setTemporaryService(@UserIdInt int userId, @NonNull String componentName,
334 int durationMs) {
335 Slog.i(mTag, "setTemporaryService(" + userId + ") to " + componentName + " for "
336 + durationMs + "ms");
337 enforceCallingPermissionForManagement();
338
339 Preconditions.checkNotNull(componentName);
340 final int maxDurationMs = getMaximumTemporaryServiceDurationMs();
341 if (durationMs > maxDurationMs) {
342 throw new IllegalArgumentException(
343 "Max duration is " + maxDurationMs + " (called with " + durationMs + ")");
344 }
345
346 synchronized (mLock) {
Felipe Leme18a9a4a2019-01-08 15:53:42 -0800347 final S oldService = peekServiceForUserLocked(userId);
348 if (oldService != null) {
349 oldService.removeSelfFromCacheLocked();
Felipe Leme658c8e42018-11-30 12:49:45 -0800350 }
Felipe Leme18a9a4a2019-01-08 15:53:42 -0800351 mServiceNameResolver.setTemporaryService(userId, componentName, durationMs);
Felipe Leme658c8e42018-11-30 12:49:45 -0800352 }
353 }
354
355 /**
Felipe Leme567df6a2019-02-05 15:00:05 -0800356 * Sets whether the default service should be used.
357 *
358 * <p>Typically used during CTS tests to make sure only the default service doesn't interfere
359 * with the test results.
360 *
361 * @throws SecurityException if caller is not allowed to manage this service's settings.
Felipe Lemea70dd8c2019-03-19 10:21:28 -0700362 *
363 * @return whether the enabled state changed.
Felipe Leme567df6a2019-02-05 15:00:05 -0800364 */
Felipe Lemea70dd8c2019-03-19 10:21:28 -0700365 public final boolean setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
Felipe Leme567df6a2019-02-05 15:00:05 -0800366 Slog.i(mTag, "setDefaultServiceEnabled() for userId " + userId + ": " + enabled);
367 enforceCallingPermissionForManagement();
368
369 synchronized (mLock) {
Felipe Lemea70dd8c2019-03-19 10:21:28 -0700370 final boolean changed = mServiceNameResolver.setDefaultServiceEnabled(userId, enabled);
371 if (!changed) {
372 if (verbose) {
373 Slog.v(mTag, "setDefaultServiceEnabled(" + userId + "): already " + enabled);
374 }
375 return false;
376 }
377
Felipe Leme567df6a2019-02-05 15:00:05 -0800378 final S oldService = peekServiceForUserLocked(userId);
379 if (oldService != null) {
380 oldService.removeSelfFromCacheLocked();
381 }
Felipe Leme567df6a2019-02-05 15:00:05 -0800382
383 // Must update the service on cache so its initialization code is triggered
384 updateCachedServiceLocked(userId);
385 }
Felipe Lemea70dd8c2019-03-19 10:21:28 -0700386 return true;
Felipe Leme567df6a2019-02-05 15:00:05 -0800387 }
388
389 /**
390 * Checks whether the default service should be used.
391 *
392 * <p>Typically used during CTS tests to make sure only the default service doesn't interfere
393 * with the test results.
394 *
395 * @throws SecurityException if caller is not allowed to manage this service's settings.
396 */
397 public final boolean isDefaultServiceEnabled(@UserIdInt int userId) {
398 enforceCallingPermissionForManagement();
399
400 synchronized (mLock) {
401 return mServiceNameResolver.isDefaultServiceEnabled(userId);
402 }
403 }
404
405 /**
Felipe Leme658c8e42018-11-30 12:49:45 -0800406 * Gets the maximum time the service implementation can be changed.
407 *
408 * @throws UnsupportedOperationException if subclass doesn't override it.
409 */
410 protected int getMaximumTemporaryServiceDurationMs() {
411 throw new UnsupportedOperationException("Not implemented by " + getClass());
412 }
413
414 /**
415 * Resets the temporary service implementation to the default component.
416 *
417 * <p>Typically used by Shell command and/or CTS tests.
418 *
419 * @throws SecurityException if caller is not allowed to manage this service's settings.
420 */
421 public final void resetTemporaryService(@UserIdInt int userId) {
422 Slog.i(mTag, "resetTemporaryService(): " + userId);
423 enforceCallingPermissionForManagement();
424 synchronized (mLock) {
425 final S service = getServiceForUserLocked(userId);
426 if (service != null) {
427 service.resetTemporaryServiceLocked();
428 }
429 }
430 }
431
432 /**
Felipe Leme5933efb2018-11-29 16:08:49 -0800433 * Asserts that the caller has permissions to manage this service.
434 *
435 * <p>Typically called by {@code ShellCommand} implementations.
436 *
437 * @throws UnsupportedOperationException if subclass doesn't override it.
438 * @throws SecurityException if caller is not allowed to manage this service's settings.
439 */
440 protected void enforceCallingPermissionForManagement() {
441 throw new UnsupportedOperationException("Not implemented by " + getClass());
442 }
443
444 /**
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700445 * Creates a new service that will be added to the cache.
446 *
447 * @param resolvedUserId the resolved user id for the service.
448 * @param disabled whether the service is currently disabled (due to {@link UserManager}
449 * restrictions).
450 *
451 * @return a new instance.
452 */
Felipe Leme50b33dc2018-12-20 16:01:39 -0800453 @Nullable
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700454 protected abstract S newServiceLocked(@UserIdInt int resolvedUserId, boolean disabled);
455
456 /**
457 * Register the service for extra Settings changes (i.e., other than
458 * {@link android.provider.Settings.Secure#USER_SETUP_COMPLETE} or
459 * {@link #getServiceSettingsProperty()}, which are automatically handled).
460 *
461 * <p> Example:
462 *
463 * <pre><code>
464 * resolver.registerContentObserver(Settings.Global.getUriFor(
465 * Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES), false, observer,
466 * UserHandle.USER_ALL);
467 * </code></pre>
468 *
469 * <p><b>NOTE: </p>it doesn't need to register for
470 * {@link android.provider.Settings.Secure#USER_SETUP_COMPLETE} or
471 * {@link #getServiceSettingsProperty()}.
472 *
473 */
474 @SuppressWarnings("unused")
475 protected void registerForExtraSettingsChanges(@NonNull ContentResolver resolver,
476 @NonNull ContentObserver observer) {
477 }
478
479 /**
480 * Callback for Settings changes that were registered though
481 * {@link #registerForExtraSettingsChanges(ContentResolver, ContentObserver)}.
482 *
483 * @param userId user associated with the change
484 * @param property Settings property changed.
485 */
486 protected void onSettingsChanged(@UserIdInt int userId, @NonNull String property) {
487 }
488
489 /**
490 * Gets the service instance for an user, creating an instance if not present in the cache.
491 */
492 @GuardedBy("mLock")
493 @NonNull
494 protected S getServiceForUserLocked(@UserIdInt int userId) {
495 final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
496 Binder.getCallingUid(), userId, false, false, null, null);
497 S service = mServicesCache.get(resolvedUserId);
498 if (service == null) {
499 final boolean disabled = isDisabledLocked(userId);
500 service = newServiceLocked(resolvedUserId, disabled);
501 if (!disabled) {
502 onServiceEnabledLocked(service, resolvedUserId);
503 }
504 mServicesCache.put(userId, service);
505 }
506 return service;
507 }
508
509 /**
510 * Gets the <b>existing</b> service instance for a user, returning {@code null} if not already
511 * present in the cache.
512 */
513 @GuardedBy("mLock")
514 @Nullable
Felipe Leme7ed7b2c2018-11-14 17:47:15 -0800515 protected S peekServiceForUserLocked(@UserIdInt int userId) {
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700516 final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
517 Binder.getCallingUid(), userId, false, false, null, null);
518 return mServicesCache.get(resolvedUserId);
519 }
520
521 /**
522 * Updates a cached service for a given user.
523 */
524 @GuardedBy("mLock")
Felipe Leme7ed7b2c2018-11-14 17:47:15 -0800525 protected void updateCachedServiceLocked(@UserIdInt int userId) {
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700526 updateCachedServiceLocked(userId, isDisabledLocked(userId));
527 }
528
529 /**
530 * Checks whether the service is disabled (through {@link UserManager} restrictions) for the
531 * given user.
532 */
Felipe Leme7ed7b2c2018-11-14 17:47:15 -0800533 protected boolean isDisabledLocked(@UserIdInt int userId) {
Felipe Leme91ddeca2019-01-24 18:01:58 -0800534 return mDisabledByUserRestriction == null ? false : mDisabledByUserRestriction.get(userId);
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700535 }
536
537 /**
538 * Updates a cached service for a given user.
539 *
540 * @param userId user handle.
541 * @param disabled whether the user is disabled.
542 * @return service for the user.
543 */
544 @GuardedBy("mLock")
Felipe Leme7ed7b2c2018-11-14 17:47:15 -0800545 protected S updateCachedServiceLocked(@UserIdInt int userId, boolean disabled) {
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700546 final S service = getServiceForUserLocked(userId);
547 if (service != null) {
548 service.updateLocked(disabled);
549 if (!service.isEnabledLocked()) {
550 removeCachedServiceLocked(userId);
551 } else {
552 onServiceEnabledLocked(service, userId);
553 }
554 }
555 return service;
556 }
557
558 /**
559 * Gets the Settings property that defines the name of the component name used to bind this
560 * service to an external service, or {@code null} when the service is not defined by such
561 * property (for example, if it's a system service defined by framework resources).
562 */
563 @Nullable
564 protected String getServiceSettingsProperty() {
565 return null;
566 }
567
568 /**
569 * Callback called after a new service was added to the cache, or an existing service that was
570 * previously disabled gets enabled.
571 *
572 * <p>By default doesn't do anything, but can be overridden by subclasses.
573 */
574 @SuppressWarnings("unused")
Felipe Leme7ed7b2c2018-11-14 17:47:15 -0800575 protected void onServiceEnabledLocked(@NonNull S service, @UserIdInt int userId) {
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700576 }
577
578 /**
579 * Removes a cached service for a given user.
580 *
Felipe Leme50b33dc2018-12-20 16:01:39 -0800581 * @return the removed service.
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700582 */
583 @GuardedBy("mLock")
584 @NonNull
Felipe Leme50b33dc2018-12-20 16:01:39 -0800585 protected final S removeCachedServiceLocked(@UserIdInt int userId) {
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700586 final S service = peekServiceForUserLocked(userId);
587 if (service != null) {
588 mServicesCache.delete(userId);
Felipe Leme7ed7b2c2018-11-14 17:47:15 -0800589 onServiceRemoved(service, userId);
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700590 }
591 return service;
592 }
593
594 /**
Felipe Leme2f288432019-03-21 13:57:45 -0700595 * Called before the package that provides the service for the given user is being updated.
596 */
597 protected void onServicePackageUpdatingLocked(@UserIdInt int userId) {
598 if (verbose) Slog.v(mTag, "onServicePackageUpdatingLocked(" + userId + ")");
599 }
600
601 /**
602 * Called after the package that provides the service for the given user is being updated.
603 */
604 protected void onServicePackageUpdatedLocked(@UserIdInt int userId) {
605 if (verbose) Slog.v(mTag, "onServicePackageUpdated(" + userId + ")");
606 }
607
608 /**
Felipe Leme7ed7b2c2018-11-14 17:47:15 -0800609 * Called after the service is removed from the cache.
610 */
611 @SuppressWarnings("unused")
612 protected void onServiceRemoved(@NonNull S service, @UserIdInt int userId) {
613 }
614
615 /**
Felipe Leme9bee9442019-03-27 13:40:40 -0700616 * Called when the service name changed (typically when using temporary services).
617 *
618 * <p>By default, it calls {@link #updateCachedServiceLocked(int)}; subclasses must either call
619 * that same method, or {@code super.onServiceNameChanged()}.
620 *
621 * @param userId user handle.
622 * @param serviceName the new service name.
623 * @param isTemporary whether the new service is temporary.
624 */
625 protected void onServiceNameChanged(@UserIdInt int userId, @Nullable String serviceName,
626 boolean isTemporary) {
627 synchronized (mLock) {
628 updateCachedServiceLocked(userId);
629 }
630 }
631
632 /**
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700633 * Visits all services in the cache.
634 */
635 @GuardedBy("mLock")
636 protected void visitServicesLocked(@NonNull Visitor<S> visitor) {
637 final int size = mServicesCache.size();
638 for (int i = 0; i < size; i++) {
639 visitor.visit(mServicesCache.valueAt(i));
640 }
641 }
642
643 /**
644 * Clear the cache by removing all services.
645 */
646 @GuardedBy("mLock")
647 protected void clearCacheLocked() {
648 mServicesCache.clear();
649 }
650
Felipe Lemeafbba9f2019-03-26 14:02:25 -0700651 /**
652 * Asserts that the given package name is owned by the UID making this call.
653 *
654 * @throws SecurityException when it's not...
655 */
656 protected final void assertCalledByPackageOwner(@NonNull String packageName) {
657 Preconditions.checkNotNull(packageName);
658 final int uid = Binder.getCallingUid();
659 final String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
660 if (packages != null) {
661 for (String candidate : packages) {
662 if (packageName.equals(candidate)) return; // Found it
663 }
664 }
665 throw new SecurityException("UID " + uid + " does not own " + packageName);
666 }
667
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700668 // TODO(b/117779333): support proto
669 protected void dumpLocked(@NonNull String prefix, @NonNull PrintWriter pw) {
670 boolean realDebug = debug;
671 boolean realVerbose = verbose;
Felipe Leme18a9a4a2019-01-08 15:53:42 -0800672 final String prefix2 = " ";
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700673
674 try {
675 // Temporarily turn on full logging;
676 debug = verbose = true;
677 final int size = mServicesCache.size();
678 pw.print(prefix); pw.print("Debug: "); pw.print(realDebug);
679 pw.print(" Verbose: "); pw.println(realVerbose);
Robert Berry835123d2019-03-18 16:33:42 -0400680 pw.print("Refresh on package update: "); pw.println(mPackageUpdatePolicy);
Felipe Leme2f288432019-03-21 13:57:45 -0700681 if (mUpdatingPackageNames != null) {
682 pw.print("Packages being updated: "); pw.println(mUpdatingPackageNames);
683 }
Felipe Lemec28711c2018-12-20 11:17:02 -0800684 if (mServiceNameResolver != null) {
685 pw.print(prefix); pw.print("Name resolver: ");
686 mServiceNameResolver.dumpShort(pw); pw.println();
Felipe Leme18a9a4a2019-01-08 15:53:42 -0800687 final UserManager um = getContext().getSystemService(UserManager.class);
688 final List<UserInfo> users = um.getUsers();
689 for (int i = 0; i < users.size(); i++) {
690 final int userId = users.get(i).id;
691 pw.print(prefix2); pw.print(userId); pw.print(": ");
692 mServiceNameResolver.dumpShort(pw, userId); pw.println();
693 }
Felipe Lemec28711c2018-12-20 11:17:02 -0800694 }
Felipe Leme91ddeca2019-01-24 18:01:58 -0800695 pw.print(prefix); pw.print("Users disabled by restriction: ");
696 pw.println(mDisabledByUserRestriction);
Felipe Leme5933efb2018-11-29 16:08:49 -0800697 pw.print(prefix); pw.print("Allow instant service: "); pw.println(mAllowInstantService);
Felipe Leme0486d202018-12-04 09:47:39 -0800698 final String settingsProperty = getServiceSettingsProperty();
699 if (settingsProperty != null) {
700 pw.print(prefix); pw.print("Settings property: "); pw.println(settingsProperty);
701 }
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700702 pw.print(prefix); pw.print("Cached services: ");
703 if (size == 0) {
704 pw.println("none");
705 } else {
706 pw.println(size);
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700707 for (int i = 0; i < size; i++) {
708 pw.print(prefix); pw.print("Service at "); pw.print(i); pw.println(": ");
709 final S service = mServicesCache.valueAt(i);
710 service.dumpLocked(prefix2, pw);
711 pw.println();
712 }
713 }
714 } finally {
715 debug = realDebug;
716 verbose = realVerbose;
717 }
718 }
719
720 private void startTrackingPackageChanges() {
Felipe Leme73e65ba2019-03-13 10:57:09 -0700721 final PackageMonitor monitor = new PackageMonitor() {
722
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700723 @Override
Felipe Leme2f288432019-03-21 13:57:45 -0700724 public void onPackageUpdateStarted(@NonNull String packageName, int uid) {
725 if (verbose) Slog.v(mTag, "onPackageUpdateStarted(): " + packageName);
726 final String activePackageName = getActiveServicePackageNameLocked();
727 if (!packageName.equals(activePackageName)) return;
728
729 final int userId = getChangingUserId();
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700730 synchronized (mLock) {
Felipe Leme2f288432019-03-21 13:57:45 -0700731 if (mUpdatingPackageNames == null) {
732 mUpdatingPackageNames = new SparseArray<String>(mServicesCache.size());
733 }
734 mUpdatingPackageNames.put(userId, packageName);
735 onServicePackageUpdatingLocked(userId);
Robert Berry835123d2019-03-18 16:33:42 -0400736 if (mPackageUpdatePolicy != PACKAGE_UPDATE_POLICY_NO_REFRESH) {
Felipe Leme2f288432019-03-21 13:57:45 -0700737 if (debug) {
Robert Berry835123d2019-03-18 16:33:42 -0400738 Slog.d(mTag, "Removing service for user " + userId
739 + " because package " + activePackageName
740 + " is being updated");
Felipe Leme2f288432019-03-21 13:57:45 -0700741 }
742 removeCachedServiceLocked(userId);
Robert Berry835123d2019-03-18 16:33:42 -0400743
744 if (mPackageUpdatePolicy == PACKAGE_UPDATE_POLICY_REFRESH_EAGER) {
745 if (debug) {
746 Slog.d(mTag, "Eagerly recreating service for user "
747 + userId);
748 }
749 getServiceForUserLocked(userId);
750 }
Felipe Leme2f288432019-03-21 13:57:45 -0700751 } else {
752 if (debug) {
753 Slog.d(mTag, "Holding service for user " + userId + " while package "
754 + activePackageName + " is being updated");
Felipe Leme73e65ba2019-03-13 10:57:09 -0700755 }
756 }
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700757 }
758 }
759
760 @Override
Felipe Leme2f288432019-03-21 13:57:45 -0700761 public void onPackageUpdateFinished(@NonNull String packageName, int uid) {
762 if (verbose) Slog.v(mTag, "onPackageUpdateFinished(): " + packageName);
763 final int userId = getChangingUserId();
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700764 synchronized (mLock) {
Felipe Leme2f288432019-03-21 13:57:45 -0700765 final String activePackageName = mUpdatingPackageNames == null ? null
766 : mUpdatingPackageNames.get(userId);
767 if (packageName.equals(activePackageName)) {
768 if (mUpdatingPackageNames != null) {
769 mUpdatingPackageNames.remove(userId);
770 if (mUpdatingPackageNames.size() == 0) {
771 mUpdatingPackageNames = null;
772 }
773 }
774 onServicePackageUpdatedLocked(userId);
775 } else {
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700776 handlePackageUpdateLocked(packageName);
777 }
778 }
779 }
780
781 @Override
782 public void onPackageRemoved(String packageName, int uid) {
783 synchronized (mLock) {
784 final int userId = getChangingUserId();
785 final S service = peekServiceForUserLocked(userId);
786 if (service != null) {
787 final ComponentName componentName = service.getServiceComponentName();
788 if (componentName != null) {
789 if (packageName.equals(componentName.getPackageName())) {
790 handleActiveServiceRemoved(userId);
791 }
792 }
793 }
794 }
795 }
796
797 @Override
798 public boolean onHandleForceStop(Intent intent, String[] packages,
799 int uid, boolean doit) {
800 synchronized (mLock) {
Felipe Leme73e65ba2019-03-13 10:57:09 -0700801 final String activePackageName = getActiveServicePackageNameLocked();
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700802 for (String pkg : packages) {
803 if (pkg.equals(activePackageName)) {
804 if (!doit) {
805 return true;
806 }
807 removeCachedServiceLocked(getChangingUserId());
808 } else {
809 handlePackageUpdateLocked(pkg);
810 }
811 }
812 }
813 return false;
814 }
815
816 private void handleActiveServiceRemoved(@UserIdInt int userId) {
Felipe Leme73e65ba2019-03-13 10:57:09 -0700817 synchronized (mLock) {
818 removeCachedServiceLocked(userId);
819 }
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700820 final String serviceSettingsProperty = getServiceSettingsProperty();
821 if (serviceSettingsProperty != null) {
822 Settings.Secure.putStringForUser(getContext().getContentResolver(),
823 serviceSettingsProperty, null, userId);
824 }
825 }
826
Felipe Leme73e65ba2019-03-13 10:57:09 -0700827 private String getActiveServicePackageNameLocked() {
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700828 final int userId = getChangingUserId();
829 final S service = peekServiceForUserLocked(userId);
830 if (service == null) {
831 return null;
832 }
833 final ComponentName serviceComponent = service.getServiceComponentName();
834 if (serviceComponent == null) {
835 return null;
836 }
837 return serviceComponent.getPackageName();
838 }
839
840 @GuardedBy("mLock")
841 private void handlePackageUpdateLocked(String packageName) {
842 visitServicesLocked((s) -> s.handlePackageUpdateLocked(packageName));
843 }
844 };
845
846 // package changes
847 monitor.register(getContext(), null, UserHandle.ALL, true);
848 }
849
850 /**
851 * Visitor pattern.
852 *
853 * @param <S> visited class.
854 */
855 public interface Visitor<S> {
856 /**
857 * Visits a service.
858 *
859 * @param service the service to be visited.
860 */
861 void visit(@NonNull S service);
862 }
863
864 private final class SettingsObserver extends ContentObserver {
865 SettingsObserver(Handler handler) {
866 super(handler);
867 ContentResolver resolver = getContext().getContentResolver();
868 final String serviceProperty = getServiceSettingsProperty();
869 if (serviceProperty != null) {
870 resolver.registerContentObserver(Settings.Secure.getUriFor(
871 serviceProperty), false, this, UserHandle.USER_ALL);
872 }
873 resolver.registerContentObserver(Settings.Secure.getUriFor(
874 Settings.Secure.USER_SETUP_COMPLETE), false, this, UserHandle.USER_ALL);
875 registerForExtraSettingsChanges(resolver, this);
876 }
877
878 @Override
879 public void onChange(boolean selfChange, Uri uri, @UserIdInt int userId) {
880 if (verbose) Slog.v(mTag, "onChange(): uri=" + uri + ", userId=" + userId);
881 final String property = uri.getLastPathSegment();
882 if (property.equals(getServiceSettingsProperty())
883 || property.equals(Settings.Secure.USER_SETUP_COMPLETE)) {
884 synchronized (mLock) {
885 updateCachedServiceLocked(userId);
886 }
887 } else {
888 onSettingsChanged(userId, property);
889 }
890 }
891 }
892}