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