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