• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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