Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7d726bc5 authored by Victor Hsieh's avatar Victor Hsieh Committed by Android (Google) Code Review
Browse files

Merge changes Ic877c85a,Iecc6933e,I67da3111

* changes:
  Return early if no need to record measurement
  Organize MBA and APEX info with structs
  Drop unused return value
parents 40db8a18 256abd41
Loading
Loading
Loading
Loading
+22 −1
Original line number Original line Diff line number Diff line
@@ -28,5 +28,26 @@ interface IBinaryTransparencyService {


    List getApexInfo();
    List getApexInfo();


    List getMeasurementsForAllPackages();
    void recordMeasurementsForAllPackages();

    parcelable ApexInfo {
        String packageName;
        long longVersion;
        byte[] digest;
        int digestAlgorithm;
        String[] signerDigests;
    }

    parcelable AppInfo {
        String packageName;
        long longVersion;
        byte[] digest;
        int digestAlgorithm;
        String[] signerDigests;
        int mbaStatus;
        String initiator;
        String[] initiatorSignerDigests;
        String installer;
        String originator;
    }
}
}
 No newline at end of file
+93 −106
Original line number Original line Diff line number Diff line
@@ -103,7 +103,6 @@ import java.util.stream.Collectors;
 */
 */
public class BinaryTransparencyService extends SystemService {
public class BinaryTransparencyService extends SystemService {
    private static final String TAG = "TransparencyService";
    private static final String TAG = "TransparencyService";
    private static final String EXTRA_SERVICE = "service";


