blob: 259527a5f217304ad1b65a584a0d6c5aa994bc2b [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. */
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -070082 public static final int PACKAGE_UPDATE_POLICY_NO_REFRESH = 0x00000001;
Robert Berry835123d2019-03-18 16:33:42 -040083
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 */
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -070090 public static final int PACKAGE_UPDATE_POLICY_REFRESH_LAZY = 0x00000002;
Robert Berry835123d2019-03-18 16:33:42 -040091
92 /**
93 * On a package update, removes and recreates any existing per-user services in the cache.
94 */
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -070095 public static final int PACKAGE_UPDATE_POLICY_REFRESH_EAGER = 0x00000004;
Robert Berry835123d2019-03-18 16:33:42 -040096
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -070097 /** On a package restart, does not refresh the per-user service in the cache. */
98 public static final int PACKAGE_RESTART_POLICY_NO_REFRESH = 0x00000010;
99
100 /**
101 * On a package restart, removes any existing per-user services in the cache.
102 *
103 * <p>This does not immediately recreate these services. It is assumed they will be recreated
104 * for the next user request.
105 */
106 public static final int PACKAGE_RESTART_POLICY_REFRESH_LAZY = 0x00000020;
107
108 /**
109 * On a package restart, removes and recreates any existing per-user services in the cache.
110 */
111 public static final int PACKAGE_RESTART_POLICY_REFRESH_EAGER = 0x00000040;
112
113 @IntDef(flag = true, prefix = { "PACKAGE_" }, value = {
Robert Berry835123d2019-03-18 16:33:42 -0400114 PACKAGE_UPDATE_POLICY_NO_REFRESH,
115 PACKAGE_UPDATE_POLICY_REFRESH_LAZY,
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700116 PACKAGE_UPDATE_POLICY_REFRESH_EAGER,
117 PACKAGE_RESTART_POLICY_NO_REFRESH,
118 PACKAGE_RESTART_POLICY_REFRESH_LAZY,
119 PACKAGE_RESTART_POLICY_REFRESH_EAGER
Robert Berry835123d2019-03-18 16:33:42 -0400120 })
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700121
Robert Berry835123d2019-03-18 16:33:42 -0400122 @Retention(RetentionPolicy.SOURCE)
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700123 public @interface ServicePackagePolicyFlags {}
Robert Berry835123d2019-03-18 16:33:42 -0400124
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700125 /**
126 * Log tag
127 */
128 protected final String mTag = getClass().getSimpleName();
129
130 /**
131 * Lock used to synchronize access to internal state; should be acquired before calling a
132 * method whose name ends with {@code locked}.
133 */
134 protected final Object mLock = new Object();
135
136 /**
Felipe Lemec28711c2018-12-20 11:17:02 -0800137 * Object used to define the name of the service component used to create
138 * {@link com.android.internal.infra.AbstractRemoteService} instances.
139 */
140 @Nullable
141 protected final ServiceNameResolver mServiceNameResolver;
142
143 /**
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700144 * Whether the service should log debug statements.
145 */
Felipe Lemec28711c2018-12-20 11:17:02 -0800146 //TODO(b/117779333): consider using constants for these guards
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700147 public boolean verbose = false;
148
149 /**
150 * Whether the service should log verbose statements.
151 */
Felipe Lemec28711c2018-12-20 11:17:02 -0800152 //TODO(b/117779333): consider using constants for these guards
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700153 public boolean debug = false;
154
155 /**
Felipe Leme5933efb2018-11-29 16:08:49 -0800156 * Whether the service is allowed to bind to an instant-app.
157 */
158 @GuardedBy("mLock")
159 protected boolean mAllowInstantService;
160
161 /**
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700162 * Users disabled due to {@link UserManager} restrictions, or {@code null} if the service cannot
163 * be disabled through {@link UserManager}.
164 */
165 @GuardedBy("mLock")
166 @Nullable
Felipe Leme91ddeca2019-01-24 18:01:58 -0800167 private final SparseBooleanArray mDisabledByUserRestriction;
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700168
169 /**
170 * Cache of services per user id.
171 */
172 @GuardedBy("mLock")
173 private final SparseArray<S> mServicesCache = new SparseArray<>();
174
175 /**
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700176 * Value that determines whether the per-user service should be removed from the cache when its
177 * apk is updated or restarted.
Felipe Leme73e65ba2019-03-13 10:57:09 -0700178 */
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700179 private final @ServicePackagePolicyFlags int mServicePackagePolicyFlags;
Felipe Leme73e65ba2019-03-13 10:57:09 -0700180
181 /**
Felipe Leme2f288432019-03-21 13:57:45 -0700182 * Name of the service packages whose APK are being updated, keyed by user id.
Felipe Leme73e65ba2019-03-13 10:57:09 -0700183 */
184 @GuardedBy("mLock")
Felipe Leme2f288432019-03-21 13:57:45 -0700185 private SparseArray<String> mUpdatingPackageNames;
Felipe Leme73e65ba2019-03-13 10:57:09 -0700186
187 /**
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700188 * Default constructor.
189 *
Felipe Leme73e65ba2019-03-13 10:57:09 -0700190 * <p>When using this constructor, the {@link AbstractPerUserSystemService} is removed from
191 * the cache (and re-added) when the service package is updated.
192 *
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700193 * @param context system context.
Felipe Lemec28711c2018-12-20 11:17:02 -0800194 * @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.
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700197 * @param disallowProperty when not {@code null}, defines a {@link UserManager} restriction that
Felipe Lemec0ac60b2019-02-25 09:17:16 -0800198 * disables the service. <b>NOTE: </b> you'll also need to add it to
199 * {@code UserRestrictionsUtils.USER_RESTRICTIONS}.
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700200 */
201 protected AbstractMasterSystemService(@NonNull Context context,
Felipe Lemec28711c2018-12-20 11:17:02 -0800202 @Nullable ServiceNameResolver serviceNameResolver,
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700203 @Nullable String disallowProperty) {
Felipe Leme73e65ba2019-03-13 10:57:09 -0700204 this(context, serviceNameResolver, disallowProperty,
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700205 PACKAGE_UPDATE_POLICY_REFRESH_LAZY | PACKAGE_RESTART_POLICY_REFRESH_LAZY);
Felipe Leme73e65ba2019-03-13 10:57:09 -0700206 }
207
208 /**
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700209 * Full Constructor.
Felipe Leme73e65ba2019-03-13 10:57:09 -0700210 *
211 * @param context system context.
212 * @param serviceNameResolver resolver for
213 * {@link com.android.internal.infra.AbstractRemoteService} instances, or
214 * {@code null} when the service doesn't bind to remote services.
215 * @param disallowProperty when not {@code null}, defines a {@link UserManager} restriction that
216 * disables the service. <b>NOTE: </b> you'll also need to add it to
217 * {@code UserRestrictionsUtils.USER_RESTRICTIONS}.
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700218 * @param servicePackagePolicyFlags a combination of
219 * {@link #PACKAGE_UPDATE_POLICY_NO_REFRESH},
220 * {@link #PACKAGE_UPDATE_POLICY_REFRESH_LAZY},
221 * {@link #PACKAGE_UPDATE_POLICY_REFRESH_EAGER},
222 * {@link #PACKAGE_RESTART_POLICY_NO_REFRESH},
223 * {@link #PACKAGE_RESTART_POLICY_REFRESH_LAZY} or
224 * {@link #PACKAGE_RESTART_POLICY_REFRESH_EAGER}
Felipe Leme73e65ba2019-03-13 10:57:09 -0700225 */
226 protected AbstractMasterSystemService(@NonNull Context context,
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700227 @Nullable ServiceNameResolver serviceNameResolver, @Nullable String disallowProperty,
228 @ServicePackagePolicyFlags int servicePackagePolicyFlags) {
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700229 super(context);
230
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700231 final int updatePolicyMask = PACKAGE_UPDATE_POLICY_NO_REFRESH
232 | PACKAGE_UPDATE_POLICY_REFRESH_LAZY | PACKAGE_UPDATE_POLICY_REFRESH_EAGER;
233 if ((servicePackagePolicyFlags & updatePolicyMask) == 0) {
234 // If the package update policy is not set, add the default flag
235 servicePackagePolicyFlags |= PACKAGE_UPDATE_POLICY_REFRESH_LAZY;
236 }
237 final int restartPolicyMask = PACKAGE_RESTART_POLICY_NO_REFRESH
238 | PACKAGE_RESTART_POLICY_REFRESH_LAZY | PACKAGE_RESTART_POLICY_REFRESH_EAGER;
239 if ((servicePackagePolicyFlags & restartPolicyMask) == 0) {
240 // If the package restart policy is not set, add the default flag
241 servicePackagePolicyFlags |= PACKAGE_RESTART_POLICY_REFRESH_LAZY;
242 }
243 mServicePackagePolicyFlags = servicePackagePolicyFlags;
Felipe Leme73e65ba2019-03-13 10:57:09 -0700244
Felipe Lemec28711c2018-12-20 11:17:02 -0800245 mServiceNameResolver = serviceNameResolver;
246 if (mServiceNameResolver != null) {
Felipe Leme9bee9442019-03-27 13:40:40 -0700247 mServiceNameResolver.setOnTemporaryServiceNameChangedCallback(
248 (u, s, t) -> onServiceNameChanged(u, s, t));
Felipe Lemec28711c2018-12-20 11:17:02 -0800249
250 }
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700251 if (disallowProperty == null) {
Felipe Leme91ddeca2019-01-24 18:01:58 -0800252 mDisabledByUserRestriction = null;
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700253 } else {
Felipe Leme91ddeca2019-01-24 18:01:58 -0800254 mDisabledByUserRestriction = new SparseBooleanArray();
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700255 // Hookup with UserManager to disable service when necessary.
256 final UserManager um = context.getSystemService(UserManager.class);
257 final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
258 final List<UserInfo> users = um.getUsers();
259 for (int i = 0; i < users.size(); i++) {
260 final int userId = users.get(i).id;
261 final boolean disabled = umi.getUserRestriction(userId, disallowProperty);
262 if (disabled) {
Felipe Leme91ddeca2019-01-24 18:01:58 -0800263 Slog.i(mTag, "Disabling by restrictions user " + userId);
264 mDisabledByUserRestriction.put(userId, disabled);
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700265 }
266 }
267 umi.addUserRestrictionsListener((userId, newRestrictions, prevRestrictions) -> {
268 final boolean disabledNow =
269 newRestrictions.getBoolean(disallowProperty, false);
270 synchronized (mLock) {
Felipe Leme91ddeca2019-01-24 18:01:58 -0800271 final boolean disabledBefore = mDisabledByUserRestriction.get(userId);
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700272 if (disabledBefore == disabledNow) {
273 // Nothing changed, do nothing.
274 if (debug) {
275 Slog.d(mTag, "Restriction did not change for user " + userId);
276 return;
277 }
278 }
279 Slog.i(mTag, "Updating for user " + userId + ": disabled=" + disabledNow);
Felipe Leme91ddeca2019-01-24 18:01:58 -0800280 mDisabledByUserRestriction.put(userId, disabledNow);
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700281 updateCachedServiceLocked(userId, disabledNow);
282 }
283 });
284 }
285 startTrackingPackageChanges();
286 }
287
288 @Override // from SystemService
289 public void onBootPhase(int phase) {
290 if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
291 new SettingsObserver(BackgroundThread.getHandler());
292 }
293 }
294
295 @Override // from SystemService
296 public void onUnlockUser(int userId) {
297 synchronized (mLock) {
298 updateCachedServiceLocked(userId);
299 }
300 }
301
302 @Override // from SystemService
303 public void onCleanupUser(int userId) {
304 synchronized (mLock) {
305 removeCachedServiceLocked(userId);
306 }
307 }
308
309 /**
Felipe Leme5933efb2018-11-29 16:08:49 -0800310 * Gets whether the service is allowed to bind to an instant-app.
311 *
312 * <p>Typically called by {@code ShellCommand} during CTS tests.
313 *
314 * @throws SecurityException if caller is not allowed to manage this service's settings.
315 */
316 public final boolean getAllowInstantService() {
317 enforceCallingPermissionForManagement();
318 synchronized (mLock) {
319 return mAllowInstantService;
320 }
321 }
322
323 /**
Felipe Leme50b33dc2018-12-20 16:01:39 -0800324 * Checks whether the service is allowed to bind to an instant-app.
325 *
326 * <p>Typically called by subclasses when creating {@link AbstractRemoteService} instances.
327 *
328 * <p><b>NOTE: </b>must not be called by {@code ShellCommand} as it does not check for
329 * permission.
330 */
331 public final boolean isBindInstantServiceAllowed() {
332 synchronized (mLock) {
333 return mAllowInstantService;
334 }
335 }
336
337 /**
Felipe Leme5933efb2018-11-29 16:08:49 -0800338 * Sets whether the service is allowed to bind to an instant-app.
339 *
340 * <p>Typically called by {@code ShellCommand} during CTS tests.
341 *
342 * @throws SecurityException if caller is not allowed to manage this service's settings.
343 */
344 public final void setAllowInstantService(boolean mode) {
345 Slog.i(mTag, "setAllowInstantService(): " + mode);
346 enforceCallingPermissionForManagement();
347 synchronized (mLock) {
348 mAllowInstantService = mode;
349 }
350 }
351
352 /**
Felipe Leme0486d202018-12-04 09:47:39 -0800353 * Temporarily sets the service implementation.
Felipe Leme658c8e42018-11-30 12:49:45 -0800354 *
355 * <p>Typically used by Shell command and/or CTS tests.
356 *
357 * @param componentName name of the new component
358 * @param durationMs how long the change will be valid (the service will be automatically reset
359 * to the default component after this timeout expires).
360 * @throws SecurityException if caller is not allowed to manage this service's settings.
361 * @throws IllegalArgumentException if value of {@code durationMs} is higher than
362 * {@link #getMaximumTemporaryServiceDurationMs()}.
363 */
364 public final void setTemporaryService(@UserIdInt int userId, @NonNull String componentName,
365 int durationMs) {
366 Slog.i(mTag, "setTemporaryService(" + userId + ") to " + componentName + " for "
367 + durationMs + "ms");
368 enforceCallingPermissionForManagement();
369
370 Preconditions.checkNotNull(componentName);
371 final int maxDurationMs = getMaximumTemporaryServiceDurationMs();
372 if (durationMs > maxDurationMs) {
373 throw new IllegalArgumentException(
374 "Max duration is " + maxDurationMs + " (called with " + durationMs + ")");
375 }
376
377 synchronized (mLock) {
Felipe Leme18a9a4a2019-01-08 15:53:42 -0800378 final S oldService = peekServiceForUserLocked(userId);
379 if (oldService != null) {
380 oldService.removeSelfFromCacheLocked();
Felipe Leme658c8e42018-11-30 12:49:45 -0800381 }
Felipe Leme18a9a4a2019-01-08 15:53:42 -0800382 mServiceNameResolver.setTemporaryService(userId, componentName, durationMs);
Felipe Leme658c8e42018-11-30 12:49:45 -0800383 }
384 }
385
386 /**
Felipe Leme567df6a2019-02-05 15:00:05 -0800387 * Sets whether the default service should be used.
388 *
389 * <p>Typically used during CTS tests to make sure only the default service doesn't interfere
390 * with the test results.
391 *
392 * @throws SecurityException if caller is not allowed to manage this service's settings.
Felipe Lemea70dd8c2019-03-19 10:21:28 -0700393 *
394 * @return whether the enabled state changed.
Felipe Leme567df6a2019-02-05 15:00:05 -0800395 */
Felipe Lemea70dd8c2019-03-19 10:21:28 -0700396 public final boolean setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
Felipe Leme567df6a2019-02-05 15:00:05 -0800397 Slog.i(mTag, "setDefaultServiceEnabled() for userId " + userId + ": " + enabled);
398 enforceCallingPermissionForManagement();
399
400 synchronized (mLock) {
Felipe Lemea70dd8c2019-03-19 10:21:28 -0700401 final boolean changed = mServiceNameResolver.setDefaultServiceEnabled(userId, enabled);
402 if (!changed) {
403 if (verbose) {
404 Slog.v(mTag, "setDefaultServiceEnabled(" + userId + "): already " + enabled);
405 }
406 return false;
407 }
408
Felipe Leme567df6a2019-02-05 15:00:05 -0800409 final S oldService = peekServiceForUserLocked(userId);
410 if (oldService != null) {
411 oldService.removeSelfFromCacheLocked();
412 }
Felipe Leme567df6a2019-02-05 15:00:05 -0800413
414 // Must update the service on cache so its initialization code is triggered
415 updateCachedServiceLocked(userId);
416 }
Felipe Lemea70dd8c2019-03-19 10:21:28 -0700417 return true;
Felipe Leme567df6a2019-02-05 15:00:05 -0800418 }
419
420 /**
421 * Checks whether the default service should be used.
422 *
423 * <p>Typically used during CTS tests to make sure only the default service doesn't interfere
424 * with the test results.
425 *
426 * @throws SecurityException if caller is not allowed to manage this service's settings.
427 */
428 public final boolean isDefaultServiceEnabled(@UserIdInt int userId) {
429 enforceCallingPermissionForManagement();
430
431 synchronized (mLock) {
432 return mServiceNameResolver.isDefaultServiceEnabled(userId);
433 }
434 }
435
436 /**
Felipe Leme658c8e42018-11-30 12:49:45 -0800437 * Gets the maximum time the service implementation can be changed.
438 *
439 * @throws UnsupportedOperationException if subclass doesn't override it.
440 */
441 protected int getMaximumTemporaryServiceDurationMs() {
442 throw new UnsupportedOperationException("Not implemented by " + getClass());
443 }
444
445 /**
446 * Resets the temporary service implementation to the default component.
447 *
448 * <p>Typically used by Shell command and/or CTS tests.
449 *
450 * @throws SecurityException if caller is not allowed to manage this service's settings.
451 */
452 public final void resetTemporaryService(@UserIdInt int userId) {
453 Slog.i(mTag, "resetTemporaryService(): " + userId);
454 enforceCallingPermissionForManagement();
455 synchronized (mLock) {
456 final S service = getServiceForUserLocked(userId);
457 if (service != null) {
458 service.resetTemporaryServiceLocked();
459 }
460 }
461 }
462
463 /**
Felipe Leme5933efb2018-11-29 16:08:49 -0800464 * Asserts that the caller has permissions to manage this service.
465 *
466 * <p>Typically called by {@code ShellCommand} implementations.
467 *
468 * @throws UnsupportedOperationException if subclass doesn't override it.
469 * @throws SecurityException if caller is not allowed to manage this service's settings.
470 */
471 protected void enforceCallingPermissionForManagement() {
472 throw new UnsupportedOperationException("Not implemented by " + getClass());
473 }
474
475 /**
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700476 * Creates a new service that will be added to the cache.
477 *
478 * @param resolvedUserId the resolved user id for the service.
479 * @param disabled whether the service is currently disabled (due to {@link UserManager}
480 * restrictions).
481 *
482 * @return a new instance.
483 */
Felipe Leme50b33dc2018-12-20 16:01:39 -0800484 @Nullable
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700485 protected abstract S newServiceLocked(@UserIdInt int resolvedUserId, boolean disabled);
486
487 /**
488 * Register the service for extra Settings changes (i.e., other than
489 * {@link android.provider.Settings.Secure#USER_SETUP_COMPLETE} or
490 * {@link #getServiceSettingsProperty()}, which are automatically handled).
491 *
492 * <p> Example:
493 *
494 * <pre><code>
495 * resolver.registerContentObserver(Settings.Global.getUriFor(
496 * Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES), false, observer,
497 * UserHandle.USER_ALL);
498 * </code></pre>
499 *
500 * <p><b>NOTE: </p>it doesn't need to register for
501 * {@link android.provider.Settings.Secure#USER_SETUP_COMPLETE} or
502 * {@link #getServiceSettingsProperty()}.
503 *
504 */
505 @SuppressWarnings("unused")
506 protected void registerForExtraSettingsChanges(@NonNull ContentResolver resolver,
507 @NonNull ContentObserver observer) {
508 }
509
510 /**
511 * Callback for Settings changes that were registered though
512 * {@link #registerForExtraSettingsChanges(ContentResolver, ContentObserver)}.
513 *
514 * @param userId user associated with the change
515 * @param property Settings property changed.
516 */
517 protected void onSettingsChanged(@UserIdInt int userId, @NonNull String property) {
518 }
519
520 /**
521 * Gets the service instance for an user, creating an instance if not present in the cache.
522 */
523 @GuardedBy("mLock")
524 @NonNull
525 protected S getServiceForUserLocked(@UserIdInt int userId) {
526 final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
527 Binder.getCallingUid(), userId, false, false, null, null);
528 S service = mServicesCache.get(resolvedUserId);
529 if (service == null) {
530 final boolean disabled = isDisabledLocked(userId);
531 service = newServiceLocked(resolvedUserId, disabled);
532 if (!disabled) {
533 onServiceEnabledLocked(service, resolvedUserId);
534 }
535 mServicesCache.put(userId, service);
536 }
537 return service;
538 }
539
540 /**
541 * Gets the <b>existing</b> service instance for a user, returning {@code null} if not already
542 * present in the cache.
543 */
544 @GuardedBy("mLock")
545 @Nullable
Felipe Leme7ed7b2c2018-11-14 17:47:15 -0800546 protected S peekServiceForUserLocked(@UserIdInt int userId) {
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700547 final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
548 Binder.getCallingUid(), userId, false, false, null, null);
549 return mServicesCache.get(resolvedUserId);
550 }
551
552 /**
553 * Updates a cached service for a given user.
554 */
555 @GuardedBy("mLock")
Felipe Leme7ed7b2c2018-11-14 17:47:15 -0800556 protected void updateCachedServiceLocked(@UserIdInt int userId) {
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700557 updateCachedServiceLocked(userId, isDisabledLocked(userId));
558 }
559
560 /**
561 * Checks whether the service is disabled (through {@link UserManager} restrictions) for the
562 * given user.
563 */
Felipe Leme7ed7b2c2018-11-14 17:47:15 -0800564 protected boolean isDisabledLocked(@UserIdInt int userId) {
Felipe Leme91ddeca2019-01-24 18:01:58 -0800565 return mDisabledByUserRestriction == null ? false : mDisabledByUserRestriction.get(userId);
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700566 }
567
568 /**
569 * Updates a cached service for a given user.
570 *
571 * @param userId user handle.
572 * @param disabled whether the user is disabled.
573 * @return service for the user.
574 */
575 @GuardedBy("mLock")
Felipe Leme7ed7b2c2018-11-14 17:47:15 -0800576 protected S updateCachedServiceLocked(@UserIdInt int userId, boolean disabled) {
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700577 final S service = getServiceForUserLocked(userId);
578 if (service != null) {
579 service.updateLocked(disabled);
580 if (!service.isEnabledLocked()) {
581 removeCachedServiceLocked(userId);
582 } else {
583 onServiceEnabledLocked(service, userId);
584 }
585 }
586 return service;
587 }
588
589 /**
590 * Gets the Settings property that defines the name of the component name used to bind this
591 * service to an external service, or {@code null} when the service is not defined by such
592 * property (for example, if it's a system service defined by framework resources).
593 */
594 @Nullable
595 protected String getServiceSettingsProperty() {
596 return null;
597 }
598
599 /**
600 * Callback called after a new service was added to the cache, or an existing service that was
601 * previously disabled gets enabled.
602 *
603 * <p>By default doesn't do anything, but can be overridden by subclasses.
604 */
605 @SuppressWarnings("unused")
Felipe Leme7ed7b2c2018-11-14 17:47:15 -0800606 protected void onServiceEnabledLocked(@NonNull S service, @UserIdInt int userId) {
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700607 }
608
609 /**
610 * Removes a cached service for a given user.
611 *
Felipe Leme50b33dc2018-12-20 16:01:39 -0800612 * @return the removed service.
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700613 */
614 @GuardedBy("mLock")
615 @NonNull
Felipe Leme50b33dc2018-12-20 16:01:39 -0800616 protected final S removeCachedServiceLocked(@UserIdInt int userId) {
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700617 final S service = peekServiceForUserLocked(userId);
618 if (service != null) {
619 mServicesCache.delete(userId);
Felipe Leme7ed7b2c2018-11-14 17:47:15 -0800620 onServiceRemoved(service, userId);
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700621 }
622 return service;
623 }
624
625 /**
Felipe Leme2f288432019-03-21 13:57:45 -0700626 * Called before the package that provides the service for the given user is being updated.
627 */
628 protected void onServicePackageUpdatingLocked(@UserIdInt int userId) {
629 if (verbose) Slog.v(mTag, "onServicePackageUpdatingLocked(" + userId + ")");
630 }
631
632 /**
633 * Called after the package that provides the service for the given user is being updated.
634 */
635 protected void onServicePackageUpdatedLocked(@UserIdInt int userId) {
636 if (verbose) Slog.v(mTag, "onServicePackageUpdated(" + userId + ")");
637 }
638
639 /**
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700640 * Called after the package data that provides the service for the given user is cleared.
641 */
642 protected void onServicePackageDataClearedLocked(@UserIdInt int userId) {
643 if (verbose) Slog.v(mTag, "onServicePackageDataCleared(" + userId + ")");
644 }
645
646 /**
647 * Called after the package that provides the service for the given user is restarted.
648 */
649 protected void onServicePackageRestartedLocked(@UserIdInt int userId) {
650 if (verbose) Slog.v(mTag, "onServicePackageRestarted(" + userId + ")");
651 }
652
653 /**
Felipe Leme7ed7b2c2018-11-14 17:47:15 -0800654 * Called after the service is removed from the cache.
655 */
656 @SuppressWarnings("unused")
657 protected void onServiceRemoved(@NonNull S service, @UserIdInt int userId) {
658 }
659
660 /**
Felipe Leme9bee9442019-03-27 13:40:40 -0700661 * Called when the service name changed (typically when using temporary services).
662 *
663 * <p>By default, it calls {@link #updateCachedServiceLocked(int)}; subclasses must either call
664 * that same method, or {@code super.onServiceNameChanged()}.
665 *
666 * @param userId user handle.
667 * @param serviceName the new service name.
668 * @param isTemporary whether the new service is temporary.
669 */
670 protected void onServiceNameChanged(@UserIdInt int userId, @Nullable String serviceName,
671 boolean isTemporary) {
672 synchronized (mLock) {
673 updateCachedServiceLocked(userId);
674 }
675 }
676
677 /**
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700678 * Visits all services in the cache.
679 */
680 @GuardedBy("mLock")
681 protected void visitServicesLocked(@NonNull Visitor<S> visitor) {
682 final int size = mServicesCache.size();
683 for (int i = 0; i < size; i++) {
684 visitor.visit(mServicesCache.valueAt(i));
685 }
686 }
687
688 /**
689 * Clear the cache by removing all services.
690 */
691 @GuardedBy("mLock")
692 protected void clearCacheLocked() {
693 mServicesCache.clear();
694 }
695
Felipe Lemeafbba9f2019-03-26 14:02:25 -0700696 /**
697 * Asserts that the given package name is owned by the UID making this call.
698 *
699 * @throws SecurityException when it's not...
700 */
701 protected final void assertCalledByPackageOwner(@NonNull String packageName) {
702 Preconditions.checkNotNull(packageName);
703 final int uid = Binder.getCallingUid();
704 final String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
705 if (packages != null) {
706 for (String candidate : packages) {
707 if (packageName.equals(candidate)) return; // Found it
708 }
709 }
710 throw new SecurityException("UID " + uid + " does not own " + packageName);
711 }
712
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700713 // TODO(b/117779333): support proto
714 protected void dumpLocked(@NonNull String prefix, @NonNull PrintWriter pw) {
715 boolean realDebug = debug;
716 boolean realVerbose = verbose;
Felipe Leme18a9a4a2019-01-08 15:53:42 -0800717 final String prefix2 = " ";
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700718
719 try {
720 // Temporarily turn on full logging;
721 debug = verbose = true;
722 final int size = mServicesCache.size();
723 pw.print(prefix); pw.print("Debug: "); pw.print(realDebug);
724 pw.print(" Verbose: "); pw.println(realVerbose);
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700725 pw.print("Package policy flags: "); pw.println(mServicePackagePolicyFlags);
Felipe Leme2f288432019-03-21 13:57:45 -0700726 if (mUpdatingPackageNames != null) {
727 pw.print("Packages being updated: "); pw.println(mUpdatingPackageNames);
728 }
Felipe Lemec28711c2018-12-20 11:17:02 -0800729 if (mServiceNameResolver != null) {
730 pw.print(prefix); pw.print("Name resolver: ");
731 mServiceNameResolver.dumpShort(pw); pw.println();
Felipe Leme18a9a4a2019-01-08 15:53:42 -0800732 final UserManager um = getContext().getSystemService(UserManager.class);
733 final List<UserInfo> users = um.getUsers();
734 for (int i = 0; i < users.size(); i++) {
735 final int userId = users.get(i).id;
736 pw.print(prefix2); pw.print(userId); pw.print(": ");
737 mServiceNameResolver.dumpShort(pw, userId); pw.println();
738 }
Felipe Lemec28711c2018-12-20 11:17:02 -0800739 }
Felipe Leme91ddeca2019-01-24 18:01:58 -0800740 pw.print(prefix); pw.print("Users disabled by restriction: ");
741 pw.println(mDisabledByUserRestriction);
Felipe Leme5933efb2018-11-29 16:08:49 -0800742 pw.print(prefix); pw.print("Allow instant service: "); pw.println(mAllowInstantService);
Felipe Leme0486d202018-12-04 09:47:39 -0800743 final String settingsProperty = getServiceSettingsProperty();
744 if (settingsProperty != null) {
745 pw.print(prefix); pw.print("Settings property: "); pw.println(settingsProperty);
746 }
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700747 pw.print(prefix); pw.print("Cached services: ");
748 if (size == 0) {
749 pw.println("none");
750 } else {
751 pw.println(size);
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700752 for (int i = 0; i < size; i++) {
753 pw.print(prefix); pw.print("Service at "); pw.print(i); pw.println(": ");
754 final S service = mServicesCache.valueAt(i);
755 service.dumpLocked(prefix2, pw);
756 pw.println();
757 }
758 }
759 } finally {
760 debug = realDebug;
761 verbose = realVerbose;
762 }
763 }
764
765 private void startTrackingPackageChanges() {
Felipe Leme73e65ba2019-03-13 10:57:09 -0700766 final PackageMonitor monitor = new PackageMonitor() {
767
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700768 @Override
Felipe Leme2f288432019-03-21 13:57:45 -0700769 public void onPackageUpdateStarted(@NonNull String packageName, int uid) {
770 if (verbose) Slog.v(mTag, "onPackageUpdateStarted(): " + packageName);
771 final String activePackageName = getActiveServicePackageNameLocked();
772 if (!packageName.equals(activePackageName)) return;
773
774 final int userId = getChangingUserId();
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700775 synchronized (mLock) {
Felipe Leme2f288432019-03-21 13:57:45 -0700776 if (mUpdatingPackageNames == null) {
777 mUpdatingPackageNames = new SparseArray<String>(mServicesCache.size());
778 }
779 mUpdatingPackageNames.put(userId, packageName);
780 onServicePackageUpdatingLocked(userId);
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700781 if ((mServicePackagePolicyFlags & PACKAGE_UPDATE_POLICY_NO_REFRESH) != 0) {
782 if (debug) {
783 Slog.d(mTag, "Holding service for user " + userId + " while package "
784 + activePackageName + " is being updated");
785 }
786 } else {
Felipe Leme2f288432019-03-21 13:57:45 -0700787 if (debug) {
Robert Berry835123d2019-03-18 16:33:42 -0400788 Slog.d(mTag, "Removing service for user " + userId
789 + " because package " + activePackageName
790 + " is being updated");
Felipe Leme2f288432019-03-21 13:57:45 -0700791 }
792 removeCachedServiceLocked(userId);
Robert Berry835123d2019-03-18 16:33:42 -0400793
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700794 if ((mServicePackagePolicyFlags & PACKAGE_UPDATE_POLICY_REFRESH_EAGER)
795 != 0) {
Robert Berry835123d2019-03-18 16:33:42 -0400796 if (debug) {
797 Slog.d(mTag, "Eagerly recreating service for user "
798 + userId);
799 }
800 getServiceForUserLocked(userId);
801 }
Felipe Leme73e65ba2019-03-13 10:57:09 -0700802 }
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700803 }
804 }
805
806 @Override
Felipe Leme2f288432019-03-21 13:57:45 -0700807 public void onPackageUpdateFinished(@NonNull String packageName, int uid) {
808 if (verbose) Slog.v(mTag, "onPackageUpdateFinished(): " + packageName);
809 final int userId = getChangingUserId();
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700810 synchronized (mLock) {
Felipe Leme2f288432019-03-21 13:57:45 -0700811 final String activePackageName = mUpdatingPackageNames == null ? null
812 : mUpdatingPackageNames.get(userId);
813 if (packageName.equals(activePackageName)) {
814 if (mUpdatingPackageNames != null) {
815 mUpdatingPackageNames.remove(userId);
816 if (mUpdatingPackageNames.size() == 0) {
817 mUpdatingPackageNames = null;
818 }
819 }
820 onServicePackageUpdatedLocked(userId);
821 } else {
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700822 handlePackageUpdateLocked(packageName);
823 }
824 }
825 }
826
827 @Override
828 public void onPackageRemoved(String packageName, int uid) {
829 synchronized (mLock) {
830 final int userId = getChangingUserId();
831 final S service = peekServiceForUserLocked(userId);
832 if (service != null) {
833 final ComponentName componentName = service.getServiceComponentName();
834 if (componentName != null) {
835 if (packageName.equals(componentName.getPackageName())) {
836 handleActiveServiceRemoved(userId);
837 }
838 }
839 }
840 }
841 }
842
843 @Override
844 public boolean onHandleForceStop(Intent intent, String[] packages,
845 int uid, boolean doit) {
846 synchronized (mLock) {
Felipe Leme73e65ba2019-03-13 10:57:09 -0700847 final String activePackageName = getActiveServicePackageNameLocked();
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700848 for (String pkg : packages) {
849 if (pkg.equals(activePackageName)) {
850 if (!doit) {
851 return true;
852 }
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700853 final String action = intent.getAction();
854 final int userId = getChangingUserId();
855 if (Intent.ACTION_PACKAGE_RESTARTED.equals(action)) {
856 handleActiveServiceRestartedLocked(activePackageName, userId);
857 } else {
858 removeCachedServiceLocked(userId);
859 }
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700860 } else {
861 handlePackageUpdateLocked(pkg);
862 }
863 }
864 }
865 return false;
866 }
867
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700868 @Override
869 public void onPackageDataCleared(String packageName, int uid) {
870 if (verbose) Slog.v(mTag, "onPackageDataCleared(): " + packageName);
871 final int userId = getChangingUserId();
872 synchronized (mLock) {
873 final S service = peekServiceForUserLocked(userId);
874 if (service != null) {
875 final ComponentName componentName = service.getServiceComponentName();
876 if (componentName != null) {
877 if (packageName.equals(componentName.getPackageName())) {
878 onServicePackageDataClearedLocked(userId);
879 }
880 }
881 }
882 }
883 }
884
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700885 private void handleActiveServiceRemoved(@UserIdInt int userId) {
Felipe Leme73e65ba2019-03-13 10:57:09 -0700886 synchronized (mLock) {
887 removeCachedServiceLocked(userId);
888 }
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700889 final String serviceSettingsProperty = getServiceSettingsProperty();
890 if (serviceSettingsProperty != null) {
891 Settings.Secure.putStringForUser(getContext().getContentResolver(),
892 serviceSettingsProperty, null, userId);
893 }
894 }
895
Mehdi Alizadeh23e044d2019-08-23 14:44:50 -0700896 private void handleActiveServiceRestartedLocked(String activePackageName,
897 @UserIdInt int userId) {
898 if ((mServicePackagePolicyFlags & PACKAGE_RESTART_POLICY_NO_REFRESH) != 0) {
899 if (debug) {
900 Slog.d(mTag, "Holding service for user " + userId + " while package "
901 + activePackageName + " is being restarted");
902 }
903 } else {
904 if (debug) {
905 Slog.d(mTag, "Removing service for user " + userId
906 + " because package " + activePackageName
907 + " is being restarted");
908 }
909 removeCachedServiceLocked(userId);
910
911 if ((mServicePackagePolicyFlags & PACKAGE_RESTART_POLICY_REFRESH_EAGER) != 0) {
912 if (debug) {
913 Slog.d(mTag, "Eagerly recreating service for user " + userId);
914 }
915 getServiceForUserLocked(userId);
916 }
917 }
918 onServicePackageRestartedLocked(userId);
919 }
920
Felipe Leme73e65ba2019-03-13 10:57:09 -0700921 private String getActiveServicePackageNameLocked() {
Felipe Lemeea95a6d2018-10-15 10:45:01 -0700922 final int userId = getChangingUserId();
923 final S service = peekServiceForUserLocked(userId);
924 if (service == null) {
925 return null;
926 }
927 final ComponentName serviceComponent = service.getServiceComponentName();
928 if (serviceComponent == null) {
929 return null;
930 }
931 return serviceComponent.getPackageName();
932 }
933
934 @GuardedBy("mLock")
935 private void handlePackageUpdateLocked(String packageName) {
936 visitServicesLocked((s) -> s.handlePackageUpdateLocked(packageName));
937 }
938 };
939
940 // package changes
941 monitor.register(getContext(), null, UserHandle.ALL, true);
942 }
943
944 /**
945 * Visitor pattern.
946 *
947 * @param <S> visited class.
948 */
949 public interface Visitor<S> {
950 /**
951 * Visits a service.
952 *
953 * @param service the service to be visited.
954 */
955 void visit(@NonNull S service);
956 }
957
958 private final class SettingsObserver extends ContentObserver {
959 SettingsObserver(Handler handler) {
960 super(handler);
961 ContentResolver resolver = getContext().getContentResolver();
962 final String serviceProperty = getServiceSettingsProperty();
963 if (serviceProperty != null) {
964 resolver.registerContentObserver(Settings.Secure.getUriFor(
965 serviceProperty), false, this, UserHandle.USER_ALL);
966 }
967 resolver.registerContentObserver(Settings.Secure.getUriFor(
968 Settings.Secure.USER_SETUP_COMPLETE), false, this, UserHandle.USER_ALL);
969 registerForExtraSettingsChanges(resolver, this);
970 }
971
972 @Override
973 public void onChange(boolean selfChange, Uri uri, @UserIdInt int userId) {
974 if (verbose) Slog.v(mTag, "onChange(): uri=" + uri + ", userId=" + userId);
975 final String property = uri.getLastPathSegment();
976 if (property.equals(getServiceSettingsProperty())
977 || property.equals(Settings.Secure.USER_SETUP_COMPLETE)) {
978 synchronized (mLock) {
979 updateCachedServiceLocked(userId);
980 }
981 } else {
982 onSettingsChanged(userId, property);
983 }
984 }
985 }
986}