summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp1
-rw-r--r--aidl/android/gsi/IGsiService.aidl14
-rw-r--r--file_paths.h12
-rw-r--r--gsi_service.cpp129
-rw-r--r--gsi_service.h7
-rw-r--r--gsi_tool.cpp62
-rw-r--r--include/libgsi/libgsi.h24
-rw-r--r--libgsi.cpp11
-rw-r--r--partition_installer.cpp23
-rw-r--r--partition_installer.h6
10 files changed, 226 insertions, 63 deletions
diff --git a/Android.bp b/Android.bp
index f911851..2197784 100644
--- a/Android.bp
+++ b/Android.bp
@@ -103,6 +103,7 @@ cc_binary {
"libgsid",
"liblp",
"libutils",
+ "libc++fs",
],
local_include_dirs: ["include"],
}
diff --git a/aidl/android/gsi/IGsiService.aidl b/aidl/android/gsi/IGsiService.aidl
index 11ea3f5..cd48c63 100644
--- a/aidl/android/gsi/IGsiService.aidl
+++ b/aidl/android/gsi/IGsiService.aidl
@@ -77,10 +77,12 @@ interface IGsiService {
*
* @param oneShot If true, the GSI will boot once and then disable itself.
* It can still be re-enabled again later with setGsiBootable.
+ * @param dsuSlot The DSU slot to be enabled. Possible values are available
+ * with the getInstalledDsuSlots()
*
* @return INSTALL_* error code.
*/
- int enableGsi(boolean oneShot);
+ int enableGsi(boolean oneShot, @utf8InCpp String dsuSlot);
/**
* @return True if Gsi is enabled
@@ -122,12 +124,22 @@ interface IGsiService {
boolean isGsiRunning();
/**
+ * Returns the active DSU slot if there is any DSU installed, empty string otherwise.
+ */
+ @utf8InCpp String getActiveDsuSlot();
+
+ /**
* If a GSI is installed, returns the directory where the installed images
* are located. Otherwise, returns an empty string.
*/
@utf8InCpp String getInstalledGsiImageDir();
/**
+ * Returns all installed DSU slots.
+ */
+ @utf8InCpp List<String> getInstalledDsuSlots();
+
+ /**
* Open a DSU installation
*
* @param installDir The directory to install DSU images under. This must be
diff --git a/file_paths.h b/file_paths.h
index b596704..1ae7817 100644
--- a/file_paths.h
+++ b/file_paths.h
@@ -16,22 +16,26 @@
#pragma once
+#include <filesystem>
+
namespace android {
namespace gsi {
static constexpr char kDefaultDsuImageFolder[] = "/data/gsi/dsu/";
static constexpr char kUserdataDevice[] = "/dev/block/by-name/userdata";
-static constexpr char kDsuMetadataDir[] = "/metadata/gsi/dsu";
-static constexpr char kDsuOneShotBootFile[] = "/metadata/gsi/dsu/one_shot_boot";
-static constexpr char kDsuInstallDirFile[] = "/metadata/gsi/dsu/install_dir";
+static inline std::string MetadataDir(const std::string& dsu_slot) {
+ return std::filesystem::path(DSU_METADATA_PREFIX) / dsu_slot;
+}
+
+static constexpr char kDsuOneShotBootFile[] = DSU_METADATA_PREFIX "one_shot_boot";
// This file can contain the following values:
// [int] - boot attempt counter, starting from 0
// "ok" - boot was marked successful
// "disabled" - boot into GSI no longer allowed
// "wipe" - boot into GSI not allowed; next reboot will delete gsi
-static constexpr char kDsuInstallStatusFile[] = "/metadata/gsi/dsu/install_status";
+static constexpr char kDsuInstallStatusFile[] = DSU_METADATA_PREFIX "install_status";
} // namespace gsi
} // namespace android
diff --git a/gsi_service.cpp b/gsi_service.cpp
index 3ed097e..a782d63 100644
--- a/gsi_service.cpp
+++ b/gsi_service.cpp
@@ -52,7 +52,6 @@ using namespace android::fs_mgr;
using namespace android::fiemap;
using android::base::ReadFileToString;
using android::base::RemoveFileIfExists;
-using android::base::Split;
using android::base::StringPrintf;
using android::base::unique_fd;
using android::base::WriteStringToFd;
@@ -115,10 +114,19 @@ android::sp<IGsiService> GsiService::Get(Gsid* parent) {
} while (0)
int GsiService::SaveInstallation(const std::string& installation) {
+ auto dsu_slot = GetDsuSlot(installation);
+ auto install_dir_file = DsuInstallDirFile(dsu_slot);
+ auto metadata_dir = android::base::Dirname(install_dir_file);
+ if (access(metadata_dir.c_str(), F_OK) != 0) {
+ if (mkdir(metadata_dir.c_str(), 0777) != 0) {
+ PLOG(ERROR) << "Failed to mkdir " << metadata_dir;
+ return INSTALL_ERROR_GENERIC;
+ }
+ }
auto fd = android::base::unique_fd(
- open(kDsuInstallDirFile, O_RDWR | O_SYNC | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR));
+ open(install_dir_file.c_str(), O_RDWR | O_SYNC | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR));
if (!WriteStringToFd(installation, fd)) {
- PLOG(ERROR) << "write failed: " << kDsuInstallDirFile;
+ PLOG(ERROR) << "write failed: " << DsuInstallDirFile(dsu_slot);
return INSTALL_ERROR_GENERIC;
}
return INSTALL_OK;
@@ -137,7 +145,8 @@ binder::Status GsiService::openInstall(const std::string& install_dir, int* _aid
return binder::Status::ok();
}
std::string message;
- if (!RemoveFileIfExists(GetCompleteIndication(install_dir_), &message)) {
+ auto dsu_slot = GetDsuSlot(install_dir_);
+ if (!RemoveFileIfExists(GetCompleteIndication(dsu_slot), &message)) {
LOG(ERROR) << message;
}
// Remember the installation directory before allocate any resource
@@ -148,12 +157,12 @@ binder::Status GsiService::openInstall(const std::string& install_dir, int* _aid
binder::Status GsiService::closeInstall(int* _aidl_return) {
ENFORCE_SYSTEM;
std::lock_guard<std::mutex> guard(parent_->lock());
- std::string file = GetCompleteIndication(install_dir_);
+ auto dsu_slot = GetDsuSlot(install_dir_);
+ std::string file = GetCompleteIndication(dsu_slot);
if (!WriteStringToFile("OK", file)) {
PLOG(ERROR) << "write failed: " << file;
*_aidl_return = INSTALL_ERROR_GENERIC;
}
- install_dir_ = {};
*_aidl_return = INSTALL_OK;
return binder::Status::ok();
}
@@ -183,7 +192,8 @@ binder::Status GsiService::createPartition(const ::std::string& name, int64_t si
if (size == 0 && name == "userdata") {
size = kDefaultUserdataSize;
}
- installer_ = std::make_unique<PartitionInstaller>(this, install_dir_, name, size, readOnly);
+ installer_ = std::make_unique<PartitionInstaller>(this, install_dir_, name,
+ GetDsuSlot(install_dir_), size, readOnly);
int status = installer_->StartInstall();
if (status != INSTALL_OK) {
installer_ = nullptr;
@@ -248,6 +258,7 @@ binder::Status GsiService::commitGsiChunkFromAshmem(int64_t bytes, bool* _aidl_r
binder::Status GsiService::setGsiAshmem(const ::android::os::ParcelFileDescriptor& ashmem,
int64_t size, bool* _aidl_return) {
+ ENFORCE_SYSTEM;
if (!installer_) {
*_aidl_return = false;
return binder::Status::ok();
@@ -256,9 +267,14 @@ binder::Status GsiService::setGsiAshmem(const ::android::os::ParcelFileDescripto
return binder::Status::ok();
}
-binder::Status GsiService::enableGsi(bool one_shot, int* _aidl_return) {
+binder::Status GsiService::enableGsi(bool one_shot, const std::string& dsuSlot, int* _aidl_return) {
std::lock_guard<std::mutex> guard(parent_->lock());
+ if (!WriteStringToFile(dsuSlot, kDsuActiveFile)) {
+ PLOG(ERROR) << "write failed: " << GetDsuSlot(install_dir_);
+ *_aidl_return = INSTALL_ERROR_GENERIC;
+ return binder::Status::ok();
+ }
if (installer_) {
ENFORCE_SYSTEM;
installer_ = {};
@@ -285,7 +301,7 @@ binder::Status GsiService::isGsiEnabled(bool* _aidl_return) {
if (!GetInstallStatus(&boot_key)) {
*_aidl_return = false;
} else {
- *_aidl_return = (boot_key == kInstallStatusOk);
+ *_aidl_return = (boot_key != kInstallStatusDisabled);
}
return binder::Status::ok();
}
@@ -356,6 +372,21 @@ binder::Status GsiService::getInstalledGsiImageDir(std::string* _aidl_return) {
return binder::Status::ok();
}
+binder::Status GsiService::getActiveDsuSlot(std::string* _aidl_return) {
+ ENFORCE_SYSTEM_OR_SHELL;
+ std::lock_guard<std::mutex> guard(parent_->lock());
+
+ *_aidl_return = GetActiveDsuSlot();
+ return binder::Status::ok();
+}
+
+binder::Status GsiService::getInstalledDsuSlots(std::vector<std::string>* _aidl_return) {
+ ENFORCE_SYSTEM;
+ std::lock_guard<std::mutex> guard(parent_->lock());
+ *_aidl_return = GetInstalledDsuSlots();
+ return binder::Status::ok();
+}
+
binder::Status GsiService::zeroPartition(const std::string& name, int* _aidl_return) {
ENFORCE_SYSTEM_OR_SHELL;
std::lock_guard<std::mutex> guard(parent_->lock());
@@ -366,7 +397,7 @@ binder::Status GsiService::zeroPartition(const std::string& name, int* _aidl_ret
}
std::string install_dir = GetActiveInstalledImageDir();
- *_aidl_return = PartitionInstaller::WipeWritable(install_dir, name);
+ *_aidl_return = PartitionInstaller::WipeWritable(GetDsuSlot(install_dir), install_dir, name);
return binder::Status::ok();
}
@@ -589,7 +620,11 @@ binder::Status GsiService::openImageService(const std::string& prefix,
auto in_metadata_dir = kImageMetadataPrefix + prefix;
auto in_data_dir = kImageDataPrefix + prefix;
+ auto install_dir_file = DsuInstallDirFile(GetDsuSlot(prefix));
+ if (android::base::ReadFileToString(install_dir_file, &in_data_dir)) {
+ LOG(INFO) << "load " << install_dir_file << ":" << in_data_dir;
+ }
std::string metadata_dir, data_dir;
if (!android::base::Realpath(in_metadata_dir, &metadata_dir)) {
PLOG(ERROR) << "realpath failed: " << metadata_dir;
@@ -693,6 +728,15 @@ int GsiService::ValidateInstallParams(std::string& install_dir) {
return INSTALL_OK;
}
+std::string GsiService::GetActiveDsuSlot() {
+ if (!install_dir_.empty()) {
+ return GetDsuSlot(install_dir_);
+ } else {
+ std::string active_dsu;
+ return GetActiveDsu(&active_dsu) ? active_dsu : "";
+ }
+}
+
std::string GsiService::GetActiveInstalledImageDir() {
// Just in case an install was left hanging.
if (installer_) {
@@ -705,8 +749,10 @@ std::string GsiService::GetActiveInstalledImageDir() {
std::string GsiService::GetInstalledImageDir() {
// If there's no install left, just return /data/gsi since that's where
// installs go by default.
+ std::string active_dsu;
std::string dir;
- if (android::base::ReadFileToString(kDsuInstallDirFile, &dir)) {
+ if (GetActiveDsu(&active_dsu) &&
+ android::base::ReadFileToString(DsuInstallDirFile(active_dsu), &dir)) {
return dir;
}
return kDefaultDsuImageFolder;
@@ -740,10 +786,11 @@ int GsiService::ReenableGsi(bool one_shot) {
bool GsiService::RemoveGsiFiles(const std::string& install_dir) {
bool ok = true;
- if (auto manager = ImageManager::Open(kDsuMetadataDir, install_dir)) {
+ auto active_dsu = GetDsuSlot(install_dir);
+ if (auto manager = ImageManager::Open(MetadataDir(active_dsu), install_dir)) {
std::vector<std::string> images = manager->GetAllBackingImages();
for (auto&& image : images) {
- if (!android::base::EndsWith(image, "_gsi")) {
+ if (!android::base::EndsWith(image, kDsuPostfix)) {
continue;
}
if (manager->IsImageMapped(image)) {
@@ -752,11 +799,12 @@ bool GsiService::RemoveGsiFiles(const std::string& install_dir) {
ok &= manager->DeleteBackingImage(image);
}
}
+ auto dsu_slot = GetDsuSlot(install_dir);
std::vector<std::string> files{
kDsuInstallStatusFile,
kDsuOneShotBootFile,
- kDsuInstallDirFile,
- GetCompleteIndication(install_dir),
+ DsuInstallDirFile(dsu_slot),
+ GetCompleteIndication(dsu_slot),
};
for (const auto& file : files) {
std::string message;
@@ -784,14 +832,15 @@ bool GsiService::DisableGsiInstall() {
return true;
}
-std::string GsiService::GetCompleteIndication(const std::string& installation) {
- auto strip_slash = installation.substr(0, installation.size() - 1);
- auto prefix = Split(strip_slash, "/").back();
- return "/metadata/gsi/" + prefix + "/complete";
+std::string GsiService::GetCompleteIndication(const std::string& dsu_slot) {
+ return DSU_METADATA_PREFIX + dsu_slot + "/complete";
}
-bool GsiService::IsInstallationComplete(const std::string& install_dir) {
- std::string file = GetCompleteIndication(install_dir);
+bool GsiService::IsInstallationComplete(const std::string& dsu_slot) {
+ if (access(kDsuInstallStatusFile, F_OK) != 0) {
+ return false;
+ }
+ std::string file = GetCompleteIndication(dsu_slot);
std::string content;
if (!ReadFileToString(file, &content)) {
return false;
@@ -799,12 +848,35 @@ bool GsiService::IsInstallationComplete(const std::string& install_dir) {
return content == "OK";
}
+std::vector<std::string> GsiService::GetInstalledDsuSlots() {
+ std::vector<std::string> dsu_slots;
+ auto d = std::unique_ptr<DIR, decltype(&closedir)>(opendir(DSU_METADATA_PREFIX), closedir);
+ if (d != nullptr) {
+ struct dirent* de;
+ while ((de = readdir(d.get())) != nullptr) {
+ if (de->d_name[0] == '.') {
+ continue;
+ }
+ auto dsu_slot = std::string(de->d_name);
+ if (access(DsuInstallDirFile(dsu_slot).c_str(), F_OK) != 0) {
+ continue;
+ }
+ dsu_slots.push_back(dsu_slot);
+ }
+ }
+ return dsu_slots;
+}
+
void GsiService::CleanCorruptedInstallation() {
- auto install_dir = GetInstalledImageDir();
- bool is_complete = IsInstallationComplete(install_dir);
- if (!is_complete) {
- if (!RemoveGsiFiles(install_dir)) {
- LOG(ERROR) << "Failed to CleanCorruptedInstallation on " << install_dir;
+ for (auto&& slot : GetInstalledDsuSlots()) {
+ bool is_complete = IsInstallationComplete(slot);
+ if (!is_complete) {
+ LOG(INFO) << "CleanCorruptedInstallation for slot: " << slot;
+ std::string install_dir;
+ if (!android::base::ReadFileToString(DsuInstallDirFile(slot), &install_dir) ||
+ !RemoveGsiFiles(install_dir)) {
+ LOG(ERROR) << "Failed to CleanCorruptedInstallation on " << slot;
+ }
}
}
}
@@ -812,6 +884,11 @@ void GsiService::CleanCorruptedInstallation() {
void GsiService::RunStartupTasks() {
CleanCorruptedInstallation();
+ std::string active_dsu;
+ if (!GetActiveDsu(&active_dsu)) {
+ PLOG(INFO) << "no DSU";
+ return;
+ }
std::string boot_key;
if (!GetInstallStatus(&boot_key)) {
PLOG(ERROR) << "read " << kDsuInstallStatusFile;
diff --git a/gsi_service.h b/gsi_service.h
index fe70a04..b828899 100644
--- a/gsi_service.h
+++ b/gsi_service.h
@@ -68,7 +68,7 @@ class GsiService : public BinderService<GsiService>, public BnGsiService {
bool* _aidl_return) override;
binder::Status commitGsiChunkFromAshmem(int64_t bytes, bool* _aidl_return) override;
binder::Status cancelGsiInstall(bool* _aidl_return) override;
- binder::Status enableGsi(bool oneShot, int* _aidl_return) override;
+ binder::Status enableGsi(bool oneShot, const std::string& dsuSlot, int* _aidl_return) override;
binder::Status isGsiEnabled(bool* _aidl_return) override;
binder::Status removeGsi(bool* _aidl_return) override;
binder::Status disableGsi(bool* _aidl_return) override;
@@ -76,6 +76,8 @@ class GsiService : public BinderService<GsiService>, public BnGsiService {
binder::Status isGsiRunning(bool* _aidl_return) override;
binder::Status isGsiInstallInProgress(bool* _aidl_return) override;
binder::Status getInstalledGsiImageDir(std::string* _aidl_return) override;
+ binder::Status getActiveDsuSlot(std::string* _aidl_return) override;
+ binder::Status getInstalledDsuSlots(std::vector<std::string>* _aidl_return) override;
binder::Status zeroPartition(const std::string& name, int* _aidl_return) override;
binder::Status openImageService(const std::string& prefix,
android::sp<IImageService>* _aidl_return) override;
@@ -93,8 +95,11 @@ class GsiService : public BinderService<GsiService>, public BnGsiService {
static void RunStartupTasks();
static std::string GetInstalledImageDir();
+ std::string GetActiveDsuSlot();
std::string GetActiveInstalledImageDir();
+ static std::vector<std::string> GetInstalledDsuSlots();
+
private:
GsiService(Gsid* parent);
static int ValidateInstallParams(std::string& install_dir);
diff --git a/gsi_tool.cpp b/gsi_tool.cpp
index 6cafd82..9abb1ff 100644
--- a/gsi_tool.cpp
+++ b/gsi_tool.cpp
@@ -299,8 +299,13 @@ static int Install(sp<IGsiService> gsid, int argc, char** argv) {
return EX_SOFTWARE;
}
progress.Finish();
-
- status = gsid->enableGsi(true, &error);
+ std::string dsuSlot;
+ status = gsid->getActiveDsuSlot(&dsuSlot);
+ if (!status.isOk()) {
+ std::cerr << "Could not get the active DSU slot: " << ErrorMessage(status) << "\n";
+ return EX_SOFTWARE;
+ }
+ status = gsid->enableGsi(true, dsuSlot, &error);
if (!status.isOk() || error != IGsiService::INSTALL_OK) {
std::cerr << "Could not make live image bootable: " << ErrorMessage(status, error) << "\n";
return EX_SOFTWARE;
@@ -409,21 +414,31 @@ static int Status(sp<IGsiService> gsid, int argc, char** /* argv */) {
if (getuid() != 0) {
return 0;
}
- sp<IImageService> image_service = nullptr;
- status = gsid->openImageService("dsu", &image_service);
- if (!status.isOk()) {
- std::cerr << "error: " << status.exceptionMessage().string() << std::endl;
- return EX_SOFTWARE;
- }
- std::vector<std::string> images;
- status = image_service->getAllBackingImages(&images);
+
+ std::vector<std::string> dsu_slots;
+ status = gsid->getInstalledDsuSlots(&dsu_slots);
if (!status.isOk()) {
- std::cerr << "error: " << status.exceptionMessage().string() << std::endl;
+ std::cerr << status.exceptionMessage().string() << std::endl;
return EX_SOFTWARE;
}
-
- for (auto&& image : images) {
- std::cout << "installed: " << image << std::endl;
+ int n = 0;
+ for (auto&& dsu_slot : dsu_slots) {
+ std::cout << "[" << n++ << "] " << dsu_slot << std::endl;
+ sp<IImageService> image_service = nullptr;
+ status = gsid->openImageService("dsu/" + dsu_slot + "/", &image_service);
+ if (!status.isOk()) {
+ std::cerr << "error: " << status.exceptionMessage().string() << std::endl;
+ return EX_SOFTWARE;
+ }
+ std::vector<std::string> images;
+ status = image_service->getAllBackingImages(&images);
+ if (!status.isOk()) {
+ std::cerr << "error: " << status.exceptionMessage().string() << std::endl;
+ return EX_SOFTWARE;
+ }
+ for (auto&& image : images) {
+ std::cout << "installed: " << image << std::endl;
+ }
}
return 0;
}
@@ -444,9 +459,10 @@ static int Cancel(sp<IGsiService> gsid, int /* argc */, char** /* argv */) {
static int Enable(sp<IGsiService> gsid, int argc, char** argv) {
bool one_shot = false;
-
+ std::string dsuSlot = {};
struct option options[] = {
{"single-boot", no_argument, nullptr, 's'},
+ {"dsuslot", required_argument, nullptr, 'd'},
{nullptr, 0, nullptr, 0},
};
int rv, index;
@@ -455,6 +471,9 @@ static int Enable(sp<IGsiService> gsid, int argc, char** argv) {
case 's':
one_shot = true;
break;
+ case 'd':
+ dsuSlot = optarg;
+ break;
default:
std::cerr << "Unrecognized argument to enable\n";
return EX_USAGE;
@@ -474,9 +493,15 @@ static int Enable(sp<IGsiService> gsid, int argc, char** argv) {
std::cerr << "Cannot enable or disable while an installation is in progress." << std::endl;
return EX_SOFTWARE;
}
-
+ if (dsuSlot.empty()) {
+ auto status = gsid->getActiveDsuSlot(&dsuSlot);
+ if (!status.isOk()) {
+ std::cerr << "Could not get the active DSU slot: " << ErrorMessage(status) << "\n";
+ return EX_SOFTWARE;
+ }
+ }
int error;
- auto status = gsid->enableGsi(one_shot, &error);
+ auto status = gsid->enableGsi(one_shot, dsuSlot, &error);
if (!status.isOk() || error != IGsiService::INSTALL_OK) {
std::cerr << "Error re-enabling GSI: " << ErrorMessage(status, error) << "\n";
return EX_SOFTWARE;
@@ -516,7 +541,8 @@ static int usage(int /* argc */, char* argv[]) {
" %s <disable|install|wipe|status> [options]\n"
"\n"
" disable Disable the currently installed GSI.\n"
- " enable [-s, --single-boot]\n"
+ " enable [-s, --single-boot]\n"
+ " [-d, --dsuslot slotname]\n"
" Enable a previously disabled GSI.\n"
" install Install a new GSI. Specify the image size with\n"
" --gsi-size and the desired userdata size with\n"
diff --git a/include/libgsi/libgsi.h b/include/libgsi/libgsi.h
index 9b24f47..987797a 100644
--- a/include/libgsi/libgsi.h
+++ b/include/libgsi/libgsi.h
@@ -23,11 +23,25 @@ namespace gsi {
static constexpr char kGsiServiceName[] = "gsiservice";
-static constexpr char kGsiBootedIndicatorFile[] = "/metadata/gsi/dsu/booted";
+#define DSU_METADATA_PREFIX "/metadata/gsi/dsu/"
-static constexpr char kGsiLpNamesFile[] = "/metadata/gsi/dsu/lp_names";
+static constexpr char kGsiBootedIndicatorFile[] = DSU_METADATA_PREFIX "booted";
-static constexpr char kDsuLpMetadataFile[] = "/metadata/gsi/dsu/lp_metadata";
+static constexpr char kGsiLpNamesFile[] = DSU_METADATA_PREFIX "lp_names";
+
+static constexpr char kDsuActiveFile[] = DSU_METADATA_PREFIX "active";
+
+static inline std::string DsuLpMetadataFile(const std::string& dsu_slot) {
+ return DSU_METADATA_PREFIX + dsu_slot + "/lp_metadata";
+}
+
+static inline std::string DsuInstallDirFile(const std::string& dsu_slot) {
+ return DSU_METADATA_PREFIX + dsu_slot + "/install_dir";
+}
+
+// install_dir "/data/gsi/dsu/dsu" has a slot name "dsu"
+// install_dir "/data/gsi/dsu/dsu2" has a slot name "dsu2"
+std::string GetDsuSlot(const std::string& install_dir);
static constexpr char kGsiBootedProp[] = "ro.gsid.image_running";
@@ -35,6 +49,10 @@ static constexpr char kDsuPostfix[] = "_gsi";
static constexpr int kMaxBootAttempts = 1;
+// Get the currently active dsu slot
+// Return true on success
+bool GetActiveDsu(std::string* active_dsu);
+
// Returns true if the currently running system image is a live GSI.
bool IsGsiRunning();
diff --git a/libgsi.cpp b/libgsi.cpp
index 2c8deb0..b342cc5 100644
--- a/libgsi.cpp
+++ b/libgsi.cpp
@@ -23,6 +23,7 @@
#include <android-base/file.h>
#include <android-base/parseint.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include "file_paths.h"
@@ -32,8 +33,14 @@ namespace android {
namespace gsi {
using namespace std::literals;
+using android::base::ReadFileToString;
+using android::base::Split;
using android::base::unique_fd;
+bool GetActiveDsu(std::string* active_dsu) {
+ return android::base::ReadFileToString(kDsuActiveFile, active_dsu);
+}
+
bool IsGsiRunning() {
return !access(kGsiBootedIndicatorFile, F_OK);
}
@@ -53,6 +60,10 @@ static bool WriteAndSyncFile(const std::string& data, const std::string& file) {
return fsync(fd) == 0;
}
+std::string GetDsuSlot(const std::string& install_dir) {
+ return android::base::Basename(install_dir);
+}
+
bool CanBootIntoGsi(std::string* error) {
// Always delete this as a safety precaution, so we can return to the
// original system image. If we're confident GSI will boot, this will
diff --git a/partition_installer.cpp b/partition_installer.cpp
index 8e67420..ff2cc59 100644
--- a/partition_installer.cpp
+++ b/partition_installer.cpp
@@ -44,9 +44,15 @@ using android::base::unique_fd;
static constexpr uint32_t kMinimumFreeSpaceThreshold = 40;
PartitionInstaller::PartitionInstaller(GsiService* service, const std::string& install_dir,
- const std::string& name, int64_t size, bool read_only)
- : service_(service), install_dir_(install_dir), name_(name), size_(size), readOnly_(read_only) {
- images_ = ImageManager::Open(kDsuMetadataDir, install_dir_);
+ const std::string& name, const std::string& active_dsu,
+ int64_t size, bool read_only)
+ : service_(service),
+ install_dir_(install_dir),
+ name_(name),
+ active_dsu_(active_dsu),
+ size_(size),
+ readOnly_(read_only) {
+ images_ = ImageManager::Open(MetadataDir(active_dsu), install_dir_);
}
PartitionInstaller::~PartitionInstaller() {
@@ -62,7 +68,7 @@ PartitionInstaller::~PartitionInstaller() {
}
void PartitionInstaller::PostInstallCleanup() {
- auto manager = ImageManager::Open(kDsuMetadataDir, GsiService::GetInstalledImageDir());
+ auto manager = ImageManager::Open(MetadataDir(active_dsu_), install_dir_);
if (!manager) {
LOG(ERROR) << "Could not open image manager";
return;
@@ -299,13 +305,13 @@ bool PartitionInstaller::Format() {
}
int PartitionInstaller::Finish() {
- if (!readOnly_ && gsi_bytes_written_ != size_) {
+ if (readOnly_ && gsi_bytes_written_ != size_) {
// We cannot boot if the image is incomplete.
LOG(ERROR) << "image incomplete; expected " << size_ << " bytes, waiting for "
<< (size_ - gsi_bytes_written_) << " bytes";
return IGsiService::INSTALL_ERROR_GENERIC;
}
- if (fsync(system_device_->fd())) {
+ if (system_device_ != nullptr && fsync(system_device_->fd())) {
PLOG(ERROR) << "fsync failed for " << name_ << "_gsi";
return IGsiService::INSTALL_ERROR_GENERIC;
}
@@ -321,8 +327,9 @@ int PartitionInstaller::Finish() {
return IGsiService::INSTALL_OK;
}
-int PartitionInstaller::WipeWritable(const std::string& install_dir, const std::string& name) {
- auto image = ImageManager::Open(kDsuMetadataDir, install_dir);
+int PartitionInstaller::WipeWritable(const std::string& active_dsu, const std::string& install_dir,
+ const std::string& name) {
+ auto image = ImageManager::Open(MetadataDir(active_dsu), install_dir);
// The device object has to be destroyed before the image object
auto device = MappedDevice::Open(image.get(), 10s, name);
if (!device) {
diff --git a/partition_installer.h b/partition_installer.h
index 787eda4..830c034 100644
--- a/partition_installer.h
+++ b/partition_installer.h
@@ -39,7 +39,7 @@ class PartitionInstaller final {
public:
// Constructor for a new GSI installation.
PartitionInstaller(GsiService* service, const std::string& installDir, const std::string& name,
- int64_t size, bool read_only);
+ const std::string& active_dsu, int64_t size, bool read_only);
~PartitionInstaller();
// Methods for a clean GSI install.
@@ -49,7 +49,8 @@ class PartitionInstaller final {
bool MapAshmem(int fd, size_t size);
bool CommitGsiChunk(size_t bytes);
- static int WipeWritable(const std::string& install_dir, const std::string& name);
+ static int WipeWritable(const std::string& active_dsu, const std::string& install_dir,
+ const std::string& name);
// Clean up install state if gsid crashed and restarted.
void PostInstallCleanup();
@@ -74,6 +75,7 @@ class PartitionInstaller final {
std::string install_dir_;
std::string name_;
+ std::string active_dsu_;
std::unique_ptr<ImageManager> images_;
uint64_t size_ = 0;
bool readOnly_;