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         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 master 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 master'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