summaryrefslogtreecommitdiff
path: root/gsi_service.cpp
diff options
context:
space:
mode:
authorHoward Chen <howardsoc@google.com>2019-11-05 20:46:20 +0800
committerHoward Chen <howardsoc@google.com>2019-11-12 20:13:26 +0800
commit4663de60960272ce35e390f325a4448992b5f6a0 (patch)
tree824ebcd05b938e791a9640c5ad72d08c50625d74 /gsi_service.cpp
parent4d4c722d2fc0a5583d52a2f3111553c168f73979 (diff)
downloadgsid-4663de60960272ce35e390f325a4448992b5f6a0.tar.gz
Refactoring
* Remove GsiInstallParams.aidl * GsiInstaller -> PartitionInstaller * beginGsiInstall -> open, close, createPartition * wipeUserdata -> zeroPartition * GetInstallation returns current installation * SaveInstallation save current installation Test: gsi_tool install & reboot adb shell am start-activity \ -n com.android.dynsystem/com.android.dynsystem.VerificationActivity \ -a android.os.image.action.START_INSTALL \ -d file:///storage/emulated/0/Download/system.raw.gz \ --el KEY_SYSTEM_SIZE $(du -b system.raw|cut -f1) \ --el KEY_USERDATA_SIZE 8589934592 Change-Id: I2be8b12130bd0a5f768a496c3a0ca8a3b2682c45
Diffstat (limited to 'gsi_service.cpp')
-rw-r--r--gsi_service.cpp191
1 files changed, 147 insertions, 44 deletions
diff --git a/gsi_service.cpp b/gsi_service.cpp
index dbf0ea6..14e7640 100644
--- a/gsi_service.cpp
+++ b/gsi_service.cpp
@@ -18,6 +18,7 @@
#include <errno.h>
#include <linux/fs.h>
+#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -49,12 +50,20 @@ namespace gsi {
using namespace std::literals;
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;
+using android::base::WriteStringToFile;
using android::dm::DeviceMapper;
android::wp<GsiService> GsiService::sInstance;
+// Default userdata image size.
+static constexpr int64_t kDefaultUserdataSize = int64_t(2) * 1024 * 1024 * 1024;
+
void Gsid::Register() {
auto ret = android::BinderService<Gsid>::publish();
if (ret != android::OK) {
@@ -103,23 +112,76 @@ android::sp<IGsiService> GsiService::Get(Gsid* parent) {
if (!status.isOk()) return status; \
} while (0)
-binder::Status GsiService::beginGsiInstall(const GsiInstallParams& given_params,
- int* _aidl_return) {
+int GsiService::SaveInstallation(const std::string& installation) {
+ auto fd = android::base::unique_fd(
+ open(kDsuInstallDirFile, O_RDWR | O_SYNC | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR));
+ if (!WriteStringToFd(installation, fd)) {
+ PLOG(ERROR) << "write failed: " << kDsuInstallDirFile;
+ return INSTALL_ERROR_GENERIC;
+ }
+ return INSTALL_OK;
+}
+
+binder::Status GsiService::openInstall(const std::string& install_dir, int* _aidl_return) {
ENFORCE_SYSTEM;
std::lock_guard<std::mutex> guard(parent_->lock());
+ if (IsGsiRunning()) {
+ *_aidl_return = IGsiService::INSTALL_ERROR_GENERIC;
+ return binder::Status::ok();
+ }
+ install_dir_ = install_dir;
+ if (int status = ValidateInstallParams(install_dir_)) {
+ *_aidl_return = status;
+ return binder::Status::ok();
+ }
+ std::string message;
+ if (!RemoveFileIfExists(GetCompleteIndication(install_dir_), &message)) {
+ LOG(ERROR) << message;
+ }
+ // Remember the installation directory before allocate any resource
+ *_aidl_return = SaveInstallation(install_dir_);
+ return binder::Status::ok();
+}
- // Make sure any interrupted installations are cleaned up.
+binder::Status GsiService::closeInstall(int* _aidl_return) {
+ ENFORCE_SYSTEM;
+ std::lock_guard<std::mutex> guard(parent_->lock());
+ std::string file = GetCompleteIndication(install_dir_);
+ if (!WriteStringToFile("OK", file)) {
+ PLOG(ERROR) << "write failed: " << file;
+ *_aidl_return = INSTALL_ERROR_GENERIC;
+ }
+ install_dir_ = {};
+ *_aidl_return = INSTALL_OK;
+ return binder::Status::ok();
+}
+
+binder::Status GsiService::createPartition(const ::std::string& name, int64_t size, bool readOnly,
+ int32_t* _aidl_return) {
+ ENFORCE_SYSTEM;
+ std::lock_guard<std::mutex> guard(parent_->lock());
+
+ if (install_dir_.empty()) {
+ PLOG(ERROR) << "open is required for createPartition";
+ *_aidl_return = INSTALL_ERROR_GENERIC;
+ return binder::Status::ok();
+ }
+
+ // Make sure a pending interrupted installations are cleaned up.
installer_ = nullptr;
// Do some precursor validation on the arguments before diving into the
// install process.
- GsiInstallParams params = given_params;
- if (int status = ValidateInstallParams(&params)) {
- *_aidl_return = status;
+ if (size % LP_SECTOR_SIZE) {
+ LOG(ERROR) << " size " << size << " is not a multiple of " << LP_SECTOR_SIZE;
+ *_aidl_return = INSTALL_ERROR_GENERIC;
return binder::Status::ok();
}
- installer_ = std::make_unique<GsiInstaller>(this, params);
+ if (size == 0 && name == "userdata") {
+ size = kDefaultUserdataSize;
+ }
+ installer_ = std::make_unique<PartitionInstaller>(this, install_dir_, name, size, readOnly);
int status = installer_->StartInstall();
if (status != INSTALL_OK) {
installer_ = nullptr;
@@ -197,8 +259,11 @@ binder::Status GsiService::enableGsi(bool one_shot, int* _aidl_return) {
if (installer_) {
ENFORCE_SYSTEM;
- if (int error = installer_->SetGsiBootable(one_shot)) {
- *_aidl_return = error;
+ installer_ = {};
+ // Note: create the install status file last, since this is the actual boot
+ // indicator.
+ if (!SetBootMode(one_shot) || !CreateInstallStatusFile()) {
+ *_aidl_return = IGsiService::INSTALL_ERROR_GENERIC;
} else {
*_aidl_return = INSTALL_OK;
}
@@ -232,7 +297,7 @@ binder::Status GsiService::removeGsi(bool* _aidl_return) {
// Can't remove gsi files while running.
*_aidl_return = UninstallGsi();
} else {
- *_aidl_return = RemoveGsiFiles(install_dir, true /* wipeUserdata */);
+ *_aidl_return = RemoveGsiFiles(install_dir);
}
return binder::Status::ok();
}
@@ -289,7 +354,7 @@ binder::Status GsiService::getInstalledGsiImageDir(std::string* _aidl_return) {
return binder::Status::ok();
}
-binder::Status GsiService::wipeGsiUserdata(int* _aidl_return) {
+binder::Status GsiService::zeroPartition(const std::string& name, int* _aidl_return) {
ENFORCE_SYSTEM_OR_SHELL;
std::lock_guard<std::mutex> guard(parent_->lock());
@@ -299,7 +364,7 @@ binder::Status GsiService::wipeGsiUserdata(int* _aidl_return) {
}
std::string install_dir = GetActiveInstalledImageDir();
- *_aidl_return = GsiInstaller::WipeWritable(install_dir, "userdata");
+ *_aidl_return = PartitionInstaller::WipeWritable(install_dir, name);
return binder::Status::ok();
}
@@ -341,6 +406,30 @@ binder::Status GsiService::dumpDeviceMapperDevices(std::string* _aidl_return) {
return binder::Status::ok();
}
+bool GsiService::CreateInstallStatusFile() {
+ if (!android::base::WriteStringToFile("0", kDsuInstallStatusFile)) {
+ PLOG(ERROR) << "write " << kDsuInstallStatusFile;
+ return false;
+ }
+ return true;
+}
+
+bool GsiService::SetBootMode(bool one_shot) {
+ if (one_shot) {
+ if (!android::base::WriteStringToFile("1", kDsuOneShotBootFile)) {
+ PLOG(ERROR) << "write " << kDsuOneShotBootFile;
+ return false;
+ }
+ } else if (!access(kDsuOneShotBootFile, F_OK)) {
+ std::string error;
+ if (!android::base::RemoveFileIfExists(kDsuOneShotBootFile, &error)) {
+ LOG(ERROR) << error;
+ return false;
+ }
+ }
+ return true;
+}
+
static binder::Status UidSecurityError() {
uid_t uid = IPCThreadState::self()->getCallingUid();
auto message = StringPrintf("UID %d is not allowed", uid);
@@ -527,27 +616,27 @@ static bool IsExternalStoragePath(const std::string& path) {
return info.f_type == MSDOS_SUPER_MAGIC;
}
-int GsiService::ValidateInstallParams(GsiInstallParams* params) {
+int GsiService::ValidateInstallParams(std::string& install_dir) {
// If no install path was specified, use the default path. We also allow
// specifying the top-level folder, and then we choose the correct location
// underneath.
- if (params->installDir.empty() || params->installDir == "/data/gsi") {
- params->installDir = kDefaultDsuImageFolder;
+ if (install_dir.empty() || install_dir == "/data/gsi") {
+ install_dir = kDefaultDsuImageFolder;
}
// Normalize the path and add a trailing slash.
- std::string origInstallDir = params->installDir;
- if (!android::base::Realpath(origInstallDir, &params->installDir)) {
+ std::string origInstallDir = install_dir;
+ if (!android::base::Realpath(origInstallDir, &install_dir)) {
PLOG(ERROR) << "realpath failed: " << origInstallDir;
return INSTALL_ERROR_GENERIC;
}
// Ensure the path ends in / for consistency.
- if (!android::base::EndsWith(params->installDir, "/")) {
- params->installDir += "/";
+ if (!android::base::EndsWith(install_dir, "/")) {
+ install_dir += "/";
}
// Currently, we can only install to /data/gsi/ or external storage.
- if (IsExternalStoragePath(params->installDir)) {
+ if (IsExternalStoragePath(install_dir)) {
Fstab fstab;
if (!ReadDefaultFstab(&fstab)) {
LOG(ERROR) << "cannot read default fstab";
@@ -562,14 +651,8 @@ int GsiService::ValidateInstallParams(GsiInstallParams* params) {
LOG(ERROR) << "cannot install GSIs to external media if verity uses check_at_most_once";
return INSTALL_ERROR_GENERIC;
}
- } else if (params->installDir != kDefaultDsuImageFolder) {
- LOG(ERROR) << "cannot install GSI to " << params->installDir;
- return INSTALL_ERROR_GENERIC;
- }
-
- if (params->size % LP_SECTOR_SIZE) {
- LOG(ERROR) << params->name << " size " << params->size << " is not a multiple of "
- << LP_SECTOR_SIZE;
+ } else if (install_dir != kDefaultDsuImageFolder) {
+ LOG(ERROR) << "cannot install DSU to " << install_dir;
return INSTALL_ERROR_GENERIC;
}
return INSTALL_OK;
@@ -599,7 +682,6 @@ int GsiService::ReenableGsi(bool one_shot) {
LOG(ERROR) << "no gsi installed - cannot re-enable";
return INSTALL_ERROR_GENERIC;
}
-
std::string boot_key;
if (!GetInstallStatus(&boot_key)) {
PLOG(ERROR) << "read " << kDsuInstallStatusFile;
@@ -609,11 +691,19 @@ int GsiService::ReenableGsi(bool one_shot) {
LOG(ERROR) << "GSI is not currently disabled";
return INSTALL_ERROR_GENERIC;
}
-
- return GsiInstaller::ReenableGsi(one_shot);
+ if (IsGsiRunning()) {
+ if (!SetBootMode(one_shot) || !CreateInstallStatusFile()) {
+ return IGsiService::INSTALL_ERROR_GENERIC;
+ }
+ return IGsiService::INSTALL_OK;
+ }
+ if (!SetBootMode(one_shot) || !CreateInstallStatusFile()) {
+ return IGsiService::INSTALL_ERROR_GENERIC;
+ }
+ return IGsiService::INSTALL_OK;
}
-bool GsiService::RemoveGsiFiles(const std::string& install_dir, bool wipeUserdata) {
+bool GsiService::RemoveGsiFiles(const std::string& install_dir) {
bool ok = true;
if (auto manager = ImageManager::Open(kDsuMetadataDir, install_dir)) {
std::vector<std::string> images = manager->GetAllBackingImages();
@@ -624,20 +714,18 @@ bool GsiService::RemoveGsiFiles(const std::string& install_dir, bool wipeUserdat
if (manager->IsImageMapped(image)) {
ok &= manager->UnmapImageDevice(image);
}
- if (!android::base::StartsWith(image, "userdata") || wipeUserdata) {
- ok &= manager->DeleteBackingImage(image);
- }
+ ok &= manager->DeleteBackingImage(image);
}
}
-
std::vector<std::string> files{
kDsuInstallStatusFile,
kDsuOneShotBootFile,
kDsuInstallDirFile,
+ GetCompleteIndication(install_dir),
};
for (const auto& file : files) {
std::string message;
- if (!android::base::RemoveFileIfExists(file, &message)) {
+ if (!RemoveFileIfExists(file, &message)) {
LOG(ERROR) << message;
ok = false;
}
@@ -661,18 +749,33 @@ 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";
+}
+
+bool GsiService::IsInstallationComplete(const std::string& install_dir) {
+ std::string file = GetCompleteIndication(install_dir);
+ std::string content;
+ if (!ReadFileToString(file, &content)) {
+ return false;
+ }
+ return content == "OK";
+}
+
void GsiService::CleanCorruptedInstallation() {
auto install_dir = GetInstalledImageDir();
- if (!RemoveGsiFiles(install_dir, true)) {
- LOG(ERROR) << "Failed to CleanCorruptedInstallation on " << install_dir;
+ bool is_complete = IsInstallationComplete(install_dir);
+ if (!is_complete) {
+ if (!RemoveGsiFiles(install_dir)) {
+ LOG(ERROR) << "Failed to CleanCorruptedInstallation on " << install_dir;
+ }
}
}
void GsiService::RunStartupTasks() {
- if (!IsGsiInstalled()) {
- CleanCorruptedInstallation();
- return;
- }
+ CleanCorruptedInstallation();
std::string boot_key;
if (!GetInstallStatus(&boot_key)) {
@@ -683,7 +786,7 @@ void GsiService::RunStartupTasks() {
if (!IsGsiRunning()) {
// Check if a wipe was requested from fastboot or adb-in-gsi.
if (boot_key == kInstallStatusWipe) {
- RemoveGsiFiles(GetInstalledImageDir(), true /* wipeUserdata */);
+ RemoveGsiFiles(GetInstalledImageDir());
}
} else {
// NB: When single-boot is enabled, init will write "disabled" into the