1 /* 2 * Copyright (C) 2022 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; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.SuppressLint; 22 import android.apex.ApexInfo; 23 import android.apex.IApexService; 24 import android.app.compat.CompatChanges; 25 import android.app.job.JobInfo; 26 import android.app.job.JobParameters; 27 import android.app.job.JobScheduler; 28 import android.app.job.JobService; 29 import android.compat.annotation.ChangeId; 30 import android.content.BroadcastReceiver; 31 import android.content.ComponentName; 32 import android.content.Context; 33 import android.content.Intent; 34 import android.content.IntentFilter; 35 import android.content.pm.ApexStagedEvent; 36 import android.content.pm.ApplicationInfo; 37 import android.content.pm.IBackgroundInstallControlService; 38 import android.content.pm.IPackageManagerNative; 39 import android.content.pm.IStagedApexObserver; 40 import android.content.pm.InstallSourceInfo; 41 import android.content.pm.ModuleInfo; 42 import android.content.pm.PackageInfo; 43 import android.content.pm.PackageManager; 44 import android.content.pm.PackageManagerInternal; 45 import android.content.pm.ParceledListSlice; 46 import android.content.pm.SharedLibraryInfo; 47 import android.content.pm.Signature; 48 import android.content.pm.SigningDetails; 49 import android.content.pm.SigningInfo; 50 import android.content.pm.parsing.result.ParseInput; 51 import android.content.pm.parsing.result.ParseResult; 52 import android.content.pm.parsing.result.ParseTypeImpl; 53 import android.hardware.biometrics.SensorProperties; 54 import android.hardware.biometrics.SensorProperties.ComponentInfo; 55 import android.hardware.face.FaceManager; 56 import android.hardware.face.FaceSensorProperties; 57 import android.hardware.face.FaceSensorPropertiesInternal; 58 import android.hardware.face.IFaceAuthenticatorsRegisteredCallback; 59 import android.hardware.fingerprint.FingerprintManager; 60 import android.hardware.fingerprint.FingerprintSensorProperties; 61 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; 62 import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; 63 import android.net.Uri; 64 import android.os.Binder; 65 import android.os.Build; 66 import android.os.Bundle; 67 import android.os.IBinder; 68 import android.os.IRemoteCallback; 69 import android.os.RemoteException; 70 import android.os.ResultReceiver; 71 import android.os.ServiceManager; 72 import android.os.ShellCallback; 73 import android.os.ShellCommand; 74 import android.os.SystemProperties; 75 import android.os.UserHandle; 76 import android.provider.DeviceConfig; 77 import android.text.TextUtils; 78 import android.util.PackageUtils; 79 import android.util.Slog; 80 import android.util.apk.ApkSignatureVerifier; 81 import android.util.apk.ApkSigningBlockUtils; 82 83 import com.android.internal.annotations.VisibleForTesting; 84 import com.android.internal.os.IBinaryTransparencyService; 85 import com.android.internal.util.FrameworkStatsLog; 86 import com.android.modules.expresslog.Histogram; 87 import com.android.server.pm.ApexManager; 88 import com.android.server.pm.BackgroundInstallControlCallbackHelper; 89 import com.android.server.pm.BackgroundInstallControlService; 90 import com.android.server.pm.pkg.AndroidPackage; 91 import com.android.server.pm.pkg.AndroidPackageSplit; 92 import com.android.server.pm.pkg.PackageState; 93 94 import libcore.util.HexEncoding; 95 96 import java.io.FileDescriptor; 97 import java.io.PrintWriter; 98 import java.security.PublicKey; 99 import java.security.cert.CertificateException; 100 import java.util.ArrayList; 101 import java.util.List; 102 import java.util.Map; 103 import java.util.concurrent.Executors; 104 import java.util.stream.Collectors; 105 106 /** 107 * @hide 108 */ 109 public class BinaryTransparencyService extends SystemService { 110 private static final String TAG = "TransparencyService"; 111 112 @VisibleForTesting 113 static final String VBMETA_DIGEST_UNINITIALIZED = "vbmeta-digest-uninitialized"; 114 @VisibleForTesting 115 static final String VBMETA_DIGEST_UNAVAILABLE = "vbmeta-digest-unavailable"; 116 @VisibleForTesting 117 static final String SYSPROP_NAME_VBETA_DIGEST = "ro.boot.vbmeta.digest"; 118 119 @VisibleForTesting 120 static final String BINARY_HASH_ERROR = "SHA256HashError"; 121 122 static final long RECORD_MEASUREMENTS_COOLDOWN_MS = 24 * 60 * 60 * 1000; 123 124 static final String APEX_PRELOAD_LOCATION_ERROR = "could-not-be-determined"; 125 126 // Copy from the atom. Consistent for both ApexInfoGathered and MobileBundledAppInfoGathered. 127 static final int DIGEST_ALGORITHM_UNKNOWN = 0; 128 static final int DIGEST_ALGORITHM_CHUNKED_SHA256 = 1; 129 static final int DIGEST_ALGORITHM_CHUNKED_SHA512 = 2; 130 static final int DIGEST_ALGORITHM_VERITY_CHUNKED_SHA256 = 3; 131 static final int DIGEST_ALGORITHM_SHA256 = 4; 132 133 // used for indicating any type of error during MBA measurement 134 static final int MBA_STATUS_ERROR = 0; 135 // used for indicating factory condition preloads 136 static final int MBA_STATUS_PRELOADED = 1; 137 // used for indicating preloaded apps that are updated 138 static final int MBA_STATUS_UPDATED_PRELOAD = 2; 139 // used for indicating newly installed MBAs 140 static final int MBA_STATUS_NEW_INSTALL = 3; 141 // used for indicating newly installed MBAs that are updated (but unused currently) 142 static final int MBA_STATUS_UPDATED_NEW_INSTALL = 4; 143 // used for indicating preloaded MBAs that are downgraded 144 static final int MBA_STATUS_DOWNGRADED_PRELOADED = 5; 145 // used for indicating MBAs that are uninstalled 146 static final int MBA_STATUS_UNINSTALLED = 6; 147 148 @VisibleForTesting 149 static final String KEY_ENABLE_BIOMETRIC_PROPERTY_VERIFICATION = 150 "enable_biometric_property_verification"; 151 152 private static final boolean DEBUG = false; // toggle this for local debug 153 154 private static final Histogram digestAllPackagesLatency = new Histogram( 155 "binary_transparency.value_digest_all_packages_latency_uniform", 156 new Histogram.UniformOptions(50, 0, 500)); 157 158 private final Context mContext; 159 private String mVbmetaDigest; 160 // the system time (in ms) the last measurement was taken 161 private long mMeasurementsLastRecordedMs; 162 private PackageManagerInternal mPackageManagerInternal; 163 private BiometricLogger mBiometricLogger; 164 165 /** 166 * Guards whether or not measurements of MBA to be performed. When this change is enabled, 167 * measurements of MBAs are performed. But when it is disabled, only measurements of APEX 168 * and modules are done. 169 */ 170 @ChangeId 171 public static final long LOG_MBA_INFO = 245692487L; 172 173 final class BinaryTransparencyServiceImpl extends IBinaryTransparencyService.Stub { 174 175 @Override getSignedImageInfo()176 public String getSignedImageInfo() { 177 return mVbmetaDigest; 178 } 179 180 /** 181 * A helper function to compute the SHA256 digest of APK package signer. 182 * @param signingInfo The signingInfo of a package, usually {@link PackageInfo#signingInfo}. 183 * @return an array of {@code String} representing hex encoded string of the 184 * SHA256 digest of APK signer(s). The number of signers will be reflected by the 185 * size of the array. 186 * However, {@code null} is returned if there is any error. 187 */ computePackageSignerSha256Digests(@ullable SigningInfo signingInfo)188 private String[] computePackageSignerSha256Digests(@Nullable SigningInfo signingInfo) { 189 if (signingInfo == null) { 190 Slog.e(TAG, "signingInfo is null"); 191 return null; 192 } 193 194 Signature[] packageSigners = signingInfo.getApkContentsSigners(); 195 List<String> resultList = new ArrayList<>(); 196 for (Signature packageSigner : packageSigners) { 197 byte[] digest = PackageUtils.computeSha256DigestBytes(packageSigner.toByteArray()); 198 String digestHexString = HexEncoding.encodeToString(digest, false); 199 resultList.add(digestHexString); 200 } 201 return resultList.toArray(new String[1]); 202 } 203 204 /* 205 * Perform basic measurement (i.e. content digest) on a given app, including the split APKs. 206 * 207 * @param packageState The package to be measured. 208 * @param mbaStatus Assign this value of MBA status to the returned elements. 209 * @return a @{@code List<IBinaryTransparencyService.AppInfo>} 210 */ 211 @VisibleForTesting 212 @NonNull collectAppInfo( PackageState packageState, int mbaStatus)213 List<IBinaryTransparencyService.AppInfo> collectAppInfo( 214 PackageState packageState, int mbaStatus) { 215 // compute content digest 216 if (DEBUG) { 217 Slog.d(TAG, "Computing content digest for " + packageState.getPackageName() + " at " 218 + packageState.getPath()); 219 } 220 221 var results = new ArrayList<IBinaryTransparencyService.AppInfo>(); 222 223 // Same attributes across base and splits. 224 String packageName = packageState.getPackageName(); 225 long versionCode = packageState.getVersionCode(); 226 String[] signerDigests = 227 computePackageSignerSha256Digests(packageState.getSigningInfo()); 228 229 AndroidPackage pkg = packageState.getAndroidPackage(); 230 if(pkg != null) { 231 for (AndroidPackageSplit split : pkg.getSplits()) { 232 var appInfo = new IBinaryTransparencyService.AppInfo(); 233 appInfo.packageName = packageName; 234 appInfo.longVersion = versionCode; 235 appInfo.splitName = split.getName(); // base's split name is null 236 // Signer digests are consistent between splits, guaranteed by Package Manager. 237 appInfo.signerDigests = signerDigests; 238 appInfo.mbaStatus = mbaStatus; 239 240 // Only digest and split name are different between splits. 241 Digest digest = measureApk(split.getPath()); 242 appInfo.digest = digest.value(); 243 appInfo.digestAlgorithm = digest.algorithm(); 244 245 results.add(appInfo); 246 } 247 } else { 248 Slog.w(TAG, packageName + " APK file is not physically present," 249 + " skipping split and digest measurement"); 250 var appInfo = new IBinaryTransparencyService.AppInfo(); 251 appInfo.packageName = packageName; 252 appInfo.longVersion = versionCode; 253 appInfo.signerDigests = signerDigests; 254 appInfo.mbaStatus = mbaStatus; 255 results.add(appInfo); 256 } 257 258 // InstallSourceInfo is only available per package name, so store it only on the base 259 // APK. It's not current currently available in PackageState (there's a TODO), to we 260 // need to extract manually with another call. 261 // 262 // Base APK is already the 0-th split from getSplits() and can't be null. 263 AppInfo base = results.get(0); 264 InstallSourceInfo installSourceInfo = getInstallSourceInfo( 265 packageState.getPackageName()); 266 if (installSourceInfo != null) { 267 base.initiator = installSourceInfo.getInitiatingPackageName(); 268 SigningInfo initiatorSignerInfo = 269 installSourceInfo.getInitiatingPackageSigningInfo(); 270 if (initiatorSignerInfo != null) { 271 base.initiatorSignerDigests = 272 computePackageSignerSha256Digests(initiatorSignerInfo); 273 } 274 base.installer = installSourceInfo.getInstallingPackageName(); 275 base.originator = installSourceInfo.getOriginatingPackageName(); 276 } 277 278 return results; 279 } 280 281 /** 282 * Perform basic measurement (i.e. content digest) on a given APK. 283 * 284 * @param apkPath The APK (or APEX, since it's also an APK) file to be measured. 285 * @return a {@link #Digest} with preferred digest algorithm type and the value. 286 */ measureApk(@onNull String apkPath)287 private @Nullable Digest measureApk(@NonNull String apkPath) { 288 // compute content digest 289 Map<Integer, byte[]> contentDigests = computeApkContentDigest(apkPath); 290 if (contentDigests == null) { 291 Slog.d(TAG, "Failed to compute content digest for " + apkPath); 292 } else { 293 // in this iteration, we'll be supporting only 2 types of digests: 294 // CHUNKED_SHA256 and CHUNKED_SHA512. 295 // And only one of them will be available per package. 296 if (contentDigests.containsKey( 297 ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256)) { 298 return new Digest( 299 DIGEST_ALGORITHM_CHUNKED_SHA256, 300 contentDigests.get(ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256)); 301 } else if (contentDigests.containsKey( 302 ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512)) { 303 return new Digest( 304 DIGEST_ALGORITHM_CHUNKED_SHA512, 305 contentDigests.get(ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512)); 306 } 307 } 308 // When something went wrong, fall back to simple sha256. 309 byte[] digest = PackageUtils.computeSha256DigestForLargeFileAsBytes(apkPath, 310 PackageUtils.createLargeFileBuffer()); 311 return new Digest(DIGEST_ALGORITHM_SHA256, digest); 312 } 313 314 315 /** 316 * Measures and records digests for *all* covered binaries/packages. 317 * 318 * This method will be called in a Job scheduled to take measurements periodically. If the 319 * last measurement was performaned recently (less than RECORD_MEASUREMENT_COOLDOWN_MS 320 * ago), the measurement and recording will be skipped. 321 * 322 * Packages that are covered so far are: 323 * - all APEXs (introduced in Android T) 324 * - all mainline modules (introduced in Android T) 325 * - all preloaded apps and their update(s) (new in Android U) 326 * - dynamically installed mobile bundled apps (MBAs) (new in Android U) 327 */ recordMeasurementsForAllPackages()328 public void recordMeasurementsForAllPackages() { 329 // check if we should measure and record 330 long currentTimeMs = System.currentTimeMillis(); 331 if ((currentTimeMs - mMeasurementsLastRecordedMs) < RECORD_MEASUREMENTS_COOLDOWN_MS) { 332 Slog.d(TAG, "Skip measurement since the last measurement was only taken at " 333 + mMeasurementsLastRecordedMs + " within the cooldown period"); 334 return; 335 } 336 Slog.d(TAG, "Measurement was last taken at " + mMeasurementsLastRecordedMs 337 + " and is now updated to: " + currentTimeMs); 338 mMeasurementsLastRecordedMs = currentTimeMs; 339 340 Bundle packagesMeasured = new Bundle(); 341 342 // measure all APEXs first 343 if (DEBUG) { 344 Slog.d(TAG, "Measuring APEXs..."); 345 } 346 List<IBinaryTransparencyService.ApexInfo> allApexInfo = collectAllApexInfo( 347 /* includeTestOnly */ false); 348 for (IBinaryTransparencyService.ApexInfo apexInfo : allApexInfo) { 349 packagesMeasured.putBoolean(apexInfo.packageName, true); 350 351 recordApexInfo(apexInfo); 352 } 353 if (DEBUG) { 354 Slog.d(TAG, "Measured " + packagesMeasured.size() 355 + " packages after considering APEXs."); 356 } 357 358 if (!android.app.Flags.backgroundInstallControlCallbackApi()) { 359 // proceed with all preloaded apps 360 List<IBinaryTransparencyService.AppInfo> allUpdatedPreloadInfo = 361 collectAllUpdatedPreloadInfo(packagesMeasured); 362 for (IBinaryTransparencyService.AppInfo appInfo : allUpdatedPreloadInfo) { 363 packagesMeasured.putBoolean(appInfo.packageName, true); 364 writeAppInfoToLog(appInfo); 365 } 366 if (DEBUG) { 367 Slog.d(TAG, "Measured " + packagesMeasured.size() 368 + " packages after considering preloads"); 369 } 370 371 if (CompatChanges.isChangeEnabled(LOG_MBA_INFO)) { 372 // lastly measure all newly installed MBAs 373 List<IBinaryTransparencyService.AppInfo> allMbaInfo = 374 collectAllSilentInstalledMbaInfo(packagesMeasured); 375 for (IBinaryTransparencyService.AppInfo appInfo : allMbaInfo) { 376 packagesMeasured.putBoolean(appInfo.packageName, true); 377 writeAppInfoToLog(appInfo); 378 } 379 } 380 } 381 long timeSpentMeasuring = System.currentTimeMillis() - currentTimeMs; 382 digestAllPackagesLatency.logSample(timeSpentMeasuring); 383 if (DEBUG) { 384 Slog.d(TAG, "Measured " + packagesMeasured.size() 385 + " packages altogether in " + timeSpentMeasuring + "ms"); 386 } 387 } 388 389 @Override collectAllApexInfo( boolean includeTestOnly)390 public List<IBinaryTransparencyService.ApexInfo> collectAllApexInfo( 391 boolean includeTestOnly) { 392 var results = new ArrayList<IBinaryTransparencyService.ApexInfo>(); 393 for (PackageInfo packageInfo : getCurrentInstalledApexs()) { 394 PackageState packageState = mPackageManagerInternal.getPackageStateInternal( 395 packageInfo.packageName); 396 if (packageState == null) { 397 Slog.w(TAG, "Package state is unavailable, ignoring the APEX " 398 + packageInfo.packageName); 399 continue; 400 } 401 402 AndroidPackage pkg = packageState.getAndroidPackage(); 403 if (pkg == null) { 404 Slog.w(TAG, "Skipping the missing APK in " + pkg.getPath()); 405 continue; 406 } 407 Digest apexChecksum = measureApk(pkg.getPath()); 408 if (apexChecksum == null) { 409 Slog.w(TAG, "Skipping the missing APEX in " + pkg.getPath()); 410 continue; 411 } 412 413 var apexInfo = new IBinaryTransparencyService.ApexInfo(); 414 apexInfo.packageName = packageState.getPackageName(); 415 apexInfo.longVersion = packageState.getVersionCode(); 416 apexInfo.digest = apexChecksum.value(); 417 apexInfo.digestAlgorithm = apexChecksum.algorithm(); 418 apexInfo.signerDigests = 419 computePackageSignerSha256Digests(packageState.getSigningInfo()); 420 421 if (includeTestOnly) { 422 apexInfo.moduleName = apexPackageNameToModuleName( 423 packageState.getPackageName()); 424 } 425 426 results.add(apexInfo); 427 } 428 return results; 429 } 430 431 @Override collectAllUpdatedPreloadInfo( Bundle packagesToSkip)432 public List<IBinaryTransparencyService.AppInfo> collectAllUpdatedPreloadInfo( 433 Bundle packagesToSkip) { 434 final var results = new ArrayList<IBinaryTransparencyService.AppInfo>(); 435 436 PackageManager pm = mContext.getPackageManager(); 437 mPackageManagerInternal.forEachPackageState((packageState) -> { 438 if (!packageState.isUpdatedSystemApp()) { 439 return; 440 } 441 if (packagesToSkip.containsKey(packageState.getPackageName())) { 442 return; 443 } 444 445 Slog.d(TAG, "Preload " + packageState.getPackageName() + " at " 446 + packageState.getPath() + " has likely been updated."); 447 448 List<IBinaryTransparencyService.AppInfo> resultsForApp = collectAppInfo( 449 packageState, MBA_STATUS_UPDATED_PRELOAD); 450 results.addAll(resultsForApp); 451 }); 452 return results; 453 } 454 455 @Override collectAllSilentInstalledMbaInfo( Bundle packagesToSkip)456 public List<IBinaryTransparencyService.AppInfo> collectAllSilentInstalledMbaInfo( 457 Bundle packagesToSkip) { 458 var results = new ArrayList<IBinaryTransparencyService.AppInfo>(); 459 for (PackageInfo packageInfo : getNewlyInstalledMbas()) { 460 if (packagesToSkip.containsKey(packageInfo.packageName)) { 461 continue; 462 } 463 PackageState packageState = mPackageManagerInternal.getPackageStateInternal( 464 packageInfo.packageName); 465 if (packageState == null) { 466 Slog.w(TAG, "Package state is unavailable, ignoring the package " 467 + packageInfo.packageName); 468 continue; 469 } 470 471 List<IBinaryTransparencyService.AppInfo> resultsForApp = collectAppInfo( 472 packageState, MBA_STATUS_NEW_INSTALL); 473 results.addAll(resultsForApp); 474 } 475 return results; 476 } 477 recordApexInfo(IBinaryTransparencyService.ApexInfo apexInfo)478 private void recordApexInfo(IBinaryTransparencyService.ApexInfo apexInfo) { 479 // Must order by the proto's field number. 480 FrameworkStatsLog.write(FrameworkStatsLog.APEX_INFO_GATHERED, 481 apexInfo.packageName, 482 apexInfo.longVersion, 483 (apexInfo.digest != null) ? HexEncoding.encodeToString(apexInfo.digest, false) 484 : null, 485 apexInfo.digestAlgorithm, 486 apexInfo.signerDigests); 487 } 488 489 @VisibleForTesting writeAppInfoToLog(IBinaryTransparencyService.AppInfo appInfo)490 void writeAppInfoToLog(IBinaryTransparencyService.AppInfo appInfo) { 491 // Must order by the proto's field number. 492 FrameworkStatsLog.write(FrameworkStatsLog.MOBILE_BUNDLED_APP_INFO_GATHERED, 493 appInfo.packageName, 494 appInfo.longVersion, 495 (appInfo.digest != null) ? HexEncoding.encodeToString(appInfo.digest, false) 496 : null, 497 appInfo.digestAlgorithm, 498 appInfo.signerDigests, 499 appInfo.mbaStatus, 500 appInfo.initiator, 501 appInfo.initiatorSignerDigests, 502 appInfo.installer, 503 appInfo.originator, 504 appInfo.splitName); 505 } 506 507 /** 508 * A wrapper around 509 * {@link ApkSignatureVerifier#verifySignaturesInternal(ParseInput, String, int, boolean)}. 510 * @param pathToApk The APK's installation path 511 * @return a {@code Map<Integer, byte[]>} with algorithm type as the key and content 512 * digest as the value. 513 * a {@code null} is returned upon encountering any error. 514 */ computeApkContentDigest(String pathToApk)515 private Map<Integer, byte[]> computeApkContentDigest(String pathToApk) { 516 final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); 517 ParseResult<ApkSignatureVerifier.SigningDetailsWithDigests> parseResult = 518 ApkSignatureVerifier.verifySignaturesInternal(input, 519 pathToApk, 520 SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2, false); 521 if (parseResult.isError()) { 522 Slog.e(TAG, "Failed to compute content digest for " 523 + pathToApk + " due to: " 524 + parseResult.getErrorMessage()); 525 return null; 526 } 527 return parseResult.getResult().contentDigests; 528 } 529 530 @Override onShellCommand(@ullable FileDescriptor in, @Nullable FileDescriptor out, @Nullable FileDescriptor err, @NonNull String[] args, @Nullable ShellCallback callback, @NonNull ResultReceiver resultReceiver)531 public void onShellCommand(@Nullable FileDescriptor in, 532 @Nullable FileDescriptor out, 533 @Nullable FileDescriptor err, 534 @NonNull String[] args, 535 @Nullable ShellCallback callback, 536 @NonNull ResultReceiver resultReceiver) throws RemoteException { 537 (new ShellCommand() { 538 539 private int printSignedImageInfo() { 540 final PrintWriter pw = getOutPrintWriter(); 541 boolean listAllPartitions = false; 542 String opt; 543 544 while ((opt = getNextOption()) != null) { 545 switch (opt) { 546 case "-a": 547 listAllPartitions = true; 548 break; 549 default: 550 pw.println("ERROR: Unknown option: " + opt); 551 return 1; 552 } 553 } 554 555 final String signedImageInfo = getSignedImageInfo(); 556 pw.println("Image Info:"); 557 pw.println(Build.FINGERPRINT); 558 pw.println(signedImageInfo); 559 pw.println(""); 560 561 if (listAllPartitions) { 562 PackageManager pm = mContext.getPackageManager(); 563 if (pm == null) { 564 pw.println("ERROR: Failed to obtain an instance of package manager."); 565 return -1; 566 } 567 568 pw.println("Other partitions:"); 569 List<Build.Partition> buildPartitions = Build.getFingerprintedPartitions(); 570 for (Build.Partition buildPartition : buildPartitions) { 571 pw.println("Name: " + buildPartition.getName()); 572 pw.println("Fingerprint: " + buildPartition.getFingerprint()); 573 pw.println("Build time (ms): " + buildPartition.getBuildTimeMillis()); 574 } 575 } 576 return 0; 577 } 578 579 private void printPackageMeasurements(PackageInfo packageInfo, 580 boolean useSha256, 581 final PrintWriter pw) { 582 Map<Integer, byte[]> contentDigests = computeApkContentDigest( 583 packageInfo.applicationInfo.sourceDir); 584 if (contentDigests == null) { 585 pw.println("ERROR: Failed to compute package content digest for " 586 + packageInfo.applicationInfo.sourceDir); 587 return; 588 } 589 590 if (useSha256) { 591 byte[] fileBuff = PackageUtils.createLargeFileBuffer(); 592 String hexEncodedSha256Digest = 593 PackageUtils.computeSha256DigestForLargeFile( 594 packageInfo.applicationInfo.sourceDir, fileBuff); 595 pw.print(hexEncodedSha256Digest + ","); 596 } 597 598 for (Map.Entry<Integer, byte[]> entry : contentDigests.entrySet()) { 599 Integer algorithmId = entry.getKey(); 600 byte[] contentDigest = entry.getValue(); 601 602 pw.print(translateContentDigestAlgorithmIdToString(algorithmId)); 603 pw.print(":"); 604 pw.print(HexEncoding.encodeToString(contentDigest, false)); 605 pw.print("\n"); 606 } 607 } 608 609 private void printPackageInstallationInfo(PackageInfo packageInfo, 610 boolean useSha256, 611 final PrintWriter pw) { 612 pw.println("--- Package Installation Info ---"); 613 pw.println("Current install location: " 614 + packageInfo.applicationInfo.sourceDir); 615 if (packageInfo.applicationInfo.sourceDir.startsWith("/data/apex/")) { 616 String origPackageFilepath = getOriginalApexPreinstalledLocation( 617 packageInfo.packageName); 618 pw.println("|--> Pre-installed package install location: " 619 + origPackageFilepath); 620 621 if (!origPackageFilepath.equals(APEX_PRELOAD_LOCATION_ERROR)) { 622 if (useSha256) { 623 String sha256Digest = PackageUtils.computeSha256DigestForLargeFile( 624 origPackageFilepath, PackageUtils.createLargeFileBuffer()); 625 pw.println("|--> Pre-installed package SHA-256 digest: " 626 + sha256Digest); 627 } 628 629 Map<Integer, byte[]> contentDigests = computeApkContentDigest( 630 origPackageFilepath); 631 if (contentDigests == null) { 632 pw.println("|--> ERROR: Failed to compute package content digest " 633 + "for " + origPackageFilepath); 634 } else { 635 for (Map.Entry<Integer, byte[]> entry : contentDigests.entrySet()) { 636 Integer algorithmId = entry.getKey(); 637 byte[] contentDigest = entry.getValue(); 638 pw.println("|--> Pre-installed package content digest: " 639 + HexEncoding.encodeToString(contentDigest, false)); 640 pw.println("|--> Pre-installed package content digest " 641 + "algorithm: " 642 + translateContentDigestAlgorithmIdToString( 643 algorithmId)); 644 } 645 } 646 } 647 } 648 pw.println("First install time (ms): " + packageInfo.firstInstallTime); 649 pw.println("Last update time (ms): " + packageInfo.lastUpdateTime); 650 // TODO(b/261493591): Determination of whether a package is preinstalled can be 651 // made more robust 652 boolean isPreloaded = (packageInfo.firstInstallTime 653 == packageInfo.lastUpdateTime); 654 pw.println("Is preloaded: " + isPreloaded); 655 656 InstallSourceInfo installSourceInfo = getInstallSourceInfo( 657 packageInfo.packageName); 658 if (installSourceInfo == null) { 659 pw.println("ERROR: Unable to obtain installSourceInfo of " 660 + packageInfo.packageName); 661 } else { 662 pw.println("Installation initiated by: " 663 + installSourceInfo.getInitiatingPackageName()); 664 pw.println("Installation done by: " 665 + installSourceInfo.getInstallingPackageName()); 666 pw.println("Installation originating from: " 667 + installSourceInfo.getOriginatingPackageName()); 668 } 669 670 if (packageInfo.isApex) { 671 pw.println("Is an active APEX: " + packageInfo.isActiveApex); 672 } 673 } 674 675 private void printPackageSignerDetails(SigningInfo signerInfo, 676 final PrintWriter pw) { 677 if (signerInfo == null) { 678 pw.println("ERROR: Package's signingInfo is null."); 679 return; 680 } 681 pw.println("--- Package Signer Info ---"); 682 pw.println("Has multiple signers: " + signerInfo.hasMultipleSigners()); 683 pw.println("Signing key has been rotated: " 684 + signerInfo.hasPastSigningCertificates()); 685 Signature[] packageSigners = signerInfo.getApkContentsSigners(); 686 for (Signature packageSigner : packageSigners) { 687 byte[] packageSignerDigestBytes = 688 PackageUtils.computeSha256DigestBytes(packageSigner.toByteArray()); 689 String packageSignerDigestHextring = 690 HexEncoding.encodeToString(packageSignerDigestBytes, false); 691 pw.println("Signer cert's SHA256-digest: " + packageSignerDigestHextring); 692 try { 693 PublicKey publicKey = packageSigner.getPublicKey(); 694 pw.println("Signing key algorithm: " + publicKey.getAlgorithm()); 695 } catch (CertificateException e) { 696 Slog.e(TAG, 697 "Failed to obtain public key of signer for cert with hash: " 698 + packageSignerDigestHextring, e); 699 } 700 } 701 702 if (!signerInfo.hasMultipleSigners() 703 && signerInfo.hasPastSigningCertificates()) { 704 pw.println("== Signing Cert Lineage (Excluding The Most Recent) =="); 705 pw.println("(Certs are sorted in the order of rotation, beginning with the " 706 + "original signing cert)"); 707 Signature[] signingCertHistory = signerInfo.getSigningCertificateHistory(); 708 for (int i = 0; i < (signingCertHistory.length - 1); i++) { 709 Signature signature = signingCertHistory[i]; 710 byte[] signatureDigestBytes = PackageUtils.computeSha256DigestBytes( 711 signature.toByteArray()); 712 String certHashHexString = HexEncoding.encodeToString( 713 signatureDigestBytes, false); 714 pw.println(" ++ Signer cert #" + (i + 1) + " ++"); 715 pw.println(" Cert SHA256-digest: " + certHashHexString); 716 try { 717 PublicKey publicKey = signature.getPublicKey(); 718 pw.println(" Signing key algorithm: " + publicKey.getAlgorithm()); 719 } catch (CertificateException e) { 720 Slog.e(TAG, "Failed to obtain public key of signer for cert " 721 + "with hash: " + certHashHexString, e); 722 } 723 } 724 } 725 726 } 727 728 private void printModuleDetails(ModuleInfo moduleInfo, final PrintWriter pw) { 729 pw.println("--- Module Details ---"); 730 pw.println("Module name: " + moduleInfo.getName()); 731 if (!android.content.pm.Flags.removeHiddenModuleUsage()) { 732 pw.println("Module visibility: " 733 + (moduleInfo.isHidden() ? "hidden" : "visible")); 734 } 735 } 736 737 private void printAppDetails(PackageInfo packageInfo, 738 boolean printLibraries, 739 final PrintWriter pw) { 740 pw.println("--- App Details ---"); 741 pw.println("Name: " + packageInfo.applicationInfo.name); 742 pw.println("Label: " + mContext.getPackageManager().getApplicationLabel( 743 packageInfo.applicationInfo)); 744 pw.println("Description: " + packageInfo.applicationInfo.loadDescription( 745 mContext.getPackageManager())); 746 pw.println("Has code: " + packageInfo.applicationInfo.hasCode()); 747 pw.println("Is enabled: " + packageInfo.applicationInfo.enabled); 748 pw.println("Is suspended: " + ((packageInfo.applicationInfo.flags 749 & ApplicationInfo.FLAG_SUSPENDED) != 0)); 750 751 pw.println("Compile SDK version: " + packageInfo.compileSdkVersion); 752 pw.println("Target SDK version: " 753 + packageInfo.applicationInfo.targetSdkVersion); 754 755 pw.println("Is privileged: " 756 + packageInfo.applicationInfo.isPrivilegedApp()); 757 pw.println("Is a stub: " + packageInfo.isStub); 758 pw.println("Is a core app: " + packageInfo.coreApp); 759 pw.println("SEInfo: " + packageInfo.applicationInfo.seInfo); 760 pw.println("Component factory: " 761 + packageInfo.applicationInfo.appComponentFactory); 762 pw.println("Process name: " + packageInfo.applicationInfo.processName); 763 pw.println("Task affinity: " + packageInfo.applicationInfo.taskAffinity); 764 pw.println("UID: " + packageInfo.applicationInfo.uid); 765 pw.println("Shared UID: " + packageInfo.sharedUserId); 766 767 if (printLibraries) { 768 pw.println("== App's Shared Libraries =="); 769 List<SharedLibraryInfo> sharedLibraryInfos = 770 packageInfo.applicationInfo.getSharedLibraryInfos(); 771 if (sharedLibraryInfos == null || sharedLibraryInfos.isEmpty()) { 772 pw.println("<none>"); 773 } 774 775 for (int i = 0; i < sharedLibraryInfos.size(); i++) { 776 SharedLibraryInfo sharedLibraryInfo = sharedLibraryInfos.get(i); 777 pw.println(" ++ Library #" + (i + 1) + " ++"); 778 pw.println(" Lib name: " + sharedLibraryInfo.getName()); 779 long libVersion = sharedLibraryInfo.getLongVersion(); 780 pw.print(" Lib version: "); 781 if (libVersion == SharedLibraryInfo.VERSION_UNDEFINED) { 782 pw.print("undefined"); 783 } else { 784 pw.print(libVersion); 785 } 786 pw.print("\n"); 787 788 pw.println(" Lib package name (if available): " 789 + sharedLibraryInfo.getPackageName()); 790 pw.println(" Lib path: " + sharedLibraryInfo.getPath()); 791 pw.print(" Lib type: "); 792 switch (sharedLibraryInfo.getType()) { 793 case SharedLibraryInfo.TYPE_BUILTIN: 794 pw.print("built-in"); 795 break; 796 case SharedLibraryInfo.TYPE_DYNAMIC: 797 pw.print("dynamic"); 798 break; 799 case SharedLibraryInfo.TYPE_STATIC: 800 pw.print("static"); 801 break; 802 case SharedLibraryInfo.TYPE_SDK_PACKAGE: 803 pw.print("SDK"); 804 break; 805 case SharedLibraryInfo.VERSION_UNDEFINED: 806 default: 807 pw.print("undefined"); 808 break; 809 } 810 pw.print("\n"); 811 pw.println(" Is a native lib: " + sharedLibraryInfo.isNative()); 812 } 813 } 814 815 } 816 817 private void printHeadersHelper(@NonNull String packageType, 818 boolean useSha256, 819 @NonNull final PrintWriter pw) { 820 pw.print(packageType + " Info [Format: package_name,package_version,"); 821 if (useSha256) { 822 pw.print("package_sha256_digest,"); 823 } 824 pw.print("content_digest_algorithm:content_digest]:\n"); 825 } 826 827 private int printAllApexs() { 828 final PrintWriter pw = getOutPrintWriter(); 829 boolean verbose = false; 830 boolean useSha256 = false; 831 boolean printHeaders = true; 832 String opt; 833 while ((opt = getNextOption()) != null) { 834 switch (opt) { 835 case "-v": 836 case "--verbose": 837 verbose = true; 838 break; 839 case "-o": 840 case "--old": 841 useSha256 = true; 842 break; 843 case "--no-headers": 844 printHeaders = false; 845 break; 846 default: 847 pw.println("ERROR: Unknown option: " + opt); 848 return 1; 849 } 850 } 851 852 PackageManager pm = mContext.getPackageManager(); 853 if (pm == null) { 854 pw.println("ERROR: Failed to obtain an instance of package manager."); 855 return -1; 856 } 857 858 if (!verbose && printHeaders) { 859 printHeadersHelper("APEX", useSha256, pw); 860 } 861 for (PackageInfo packageInfo : getCurrentInstalledApexs()) { 862 if (verbose && printHeaders) { 863 printHeadersHelper("APEX", useSha256, pw); 864 } 865 String packageName = packageInfo.packageName; 866 pw.print(packageName + "," 867 + packageInfo.getLongVersionCode() + ","); 868 printPackageMeasurements(packageInfo, useSha256, pw); 869 870 if (verbose) { 871 ModuleInfo moduleInfo; 872 try { 873 moduleInfo = pm.getModuleInfo(packageInfo.packageName, 0); 874 pw.println("Is a module: true"); 875 printModuleDetails(moduleInfo, pw); 876 } catch (PackageManager.NameNotFoundException e) { 877 pw.println("Is a module: false"); 878 } 879 880 printPackageInstallationInfo(packageInfo, useSha256, pw); 881 printPackageSignerDetails(packageInfo.signingInfo, pw); 882 pw.println(""); 883 } 884 } 885 return 0; 886 } 887 888 private int printAllModules() { 889 final PrintWriter pw = getOutPrintWriter(); 890 boolean verbose = false; 891 boolean useSha256 = false; 892 boolean printHeaders = true; 893 String opt; 894 while ((opt = getNextOption()) != null) { 895 switch (opt) { 896 case "-v": 897 case "--verbose": 898 verbose = true; 899 break; 900 case "-o": 901 case "--old": 902 useSha256 = true; 903 break; 904 case "--no-headers": 905 printHeaders = false; 906 break; 907 default: 908 pw.println("ERROR: Unknown option: " + opt); 909 return 1; 910 } 911 } 912 913 PackageManager pm = mContext.getPackageManager(); 914 if (pm == null) { 915 pw.println("ERROR: Failed to obtain an instance of package manager."); 916 return -1; 917 } 918 919 if (!verbose && printHeaders) { 920 printHeadersHelper("Module", useSha256, pw); 921 } 922 for (ModuleInfo module : pm.getInstalledModules(PackageManager.MATCH_ALL)) { 923 String packageName = module.getPackageName(); 924 if (verbose && printHeaders) { 925 printHeadersHelper("Module", useSha256, pw); 926 } 927 try { 928 PackageInfo packageInfo = pm.getPackageInfo(packageName, 929 PackageManager.MATCH_APEX 930 | PackageManager.GET_SIGNING_CERTIFICATES); 931 pw.print(packageInfo.packageName + ","); 932 pw.print(packageInfo.getLongVersionCode() + ","); 933 printPackageMeasurements(packageInfo, useSha256, pw); 934 935 if (verbose) { 936 printModuleDetails(module, pw); 937 printPackageInstallationInfo(packageInfo, useSha256, pw); 938 printPackageSignerDetails(packageInfo.signingInfo, pw); 939 pw.println(""); 940 } 941 } catch (PackageManager.NameNotFoundException e) { 942 pw.println(packageName 943 + ",ERROR:Unable to find PackageInfo for this module."); 944 if (verbose) { 945 printModuleDetails(module, pw); 946 pw.println(""); 947 } 948 continue; 949 } 950 } 951 return 0; 952 } 953 954 private int printAllMbas() { 955 final PrintWriter pw = getOutPrintWriter(); 956 boolean verbose = false; 957 boolean printLibraries = false; 958 boolean useSha256 = false; 959 boolean printHeaders = true; 960 boolean preloadsOnly = false; 961 String opt; 962 while ((opt = getNextOption()) != null) { 963 switch (opt) { 964 case "-v": 965 case "--verbose": 966 verbose = true; 967 break; 968 case "-l": 969 printLibraries = true; 970 break; 971 case "-o": 972 case "--old": 973 useSha256 = true; 974 break; 975 case "--no-headers": 976 printHeaders = false; 977 break; 978 case "--preloads-only": 979 preloadsOnly = true; 980 break; 981 default: 982 pw.println("ERROR: Unknown option: " + opt); 983 return 1; 984 } 985 } 986 987 if (!verbose && printHeaders) { 988 if (preloadsOnly) { 989 printHeadersHelper("Preload", useSha256, pw); 990 } else { 991 printHeadersHelper("MBA", useSha256, pw); 992 } 993 } 994 995 PackageManager pm = mContext.getPackageManager(); 996 for (PackageInfo packageInfo : pm.getInstalledPackages( 997 PackageManager.PackageInfoFlags.of(PackageManager.MATCH_FACTORY_ONLY 998 | PackageManager.GET_SIGNING_CERTIFICATES))) { 999 if (packageInfo.signingInfo == null) { 1000 PackageInfo origPackageInfo = packageInfo; 1001 try { 1002 pm.getPackageInfo(packageInfo.packageName, 1003 PackageManager.PackageInfoFlags.of(PackageManager.MATCH_ALL 1004 | PackageManager.GET_SIGNING_CERTIFICATES)); 1005 } catch (PackageManager.NameNotFoundException e) { 1006 Slog.e(TAG, "Failed to obtain an updated PackageInfo of " 1007 + origPackageInfo.packageName); 1008 packageInfo = origPackageInfo; 1009 } 1010 } 1011 1012 if (verbose && printHeaders) { 1013 printHeadersHelper("Preload", useSha256, pw); 1014 } 1015 pw.print(packageInfo.packageName + ","); 1016 pw.print(packageInfo.getLongVersionCode() + ","); 1017 printPackageMeasurements(packageInfo, useSha256, pw); 1018 1019 if (verbose) { 1020 printAppDetails(packageInfo, printLibraries, pw); 1021 printPackageInstallationInfo(packageInfo, useSha256, pw); 1022 printPackageSignerDetails(packageInfo.signingInfo, pw); 1023 pw.println(""); 1024 } 1025 } 1026 1027 if (preloadsOnly) { 1028 return 0; 1029 } 1030 for (PackageInfo packageInfo : getNewlyInstalledMbas()) { 1031 if (verbose && printHeaders) { 1032 printHeadersHelper("MBA", useSha256, pw); 1033 } 1034 pw.print(packageInfo.packageName + ","); 1035 pw.print(packageInfo.getLongVersionCode() + ","); 1036 printPackageMeasurements(packageInfo, useSha256, pw); 1037 1038 if (verbose) { 1039 printAppDetails(packageInfo, printLibraries, pw); 1040 printPackageInstallationInfo(packageInfo, useSha256, pw); 1041 printPackageSignerDetails(packageInfo.signingInfo, pw); 1042 pw.println(""); 1043 } 1044 } 1045 return 0; 1046 } 1047 1048 @Override 1049 public int onCommand(String cmd) { 1050 if (cmd == null) { 1051 return handleDefaultCommands(cmd); 1052 } 1053 1054 final PrintWriter pw = getOutPrintWriter(); 1055 switch (cmd) { 1056 case "get": { 1057 final String infoType = getNextArg(); 1058 if (infoType == null) { 1059 printHelpMenu(); 1060 return -1; 1061 } 1062 1063 switch (infoType) { 1064 case "image_info": 1065 return printSignedImageInfo(); 1066 case "apex_info": 1067 return printAllApexs(); 1068 case "module_info": 1069 return printAllModules(); 1070 case "mba_info": 1071 return printAllMbas(); 1072 default: 1073 pw.println(String.format("ERROR: Unknown info type '%s'", 1074 infoType)); 1075 return 1; 1076 } 1077 } 1078 default: 1079 return handleDefaultCommands(cmd); 1080 } 1081 } 1082 1083 private void printHelpMenu() { 1084 final PrintWriter pw = getOutPrintWriter(); 1085 pw.println("Transparency manager (transparency) commands:"); 1086 pw.println(" help"); 1087 pw.println(" Print this help text."); 1088 pw.println(""); 1089 pw.println(" get image_info [-a]"); 1090 pw.println(" Print information about loaded image (firmware). Options:"); 1091 pw.println(" -a: lists all other identifiable partitions."); 1092 pw.println(""); 1093 pw.println(" get apex_info [-o] [-v] [--no-headers]"); 1094 pw.println(" Print information about installed APEXs on device."); 1095 pw.println(" -o: also uses the old digest scheme (SHA256) to compute " 1096 + "APEX hashes. WARNING: This can be a very slow and CPU-intensive " 1097 + "computation."); 1098 pw.println(" -v: lists more verbose information about each APEX."); 1099 pw.println(" --no-headers: does not print the header if specified."); 1100 pw.println(""); 1101 pw.println(" get module_info [-o] [-v] [--no-headers]"); 1102 pw.println(" Print information about installed modules on device."); 1103 pw.println(" -o: also uses the old digest scheme (SHA256) to compute " 1104 + "module hashes. WARNING: This can be a very slow and " 1105 + "CPU-intensive computation."); 1106 pw.println(" -v: lists more verbose information about each module."); 1107 pw.println(" --no-headers: does not print the header if specified."); 1108 pw.println(""); 1109 pw.println(" get mba_info [-o] [-v] [-l] [--no-headers] [--preloads-only]"); 1110 pw.println(" Print information about installed mobile bundle apps " 1111 + "(MBAs on device)."); 1112 pw.println(" -o: also uses the old digest scheme (SHA256) to compute " 1113 + "MBA hashes. WARNING: This can be a very slow and CPU-intensive " 1114 + "computation."); 1115 pw.println(" -v: lists more verbose information about each app."); 1116 pw.println(" -l: lists shared library info. (This option only works " 1117 + "when -v option is also specified)"); 1118 pw.println(" --no-headers: does not print the header if specified."); 1119 pw.println(" --preloads-only: lists only preloaded apps. This options can " 1120 + "also be combined with others."); 1121 pw.println(""); 1122 } 1123 1124 @Override 1125 public void onHelp() { 1126 printHelpMenu(); 1127 } 1128 }).exec(this, in, out, err, args, callback, resultReceiver); 1129 } 1130 } 1131 private final BinaryTransparencyServiceImpl mServiceImpl; 1132 1133 /** 1134 * A wrapper of {@link FrameworkStatsLog} for easier testing 1135 */ 1136 @VisibleForTesting 1137 public static class BiometricLogger { 1138 private static final String TAG = "BiometricLogger"; 1139 1140 private static final BiometricLogger sInstance = new BiometricLogger(); 1141 BiometricLogger()1142 private BiometricLogger() {} 1143 getInstance()1144 public static BiometricLogger getInstance() { 1145 return sInstance; 1146 } 1147 1148 /** 1149 * A wrapper of {@link FrameworkStatsLog} 1150 * 1151 * @param sensorId The sensorId of the biometric to be logged 1152 * @param modality The modality of the biometric 1153 * @param sensorType The sensor type of the biometric 1154 * @param sensorStrength The sensor strength of the biometric 1155 * @param componentId The component Id of a component of the biometric 1156 * @param hardwareVersion The hardware version of a component of the biometric 1157 * @param firmwareVersion The firmware version of a component of the biometric 1158 * @param serialNumber The serial number of a component of the biometric 1159 * @param softwareVersion The software version of a component of the biometric 1160 */ logStats(int sensorId, int modality, int sensorType, int sensorStrength, String componentId, String hardwareVersion, String firmwareVersion, String serialNumber, String softwareVersion)1161 public void logStats(int sensorId, int modality, int sensorType, int sensorStrength, 1162 String componentId, String hardwareVersion, String firmwareVersion, 1163 String serialNumber, String softwareVersion) { 1164 FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_PROPERTIES_COLLECTED, 1165 sensorId, modality, sensorType, sensorStrength, componentId, hardwareVersion, 1166 firmwareVersion, serialNumber, softwareVersion); 1167 } 1168 } 1169 BinaryTransparencyService(Context context)1170 public BinaryTransparencyService(Context context) { 1171 this(context, BiometricLogger.getInstance()); 1172 } 1173 1174 @VisibleForTesting BinaryTransparencyService(Context context, BiometricLogger biometricLogger)1175 BinaryTransparencyService(Context context, BiometricLogger biometricLogger) { 1176 super(context); 1177 mContext = context; 1178 mServiceImpl = new BinaryTransparencyServiceImpl(); 1179 mVbmetaDigest = VBMETA_DIGEST_UNINITIALIZED; 1180 mMeasurementsLastRecordedMs = 0; 1181 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); 1182 mBiometricLogger = biometricLogger; 1183 } 1184 1185 /** 1186 * Receive callbacks from BIC to write silently installed apps to log 1187 * 1188 * TODO: Add a host test for testing registration and callback of BicCallbackHandler 1189 * b/380002484 1190 */ 1191 @VisibleForTesting 1192 static class BicCallbackHandler extends IRemoteCallback.Stub { 1193 private static final String BIC_CALLBACK_HANDLER_TAG = TAG + ".BicCallbackHandler"; 1194 1195 private static final int INSTALL_EVENT_TYPE_UNSET = -1; 1196 1197 private final IBicAppInfoHelper mBicAppInfoHelper; 1198 1199 @VisibleForTesting BicCallbackHandler(IBicAppInfoHelper bicAppInfoHelper)1200 BicCallbackHandler(IBicAppInfoHelper bicAppInfoHelper) { 1201 mBicAppInfoHelper = bicAppInfoHelper; 1202 } 1203 1204 @Override sendResult(Bundle data)1205 public void sendResult(Bundle data) { 1206 String packageName = data.getString( 1207 BackgroundInstallControlCallbackHelper.FLAGGED_PACKAGE_NAME_KEY); 1208 int installType = data.getInt( 1209 BackgroundInstallControlCallbackHelper.INSTALL_EVENT_TYPE_KEY, 1210 INSTALL_EVENT_TYPE_UNSET); 1211 if (packageName == null || installType == INSTALL_EVENT_TYPE_UNSET) { 1212 Slog.w(BIC_CALLBACK_HANDLER_TAG, "Package name or install type is " 1213 + "unavailable, ignoring event"); 1214 return; 1215 } 1216 Slog.d(BIC_CALLBACK_HANDLER_TAG, "Detected new bic event for: " + packageName); 1217 if (installType == BackgroundInstallControlService.INSTALL_EVENT_TYPE_INSTALL) { 1218 PackageState packageState = LocalServices.getService(PackageManagerInternal.class) 1219 .getPackageStateInternal(packageName); 1220 if (packageState == null) { 1221 Slog.w(TAG, "Package state is unavailable, ignoring the package " 1222 + packageName); 1223 return; 1224 } 1225 int mbaStatus = MBA_STATUS_NEW_INSTALL; 1226 if (packageState.isUpdatedSystemApp()) { 1227 mbaStatus = MBA_STATUS_UPDATED_PRELOAD; 1228 } 1229 List<IBinaryTransparencyService.AppInfo> mbaInfo = mBicAppInfoHelper.collectAppInfo( 1230 packageState, mbaStatus); 1231 for (IBinaryTransparencyService.AppInfo appInfo : mbaInfo) { 1232 mBicAppInfoHelper.writeAppInfoToLog(appInfo); 1233 } 1234 } else if (installType 1235 == BackgroundInstallControlService.INSTALL_EVENT_TYPE_UNINSTALL) { 1236 IBinaryTransparencyService.AppInfo appInfo 1237 = new IBinaryTransparencyService.AppInfo(); 1238 // since app is already uninstalled we won't be able to retrieve additional 1239 // info on it. 1240 appInfo.packageName = packageName; 1241 appInfo.mbaStatus = MBA_STATUS_UNINSTALLED; 1242 mBicAppInfoHelper.writeAppInfoToLog(appInfo); 1243 } else { 1244 Slog.w(BIC_CALLBACK_HANDLER_TAG, "Unsupported BIC event: " + installType); 1245 } 1246 } 1247 1248 /** 1249 * A wrapper of interface for{@link FrameworkStatsLog and ApkDigests} 1250 * for easier testing 1251 */ 1252 @VisibleForTesting 1253 public interface IBicAppInfoHelper { 1254 1255 /** 1256 * A wrapper of {@link FrameworkStatsLog} 1257 * 1258 * @param appInfo The app info of the changed MBA to be logged 1259 */ writeAppInfoToLog(IBinaryTransparencyService.AppInfo appInfo)1260 public void writeAppInfoToLog(IBinaryTransparencyService.AppInfo appInfo); 1261 1262 /** 1263 * A wrapper of {@link BinaryTransparencyServiceImpl} 1264 * 1265 * @param packageState The packageState provided retrieved from PackageManagerInternal 1266 * @param mbaStatus The MBA status of the package 1267 */ collectAppInfo( PackageState packageState, int mbaStatus)1268 public List<IBinaryTransparencyService.AppInfo> collectAppInfo( 1269 PackageState packageState, int mbaStatus); 1270 } 1271 }; 1272 1273 /** 1274 * Called when the system service should publish a binder service using 1275 * {@link #publishBinderService(String, IBinder).} 1276 */ 1277 @Override onStart()1278 public void onStart() { 1279 try { 1280 publishBinderService(Context.BINARY_TRANSPARENCY_SERVICE, mServiceImpl); 1281 Slog.i(TAG, "Started BinaryTransparencyService"); 1282 } catch (Throwable t) { 1283 Slog.e(TAG, "Failed to start BinaryTransparencyService.", t); 1284 } 1285 } 1286 1287 /** 1288 * Called on each phase of the boot process. Phases before the service's start phase 1289 * (as defined in the @Service annotation) are never received. 1290 * 1291 * @param phase The current boot phase. 1292 */ 1293 @Override onBootPhase(int phase)1294 public void onBootPhase(int phase) { 1295 1296 // we are only interested in doing things at PHASE_BOOT_COMPLETED 1297 if (phase == PHASE_BOOT_COMPLETED) { 1298 Slog.i(TAG, "Boot completed. Getting boot integrity data."); 1299 collectBootIntegrityInfo(); 1300 1301 // Log to statsd 1302 // TODO(b/264061957): For now, biometric system properties are always collected if users 1303 // share usage & diagnostics information. In the future, collect biometric system 1304 // properties only when transparency log verification of the target partitions fails 1305 // (e.g. when the system/vendor partitions have been changed) once the binary 1306 // transparency infrastructure is ready. 1307 Slog.i(TAG, "Boot completed. Collecting biometric system properties."); 1308 collectBiometricProperties(); 1309 1310 // to avoid the risk of holding up boot time, computations to measure APEX, Module, and 1311 // MBA digests are scheduled here, but only executed when the device is idle and plugged 1312 // in. 1313 Slog.i(TAG, "Scheduling measurements to be taken."); 1314 UpdateMeasurementsJobService.scheduleBinaryMeasurements(mContext, 1315 BinaryTransparencyService.this); 1316 1317 registerAllPackageUpdateObservers(); 1318 } 1319 } 1320 1321 /** 1322 * JobService to measure all covered binaries and record results to statsd. 1323 */ 1324 public static class UpdateMeasurementsJobService extends JobService { 1325 private static long sTimeLastRanMs = 0; 1326 private static final int DO_BINARY_MEASUREMENTS_JOB_ID = 1740526926; 1327 1328 @Override onStartJob(JobParameters params)1329 public boolean onStartJob(JobParameters params) { 1330 Slog.d(TAG, "Job to update binary measurements started."); 1331 if (params.getJobId() != DO_BINARY_MEASUREMENTS_JOB_ID) { 1332 return false; 1333 } 1334 1335 // we'll perform binary measurements via threads to be mindful of low-end devices 1336 // where this operation might take longer than expected, and so that we don't block 1337 // system_server's main thread. 1338 Executors.defaultThreadFactory().newThread(() -> { 1339 IBinder b = ServiceManager.getService(Context.BINARY_TRANSPARENCY_SERVICE); 1340 IBinaryTransparencyService iBtsService = 1341 IBinaryTransparencyService.Stub.asInterface(b); 1342 try { 1343 iBtsService.recordMeasurementsForAllPackages(); 1344 } catch (RemoteException e) { 1345 Slog.e(TAG, "Taking binary measurements was interrupted.", e); 1346 return; 1347 } 1348 sTimeLastRanMs = System.currentTimeMillis(); 1349 jobFinished(params, false); 1350 }).start(); 1351 1352 return true; 1353 } 1354 1355 @Override onStopJob(JobParameters params)1356 public boolean onStopJob(JobParameters params) { 1357 return false; 1358 } 1359 1360 @SuppressLint("DefaultLocale") scheduleBinaryMeasurements(Context context, BinaryTransparencyService service)1361 static void scheduleBinaryMeasurements(Context context, BinaryTransparencyService service) { 1362 Slog.i(TAG, "Scheduling binary content-digest computation job"); 1363 final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); 1364 if (jobScheduler == null) { 1365 Slog.e(TAG, "Failed to obtain an instance of JobScheduler."); 1366 return; 1367 } 1368 1369 if (jobScheduler.getPendingJob(DO_BINARY_MEASUREMENTS_JOB_ID) != null) { 1370 Slog.d(TAG, "A measurement job has already been scheduled."); 1371 return; 1372 } 1373 1374 long minWaitingPeriodMs = 0; 1375 if (sTimeLastRanMs != 0) { 1376 minWaitingPeriodMs = RECORD_MEASUREMENTS_COOLDOWN_MS 1377 - (System.currentTimeMillis() - sTimeLastRanMs); 1378 // bound the range of minWaitingPeriodMs in the case where > 24h has elapsed 1379 minWaitingPeriodMs = Math.max(0, 1380 Math.min(minWaitingPeriodMs, RECORD_MEASUREMENTS_COOLDOWN_MS)); 1381 Slog.d(TAG, "Scheduling the next measurement to be done at least " 1382 + minWaitingPeriodMs + "ms from now."); 1383 } 1384 1385 final JobInfo jobInfo = new JobInfo.Builder(DO_BINARY_MEASUREMENTS_JOB_ID, 1386 new ComponentName(context, UpdateMeasurementsJobService.class)) 1387 .setRequiresDeviceIdle(true) 1388 .setRequiresCharging(true) 1389 .setMinimumLatency(minWaitingPeriodMs) 1390 .build(); 1391 if (jobScheduler.schedule(jobInfo) != JobScheduler.RESULT_SUCCESS) { 1392 Slog.e(TAG, "Failed to schedule job to measure binaries."); 1393 return; 1394 } 1395 Slog.d(TAG, TextUtils.formatSimple( 1396 "Job %d to measure binaries was scheduled successfully.", 1397 DO_BINARY_MEASUREMENTS_JOB_ID)); 1398 } 1399 } 1400 1401 /** 1402 * Convert a {@link FingerprintSensorProperties} sensor type to the corresponding enum to be 1403 * logged. 1404 * 1405 * @param sensorType See {@link FingerprintSensorProperties} 1406 * @return The enum to be logged 1407 */ toFingerprintSensorType(@ingerprintSensorProperties.SensorType int sensorType)1408 private int toFingerprintSensorType(@FingerprintSensorProperties.SensorType int sensorType) { 1409 switch (sensorType) { 1410 case FingerprintSensorProperties.TYPE_REAR: 1411 return FrameworkStatsLog 1412 .BIOMETRIC_PROPERTIES_COLLECTED__SENSOR_TYPE__SENSOR_FP_REAR; 1413 case FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC: 1414 return FrameworkStatsLog 1415 .BIOMETRIC_PROPERTIES_COLLECTED__SENSOR_TYPE__SENSOR_FP_UDFPS_ULTRASONIC; 1416 case FingerprintSensorProperties.TYPE_UDFPS_OPTICAL: 1417 return FrameworkStatsLog 1418 .BIOMETRIC_PROPERTIES_COLLECTED__SENSOR_TYPE__SENSOR_FP_UDFPS_OPTICAL; 1419 case FingerprintSensorProperties.TYPE_POWER_BUTTON: 1420 return FrameworkStatsLog 1421 .BIOMETRIC_PROPERTIES_COLLECTED__SENSOR_TYPE__SENSOR_FP_POWER_BUTTON; 1422 case FingerprintSensorProperties.TYPE_HOME_BUTTON: 1423 return FrameworkStatsLog 1424 .BIOMETRIC_PROPERTIES_COLLECTED__SENSOR_TYPE__SENSOR_FP_HOME_BUTTON; 1425 default: 1426 return FrameworkStatsLog 1427 .BIOMETRIC_PROPERTIES_COLLECTED__SENSOR_TYPE__SENSOR_UNKNOWN; 1428 } 1429 } 1430 1431 /** 1432 * Convert a {@link FaceSensorProperties} sensor type to the corresponding enum to be logged. 1433 * 1434 * @param sensorType See {@link FaceSensorProperties} 1435 * @return The enum to be logged 1436 */ toFaceSensorType(@aceSensorProperties.SensorType int sensorType)1437 private int toFaceSensorType(@FaceSensorProperties.SensorType int sensorType) { 1438 switch (sensorType) { 1439 case FaceSensorProperties.TYPE_RGB: 1440 return FrameworkStatsLog 1441 .BIOMETRIC_PROPERTIES_COLLECTED__SENSOR_TYPE__SENSOR_FACE_RGB; 1442 case FaceSensorProperties.TYPE_IR: 1443 return FrameworkStatsLog 1444 .BIOMETRIC_PROPERTIES_COLLECTED__SENSOR_TYPE__SENSOR_FACE_IR; 1445 default: 1446 return FrameworkStatsLog 1447 .BIOMETRIC_PROPERTIES_COLLECTED__SENSOR_TYPE__SENSOR_UNKNOWN; 1448 } 1449 } 1450 1451 /** 1452 * Convert a {@link SensorProperties} sensor strength to the corresponding enum to be logged. 1453 * 1454 * @param sensorStrength See {@link SensorProperties} 1455 * @return The enum to be logged 1456 */ toSensorStrength(@ensorProperties.Strength int sensorStrength)1457 private int toSensorStrength(@SensorProperties.Strength int sensorStrength) { 1458 switch (sensorStrength) { 1459 case SensorProperties.STRENGTH_CONVENIENCE: 1460 return FrameworkStatsLog 1461 .BIOMETRIC_PROPERTIES_COLLECTED__SENSOR_STRENGTH__STRENGTH_CONVENIENCE; 1462 case SensorProperties.STRENGTH_WEAK: 1463 return FrameworkStatsLog 1464 .BIOMETRIC_PROPERTIES_COLLECTED__SENSOR_STRENGTH__STRENGTH_WEAK; 1465 case SensorProperties.STRENGTH_STRONG: 1466 return FrameworkStatsLog 1467 .BIOMETRIC_PROPERTIES_COLLECTED__SENSOR_STRENGTH__STRENGTH_STRONG; 1468 default: 1469 return FrameworkStatsLog 1470 .BIOMETRIC_PROPERTIES_COLLECTED__SENSOR_STRENGTH__STRENGTH_UNKNOWN; 1471 } 1472 } 1473 1474 /** 1475 * A helper function to log detailed biometric sensor properties to statsd. 1476 * 1477 * @param prop The biometric sensor properties to be logged 1478 * @param modality The modality of the biometric (e.g. fingerprint, face) to be logged 1479 * @param sensorType The specific type of the biometric to be logged 1480 */ logBiometricProperties(SensorProperties prop, int modality, int sensorType)1481 private void logBiometricProperties(SensorProperties prop, int modality, int sensorType) { 1482 final int sensorId = prop.getSensorId(); 1483 final int sensorStrength = toSensorStrength(prop.getSensorStrength()); 1484 1485 // Log data for each component 1486 // Note: none of the component info is a device identifier since every device of a given 1487 // model and build share the same biometric system info (see b/216195167) 1488 for (ComponentInfo componentInfo : prop.getComponentInfo()) { 1489 mBiometricLogger.logStats( 1490 sensorId, 1491 modality, 1492 sensorType, 1493 sensorStrength, 1494 componentInfo.getComponentId().trim(), 1495 componentInfo.getHardwareVersion().trim(), 1496 componentInfo.getFirmwareVersion().trim(), 1497 componentInfo.getSerialNumber().trim(), 1498 componentInfo.getSoftwareVersion().trim()); 1499 } 1500 } 1501 1502 @VisibleForTesting collectBiometricProperties()1503 void collectBiometricProperties() { 1504 // Check the flag to determine whether biometric property verification is enabled. It's 1505 // disabled by default. 1506 if (!DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_BIOMETRICS, 1507 KEY_ENABLE_BIOMETRIC_PROPERTY_VERIFICATION, true)) { 1508 if (DEBUG) { 1509 Slog.d(TAG, "Do not collect/verify biometric properties. Feature disabled by " 1510 + "DeviceConfig"); 1511 } 1512 return; 1513 } 1514 1515 PackageManager pm = mContext.getPackageManager(); 1516 FingerprintManager fpManager = null; 1517 FaceManager faceManager = null; 1518 if (pm != null && pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) { 1519 fpManager = mContext.getSystemService(FingerprintManager.class); 1520 } 1521 if (pm != null && pm.hasSystemFeature(PackageManager.FEATURE_FACE)) { 1522 faceManager = mContext.getSystemService(FaceManager.class); 1523 } 1524 1525 if (fpManager != null) { 1526 final int fpModality = FrameworkStatsLog 1527 .BIOMETRIC_PROPERTIES_COLLECTED__MODALITY__MODALITY_FINGERPRINT; 1528 fpManager.addAuthenticatorsRegisteredCallback( 1529 new IFingerprintAuthenticatorsRegisteredCallback.Stub() { 1530 @Override 1531 public void onAllAuthenticatorsRegistered( 1532 List<FingerprintSensorPropertiesInternal> sensors) { 1533 if (DEBUG) { 1534 Slog.d(TAG, "Retrieve fingerprint sensor properties. " 1535 + "sensors.size()=" + sensors.size()); 1536 } 1537 // Log data for each fingerprint sensor 1538 for (FingerprintSensorPropertiesInternal propInternal : sensors) { 1539 final FingerprintSensorProperties prop = 1540 FingerprintSensorProperties.from(propInternal); 1541 logBiometricProperties(prop, 1542 fpModality, 1543 toFingerprintSensorType(prop.getSensorType())); 1544 } 1545 } 1546 }); 1547 } 1548 1549 if (faceManager != null) { 1550 final int faceModality = FrameworkStatsLog 1551 .BIOMETRIC_PROPERTIES_COLLECTED__MODALITY__MODALITY_FACE; 1552 faceManager.addAuthenticatorsRegisteredCallback( 1553 new IFaceAuthenticatorsRegisteredCallback.Stub() { 1554 @Override 1555 public void onAllAuthenticatorsRegistered( 1556 List<FaceSensorPropertiesInternal> sensors) { 1557 if (DEBUG) { 1558 Slog.d(TAG, "Retrieve face sensor properties. sensors.size()=" 1559 + sensors.size()); 1560 } 1561 // Log data for each face sensor 1562 for (FaceSensorPropertiesInternal propInternal : sensors) { 1563 final FaceSensorProperties prop = 1564 FaceSensorProperties.from(propInternal); 1565 logBiometricProperties(prop, 1566 faceModality, 1567 toFaceSensorType(prop.getSensorType())); 1568 } 1569 } 1570 }); 1571 } 1572 } 1573 collectBootIntegrityInfo()1574 private void collectBootIntegrityInfo() { 1575 mVbmetaDigest = SystemProperties.get(SYSPROP_NAME_VBETA_DIGEST, VBMETA_DIGEST_UNAVAILABLE); 1576 Slog.d(TAG, String.format("VBMeta Digest: %s", mVbmetaDigest)); 1577 FrameworkStatsLog.write(FrameworkStatsLog.VBMETA_DIGEST_REPORTED, mVbmetaDigest); 1578 1579 IoThread.getExecutor().execute(() -> { 1580 byte[] sepolicyHash = PackageUtils.computeSha256DigestForLargeFileAsBytes( 1581 "/sys/fs/selinux/policy", PackageUtils.createLargeFileBuffer()); 1582 String sepolicyHashEncoded = null; 1583 if (sepolicyHash != null) { 1584 sepolicyHashEncoded = HexEncoding.encodeToString(sepolicyHash, false); 1585 Slog.d(TAG, "sepolicy hash: " + sepolicyHashEncoded); 1586 } 1587 FrameworkStatsLog.write(FrameworkStatsLog.BOOT_INTEGRITY_INFO_REPORTED, 1588 sepolicyHashEncoded, mVbmetaDigest); 1589 }); 1590 } 1591 1592 /** 1593 * Listen for APK updates. 1594 * 1595 * There are two ways available to us to do this: 1596 * 1. Register an observer using 1597 * {@link PackageManagerInternal#getPackageList(PackageManagerInternal.PackageListObserver)}. 1598 * 2. Register broadcast receivers, listening to either {@code ACTION_PACKAGE_ADDED} or 1599 * {@code ACTION_PACKAGE_REPLACED}. 1600 * 1601 * After experimentation, we found that Option #1 does not catch updates to non-staged APEXs. 1602 * Thus, we are implementing Option #2 here. More specifically, listening to 1603 * {@link Intent#ACTION_PACKAGE_ADDED} allows us to capture all events we care about. 1604 * 1605 * We did not use {@link Intent#ACTION_PACKAGE_REPLACED} because it unfortunately does not 1606 * detect updates to non-staged APEXs. Thus, we rely on {@link Intent#EXTRA_REPLACING} to 1607 * filter out new installation from updates instead. 1608 */ registerApkAndNonStagedApexUpdateListener()1609 private void registerApkAndNonStagedApexUpdateListener() { 1610 Slog.d(TAG, "Registering APK & Non-Staged APEX updates..."); 1611 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); 1612 filter.addDataScheme("package"); // this is somehow necessary 1613 mContext.registerReceiver(new PackageUpdatedReceiver(), filter); 1614 } 1615 1616 /** 1617 * Listen for staged-APEX updates. 1618 * 1619 * This method basically covers cases that are not caught by 1620 * {@link #registerApkAndNonStagedApexUpdateListener()}, namely updates to APEXs that are staged 1621 * for the subsequent reboot. 1622 */ registerStagedApexUpdateObserver()1623 private void registerStagedApexUpdateObserver() { 1624 Slog.d(TAG, "Registering APEX updates..."); 1625 IPackageManagerNative iPackageManagerNative = IPackageManagerNative.Stub.asInterface( 1626 ServiceManager.getService("package_native")); 1627 if (iPackageManagerNative == null) { 1628 Slog.e(TAG, "IPackageManagerNative is null"); 1629 return; 1630 } 1631 1632 try { 1633 iPackageManagerNative.registerStagedApexObserver(new IStagedApexObserver.Stub() { 1634 @Override 1635 public void onApexStaged(ApexStagedEvent event) throws RemoteException { 1636 Slog.d(TAG, "A new APEX has been staged for update. There are currently " 1637 + event.stagedApexInfos.length + " APEX(s) staged for update. " 1638 + "Scheduling measurement..."); 1639 UpdateMeasurementsJobService.scheduleBinaryMeasurements(mContext, 1640 BinaryTransparencyService.this); 1641 } 1642 }); 1643 } catch (RemoteException e) { 1644 Slog.e(TAG, "Failed to register a StagedApexObserver."); 1645 } 1646 } 1647 registerBicCallback()1648 private void registerBicCallback() { 1649 if(!com.android.server.flags.Flags.optionalBackgroundInstallControl()) { 1650 Slog.d(TAG, "BICS is disabled for this device, skipping registration."); 1651 return; 1652 } 1653 IBackgroundInstallControlService iBics = 1654 IBackgroundInstallControlService.Stub.asInterface( 1655 ServiceManager.getService( 1656 Context.BACKGROUND_INSTALL_CONTROL_SERVICE)); 1657 if(iBics == null) { 1658 Slog.e(TAG, "Failed to register BackgroundInstallControl callback, either " 1659 + "background install control service does not exist or disabled on this " 1660 + "build."); 1661 return; 1662 } 1663 try { 1664 iBics.registerBackgroundInstallCallback( 1665 new BicCallbackHandler( 1666 new BicCallbackHandler.IBicAppInfoHelper() { 1667 @Override 1668 public void writeAppInfoToLog( 1669 IBinaryTransparencyService.AppInfo appInfo) { 1670 mServiceImpl.writeAppInfoToLog(appInfo); 1671 } 1672 1673 @Override 1674 public List<IBinaryTransparencyService.AppInfo> collectAppInfo( 1675 PackageState packageState, int mbaStatus) { 1676 return mServiceImpl.collectAppInfo(packageState, mbaStatus); 1677 } 1678 } 1679 )); 1680 } catch (RemoteException e) { 1681 Slog.e(TAG, "Failed to register BackgroundInstallControl callback."); 1682 } 1683 } 1684 isPackagePreloaded(String packageName)1685 private boolean isPackagePreloaded(String packageName) { 1686 PackageManager pm = mContext.getPackageManager(); 1687 try { 1688 pm.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of( 1689 PackageManager.MATCH_FACTORY_ONLY)); 1690 } catch (PackageManager.NameNotFoundException e) { 1691 return false; 1692 } 1693 return true; 1694 } 1695 isPackageAnApex(String packageName)1696 private boolean isPackageAnApex(String packageName) { 1697 PackageManager pm = mContext.getPackageManager(); 1698 try { 1699 PackageInfo packageInfo = pm.getPackageInfo(packageName, 1700 PackageManager.PackageInfoFlags.of(PackageManager.MATCH_APEX)); 1701 return packageInfo.isApex; 1702 } catch (PackageManager.NameNotFoundException e) { 1703 return false; 1704 } 1705 } 1706 1707 private class PackageUpdatedReceiver extends BroadcastReceiver { 1708 @Override onReceive(Context context, Intent intent)1709 public void onReceive(Context context, Intent intent) { 1710 if (!Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) { 1711 return; 1712 } 1713 1714 Uri data = intent.getData(); 1715 if (data == null) { 1716 Slog.e(TAG, "Shouldn't happen: intent data is null!"); 1717 return; 1718 } 1719 1720 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 1721 Slog.d(TAG, "Not an update. Skipping..."); 1722 return; 1723 } 1724 1725 String packageName = data.getSchemeSpecificPart(); 1726 1727 boolean shouldMeasureMba = 1728 !android.app.Flags.backgroundInstallControlCallbackApi() 1729 && isPackagePreloaded(packageName); 1730 1731 if (shouldMeasureMba || isPackageAnApex(packageName)) { 1732 Slog.d(TAG, packageName + " was updated. Scheduling measurement..."); 1733 UpdateMeasurementsJobService.scheduleBinaryMeasurements(mContext, 1734 BinaryTransparencyService.this); 1735 } 1736 } 1737 } 1738 1739 /** 1740 * Register observers for APK and APEX updates. The current implementation breaks this process 1741 * into 2 cases/methods because PackageManager does not offer a unified interface to register 1742 * for all package updates in a universal and comprehensive manner. 1743 * Thus, the observers will be invoked when either 1744 * i) APK or non-staged APEX update; or 1745 * ii) APEX staging happens. 1746 * This will then be used as signals to schedule measurement for the relevant binaries. 1747 */ registerAllPackageUpdateObservers()1748 private void registerAllPackageUpdateObservers() { 1749 registerApkAndNonStagedApexUpdateListener(); 1750 registerStagedApexUpdateObserver(); 1751 if (android.app.Flags.backgroundInstallControlCallbackApi() 1752 && CompatChanges.isChangeEnabled(LOG_MBA_INFO)) { 1753 registerBicCallback(); 1754 } 1755 } 1756 translateContentDigestAlgorithmIdToString(int algorithmId)1757 private String translateContentDigestAlgorithmIdToString(int algorithmId) { 1758 switch (algorithmId) { 1759 case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256: 1760 return "CHUNKED_SHA256"; 1761 case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512: 1762 return "CHUNKED_SHA512"; 1763 case ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256: 1764 return "VERITY_CHUNKED_SHA256"; 1765 case ApkSigningBlockUtils.CONTENT_DIGEST_SHA256: 1766 return "SHA256"; 1767 default: 1768 return "UNKNOWN_ALGO_ID(" + algorithmId + ")"; 1769 } 1770 } 1771 1772 @NonNull getCurrentInstalledApexs()1773 private List<PackageInfo> getCurrentInstalledApexs() { 1774 List<PackageInfo> results = new ArrayList<>(); 1775 PackageManager pm = mContext.getPackageManager(); 1776 if (pm == null) { 1777 Slog.e(TAG, "Error obtaining an instance of PackageManager."); 1778 return results; 1779 } 1780 List<PackageInfo> allPackages = pm.getInstalledPackages( 1781 PackageManager.PackageInfoFlags.of(PackageManager.MATCH_APEX 1782 | PackageManager.GET_SIGNING_CERTIFICATES)); 1783 if (allPackages == null) { 1784 Slog.e(TAG, "Error obtaining installed packages (including APEX)"); 1785 return results; 1786 } 1787 1788 results = allPackages.stream().filter(p -> p.isApex).collect(Collectors.toList()); 1789 return results; 1790 } 1791 1792 @Nullable getInstallSourceInfo(String packageName)1793 private InstallSourceInfo getInstallSourceInfo(String packageName) { 1794 PackageManager pm = mContext.getPackageManager(); 1795 if (pm == null) { 1796 Slog.e(TAG, "Error obtaining an instance of PackageManager."); 1797 return null; 1798 } 1799 try { 1800 return pm.getInstallSourceInfo(packageName); 1801 } catch (PackageManager.NameNotFoundException e) { 1802 e.printStackTrace(); 1803 return null; 1804 } 1805 } 1806 1807 @NonNull getOriginalApexPreinstalledLocation(String packageName)1808 private String getOriginalApexPreinstalledLocation(String packageName) { 1809 try { 1810 final String moduleName = apexPackageNameToModuleName(packageName); 1811 IApexService apexService = IApexService.Stub.asInterface( 1812 Binder.allowBlocking(ServiceManager.waitForService("apexservice"))); 1813 for (ApexInfo info : apexService.getAllPackages()) { 1814 if (moduleName.equals(info.moduleName)) { 1815 return info.preinstalledModulePath; 1816 } 1817 } 1818 } catch (RemoteException e) { 1819 Slog.e(TAG, "Unable to get package list from apexservice", e); 1820 } 1821 return APEX_PRELOAD_LOCATION_ERROR; 1822 } 1823 apexPackageNameToModuleName(String packageName)1824 private String apexPackageNameToModuleName(String packageName) { 1825 // It appears that only apexd knows the preinstalled location, and it uses module name as 1826 // the identifier instead of package name. Given the input is a package name, we need to 1827 // covert to module name. 1828 return ApexManager.getInstance().getApexModuleNameForPackageName(packageName); 1829 } 1830 1831 /** 1832 * Wrapper method to call into IBICS to get a list of all newly installed MBAs. 1833 * 1834 * We expect IBICS to maintain an accurate list of installed MBAs, and we merely make use of 1835 * the results within this service. This means we do not further check whether the 1836 * apps in the returned slice is still installed or not, esp. considering that preloaded apps 1837 * could be updated, or post-setup installed apps *might* be deleted in real time. 1838 * 1839 * Note that we do *not* cache the results from IBICS because of the more dynamic nature of 1840 * MBAs v.s. other binaries that we measure. 1841 * 1842 * @return a list of preloaded apps + dynamically installed apps that fit the definition of MBA. 1843 */ 1844 @NonNull getNewlyInstalledMbas()1845 private List<PackageInfo> getNewlyInstalledMbas() { 1846 List<PackageInfo> result = new ArrayList<>(); 1847 IBackgroundInstallControlService iBics = IBackgroundInstallControlService.Stub.asInterface( 1848 ServiceManager.getService(Context.BACKGROUND_INSTALL_CONTROL_SERVICE)); 1849 if (iBics == null) { 1850 Slog.e(TAG, 1851 "Failed to obtain an IBinder instance of IBackgroundInstallControlService"); 1852 return result; 1853 } 1854 ParceledListSlice<PackageInfo> slice; 1855 try { 1856 slice = iBics.getBackgroundInstalledPackages( 1857 PackageManager.MATCH_ALL | PackageManager.GET_SIGNING_CERTIFICATES, 1858 UserHandle.USER_SYSTEM); 1859 } catch (RemoteException e) { 1860 Slog.e(TAG, "Failed to get a list of MBAs.", e); 1861 return result; 1862 } 1863 return slice.getList(); 1864 } 1865 Digest(int algorithm, byte[] value)1866 private record Digest(int algorithm, byte[] value) {} 1867 } 1868