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