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