• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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