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 
17 package android.content.om;
18 
19 import android.annotation.NonNull;
20 import android.annotation.NonUiContext;
21 import android.annotation.Nullable;
22 import android.annotation.RequiresPermission;
23 import android.annotation.SuppressLint;
24 import android.annotation.SystemApi;
25 import android.annotation.SystemService;
26 import android.compat.Compatibility;
27 import android.compat.annotation.ChangeId;
28 import android.compat.annotation.EnabledSince;
29 import android.content.Context;
30 import android.content.pm.PackageManager;
31 import android.os.Build;
32 import android.os.RemoteException;
33 import android.os.ServiceManager;
34 import android.os.UserHandle;
35 
36 import com.android.internal.content.om.OverlayManagerImpl;
37 
38 import java.io.IOException;
39 import java.util.List;
40 
41 /**
42  * OverlayManager gives apps the ability to create an {@link OverlayManagerTransaction} to
43  * maintain the overlays and list the registered fabricated runtime resources overlays(FRROs).
44  *
45  * <p>OverlayManager returns the list of overlays to the app calling {@link
46  * #getOverlayInfosForTarget(String)}. The app starts an {@link OverlayManagerTransaction} to manage
47  * the overlays. The app can achieve the following by using {@link OverlayManagerTransaction}.
48  *
49  * <ul>
50  *   <li>register overlays
51  *   <li>unregister overlays
52  *   <li>execute multiple operations in one commitment by calling {@link
53  *       #commit(OverlayManagerTransaction)}
54  * </ul>
55  *
56  * @see OverlayManagerTransaction
57  */
58 @SystemService(Context.OVERLAY_SERVICE)
59 public class OverlayManager {
60 
61     private final IOverlayManager mService;
62     private final Context mContext;
63     private final OverlayManagerImpl mOverlayManagerImpl;
64 
65     /**
66      * Pre R a {@link java.lang.SecurityException} would only be thrown by setEnabled APIs (e
67      * .g. {@code #setEnabled(String, boolean, UserHandle)}) for a permission error.
68      * Since R this no longer holds true, and {@link java.lang.SecurityException} can be
69      * thrown for any number of reasons, none of which are exposed to the caller.
70      *
71      * <p>To maintain existing API behavior, if a legacy permission failure or actor enforcement
72      * failure occurs for an app not yet targeting R, coerce it into an {@link
73      * java.lang.IllegalStateException}, which existed in the source prior to R.
74      */
75     @ChangeId
76     @EnabledSince(targetSdkVersion = Build.VERSION_CODES.R)
77     private static final long THROW_SECURITY_EXCEPTIONS = 147340954;
78 
79     /**
80      * Applications can use OverlayManager to create overlays to overlay on itself resources. The
81      * overlay target is itself and the work range is only in caller application.
82      *
83      * <p>In {@link android.content.Context#getSystemService(String)}, it crashes because of {@link
84      * java.lang.NullPointerException} if the parameter is OverlayManager. if the self-targeting is
85      * enabled, the caller application can get the OverlayManager instance to use self-targeting
86      * functionality.
87      *
88      * @hide
89      */
90     @ChangeId
91     @EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
92     public static final long SELF_TARGETING_OVERLAY = 205919743;
93 
94     /**
95      * Creates a new instance.
96      *
97      * Updates OverlayManager state; gets information about installed overlay packages.
98      * <p>Users of this API must be actors of any overlays they desire to change the state of.
99      *
100      * <p>An actor is a package responsible for managing the state of overlays targeting
101      * overlayables that specify the actor. For example, an actor may enable or disable an overlay
102      * or otherwise change its state.
103      *
104      * <p>Actors are specified as part of the overlayable definition.
105      *
106      * <pre>{@code
107      * <overlayable name="OverlayableResourcesName" actor="overlay://namespace/actorName">
108      * }</pre></p>
109      *
110      * <p>Actors are defined through {@code com.android.server.SystemConfig}. Only system packages
111      * can be used. The namespace "android" is reserved for use by AOSP and any "android"
112      * definitions must have an implementation on device that fulfill their intended functionality.
113      *
114      * <pre>{@code
115      * <named-actor
116      *     namespace="namespace"
117      *     name="actorName"
118      *     package="com.example.pkg"
119      *     />
120      * }</pre></p>
121      *
122      * <p>An actor can manipulate a particular overlay if any of the following is true:
123      * <ul>
124      * <li>its UID is {@link android.os.Process#ROOT_UID}, {@link android.os.Process#SYSTEM_UID}
125      * </li>
126      * <li>it is the target of the overlay package</li>
127      * <li>it has the CHANGE_OVERLAY_PACKAGES permission and the target does not specify an actor
128      * </li>
129      * <li>it is the actor specified by the overlayable</li>
130      * </ul></p>
131      *
132      * @param context The current context in which to operate.
133      * @param service The backing system service.
134      *
135      * @hide
136      */
137     @SuppressLint("ReferencesHidden")
OverlayManager(@onNull Context context, @Nullable IOverlayManager service)138     public OverlayManager(@NonNull Context context, @Nullable IOverlayManager service) {
139         mContext = context;
140         mService = service;
141         mOverlayManagerImpl = new OverlayManagerImpl(context);
142     }
143 
144     /** @hide */
145     @SuppressLint("ReferencesHidden")
OverlayManager(@onNull Context context)146     public OverlayManager(@NonNull Context context) {
147         this(context, IOverlayManager.Stub.asInterface(
148             ServiceManager.getService(Context.OVERLAY_SERVICE)));
149     }
150 
151     /**
152      * Request that an overlay package is enabled and any other overlay packages with the same
153      * target package and category are disabled.
154      *
155      * If a set of overlay packages share the same category, single call to this method is
156      * equivalent to multiple calls to {@code #setEnabled(String, boolean, UserHandle)}.
157      *
158      * The caller must pass the actor requirements specified in the class comment.
159      *
160      * @param packageName the name of the overlay package to enable.
161      * @param user The user for which to change the overlay.
162      *
163      * @throws SecurityException when caller is not allowed to enable {@param packageName}
164      * @throws IllegalStateException when enabling fails otherwise
165      *
166      * @hide
167      */
168     @SystemApi
169     @RequiresPermission(anyOf = {
170             "android.permission.INTERACT_ACROSS_USERS",
171             "android.permission.INTERACT_ACROSS_USERS_FULL"
172     })
setEnabledExclusiveInCategory(@onNull final String packageName, @NonNull UserHandle user)173     public void setEnabledExclusiveInCategory(@NonNull final String packageName,
174             @NonNull UserHandle user) throws SecurityException, IllegalStateException {
175         try {
176             if (!mService.setEnabledExclusiveInCategory(packageName, user.getIdentifier())) {
177                 throw new IllegalStateException("setEnabledExclusiveInCategory failed");
178             }
179         } catch (SecurityException e) {
180             rethrowSecurityException(e);
181         } catch (RemoteException e) {
182             throw e.rethrowFromSystemServer();
183         }
184     }
185 
186     /**
187      * Request that an overlay package is enabled or disabled.
188      *
189      * While {@link #setEnabledExclusiveInCategory(String, UserHandle)} doesn't support disabling
190      * every overlay in a category, this method allows you to disable everything.
191      *
192      * The caller must pass the actor requirements specified in the class comment.
193      *
194      * @param packageName the name of the overlay package to enable.
195      * @param enable {@code false} if the overlay should be turned off.
196      * @param user The user for which to change the overlay.
197      *
198      * @throws SecurityException when caller is not allowed to enable/disable {@param packageName}
199      * @throws IllegalStateException when enabling/disabling fails otherwise
200      *
201      * @hide
202      */
203     @SystemApi
204     @RequiresPermission(anyOf = {
205             "android.permission.INTERACT_ACROSS_USERS",
206             "android.permission.INTERACT_ACROSS_USERS_FULL"
207     })
setEnabled(@onNull final String packageName, final boolean enable, @NonNull UserHandle user)208     public void setEnabled(@NonNull final String packageName, final boolean enable,
209             @NonNull UserHandle user) throws SecurityException, IllegalStateException {
210         try {
211             if (!mService.setEnabled(packageName, enable, user.getIdentifier())) {
212                 throw new IllegalStateException("setEnabled failed");
213             }
214         } catch (SecurityException e) {
215             rethrowSecurityException(e);
216         } catch (RemoteException e) {
217             throw e.rethrowFromSystemServer();
218         }
219     }
220 
221     /**
222      * Returns information about the overlay with the given package name for
223      * the specified user.
224      *
225      * @param packageName The name of the package.
226      * @param userHandle The user to get the OverlayInfos for.
227      * @return An OverlayInfo object; if no overlays exist with the
228      *         requested package name, null is returned.
229      *
230      * @hide
231      */
232     @SystemApi
233     @Nullable
getOverlayInfo(@onNull final String packageName, @NonNull final UserHandle userHandle)234     public OverlayInfo getOverlayInfo(@NonNull final String packageName,
235             @NonNull final UserHandle userHandle) {
236         try {
237             return mService.getOverlayInfo(packageName, userHandle.getIdentifier());
238         } catch (RemoteException e) {
239             throw e.rethrowFromSystemServer();
240         }
241     }
242 
243     /**
244      * Returns information about the overlay represented by the identifier for the specified user.
245      *
246      * @param overlay the identifier representing the overlay
247      * @param userHandle the user of which to get overlay state info
248      * @return the overlay info or null if the overlay cannot be found
249      *
250      * @hide
251      */
252     @Nullable
getOverlayInfo(@onNull final OverlayIdentifier overlay, @NonNull final UserHandle userHandle)253     public OverlayInfo getOverlayInfo(@NonNull final OverlayIdentifier overlay,
254             @NonNull final UserHandle userHandle) {
255         try {
256             return mService.getOverlayInfoByIdentifier(overlay, userHandle.getIdentifier());
257         } catch (RemoteException e) {
258             throw e.rethrowFromSystemServer();
259         }
260     }
261 
262     /**
263      * Returns information about all overlays for the given target package for
264      * the specified user. The returned list is ordered according to the
265      * overlay priority with the highest priority at the end of the list.
266      *
267      * @param targetPackageName The name of the target package.
268      * @param user The user to get the OverlayInfos for.
269      * @return A list of OverlayInfo objects; if no overlays exist for the
270      *         requested package, an empty list is returned.
271      *
272      * @hide
273      */
274     @SystemApi
275     @RequiresPermission(anyOf = {
276             "android.permission.INTERACT_ACROSS_USERS",
277             "android.permission.INTERACT_ACROSS_USERS_FULL"
278     })
279     @NonNull
getOverlayInfosForTarget(@onNull final String targetPackageName, @NonNull UserHandle user)280     public List<OverlayInfo> getOverlayInfosForTarget(@NonNull final String targetPackageName,
281             @NonNull UserHandle user) {
282         try {
283             return mService.getOverlayInfosForTarget(targetPackageName, user.getIdentifier());
284         } catch (RemoteException e) {
285             throw e.rethrowFromSystemServer();
286         }
287     }
288 
289     /**
290      * Clear part of the overlay manager's internal cache of PackageInfo
291      * objects. Only intended for testing.
292      *
293      * @param targetPackageName The name of the target package.
294      * @param user The user to get the OverlayInfos for.
295      *
296      * @hide
297      */
298     @RequiresPermission(anyOf = {
299             "android.permission.INTERACT_ACROSS_USERS",
300     })
301     @NonNull
invalidateCachesForOverlay(@onNull final String targetPackageName, @NonNull UserHandle user)302     public void invalidateCachesForOverlay(@NonNull final String targetPackageName,
303             @NonNull UserHandle user) {
304         try {
305             mService.invalidateCachesForOverlay(targetPackageName, user.getIdentifier());
306         } catch (RemoteException e) {
307             throw e.rethrowFromSystemServer();
308         }
309     }
310 
311     /**
312      * Perform a series of requests related to overlay packages. This is an
313      * atomic operation: either all requests were performed successfully and
314      * the changes were propagated to the rest of the system, or at least one
315      * request could not be performed successfully and nothing is changed and
316      * nothing is propagated to the rest of the system.
317      *
318      * @see OverlayManagerTransaction
319      *
320      * @param transaction the series of overlay related requests to perform
321      * @throws Exception if not all the requests could be successfully and
322      *         atomically executed
323      *
324      * @hide
325      */
commitToSystemServer(@onNull final OverlayManagerTransaction transaction)326     private void commitToSystemServer(@NonNull final OverlayManagerTransaction transaction) {
327         try {
328             mService.commit(transaction);
329         } catch (RemoteException e) {
330             throw e.rethrowFromSystemServer();
331         }
332     }
333 
334     /**
335      * Commit the overlay manager transaction.
336      *
337      * <p>Applications can register overlays and unregister the registered overlays in an atomic
338      * operation via {@link OverlayManagerTransaction}.
339      *
340      * @see OverlayManagerTransaction
341      *
342      * @param transaction the series of overlay related requests to perform
343      * @throws Exception if not all the requests could be successfully
344      */
commit(@onNull final OverlayManagerTransaction transaction)345     public void commit(@NonNull final OverlayManagerTransaction transaction) {
346         if (transaction.isSelfTargeting()
347                 || mService == null
348                 || mService.asBinder() == null) {
349             try {
350                 commitSelfTarget(transaction);
351             } catch (PackageManager.NameNotFoundException | IOException e) {
352                 throw new RuntimeException(e);
353             }
354             return;
355         }
356 
357         commitToSystemServer(transaction);
358     }
359 
360     /**
361      * Starting on R, actor enforcement and app visibility changes introduce additional failure
362      * cases, but the SecurityException thrown with these checks is unexpected for existing
363      * consumers of the API.
364      *
365      * The only prior case it would be thrown is with a permission failure, but the calling
366      * application would be able to verify that themselves, and so they may choose to ignore
367      * catching SecurityException when calling these APIs.
368      *
369      * For R, this no longer holds true, and SecurityExceptions can be thrown for any number of
370      * reasons, none of which are exposed to the caller. So for consumers targeting below R,
371      * transform these SecurityExceptions into IllegalStateExceptions, which are a little more
372      * expected to be thrown by the setEnabled APIs.
373      *
374      * This will mask the prior permission exception if it applies, but it's assumed that apps
375      * wouldn't call the APIs without the permission on prior versions, and so it's safe to ignore.
376      */
rethrowSecurityException(SecurityException e)377     private void rethrowSecurityException(SecurityException e) {
378         if (!Compatibility.isChangeEnabled(THROW_SECURITY_EXCEPTIONS)) {
379             throw new IllegalStateException(e);
380         } else {
381             throw e;
382         }
383     }
384 
385     /**
386      * Commit the self-targeting transaction to register or unregister overlays.
387      *
388      * <p>Applications can request OverlayManager to register overlays and unregister the registered
389      * overlays via {@link OverlayManagerTransaction}.
390      *
391      * @throws IOException if there is a file operation error.
392      * @throws PackageManager.NameNotFoundException if the package name is not found.
393      * @hide
394      */
395     @NonUiContext
commitSelfTarget(@onNull final OverlayManagerTransaction transaction)396     void commitSelfTarget(@NonNull final OverlayManagerTransaction transaction)
397             throws PackageManager.NameNotFoundException, IOException {
398         synchronized (mOverlayManagerImpl) {
399             mOverlayManagerImpl.commit(transaction);
400         }
401     }
402 
403     /**
404      * Get the related information of overlays for {@code targetPackageName}.
405      *
406      * @param targetPackageName the target package name
407      * @return a list of overlay information
408      */
409     @NonNull
410     @NonUiContext
getOverlayInfosForTarget(@onNull final String targetPackageName)411     public List<OverlayInfo> getOverlayInfosForTarget(@NonNull final String targetPackageName) {
412         synchronized (mOverlayManagerImpl) {
413             return mOverlayManagerImpl.getOverlayInfosForTarget(targetPackageName);
414         }
415     }
416 }
417