• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 com.android.server.pm;
18 
19 import static android.content.Intent.CATEGORY_DEFAULT;
20 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
21 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
22 
23 import static com.android.server.pm.PackageManagerService.DEBUG_BACKUP;
24 import static com.android.server.pm.PackageManagerService.DEBUG_PREFERRED;
25 import static com.android.server.pm.PackageManagerService.TAG;
26 
27 import android.annotation.NonNull;
28 import android.annotation.SpecialUsers.CanBeALL;
29 import android.annotation.UserIdInt;
30 import android.content.ComponentName;
31 import android.content.Intent;
32 import android.content.IntentFilter;
33 import android.content.pm.ActivityInfo;
34 import android.content.pm.PackageManager;
35 import android.content.pm.ResolveInfo;
36 import android.os.Binder;
37 import android.os.Build;
38 import android.os.Process;
39 import android.os.UserHandle;
40 import android.text.TextUtils;
41 import android.util.EventLog;
42 import android.util.Log;
43 import android.util.LogPrinter;
44 import android.util.PrintStreamPrinter;
45 import android.util.Slog;
46 import android.util.SparseBooleanArray;
47 import android.util.Xml;
48 
49 import com.android.internal.util.ArrayUtils;
50 import com.android.modules.utils.TypedXmlPullParser;
51 import com.android.modules.utils.TypedXmlSerializer;
52 import com.android.server.net.NetworkPolicyManagerInternal;
53 import com.android.server.pm.pkg.PackageStateInternal;
54 
55 import org.xmlpull.v1.XmlPullParser;
56 import org.xmlpull.v1.XmlPullParserException;
57 
58 import java.io.ByteArrayInputStream;
59 import java.io.ByteArrayOutputStream;
60 import java.io.IOException;
61 import java.nio.charset.StandardCharsets;
62 import java.util.ArrayList;
63 import java.util.Arrays;
64 import java.util.Iterator;
65 import java.util.List;
66 
67 final class PreferredActivityHelper {
68     // XML tags for backup/restore of various bits of state
69     private static final String TAG_PREFERRED_BACKUP = "pa";
70     private static final String TAG_DEFAULT_APPS = "da";
71 
72     private final PackageManagerService mPm;
73     private final BroadcastHelper mBroadcastHelper;
74 
75     // TODO(b/198166813): remove PMS dependency
PreferredActivityHelper(PackageManagerService pm, BroadcastHelper broadcastHelper)76     PreferredActivityHelper(PackageManagerService pm, BroadcastHelper broadcastHelper) {
77         mPm = pm;
78         mBroadcastHelper = broadcastHelper;
79     }
80 
findPreferredActivityNotLocked(@onNull Computer snapshot, Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, List<ResolveInfo> query, boolean always, boolean removeMatches, boolean debug, @UserIdInt int userId)81     private ResolveInfo findPreferredActivityNotLocked(@NonNull Computer snapshot, Intent intent,
82             String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
83             List<ResolveInfo> query, boolean always, boolean removeMatches, boolean debug,
84             @UserIdInt int userId) {
85         return findPreferredActivityNotLocked(snapshot, intent, resolvedType, flags, query, always,
86                 removeMatches, debug, userId,
87                 UserHandle.getAppId(Binder.getCallingUid()) >= Process.FIRST_APPLICATION_UID);
88     }
89 
90     // TODO: handle preferred activities missing while user has amnesia
91     /** <b>must not hold {@link PackageManagerService.mLock}</b> */
findPreferredActivityNotLocked(@onNull Computer snapshot, Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, List<ResolveInfo> query, boolean always, boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered)92     public ResolveInfo findPreferredActivityNotLocked(@NonNull Computer snapshot,
93             Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
94             List<ResolveInfo> query, boolean always, boolean removeMatches, boolean debug,
95             int userId, boolean queryMayBeFiltered) {
96         if (Thread.holdsLock(mPm.mLock)) {
97             Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
98                     + " is holding mLock", new Throwable());
99         }
100         if (!mPm.mUserManager.exists(userId)) return null;
101 
102         PackageManagerService.FindPreferredActivityBodyResult body =
103                 snapshot.findPreferredActivityInternal(
104                 intent, resolvedType, flags, query, always,
105                 removeMatches, debug, userId, queryMayBeFiltered);
106         if (body.mChanged) {
107             if (DEBUG_PREFERRED) {
108                 Slog.v(TAG, "Preferred activity bookkeeping changed; writing restrictions");
109             }
110             mPm.scheduleWritePackageRestrictions(userId);
111         }
112         if ((DEBUG_PREFERRED || debug) && body.mPreferredResolveInfo == null) {
113             Slog.v(TAG, "No preferred activity to return");
114         }
115         return body.mPreferredResolveInfo;
116     }
117 
118     /** This method takes a specific user id as well as UserHandle.USER_ALL. */
clearPackagePreferredActivities(String packageName, @CanBeALL @UserIdInt int userId)119     public void clearPackagePreferredActivities(String packageName,
120             @CanBeALL @UserIdInt int userId) {
121         final SparseBooleanArray changedUsers = new SparseBooleanArray();
122         synchronized (mPm.mLock) {
123             mPm.clearPackagePreferredActivitiesLPw(packageName, changedUsers, userId);
124         }
125         if (changedUsers.size() > 0) {
126             updateDefaultHomeNotLocked(mPm.snapshotComputer(), changedUsers);
127             mBroadcastHelper.sendPreferredActivityChangedBroadcast(userId);
128             mPm.scheduleWritePackageRestrictions(userId);
129         }
130     }
131 
132     /**
133      * <b>must not hold {@link PackageManagerService.mLock}</b>
134      *
135      * @return Whether the ACTION_PREFERRED_ACTIVITY_CHANGED broadcast has been scheduled.
136      */
updateDefaultHomeNotLocked(@onNull Computer snapshot, @UserIdInt int userId)137     public boolean updateDefaultHomeNotLocked(@NonNull Computer snapshot, @UserIdInt int userId) {
138         if (Thread.holdsLock(mPm.mLock)) {
139             Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
140                     + " is holding mLock", new Throwable());
141         }
142         if (!mPm.isSystemReady()) {
143             // We might get called before system is ready because of package changes etc, but
144             // finding preferred activity depends on settings provider, so we ignore the update
145             // before that.
146             return false;
147         }
148         final Intent intent = snapshot.getHomeIntent();
149         final List<ResolveInfo> resolveInfos = snapshot.queryIntentActivitiesInternal(
150                 intent, null, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId);
151         final ResolveInfo preferredResolveInfo = findPreferredActivityNotLocked(snapshot,
152                 intent, null, 0, resolveInfos, true, false, false, userId);
153         final String packageName = preferredResolveInfo != null
154                 && preferredResolveInfo.activityInfo != null
155                 ? preferredResolveInfo.activityInfo.packageName : null;
156         final String currentPackageName = mPm.getActiveLauncherPackageName(userId);
157         if (TextUtils.equals(currentPackageName, packageName)) {
158             return false;
159         }
160         final String[] callingPackages = snapshot.getPackagesForUid(Binder.getCallingUid());
161         if (callingPackages != null && ArrayUtils.contains(callingPackages,
162                 mPm.mRequiredPermissionControllerPackage)) {
163             // PermissionController manages default home directly.
164             return false;
165         }
166 
167         if (packageName == null) {
168             // Keep the default home package in RoleManager.
169             return false;
170         }
171         return mPm.setActiveLauncherPackage(packageName, userId,
172                 successful -> {
173                     if (successful) {
174                         mBroadcastHelper.sendPreferredActivityChangedBroadcast(userId);
175                     }
176                 });
177     }
178 
179     /**
180      * Variant that takes a {@link WatchedIntentFilter}
181      */
182     public void addPreferredActivity(@NonNull Computer snapshot, WatchedIntentFilter filter,
183             int match, ComponentName[] set, ComponentName activity, boolean always, int userId,
184             String opname, boolean removeExisting) {
185         // writer
186         int callingUid = Binder.getCallingUid();
187         snapshot.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
188                 false /* checkShell */, "add preferred activity");
189         if (mPm.mContext.checkCallingOrSelfPermission(
190                 android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
191                 != PackageManager.PERMISSION_GRANTED) {
192             if (snapshot.getUidTargetSdkVersion(callingUid)
193                     < Build.VERSION_CODES.FROYO) {
194                 Slog.w(TAG, "Ignoring addPreferredActivity() from uid "
195                         + callingUid);
196                 return;
197             }
198             mPm.mContext.enforceCallingOrSelfPermission(
199                     android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
200         }
201         if (filter.countActions() == 0) {
202             Slog.w(TAG, "Cannot set a preferred activity with no filter actions");
203             return;
204         }
205         if (DEBUG_PREFERRED) {
206             Slog.i(TAG, opname + " activity " + activity.flattenToShortString() + " for user "
207                     + userId + ":");
208             filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
209         }
210         synchronized (mPm.mLock) {
211             final PreferredIntentResolver pir = mPm.mSettings.editPreferredActivitiesLPw(userId);
212             final ArrayList<PreferredActivity> existing = pir.findFilters(filter);
213             if (removeExisting && existing != null) {
214                 Settings.removeFilters(pir, filter, existing);
215             }
216             pir.addFilter(mPm.snapshotComputer(),
217                     new PreferredActivity(filter, match, set, activity, always));
218             mPm.scheduleWritePackageRestrictions(userId);
219         }
220         // Re-snapshot after mLock
221         if (!(isHomeFilter(filter) && updateDefaultHomeNotLocked(mPm.snapshotComputer(), userId))) {
222             mBroadcastHelper.sendPreferredActivityChangedBroadcast(userId);
223         }
224     }
225 
226     /**
227      * Variant that takes a {@link WatchedIntentFilter}
228      */
229     public void replacePreferredActivity(@NonNull Computer snapshot, WatchedIntentFilter filter,
230             int match, ComponentName[] set, ComponentName activity, int userId) {
231         if (filter.countActions() != 1) {
232             throw new IllegalArgumentException(
233                     "replacePreferredActivity expects filter to have only 1 action.");
234         }
235         if (filter.countDataAuthorities() != 0
236                 || filter.countDataPaths() != 0
237                 || filter.countDataSchemes() > 1
238                 || filter.countDataTypes() != 0) {
239             throw new IllegalArgumentException(
240                     "replacePreferredActivity expects filter to have no data authorities, "
241                             + "paths, or types; and at most one scheme.");
242         }
243 
244         final int callingUid = Binder.getCallingUid();
245         snapshot.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
246                 false /* checkShell */, "replace preferred activity");
247         if (mPm.mContext.checkCallingOrSelfPermission(
248                 android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
249                 != PackageManager.PERMISSION_GRANTED) {
250             synchronized (mPm.mLock) {
251                 // TODO: Remove lock?
252                 if (mPm.snapshotComputer().getUidTargetSdkVersion(callingUid)
253                         < Build.VERSION_CODES.FROYO) {
254                     Slog.w(TAG, "Ignoring replacePreferredActivity() from uid "
255                             + Binder.getCallingUid());
256                     return;
257                 }
258             }
259             mPm.mContext.enforceCallingOrSelfPermission(
260                     android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
261         }
262 
263         synchronized (mPm.mLock) {
264             final PreferredIntentResolver pir = mPm.mSettings.getPreferredActivities(userId);
265             if (pir != null) {
266                 // Get all of the existing entries that exactly match this filter.
267                 final ArrayList<PreferredActivity> existing = pir.findFilters(filter);
268                 if (existing != null && existing.size() == 1) {
269                     final PreferredActivity cur = existing.get(0);
270                     if (DEBUG_PREFERRED) {
271                         Slog.i(TAG, "Checking replace of preferred:");
272                         filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
273                         if (!cur.mPref.mAlways) {
274                             Slog.i(TAG, "  -- CUR; not mAlways!");
275                         } else {
276                             Slog.i(TAG, "  -- CUR: mMatch=" + cur.mPref.mMatch);
277                             Slog.i(TAG, "  -- CUR: mSet="
278                                     + Arrays.toString(cur.mPref.mSetComponents));
279                             Slog.i(TAG, "  -- CUR: mComponent=" + cur.mPref.mShortComponent);
280                             Slog.i(TAG, "  -- NEW: mMatch="
281                                     + (match & IntentFilter.MATCH_CATEGORY_MASK));
282                             Slog.i(TAG, "  -- CUR: mSet=" + Arrays.toString(set));
283                             Slog.i(TAG, "  -- CUR: mComponent=" + activity.flattenToShortString());
284                         }
285                     }
286                     if (cur.mPref.mAlways && cur.mPref.mComponent.equals(activity)
287                             && cur.mPref.mMatch == (match & IntentFilter.MATCH_CATEGORY_MASK)
288                             && cur.mPref.sameSet(set)) {
289                         // Setting the preferred activity to what it happens to be already
290                         if (DEBUG_PREFERRED) {
291                             Slog.i(TAG, "Replacing with same preferred activity "
292                                     + cur.mPref.mShortComponent + " for user "
293                                     + userId + ":");
294                             filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
295                         }
296                         return;
297                     }
298                 }
299                 if (existing != null) {
300                     Settings.removeFilters(pir, filter, existing);
301                 }
302             }
303         }
304 
305         // Retake a snapshot after editing with lock held
306         addPreferredActivity(mPm.snapshotComputer(), filter, match, set, activity, true, userId,
307                 "Replacing preferred", false);
308     }
309 
310     public void clearPackagePreferredActivities(@NonNull Computer snapshot, String packageName) {
311         final int callingUid = Binder.getCallingUid();
312         if (snapshot.getInstantAppPackageName(callingUid) != null) {
313             return;
314         }
315         final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
316         if (packageState == null || !snapshot.isCallerSameApp(packageName, callingUid)) {
317             if (mPm.mContext.checkCallingOrSelfPermission(
318                     android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
319                     != PackageManager.PERMISSION_GRANTED) {
320                 if (snapshot.getUidTargetSdkVersion(callingUid)
321                         < Build.VERSION_CODES.FROYO) {
322                     Slog.w(TAG, "Ignoring clearPackagePreferredActivities() from uid "
323                             + callingUid);
324                     return;
325                 }
326                 mPm.mContext.enforceCallingOrSelfPermission(
327                         android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
328             }
329         }
330         if (packageState != null && snapshot.shouldFilterApplication(packageState, callingUid,
331                 UserHandle.getUserId(callingUid))) {
332             return;
333         }
334         int callingUserId = UserHandle.getCallingUserId();
335         clearPackagePreferredActivities(packageName, callingUserId);
336     }
337 
338     /** <b>must not hold {@link #PackageManagerService.mLock}</b> */
339     void updateDefaultHomeNotLocked(@NonNull Computer snapshot, SparseBooleanArray userIds) {
340         if (Thread.holdsLock(mPm.mLock)) {
341             Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
342                     + " is holding mLock", new Throwable());
343         }
344         for (int i = userIds.size() - 1; i >= 0; --i) {
345             final int userId = userIds.keyAt(i);
346             updateDefaultHomeNotLocked(snapshot, userId);
347         }
348     }
349 
350     public void setHomeActivity(@NonNull Computer snapshot, ComponentName comp, int userId) {
351         if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
352             return;
353         }
354         ArrayList<ResolveInfo> homeActivities = new ArrayList<>();
355         snapshot.getHomeActivitiesAsUser(homeActivities, userId);
356 
357         boolean found = false;
358 
359         final int size = homeActivities.size();
360         final ComponentName[] set = new ComponentName[size];
361         for (int i = 0; i < size; i++) {
362             final ResolveInfo candidate = homeActivities.get(i);
363             final ActivityInfo info = candidate.activityInfo;
364             final ComponentName activityName = new ComponentName(info.packageName, info.name);
365             set[i] = activityName;
366             if (!found && activityName.equals(comp)) {
367                 found = true;
368             }
369         }
370         if (!found) {
371             throw new IllegalArgumentException("Component " + comp + " cannot be home on user "
372                     + userId);
373         }
374         replacePreferredActivity(snapshot, getHomeFilter(), IntentFilter.MATCH_CATEGORY_EMPTY,
375                 set, comp, userId);
376     }
377 
378     private WatchedIntentFilter getHomeFilter() {
379         WatchedIntentFilter filter = new WatchedIntentFilter(Intent.ACTION_MAIN);
380         filter.addCategory(Intent.CATEGORY_HOME);
381         filter.addCategory(Intent.CATEGORY_DEFAULT);
382         return filter;
383     }
384 
385     /**
386      * Variant that takes a {@link WatchedIntentFilter}
387      */
388     public void addPersistentPreferredActivity(WatchedIntentFilter filter, ComponentName activity,
389             int userId) {
390         int callingUid = Binder.getCallingUid();
391         if (callingUid != Process.SYSTEM_UID) {
392             throw new SecurityException(
393                     "addPersistentPreferredActivity can only be run by the system");
394         }
395         if (!filter.checkDataPathAndSchemeSpecificParts()) {
396             EventLog.writeEvent(0x534e4554, "246749702", callingUid);
397             throw new IllegalArgumentException("Invalid intent data paths or scheme specific parts"
398                     + " in the filter.");
399         }
400         if (filter.countActions() == 0) {
401             Slog.w(TAG, "Cannot set a preferred activity with no filter actions");
402             return;
403         }
404         if (DEBUG_PREFERRED) {
405             Slog.i(TAG, "Adding persistent preferred activity " + activity
406                     + " for user " + userId + ":");
407             filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
408         }
409         synchronized (mPm.mLock) {
410             mPm.mSettings.editPersistentPreferredActivitiesLPw(userId).addFilter(
411                     mPm.snapshotComputer(),
412                     new PersistentPreferredActivity(filter, activity, true));
413             mPm.scheduleWritePackageRestrictions(userId);
414         }
415         if (isHomeFilter(filter)) {
416             updateDefaultHomeNotLocked(mPm.snapshotComputer(), userId);
417         }
418         mBroadcastHelper.sendPreferredActivityChangedBroadcast(userId);
419     }
420 
421     public void clearPackagePersistentPreferredActivities(String packageName, int userId) {
422         int callingUid = Binder.getCallingUid();
423         if (callingUid != Process.SYSTEM_UID) {
424             throw new SecurityException(
425                     "clearPackagePersistentPreferredActivities can only be run by the system");
426         }
427         boolean changed = false;
428         synchronized (mPm.mLock) {
429             changed = mPm.mSettings.clearPackagePersistentPreferredActivities(packageName, userId);
430         }
431         if (changed) {
432             updateDefaultHomeNotLocked(mPm.snapshotComputer(), userId);
433             mBroadcastHelper.sendPreferredActivityChangedBroadcast(userId);
434             mPm.scheduleWritePackageRestrictions(userId);
435         }
436     }
437 
438     public void clearPersistentPreferredActivity(IntentFilter filter, int userId) {
439         int callingUid = Binder.getCallingUid();
440         if (callingUid != Process.SYSTEM_UID) {
441             throw new SecurityException(
442                     "clearPersistentPreferredActivity can only be run by the system");
443         }
444         boolean changed = false;
445         synchronized (mPm.mLock) {
446             changed = mPm.mSettings.clearPersistentPreferredActivity(filter, userId);
447         }
448         if (changed) {
449             updateDefaultHomeNotLocked(mPm.snapshotComputer(), userId);
450             mBroadcastHelper.sendPreferredActivityChangedBroadcast(userId);
451             mPm.scheduleWritePackageRestrictions(userId);
452         }
453     }
454 
455     private boolean isHomeFilter(@NonNull WatchedIntentFilter filter) {
456         return filter.hasAction(Intent.ACTION_MAIN) && filter.hasCategory(Intent.CATEGORY_HOME)
457                 && filter.hasCategory(CATEGORY_DEFAULT);
458     }
459 
460     /**
461      * Common machinery for picking apart a restored XML blob and passing
462      * it to a caller-supplied functor to be applied to the running system.
463      */
464     private void restoreFromXml(TypedXmlPullParser parser, int userId,
465             String expectedStartTag, BlobXmlRestorer functor)
466             throws IOException, XmlPullParserException {
467         int type;
468         while ((type = parser.next()) != XmlPullParser.START_TAG
469                 && type != XmlPullParser.END_DOCUMENT) {
470         }
471         if (type != XmlPullParser.START_TAG) {
472             // oops didn't find a start tag?!
473             if (DEBUG_BACKUP) {
474                 Slog.e(TAG, "Didn't find start tag during restore");
475             }
476             return;
477         }
478         // this is supposed to be TAG_PREFERRED_BACKUP
479         if (!expectedStartTag.equals(parser.getName())) {
480             if (DEBUG_BACKUP) {
481                 Slog.e(TAG, "Found unexpected tag " + parser.getName());
482             }
483             return;
484         }
485 
486         // skip interfering stuff, then we're aligned with the backing implementation
487         while ((type = parser.next()) == XmlPullParser.TEXT) { }
488         functor.apply(parser, userId);
489     }
490 
491     private interface BlobXmlRestorer {
492         void apply(TypedXmlPullParser parser, int userId)
493                 throws IOException, XmlPullParserException;
494     }
495 
496     public byte[] getPreferredActivityBackup(int userId) {
497         if (Binder.getCallingUid() != Process.SYSTEM_UID) {
498             throw new SecurityException("Only the system may call getPreferredActivityBackup()");
499         }
500 
501         ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
502         try {
503             final TypedXmlSerializer serializer = Xml.newFastSerializer();
504             serializer.setOutput(dataStream, StandardCharsets.UTF_8.name());
505             serializer.startDocument(null, true);
506             serializer.startTag(null, TAG_PREFERRED_BACKUP);
507 
508             synchronized (mPm.mLock) {
509                 mPm.mSettings.writePreferredActivitiesLPr(serializer, userId, true);
510             }
511 
512             serializer.endTag(null, TAG_PREFERRED_BACKUP);
513             serializer.endDocument();
514             serializer.flush();
515         } catch (Exception e) {
516             if (DEBUG_BACKUP) {
517                 Slog.e(TAG, "Unable to write preferred activities for backup", e);
518             }
519             return null;
520         }
521 
522         return dataStream.toByteArray();
523     }
524 
525     public void restorePreferredActivities(byte[] backup, int userId) {
526         if (Binder.getCallingUid() != Process.SYSTEM_UID) {
527             throw new SecurityException("Only the system may call restorePreferredActivities()");
528         }
529 
530         try {
531             final TypedXmlPullParser parser = Xml.newFastPullParser();
532             parser.setInput(new ByteArrayInputStream(backup), StandardCharsets.UTF_8.name());
533             restoreFromXml(parser, userId, TAG_PREFERRED_BACKUP,
534                     (readParser, readUserId) -> {
535                         synchronized (mPm.mLock) {
536                             mPm.mSettings.readPreferredActivitiesLPw(readParser, readUserId);
537                         }
538                         updateDefaultHomeNotLocked(mPm.snapshotComputer(), readUserId);
539                     });
540         } catch (Exception e) {
541             if (DEBUG_BACKUP) {
542                 Slog.e(TAG, "Exception restoring preferred activities: " + e.getMessage());
543             }
544         }
545     }
546 
547     /**
548      * Non-Binder method, support for the backup/restore mechanism: write the
549      * default browser (etc) settings in its canonical XML format.  Returns the default
550      * browser XML representation as a byte array, or null if there is none.
551      */
552     public byte[] getDefaultAppsBackup(int userId) {
553         if (Binder.getCallingUid() != Process.SYSTEM_UID) {
554             throw new SecurityException("Only the system may call getDefaultAppsBackup()");
555         }
556 
557         ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
558         try {
559             final TypedXmlSerializer serializer = Xml.newFastSerializer();
560             serializer.setOutput(dataStream, StandardCharsets.UTF_8.name());
561             serializer.startDocument(null, true);
562             serializer.startTag(null, TAG_DEFAULT_APPS);
563 
564             final String defaultBrowser = mPm.getDefaultBrowser(userId);
565             Settings.writeDefaultApps(serializer, defaultBrowser);
566 
567             serializer.endTag(null, TAG_DEFAULT_APPS);
568             serializer.endDocument();
569             serializer.flush();
570         } catch (Exception e) {
571             if (DEBUG_BACKUP) {
572                 Slog.e(TAG, "Unable to write default apps for backup", e);
573             }
574             return null;
575         }
576 
577         return dataStream.toByteArray();
578     }
579 
580     public void restoreDefaultApps(byte[] backup, int userId) {
581         if (Binder.getCallingUid() != Process.SYSTEM_UID) {
582             throw new SecurityException("Only the system may call restoreDefaultApps()");
583         }
584 
585         try {
586             final TypedXmlPullParser parser = Xml.newFastPullParser();
587             parser.setInput(new ByteArrayInputStream(backup), StandardCharsets.UTF_8.name());
588             restoreFromXml(parser, userId, TAG_DEFAULT_APPS,
589                     (parser1, userId1) -> {
590                         final String defaultBrowser = Settings.readDefaultApps(parser1);
591                         if (defaultBrowser != null) {
592                             final PackageStateInternal packageState = mPm.snapshotComputer()
593                                     .getPackageStateInternal(defaultBrowser);
594                             if (packageState != null
595                                     && packageState.getUserStateOrDefault(userId1).isInstalled()) {
596                                 mPm.setDefaultBrowser(defaultBrowser, userId1);
597                             } else {
598                                 synchronized (mPm.mLock) {
599                                     mPm.mSettings.setPendingDefaultBrowserLPw(defaultBrowser,
600                                             userId1);
601                                 }
602                             }
603                         }
604                     });
605         } catch (Exception e) {
606             if (DEBUG_BACKUP) {
607                 Slog.e(TAG, "Exception restoring default apps: " + e.getMessage());
608             }
609         }
610     }
611 
612     public void resetApplicationPreferences(int userId) {
613         mPm.mContext.enforceCallingOrSelfPermission(
614                 android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
615         final long identity = Binder.clearCallingIdentity();
616         // writer
617         try {
618             final SparseBooleanArray changedUsers = new SparseBooleanArray();
619             synchronized (mPm.mLock) {
620                 mPm.clearPackagePreferredActivitiesLPw(null, changedUsers, userId);
621             }
622             if (changedUsers.size() > 0) {
623                 mBroadcastHelper.sendPreferredActivityChangedBroadcast(userId);
624             }
625             synchronized (mPm.mLock) {
626                 mPm.mSettings.applyDefaultPreferredAppsLPw(userId);
627                 mPm.mDomainVerificationManager.clearUser(userId);
628                 mPm.mPermissionManager.resetRuntimePermissionsForUser(userId);
629             }
630             updateDefaultHomeNotLocked(mPm.snapshotComputer(), userId);
631             resetNetworkPolicies(userId);
632             mPm.scheduleWritePackageRestrictions(userId);
633         } finally {
634             Binder.restoreCallingIdentity(identity);
635         }
636     }
637 
638     private void resetNetworkPolicies(int userId) {
639         mPm.mInjector.getLocalService(NetworkPolicyManagerInternal.class).resetUserState(userId);
640     }
641 
642     public int getPreferredActivities(@NonNull Computer snapshot, List<IntentFilter> outFilters,
643             List<ComponentName> outActivities, String packageName) {
644         List<WatchedIntentFilter> temp =
645                 WatchedIntentFilter.toWatchedIntentFilterList(outFilters);
646         int result = getPreferredActivitiesInternal(snapshot, temp, outActivities, packageName);
647         outFilters.clear();
648         for (int i = 0; i < temp.size(); i++) {
649             outFilters.add(temp.get(i).getIntentFilter());
650         }
651         return result;
652     }
653 
654     /**
655      * Variant that takes a {@link WatchedIntentFilter}
656      */
657     private int getPreferredActivitiesInternal(@NonNull Computer snapshot,
658             List<WatchedIntentFilter> outFilters, List<ComponentName> outActivities,
659             String packageName) {
660         final int callingUid = Binder.getCallingUid();
661         if (snapshot.getInstantAppPackageName(callingUid) != null) {
662             return 0;
663         }
664         int num = 0;
665         final int userId = UserHandle.getCallingUserId();
666 
667         PreferredIntentResolver pir = snapshot.getPreferredActivities(userId);
668         if (pir != null) {
669             final Iterator<PreferredActivity> it = pir.filterIterator();
670             while (it.hasNext()) {
671                 final PreferredActivity pa = it.next();
672                 if (pa == null) continue;
673                 final String prefPackageName = pa.mPref.mComponent.getPackageName();
674                 if (packageName == null
675                         || (prefPackageName.equals(packageName) && pa.mPref.mAlways)) {
676                     if (snapshot.shouldFilterApplication(
677                             snapshot.getPackageStateInternal(prefPackageName), callingUid,
678                             userId)) {
679                         continue;
680                     }
681                     if (outFilters != null) {
682                         outFilters.add(new WatchedIntentFilter(pa.getIntentFilter()));
683                     }
684                     if (outActivities != null) {
685                         outActivities.add(pa.mPref.mComponent);
686                     }
687                 }
688             }
689         }
690 
691         return num;
692     }
693 
694     public ResolveInfo findPersistentPreferredActivity(@NonNull Computer snapshot, Intent intent,
695             int userId) {
696         if (!UserHandle.isSameApp(Binder.getCallingUid(), Process.SYSTEM_UID)) {
697             throw new SecurityException(
698                     "findPersistentPreferredActivity can only be run by the system");
699         }
700         if (!mPm.mUserManager.exists(userId)) {
701             return null;
702         }
703         final int callingUid = Binder.getCallingUid();
704         intent = PackageManagerServiceUtils.updateIntentForResolve(intent);
705         final String resolvedType = intent.resolveTypeIfNeeded(mPm.mContext.getContentResolver());
706         final long flags = snapshot.updateFlagsForResolve(
707                 0, userId, callingUid, false /*includeInstantApps*/,
708                 snapshot.isImplicitImageCaptureIntentAndNotSetByDpc(intent, userId, resolvedType,
709                         0));
710         final List<ResolveInfo> query = snapshot.queryIntentActivitiesInternal(intent,
711                 resolvedType, flags, userId);
712         return snapshot.findPersistentPreferredActivity(intent, resolvedType, flags, query, false,
713                 userId);
714     }
715 
716     /**
717      * Variant that takes a {@link WatchedIntentFilter}
718      */
719     public void setLastChosenActivity(@NonNull Computer snapshot, Intent intent,
720             String resolvedType, int flags, WatchedIntentFilter filter, int match,
721             ComponentName activity) {
722         if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
723             return;
724         }
725         final int userId = UserHandle.getCallingUserId();
726         if (DEBUG_PREFERRED) {
727             Log.v(TAG, "setLastChosenActivity intent=" + intent
728                     + " resolvedType=" + resolvedType
729                     + " flags=" + flags
730                     + " filter=" + filter
731                     + " match=" + match
732                     + " activity=" + activity);
733             filter.dump(new PrintStreamPrinter(System.out), "    ");
734         }
735         intent.setComponent(null);
736         final List<ResolveInfo> query = snapshot.queryIntentActivitiesInternal(intent,
737                 resolvedType, flags, userId);
738         // Find any earlier preferred or last chosen entries and nuke them
739         findPreferredActivityNotLocked(snapshot, intent, resolvedType, flags, query, false, true,
740                 false, userId);
741         // Add the new activity as the last chosen for this filter
742         addPreferredActivity(snapshot, filter, match, null, activity, false, userId,
743                 "Setting last chosen", false);
744     }
745 
746     public ResolveInfo getLastChosenActivity(@NonNull Computer snapshot, Intent intent,
747             String resolvedType, int flags) {
748         if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
749             return null;
750         }
751         final int userId = UserHandle.getCallingUserId();
752         if (DEBUG_PREFERRED) Log.v(TAG, "Querying last chosen activity for " + intent);
753         final List<ResolveInfo> query = snapshot.queryIntentActivitiesInternal(intent,
754                 resolvedType, flags, userId);
755         return findPreferredActivityNotLocked(snapshot, intent, resolvedType, flags, query, false,
756                 false, false, userId);
757     }
758 }
759