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

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

Merge "Add RollbackPackageHealthObserver"

parents c1b889d2 c4073cc2
Loading
Loading
Loading
Loading
+47 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.rollback;

import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentSender;
import android.os.Bundle;
import android.os.IBinder;

import java.util.function.Consumer;

/** {@code IntentSender} implementation for RollbackManager internal use. */
class LocalIntentReceiver {
    final Consumer<Intent> mConsumer;

    LocalIntentReceiver(Consumer<Intent> consumer) {
        mConsumer = consumer;
    }

    private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
        @Override
        public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
                IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
            mConsumer.accept(intent);
        }
    };

    public IntentSender getIntentSender() {
        return new IntentSender((IIntentSender) mLocalSender);
    }
}
+40 −48
Original line number Diff line number Diff line
@@ -19,8 +19,6 @@ package com.android.server.rollback;
import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
@@ -36,11 +34,9 @@ import android.content.rollback.IRollbackManager;
import android.content.rollback.PackageRollbackInfo;
import android.content.rollback.RollbackInfo;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.storage.StorageManager;
@@ -66,7 +62,6 @@ import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.function.Consumer;

/**
 * Implementation of service that manages APK level rollbacks.
@@ -116,6 +111,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
    private final Context mContext;
    private final HandlerThread mHandlerThread;
    private final Installer mInstaller;
    private final RollbackPackageHealthObserver mPackageHealthObserver;

    RollbackManagerServiceImpl(Context context) {
        mContext = context;
@@ -128,6 +124,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {

        mRollbackStore = new RollbackStore(new File(Environment.getDataDirectory(), "rollback"));

        mPackageHealthObserver = new RollbackPackageHealthObserver(mContext);

        // Kick off loading of the rollback data from strorage in a background
        // thread.
        // TODO: Consider loading the rollback data directly here instead, to
@@ -376,6 +374,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {

            final LocalIntentReceiver receiver = new LocalIntentReceiver(
                    (Intent result) -> {
                        getHandler().post(() -> {
                            // We've now completed the rollback, so we mark it as no longer in
                            // progress.
                            data.inProgress = false;
@@ -383,8 +382,10 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
                            int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
                                    PackageInstaller.STATUS_FAILURE);
                            if (status != PackageInstaller.STATUS_SUCCESS) {
                            sendFailure(statusReceiver, "Rollback downgrade install failed: "
                                    + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE));
                                sendFailure(statusReceiver,
                                        "Rollback downgrade install failed: "
                                        + result.getStringExtra(
                                                PackageInstaller.EXTRA_STATUS_MESSAGE));
                                return;
                            }

@@ -398,6 +399,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
                            // TODO: Limit this to receivers holding the
                            // MANAGE_ROLLBACKS permission?
                            mContext.sendBroadcast(broadcast);
                        });
                    }
            );

@@ -820,26 +822,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
        });
    }

    private class LocalIntentReceiver {
        final Consumer<Intent> mConsumer;

        LocalIntentReceiver(Consumer<Intent> consumer) {
            mConsumer = consumer;
        }

        private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
            @Override
            public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
                    IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
                getHandler().post(() -> mConsumer.accept(intent));
            }
        };

        public IntentSender getIntentSender() {
            return new IntentSender((IIntentSender) mLocalSender);
        }
    }

    /**
     * Gets the version of the package currently installed.
     * Returns null if the package is not currently installed.
@@ -906,7 +888,17 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
                            ensureRollbackDataLoadedLocked();
                            mAvailableRollbacks.add(data);
                        }

                        // TODO(zezeozue): Provide API to explicitly start observing instead
                        // of doing this for all rollbacks. If we do this for all rollbacks,
                        // should document in PackageInstaller.SessionParams#setEnableRollback
                        // After enabling and commiting any rollback, observe packages and
                        // prepare to rollback if packages crashes too frequently.
                        List<String> packages = new ArrayList<>();
                        for (int i = 0; i < data.packages.size(); i++) {
                            packages.add(data.packages.get(i).getPackageName());
                        }
                        mPackageHealthObserver.startObservingHealth(packages,
                                ROLLBACK_LIFETIME_DURATION_MILLIS);
                        scheduleExpiration(ROLLBACK_LIFETIME_DURATION_MILLIS);
                    } catch (IOException e) {
                        Log.e(TAG, "Unable to enable rollback", e);
+94 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.rollback;

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInstaller;
import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
import android.os.Handler;
import android.os.HandlerThread;

import com.android.server.PackageWatchdog;
import com.android.server.PackageWatchdog.PackageHealthObserver;

import java.util.List;

/**
 * {@code PackageHealthObserver} for {@code RollbackManagerService}.
 *
 * @hide
 */
