summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Rosenberg <drosen@google.com>2018-10-02 17:40:44 -0700
committerDaniel Rosenberg <drosen@google.com>2018-10-03 15:39:25 -0700
commitd3992498556fb1dce783d9d5e59f38cad492a6c3 (patch)
tree2c8cbf4f2a7e839e80af0dc3808c8813b3701284
parentac244261c8abaaaab5cd24506dc464fb6d762043 (diff)
downloadvold-d3992498556fb1dce783d9d5e59f38cad492a6c3.tar.gz
Add checkpointing support for A/B updates
This adds implicit rollback support during A/B style updates. If you explicitly start a checkpoint with -1, needsRollback will trigger if the update fails, and should be used if any additional cleanup is needed that is not covered by A/B itself. Test: All Checkpoint tests pass Bug: 111020314 Change-Id: I88b4a1098c6bac4dc1438a54c8a8f59577a6c17b
-rw-r--r--Android.bp1
-rw-r--r--Checkpoint.cpp37
-rw-r--r--Checkpoint.h2
-rw-r--r--VoldNativeService.cpp8
-rw-r--r--VoldNativeService.h1
-rw-r--r--binder/android/os/IVold.aidl1
-rw-r--r--vdc.cpp4
7 files changed, 50 insertions, 4 deletions
diff --git a/Android.bp b/Android.bp
index b115bc15..af77cef3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -39,6 +39,7 @@ cc_defaults {
shared_libs: [
"android.hardware.keymaster@3.0",
"android.hardware.keymaster@4.0",
+ "android.hardware.boot@1.0",
"libbase",
"libbinder",
"libcrypto",
diff --git a/Checkpoint.cpp b/Checkpoint.cpp
index d9c0cd10..5d1ec1f5 100644
--- a/Checkpoint.cpp
+++ b/Checkpoint.cpp
@@ -26,6 +26,7 @@
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/unique_fd.h>
+#include <android/hardware/boot/1.0/IBootControl.h>
#include <cutils/android_reboot.h>
#include <fcntl.h>
#include <fs_mgr.h>
@@ -34,6 +35,11 @@
#include <sys/mount.h>
#include <sys/stat.h>
+using android::hardware::hidl_string;
+using android::hardware::boot::V1_0::BoolResult;
+using android::hardware::boot::V1_0::IBootControl;
+using android::hardware::boot::V1_0::Slot;
+
namespace android {
namespace vold {
@@ -60,6 +66,14 @@ bool setBowState(std::string const& block_device, std::string const& state) {
bool cp_startCheckpoint(int retry) {
if (retry < -1) return false;
std::string content = std::to_string(retry);
+ if (retry == -1) {
+ sp<IBootControl> module = IBootControl::getService();
+ if (module) {
+ std::string suffix;
+ auto cb = [&suffix](hidl_string s) { suffix = s; };
+ if (module->getSuffix(module->getCurrentSlot(), cb).isOk()) content += " " + suffix;
+ }
+ }
return android::base::WriteStringToFile(content, kMetadataCPFile);
}
@@ -101,19 +115,35 @@ void cp_abortChanges() {
android_reboot(ANDROID_RB_RESTART2, 0, nullptr);
}
-bool cp_needRollback(const std::string& id) {
+bool cp_needsRollback() {
std::string content;
bool ret;
ret = android::base::ReadFileToString(kMetadataCPFile, &content);
- if (ret) return content == "0";
+ if (ret) {
+ if (content == "0") return true;
+ if (content.substr(0, 3) == "-1 ") {
+ std::string oldSuffix = content.substr(3);
+ sp<IBootControl> module = IBootControl::getService();
+ std::string newSuffix;
+
+ if (module) {
+ auto cb = [&newSuffix](hidl_string s) { newSuffix = s; };
+ module->getSuffix(module->getCurrentSlot(), cb);
+ if (oldSuffix == newSuffix) return true;
+ }
+ }
+ }
return false;
}
bool cp_needsCheckpoint(void) {
bool ret;
std::string content;
+ sp<IBootControl> module = IBootControl::getService();
+ if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE)
+ return true;
ret = android::base::ReadFileToString(kMetadataCPFile, &content);
if (ret) return content != "0";
return false;
@@ -297,8 +327,9 @@ bool cp_markBootAttempt() {
std::string oldContent, newContent;
int retry = 0;
if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) return false;
+ std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
- if (!android::base::ParseInt(oldContent, &retry)) return false;
+ if (!android::base::ParseInt(retryContent, &retry)) return false;
if (retry > 0) retry--;
newContent = std::to_string(retry);
diff --git a/Checkpoint.h b/Checkpoint.h
index 81fba992..54574a74 100644
--- a/Checkpoint.h
+++ b/Checkpoint.h
@@ -28,7 +28,7 @@ bool cp_commitChanges();
void cp_abortChanges();
-bool cp_needRollback(const std::string& id);
+bool cp_needsRollback();
bool cp_needsCheckpoint();
diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp
index 41250c71..3884875f 100644
--- a/VoldNativeService.cpp
+++ b/VoldNativeService.cpp
@@ -773,6 +773,14 @@ binder::Status VoldNativeService::startCheckpoint(int32_t retry, bool* _aidl_ret
return ok();
}
+binder::Status VoldNativeService::needsRollback(bool* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_LOCK;
+
+ *_aidl_return = cp_needsRollback();
+ return ok();
+}
+
binder::Status VoldNativeService::needsCheckpoint(bool* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
ACQUIRE_LOCK;
diff --git a/VoldNativeService.h b/VoldNativeService.h
index 9a05b45a..594c002b 100644
--- a/VoldNativeService.h
+++ b/VoldNativeService.h
@@ -116,6 +116,7 @@ class VoldNativeService : public BinderService<VoldNativeService>, public os::Bn
binder::Status startCheckpoint(int32_t retry, bool* _aidl_return);
binder::Status needsCheckpoint(bool* _aidl_return);
+ binder::Status needsRollback(bool* _aidl_return);
binder::Status commitChanges(bool* _aidl_return);
binder::Status prepareDriveForCheckpoint(const std::string& mountPoint, bool* _aidl_return);
binder::Status restoreCheckpoint(const std::string& mountPoint, bool* _aidl_return);
diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl
index f4458a8c..27330fe2 100644
--- a/binder/android/os/IVold.aidl
+++ b/binder/android/os/IVold.aidl
@@ -98,6 +98,7 @@ interface IVold {
boolean startCheckpoint(int retry);
boolean needsCheckpoint();
+ boolean needsRollback();
void abortChanges();
boolean commitChanges();
boolean prepareDriveForCheckpoint(@utf8InCpp String mountPoint);
diff --git a/vdc.cpp b/vdc.cpp
index a080c178..5e2c37a6 100644
--- a/vdc.cpp
+++ b/vdc.cpp
@@ -115,6 +115,10 @@ int main(int argc, char** argv) {
bool enabled = false;
checkStatus(vold->needsCheckpoint(&enabled));
return enabled ? 1 : 0;
+ } else if (args[0] == "checkpoint" && args[1] == "needsRollback" && args.size() == 2) {
+ bool enabled = false;
+ checkStatus(vold->needsRollback(&enabled));
+ return enabled ? 1 : 0;
} else if (args[0] == "checkpoint" && args[1] == "commitChanges" && args.size() == 2) {
bool success = false;
checkStatus(vold->commitChanges(&success));