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