Add vdc checkpoint restoreCheckpointPart

Restores the first n entries of a checkpoint. Allows automated testing
of interrupted restores.

Test: vdc checkpoint restoreCheckpoint [device] [n]
Change-Id: I47570e8eba0bc3c6549a04a33600df05d393990b
diff --git a/Checkpoint.cpp b/Checkpoint.cpp
index 1020ad7..08f0fce 100644
--- a/Checkpoint.cpp
+++ b/Checkpoint.cpp
@@ -371,9 +371,10 @@
 
 }  // namespace
 
-Status cp_restoreCheckpoint(const std::string& blockDevice) {
+Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
     bool validating = true;
     std::string action = "Validating";
+    int restore_count = 0;
 
     for (;;) {
         Relocations relocations;
@@ -449,6 +450,12 @@
                 } else {
                     lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
                     write(device_fd, &buffer[0], le->size);
+                    restore_count++;
+                    if (restore_limit && restore_count >= restore_limit) {
+                        LOG(WARNING) << "Hit the test limit";
+                        status = Status::fromExceptionCode(EAGAIN, "Hit the test limit");
+                        break;
+                    }
                 }
             }
         }
diff --git a/Checkpoint.h b/Checkpoint.h
index 64ceed3..70dad8a 100644
--- a/Checkpoint.h
+++ b/Checkpoint.h
@@ -37,7 +37,7 @@
 
 android::binder::Status cp_prepareCheckpoint();
 
-android::binder::Status cp_restoreCheckpoint(const std::string& mountPoint);
+android::binder::Status cp_restoreCheckpoint(const std::string& mountPoint, int count = 0);
 
 android::binder::Status cp_markBootAttempt();
 
diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp
index 1001d2b..69f8a8c 100644
--- a/VoldNativeService.cpp
+++ b/VoldNativeService.cpp
@@ -850,6 +850,14 @@
     return cp_restoreCheckpoint(mountPoint);
 }
 
+binder::Status VoldNativeService::restoreCheckpointPart(const std::string& mountPoint, int count) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PATH(mountPoint);
+    ACQUIRE_LOCK;
+
+    return cp_restoreCheckpoint(mountPoint, count);
+}
+
 binder::Status VoldNativeService::markBootAttempt() {
     ENFORCE_UID(AID_SYSTEM);
     ACQUIRE_LOCK;
diff --git a/VoldNativeService.h b/VoldNativeService.h
index 7db3e5c..954b8ae 100644
--- a/VoldNativeService.h
+++ b/VoldNativeService.h
@@ -127,6 +127,7 @@
     binder::Status commitChanges();
     binder::Status prepareCheckpoint();
     binder::Status restoreCheckpoint(const std::string& mountPoint);
+    binder::Status restoreCheckpointPart(const std::string& mountPoint, int count);
     binder::Status markBootAttempt();
     binder::Status abortChanges();
     binder::Status supportsCheckpoint(bool* _aidl_return);
diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl
index 4b21078..83ee116 100644
--- a/binder/android/os/IVold.aidl
+++ b/binder/android/os/IVold.aidl
@@ -103,6 +103,7 @@
     void commitChanges();
     void prepareCheckpoint();
     void restoreCheckpoint(@utf8InCpp String device);
+    void restoreCheckpointPart(@utf8InCpp String device, int count);
     void markBootAttempt();
     boolean supportsCheckpoint();
 
diff --git a/vdc.cpp b/vdc.cpp
index 35775a7..d01fb49 100644
--- a/vdc.cpp
+++ b/vdc.cpp
@@ -127,6 +127,10 @@
         checkStatus(vold->prepareCheckpoint());
     } else if (args[0] == "checkpoint" && args[1] == "restoreCheckpoint" && args.size() == 3) {
         checkStatus(vold->restoreCheckpoint(args[2]));
+    } else if (args[0] == "checkpoint" && args[1] == "restoreCheckpointPart" && args.size() == 4) {
+        int count;
+        if (!android::base::ParseInt(args[3], &count)) exit(EINVAL);
+        checkStatus(vold->restoreCheckpointPart(args[2], count));
     } else if (args[0] == "checkpoint" && args[1] == "markBootAttempt" && args.size() == 2) {
         checkStatus(vold->markBootAttempt());
     } else if (args[0] == "checkpoint" && args[1] == "abortChanges" && args.size() == 2) {