public final class RollbackPackageHealthObserver implements PackageHealthObserver {
    private static final String TAG = "RollbackPackageHealthObserver";
    private static final String NAME = "rollback-observer";
    private Context mContext;
    private Handler mHandler;

    RollbackPackageHealthObserver(Context context) {
        mContext = context;
        HandlerThread handlerThread = new HandlerThread("RollbackPackageHealthObserver");
        handlerThread.start();
        mHandler = handlerThread.getThreadHandler();
        PackageWatchdog.getInstance(mContext).registerHealthObserver(this);
    }

    @Override
    public boolean onHealthCheckFailed(String packageName) {
        RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
        RollbackInfo rollback = rollbackManager.getAvailableRollback(packageName);
        if (rollback != null) {
            // TODO(zezeozue): Only rollback if rollback version == failed package version
            mHandler.post(() -> executeRollback(rollbackManager, rollback));
            return true;
        }
        // Don't handle the notification, no rollbacks available
        return false;
    }

    /**
     * Start observing health of {@code packages} for {@code durationMs}.
     * This may cause {@code packages} to be rolled back if they crash too freqeuntly.
     */
    public void startObservingHealth(List<String> packages, long durationMs) {
        PackageWatchdog.getInstance(mContext).startObservingHealth(this, packages, durationMs);
    }

    private void executeRollback(RollbackManager manager, RollbackInfo rollback) {
        // TODO(zezeozue): Log initiated metrics
        LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver((Intent result) -> {
            mHandler.post(() -> {
                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
                } else {
                    // TODO(zezeozue); Log failure metrics
                    // Rollback failed other observers should have a shot
                }
            });
        });
        manager.executeRollback(rollback, rollbackReceiver.getIntentSender());
    }

    @Override
    public String getName() {
        return NAME;
    }
}
+13 −0
Original line number Diff line number Diff line
@@ -36,6 +36,17 @@ LOCAL_PACKAGE_NAME := RollbackTestAppAv2
include $(BUILD_PACKAGE)
ROLLBACK_TEST_APP_AV2 := $(LOCAL_INSTALLED_MODULE)

# RollbackTestAppACrashingV2.apk
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := $(call all-java-files-under, TestApp/src)
LOCAL_MANIFEST_FILE := TestApp/ACrashingV2.xml
LOCAL_PACKAGE_NAME := RollbackTestAppACrashingV2
include $(BUILD_PACKAGE)
ROLLBACK_TEST_APP_A_CRASHING_V2 := $(LOCAL_INSTALLED_MODULE)

# RollbackTestAppBv1.apk
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
@@ -68,6 +79,7 @@ LOCAL_COMPATIBILITY_SUITE := general-tests
LOCAL_JAVA_RESOURCE_FILES := \
  $(ROLLBACK_TEST_APP_AV1) \
  $(ROLLBACK_TEST_APP_AV2) \
  $(ROLLBACK_TEST_APP_A_CRASHING_V2) \
  $(ROLLBACK_TEST_APP_BV1) \
  $(ROLLBACK_TEST_APP_BV2)
LOCAL_SDK_VERSION := system_current
@@ -77,5 +89,6 @@ include $(BUILD_PACKAGE)
# Clean up local variables
ROLLBACK_TEST_APP_AV1 :=
ROLLBACK_TEST_APP_AV2 :=
ROLLBACK_TEST_APP_A_CRASHING_V2 :=
ROLLBACK_TEST_APP_BV1 :=
ROLLBACK_TEST_APP_BV2 :=
+37 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2019 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.tests.rollback.testapp.A"
    android:versionCode="2"
    android:versionName="2.0" >


    <uses-sdk android:minSdkVersion="19" />

    <application android:label="Rollback Test App A v2">
        <meta-data android:name="version" android:value="2" />
        <receiver android:name="com.android.tests.rollback.testapp.ProcessUserData"
                  android:exported="true" />
        <activity android:name="com.android.tests.rollback.testapp.CrashingMainActivity">
            <intent-filter>
              <action android:name="android.intent.action.MAIN" />
              <category android:name="android.intent.category.DEFAULT"/>
              <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>
Loading