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