1 /* 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 */ 16 package com.android.server.infra; 17 18 import android.annotation.CallSuper; 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.UserIdInt; 22 import android.app.AppGlobals; 23 import android.content.ComponentName; 24 import android.content.Context; 25 import android.content.pm.PackageItemInfo; 26 import android.content.pm.PackageManager.NameNotFoundException; 27 import android.content.pm.ServiceInfo; 28 import android.graphics.drawable.Drawable; 29 import android.os.Process; 30 import android.os.RemoteException; 31 import android.os.UserManager; 32 import android.provider.Settings; 33 import android.text.TextUtils; 34 import android.util.Slog; 35 36 import com.android.internal.annotations.GuardedBy; 37 38 import java.io.PrintWriter; 39 40 /** 41 * Companion for {@link AbstractMasterSystemService}, it's the base class for the "real" service 42 * implementation. 43 * 44 * @param <M> "main" service class. 45 * @param <S> "real" service class. 46 * 47 * @hide 48 */ 49 public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSystemService<S, M>, 50 M extends AbstractMasterSystemService<M, S>> { 51 52 protected final @UserIdInt int mUserId; 53 protected final Object mLock; 54 protected final String mTag = getClass().getSimpleName(); 55 56 protected final M mMaster; 57 58 /** 59 * Whether service was disabled for user due to {@link UserManager} restrictions. 60 */ 61 @GuardedBy("mLock") 62 private boolean mDisabled; 63 64 /** 65 * Caches whether the setup completed for the current user. 66 */ 67 @GuardedBy("mLock") 68 private boolean mSetupComplete; 69 70 @GuardedBy("mLock") 71 private ServiceInfo mServiceInfo; 72 AbstractPerUserSystemService(@onNull M master, @NonNull Object lock, @UserIdInt int userId)73 protected AbstractPerUserSystemService(@NonNull M master, @NonNull Object lock, 74 @UserIdInt int userId) { 75 mMaster = master; 76 mLock = lock; 77 mUserId = userId; 78 updateIsSetupComplete(userId); 79 } 80 81 /** Updates whether setup is complete for current user */ updateIsSetupComplete(@serIdInt int userId)82 private void updateIsSetupComplete(@UserIdInt int userId) { 83 final String setupComplete = Settings.Secure.getStringForUser( 84 getContext().getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, userId); 85 mSetupComplete = "1".equals(setupComplete); 86 } 87 88 /** 89 * Creates a new {@link ServiceInfo} for the given service name. 90 * 91 * <p><b>MUST</b> be overridden by subclasses that bind to an 92 * {@link com.android.internal.infra.AbstractRemoteService}. 93 * 94 * @throws NameNotFoundException if the service does not exist. 95 * @throws SecurityException if the service does not have the proper permissions to be bound to. 96 * @throws UnsupportedOperationException if subclass binds to a remote service but does not 97 * overrides it. 98 * 99 * @return new {@link ServiceInfo}, 100 */ newServiceInfoLocked( @uppressWarnings"unused") @onNull ComponentName serviceComponent)101 protected @NonNull ServiceInfo newServiceInfoLocked( 102 @SuppressWarnings("unused") @NonNull ComponentName serviceComponent) 103 throws NameNotFoundException { 104 throw new UnsupportedOperationException("not overridden"); 105 } 106 107 /** 108 * Callback called when an app has been updated. 109 * 110 * @param packageName package of the app being updated. 111 */ handlePackageUpdateLocked(@onNull String packageName)112 protected void handlePackageUpdateLocked(@NonNull String packageName) { 113 } 114 115 /** 116 * Gets whether the service is enabled and ready. 117 */ 118 @GuardedBy("mLock") isEnabledLocked()119 protected boolean isEnabledLocked() { 120 return mSetupComplete && mServiceInfo != null && !mDisabled; 121 } 122 123 /** 124 * Gets whether the service is disabled by {@link UserManager} restrictions. 125 */ isDisabledByUserRestrictionsLocked()126 protected final boolean isDisabledByUserRestrictionsLocked() { 127 return mDisabled; 128 } 129 130 /** 131 * Updates the state of this service. 132 * 133 * <p>Typically called when the service {@link Settings} property or {@link UserManager} 134 * restriction changed, which includes the initial creation of the service. 135 * 136 * <p>Subclasses can extend this method to provide extra initialization, like clearing up 137 * previous state. 138 * 139 * @param disabled whether the service is disabled (due to {@link UserManager} restrictions). 140 * 141 * @return whether the disabled state changed. 142 */ 143 @GuardedBy("mLock") 144 @CallSuper updateLocked(boolean disabled)145 protected boolean updateLocked(boolean disabled) { 146 147 final boolean wasEnabled = isEnabledLocked(); 148 if (mMaster.verbose) { 149 Slog.v(mTag, "updateLocked(u=" + mUserId + "): wasEnabled=" + wasEnabled 150 + ", mSetupComplete=" + mSetupComplete 151 + ", disabled=" + disabled + ", mDisabled=" + mDisabled); 152 } 153 154 updateIsSetupComplete(mUserId); 155 mDisabled = disabled; 156 157 updateServiceInfoLocked(); 158 return wasEnabled != isEnabledLocked(); 159 } 160 161 /** 162 * Updates the internal reference to the service info, and returns the service's component. 163 */ updateServiceInfoLocked()164 protected final ComponentName updateServiceInfoLocked() { 165 ComponentName serviceComponent = null; 166 if (mMaster.mServiceNameResolver != null) { 167 ServiceInfo serviceInfo = null; 168 final String componentName = getComponentNameLocked(); 169 if (!TextUtils.isEmpty(componentName)) { 170 try { 171 serviceComponent = ComponentName.unflattenFromString(componentName); 172 serviceInfo = AppGlobals.getPackageManager().getServiceInfo(serviceComponent, 173 0, mUserId); 174 if (serviceInfo == null) { 175 Slog.e(mTag, "Bad service name: " + componentName); 176 } 177 } catch (RuntimeException | RemoteException e) { 178 Slog.e(mTag, "Error getting service info for '" + componentName + "': " + e); 179 serviceInfo = null; 180 } 181 } 182 try { 183 if (serviceInfo != null) { 184 mServiceInfo = newServiceInfoLocked(serviceComponent); 185 if (mMaster.debug) { 186 Slog.d(mTag, "Set component for user " + mUserId + " as " 187 + serviceComponent + " and info as " + mServiceInfo); 188 } 189 } else { 190 mServiceInfo = null; 191 if (mMaster.debug) { 192 Slog.d(mTag, "Reset component for user " + mUserId + ":" + componentName); 193 } 194 } 195 } catch (Exception e) { 196 Slog.e(mTag, "Bad ServiceInfo for '" + componentName + "': " + e); 197 mServiceInfo = null; 198 } 199 } 200 return serviceComponent; 201 } 202 203 /** 204 * Gets the user associated with this service. 205 */ getUserId()206 public final @UserIdInt int getUserId() { 207 return mUserId; 208 } 209 210 /** 211 * Gets the main service. 212 */ getMaster()213 public final M getMaster() { 214 return mMaster; 215 } 216 217 /** 218 * Gets this UID of the remote service this service binds to, or {@code -1} if the service is 219 * disabled. 220 */ 221 @GuardedBy("mLock") getServiceUidLocked()222 protected final int getServiceUidLocked() { 223 if (mServiceInfo == null) { 224 if (mMaster.verbose) Slog.v(mTag, "getServiceUidLocked(): no mServiceInfo"); 225 return Process.INVALID_UID; 226 } 227 return mServiceInfo.applicationInfo.uid; 228 } 229 230 /** 231 * Gets the current name of the service, which is either the default service or the 232 * {@link AbstractMasterSystemService#setTemporaryService(int, String, int) temporary one}. 233 */ getComponentNameLocked()234 protected final @Nullable String getComponentNameLocked() { 235 return mMaster.mServiceNameResolver.getServiceName(mUserId); 236 } 237 238 /** 239 * Checks whether the current service for the user was temporarily set. 240 */ isTemporaryServiceSetLocked()241 public final boolean isTemporaryServiceSetLocked() { 242 return mMaster.mServiceNameResolver.isTemporary(mUserId); 243 } 244 245 /** 246 * Resets the temporary service implementation to the default component. 247 */ resetTemporaryServiceLocked()248 protected final void resetTemporaryServiceLocked() { 249 mMaster.mServiceNameResolver.resetTemporaryService(mUserId); 250 } 251 252 /** 253 * Gets the {@link ServiceInfo} of the remote service this service binds to, or {@code null} 254 * if the service is disabled. 255 */ 256 @Nullable getServiceInfo()257 public final ServiceInfo getServiceInfo() { 258 return mServiceInfo; 259 } 260 261 /** 262 * Gets the {@link ComponentName} of the remote service this service binds to, or {@code null} 263 * if the service is disabled. 264 */ 265 @Nullable getServiceComponentName()266 public final ComponentName getServiceComponentName() { 267 synchronized (mLock) { 268 return mServiceInfo == null ? null : mServiceInfo.getComponentName(); 269 } 270 } 271 /** 272 * Gets the name of the of the app this service binds to, or {@code null} if the service is 273 * disabled. 274 */ 275 @Nullable getServicePackageName()276 public final String getServicePackageName() { 277 final ComponentName serviceComponent = getServiceComponentName(); 278 return serviceComponent == null ? null : serviceComponent.getPackageName(); 279 } 280 281 /** 282 * Gets the user-visibile name of the service this service binds to, or {@code null} if the 283 * service is disabled. 284 */ 285 @Nullable 286 @GuardedBy("mLock") getServiceLabelLocked()287 public final CharSequence getServiceLabelLocked() { 288 return mServiceInfo == null ? null : mServiceInfo.loadSafeLabel( 289 getContext().getPackageManager(), 0 /* do not ellipsize */, 290 PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE | PackageItemInfo.SAFE_LABEL_FLAG_TRIM); 291 } 292 293 /** 294 * Gets the icon the service this service binds to, or {@code null} if the service is disabled. 295 */ 296 @Nullable 297 @GuardedBy("mLock") getServiceIconLocked()298 public final Drawable getServiceIconLocked() { 299 return mServiceInfo == null ? null 300 : mServiceInfo.loadIcon(getContext().getPackageManager()); 301 } 302 303 /** 304 * Removes the service from the main service's cache. 305 */ removeSelfFromCacheLocked()306 protected final void removeSelfFromCacheLocked() { 307 mMaster.removeCachedServiceLocked(mUserId); 308 } 309 310 /** 311 * Whether the service should log debug statements. 312 */ 313 //TODO(b/117779333): consider using constants for these guards isDebug()314 public final boolean isDebug() { 315 return mMaster.debug; 316 } 317 318 /** 319 * Whether the service should log verbose statements. 320 */ 321 //TODO(b/117779333): consider using constants for these guards isVerbose()322 public final boolean isVerbose() { 323 return mMaster.verbose; 324 } 325 326 /** 327 * Gets the target SDK level of the service this service binds to, 328 * or {@code 0} if the service is disabled. 329 */ getTargedSdkLocked()330 public final int getTargedSdkLocked() { 331 return mServiceInfo == null ? 0 : mServiceInfo.applicationInfo.targetSdkVersion; 332 } 333 334 /** 335 * Gets whether the device already finished setup. 336 */ isSetupCompletedLocked()337 protected final boolean isSetupCompletedLocked() { 338 return mSetupComplete; 339 } 340 341 /** 342 * Gets the context associated with this service. 343 */ getContext()344 protected final Context getContext() { 345 return mMaster.getContext(); 346 } 347 348 // TODO(b/117779333): support proto 349 @GuardedBy("mLock") dumpLocked(@onNull String prefix, @NonNull PrintWriter pw)350 protected void dumpLocked(@NonNull String prefix, @NonNull PrintWriter pw) { 351 pw.print(prefix); pw.print("User: "); pw.println(mUserId); 352 if (mServiceInfo != null) { 353 pw.print(prefix); pw.print("Service Label: "); pw.println(getServiceLabelLocked()); 354 pw.print(prefix); pw.print("Target SDK: "); pw.println(getTargedSdkLocked()); 355 } 356 if (mMaster.mServiceNameResolver != null) { 357 pw.print(prefix); pw.print("Name resolver: "); 358 mMaster.mServiceNameResolver.dumpShort(pw, mUserId); pw.println(); 359 } 360 pw.print(prefix); pw.print("Disabled by UserManager: "); pw.println(mDisabled); 361 pw.print(prefix); pw.print("Setup complete: "); pw.println(mSetupComplete); 362 if (mServiceInfo != null) { 363 pw.print(prefix); pw.print("Service UID: "); 364 pw.println(mServiceInfo.applicationInfo.uid); 365 } 366 pw.println(); 367 } 368 } 369