Loading services/core/java/com/android/server/rollback/LocalIntentReceiver.java 0 → 100644 +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); } } services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +40 −48 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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. Loading Loading @@ -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; Loading @@ -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 Loading Loading @@ -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; Loading @@ -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; } Loading @@ -398,6 +399,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // TODO: Limit this to receivers holding the // MANAGE_ROLLBACKS permission? mContext.sendBroadcast(broadcast); }); } ); Loading Loading @@ -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. Loading Loading @@ -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); Loading services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java 0 → 100644 +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; } } tests/RollbackTest/Android.mk +13 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading @@ -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 := tests/RollbackTest/TestApp/ACrashingV2.xml 0 → 100644 +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
services/core/java/com/android/server/rollback/LocalIntentReceiver.java 0 → 100644 +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); } }
services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +40 −48 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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. Loading Loading @@ -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; Loading @@ -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 Loading Loading @@ -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; Loading @@ -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; } Loading @@ -398,6 +399,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // TODO: Limit this to receivers holding the // MANAGE_ROLLBACKS permission? mContext.sendBroadcast(broadcast); }); } ); Loading Loading @@ -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. Loading Loading @@ -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); Loading
services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java 0 → 100644 +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; } }
tests/RollbackTest/Android.mk +13 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading @@ -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 :=
tests/RollbackTest/TestApp/ACrashingV2.xml 0 → 100644 +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>