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