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