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

Commit 65ac428e authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add statsd logging for RollbackHealthObserver events"

parents 0e9854e0 03eeb137
Loading
Loading
Loading
Loading
+67 −20
Original line number Diff line number Diff line
@@ -18,14 +18,18 @@ package com.android.server.rollback;

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
import android.content.rollback.PackageRollbackInfo;
import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
import android.os.Handler;
import android.os.HandlerThread;
import android.text.TextUtils;
import android.util.Slog;
import android.util.StatsLog;

import com.android.internal.R;
import com.android.server.PackageWatchdog;
import com.android.server.PackageWatchdog.PackageHealthObserver;
import com.android.server.PackageWatchdog.PackageHealthObserverImpact;
@@ -54,9 +58,15 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve

    @Override
    public int onHealthCheckFailed(String packageName, long versionCode) {
        VersionedPackage moduleMetadataPackage = getModuleMetadataPackage();
        if (moduleMetadataPackage == null) {
            // Ignore failure, no mainline update available
            return PackageHealthObserverImpact.USER_IMPACT_NONE;
        }

        RollbackInfo rollback =
                getAvailableRollback(mContext.getSystemService(RollbackManager.class),
                    packageName, versionCode);
                getAvailableMainlineRollback(mContext.getSystemService(RollbackManager.class),
                    packageName, versionCode, moduleMetadataPackage);
        if (rollback == null) {
            // Don't handle the notification, no rollbacks available for the package
            return PackageHealthObserverImpact.USER_IMPACT_NONE;
@@ -67,27 +77,41 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve

    @Override
    public boolean execute(String packageName, long versionCode) {
        VersionedPackage moduleMetadataPackage = getModuleMetadataPackage();
        if (moduleMetadataPackage == null) {
            // Ignore failure, no mainline update available
            return false;
        }

        RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
        RollbackInfo rollback = getAvailableRollback(rollbackManager, packageName, versionCode);
        RollbackInfo rollback = getAvailableMainlineRollback(rollbackManager,
                packageName, versionCode, moduleMetadataPackage);
        if (rollback == null) {
            // Expected a rollback to be available, what happened?
            Slog.w(TAG, "Expected rollback but no rollback found for package: [ "
                    + packageName + "] with versionCode: [" + versionCode + "]");
            return false;
        }

        // TODO(zezeozue): Only rollback if rollback version == failed package version
        StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
                StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE,
                moduleMetadataPackage.getPackageName(),
                moduleMetadataPackage.getVersionCode());
        LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver((Intent result) -> {
            int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
                    PackageInstaller.STATUS_FAILURE);
            if (status == PackageInstaller.STATUS_SUCCESS) {
                // TODO(zezeozue); Log success metrics
                // Rolledback successfully, no action required by other observers
            int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
                    RollbackManager.STATUS_FAILURE);
            if (status == RollbackManager.STATUS_SUCCESS) {
                StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
                        StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS,
                        moduleMetadataPackage.getPackageName(),
                        moduleMetadataPackage.getVersionCode());
            } else {
                // TODO(zezeozue); Log failure metrics
                // Rollback failed other observers should have a shot
                StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
                        StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
                        moduleMetadataPackage.getPackageName(),
                        moduleMetadataPackage.getVersionCode());
            }
        });

        // TODO(zezeozue): Log initiated metrics
        mHandler.post(() ->
                rollbackManager.commitRollback(rollback.getRollbackId(),
                    Collections.singletonList(new VersionedPackage(packageName, versionCode)),
@@ -109,17 +133,40 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
        PackageWatchdog.getInstance(mContext).startObservingHealth(this, packages, durationMs);
    }

    private RollbackInfo getAvailableRollback(RollbackManager rollbackManager,
            String packageName, long versionCode) {
    private RollbackInfo getAvailableMainlineRollback(RollbackManager rollbackManager,
            String packageName, long versionCode, VersionedPackage moduleMetadataPackage) {
        for (RollbackInfo rollback : rollbackManager.getAvailableRollbacks()) {
            // We only rollback mainline packages, so check if rollback contains the
            // module metadata provider, if it does, the rollback is a mainline rollback
            boolean hasModuleMetadataPackage = false;
            boolean hasFailedPackage = false;
            for (PackageRollbackInfo packageRollback : rollback.getPackages()) {
                if (packageName.equals(packageRollback.getPackageName())
                hasModuleMetadataPackage |= packageRollback.getPackageName().equals(
                                moduleMetadataPackage.getPackageName());
                hasFailedPackage |= packageRollback.getPackageName().equals(packageName)
                        && packageRollback.getVersionRolledBackFrom().getVersionCode()
                        == versionCode) {
                        == versionCode;
            }
            if (hasModuleMetadataPackage && hasFailedPackage) {
                return rollback;
            }
        }
        return null;
    }

    private VersionedPackage getModuleMetadataPackage() {
        String packageName = mContext.getResources().getString(
                R.string.config_defaultModuleMetadataProvider);
        if (!TextUtils.isEmpty(packageName)) {
            return null;
        }

        try {
            return new VersionedPackage(packageName, mContext.getPackageManager().getPackageInfo(
                            packageName, 0 /* flags */).getLongVersionCode());
        } catch (PackageManager.NameNotFoundException e) {
            Slog.w(TAG, "Module metadata provider not found");
            return null;
        }
    }
}
+4 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;

import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -628,9 +629,12 @@ public class RollbackTest {
        assertEquals(versionRolledBackTo, info.getVersionRolledBackTo().getLongVersionCode());
    }

    // TODO: Allow installing test app along atomically with module metadata package so that
    // a failed test app will be flagged as a failed mainline app
    /**
     * Test bad update automatic rollback.
     */
    @Ignore
    @Test
    public void testBadUpdateRollback() throws Exception {
        BroadcastReceiver crashCountReceiver = null;