1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.pm; 18 19 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; 20 21 import android.annotation.IntDef; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.apex.ApexInfo; 25 import android.apex.ApexInfoList; 26 import android.apex.ApexSessionInfo; 27 import android.apex.ApexSessionParams; 28 import android.apex.CompressedApexInfoList; 29 import android.apex.IApexService; 30 import android.content.pm.ApplicationInfo; 31 import android.content.pm.PackageInfo; 32 import android.content.pm.PackageInstaller; 33 import android.content.pm.PackageManager; 34 import android.content.pm.PackageParser.PackageParserException; 35 import android.content.pm.PackageParser.SigningDetails; 36 import android.content.pm.parsing.PackageInfoWithoutStateUtils; 37 import android.content.pm.parsing.ParsingPackageUtils; 38 import android.os.Binder; 39 import android.os.Environment; 40 import android.os.RemoteException; 41 import android.os.ServiceManager; 42 import android.os.Trace; 43 import android.sysprop.ApexProperties; 44 import android.util.ArrayMap; 45 import android.util.ArraySet; 46 import android.util.Singleton; 47 import android.util.Slog; 48 import android.util.SparseArray; 49 import android.util.apk.ApkSignatureVerifier; 50 51 import com.android.internal.annotations.GuardedBy; 52 import com.android.internal.annotations.VisibleForTesting; 53 import com.android.internal.util.IndentingPrintWriter; 54 import com.android.internal.util.Preconditions; 55 import com.android.server.pm.parsing.PackageParser2; 56 import com.android.server.pm.parsing.pkg.AndroidPackage; 57 import com.android.server.pm.parsing.pkg.ParsedPackage; 58 import com.android.server.utils.TimingsTraceAndSlog; 59 60 import com.google.android.collect.Lists; 61 62 import java.io.File; 63 import java.io.PrintWriter; 64 import java.lang.annotation.Retention; 65 import java.lang.annotation.RetentionPolicy; 66 import java.util.ArrayList; 67 import java.util.Collections; 68 import java.util.HashSet; 69 import java.util.List; 70 import java.util.Map; 71 import java.util.Objects; 72 import java.util.Set; 73 import java.util.concurrent.ExecutorService; 74 75 /** 76 * ApexManager class handles communications with the apex service to perform operation and queries, 77 * as well as providing caching to avoid unnecessary calls to the service. 78 */ 79 public abstract class ApexManager { 80 81 private static final String TAG = "ApexManager"; 82 83 public static final int MATCH_ACTIVE_PACKAGE = 1 << 0; 84 static final int MATCH_FACTORY_PACKAGE = 1 << 1; 85 86 private static final String VNDK_APEX_MODULE_NAME_PREFIX = "com.android.vndk."; 87 88 private static final Singleton<ApexManager> sApexManagerSingleton = 89 new Singleton<ApexManager>() { 90 @Override 91 protected ApexManager create() { 92 if (ApexProperties.updatable().orElse(false)) { 93 return new ApexManagerImpl(); 94 } else { 95 return new ApexManagerFlattenedApex(); 96 } 97 } 98 }; 99 100 /** 101 * Returns an instance of either {@link ApexManagerImpl} or {@link ApexManagerFlattenedApex} 102 * depending on whether this device supports APEX, i.e. {@link ApexProperties#updatable()} 103 * evaluates to {@code true}. 104 * @hide 105 */ getInstance()106 public static ApexManager getInstance() { 107 return sApexManagerSingleton.get(); 108 } 109 110 /** 111 * Minimal information about APEX mount points and the original APEX package they refer to. 112 * @hide 113 */ 114 public static class ActiveApexInfo { 115 @Nullable public final String apexModuleName; 116 public final File apexDirectory; 117 public final File preInstalledApexPath; 118 ActiveApexInfo(File apexDirectory, File preInstalledApexPath)119 private ActiveApexInfo(File apexDirectory, File preInstalledApexPath) { 120 this(null, apexDirectory, preInstalledApexPath); 121 } 122 ActiveApexInfo(@ullable String apexModuleName, File apexDirectory, File preInstalledApexPath)123 private ActiveApexInfo(@Nullable String apexModuleName, File apexDirectory, 124 File preInstalledApexPath) { 125 this.apexModuleName = apexModuleName; 126 this.apexDirectory = apexDirectory; 127 this.preInstalledApexPath = preInstalledApexPath; 128 } 129 ActiveApexInfo(ApexInfo apexInfo)130 private ActiveApexInfo(ApexInfo apexInfo) { 131 this( 132 apexInfo.moduleName, 133 new File(Environment.getApexDirectory() + File.separator 134 + apexInfo.moduleName), 135 new File(apexInfo.preinstalledModulePath)); 136 } 137 } 138 139 /** 140 * Returns {@link ActiveApexInfo} records relative to all active APEX packages. 141 * 142 * @hide 143 */ getActiveApexInfos()144 public abstract List<ActiveApexInfo> getActiveApexInfos(); 145 146 /** 147 * Called by package manager service to scan apex package files when device boots up. 148 * 149 * @param packageParser The package parser to support apex package parsing and caching parsed 150 * results. 151 * @param executorService An executor to support parallel package parsing. 152 */ scanApexPackagesTraced(@onNull PackageParser2 packageParser, @NonNull ExecutorService executorService)153 abstract void scanApexPackagesTraced(@NonNull PackageParser2 packageParser, 154 @NonNull ExecutorService executorService); 155 156 /** 157 * Retrieves information about an APEX package. 158 * 159 * @param packageName the package name to look for. Note that this is the package name reported 160 * in the APK container manifest (i.e. AndroidManifest.xml), which might 161 * differ from the one reported in the APEX manifest (i.e. 162 * apex_manifest.json). 163 * @param flags the type of package to return. This may match to active packages 164 * and factory (pre-installed) packages. 165 * @return a PackageInfo object with the information about the package, or null if the package 166 * is not found. 167 */ 168 @Nullable getPackageInfo(String packageName, @PackageInfoFlags int flags)169 public abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags); 170 171 /** 172 * Retrieves information about all active APEX packages. 173 * 174 * @return a List of PackageInfo object, each one containing information about a different 175 * active package. 176 */ getActivePackages()177 abstract List<PackageInfo> getActivePackages(); 178 179 /** 180 * Retrieves information about all active pre-installed APEX packages. 181 * 182 * @return a List of PackageInfo object, each one containing information about a different 183 * active pre-installed package. 184 */ getFactoryPackages()185 abstract List<PackageInfo> getFactoryPackages(); 186 187 /** 188 * Retrieves information about all inactive APEX packages. 189 * 190 * @return a List of PackageInfo object, each one containing information about a different 191 * inactive package. 192 */ getInactivePackages()193 abstract List<PackageInfo> getInactivePackages(); 194 195 /** 196 * Checks if {@code packageName} is an apex package. 197 * 198 * @param packageName package to check. 199 * @return {@code true} if {@code packageName} is an apex package. 200 */ isApexPackage(String packageName)201 abstract boolean isApexPackage(String packageName); 202 203 /** 204 * Whether the APEX package is pre-installed or not. 205 * 206 * @param packageInfo the package to check 207 * @return {@code true} if this package is pre-installed, {@code false} otherwise. 208 */ isFactory(@onNull PackageInfo packageInfo)209 public static boolean isFactory(@NonNull PackageInfo packageInfo) { 210 return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; 211 } 212 213 /** 214 * Returns the active apex package's name that contains the (apk) package. 215 * 216 * @param containedPackageName The (apk) package that might be in a apex 217 * @return the apex package's name of {@code null} if the {@code containedPackage} is not inside 218 * any apex. 219 */ 220 @Nullable getActiveApexPackageNameContainingPackage( @onNull String containedPackageName)221 public abstract String getActiveApexPackageNameContainingPackage( 222 @NonNull String containedPackageName); 223 224 /** 225 * Retrieves information about an apexd staged session i.e. the internal state used by apexd to 226 * track the different states of a session. 227 * 228 * @param sessionId the identifier of the session. 229 * @return an ApexSessionInfo object, or null if the session is not known. 230 */ 231 @Nullable getStagedSessionInfo(int sessionId)232 abstract ApexSessionInfo getStagedSessionInfo(int sessionId); 233 234 /** 235 * Returns array of all staged sessions known to apexd. 236 */ 237 @NonNull getSessions()238 abstract SparseArray<ApexSessionInfo> getSessions(); 239 240 /** 241 * Submit a staged session to apex service. This causes the apex service to perform some initial 242 * verification and accept or reject the session. Submitting a session successfully is not 243 * enough for it to be activated at the next boot, the caller needs to call 244 * {@link #markStagedSessionReady(int)}. 245 * 246 * @throws PackageManagerException if call to apexd fails 247 */ submitStagedSession(ApexSessionParams params)248 abstract ApexInfoList submitStagedSession(ApexSessionParams params) 249 throws PackageManagerException; 250 251 /** 252 * Mark a staged session previously submitted using {@code submitStagedSession} as ready to be 253 * applied at next reboot. 254 * 255 * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as ready. 256 * @throws PackageManagerException if call to apexd fails 257 */ markStagedSessionReady(int sessionId)258 abstract void markStagedSessionReady(int sessionId) throws PackageManagerException; 259 260 /** 261 * Marks a staged session as successful. 262 * 263 * <p>Only activated session can be marked as successful. 264 * 265 * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as 266 * successful. 267 */ markStagedSessionSuccessful(int sessionId)268 abstract void markStagedSessionSuccessful(int sessionId); 269 270 /** 271 * Whether the current device supports the management of APEX packages. 272 * 273 * @return true if APEX packages can be managed on this device, false otherwise. 274 */ isApexSupported()275 abstract boolean isApexSupported(); 276 277 /** 278 * Abandons the (only) active session previously submitted. 279 * 280 * @return {@code true} upon success, {@code false} if any remote exception occurs 281 */ revertActiveSessions()282 abstract boolean revertActiveSessions(); 283 284 /** 285 * Abandons the staged session with the given sessionId. Client should handle {@code false} 286 * return value carefully as failure here can leave device in inconsistent state. 287 * 288 * @return {@code true} upon success, {@code false} if any exception occurs 289 */ abortStagedSession(int sessionId)290 abstract boolean abortStagedSession(int sessionId); 291 292 /** 293 * Uninstalls given {@code apexPackage}. 294 * 295 * <p>NOTE. Device must be rebooted in order for uninstall to take effect. 296 * 297 * @param apexPackagePath package to uninstall. 298 * @return {@code true} upon successful uninstall, {@code false} otherwise. 299 */ uninstallApex(String apexPackagePath)300 abstract boolean uninstallApex(String apexPackagePath); 301 302 /** 303 * Registers an APK package as an embedded apk of apex. 304 */ registerApkInApex(AndroidPackage pkg)305 abstract void registerApkInApex(AndroidPackage pkg); 306 307 /** 308 * Reports error raised during installation of apk-in-apex. 309 * 310 * @param scanDirPath the directory of the apex inside which apk-in-apex resides. 311 * @param errorMsg the actual error that occurred when scanning the path 312 */ reportErrorWithApkInApex(String scanDirPath, String errorMsg)313 abstract void reportErrorWithApkInApex(String scanDirPath, String errorMsg); 314 315 /** 316 * Returns null if there were no errors when installing apk-in-apex inside 317 * {@param apexPackageName}, otherwise returns the error as string 318 * 319 * @param apexPackageName Package name of the apk container of apex 320 */ 321 @Nullable getApkInApexInstallError(String apexPackageName)322 abstract String getApkInApexInstallError(String apexPackageName); 323 324 /** 325 * Returns list of {@code packageName} of apks inside the given apex. 326 * @param apexPackageName Package name of the apk container of apex 327 */ getApksInApex(String apexPackageName)328 abstract List<String> getApksInApex(String apexPackageName); 329 330 /** 331 * Returns the apex module name for the given package name, if the package is an APEX. Otherwise 332 * returns {@code null}. 333 */ 334 @Nullable getApexModuleNameForPackageName(String apexPackageName)335 public abstract String getApexModuleNameForPackageName(String apexPackageName); 336 337 /** 338 * Copies the CE apex data directory for the given {@code userId} to a backup location, for use 339 * in case of rollback. 340 * 341 * @return boolean true if the snapshot was successful 342 */ snapshotCeData(int userId, int rollbackId, String apexPackageName)343 public abstract boolean snapshotCeData(int userId, int rollbackId, String apexPackageName); 344 345 /** 346 * Restores the snapshot of the CE apex data directory for the given {@code userId}. 347 * Note the snapshot will be deleted after restoration succeeded. 348 * 349 * @return boolean true if the restore was successful 350 */ restoreCeData(int userId, int rollbackId, String apexPackageName)351 public abstract boolean restoreCeData(int userId, int rollbackId, String apexPackageName); 352 353 /** 354 * Deletes snapshots of the device encrypted apex data directories for the given 355 * {@code rollbackId}. 356 * 357 * @return boolean true if the delete was successful 358 */ destroyDeSnapshots(int rollbackId)359 public abstract boolean destroyDeSnapshots(int rollbackId); 360 361 /** 362 * Deletes snapshots of the credential encrypted apex data directories for the specified user, 363 * for the given rollback id as long as the user is credential unlocked. 364 * 365 * @return boolean true if the delete was successful 366 */ destroyCeSnapshots(int userId, int rollbackId)367 public abstract boolean destroyCeSnapshots(int userId, int rollbackId); 368 369 /** 370 * Deletes snapshots of the credential encrypted apex data directories for the specified user, 371 * where the rollback id is not included in {@code retainRollbackIds} as long as the user is 372 * credential unlocked. 373 * 374 * @return boolean true if the delete was successful 375 */ destroyCeSnapshotsNotSpecified(int userId, int[] retainRollbackIds)376 public abstract boolean destroyCeSnapshotsNotSpecified(int userId, int[] retainRollbackIds); 377 378 /** 379 * Inform apexd that the boot has completed. 380 */ markBootCompleted()381 public abstract void markBootCompleted(); 382 383 /** 384 * Estimate how much storage space is needed on /data/ for decompressing apexes 385 * @param infoList List of apexes that are compressed in target build. 386 * @return Size, in bytes, the amount of space needed on /data/ 387 */ calculateSizeForCompressedApex(CompressedApexInfoList infoList)388 public abstract long calculateSizeForCompressedApex(CompressedApexInfoList infoList) 389 throws RemoteException; 390 391 /** 392 * Reserve space on /data so that apexes can be decompressed after OTA 393 * @param infoList List of apexes that are compressed in target build. 394 */ reserveSpaceForCompressedApex(CompressedApexInfoList infoList)395 public abstract void reserveSpaceForCompressedApex(CompressedApexInfoList infoList) 396 throws RemoteException; 397 398 /** 399 * Performs a non-staged install of the given {@code apexFile}. 400 */ installPackage(File apexFile, PackageParser2 packageParser)401 abstract void installPackage(File apexFile, PackageParser2 packageParser) 402 throws PackageManagerException; 403 404 /** 405 * Dumps various state information to the provided {@link PrintWriter} object. 406 * 407 * @param pw the {@link PrintWriter} object to send information to. 408 * @param packageName a {@link String} containing a package name, or {@code null}. If set, only 409 * information about that specific package will be dumped. 410 */ dump(PrintWriter pw, @Nullable String packageName)411 abstract void dump(PrintWriter pw, @Nullable String packageName); 412 413 @IntDef( 414 flag = true, 415 prefix = { "MATCH_"}, 416 value = {MATCH_ACTIVE_PACKAGE, MATCH_FACTORY_PACKAGE}) 417 @Retention(RetentionPolicy.SOURCE) 418 @interface PackageInfoFlags{} 419 420 /** 421 * An implementation of {@link ApexManager} that should be used in case device supports updating 422 * APEX packages. 423 */ 424 @VisibleForTesting 425 protected static class ApexManagerImpl extends ApexManager { 426 private final Object mLock = new Object(); 427 428 @GuardedBy("mLock") 429 private Set<ActiveApexInfo> mActiveApexInfosCache; 430 431 /** 432 * Contains the list of {@code packageName}s of apks-in-apex for given 433 * {@code apexModuleName}. See {@link #mPackageNameToApexModuleName} to understand the 434 * difference between {@code packageName} and {@code apexModuleName}. 435 */ 436 @GuardedBy("mLock") 437 private ArrayMap<String, List<String>> mApksInApex = new ArrayMap<>(); 438 439 /** 440 * Contains the list of {@code Exception}s that were raised when installing apk-in-apex 441 * inside {@code apexModuleName}. 442 */ 443 @GuardedBy("mLock") 444 private Map<String, String> mErrorWithApkInApex = new ArrayMap<>(); 445 446 @GuardedBy("mLock") 447 private List<PackageInfo> mAllPackagesCache; 448 449 /** 450 * An APEX is a file format that delivers the apex-payload wrapped in an apk container. The 451 * apk container has a reference name, called {@code packageName}, which is found inside the 452 * {@code AndroidManifest.xml}. The apex payload inside the container also has a reference 453 * name, called {@code apexModuleName}, which is found in {@code apex_manifest.json} file. 454 * 455 * {@link #mPackageNameToApexModuleName} contains the mapping from {@code packageName} of 456 * the apk container to {@code apexModuleName} of the apex-payload inside. 457 */ 458 @GuardedBy("mLock") 459 private ArrayMap<String, String> mPackageNameToApexModuleName; 460 461 /** 462 * Whether an APEX package is active or not. 463 * 464 * @param packageInfo the package to check 465 * @return {@code true} if this package is active, {@code false} otherwise. 466 */ isActive(PackageInfo packageInfo)467 private static boolean isActive(PackageInfo packageInfo) { 468 return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0; 469 } 470 471 /** 472 * Retrieve the service from ServiceManager. If the service is not running, it will be 473 * started, and this function will block until it is ready. 474 */ 475 @VisibleForTesting waitForApexService()476 protected IApexService waitForApexService() { 477 // Since apexd is a trusted platform component, synchronized calls are allowable 478 return IApexService.Stub.asInterface( 479 Binder.allowBlocking(ServiceManager.waitForService("apexservice"))); 480 } 481 482 @Override getActiveApexInfos()483 public List<ActiveApexInfo> getActiveApexInfos() { 484 final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing", 485 Trace.TRACE_TAG_APEX_MANAGER); 486 synchronized (mLock) { 487 if (mActiveApexInfosCache == null) { 488 t.traceBegin("getActiveApexInfos_noCache"); 489 try { 490 mActiveApexInfosCache = new ArraySet<>(); 491 final ApexInfo[] activePackages = waitForApexService().getActivePackages(); 492 for (int i = 0; i < activePackages.length; i++) { 493 ApexInfo apexInfo = activePackages[i]; 494 mActiveApexInfosCache.add(new ActiveApexInfo(apexInfo)); 495 } 496 } catch (RemoteException e) { 497 Slog.e(TAG, "Unable to retrieve packages from apexservice", e); 498 } 499 t.traceEnd(); 500 } 501 if (mActiveApexInfosCache != null) { 502 return new ArrayList<>(mActiveApexInfosCache); 503 } else { 504 return Collections.emptyList(); 505 } 506 } 507 } 508 509 @Override scanApexPackagesTraced(@onNull PackageParser2 packageParser, @NonNull ExecutorService executorService)510 void scanApexPackagesTraced(@NonNull PackageParser2 packageParser, 511 @NonNull ExecutorService executorService) { 512 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanApexPackagesTraced"); 513 try { 514 synchronized (mLock) { 515 scanApexPackagesInternalLocked(packageParser, executorService); 516 } 517 } finally { 518 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 519 } 520 } 521 522 @GuardedBy("mLock") scanApexPackagesInternalLocked(PackageParser2 packageParser, ExecutorService executorService)523 private void scanApexPackagesInternalLocked(PackageParser2 packageParser, 524 ExecutorService executorService) { 525 final ApexInfo[] allPkgs; 526 try { 527 mAllPackagesCache = new ArrayList<>(); 528 mPackageNameToApexModuleName = new ArrayMap<>(); 529 allPkgs = waitForApexService().getAllPackages(); 530 } catch (RemoteException re) { 531 Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString()); 532 throw new RuntimeException(re); 533 } 534 if (allPkgs.length == 0) { 535 return; 536 } 537 final int flags = PackageManager.GET_META_DATA 538 | PackageManager.GET_SIGNING_CERTIFICATES 539 | PackageManager.GET_SIGNATURES; 540 ArrayMap<File, ApexInfo> parsingApexInfo = new ArrayMap<>(); 541 ParallelPackageParser parallelPackageParser = 542 new ParallelPackageParser(packageParser, executorService); 543 544 for (ApexInfo ai : allPkgs) { 545 File apexFile = new File(ai.modulePath); 546 parallelPackageParser.submit(apexFile, 547 ParsingPackageUtils.PARSE_COLLECT_CERTIFICATES); 548 parsingApexInfo.put(apexFile, ai); 549 } 550 551 HashSet<String> activePackagesSet = new HashSet<>(); 552 HashSet<String> factoryPackagesSet = new HashSet<>(); 553 // Process results one by one 554 for (int i = 0; i < parsingApexInfo.size(); i++) { 555 ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take(); 556 Throwable throwable = parseResult.throwable; 557 ApexInfo ai = parsingApexInfo.get(parseResult.scanFile); 558 559 if (throwable == null) { 560 final PackageInfo packageInfo = PackageInfoWithoutStateUtils.generate( 561 parseResult.parsedPackage, ai, flags); 562 if (packageInfo == null) { 563 throw new IllegalStateException("Unable to generate package info: " 564 + ai.modulePath); 565 } 566 mAllPackagesCache.add(packageInfo); 567 mPackageNameToApexModuleName.put(packageInfo.packageName, ai.moduleName); 568 if (ai.isActive) { 569 if (activePackagesSet.contains(packageInfo.packageName)) { 570 throw new IllegalStateException( 571 "Two active packages have the same name: " 572 + packageInfo.packageName); 573 } 574 activePackagesSet.add(packageInfo.packageName); 575 } 576 if (ai.isFactory) { 577 // Don't throw when the duplicating APEX is VNDK APEX 578 if (factoryPackagesSet.contains(packageInfo.packageName) 579 && !ai.moduleName.startsWith(VNDK_APEX_MODULE_NAME_PREFIX)) { 580 throw new IllegalStateException( 581 "Two factory packages have the same name: " 582 + packageInfo.packageName); 583 } 584 factoryPackagesSet.add(packageInfo.packageName); 585 } 586 } else if (throwable instanceof PackageParserException) { 587 final PackageParserException e = (PackageParserException) throwable; 588 // Skip parsing non-coreApp apex file if system is in minimal boot state. 589 if (e.error == PackageManager.INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED) { 590 Slog.w(TAG, "Scan apex failed, not a coreApp:" + ai.modulePath); 591 continue; 592 } 593 throw new IllegalStateException("Unable to parse: " + ai.modulePath, throwable); 594 } else { 595 throw new IllegalStateException("Unexpected exception occurred while parsing " 596 + ai.modulePath, throwable); 597 } 598 } 599 } 600 601 @Override 602 @Nullable getPackageInfo(String packageName, @PackageInfoFlags int flags)603 public PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags) { 604 synchronized (mLock) { 605 Preconditions.checkState(mAllPackagesCache != null, 606 "APEX packages have not been scanned"); 607 boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0; 608 boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0; 609 for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) { 610 final PackageInfo packageInfo = mAllPackagesCache.get(i); 611 if (!packageInfo.packageName.equals(packageName)) { 612 continue; 613 } 614 if ((matchActive && isActive(packageInfo)) 615 || (matchFactory && isFactory(packageInfo))) { 616 return packageInfo; 617 } 618 } 619 return null; 620 } 621 } 622 623 @Override getActivePackages()624 List<PackageInfo> getActivePackages() { 625 synchronized (mLock) { 626 Preconditions.checkState(mAllPackagesCache != null, 627 "APEX packages have not been scanned"); 628 final List<PackageInfo> activePackages = new ArrayList<>(); 629 for (int i = 0; i < mAllPackagesCache.size(); i++) { 630 final PackageInfo packageInfo = mAllPackagesCache.get(i); 631 if (isActive(packageInfo)) { 632 activePackages.add(packageInfo); 633 } 634 } 635 return activePackages; 636 } 637 } 638 639 @Override getFactoryPackages()640 List<PackageInfo> getFactoryPackages() { 641 synchronized (mLock) { 642 Preconditions.checkState(mAllPackagesCache != null, 643 "APEX packages have not been scanned"); 644 final List<PackageInfo> factoryPackages = new ArrayList<>(); 645 for (int i = 0; i < mAllPackagesCache.size(); i++) { 646 final PackageInfo packageInfo = mAllPackagesCache.get(i); 647 if (isFactory(packageInfo)) { 648 factoryPackages.add(packageInfo); 649 } 650 } 651 return factoryPackages; 652 } 653 } 654 655 @Override getInactivePackages()656 List<PackageInfo> getInactivePackages() { 657 synchronized (mLock) { 658 Preconditions.checkState(mAllPackagesCache != null, 659 "APEX packages have not been scanned"); 660 final List<PackageInfo> inactivePackages = new ArrayList<>(); 661 for (int i = 0; i < mAllPackagesCache.size(); i++) { 662 final PackageInfo packageInfo = mAllPackagesCache.get(i); 663 if (!isActive(packageInfo)) { 664 inactivePackages.add(packageInfo); 665 } 666 } 667 return inactivePackages; 668 } 669 } 670 671 @Override isApexPackage(String packageName)672 boolean isApexPackage(String packageName) { 673 if (!isApexSupported()) return false; 674 synchronized (mLock) { 675 Preconditions.checkState(mAllPackagesCache != null, 676 "APEX packages have not been scanned"); 677 for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) { 678 final PackageInfo packageInfo = mAllPackagesCache.get(i); 679 if (packageInfo.packageName.equals(packageName)) { 680 return true; 681 } 682 } 683 } 684 return false; 685 } 686 687 @Override 688 @Nullable getActiveApexPackageNameContainingPackage(String containedPackageName)689 public String getActiveApexPackageNameContainingPackage(String containedPackageName) { 690 Objects.requireNonNull(containedPackageName); 691 synchronized (mLock) { 692 Preconditions.checkState(mPackageNameToApexModuleName != null, 693 "APEX packages have not been scanned"); 694 int numApksInApex = mApksInApex.size(); 695 for (int apkInApexNum = 0; apkInApexNum < numApksInApex; apkInApexNum++) { 696 if (mApksInApex.valueAt(apkInApexNum).contains(containedPackageName)) { 697 String apexModuleName = mApksInApex.keyAt(apkInApexNum); 698 699 int numApexPkgs = mPackageNameToApexModuleName.size(); 700 for (int apexPkgNum = 0; apexPkgNum < numApexPkgs; apexPkgNum++) { 701 if (mPackageNameToApexModuleName.valueAt(apexPkgNum).equals( 702 apexModuleName)) { 703 return mPackageNameToApexModuleName.keyAt(apexPkgNum); 704 } 705 } 706 } 707 } 708 } 709 710 return null; 711 } 712 713 @Override getStagedSessionInfo(int sessionId)714 @Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) { 715 try { 716 ApexSessionInfo apexSessionInfo = 717 waitForApexService().getStagedSessionInfo(sessionId); 718 if (apexSessionInfo.isUnknown) { 719 return null; 720 } 721 return apexSessionInfo; 722 } catch (RemoteException re) { 723 Slog.e(TAG, "Unable to contact apexservice", re); 724 throw new RuntimeException(re); 725 } 726 } 727 728 @Override getSessions()729 SparseArray<ApexSessionInfo> getSessions() { 730 try { 731 final ApexSessionInfo[] sessions = waitForApexService().getSessions(); 732 final SparseArray<ApexSessionInfo> result = new SparseArray<>(sessions.length); 733 for (int i = 0; i < sessions.length; i++) { 734 result.put(sessions[i].sessionId, sessions[i]); 735 } 736 return result; 737 } catch (RemoteException re) { 738 Slog.e(TAG, "Unable to contact apexservice", re); 739 throw new RuntimeException(re); 740 } 741 } 742 743 @Override submitStagedSession(ApexSessionParams params)744 ApexInfoList submitStagedSession(ApexSessionParams params) throws PackageManagerException { 745 try { 746 final ApexInfoList apexInfoList = new ApexInfoList(); 747 waitForApexService().submitStagedSession(params, apexInfoList); 748 return apexInfoList; 749 } catch (RemoteException re) { 750 Slog.e(TAG, "Unable to contact apexservice", re); 751 throw new RuntimeException(re); 752 } catch (Exception e) { 753 throw new PackageManagerException( 754 PackageInstaller.SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, 755 "apexd verification failed : " + e.getMessage()); 756 } 757 } 758 759 @Override markStagedSessionReady(int sessionId)760 void markStagedSessionReady(int sessionId) throws PackageManagerException { 761 try { 762 waitForApexService().markStagedSessionReady(sessionId); 763 } catch (RemoteException re) { 764 Slog.e(TAG, "Unable to contact apexservice", re); 765 throw new RuntimeException(re); 766 } catch (Exception e) { 767 throw new PackageManagerException( 768 PackageInstaller.SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, 769 "Failed to mark apexd session as ready : " + e.getMessage()); 770 } 771 } 772 773 @Override markStagedSessionSuccessful(int sessionId)774 void markStagedSessionSuccessful(int sessionId) { 775 try { 776 waitForApexService().markStagedSessionSuccessful(sessionId); 777 } catch (RemoteException re) { 778 Slog.e(TAG, "Unable to contact apexservice", re); 779 throw new RuntimeException(re); 780 } catch (Exception e) { 781 // It is fine to just log an exception in this case. APEXd will be able to recover 782 // in case markStagedSessionSuccessful fails. 783 Slog.e(TAG, "Failed to mark session " + sessionId + " as successful", e); 784 } 785 } 786 787 @Override isApexSupported()788 boolean isApexSupported() { 789 return true; 790 } 791 792 @Override revertActiveSessions()793 boolean revertActiveSessions() { 794 try { 795 waitForApexService().revertActiveSessions(); 796 return true; 797 } catch (RemoteException re) { 798 Slog.e(TAG, "Unable to contact apexservice", re); 799 return false; 800 } catch (Exception e) { 801 Slog.e(TAG, e.getMessage(), e); 802 return false; 803 } 804 } 805 806 @Override abortStagedSession(int sessionId)807 boolean abortStagedSession(int sessionId) { 808 try { 809 waitForApexService().abortStagedSession(sessionId); 810 return true; 811 } catch (Exception e) { 812 Slog.e(TAG, e.getMessage(), e); 813 return false; 814 } 815 } 816 817 @Override uninstallApex(String apexPackagePath)818 boolean uninstallApex(String apexPackagePath) { 819 try { 820 waitForApexService().unstagePackages(Collections.singletonList(apexPackagePath)); 821 return true; 822 } catch (Exception e) { 823 return false; 824 } 825 } 826 827 @Override registerApkInApex(AndroidPackage pkg)828 void registerApkInApex(AndroidPackage pkg) { 829 synchronized (mLock) { 830 for (ActiveApexInfo aai : mActiveApexInfosCache) { 831 if (pkg.getBaseApkPath().startsWith( 832 aai.apexDirectory.getAbsolutePath() + File.separator)) { 833 List<String> apks = mApksInApex.get(aai.apexModuleName); 834 if (apks == null) { 835 apks = Lists.newArrayList(); 836 mApksInApex.put(aai.apexModuleName, apks); 837 } 838 Slog.i(TAG, "Registering " + pkg.getPackageName() + " as apk-in-apex of " 839 + aai.apexModuleName); 840 apks.add(pkg.getPackageName()); 841 } 842 } 843 } 844 } 845 846 @Override reportErrorWithApkInApex(String scanDirPath, String errorMsg)847 void reportErrorWithApkInApex(String scanDirPath, String errorMsg) { 848 synchronized (mLock) { 849 for (ActiveApexInfo aai : mActiveApexInfosCache) { 850 if (scanDirPath.startsWith(aai.apexDirectory.getAbsolutePath())) { 851 mErrorWithApkInApex.put(aai.apexModuleName, errorMsg); 852 } 853 } 854 } 855 } 856 857 @Override 858 @Nullable getApkInApexInstallError(String apexPackageName)859 String getApkInApexInstallError(String apexPackageName) { 860 synchronized (mLock) { 861 Preconditions.checkState(mPackageNameToApexModuleName != null, 862 "APEX packages have not been scanned"); 863 String moduleName = mPackageNameToApexModuleName.get(apexPackageName); 864 if (moduleName == null) { 865 return null; 866 } 867 return mErrorWithApkInApex.get(moduleName); 868 } 869 } 870 871 @Override getApksInApex(String apexPackageName)872 List<String> getApksInApex(String apexPackageName) { 873 synchronized (mLock) { 874 Preconditions.checkState(mPackageNameToApexModuleName != null, 875 "APEX packages have not been scanned"); 876 String moduleName = mPackageNameToApexModuleName.get(apexPackageName); 877 if (moduleName == null) { 878 return Collections.emptyList(); 879 } 880 return mApksInApex.getOrDefault(moduleName, Collections.emptyList()); 881 } 882 } 883 884 @Override 885 @Nullable getApexModuleNameForPackageName(String apexPackageName)886 public String getApexModuleNameForPackageName(String apexPackageName) { 887 synchronized (mLock) { 888 Preconditions.checkState(mPackageNameToApexModuleName != null, 889 "APEX packages have not been scanned"); 890 return mPackageNameToApexModuleName.get(apexPackageName); 891 } 892 } 893 894 @Override snapshotCeData(int userId, int rollbackId, String apexPackageName)895 public boolean snapshotCeData(int userId, int rollbackId, String apexPackageName) { 896 String apexModuleName; 897 synchronized (mLock) { 898 Preconditions.checkState(mPackageNameToApexModuleName != null, 899 "APEX packages have not been scanned"); 900 apexModuleName = mPackageNameToApexModuleName.get(apexPackageName); 901 } 902 if (apexModuleName == null) { 903 Slog.e(TAG, "Invalid apex package name: " + apexPackageName); 904 return false; 905 } 906 try { 907 waitForApexService().snapshotCeData(userId, rollbackId, apexModuleName); 908 return true; 909 } catch (Exception e) { 910 Slog.e(TAG, e.getMessage(), e); 911 return false; 912 } 913 } 914 915 @Override restoreCeData(int userId, int rollbackId, String apexPackageName)916 public boolean restoreCeData(int userId, int rollbackId, String apexPackageName) { 917 String apexModuleName; 918 synchronized (mLock) { 919 Preconditions.checkState(mPackageNameToApexModuleName != null, 920 "APEX packages have not been scanned"); 921 apexModuleName = mPackageNameToApexModuleName.get(apexPackageName); 922 } 923 if (apexModuleName == null) { 924 Slog.e(TAG, "Invalid apex package name: " + apexPackageName); 925 return false; 926 } 927 try { 928 waitForApexService().restoreCeData(userId, rollbackId, apexModuleName); 929 return true; 930 } catch (Exception e) { 931 Slog.e(TAG, e.getMessage(), e); 932 return false; 933 } 934 } 935 936 @Override destroyDeSnapshots(int rollbackId)937 public boolean destroyDeSnapshots(int rollbackId) { 938 try { 939 waitForApexService().destroyDeSnapshots(rollbackId); 940 return true; 941 } catch (Exception e) { 942 Slog.e(TAG, e.getMessage(), e); 943 return false; 944 } 945 } 946 947 @Override destroyCeSnapshots(int userId, int rollbackId)948 public boolean destroyCeSnapshots(int userId, int rollbackId) { 949 try { 950 waitForApexService().destroyCeSnapshots(userId, rollbackId); 951 return true; 952 } catch (Exception e) { 953 Slog.e(TAG, e.getMessage(), e); 954 return false; 955 } 956 } 957 958 @Override destroyCeSnapshotsNotSpecified(int userId, int[] retainRollbackIds)959 public boolean destroyCeSnapshotsNotSpecified(int userId, int[] retainRollbackIds) { 960 try { 961 waitForApexService().destroyCeSnapshotsNotSpecified(userId, retainRollbackIds); 962 return true; 963 } catch (Exception e) { 964 Slog.e(TAG, e.getMessage(), e); 965 return false; 966 } 967 } 968 969 @Override markBootCompleted()970 public void markBootCompleted() { 971 try { 972 waitForApexService().markBootCompleted(); 973 } catch (RemoteException re) { 974 Slog.e(TAG, "Unable to contact apexservice", re); 975 } 976 } 977 978 @Override calculateSizeForCompressedApex(CompressedApexInfoList infoList)979 public long calculateSizeForCompressedApex(CompressedApexInfoList infoList) 980 throws RemoteException { 981 return waitForApexService().calculateSizeForCompressedApex(infoList); 982 } 983 984 @Override reserveSpaceForCompressedApex(CompressedApexInfoList infoList)985 public void reserveSpaceForCompressedApex(CompressedApexInfoList infoList) 986 throws RemoteException { 987 waitForApexService().reserveSpaceForCompressedApex(infoList); 988 } 989 getSigningDetails(PackageInfo pkg)990 private SigningDetails getSigningDetails(PackageInfo pkg) throws PackageManagerException { 991 int minSignatureScheme = 992 ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk( 993 pkg.applicationInfo.targetSdkVersion); 994 try { 995 return ApkSignatureVerifier.verify(pkg.applicationInfo.sourceDir, 996 minSignatureScheme); 997 } catch (PackageParserException e) { 998 throw PackageManagerException.from(e); 999 } 1000 } 1001 checkApexSignature(PackageInfo existingApexPkg, PackageInfo newApexPkg)1002 private void checkApexSignature(PackageInfo existingApexPkg, PackageInfo newApexPkg) 1003 throws PackageManagerException { 1004 final SigningDetails existingSigningDetails = getSigningDetails(existingApexPkg); 1005 final SigningDetails newSigningDetails = getSigningDetails(newApexPkg); 1006 if (!newSigningDetails.checkCapability(existingSigningDetails, 1007 SigningDetails.CertCapabilities.INSTALLED_DATA)) { 1008 throw new PackageManagerException(PackageManager.INSTALL_FAILED_BAD_SIGNATURE, 1009 "APK container signature of " + newApexPkg.applicationInfo.sourceDir 1010 + " is not compatible with currently installed on device"); 1011 } 1012 } 1013 checkDowngrade(PackageInfo existingApexPkg, PackageInfo newApexPkg)1014 private void checkDowngrade(PackageInfo existingApexPkg, PackageInfo newApexPkg) 1015 throws PackageManagerException { 1016 final long currentVersionCode = existingApexPkg.applicationInfo.longVersionCode; 1017 final long newVersionCode = newApexPkg.applicationInfo.longVersionCode; 1018 if (currentVersionCode > newVersionCode) { 1019 throw new PackageManagerException(PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE, 1020 "Downgrade of APEX package " + newApexPkg.packageName 1021 + " is not allowed"); 1022 } 1023 } 1024 1025 @Override installPackage(File apexFile, PackageParser2 packageParser)1026 void installPackage(File apexFile, PackageParser2 packageParser) 1027 throws PackageManagerException { 1028 try { 1029 final int flags = PackageManager.GET_META_DATA 1030 | PackageManager.GET_SIGNING_CERTIFICATES 1031 | PackageManager.GET_SIGNATURES; 1032 final ParsedPackage parsedPackage = packageParser.parsePackage( 1033 apexFile, flags, /* useCaches= */ false); 1034 final PackageInfo newApexPkg = PackageInfoWithoutStateUtils.generate(parsedPackage, 1035 /* apexInfo= */ null, flags); 1036 if (newApexPkg == null) { 1037 throw new PackageManagerException(PackageManager.INSTALL_FAILED_INVALID_APK, 1038 "Failed to generate package info for " + apexFile.getAbsolutePath()); 1039 } 1040 final PackageInfo existingApexPkg = getPackageInfo(newApexPkg.packageName, 1041 MATCH_ACTIVE_PACKAGE); 1042 if (existingApexPkg == null) { 1043 Slog.w(TAG, "Attempting to install new APEX package " + newApexPkg.packageName); 1044 throw new PackageManagerException(PackageManager.INSTALL_FAILED_PACKAGE_CHANGED, 1045 "It is forbidden to install new APEX packages"); 1046 } 1047 checkApexSignature(existingApexPkg, newApexPkg); 1048 checkDowngrade(existingApexPkg, newApexPkg); 1049 ApexInfo apexInfo = waitForApexService().installAndActivatePackage( 1050 apexFile.getAbsolutePath()); 1051 final ParsedPackage parsedPackage2 = packageParser.parsePackage( 1052 new File(apexInfo.modulePath), flags, /* useCaches= */ false); 1053 final PackageInfo finalApexPkg = PackageInfoWithoutStateUtils.generate( 1054 parsedPackage2, apexInfo, flags); 1055 // Installation was successful, time to update mAllPackagesCache 1056 synchronized (mLock) { 1057 if (isFactory(existingApexPkg)) { 1058 existingApexPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED; 1059 mAllPackagesCache.add(finalApexPkg); 1060 } else { 1061 for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) { 1062 if (mAllPackagesCache.get(i).equals(existingApexPkg)) { 1063 mAllPackagesCache.set(i, finalApexPkg); 1064 break; 1065 } 1066 } 1067 } 1068 } 1069 } catch (RemoteException e) { 1070 throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, 1071 "apexservice not available"); 1072 } catch (Exception e) { 1073 // TODO(b/187864524): is INSTALL_FAILED_INTERNAL_ERROR is the right error code here? 1074 throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, 1075 e.getMessage()); 1076 } 1077 } 1078 1079 /** 1080 * Dump information about the packages contained in a particular cache 1081 * @param packagesCache the cache to print information about. 1082 * @param packageName a {@link String} containing a package name, or {@code null}. If set, 1083 * only information about that specific package will be dumped. 1084 * @param ipw the {@link IndentingPrintWriter} object to send information to. 1085 */ dumpFromPackagesCache( List<PackageInfo> packagesCache, @Nullable String packageName, IndentingPrintWriter ipw)1086 void dumpFromPackagesCache( 1087 List<PackageInfo> packagesCache, 1088 @Nullable String packageName, 1089 IndentingPrintWriter ipw) { 1090 ipw.println(); 1091 ipw.increaseIndent(); 1092 for (int i = 0, size = packagesCache.size(); i < size; i++) { 1093 final PackageInfo pi = packagesCache.get(i); 1094 if (packageName != null && !packageName.equals(pi.packageName)) { 1095 continue; 1096 } 1097 ipw.println(pi.packageName); 1098 ipw.increaseIndent(); 1099 ipw.println("Version: " + pi.versionCode); 1100 ipw.println("Path: " + pi.applicationInfo.sourceDir); 1101 ipw.println("IsActive: " + isActive(pi)); 1102 ipw.println("IsFactory: " + isFactory(pi)); 1103 ipw.decreaseIndent(); 1104 } 1105 ipw.decreaseIndent(); 1106 ipw.println(); 1107 } 1108 1109 @Override dump(PrintWriter pw, @Nullable String packageName)1110 void dump(PrintWriter pw, @Nullable String packageName) { 1111 final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); 1112 try { 1113 ipw.println(); 1114 ipw.println("APEX session state:"); 1115 ipw.increaseIndent(); 1116 final ApexSessionInfo[] sessions = waitForApexService().getSessions(); 1117 for (ApexSessionInfo si : sessions) { 1118 ipw.println("Session ID: " + si.sessionId); 1119 ipw.increaseIndent(); 1120 if (si.isUnknown) { 1121 ipw.println("State: UNKNOWN"); 1122 } else if (si.isVerified) { 1123 ipw.println("State: VERIFIED"); 1124 } else if (si.isStaged) { 1125 ipw.println("State: STAGED"); 1126 } else if (si.isActivated) { 1127 ipw.println("State: ACTIVATED"); 1128 } else if (si.isActivationFailed) { 1129 ipw.println("State: ACTIVATION FAILED"); 1130 } else if (si.isSuccess) { 1131 ipw.println("State: SUCCESS"); 1132 } else if (si.isRevertInProgress) { 1133 ipw.println("State: REVERT IN PROGRESS"); 1134 } else if (si.isReverted) { 1135 ipw.println("State: REVERTED"); 1136 } else if (si.isRevertFailed) { 1137 ipw.println("State: REVERT FAILED"); 1138 } 1139 ipw.decreaseIndent(); 1140 } 1141 ipw.decreaseIndent(); 1142 ipw.println(); 1143 synchronized (mLock) { 1144 if (mAllPackagesCache == null) { 1145 ipw.println("APEX packages have not been scanned"); 1146 return; 1147 } 1148 } 1149 ipw.println("Active APEX packages:"); 1150 dumpFromPackagesCache(getActivePackages(), packageName, ipw); 1151 ipw.println("Inactive APEX packages:"); 1152 dumpFromPackagesCache(getInactivePackages(), packageName, ipw); 1153 ipw.println("Factory APEX packages:"); 1154 dumpFromPackagesCache(getFactoryPackages(), packageName, ipw); 1155 } catch (RemoteException e) { 1156 ipw.println("Couldn't communicate with apexd."); 1157 } 1158 } 1159 } 1160 1161 /** 1162 * An implementation of {@link ApexManager} that should be used in case device does not support 1163 * updating APEX packages. 1164 */ 1165 private static final class ApexManagerFlattenedApex extends ApexManager { 1166 @Override getActiveApexInfos()1167 public List<ActiveApexInfo> getActiveApexInfos() { 1168 // There is no apexd running in case of flattened apex 1169 // We look up the /apex directory and identify the active APEX modules from there. 1170 // As "preinstalled" path, we just report /system since in the case of flattened APEX 1171 // the /apex directory is just a symlink to /system/apex. 1172 List<ActiveApexInfo> result = new ArrayList<>(); 1173 File apexDir = Environment.getApexDirectory(); 1174 if (apexDir.isDirectory()) { 1175 File[] files = apexDir.listFiles(); 1176 // listFiles might be null if system server doesn't have permission to read 1177 // a directory. 1178 if (files != null) { 1179 for (File file : files) { 1180 if (file.isDirectory() && !file.getName().contains("@") 1181 // In flattened configuration, init special-cases the art directory 1182 // and bind-mounts com.android.art.debug to com.android.art. 1183 && !file.getName().equals("com.android.art.debug")) { 1184 result.add(new ActiveApexInfo(file, Environment.getRootDirectory())); 1185 } 1186 } 1187 } 1188 } 1189 return result; 1190 } 1191 1192 @Override scanApexPackagesTraced(@onNull PackageParser2 packageParser, @NonNull ExecutorService executorService)1193 void scanApexPackagesTraced(@NonNull PackageParser2 packageParser, 1194 @NonNull ExecutorService executorService) { 1195 // No-op 1196 } 1197 1198 @Override getPackageInfo(String packageName, int flags)1199 public PackageInfo getPackageInfo(String packageName, int flags) { 1200 return null; 1201 } 1202 1203 @Override getActivePackages()1204 List<PackageInfo> getActivePackages() { 1205 return Collections.emptyList(); 1206 } 1207 1208 @Override getFactoryPackages()1209 List<PackageInfo> getFactoryPackages() { 1210 return Collections.emptyList(); 1211 } 1212 1213 @Override getInactivePackages()1214 List<PackageInfo> getInactivePackages() { 1215 return Collections.emptyList(); 1216 } 1217 1218 @Override isApexPackage(String packageName)1219 boolean isApexPackage(String packageName) { 1220 return false; 1221 } 1222 1223 @Override 1224 @Nullable getActiveApexPackageNameContainingPackage( @onNull String containedPackageName)1225 public String getActiveApexPackageNameContainingPackage( 1226 @NonNull String containedPackageName) { 1227 Objects.requireNonNull(containedPackageName); 1228 1229 return null; 1230 } 1231 1232 @Override getStagedSessionInfo(int sessionId)1233 ApexSessionInfo getStagedSessionInfo(int sessionId) { 1234 throw new UnsupportedOperationException(); 1235 } 1236 1237 @Override getSessions()1238 SparseArray<ApexSessionInfo> getSessions() { 1239 return new SparseArray<>(0); 1240 } 1241 1242 @Override submitStagedSession(ApexSessionParams params)1243 ApexInfoList submitStagedSession(ApexSessionParams params) 1244 throws PackageManagerException { 1245 throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, 1246 "Device doesn't support updating APEX"); 1247 } 1248 1249 @Override markStagedSessionReady(int sessionId)1250 void markStagedSessionReady(int sessionId) { 1251 throw new UnsupportedOperationException(); 1252 } 1253 1254 @Override markStagedSessionSuccessful(int sessionId)1255 void markStagedSessionSuccessful(int sessionId) { 1256 throw new UnsupportedOperationException(); 1257 } 1258 1259 @Override isApexSupported()1260 boolean isApexSupported() { 1261 return false; 1262 } 1263 1264 @Override revertActiveSessions()1265 boolean revertActiveSessions() { 1266 throw new UnsupportedOperationException(); 1267 } 1268 1269 @Override abortStagedSession(int sessionId)1270 boolean abortStagedSession(int sessionId) { 1271 throw new UnsupportedOperationException(); 1272 } 1273 1274 @Override uninstallApex(String apexPackagePath)1275 boolean uninstallApex(String apexPackagePath) { 1276 throw new UnsupportedOperationException(); 1277 } 1278 1279 @Override registerApkInApex(AndroidPackage pkg)1280 void registerApkInApex(AndroidPackage pkg) { 1281 // No-op 1282 } 1283 1284 @Override reportErrorWithApkInApex(String scanDirPath, String errorMsg)1285 void reportErrorWithApkInApex(String scanDirPath, String errorMsg) { 1286 // No-op 1287 } 1288 1289 @Override 1290 @Nullable getApkInApexInstallError(String apexPackageName)1291 String getApkInApexInstallError(String apexPackageName) { 1292 return null; 1293 } 1294 1295 @Override getApksInApex(String apexPackageName)1296 List<String> getApksInApex(String apexPackageName) { 1297 return Collections.emptyList(); 1298 } 1299 1300 @Override 1301 @Nullable getApexModuleNameForPackageName(String apexPackageName)1302 public String getApexModuleNameForPackageName(String apexPackageName) { 1303 return null; 1304 } 1305 1306 @Override snapshotCeData(int userId, int rollbackId, String apexPackageName)1307 public boolean snapshotCeData(int userId, int rollbackId, String apexPackageName) { 1308 throw new UnsupportedOperationException(); 1309 } 1310 1311 @Override restoreCeData(int userId, int rollbackId, String apexPackageName)1312 public boolean restoreCeData(int userId, int rollbackId, String apexPackageName) { 1313 throw new UnsupportedOperationException(); 1314 } 1315 1316 @Override destroyDeSnapshots(int rollbackId)1317 public boolean destroyDeSnapshots(int rollbackId) { 1318 throw new UnsupportedOperationException(); 1319 } 1320 1321 @Override destroyCeSnapshots(int userId, int rollbackId)1322 public boolean destroyCeSnapshots(int userId, int rollbackId) { 1323 return true; 1324 } 1325 1326 @Override destroyCeSnapshotsNotSpecified(int userId, int[] retainRollbackIds)1327 public boolean destroyCeSnapshotsNotSpecified(int userId, int[] retainRollbackIds) { 1328 return true; 1329 } 1330 1331 @Override markBootCompleted()1332 public void markBootCompleted() { 1333 // No-op 1334 } 1335 1336 @Override calculateSizeForCompressedApex(CompressedApexInfoList infoList)1337 public long calculateSizeForCompressedApex(CompressedApexInfoList infoList) { 1338 throw new UnsupportedOperationException(); 1339 } 1340 1341 @Override reserveSpaceForCompressedApex(CompressedApexInfoList infoList)1342 public void reserveSpaceForCompressedApex(CompressedApexInfoList infoList) { 1343 throw new UnsupportedOperationException(); 1344 } 1345 1346 @Override installPackage(File apexFile, PackageParser2 packageParser)1347 void installPackage(File apexFile, PackageParser2 packageParser) { 1348 throw new UnsupportedOperationException("APEX updates are not supported"); 1349 } 1350 1351 @Override dump(PrintWriter pw, String packageName)1352 void dump(PrintWriter pw, String packageName) { 1353 // No-op 1354 } 1355 } 1356 } 1357