    @VisibleForTesting
    @VisibleForTesting
    static final String VBMETA_DIGEST_UNINITIALIZED = "vbmeta-digest-uninitialized";
    static final String VBMETA_DIGEST_UNINITIALIZED = "vbmeta-digest-uninitialized";
@@ -257,31 +256,30 @@ public class BinaryTransparencyService extends SystemService {
        /**
        /**
         * Measures and records digests for *all* covered binaries/packages.
         * Measures and records digests for *all* covered binaries/packages.
         *
         *
         * This method will be called in a Job scheduled to take measurements periodically.
         * This method will be called in a Job scheduled to take measurements periodically. If the
         * last measurement was performaned recently (less than RECORD_MEASUREMENT_COOLDOWN_MS
         * ago), the measurement and recording will be skipped.
         *
         *
         * Packages that are covered so far are:
         * Packages that are covered so far are:
         * - all APEXs (introduced in Android T)
         * - all APEXs (introduced in Android T)
         * - all mainline modules (introduced in Android T)
         * - all mainline modules (introduced in Android T)
         * - all preloaded apps and their update(s) (new in Android U)
         * - all preloaded apps and their update(s) (new in Android U)
         * - dynamically installed mobile bundled apps (MBAs) (new in Android U)
         * - dynamically installed mobile bundled apps (MBAs) (new in Android U)
         *
         * @return a {@code List<Bundle>}. Each Bundle item contains values as
         *          defined by the return value of {@link #measurePackage(PackageInfo)}.
         */
         */
        public List getMeasurementsForAllPackages() {
        public void recordMeasurementsForAllPackages() {
            List<Bundle> results = new ArrayList<>();
            PackageManager pm = mContext.getPackageManager();
            Set<String> packagesMeasured = new HashSet<>();

            // check if we should record the resulting measurements
            // check if we should record the resulting measurements
            long currentTimeMs = System.currentTimeMillis();
            long currentTimeMs = System.currentTimeMillis();
            boolean record = false;
            if ((currentTimeMs - mMeasurementsLastRecordedMs) < RECORD_MEASUREMENTS_COOLDOWN_MS) {
            if ((currentTimeMs - mMeasurementsLastRecordedMs) >= RECORD_MEASUREMENTS_COOLDOWN_MS) {
                Slog.d(TAG, "Skip measurement since the last measurement was only taken at "
                        + mMeasurementsLastRecordedMs + " within the cooldown period");
                return;
            }
            Slog.d(TAG, "Measurement was last taken at " + mMeasurementsLastRecordedMs
            Slog.d(TAG, "Measurement was last taken at " + mMeasurementsLastRecordedMs
                    + " and is now updated to: " + currentTimeMs);
                    + " and is now updated to: " + currentTimeMs);
            mMeasurementsLastRecordedMs = currentTimeMs;
            mMeasurementsLastRecordedMs = currentTimeMs;
                record = true;

            }
            PackageManager pm = mContext.getPackageManager();
            Set<String> packagesMeasured = new HashSet<>();


            // measure all APEXs first
            // measure all APEXs first
            if (DEBUG) {
            if (DEBUG) {
@@ -291,22 +289,17 @@ public class BinaryTransparencyService extends SystemService {
                packagesMeasured.add(packageInfo.packageName);
                packagesMeasured.add(packageInfo.packageName);


                Bundle apexMeasurement = measurePackage(packageInfo);
                Bundle apexMeasurement = measurePackage(packageInfo);
                results.add(apexMeasurement);


                if (record) {
                var apexInfo = new IBinaryTransparencyService.ApexInfo();
                    // compute digests of signing info
                apexInfo.packageName = packageInfo.packageName;
                    String[] signerDigestHexStrings = computePackageSignerSha256Digests(
                apexInfo.longVersion = packageInfo.getLongVersionCode();
                            packageInfo.signingInfo);
                apexInfo.digest = apexMeasurement.getByteArray(BUNDLE_CONTENT_DIGEST);
                apexInfo.digestAlgorithm =
                        apexMeasurement.getInt(BUNDLE_CONTENT_DIGEST_ALGORITHM);
                apexInfo.signerDigests =
                        computePackageSignerSha256Digests(packageInfo.signingInfo);


                    // log to statsd
                recordApexInfo(apexInfo);
                    FrameworkStatsLog.write(FrameworkStatsLog.APEX_INFO_GATHERED,
                                            packageInfo.packageName,
                                            packageInfo.getLongVersionCode(),
                                            HexEncoding.encodeToString(apexMeasurement.getByteArray(
                                                    BUNDLE_CONTENT_DIGEST), false),
                                            apexMeasurement.getInt(BUNDLE_CONTENT_DIGEST_ALGORITHM),
                                            signerDigestHexStrings);
                }
            }
            }
            if (DEBUG) {
            if (DEBUG) {
                Slog.d(TAG, "Measured " + packagesMeasured.size()
                Slog.d(TAG, "Measured " + packagesMeasured.size()
@@ -322,11 +315,11 @@ public class BinaryTransparencyService extends SystemService {
                }
                }
                packagesMeasured.add(packageInfo.packageName);
                packagesMeasured.add(packageInfo.packageName);


                int mba_status = MBA_STATUS_PRELOADED;
                int mbaStatus = MBA_STATUS_PRELOADED;
                if (packageInfo.signingInfo == null) {
                if (packageInfo.signingInfo == null) {
                    Slog.d(TAG, "Preload " + packageInfo.packageName  + " at "
                    Slog.d(TAG, "Preload " + packageInfo.packageName  + " at "
                            + packageInfo.applicationInfo.sourceDir + " has likely been updated.");
                            + packageInfo.applicationInfo.sourceDir + " has likely been updated.");
                    mba_status = MBA_STATUS_UPDATED_PRELOAD;
                    mbaStatus = MBA_STATUS_UPDATED_PRELOAD;


                    PackageInfo origPackageInfo = packageInfo;
                    PackageInfo origPackageInfo = packageInfo;
                    try {
                    try {
@@ -337,33 +330,24 @@ public class BinaryTransparencyService extends SystemService {
                        Slog.e(TAG, "Failed to obtain an updated PackageInfo of "
                        Slog.e(TAG, "Failed to obtain an updated PackageInfo of "
                                + origPackageInfo.packageName, e);
                                + origPackageInfo.packageName, e);
                        packageInfo = origPackageInfo;
                        packageInfo = origPackageInfo;
                        mba_status = MBA_STATUS_ERROR;
                        mbaStatus = MBA_STATUS_ERROR;
                    }
                    }
                }
                }



                if (mbaStatus == MBA_STATUS_UPDATED_PRELOAD) {
                    Bundle packageMeasurement = measurePackage(packageInfo);
                    Bundle packageMeasurement = measurePackage(packageInfo);
                results.add(packageMeasurement);


                if (record && (mba_status == MBA_STATUS_UPDATED_PRELOAD)) {
                    var appInfo = new IBinaryTransparencyService.AppInfo();
                    // compute digests of signing info
                    appInfo.packageName = packageInfo.packageName;
                    String[] signerDigestHexStrings = computePackageSignerSha256Digests(
                    appInfo.longVersion = packageInfo.getLongVersionCode();
                            packageInfo.signingInfo);
                    appInfo.digest = packageMeasurement.getByteArray(BUNDLE_CONTENT_DIGEST);
                    appInfo.digestAlgorithm =
                            packageMeasurement.getInt(BUNDLE_CONTENT_DIGEST_ALGORITHM);
                    appInfo.signerDigests =
                            computePackageSignerSha256Digests(packageInfo.signingInfo);
                    appInfo.mbaStatus = mbaStatus;


                    // now we should have all the bits for the atom
                    writeAppInfoToLog(appInfo);
                    byte[] cDigest = packageMeasurement.getByteArray(BUNDLE_CONTENT_DIGEST);
                    FrameworkStatsLog.write(FrameworkStatsLog.MOBILE_BUNDLED_APP_INFO_GATHERED,
                            packageInfo.packageName,
                            packageInfo.getLongVersionCode(),
                            (cDigest != null) ? HexEncoding.encodeToString(cDigest, false) : null,
                            packageMeasurement.getInt(BUNDLE_CONTENT_DIGEST_ALGORITHM),
                            signerDigestHexStrings, // signer_cert_digest
                            mba_status,             // mba_status
                            null,                   // initiator
                            null,                   // initiator_signer_digest
                            null,                   // installer
                            null                    // originator
                    );
                }
                }
            }
            }
            if (DEBUG) {
            if (DEBUG) {
@@ -380,54 +364,37 @@ public class BinaryTransparencyService extends SystemService {
                    packagesMeasured.add(packageInfo.packageName);
                    packagesMeasured.add(packageInfo.packageName);


                    Bundle packageMeasurement = measurePackage(packageInfo);
                    Bundle packageMeasurement = measurePackage(packageInfo);
                    results.add(packageMeasurement);

                    if (record) {
                        // compute digests of signing info
                        String[] signerDigestHexStrings = computePackageSignerSha256Digests(
                                packageInfo.signingInfo);


                        // then extract package's InstallSourceInfo
                    if (DEBUG) {
                    if (DEBUG) {
                        Slog.d(TAG,
                        Slog.d(TAG,
                                "Extracting InstallSourceInfo for " + packageInfo.packageName);
                                "Extracting InstallSourceInfo for " + packageInfo.packageName);
                    }
                    }
                    var appInfo = new IBinaryTransparencyService.AppInfo();
                    appInfo.packageName = packageInfo.packageName;
                    appInfo.longVersion = packageInfo.getLongVersionCode();
                    appInfo.digest = packageMeasurement.getByteArray(BUNDLE_CONTENT_DIGEST);
                    appInfo.digestAlgorithm =
                            packageMeasurement.getInt(BUNDLE_CONTENT_DIGEST_ALGORITHM);
                    appInfo.signerDigests =
                            computePackageSignerSha256Digests(packageInfo.signingInfo);
                    appInfo.mbaStatus = MBA_STATUS_NEW_INSTALL;

                    // extract package's InstallSourceInfo
                    InstallSourceInfo installSourceInfo = getInstallSourceInfo(
                    InstallSourceInfo installSourceInfo = getInstallSourceInfo(
                            packageInfo.packageName);
                            packageInfo.packageName);
                        String initiator = null;
                        SigningInfo initiatorSignerInfo = null;
                        String[] initiatorSignerInfoDigest = null;
                        String installer = null;
                        String originator = null;

                    if (installSourceInfo != null) {
                    if (installSourceInfo != null) {
                            initiator = installSourceInfo.getInitiatingPackageName();
                        appInfo.initiator = installSourceInfo.getInitiatingPackageName();
                            initiatorSignerInfo =
                        SigningInfo initiatorSignerInfo =
                                installSourceInfo.getInitiatingPackageSigningInfo();
                                installSourceInfo.getInitiatingPackageSigningInfo();
                        if (initiatorSignerInfo != null) {
                        if (initiatorSignerInfo != null) {
                                initiatorSignerInfoDigest = computePackageSignerSha256Digests(
                            appInfo.initiatorSignerDigests =
                                        initiatorSignerInfo);
                                    computePackageSignerSha256Digests(initiatorSignerInfo);
                        }
                        }
                            installer = installSourceInfo.getInstallingPackageName();
                        appInfo.installer = installSourceInfo.getInstallingPackageName();
                            originator = installSourceInfo.getOriginatingPackageName();
                        appInfo.originator = installSourceInfo.getOriginatingPackageName();
                    }
                    }


                        // we should now have all the info needed for the atom
                    writeAppInfoToLog(appInfo);
                        byte[] cDigest = packageMeasurement.getByteArray(BUNDLE_CONTENT_DIGEST);
                        FrameworkStatsLog.write(FrameworkStatsLog.MOBILE_BUNDLED_APP_INFO_GATHERED,
                                packageInfo.packageName,
                                packageInfo.getLongVersionCode(),
                                (cDigest != null) ? HexEncoding.encodeToString(cDigest, false)
                                        : null,
                                packageMeasurement.getInt(BUNDLE_CONTENT_DIGEST_ALGORITHM),
                                signerDigestHexStrings,
                                MBA_STATUS_NEW_INSTALL,   // mba_status
                                initiator,
                                initiatorSignerInfoDigest,
                                installer,
                                originator
                        );
                    }
                }
                }
            }
            }
            if (DEBUG) {
            if (DEBUG) {
@@ -435,8 +402,31 @@ public class BinaryTransparencyService extends SystemService {
                Slog.d(TAG, "Measured " + packagesMeasured.size()
                Slog.d(TAG, "Measured " + packagesMeasured.size()
                        + " packages altogether in " + timeSpentMeasuring + "ms");
                        + " packages altogether in " + timeSpentMeasuring + "ms");
            }
            }
        }


            return results;
        private void recordApexInfo(IBinaryTransparencyService.ApexInfo apexInfo) {
            FrameworkStatsLog.write(FrameworkStatsLog.APEX_INFO_GATHERED,
                    apexInfo.packageName,
                    apexInfo.longVersion,
                    (apexInfo.digest != null) ? HexEncoding.encodeToString(apexInfo.digest, false)
                            : null,
                    apexInfo.digestAlgorithm,
                    apexInfo.signerDigests);
        }

        private void writeAppInfoToLog(IBinaryTransparencyService.AppInfo appInfo) {
            FrameworkStatsLog.write(FrameworkStatsLog.MOBILE_BUNDLED_APP_INFO_GATHERED,
                    appInfo.packageName,
                    appInfo.longVersion,
                    (appInfo.digest != null) ? HexEncoding.encodeToString(appInfo.digest, false)
                            : null,
                    appInfo.digestAlgorithm,
                    appInfo.signerDigests,
                    appInfo.mbaStatus,
                    appInfo.initiator,
                    appInfo.initiatorSignerDigests,
                    appInfo.installer,
                    appInfo.originator);
        }
        }


        /**
        /**
@@ -1182,14 +1172,11 @@ public class BinaryTransparencyService extends SystemService {
            // where this operation might take longer than expected, and so that we don't block
            // where this operation might take longer than expected, and so that we don't block
            // system_server's main thread.
            // system_server's main thread.
            Executors.defaultThreadFactory().newThread(() -> {
            Executors.defaultThreadFactory().newThread(() -> {
                // we discard the return value of getMeasurementsForAllPackages() as the
                // results of the measurements will be recorded, and that is what we're aiming
                // for with this job.
                IBinder b = ServiceManager.getService(Context.BINARY_TRANSPARENCY_SERVICE);
                IBinder b = ServiceManager.getService(Context.BINARY_TRANSPARENCY_SERVICE);
                IBinaryTransparencyService iBtsService =
                IBinaryTransparencyService iBtsService =
                        IBinaryTransparencyService.Stub.asInterface(b);
                        IBinaryTransparencyService.Stub.asInterface(b);
                try {
                try {
                    iBtsService.getMeasurementsForAllPackages();
                    iBtsService.recordMeasurementsForAllPackages();
                } catch (RemoteException e) {
                } catch (RemoteException e) {
                    Slog.e(TAG, "Taking binary measurements was interrupted.", e);
                    Slog.e(TAG, "Taking binary measurements was interrupted.", e);
                    return;
                    return;