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 // Update of multi configured mode should always happen in AbstractMasterSystemService 158 // as this class is not aware of the complete list of multiple backends. Since we 159 // should never end up in this state, it is safe to not do anything if we end up here 160 // through a different code path. 161 if (mMaster.debug) { 162 Slog.d(mTag, "Should not end up in updateLocked when " 163 + "isConfiguredInMultipleMode is true"); 164 } 165 } else { 166 updateServiceInfoLocked(); 167 } 168 return wasEnabled != isEnabledLocked(); 169 } 170 171 /** 172 * Updates the internal reference to the service info, and returns the service's component. 173 */ 174 @GuardedBy("mLock") updateServiceInfoLocked()175 protected final ComponentName updateServiceInfoLocked() { 176 ComponentName[] componentNames = updateServiceInfoListLocked(); 177 return componentNames == null || componentNames.length == 0 ? null : componentNames[0]; 178 } 179 180 /** 181 * Updates the internal reference to the service info, and returns the service's component. 182 */ 183 @GuardedBy("mLock") updateServiceInfoListLocked()184 protected final ComponentName[] updateServiceInfoListLocked() { 185 if (mMaster.mServiceNameResolver == null) { 186 return null; 187 } 188 if (!mMaster.mServiceNameResolver.isConfiguredInMultipleMode()) { 189 final String componentName = getComponentNameLocked(); 190 return new ComponentName[] { getServiceComponent(componentName) }; 191 } 192 193 final String[] componentNames = mMaster.mServiceNameResolver.getServiceNameList( 194 mUserId); 195 if (componentNames == null) { 196 return null; 197 } 198 ComponentName[] serviceComponents = new ComponentName[componentNames.length]; 199 for (int i = 0; i < componentNames.length; i++) { 200 serviceComponents[i] = getServiceComponent(componentNames[i]); 201 } 202 return serviceComponents; 203 } 204 getServiceComponent(String componentName)205 private ComponentName getServiceComponent(String componentName) { 206 synchronized (mLock) { 207 ServiceInfo serviceInfo = null; 208 ComponentName serviceComponent = null; 209 if (!TextUtils.isEmpty(componentName)) { 210 try { 211 serviceComponent = ComponentName.unflattenFromString(componentName); 212 serviceInfo = AppGlobals.getPackageManager().getServiceInfo(serviceComponent, 213 0, mUserId); 214 if (serviceInfo == null) { 215 Slog.e(mTag, "Bad service name: " + componentName); 216 } 217 } catch (RuntimeException | RemoteException e) { 218 Slog.e(mTag, "Error getting service info for '" + componentName + "': " + e); 219 serviceInfo = null; 220 } 221 } 222 try { 223 if (serviceInfo != null) { 224 mServiceInfo = newServiceInfoLocked(serviceComponent); 225 if (mMaster.debug) { 226 Slog.d(mTag, "Set component for user " + mUserId + " as " 227 + serviceComponent + " and info as " + mServiceInfo); 228 } 229 } else { 230 mServiceInfo = null; 231 if (mMaster.debug) { 232 Slog.d(mTag, "Reset component for user " + mUserId + ":" + componentName); 233 } 234 } 235 } catch (Exception e) { 236 Slog.e(mTag, "Bad ServiceInfo for '" + componentName + "': " + e); 237 mServiceInfo = null; 238 } 239 return serviceComponent; 240 } 241 } 242 243 /** 244 * Gets the user associated with this service. 245 */ getUserId()246 @UserIdInt public final int getUserId() { 247 return mUserId; 248 } 249 250 /** 251 * Gets the main service. 252 */ getMaster()253 public final M getMaster() { 254 return mMaster; 255 } 256 257 /** 258 * Gets this UID of the remote service this service binds to, or {@code -1} if the service is 259 * disabled. 260 */ 261 @GuardedBy("mLock") getServiceUidLocked()262 protected final int getServiceUidLocked() { 263 if (mServiceInfo == null) { 264 if (mMaster.verbose) Slog.v(mTag, "getServiceUidLocked(): no mServiceInfo"); 265 return Process.INVALID_UID; 266 } 267 return mServiceInfo.applicationInfo.uid; 268 } 269 270 /** 271 * Gets the current name of the service, which is either the default service or the 272 * {@link AbstractMasterSystemService#setTemporaryService(int, String, int) temporary one}. 273 */ 274 @Nullable 275 @GuardedBy("mLock") getComponentNameLocked()276 protected final String getComponentNameLocked() { 277 return mMaster.mServiceNameResolver.getServiceName(mUserId); 278 } 279 280 /** 281 * Gets the current name of the service, which is either the default service or the 282 * {@link AbstractMasterSystemService#setTemporaryService(int, String, int) temporary one}. 283 */ 284 @Nullable 285 @GuardedBy("mLock") getComponentNameForMultipleLocked(String serviceName)286 protected final String getComponentNameForMultipleLocked(String serviceName) { 287 String[] services = mMaster.mServiceNameResolver.getServiceNameList(mUserId); 288 for (int i = 0; i < services.length; i++) { 289 if (serviceName.equals(services[i])) { 290 return services[i]; 291 } 292 } 293 return null; 294 } 295 296 /** 297 * Checks whether the current service for the user was temporarily set. 298 */ 299 @GuardedBy("mLock") isTemporaryServiceSetLocked()300 public final boolean isTemporaryServiceSetLocked() { 301 return mMaster.mServiceNameResolver.isTemporary(mUserId); 302 } 303 304 /** 305 * Resets the temporary service implementation to the default component. 306 */ 307 @GuardedBy("mLock") resetTemporaryServiceLocked()308 protected final void resetTemporaryServiceLocked() { 309 mMaster.mServiceNameResolver.resetTemporaryService(mUserId); 310 } 311 312 /** 313 * Gets the {@link ServiceInfo} of the remote service this service binds to, or {@code null} 314 * if the service is disabled. 315 */ 316 @Nullable getServiceInfo()317 public final ServiceInfo getServiceInfo() { 318 return mServiceInfo; 319 } 320 321 /** 322 * Gets the {@link ComponentName} of the remote service this service binds to, or {@code null} 323 * if the service is disabled. 324 */ 325 @Nullable getServiceComponentName()326 public final ComponentName getServiceComponentName() { 327 synchronized (mLock) { 328 return mServiceInfo == null ? null : mServiceInfo.getComponentName(); 329 } 330 } 331 332 /** 333 * Gets the name of the of the app this service binds to, or {@code null} if the service is 334 * disabled. 335 */ 336 @Nullable getServicePackageName()337 public final String getServicePackageName() { 338 final ComponentName serviceComponent = getServiceComponentName(); 339 return serviceComponent == null ? null : serviceComponent.getPackageName(); 340 } 341 342 /** 343 * Gets the user-visibile name of the service this service binds to, or {@code null} if the 344 * service is disabled. 345 */ 346 @Nullable 347 @GuardedBy("mLock") getServiceLabelLocked()348 public final CharSequence getServiceLabelLocked() { 349 return mServiceInfo == null ? null : mServiceInfo.loadSafeLabel( 350 getContext().getPackageManager(), 0 /* do not ellipsize */, 351 PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE | PackageItemInfo.SAFE_LABEL_FLAG_TRIM); 352 } 353 354 /** 355 * Gets the icon the service this service binds to, or {@code null} if the service is disabled. 356 */ 357 @Nullable 358 @GuardedBy("mLock") getServiceIconLocked()359 public final Drawable getServiceIconLocked() { 360 return mServiceInfo == null ? null 361 : mServiceInfo.loadIcon(getContext().getPackageManager()); 362 } 363 364 /** 365 * Removes the service from the main service's cache. 366 */ removeSelfFromCache()367 protected final void removeSelfFromCache() { 368 synchronized (mMaster.mLock) { 369 mMaster.removeCachedServiceListLocked(mUserId); 370 } 371 } 372 373 /** 374 * Whether the service should log debug statements. 375 */ 376 //TODO(b/117779333): consider using constants for these guards isDebug()377 public final boolean isDebug() { 378 return mMaster.debug; 379 } 380 381 /** 382 * Whether the service should log verbose statements. 383 */ 384 //TODO(b/117779333): consider using constants for these guards isVerbose()385 public final boolean isVerbose() { 386 return mMaster.verbose; 387 } 388 389 /** 390 * Gets the target SDK level of the service this service binds to, 391 * or {@code 0} if the service is disabled. 392 */ 393 @GuardedBy("mLock") getTargedSdkLocked()394 public final int getTargedSdkLocked() { 395 return mServiceInfo == null ? 0 : mServiceInfo.applicationInfo.targetSdkVersion; 396 } 397 398 /** 399 * Gets whether the device already finished setup. 400 */ 401 @GuardedBy("mLock") isSetupCompletedLocked()402 protected final boolean isSetupCompletedLocked() { 403 return mSetupComplete; 404 } 405 406 /** 407 * Gets the context associated with this service. 408 */ getContext()409 protected final Context getContext() { 410 return mMaster.getContext(); 411 } 412 413 // TODO(b/117779333): support proto 414 @GuardedBy("mLock") dumpLocked(@onNull String prefix, @NonNull PrintWriter pw)415 protected void dumpLocked(@NonNull String prefix, @NonNull PrintWriter pw) { 416 pw.print(prefix); 417 pw.print("User: "); 418 pw.println(mUserId); 419 if (mServiceInfo != null) { 420 pw.print(prefix); 421 pw.print("Service Label: "); 422 pw.println(getServiceLabelLocked()); 423 pw.print(prefix); 424 pw.print("Target SDK: "); 425 pw.println(getTargedSdkLocked()); 426 } 427 if (mMaster.mServiceNameResolver != null) { 428 pw.print(prefix); 429 pw.print("Name resolver: "); 430 mMaster.mServiceNameResolver.dumpShort(pw, mUserId); 431 pw.println(); 432 } 433 pw.print(prefix); 434 pw.print("Disabled by UserManager: "); 435 pw.println(mDisabled); 436 pw.print(prefix); 437 pw.print("Setup complete: "); 438 pw.println(mSetupComplete); 439 if (mServiceInfo != null) { 440 pw.print(prefix); 441 pw.print("Service UID: "); 442 pw.println(mServiceInfo.applicationInfo.uid); 443 } 444 pw.println(); 445 } 446 } 447