blob: dcfcc293fc47d4ed0478766c66a45f4fa27b74cb [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/arc/session/file_system_status.h"
#include <linux/magic.h>
#include <sys/statvfs.h>
#include <string>
#include "base/containers/span.h"
#include "base/files/file_util.h"
#include "base/json/json_reader.h"
#include "base/logging.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/values.h"
#include "build/build_config.h"
#include "components/arc/session/arc_vm_client_adapter_util.h"
namespace arc {
namespace {
constexpr const char kArcVmConfigJsonPath[] = "/usr/share/arcvm/config.json";
constexpr const char kBuiltinPath[] = "/opt/google/vms/android";
constexpr const char kDlcPath[] = "/run/imageloader/arcvm-dlc/package/root";
constexpr const char kFstab[] = "fstab";
constexpr const char kGeneratedPropertyFilesPath[] =
"/run/arcvm/host_generated";
constexpr const char kKernel[] = "vmlinux";
constexpr const char kPropertyFilesPath[] = "/usr/share/arcvm/properties";
constexpr const char kRootFs[] = "system.raw.img";
constexpr const char kVendorImage[] = "vendor.raw.img";
} // namespace
FileSystemStatus::FileSystemStatus(FileSystemStatus&& other) = default;
FileSystemStatus::~FileSystemStatus() = default;
FileSystemStatus& FileSystemStatus::operator=(FileSystemStatus&& other) =
default;
FileSystemStatus::FileSystemStatus()
: is_android_debuggable_(
IsAndroidDebuggable(base::FilePath(kArcVmConfigJsonPath))),
is_host_rootfs_writable_(IsHostRootfsWritable()),
system_image_path_(SelectDlcOrBuiltin(base::FilePath(kRootFs))),
vendor_image_path_(SelectDlcOrBuiltin(base::FilePath(kVendorImage))),
guest_kernel_path_(SelectDlcOrBuiltin(base::FilePath(kKernel))),
fstab_path_(SelectDlcOrBuiltin(base::FilePath(kFstab))),
property_files_expanded_(
ExpandPropertyFiles(base::FilePath(kPropertyFilesPath),
base::FilePath(kGeneratedPropertyFilesPath))),
is_system_image_ext_format_(IsSystemImageExtFormat(system_image_path_)) {}
// static
bool FileSystemStatus::IsAndroidDebuggable(const base::FilePath& json_path) {
if (!base::PathExists(json_path))
return false;
std::string content;
if (!base::ReadFileToString(json_path, &content))
return false;
base::JSONReader::ValueWithError result(
base::JSONReader::ReadAndReturnValueWithError(content,
base::JSON_PARSE_RFC));
if (!result.value) {
LOG(ERROR) << "Error parsing " << json_path
<< ": code=" << result.error_code
<< ", message=" << result.error_message << ": " << content;
return false;
}
if (!result.value->is_dict()) {
LOG(ERROR) << "Error parsing " << json_path << ": " << *(result.value);
return false;
}
const base::Value* debuggable = result.value->FindKeyOfType(
"ANDROID_DEBUGGABLE", base::Value::Type::BOOLEAN);
if (!debuggable) {
LOG(ERROR) << "ANDROID_DEBUGGABLE is not found in " << json_path;
return false;
}
return debuggable->GetBool();
}
// static
bool FileSystemStatus::IsHostRootfsWritable() {
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
base::BlockingType::MAY_BLOCK);
struct statvfs buf;
if (statvfs("/", &buf) < 0) {
PLOG(ERROR) << "statvfs() failed";
return false;
}
const bool rw = !(buf.f_flag & ST_RDONLY);
VLOG(1) << "Host's rootfs is " << (rw ? "rw" : "ro");
return rw;
}
// static
base::FilePath FileSystemStatus::SelectDlcOrBuiltin(
const base::FilePath& file) {
const base::FilePath dlc_path = base::FilePath(kDlcPath).Append(file);
if (base::PathExists(dlc_path)) {
VLOG(1) << "arcvm-dlc will be used for " << file.value();
return dlc_path;
}
return base::FilePath(kBuiltinPath).Append(file);
}
// static
bool FileSystemStatus::ExpandPropertyFiles(const base::FilePath& source_path,
const base::FilePath& dest_path) {
CrosConfig config;
for (const char* file : {"default.prop", "build.prop"}) {
if (!ExpandPropertyFile(source_path.Append(file), dest_path.Append(file),
&config)) {
LOG(ERROR) << "Failed to expand " << source_path.Append(file);
return false;
}
}
return true;
}
// static
bool FileSystemStatus::IsSystemImageExtFormat(const base::FilePath& path) {
base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
if (!file.IsValid()) {
PLOG(ERROR) << "Cannot open system image file: " << path.value();
return false;
}
uint8_t buf[2];
if (!file.ReadAndCheck(0x400 + 0x38, base::make_span(buf, sizeof(buf)))) {
PLOG(ERROR) << "File read error on system image file: " << path.value();
return false;
}
uint16_t magic_le = *reinterpret_cast<uint16_t*>(buf);
#if defined(ARCH_CPU_LITTLE_ENDIAN)
return magic_le == EXT4_SUPER_MAGIC;
#else
#error Unsupported platform
#endif
}
} // namespace arc