1 /* 2 * Copyright (C) 2014 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 org.xmlpull.v1.XmlPullParser.END_DOCUMENT; 20 import static org.xmlpull.v1.XmlPullParser.START_TAG; 21 22 import android.Manifest; 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.app.ActivityManager; 26 import android.app.AppGlobals; 27 import android.app.AppOpsManager; 28 import android.app.Notification; 29 import android.app.NotificationManager; 30 import android.app.PackageDeleteObserver; 31 import android.app.admin.DevicePolicyEventLogger; 32 import android.app.admin.DevicePolicyManagerInternal; 33 import android.content.Context; 34 import android.content.Intent; 35 import android.content.IntentSender; 36 import android.content.IntentSender.SendIntentException; 37 import android.content.pm.ApplicationInfo; 38 import android.content.pm.IPackageInstaller; 39 import android.content.pm.IPackageInstallerCallback; 40 import android.content.pm.IPackageInstallerSession; 41 import android.content.pm.PackageInfo; 42 import android.content.pm.PackageInstaller; 43 import android.content.pm.PackageInstaller.SessionInfo; 44 import android.content.pm.PackageInstaller.SessionParams; 45 import android.content.pm.PackageItemInfo; 46 import android.content.pm.PackageManager; 47 import android.content.pm.ParceledListSlice; 48 import android.content.pm.VersionedPackage; 49 import android.graphics.Bitmap; 50 import android.net.Uri; 51 import android.os.Binder; 52 import android.os.Build; 53 import android.os.Environment; 54 import android.os.Handler; 55 import android.os.HandlerThread; 56 import android.os.Looper; 57 import android.os.Message; 58 import android.os.Process; 59 import android.os.RemoteCallbackList; 60 import android.os.RemoteException; 61 import android.os.SELinux; 62 import android.os.UserManager; 63 import android.os.storage.StorageManager; 64 import android.stats.devicepolicy.DevicePolicyEnums; 65 import android.system.ErrnoException; 66 import android.system.Os; 67 import android.text.TextUtils; 68 import android.text.format.DateUtils; 69 import android.util.ArraySet; 70 import android.util.AtomicFile; 71 import android.util.ExceptionUtils; 72 import android.util.Slog; 73 import android.util.SparseArray; 74 import android.util.SparseBooleanArray; 75 import android.util.SparseIntArray; 76 import android.util.TypedXmlPullParser; 77 import android.util.TypedXmlSerializer; 78 import android.util.Xml; 79 80 import com.android.internal.R; 81 import com.android.internal.annotations.GuardedBy; 82 import com.android.internal.content.PackageHelper; 83 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; 84 import com.android.internal.notification.SystemNotificationChannels; 85 import com.android.internal.util.ImageUtils; 86 import com.android.internal.util.IndentingPrintWriter; 87 import com.android.server.IoThread; 88 import com.android.server.LocalServices; 89 import com.android.server.SystemConfig; 90 import com.android.server.SystemService; 91 import com.android.server.SystemServiceManager; 92 import com.android.server.pm.parsing.PackageParser2; 93 import com.android.server.pm.utils.RequestThrottle; 94 95 import libcore.io.IoUtils; 96 97 import org.xmlpull.v1.XmlPullParserException; 98 99 import java.io.CharArrayWriter; 100 import java.io.File; 101 import java.io.FileInputStream; 102 import java.io.FileNotFoundException; 103 import java.io.FileOutputStream; 104 import java.io.FilenameFilter; 105 import java.io.IOException; 106 import java.security.SecureRandom; 107 import java.util.ArrayList; 108 import java.util.Collections; 109 import java.util.List; 110 import java.util.Objects; 111 import java.util.Random; 112 import java.util.function.IntPredicate; 113 import java.util.function.Supplier; 114 115 /** The service responsible for installing packages. */ 116 public class PackageInstallerService extends IPackageInstaller.Stub implements 117 PackageSessionProvider { 118 private static final String TAG = "PackageInstaller"; 119 private static final boolean LOGD = false; 120 121 // TODO: remove outstanding sessions when installer package goes away 122 // TODO: notify listeners in other users when package has been installed there 123 // TODO: purge expired sessions periodically in addition to at reboot 124 125 /** XML constants used in {@link #mSessionsFile} */ 126 private static final String TAG_SESSIONS = "sessions"; 127 128 /** Automatically destroy sessions older than this */ 129 private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS; 130 /** Automatically destroy staged sessions that have not changed state in this time */ 131 private static final long MAX_TIME_SINCE_UPDATE_MILLIS = 7 * DateUtils.DAY_IN_MILLIS; 132 /** Upper bound on number of active sessions for a UID that has INSTALL_PACKAGES */ 133 private static final long MAX_ACTIVE_SESSIONS_WITH_PERMISSION = 1024; 134 /** Upper bound on number of active sessions for a UID without INSTALL_PACKAGES */ 135 private static final long MAX_ACTIVE_SESSIONS_NO_PERMISSION = 50; 136 /** Upper bound on number of historical sessions for a UID */ 137 private static final long MAX_HISTORICAL_SESSIONS = 1048576; 138 139 /** 140 * Allow verification-skipping if it's a development app installed through ADB with 141 * disable verification flag specified. 142 */ 143 private static final int ADB_DEV_MODE = PackageManager.INSTALL_FROM_ADB 144 | PackageManager.INSTALL_ALLOW_TEST; 145 146 private final Context mContext; 147 private final PackageManagerService mPm; 148 private final ApexManager mApexManager; 149 private final StagingManager mStagingManager; 150 151 private AppOpsManager mAppOps; 152 153 private final HandlerThread mInstallThread; 154 private final Handler mInstallHandler; 155 156 private final Callbacks mCallbacks; 157 158 private volatile boolean mOkToSendBroadcasts = false; 159 private volatile boolean mBypassNextStagedInstallerCheck = false; 160 private volatile boolean mBypassNextAllowedApexUpdateCheck = false; 161 162 /** 163 * File storing persisted {@link #mSessions} metadata. 164 */ 165 private final AtomicFile mSessionsFile; 166 167 /** 168 * Directory storing persisted {@link #mSessions} metadata which is too 169 * heavy to store directly in {@link #mSessionsFile}. 170 */ 171 private final File mSessionsDir; 172 173 private final InternalCallback mInternalCallback = new InternalCallback(); 174 175 /** 176 * Used for generating session IDs. Since this is created at boot time, 177 * normal random might be predictable. 178 */ 179 private final Random mRandom = new SecureRandom(); 180 181 /** All sessions allocated */ 182 @GuardedBy("mSessions") 183 private final SparseBooleanArray mAllocatedSessions = new SparseBooleanArray(); 184 185 @GuardedBy("mSessions") 186 private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>(); 187 188 /** Historical sessions kept around for debugging purposes */ 189 @GuardedBy("mSessions") 190 private final List<String> mHistoricalSessions = new ArrayList<>(); 191 192 @GuardedBy("mSessions") 193 private final SparseIntArray mHistoricalSessionsByInstaller = new SparseIntArray(); 194 195 /** Sessions allocated to legacy users */ 196 @GuardedBy("mSessions") 197 private final SparseBooleanArray mLegacySessions = new SparseBooleanArray(); 198 199 /** Policy for allowing a silent update. */ 200 private final SilentUpdatePolicy mSilentUpdatePolicy = new SilentUpdatePolicy(); 201 202 private static final FilenameFilter sStageFilter = new FilenameFilter() { 203 @Override 204 public boolean accept(File dir, String name) { 205 return isStageName(name); 206 } 207 }; 208 209 private static final class Lifecycle extends SystemService { 210 private final PackageInstallerService mPackageInstallerService; 211 Lifecycle(Context context, PackageInstallerService service)212 Lifecycle(Context context, PackageInstallerService service) { 213 super(context); 214 mPackageInstallerService = service; 215 } 216 217 @Override onStart()218 public void onStart() { 219 // no-op 220 } 221 222 @Override onBootPhase(int phase)223 public void onBootPhase(int phase) { 224 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { 225 mPackageInstallerService.onBroadcastReady(); 226 } 227 } 228 } 229 230 @NonNull 231 private final RequestThrottle mSettingsWriteRequest = new RequestThrottle(IoThread.getHandler(), 232 () -> { 233 synchronized (mSessions) { 234 return writeSessionsLocked(); 235 } 236 }); 237 PackageInstallerService(Context context, PackageManagerService pm, Supplier<PackageParser2> apexParserSupplier)238 public PackageInstallerService(Context context, PackageManagerService pm, 239 Supplier<PackageParser2> apexParserSupplier) { 240 mContext = context; 241 mPm = pm; 242 243 mInstallThread = new HandlerThread(TAG); 244 mInstallThread.start(); 245 246 mInstallHandler = new Handler(mInstallThread.getLooper()); 247 248 mCallbacks = new Callbacks(mInstallThread.getLooper()); 249 250 mSessionsFile = new AtomicFile( 251 new File(Environment.getDataSystemDirectory(), "install_sessions.xml"), 252 "package-session"); 253 mSessionsDir = new File(Environment.getDataSystemDirectory(), "install_sessions"); 254 mSessionsDir.mkdirs(); 255 256 mApexManager = ApexManager.getInstance(); 257 mStagingManager = new StagingManager(context, apexParserSupplier); 258 259 LocalServices.getService(SystemServiceManager.class).startService( 260 new Lifecycle(context, this)); 261 } 262 okToSendBroadcasts()263 boolean okToSendBroadcasts() { 264 return mOkToSendBroadcasts; 265 } 266 systemReady()267 public void systemReady() { 268 mAppOps = mContext.getSystemService(AppOpsManager.class); 269 mStagingManager.systemReady(); 270 271 synchronized (mSessions) { 272 readSessionsLocked(); 273 274 reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL); 275 276 final ArraySet<File> unclaimedIcons = newArraySet( 277 mSessionsDir.listFiles()); 278 279 // Ignore stages and icons claimed by active sessions 280 for (int i = 0; i < mSessions.size(); i++) { 281 final PackageInstallerSession session = mSessions.valueAt(i); 282 unclaimedIcons.remove(buildAppIconFile(session.sessionId)); 283 } 284 285 // Clean up orphaned icons 286 for (File icon : unclaimedIcons) { 287 Slog.w(TAG, "Deleting orphan icon " + icon); 288 icon.delete(); 289 } 290 291 // Invalid sessions might have been marked while parsing. Re-write the database with 292 // the updated information. 293 mSettingsWriteRequest.runNow(); 294 295 } 296 } 297 onBroadcastReady()298 private void onBroadcastReady() { 299 // Broadcasts are not sent while we restore sessions on boot, since no processes would be 300 // ready to listen to them. From now on, it is safe to send broadcasts which otherwise will 301 // be rejected by ActivityManagerService if its systemReady() is not completed. 302 mOkToSendBroadcasts = true; 303 } 304 restoreAndApplyStagedSessionIfNeeded()305 void restoreAndApplyStagedSessionIfNeeded() { 306 List<StagingManager.StagedSession> stagedSessionsToRestore = new ArrayList<>(); 307 synchronized (mSessions) { 308 for (int i = 0; i < mSessions.size(); i++) { 309 final PackageInstallerSession session = mSessions.valueAt(i); 310 if (!session.isStaged()) { 311 continue; 312 } 313 StagingManager.StagedSession stagedSession = session.mStagedSession; 314 if (!stagedSession.isInTerminalState() && stagedSession.hasParentSessionId() 315 && getSession(stagedSession.getParentSessionId()) == null) { 316 stagedSession.setSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, 317 "An orphan staged session " + stagedSession.sessionId() + " is found, " 318 + "parent " + stagedSession.getParentSessionId() + " is missing"); 319 continue; 320 } 321 if (!stagedSession.hasParentSessionId() && stagedSession.isCommitted() 322 && !stagedSession.isInTerminalState()) { 323 // StagingManager.restoreSessions expects a list of committed, non-finalized 324 // parent staged sessions. 325 stagedSessionsToRestore.add(stagedSession); 326 } 327 } 328 } 329 // Don't hold mSessions lock when calling restoreSessions, since it might trigger an APK 330 // atomic install which needs to query sessions, which requires lock on mSessions. 331 // Note: restoreSessions mutates content of stagedSessionsToRestore. 332 mStagingManager.restoreSessions(stagedSessionsToRestore, mPm.isDeviceUpgrading()); 333 } 334 335 @GuardedBy("mSessions") reconcileStagesLocked(String volumeUuid)336 private void reconcileStagesLocked(String volumeUuid) { 337 final File stagingDir = getTmpSessionDir(volumeUuid); 338 final ArraySet<File> unclaimedStages = newArraySet( 339 stagingDir.listFiles(sStageFilter)); 340 341 // We also need to clean up orphaned staging directory for staged sessions 342 final File stagedSessionStagingDir = Environment.getDataStagingDirectory(volumeUuid); 343 unclaimedStages.addAll(newArraySet(stagedSessionStagingDir.listFiles())); 344 345 // Ignore stages claimed by active sessions 346 for (int i = 0; i < mSessions.size(); i++) { 347 final PackageInstallerSession session = mSessions.valueAt(i); 348 unclaimedStages.remove(session.stageDir); 349 } 350 351 // Clean up orphaned staging directories 352 for (File stage : unclaimedStages) { 353 Slog.w(TAG, "Deleting orphan stage " + stage); 354 synchronized (mPm.mInstallLock) { 355 mPm.removeCodePathLI(stage); 356 } 357 } 358 } 359 onPrivateVolumeMounted(String volumeUuid)360 public void onPrivateVolumeMounted(String volumeUuid) { 361 synchronized (mSessions) { 362 reconcileStagesLocked(volumeUuid); 363 } 364 } 365 isStageName(String name)366 public static boolean isStageName(String name) { 367 final boolean isFile = name.startsWith("vmdl") && name.endsWith(".tmp"); 368 final boolean isContainer = name.startsWith("smdl") && name.endsWith(".tmp"); 369 final boolean isLegacyContainer = name.startsWith("smdl2tmp"); 370 return isFile || isContainer || isLegacyContainer; 371 } 372 373 @Deprecated allocateStageDirLegacy(String volumeUuid, boolean isEphemeral)374 public File allocateStageDirLegacy(String volumeUuid, boolean isEphemeral) throws IOException { 375 synchronized (mSessions) { 376 try { 377 final int sessionId = allocateSessionIdLocked(); 378 mLegacySessions.put(sessionId, true); 379 final File sessionStageDir = buildTmpSessionDir(sessionId, volumeUuid); 380 prepareStageDir(sessionStageDir); 381 return sessionStageDir; 382 } catch (IllegalStateException e) { 383 throw new IOException(e); 384 } 385 } 386 } 387 388 @Deprecated allocateExternalStageCidLegacy()389 public String allocateExternalStageCidLegacy() { 390 synchronized (mSessions) { 391 final int sessionId = allocateSessionIdLocked(); 392 mLegacySessions.put(sessionId, true); 393 return "smdl" + sessionId + ".tmp"; 394 } 395 } 396 397 @GuardedBy("mSessions") readSessionsLocked()398 private void readSessionsLocked() { 399 if (LOGD) Slog.v(TAG, "readSessionsLocked()"); 400 401 mSessions.clear(); 402 403 FileInputStream fis = null; 404 try { 405 fis = mSessionsFile.openRead(); 406 final TypedXmlPullParser in = Xml.resolvePullParser(fis); 407 408 int type; 409 while ((type = in.next()) != END_DOCUMENT) { 410 if (type == START_TAG) { 411 final String tag = in.getName(); 412 if (PackageInstallerSession.TAG_SESSION.equals(tag)) { 413 final PackageInstallerSession session; 414 try { 415 session = PackageInstallerSession.readFromXml(in, mInternalCallback, 416 mContext, mPm, mInstallThread.getLooper(), mStagingManager, 417 mSessionsDir, this, mSilentUpdatePolicy); 418 } catch (Exception e) { 419 Slog.e(TAG, "Could not read session", e); 420 continue; 421 } 422 423 final long age = System.currentTimeMillis() - session.createdMillis; 424 final long timeSinceUpdate = 425 System.currentTimeMillis() - session.getUpdatedMillis(); 426 final boolean valid; 427 if (session.isStaged()) { 428 if (timeSinceUpdate >= MAX_TIME_SINCE_UPDATE_MILLIS 429 && session.isStagedAndInTerminalState()) { 430 valid = false; 431 } else { 432 valid = true; 433 } 434 } else if (age >= MAX_AGE_MILLIS) { 435 Slog.w(TAG, "Abandoning old session created at " 436 + session.createdMillis); 437 valid = false; 438 } else { 439 valid = true; 440 } 441 442 if (valid) { 443 mSessions.put(session.sessionId, session); 444 } else { 445 // Since this is early during boot we don't send 446 // any observer events about the session, but we 447 // keep details around for dumpsys. 448 addHistoricalSessionLocked(session); 449 } 450 mAllocatedSessions.put(session.sessionId, true); 451 } 452 } 453 } 454 } catch (FileNotFoundException e) { 455 // Missing sessions are okay, probably first boot 456 } catch (IOException | XmlPullParserException e) { 457 Slog.wtf(TAG, "Failed reading install sessions", e); 458 } finally { 459 IoUtils.closeQuietly(fis); 460 } 461 // After reboot housekeeping. 462 for (int i = 0; i < mSessions.size(); ++i) { 463 PackageInstallerSession session = mSessions.valueAt(i); 464 session.onAfterSessionRead(mSessions); 465 } 466 } 467 468 @GuardedBy("mSessions") addHistoricalSessionLocked(PackageInstallerSession session)469 private void addHistoricalSessionLocked(PackageInstallerSession session) { 470 CharArrayWriter writer = new CharArrayWriter(); 471 IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); 472 session.dump(pw); 473 mHistoricalSessions.add(writer.toString()); 474 475 int installerUid = session.getInstallerUid(); 476 // Increment the number of sessions by this installerUid. 477 mHistoricalSessionsByInstaller.put(installerUid, 478 mHistoricalSessionsByInstaller.get(installerUid) + 1); 479 } 480 481 @GuardedBy("mSessions") writeSessionsLocked()482 private boolean writeSessionsLocked() { 483 if (LOGD) Slog.v(TAG, "writeSessionsLocked()"); 484 485 FileOutputStream fos = null; 486 try { 487 fos = mSessionsFile.startWrite(); 488 489 final TypedXmlSerializer out = Xml.resolveSerializer(fos); 490 out.startDocument(null, true); 491 out.startTag(null, TAG_SESSIONS); 492 final int size = mSessions.size(); 493 for (int i = 0; i < size; i++) { 494 final PackageInstallerSession session = mSessions.valueAt(i); 495 session.write(out, mSessionsDir); 496 } 497 out.endTag(null, TAG_SESSIONS); 498 out.endDocument(); 499 500 mSessionsFile.finishWrite(fos); 501 return true; 502 } catch (IOException e) { 503 if (fos != null) { 504 mSessionsFile.failWrite(fos); 505 } 506 } 507 508 return false; 509 } 510 buildAppIconFile(int sessionId)511 private File buildAppIconFile(int sessionId) { 512 return new File(mSessionsDir, "app_icon." + sessionId + ".png"); 513 } 514 515 @Override createSession(SessionParams params, String installerPackageName, String callingAttributionTag, int userId)516 public int createSession(SessionParams params, String installerPackageName, 517 String callingAttributionTag, int userId) { 518 try { 519 return createSessionInternal(params, installerPackageName, callingAttributionTag, 520 userId); 521 } catch (IOException e) { 522 throw ExceptionUtils.wrap(e); 523 } 524 } 525 createSessionInternal(SessionParams params, String installerPackageName, String installerAttributionTag, int userId)526 private int createSessionInternal(SessionParams params, String installerPackageName, 527 String installerAttributionTag, int userId) 528 throws IOException { 529 final int callingUid = Binder.getCallingUid(); 530 mPm.enforceCrossUserPermission( 531 callingUid, userId, true, true, "createSession"); 532 533 if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) { 534 throw new SecurityException("User restriction prevents installing"); 535 } 536 537 if (params.dataLoaderParams != null 538 && mContext.checkCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2) 539 != PackageManager.PERMISSION_GRANTED) { 540 throw new SecurityException("You need the " 541 + "com.android.permission.USE_INSTALLER_V2 permission " 542 + "to use a data loader"); 543 } 544 545 // INSTALL_REASON_ROLLBACK allows an app to be rolled back without requiring the ROLLBACK 546 // capability; ensure if this is set as the install reason the app has one of the necessary 547 // signature permissions to perform the rollback. 548 if (params.installReason == PackageManager.INSTALL_REASON_ROLLBACK) { 549 if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_ROLLBACKS) 550 != PackageManager.PERMISSION_GRANTED && 551 mContext.checkCallingOrSelfPermission(Manifest.permission.TEST_MANAGE_ROLLBACKS) 552 != PackageManager.PERMISSION_GRANTED) { 553 throw new SecurityException( 554 "INSTALL_REASON_ROLLBACK requires the MANAGE_ROLLBACKS permission or the " 555 + "TEST_MANAGE_ROLLBACKS permission"); 556 } 557 } 558 559 // App package name and label length is restricted so that really long strings aren't 560 // written to disk. 561 if (params.appPackageName != null 562 && params.appPackageName.length() > SessionParams.MAX_PACKAGE_NAME_LENGTH) { 563 params.appPackageName = null; 564 } 565 566 params.appLabel = TextUtils.trimToSize(params.appLabel, 567 PackageItemInfo.MAX_SAFE_LABEL_LENGTH); 568 569 String requestedInstallerPackageName = (params.installerPackageName != null 570 && params.installerPackageName.length() < SessionParams.MAX_PACKAGE_NAME_LENGTH) 571 ? params.installerPackageName : installerPackageName; 572 573 if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) { 574 params.installFlags |= PackageManager.INSTALL_FROM_ADB; 575 // adb installs can override the installingPackageName, but not the 576 // initiatingPackageName 577 installerPackageName = null; 578 } else { 579 if (callingUid != Process.SYSTEM_UID) { 580 // The supplied installerPackageName must always belong to the calling app. 581 mAppOps.checkPackage(callingUid, installerPackageName); 582 } 583 // Only apps with INSTALL_PACKAGES are allowed to set an installer that is not the 584 // caller. 585 if (!TextUtils.equals(requestedInstallerPackageName, installerPackageName)) { 586 if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES) 587 != PackageManager.PERMISSION_GRANTED) { 588 mAppOps.checkPackage(callingUid, requestedInstallerPackageName); 589 } 590 } 591 592 params.installFlags &= ~PackageManager.INSTALL_FROM_ADB; 593 params.installFlags &= ~PackageManager.INSTALL_ALL_USERS; 594 params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; 595 if ((params.installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0 596 && !mPm.isCallerVerifier(callingUid)) { 597 params.installFlags &= ~PackageManager.INSTALL_VIRTUAL_PRELOAD; 598 } 599 if (mContext.checkCallingOrSelfPermission( 600 Manifest.permission.INSTALL_TEST_ONLY_PACKAGE) 601 != PackageManager.PERMISSION_GRANTED) { 602 params.installFlags &= ~PackageManager.INSTALL_ALLOW_TEST; 603 } 604 } 605 606 String originatingPackageName = null; 607 if (params.originatingUid != SessionParams.UID_UNKNOWN 608 && params.originatingUid != callingUid) { 609 String[] packages = mPm.getPackagesForUid(params.originatingUid); 610 if (packages != null && packages.length > 0) { 611 // Choose an arbitrary representative package in the case of a shared UID. 612 originatingPackageName = packages[0]; 613 } 614 } 615 616 if (Build.IS_DEBUGGABLE || isCalledBySystemOrShell(callingUid)) { 617 params.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE; 618 } else { 619 params.installFlags &= ~PackageManager.INSTALL_ALLOW_DOWNGRADE; 620 params.installFlags &= ~PackageManager.INSTALL_REQUEST_DOWNGRADE; 621 } 622 623 if ((params.installFlags & ADB_DEV_MODE) != ADB_DEV_MODE) { 624 // Only tools under specific conditions (test app installed through ADB, and 625 // verification disabled flag specified) can disable verification. 626 params.installFlags &= ~PackageManager.INSTALL_DISABLE_VERIFICATION; 627 } 628 629 boolean isApex = (params.installFlags & PackageManager.INSTALL_APEX) != 0; 630 if (isApex) { 631 if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGE_UPDATES) 632 == PackageManager.PERMISSION_DENIED 633 && mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES) 634 == PackageManager.PERMISSION_DENIED) { 635 throw new SecurityException("Not allowed to perform APEX updates"); 636 } 637 } else if (params.isStaged) { 638 mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, TAG); 639 } 640 641 if (isApex) { 642 if (!mApexManager.isApexSupported()) { 643 throw new IllegalArgumentException( 644 "This device doesn't support the installation of APEX files"); 645 } 646 if (params.isMultiPackage) { 647 throw new IllegalArgumentException("A multi-session can't be set as APEX."); 648 } 649 if (!params.isStaged 650 && (params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) { 651 throw new IllegalArgumentException( 652 "Non-staged APEX session doesn't support INSTALL_ENABLE_ROLLBACK"); 653 } 654 if (isCalledBySystemOrShell(callingUid) || mBypassNextAllowedApexUpdateCheck) { 655 params.installFlags |= PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK; 656 } else { 657 // Only specific APEX updates (installed through ADB, or for CTS tests) can disable 658 // allowed APEX update check. 659 params.installFlags &= ~PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK; 660 } 661 } 662 663 if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0 664 && !isCalledBySystemOrShell(callingUid) 665 && (mPm.getFlagsForUid(callingUid) & ApplicationInfo.FLAG_SYSTEM) == 0) { 666 throw new SecurityException( 667 "Only system apps could use the PackageManager.INSTALL_INSTANT_APP flag."); 668 } 669 670 if (params.isStaged && !isCalledBySystemOrShell(callingUid)) { 671 if (!mBypassNextStagedInstallerCheck 672 && !isStagedInstallerAllowed(requestedInstallerPackageName)) { 673 throw new SecurityException("Installer not allowed to commit staged install"); 674 } 675 } 676 if (isApex && !isCalledBySystemOrShell(callingUid)) { 677 if (!mBypassNextStagedInstallerCheck 678 && !isStagedInstallerAllowed(requestedInstallerPackageName)) { 679 throw new SecurityException( 680 "Installer not allowed to commit non-staged APEX install"); 681 } 682 } 683 684 mBypassNextStagedInstallerCheck = false; 685 mBypassNextAllowedApexUpdateCheck = false; 686 687 if (!params.isMultiPackage) { 688 // Only system components can circumvent runtime permissions when installing. 689 if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0 690 && mContext.checkCallingOrSelfPermission(Manifest.permission 691 .INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) { 692 throw new SecurityException("You need the " 693 + "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission " 694 + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag"); 695 } 696 697 // Defensively resize giant app icons 698 if (params.appIcon != null) { 699 final ActivityManager am = (ActivityManager) mContext.getSystemService( 700 Context.ACTIVITY_SERVICE); 701 final int iconSize = am.getLauncherLargeIconSize(); 702 if ((params.appIcon.getWidth() > iconSize * 2) 703 || (params.appIcon.getHeight() > iconSize * 2)) { 704 params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize, 705 true); 706 } 707 } 708 709 switch (params.mode) { 710 case SessionParams.MODE_FULL_INSTALL: 711 case SessionParams.MODE_INHERIT_EXISTING: 712 break; 713 default: 714 throw new IllegalArgumentException("Invalid install mode: " + params.mode); 715 } 716 717 // If caller requested explicit location, validity check it, otherwise 718 // resolve the best internal or adopted location. 719 if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) { 720 if (!PackageHelper.fitsOnInternal(mContext, params)) { 721 throw new IOException("No suitable internal storage available"); 722 } 723 } else if ((params.installFlags & PackageManager.INSTALL_FORCE_VOLUME_UUID) != 0) { 724 // For now, installs to adopted media are treated as internal from 725 // an install flag point-of-view. 726 params.installFlags |= PackageManager.INSTALL_INTERNAL; 727 } else { 728 params.installFlags |= PackageManager.INSTALL_INTERNAL; 729 730 // Resolve best location for install, based on combination of 731 // requested install flags, delta size, and manifest settings. 732 final long ident = Binder.clearCallingIdentity(); 733 try { 734 params.volumeUuid = PackageHelper.resolveInstallVolume(mContext, params); 735 } finally { 736 Binder.restoreCallingIdentity(ident); 737 } 738 } 739 } 740 741 final int sessionId; 742 final PackageInstallerSession session; 743 synchronized (mSessions) { 744 // Check that the installer does not have too many active sessions. 745 final int activeCount = getSessionCount(mSessions, callingUid); 746 if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES) 747 == PackageManager.PERMISSION_GRANTED) { 748 if (activeCount >= MAX_ACTIVE_SESSIONS_WITH_PERMISSION) { 749 throw new IllegalStateException( 750 "Too many active sessions for UID " + callingUid); 751 } 752 } else if (activeCount >= MAX_ACTIVE_SESSIONS_NO_PERMISSION) { 753 throw new IllegalStateException( 754 "Too many active sessions for UID " + callingUid); 755 } 756 final int historicalCount = mHistoricalSessionsByInstaller.get(callingUid); 757 if (historicalCount >= MAX_HISTORICAL_SESSIONS) { 758 throw new IllegalStateException( 759 "Too many historical sessions for UID " + callingUid); 760 } 761 762 sessionId = allocateSessionIdLocked(); 763 } 764 765 final long createdMillis = System.currentTimeMillis(); 766 // We're staging to exactly one location 767 File stageDir = null; 768 String stageCid = null; 769 if (!params.isMultiPackage) { 770 if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) { 771 stageDir = buildSessionDir(sessionId, params); 772 } else { 773 stageCid = buildExternalStageCid(sessionId); 774 } 775 } 776 777 // reset the force queryable param if it's not called by an approved caller. 778 if (params.forceQueryableOverride) { 779 if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) { 780 params.forceQueryableOverride = false; 781 } 782 } 783 InstallSource installSource = InstallSource.create(installerPackageName, 784 originatingPackageName, requestedInstallerPackageName, 785 installerAttributionTag); 786 session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this, 787 mSilentUpdatePolicy, mInstallThread.getLooper(), mStagingManager, sessionId, 788 userId, callingUid, installSource, params, createdMillis, 0L, stageDir, stageCid, 789 null, null, false, false, false, false, null, SessionInfo.INVALID_ID, 790 false, false, false, SessionInfo.STAGED_SESSION_NO_ERROR, ""); 791 792 synchronized (mSessions) { 793 mSessions.put(sessionId, session); 794 } 795 796 mCallbacks.notifySessionCreated(session.sessionId, session.userId); 797 798 mSettingsWriteRequest.schedule(); 799 return sessionId; 800 } 801 isCalledBySystemOrShell(int callingUid)802 private boolean isCalledBySystemOrShell(int callingUid) { 803 return callingUid == Process.SYSTEM_UID || callingUid == Process.ROOT_UID 804 || callingUid == Process.SHELL_UID; 805 } 806 isStagedInstallerAllowed(String installerName)807 private boolean isStagedInstallerAllowed(String installerName) { 808 return SystemConfig.getInstance().getWhitelistedStagedInstallers().contains(installerName); 809 } 810 811 @Override updateSessionAppIcon(int sessionId, Bitmap appIcon)812 public void updateSessionAppIcon(int sessionId, Bitmap appIcon) { 813 synchronized (mSessions) { 814 final PackageInstallerSession session = mSessions.get(sessionId); 815 if (session == null || !isCallingUidOwner(session)) { 816 throw new SecurityException("Caller has no access to session " + sessionId); 817 } 818 819 // Defensively resize giant app icons 820 if (appIcon != null) { 821 final ActivityManager am = (ActivityManager) mContext.getSystemService( 822 Context.ACTIVITY_SERVICE); 823 final int iconSize = am.getLauncherLargeIconSize(); 824 if ((appIcon.getWidth() > iconSize * 2) 825 || (appIcon.getHeight() > iconSize * 2)) { 826 appIcon = Bitmap.createScaledBitmap(appIcon, iconSize, iconSize, true); 827 } 828 } 829 830 session.params.appIcon = appIcon; 831 session.params.appIconLastModified = -1; 832 833 mInternalCallback.onSessionBadgingChanged(session); 834 } 835 } 836 837 @Override updateSessionAppLabel(int sessionId, String appLabel)838 public void updateSessionAppLabel(int sessionId, String appLabel) { 839 synchronized (mSessions) { 840 final PackageInstallerSession session = mSessions.get(sessionId); 841 if (session == null || !isCallingUidOwner(session)) { 842 throw new SecurityException("Caller has no access to session " + sessionId); 843 } 844 session.params.appLabel = appLabel; 845 mInternalCallback.onSessionBadgingChanged(session); 846 } 847 } 848 849 @Override abandonSession(int sessionId)850 public void abandonSession(int sessionId) { 851 synchronized (mSessions) { 852 final PackageInstallerSession session = mSessions.get(sessionId); 853 if (session == null || !isCallingUidOwner(session)) { 854 throw new SecurityException("Caller has no access to session " + sessionId); 855 } 856 session.abandon(); 857 } 858 } 859 860 @Override openSession(int sessionId)861 public IPackageInstallerSession openSession(int sessionId) { 862 try { 863 return openSessionInternal(sessionId); 864 } catch (IOException e) { 865 throw ExceptionUtils.wrap(e); 866 } 867 } 868 openSessionInternal(int sessionId)869 private IPackageInstallerSession openSessionInternal(int sessionId) throws IOException { 870 synchronized (mSessions) { 871 final PackageInstallerSession session = mSessions.get(sessionId); 872 if (session == null || !isCallingUidOwner(session)) { 873 throw new SecurityException("Caller has no access to session " + sessionId); 874 } 875 session.open(); 876 return session; 877 } 878 } 879 880 @GuardedBy("mSessions") allocateSessionIdLocked()881 private int allocateSessionIdLocked() { 882 int n = 0; 883 int sessionId; 884 do { 885 sessionId = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1; 886 if (!mAllocatedSessions.get(sessionId, false)) { 887 mAllocatedSessions.put(sessionId, true); 888 return sessionId; 889 } 890 } while (n++ < 32); 891 892 throw new IllegalStateException("Failed to allocate session ID"); 893 } 894 getTmpSessionDir(String volumeUuid)895 private File getTmpSessionDir(String volumeUuid) { 896 return Environment.getDataAppDirectory(volumeUuid); 897 } 898 buildTmpSessionDir(int sessionId, String volumeUuid)899 private File buildTmpSessionDir(int sessionId, String volumeUuid) { 900 final File sessionStagingDir = getTmpSessionDir(volumeUuid); 901 return new File(sessionStagingDir, "vmdl" + sessionId + ".tmp"); 902 } 903 buildSessionDir(int sessionId, SessionParams params)904 private File buildSessionDir(int sessionId, SessionParams params) { 905 if (params.isStaged || (params.installFlags & PackageManager.INSTALL_APEX) != 0) { 906 final File sessionStagingDir = Environment.getDataStagingDirectory(params.volumeUuid); 907 return new File(sessionStagingDir, "session_" + sessionId); 908 } 909 return buildTmpSessionDir(sessionId, params.volumeUuid); 910 } 911 prepareStageDir(File stageDir)912 static void prepareStageDir(File stageDir) throws IOException { 913 if (stageDir.exists()) { 914 throw new IOException("Session dir already exists: " + stageDir); 915 } 916 917 try { 918 Os.mkdir(stageDir.getAbsolutePath(), 0775); 919 Os.chmod(stageDir.getAbsolutePath(), 0775); 920 } catch (ErrnoException e) { 921 // This purposefully throws if directory already exists 922 throw new IOException("Failed to prepare session dir: " + stageDir, e); 923 } 924 925 if (!SELinux.restorecon(stageDir)) { 926 throw new IOException("Failed to restorecon session dir: " + stageDir); 927 } 928 } 929 buildExternalStageCid(int sessionId)930 private String buildExternalStageCid(int sessionId) { 931 return "smdl" + sessionId + ".tmp"; 932 } 933 934 @Override getSessionInfo(int sessionId)935 public SessionInfo getSessionInfo(int sessionId) { 936 synchronized (mSessions) { 937 final PackageInstallerSession session = mSessions.get(sessionId); 938 939 return (session != null && !(session.isStaged() && session.isDestroyed())) 940 ? session.generateInfoForCaller(true /*withIcon*/, Binder.getCallingUid()) 941 : null; 942 } 943 } 944 945 @Override getStagedSessions()946 public ParceledListSlice<SessionInfo> getStagedSessions() { 947 final List<SessionInfo> result = new ArrayList<>(); 948 synchronized (mSessions) { 949 for (int i = 0; i < mSessions.size(); i++) { 950 final PackageInstallerSession session = mSessions.valueAt(i); 951 if (session.isStaged() && !session.isDestroyed()) { 952 result.add(session.generateInfoForCaller(false, Binder.getCallingUid())); 953 } 954 } 955 } 956 return new ParceledListSlice<>(result); 957 } 958 959 @Override getAllSessions(int userId)960 public ParceledListSlice<SessionInfo> getAllSessions(int userId) { 961 final int callingUid = Binder.getCallingUid(); 962 mPm.enforceCrossUserPermission( 963 callingUid, userId, true, false, "getAllSessions"); 964 965 final List<SessionInfo> result = new ArrayList<>(); 966 synchronized (mSessions) { 967 for (int i = 0; i < mSessions.size(); i++) { 968 final PackageInstallerSession session = mSessions.valueAt(i); 969 if (session.userId == userId && !session.hasParentSessionId() 970 && !(session.isStaged() && session.isDestroyed())) { 971 result.add(session.generateInfoForCaller(false, callingUid)); 972 } 973 } 974 } 975 return new ParceledListSlice<>(result); 976 } 977 978 @Override getMySessions(String installerPackageName, int userId)979 public ParceledListSlice<SessionInfo> getMySessions(String installerPackageName, int userId) { 980 mPm.enforceCrossUserPermission( 981 Binder.getCallingUid(), userId, true, false, "getMySessions"); 982 mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName); 983 984 final List<SessionInfo> result = new ArrayList<>(); 985 synchronized (mSessions) { 986 for (int i = 0; i < mSessions.size(); i++) { 987 final PackageInstallerSession session = mSessions.valueAt(i); 988 989 SessionInfo info = 990 session.generateInfoForCaller(false /*withIcon*/, Process.SYSTEM_UID); 991 if (Objects.equals(info.getInstallerPackageName(), installerPackageName) 992 && session.userId == userId && !session.hasParentSessionId() 993 && isCallingUidOwner(session)) { 994 result.add(info); 995 } 996 } 997 } 998 return new ParceledListSlice<>(result); 999 } 1000 1001 @Override uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags, IntentSender statusReceiver, int userId)1002 public void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags, 1003 IntentSender statusReceiver, int userId) { 1004 final int callingUid = Binder.getCallingUid(); 1005 mPm.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall"); 1006 if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) { 1007 mAppOps.checkPackage(callingUid, callerPackageName); 1008 } 1009 1010 // Check whether the caller is device owner or affiliated profile owner, in which case we do 1011 // it silently. 1012 DevicePolicyManagerInternal dpmi = 1013 LocalServices.getService(DevicePolicyManagerInternal.class); 1014 final boolean canSilentlyInstallPackage = 1015 dpmi != null && dpmi.canSilentlyInstallPackage(callerPackageName, callingUid); 1016 1017 final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext, 1018 statusReceiver, versionedPackage.getPackageName(), 1019 canSilentlyInstallPackage, userId); 1020 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES) 1021 == PackageManager.PERMISSION_GRANTED) { 1022 // Sweet, call straight through! 1023 mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags); 1024 } else if (canSilentlyInstallPackage) { 1025 // Allow the device owner and affiliated profile owner to silently delete packages 1026 // Need to clear the calling identity to get DELETE_PACKAGES permission 1027 final long ident = Binder.clearCallingIdentity(); 1028 try { 1029 mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags); 1030 } finally { 1031 Binder.restoreCallingIdentity(ident); 1032 } 1033 DevicePolicyEventLogger 1034 .createEvent(DevicePolicyEnums.UNINSTALL_PACKAGE) 1035 .setAdmin(callerPackageName) 1036 .write(); 1037 } else { 1038 ApplicationInfo appInfo = mPm.getApplicationInfo(callerPackageName, 0, userId); 1039 if (appInfo.targetSdkVersion >= Build.VERSION_CODES.P) { 1040 mContext.enforceCallingOrSelfPermission(Manifest.permission.REQUEST_DELETE_PACKAGES, 1041 null); 1042 } 1043 1044 // Take a short detour to confirm with user 1045 final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE); 1046 intent.setData(Uri.fromParts("package", versionedPackage.getPackageName(), null)); 1047 intent.putExtra(PackageInstaller.EXTRA_CALLBACK, adapter.getBinder().asBinder()); 1048 adapter.onUserActionRequired(intent); 1049 } 1050 } 1051 1052 @Override uninstallExistingPackage(VersionedPackage versionedPackage, String callerPackageName, IntentSender statusReceiver, int userId)1053 public void uninstallExistingPackage(VersionedPackage versionedPackage, 1054 String callerPackageName, IntentSender statusReceiver, int userId) { 1055 final int callingUid = Binder.getCallingUid(); 1056 mContext.enforceCallingOrSelfPermission(Manifest.permission.DELETE_PACKAGES, null); 1057 mPm.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall"); 1058 if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) { 1059 mAppOps.checkPackage(callingUid, callerPackageName); 1060 } 1061 1062 final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext, 1063 statusReceiver, versionedPackage.getPackageName(), false, userId); 1064 mPm.deleteExistingPackageAsUser(versionedPackage, adapter.getBinder(), userId); 1065 } 1066 1067 @Override installExistingPackage(String packageName, int installFlags, int installReason, IntentSender statusReceiver, int userId, List<String> whiteListedPermissions)1068 public void installExistingPackage(String packageName, int installFlags, int installReason, 1069 IntentSender statusReceiver, int userId, List<String> whiteListedPermissions) { 1070 mPm.installExistingPackageAsUser(packageName, userId, installFlags, installReason, 1071 whiteListedPermissions, statusReceiver); 1072 } 1073 1074 @Override setPermissionsResult(int sessionId, boolean accepted)1075 public void setPermissionsResult(int sessionId, boolean accepted) { 1076 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, TAG); 1077 1078 synchronized (mSessions) { 1079 PackageInstallerSession session = mSessions.get(sessionId); 1080 if (session != null) { 1081 session.setPermissionsResult(accepted); 1082 } 1083 } 1084 } 1085 1086 @Override registerCallback(IPackageInstallerCallback callback, int userId)1087 public void registerCallback(IPackageInstallerCallback callback, int userId) { 1088 mPm.enforceCrossUserPermission( 1089 Binder.getCallingUid(), userId, true, false, "registerCallback"); 1090 registerCallback(callback, eventUserId -> userId == eventUserId); 1091 } 1092 1093 /** 1094 * Assume permissions already checked and caller's identity cleared 1095 */ registerCallback(IPackageInstallerCallback callback, IntPredicate userCheck)1096 public void registerCallback(IPackageInstallerCallback callback, IntPredicate userCheck) { 1097 mCallbacks.register(callback, userCheck); 1098 } 1099 1100 @Override unregisterCallback(IPackageInstallerCallback callback)1101 public void unregisterCallback(IPackageInstallerCallback callback) { 1102 mCallbacks.unregister(callback); 1103 } 1104 1105 @Override getSession(int sessionId)1106 public PackageInstallerSession getSession(int sessionId) { 1107 synchronized (mSessions) { 1108 return mSessions.get(sessionId); 1109 } 1110 } 1111 1112 @Override bypassNextStagedInstallerCheck(boolean value)1113 public void bypassNextStagedInstallerCheck(boolean value) { 1114 if (!isCalledBySystemOrShell(Binder.getCallingUid())) { 1115 throw new SecurityException("Caller not allowed to bypass staged installer check"); 1116 } 1117 mBypassNextStagedInstallerCheck = value; 1118 } 1119 1120 @Override bypassNextAllowedApexUpdateCheck(boolean value)1121 public void bypassNextAllowedApexUpdateCheck(boolean value) { 1122 if (!isCalledBySystemOrShell(Binder.getCallingUid())) { 1123 throw new SecurityException("Caller not allowed to bypass allowed apex update check"); 1124 } 1125 mBypassNextAllowedApexUpdateCheck = value; 1126 } 1127 1128 /** 1129 * Set an installer to allow for the unlimited silent updates. 1130 */ 1131 @Override setAllowUnlimitedSilentUpdates(@ullable String installerPackageName)1132 public void setAllowUnlimitedSilentUpdates(@Nullable String installerPackageName) { 1133 if (!isCalledBySystemOrShell(Binder.getCallingUid())) { 1134 throw new SecurityException("Caller not allowed to unlimite silent updates"); 1135 } 1136 mSilentUpdatePolicy.setAllowUnlimitedSilentUpdates(installerPackageName); 1137 } 1138 1139 /** 1140 * Set the silent updates throttle time in seconds. 1141 */ 1142 @Override setSilentUpdatesThrottleTime(long throttleTimeInSeconds)1143 public void setSilentUpdatesThrottleTime(long throttleTimeInSeconds) { 1144 if (!isCalledBySystemOrShell(Binder.getCallingUid())) { 1145 throw new SecurityException("Caller not allowed to set silent updates throttle time"); 1146 } 1147 mSilentUpdatePolicy.setSilentUpdatesThrottleTime(throttleTimeInSeconds); 1148 } 1149 getSessionCount(SparseArray<PackageInstallerSession> sessions, int installerUid)1150 private static int getSessionCount(SparseArray<PackageInstallerSession> sessions, 1151 int installerUid) { 1152 int count = 0; 1153 final int size = sessions.size(); 1154 for (int i = 0; i < size; i++) { 1155 final PackageInstallerSession session = sessions.valueAt(i); 1156 if (session.getInstallerUid() == installerUid) { 1157 count++; 1158 } 1159 } 1160 return count; 1161 } 1162 isCallingUidOwner(PackageInstallerSession session)1163 private boolean isCallingUidOwner(PackageInstallerSession session) { 1164 final int callingUid = Binder.getCallingUid(); 1165 if (callingUid == Process.ROOT_UID) { 1166 return true; 1167 } else { 1168 return (session != null) && (callingUid == session.getInstallerUid()); 1169 } 1170 } 1171 1172 static class PackageDeleteObserverAdapter extends PackageDeleteObserver { 1173 private final Context mContext; 1174 private final IntentSender mTarget; 1175 private final String mPackageName; 1176 private final Notification mNotification; 1177 PackageDeleteObserverAdapter(Context context, IntentSender target, String packageName, boolean showNotification, int userId)1178 public PackageDeleteObserverAdapter(Context context, IntentSender target, 1179 String packageName, boolean showNotification, int userId) { 1180 mContext = context; 1181 mTarget = target; 1182 mPackageName = packageName; 1183 if (showNotification) { 1184 mNotification = buildSuccessNotification(mContext, 1185 mContext.getResources().getString(R.string.package_deleted_device_owner), 1186 packageName, 1187 userId); 1188 } else { 1189 mNotification = null; 1190 } 1191 } 1192 1193 @Override onUserActionRequired(Intent intent)1194 public void onUserActionRequired(Intent intent) { 1195 if (mTarget == null) { 1196 return; 1197 } 1198 final Intent fillIn = new Intent(); 1199 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName); 1200 fillIn.putExtra(PackageInstaller.EXTRA_STATUS, 1201 PackageInstaller.STATUS_PENDING_USER_ACTION); 1202 fillIn.putExtra(Intent.EXTRA_INTENT, intent); 1203 try { 1204 mTarget.sendIntent(mContext, 0, fillIn, null, null); 1205 } catch (SendIntentException ignored) { 1206 } 1207 } 1208 1209 @Override onPackageDeleted(String basePackageName, int returnCode, String msg)1210 public void onPackageDeleted(String basePackageName, int returnCode, String msg) { 1211 if (PackageManager.DELETE_SUCCEEDED == returnCode && mNotification != null) { 1212 NotificationManager notificationManager = (NotificationManager) 1213 mContext.getSystemService(Context.NOTIFICATION_SERVICE); 1214 notificationManager.notify(basePackageName, 1215 SystemMessage.NOTE_PACKAGE_STATE, 1216 mNotification); 1217 } 1218 if (mTarget == null) { 1219 return; 1220 } 1221 final Intent fillIn = new Intent(); 1222 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName); 1223 fillIn.putExtra(PackageInstaller.EXTRA_STATUS, 1224 PackageManager.deleteStatusToPublicStatus(returnCode)); 1225 fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, 1226 PackageManager.deleteStatusToString(returnCode, msg)); 1227 fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode); 1228 try { 1229 mTarget.sendIntent(mContext, 0, fillIn, null, null); 1230 } catch (SendIntentException ignored) { 1231 } 1232 } 1233 } 1234 1235 /** 1236 * Build a notification for package installation / deletion by device owners that is shown if 1237 * the operation succeeds. 1238 */ buildSuccessNotification(Context context, String contentText, String basePackageName, int userId)1239 static Notification buildSuccessNotification(Context context, String contentText, 1240 String basePackageName, int userId) { 1241 PackageInfo packageInfo = null; 1242 try { 1243 packageInfo = AppGlobals.getPackageManager().getPackageInfo( 1244 basePackageName, PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId); 1245 } catch (RemoteException ignored) { 1246 } 1247 if (packageInfo == null || packageInfo.applicationInfo == null) { 1248 Slog.w(TAG, "Notification not built for package: " + basePackageName); 1249 return null; 1250 } 1251 PackageManager pm = context.getPackageManager(); 1252 Bitmap packageIcon = ImageUtils.buildScaledBitmap( 1253 packageInfo.applicationInfo.loadIcon(pm), 1254 context.getResources().getDimensionPixelSize( 1255 android.R.dimen.notification_large_icon_width), 1256 context.getResources().getDimensionPixelSize( 1257 android.R.dimen.notification_large_icon_height)); 1258 CharSequence packageLabel = packageInfo.applicationInfo.loadLabel(pm); 1259 return new Notification.Builder(context, SystemNotificationChannels.DEVICE_ADMIN) 1260 .setSmallIcon(R.drawable.ic_check_circle_24px) 1261 .setColor(context.getResources().getColor( 1262 R.color.system_notification_accent_color)) 1263 .setContentTitle(packageLabel) 1264 .setContentText(contentText) 1265 .setStyle(new Notification.BigTextStyle().bigText(contentText)) 1266 .setLargeIcon(packageIcon) 1267 .build(); 1268 } 1269 newArraySet(E... elements)1270 public static <E> ArraySet<E> newArraySet(E... elements) { 1271 final ArraySet<E> set = new ArraySet<E>(); 1272 if (elements != null) { 1273 set.ensureCapacity(elements.length); 1274 Collections.addAll(set, elements); 1275 } 1276 return set; 1277 } 1278 1279 private static class Callbacks extends Handler { 1280 private static final int MSG_SESSION_CREATED = 1; 1281 private static final int MSG_SESSION_BADGING_CHANGED = 2; 1282 private static final int MSG_SESSION_ACTIVE_CHANGED = 3; 1283 private static final int MSG_SESSION_PROGRESS_CHANGED = 4; 1284 private static final int MSG_SESSION_FINISHED = 5; 1285 1286 private final RemoteCallbackList<IPackageInstallerCallback> 1287 mCallbacks = new RemoteCallbackList<>(); 1288 Callbacks(Looper looper)1289 public Callbacks(Looper looper) { 1290 super(looper); 1291 } 1292 register(IPackageInstallerCallback callback, IntPredicate userCheck)1293 public void register(IPackageInstallerCallback callback, IntPredicate userCheck) { 1294 mCallbacks.register(callback, userCheck); 1295 } 1296 unregister(IPackageInstallerCallback callback)1297 public void unregister(IPackageInstallerCallback callback) { 1298 mCallbacks.unregister(callback); 1299 } 1300 1301 @Override handleMessage(Message msg)1302 public void handleMessage(Message msg) { 1303 final int userId = msg.arg2; 1304 final int n = mCallbacks.beginBroadcast(); 1305 for (int i = 0; i < n; i++) { 1306 final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i); 1307 final IntPredicate userCheck = (IntPredicate) mCallbacks.getBroadcastCookie(i); 1308 if (userCheck.test(userId)) { 1309 try { 1310 invokeCallback(callback, msg); 1311 } catch (RemoteException ignored) { 1312 } 1313 } 1314 } 1315 mCallbacks.finishBroadcast(); 1316 } 1317 invokeCallback(IPackageInstallerCallback callback, Message msg)1318 private void invokeCallback(IPackageInstallerCallback callback, Message msg) 1319 throws RemoteException { 1320 final int sessionId = msg.arg1; 1321 switch (msg.what) { 1322 case MSG_SESSION_CREATED: 1323 callback.onSessionCreated(sessionId); 1324 break; 1325 case MSG_SESSION_BADGING_CHANGED: 1326 callback.onSessionBadgingChanged(sessionId); 1327 break; 1328 case MSG_SESSION_ACTIVE_CHANGED: 1329 callback.onSessionActiveChanged(sessionId, (boolean) msg.obj); 1330 break; 1331 case MSG_SESSION_PROGRESS_CHANGED: 1332 callback.onSessionProgressChanged(sessionId, (float) msg.obj); 1333 break; 1334 case MSG_SESSION_FINISHED: 1335 callback.onSessionFinished(sessionId, (boolean) msg.obj); 1336 break; 1337 } 1338 } 1339 notifySessionCreated(int sessionId, int userId)1340 private void notifySessionCreated(int sessionId, int userId) { 1341 obtainMessage(MSG_SESSION_CREATED, sessionId, userId).sendToTarget(); 1342 } 1343 notifySessionBadgingChanged(int sessionId, int userId)1344 private void notifySessionBadgingChanged(int sessionId, int userId) { 1345 obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, userId).sendToTarget(); 1346 } 1347 notifySessionActiveChanged(int sessionId, int userId, boolean active)1348 private void notifySessionActiveChanged(int sessionId, int userId, boolean active) { 1349 obtainMessage(MSG_SESSION_ACTIVE_CHANGED, sessionId, userId, active).sendToTarget(); 1350 } 1351 notifySessionProgressChanged(int sessionId, int userId, float progress)1352 private void notifySessionProgressChanged(int sessionId, int userId, float progress) { 1353 obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, userId, progress).sendToTarget(); 1354 } 1355 notifySessionFinished(int sessionId, int userId, boolean success)1356 public void notifySessionFinished(int sessionId, int userId, boolean success) { 1357 obtainMessage(MSG_SESSION_FINISHED, sessionId, userId, success).sendToTarget(); 1358 } 1359 } 1360 dump(IndentingPrintWriter pw)1361 void dump(IndentingPrintWriter pw) { 1362 synchronized (mSessions) { 1363 pw.println("Active install sessions:"); 1364 pw.increaseIndent(); 1365 1366 List<PackageInstallerSession> finalizedSessions = new ArrayList<>(); 1367 List<PackageInstallerSession> orphanedChildSessions = new ArrayList<>(); 1368 int N = mSessions.size(); 1369 for (int i = 0; i < N; i++) { 1370 final PackageInstallerSession session = mSessions.valueAt(i); 1371 1372 final PackageInstallerSession rootSession = session.hasParentSessionId() 1373 ? getSession(session.getParentSessionId()) 1374 : session; 1375 // Do not print orphaned child sessions as active install sessions 1376 if (rootSession == null) { 1377 orphanedChildSessions.add(session); 1378 continue; 1379 } 1380 1381 // Do not print finalized staged session as active install sessions 1382 if (rootSession.isStagedAndInTerminalState()) { 1383 finalizedSessions.add(session); 1384 continue; 1385 } 1386 1387 session.dump(pw); 1388 pw.println(); 1389 } 1390 pw.println(); 1391 pw.decreaseIndent(); 1392 1393 if (!orphanedChildSessions.isEmpty()) { 1394 // Presence of orphaned sessions indicate leak in cleanup for multi-package and 1395 // should be cleaned up. 1396 pw.println("Orphaned install sessions:"); 1397 pw.increaseIndent(); 1398 N = orphanedChildSessions.size(); 1399 for (int i = 0; i < N; i++) { 1400 final PackageInstallerSession session = orphanedChildSessions.get(i); 1401 session.dump(pw); 1402 pw.println(); 1403 } 1404 pw.println(); 1405 pw.decreaseIndent(); 1406 } 1407 1408 pw.println("Finalized install sessions:"); 1409 pw.increaseIndent(); 1410 N = finalizedSessions.size(); 1411 for (int i = 0; i < N; i++) { 1412 final PackageInstallerSession session = finalizedSessions.get(i); 1413 session.dump(pw); 1414 pw.println(); 1415 } 1416 pw.println(); 1417 pw.decreaseIndent(); 1418 1419 pw.println("Historical install sessions:"); 1420 pw.increaseIndent(); 1421 N = mHistoricalSessions.size(); 1422 for (int i = 0; i < N; i++) { 1423 pw.print(mHistoricalSessions.get(i)); 1424 pw.println(); 1425 } 1426 pw.println(); 1427 pw.decreaseIndent(); 1428 1429 pw.println("Legacy install sessions:"); 1430 pw.increaseIndent(); 1431 pw.println(mLegacySessions.toString()); 1432 pw.println(); 1433 pw.decreaseIndent(); 1434 } 1435 mSilentUpdatePolicy.dump(pw); 1436 } 1437 1438 class InternalCallback { onSessionBadgingChanged(PackageInstallerSession session)1439 public void onSessionBadgingChanged(PackageInstallerSession session) { 1440 mCallbacks.notifySessionBadgingChanged(session.sessionId, session.userId); 1441 mSettingsWriteRequest.schedule(); 1442 } 1443 onSessionActiveChanged(PackageInstallerSession session, boolean active)1444 public void onSessionActiveChanged(PackageInstallerSession session, boolean active) { 1445 mCallbacks.notifySessionActiveChanged(session.sessionId, session.userId, 1446 active); 1447 } 1448 onSessionProgressChanged(PackageInstallerSession session, float progress)1449 public void onSessionProgressChanged(PackageInstallerSession session, float progress) { 1450 mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId, 1451 progress); 1452 } 1453 onStagedSessionChanged(PackageInstallerSession session)1454 public void onStagedSessionChanged(PackageInstallerSession session) { 1455 session.markUpdated(); 1456 mSettingsWriteRequest.schedule(); 1457 if (mOkToSendBroadcasts && !session.isDestroyed()) { 1458 // we don't scrub the data here as this is sent only to the installer several 1459 // privileged system packages 1460 mPm.sendSessionUpdatedBroadcast( 1461 session.generateInfoForCaller(false/*icon*/, Process.SYSTEM_UID), 1462 session.userId); 1463 } 1464 } 1465 onSessionFinished(final PackageInstallerSession session, boolean success)1466 public void onSessionFinished(final PackageInstallerSession session, boolean success) { 1467 mCallbacks.notifySessionFinished(session.sessionId, session.userId, success); 1468 1469 mInstallHandler.post(new Runnable() { 1470 @Override 1471 public void run() { 1472 if (session.isStaged() && !success) { 1473 mStagingManager.abortSession(session.mStagedSession); 1474 } 1475 synchronized (mSessions) { 1476 if (!session.isStaged() || !success) { 1477 mSessions.remove(session.sessionId); 1478 } 1479 addHistoricalSessionLocked(session); 1480 1481 final File appIconFile = buildAppIconFile(session.sessionId); 1482 if (appIconFile.exists()) { 1483 appIconFile.delete(); 1484 } 1485 1486 mSettingsWriteRequest.runNow(); 1487 } 1488 } 1489 }); 1490 } 1491 onSessionPrepared(PackageInstallerSession session)1492 public void onSessionPrepared(PackageInstallerSession session) { 1493 // We prepared the destination to write into; we want to persist 1494 // this, but it's not critical enough to block for. 1495 mSettingsWriteRequest.schedule(); 1496 } 1497 onSessionSealedBlocking(PackageInstallerSession session)1498 public void onSessionSealedBlocking(PackageInstallerSession session) { 1499 // It's very important that we block until we've recorded the 1500 // session as being sealed, since we never want to allow mutation 1501 // after sealing. 1502 mSettingsWriteRequest.runNow(); 1503 } 1504 } 1505 } 1506