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