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

Commit 1db3782d authored by George Chan's avatar George Chan Committed by Android (Google) Code Review
Browse files

Merge "Added uninstall event metric handling and unit tests." into main

parents 5cb55268 ba5e334c
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -966,6 +966,13 @@ java_aconfig_library {
    defaults: ["framework-minus-apex-aconfig-java-defaults"],
}

java_aconfig_library {
    name: "android.app.flags-aconfig-java-host",
    aconfig_declarations: "android.app.flags-aconfig",
    host_supported: true,
    defaults: ["framework-minus-apex-aconfig-java-defaults"],
}

// Broadcast Radio
aconfig_declarations {
    name: "android.hardware.radio.flags-aconfig",
+122 −48
Original line number Diff line number Diff line
@@ -101,6 +101,9 @@ import java.util.Map;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

import com.android.server.pm.BackgroundInstallControlService;
import com.android.server.pm.BackgroundInstallControlCallbackHelper;

/**
 * @hide
 */
@@ -138,6 +141,10 @@ public class BinaryTransparencyService extends SystemService {
    static final int MBA_STATUS_NEW_INSTALL = 3;
    // used for indicating newly installed MBAs that are updated (but unused currently)
    static final int MBA_STATUS_UPDATED_NEW_INSTALL = 4;
    // used for indicating preloaded MBAs that are downgraded
    static final int MBA_STATUS_DOWNGRADED_PRELOADED = 5;
    // used for indicating MBAs that are uninstalled
    static final int MBA_STATUS_UNINSTALLED = 6;

    @VisibleForTesting
    static final String KEY_ENABLE_BIOMETRIC_PROPERTY_VERIFICATION =
@@ -202,7 +209,9 @@ public class BinaryTransparencyService extends SystemService {
         * @param mbaStatus Assign this value of MBA status to the returned elements.
         * @return a @{@code List<IBinaryTransparencyService.AppInfo>}
         */
        private @NonNull List<IBinaryTransparencyService.AppInfo> collectAppInfo(
        @VisibleForTesting
        @NonNull
        List<IBinaryTransparencyService.AppInfo> collectAppInfo(
                PackageState packageState, int mbaStatus) {
            // compute content digest
            if (DEBUG) {
@@ -336,6 +345,7 @@ public class BinaryTransparencyService extends SystemService {
                        + " packages after considering APEXs.");
            }

            if (!android.app.Flags.backgroundInstallControlCallbackApi()) {
                // proceed with all preloaded apps
                List<IBinaryTransparencyService.AppInfo> allUpdatedPreloadInfo =
                        collectAllUpdatedPreloadInfo(packagesMeasured);
@@ -348,8 +358,7 @@ public class BinaryTransparencyService extends SystemService {
                            + " packages after considering preloads");
                }

            if (!android.app.Flags.backgroundInstallControlCallbackApi()
                    && CompatChanges.isChangeEnabled(LOG_MBA_INFO)) {
                if (CompatChanges.isChangeEnabled(LOG_MBA_INFO)) {
                    // lastly measure all newly installed MBAs
                    List<IBinaryTransparencyService.AppInfo> allMbaInfo =
                            collectAllSilentInstalledMbaInfo(packagesMeasured);
@@ -358,6 +367,7 @@ public class BinaryTransparencyService extends SystemService {
                        writeAppInfoToLog(appInfo);
                    }
                }
            }
            long timeSpentMeasuring = System.currentTimeMillis() - currentTimeMs;
            digestAllPackagesLatency.logSample(timeSpentMeasuring);
            if (DEBUG) {
@@ -466,7 +476,8 @@ public class BinaryTransparencyService extends SystemService {
                    apexInfo.signerDigests);
        }

        private void writeAppInfoToLog(IBinaryTransparencyService.AppInfo appInfo) {
        @VisibleForTesting
        void writeAppInfoToLog(IBinaryTransparencyService.AppInfo appInfo) {
            // Must order by the proto's field number.
            FrameworkStatsLog.write(FrameworkStatsLog.MOBILE_BUNDLED_APP_INFO_GATHERED,
                    appInfo.packageName,
@@ -1165,25 +1176,33 @@ public class BinaryTransparencyService extends SystemService {
     * TODO: Add a host test for testing registration and callback of BicCallbackHandler
     *  b/380002484
     */
    @VisibleForTesting
    static class BicCallbackHandler extends IRemoteCallback.Stub {
        private static final String BIC_CALLBACK_HANDLER_TAG =
                "BTS.BicCallbackHandler";
        private final BinaryTransparencyServiceImpl mServiceImpl;
        static final String FLAGGED_PACKAGE_NAME_KEY = "packageName";
        private static final String BIC_CALLBACK_HANDLER_TAG = TAG + ".BicCallbackHandler";

        private static final int INSTALL_EVENT_TYPE_UNSET = -1;

        BicCallbackHandler(BinaryTransparencyServiceImpl impl) {
            mServiceImpl = impl;
        private final IBicAppInfoHelper mBicAppInfoHelper;

        @VisibleForTesting
        BicCallbackHandler(IBicAppInfoHelper bicAppInfoHelper) {
            mBicAppInfoHelper = bicAppInfoHelper;
        }

        @Override
        public void sendResult(Bundle data) {
            String packageName = data.getString(FLAGGED_PACKAGE_NAME_KEY);
            if (packageName == null) return;
            if (DEBUG) {
                Slog.d(BIC_CALLBACK_HANDLER_TAG, "background install event detected for "
                        + packageName);
            String packageName = data.getString(
                    BackgroundInstallControlCallbackHelper.FLAGGED_PACKAGE_NAME_KEY);
            int installType = data.getInt(
                    BackgroundInstallControlCallbackHelper.INSTALL_EVENT_TYPE_KEY,
                    INSTALL_EVENT_TYPE_UNSET);
            if (packageName == null || installType == INSTALL_EVENT_TYPE_UNSET) {
                Slog.w(BIC_CALLBACK_HANDLER_TAG, "Package name or install type is "
                        + "unavailable, ignoring event");
                return;
            }

            Slog.d(BIC_CALLBACK_HANDLER_TAG, "Detected new bic event for: " + packageName);
            if (installType == BackgroundInstallControlService.INSTALL_EVENT_TYPE_INSTALL) {
                PackageState packageState = LocalServices.getService(PackageManagerInternal.class)
                    .getPackageStateInternal(packageName);
                if (packageState == null) {
@@ -1191,15 +1210,52 @@ public class BinaryTransparencyService extends SystemService {
                            + packageName);
                    return;
                }
                int mbaStatus = MBA_STATUS_NEW_INSTALL;
                if (packageState.isUpdatedSystemApp()) {
                return;
                    mbaStatus = MBA_STATUS_UPDATED_PRELOAD;
                }
            List<IBinaryTransparencyService.AppInfo> mbaInfo = mServiceImpl.collectAppInfo(
                    packageState, MBA_STATUS_NEW_INSTALL);
                List<IBinaryTransparencyService.AppInfo> mbaInfo = mBicAppInfoHelper.collectAppInfo(
                        packageState, mbaStatus);
                for (IBinaryTransparencyService.AppInfo appInfo : mbaInfo) {
                mServiceImpl.writeAppInfoToLog(appInfo);
                    mBicAppInfoHelper.writeAppInfoToLog(appInfo);
                }
            } else if (installType
                        == BackgroundInstallControlService.INSTALL_EVENT_TYPE_UNINSTALL) {
                IBinaryTransparencyService.AppInfo appInfo
                    = new IBinaryTransparencyService.AppInfo();
                // since app is already uninstalled we won't be able to retrieve additional
                // info on it.
                appInfo.packageName = packageName;
                appInfo.mbaStatus = MBA_STATUS_UNINSTALLED;
                mBicAppInfoHelper.writeAppInfoToLog(appInfo);
            } else {
                Slog.w(BIC_CALLBACK_HANDLER_TAG, "Unsupported BIC event: " + installType);
            }
        }

        /**
         * A wrapper of interface for{@link FrameworkStatsLog and ApkDigests}
         * for easier testing
         */
        @VisibleForTesting
        public interface IBicAppInfoHelper {

            /**
             * A wrapper of {@link FrameworkStatsLog}
             *
             * @param appInfo The app info of the changed MBA to be logged
             */
            public void writeAppInfoToLog(IBinaryTransparencyService.AppInfo appInfo);

            /**
             * A wrapper of {@link BinaryTransparencyServiceImpl}
             *
             * @param packageState The packageState provided retrieved from PackageManagerInternal
             * @param mbaStatus The MBA status of the package
             */
            public List<IBinaryTransparencyService.AppInfo> collectAppInfo(
                PackageState packageState, int mbaStatus);
        }
    };

    /**
@@ -1596,7 +1652,21 @@ public class BinaryTransparencyService extends SystemService {
        }
        try {
            iBics.registerBackgroundInstallCallback(
                    new BicCallbackHandler(mServiceImpl));
                    new BicCallbackHandler(
                        new BicCallbackHandler.IBicAppInfoHelper() {
                            @Override
                            public void writeAppInfoToLog(
                                    IBinaryTransparencyService.AppInfo appInfo) {
                                mServiceImpl.writeAppInfoToLog(appInfo);
                            }

                            @Override
                            public List<IBinaryTransparencyService.AppInfo> collectAppInfo(
                                PackageState packageState, int mbaStatus) {
                                return mServiceImpl.collectAppInfo(packageState, mbaStatus);
                            }
                        }
                    ));
        } catch (RemoteException e) {
            Slog.e(TAG, "Failed to register BackgroundInstallControl callback.");
        }
@@ -1643,8 +1713,12 @@ public class BinaryTransparencyService extends SystemService {
            }

            String packageName = data.getSchemeSpecificPart();
            // now we've got to check what package is this
            if (isPackagePreloaded(packageName) || isPackageAnApex(packageName)) {

            boolean shouldMeasureMba =
                !android.app.Flags.backgroundInstallControlCallbackApi()
                && isPackagePreloaded(packageName);

            if (shouldMeasureMba || isPackageAnApex(packageName)) {
                Slog.d(TAG, packageName + " was updated. Scheduling measurement...");
                UpdateMeasurementsJobService.scheduleBinaryMeasurements(mContext,
                        BinaryTransparencyService.this);
+4 −3
Original line number Diff line number Diff line
@@ -33,9 +33,10 @@ import com.android.server.ServiceThread;

public class BackgroundInstallControlCallbackHelper {

    @VisibleForTesting static final String FLAGGED_PACKAGE_NAME_KEY = "packageName";
    @VisibleForTesting static final String FLAGGED_USER_ID_KEY = "userId";
    @VisibleForTesting static final String INSTALL_EVENT_TYPE_KEY = "installEventType";
    public static final String FLAGGED_PACKAGE_NAME_KEY = "packageName";
    public static final String FLAGGED_USER_ID_KEY = "userId";
    public static final String INSTALL_EVENT_TYPE_KEY = "installEventType";

    private static final String TAG = "BackgroundInstallControlCallbackHelper";

    private final Handler mHandler;
+81 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -40,6 +41,7 @@ import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.SystemProperties;
@@ -50,6 +52,12 @@ import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;

import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.os.IBinaryTransparencyService;
import com.android.server.pm.BackgroundInstallControlService;
import com.android.server.pm.BackgroundInstallControlCallbackHelper;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.AndroidPackageSplit;
import com.android.server.pm.pkg.PackageStateInternal;

import org.junit.After;
import org.junit.Assert;
@@ -68,6 +76,9 @@ import java.util.List;
public class BinaryTransparencyServiceTest {
    private static final String TAG = "BinaryTransparencyServiceTest";

    private static final String TEST_PKG_NAME = "testPackageName";
    private static final long TEST_VERSION_CODE = 1L;

    private Context mContext;
    private BinaryTransparencyService mBinaryTransparencyService;
    private BinaryTransparencyService.BinaryTransparencyServiceImpl mTestInterface;
@@ -83,6 +94,8 @@ public class BinaryTransparencyServiceTest {
    private PackageManager mPackageManager;
    @Mock
    private PackageManagerInternal mPackageManagerInternal;
    @Mock
    private BinaryTransparencyService.BicCallbackHandler.IBicAppInfoHelper mBicAppInfoHelper;

    @Captor
    private ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback>
@@ -91,6 +104,9 @@ public class BinaryTransparencyServiceTest {
    private ArgumentCaptor<IFaceAuthenticatorsRegisteredCallback>
            mFaceAuthenticatorsRegisteredCaptor;

    @Captor
    private ArgumentCaptor<IBinaryTransparencyService.AppInfo> appInfoCaptor;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
@@ -262,4 +278,69 @@ public class BinaryTransparencyServiceTest {
                eq("") /* softwareVersion */
        );
    }

    @Test
    public void BicCallbackHandler_uploads_mba_metrics() {
        Bundle data = setupBicCallbackHandlerTest(false,
            BinaryTransparencyService.MBA_STATUS_NEW_INSTALL);

        BinaryTransparencyService.BicCallbackHandler handler =
            new BinaryTransparencyService.BicCallbackHandler(mBicAppInfoHelper);
        handler.sendResult(data);

        verify(mBicAppInfoHelper, times(1)).writeAppInfoToLog(appInfoCaptor.capture());
        Assert.assertEquals(TEST_PKG_NAME, appInfoCaptor.getValue().packageName);
        Assert.assertEquals(TEST_VERSION_CODE, appInfoCaptor.getValue().longVersion);
    }

    @Test
    public void BicCallbackHandler_uploads_mba_metrics_for_preloads() {
        Bundle data = setupBicCallbackHandlerTest(true,
            BinaryTransparencyService.MBA_STATUS_UPDATED_PRELOAD);

        BinaryTransparencyService.BicCallbackHandler handler =
            new BinaryTransparencyService.BicCallbackHandler(mBicAppInfoHelper);
        handler.sendResult(data);

        verify(mBicAppInfoHelper, times(1)).writeAppInfoToLog(appInfoCaptor.capture());
        Assert.assertEquals(TEST_PKG_NAME, appInfoCaptor.getValue().packageName);
        Assert.assertEquals(TEST_VERSION_CODE, appInfoCaptor.getValue().longVersion);
    }

    @Test
    public void BicCallbackHandler_uploads_mba_metrics_for_uninstalls() {
        Bundle data = new Bundle();
        data.putString(BackgroundInstallControlCallbackHelper.FLAGGED_PACKAGE_NAME_KEY,
            TEST_PKG_NAME);
        data.putInt(BackgroundInstallControlCallbackHelper.INSTALL_EVENT_TYPE_KEY,
            BackgroundInstallControlService.INSTALL_EVENT_TYPE_UNINSTALL);

        BinaryTransparencyService.BicCallbackHandler handler =
                new BinaryTransparencyService.BicCallbackHandler(mBicAppInfoHelper);
        handler.sendResult(data);

        verify(mBicAppInfoHelper, times(1)).writeAppInfoToLog(appInfoCaptor.capture());
        Assert.assertEquals(TEST_PKG_NAME ,appInfoCaptor.getValue().packageName);
        Assert.assertEquals(BinaryTransparencyService.MBA_STATUS_UNINSTALLED,
            appInfoCaptor.getValue().mbaStatus);
    }

    private Bundle setupBicCallbackHandlerTest(boolean isUpdatedSystemApp,
            int expectedBtsMbaStatus) {
        Bundle data = new Bundle();
        data.putString(BackgroundInstallControlCallbackHelper.FLAGGED_PACKAGE_NAME_KEY,
            TEST_PKG_NAME);
        data.putInt(BackgroundInstallControlCallbackHelper.INSTALL_EVENT_TYPE_KEY,
            BackgroundInstallControlService.INSTALL_EVENT_TYPE_INSTALL);
        PackageStateInternal mockPackageState = mock(PackageStateInternal.class);
        when(mPackageManagerInternal.getPackageStateInternal(TEST_PKG_NAME))
            .thenReturn(mockPackageState);
        when(mockPackageState.isUpdatedSystemApp()).thenReturn(isUpdatedSystemApp);
        IBinaryTransparencyService.AppInfo appInfo = new IBinaryTransparencyService.AppInfo();
        appInfo.packageName = TEST_PKG_NAME;
        appInfo.longVersion = TEST_VERSION_CODE;
        when(mBicAppInfoHelper.collectAppInfo(mockPackageState, expectedBtsMbaStatus))
            .thenReturn(List.of(appInfo));
        return data;
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -31,6 +31,8 @@ java_test_host {
    ],
    static_libs: [
        "truth",
        "flag-junit-host",
        "android.app.flags-aconfig-java-host",
    ],
    device_common_data: [
        ":BinaryTransparencyTestApp",
Loading