Merge "adb: add remount -R for deduplicated ext4"
diff --git a/init/Android.bp b/init/Android.bp
index 517847c..25877c0 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -236,7 +236,8 @@
"epoll.cpp",
"keychords.cpp",
"import_parser.cpp",
- "host_init_parser.cpp",
+ "host_import_parser.cpp",
+ "host_init_verifier.cpp",
"host_init_stubs.cpp",
"parser.cpp",
"rlimit_parser.cpp",
@@ -249,7 +250,10 @@
proto: {
type: "lite",
},
- generated_headers: ["generated_stub_builtin_function_map"],
+ generated_headers: [
+ "generated_stub_builtin_function_map",
+ "generated_android_ids"
+ ],
target: {
android: {
enabled: false,
diff --git a/init/host_import_parser.cpp b/init/host_import_parser.cpp
new file mode 100644
index 0000000..faf6fc1
--- /dev/null
+++ b/init/host_import_parser.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "host_import_parser.h"
+
+#include <android-base/strings.h>
+
+using android::base::StartsWith;
+
+namespace android {
+namespace init {
+
+Result<Success> HostImportParser::ParseSection(std::vector<std::string>&& args,
+ const std::string& filename, int line) {
+ if (args.size() != 2) {
+ return Error() << "single argument needed for import\n";
+ }
+
+ auto import_path = args[1];
+
+ if (StartsWith(import_path, "/system") || StartsWith(import_path, "/product") ||
+ StartsWith(import_path, "/odm") || StartsWith(import_path, "/vendor")) {
+ import_path = out_dir_ + "/" + import_path;
+ } else {
+ import_path = out_dir_ + "/root/" + import_path;
+ }
+
+ return ImportParser::ParseSection({"import", import_path}, filename, line);
+}
+
+} // namespace init
+} // namespace android
diff --git a/init/host_import_parser.h b/init/host_import_parser.h
new file mode 100644
index 0000000..e2980b2
--- /dev/null
+++ b/init/host_import_parser.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "import_parser.h"
+#include "parser.h"
+
+namespace android {
+namespace init {
+
+class HostImportParser : public ImportParser {
+ public:
+ HostImportParser(const std::string& out_dir, Parser* parser)
+ : ImportParser(parser), out_dir_(out_dir) {}
+ Result<Success> ParseSection(std::vector<std::string>&& args, const std::string& filename,
+ int line) override;
+
+ private:
+ std::string out_dir_;
+};
+
+} // namespace init
+} // namespace android
diff --git a/init/host_init_parser.cpp b/init/host_init_parser.cpp
deleted file mode 100644
index df497ea..0000000
--- a/init/host_init_parser.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-//
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-#include <pwd.h>
-
-#include <android-base/logging.h>
-
-#include "action.h"
-#include "action_manager.h"
-#include "action_parser.h"
-#include "parser.h"
-#include "result.h"
-#include "service.h"
-
-// The host passwd file won't have the Android entries, so we fake success here.
-passwd* getpwnam(const char* login) { // NOLINT: implementing bad function.
- char dummy_buf[] = "dummy";
- static passwd dummy_passwd = {
- .pw_name = dummy_buf,
- .pw_dir = dummy_buf,
- .pw_shell = dummy_buf,
- .pw_uid = 123,
- .pw_gid = 123,
- };
- return &dummy_passwd;
-}
-
-namespace android {
-namespace init {
-
-static Result<Success> do_stub(const BuiltinArguments& args) {
- return Success();
-}
-
-#include "generated_stub_builtin_function_map.h"
-
-int main(int argc, char** argv) {
- android::base::InitLogging(argv, &android::base::StdioLogger);
- if (argc != 2) {
- LOG(ERROR) << "Usage: " << argv[0] << " <init file to parse>";
- return -1;
- }
- const BuiltinFunctionMap function_map;
- Action::set_function_map(&function_map);
- ActionManager& am = ActionManager::GetInstance();
- ServiceList& sl = ServiceList::GetInstance();
- Parser parser;
- parser.AddSectionParser("service", std::make_unique<ServiceParser>(&sl, nullptr));
- parser.AddSectionParser("on", std::make_unique<ActionParser>(&am, nullptr));
-
- size_t num_errors = 0;
- if (!parser.ParseConfig(argv[1], &num_errors)) {
- LOG(ERROR) << "Failed to find script";
- return -1;
- }
- if (num_errors > 0) {
- LOG(ERROR) << "Parse failed with " << num_errors << " errors";
- return -1;
- }
- LOG(INFO) << "Parse success!";
- return 0;
-}
-
-} // namespace init
-} // namespace android
-
-int main(int argc, char** argv) {
- android::init::main(argc, argv);
-}
diff --git a/init/host_init_stubs.cpp b/init/host_init_stubs.cpp
index c40a254..2352fc7 100644
--- a/init/host_init_stubs.cpp
+++ b/init/host_init_stubs.cpp
@@ -16,6 +16,8 @@
#include "host_init_stubs.h"
+#include <android-base/properties.h>
+
// unistd.h
int setgroups(size_t __size, const gid_t* __list) {
return 0;
@@ -28,7 +30,11 @@
std::string default_console = "/dev/console";
// property_service.h
-uint32_t (*property_set)(const std::string& name, const std::string& value) = nullptr;
+uint32_t SetProperty(const std::string& key, const std::string& value) {
+ android::base::SetProperty(key, value);
+ return 0;
+}
+uint32_t (*property_set)(const std::string& name, const std::string& value) = SetProperty;
uint32_t HandlePropertySet(const std::string&, const std::string&, const std::string&, const ucred&,
std::string*) {
return 0;
diff --git a/init/host_init_verifier.cpp b/init/host_init_verifier.cpp
new file mode 100644
index 0000000..d6884af
--- /dev/null
+++ b/init/host_init_verifier.cpp
@@ -0,0 +1,162 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+
+#include "action.h"
+#include "action_manager.h"
+#include "action_parser.h"
+#include "host_import_parser.h"
+#include "host_init_stubs.h"
+#include "parser.h"
+#include "result.h"
+#include "service.h"
+
+#define EXCLUDE_FS_CONFIG_STRUCTURES
+#include "generated_android_ids.h"
+
+using namespace std::literals;
+
+using android::base::ParseInt;
+using android::base::ReadFileToString;
+using android::base::Split;
+
+static std::string out_dir;
+
+static std::vector<std::pair<std::string, int>> GetVendorPasswd() {
+ std::string passwd;
+ if (!ReadFileToString(out_dir + "/vendor/etc/passwd", &passwd)) {
+ return {};
+ }
+
+ std::vector<std::pair<std::string, int>> result;
+ auto passwd_lines = Split(passwd, "\n");
+ for (const auto& line : passwd_lines) {
+ auto split_line = Split(line, ":");
+ if (split_line.size() < 3) {
+ continue;
+ }
+ int uid = 0;
+ if (!ParseInt(split_line[2], &uid)) {
+ continue;
+ }
+ result.emplace_back(split_line[0], uid);
+ }
+ return result;
+}
+
+passwd* getpwnam(const char* login) { // NOLINT: implementing bad function.
+ // This isn't thread safe, but that's okay for our purposes.
+ static char static_name[32] = "";
+ static char static_dir[32] = "/";
+ static char static_shell[32] = "/system/bin/sh";
+ static passwd static_passwd = {
+ .pw_name = static_name,
+ .pw_dir = static_dir,
+ .pw_shell = static_shell,
+ .pw_uid = 0,
+ .pw_gid = 0,
+ };
+
+ for (size_t n = 0; n < android_id_count; ++n) {
+ if (!strcmp(android_ids[n].name, login)) {
+ snprintf(static_name, sizeof(static_name), "%s", android_ids[n].name);
+ static_passwd.pw_uid = android_ids[n].aid;
+ static_passwd.pw_gid = android_ids[n].aid;
+ return &static_passwd;
+ }
+ }
+
+ static const auto vendor_passwd = GetVendorPasswd();
+
+ for (const auto& [name, uid] : vendor_passwd) {
+ if (name == login) {
+ snprintf(static_name, sizeof(static_name), "%s", name.c_str());
+ static_passwd.pw_uid = uid;
+ static_passwd.pw_gid = uid;
+ return &static_passwd;
+ }
+ }
+
+ errno = ENOENT;
+ return nullptr;
+}
+
+namespace android {
+namespace init {
+
+static Result<Success> do_stub(const BuiltinArguments& args) {
+ return Success();
+}
+
+#include "generated_stub_builtin_function_map.h"
+
+int main(int argc, char** argv) {
+ android::base::InitLogging(argv, &android::base::StdioLogger);
+ android::base::SetMinimumLogSeverity(android::base::ERROR);
+ if (argc != 3) {
+ LOG(ERROR) << "Usage: " << argv[0] << " <out directory> <properties>";
+ return -1;
+ }
+
+ out_dir = argv[1];
+
+ auto properties = Split(argv[2], ",");
+ for (const auto& property : properties) {
+ auto split_property = Split(property, "=");
+ if (split_property.size() != 2) {
+ continue;
+ }
+ property_set(split_property[0], split_property[1]);
+ }
+
+ const BuiltinFunctionMap function_map;
+ Action::set_function_map(&function_map);
+ ActionManager& am = ActionManager::GetInstance();
+ ServiceList& sl = ServiceList::GetInstance();
+ Parser parser;
+ parser.AddSectionParser("service", std::make_unique<ServiceParser>(&sl, nullptr));
+ parser.AddSectionParser("on", std::make_unique<ActionParser>(&am, nullptr));
+ parser.AddSectionParser("import", std::make_unique<HostImportParser>(out_dir, &parser));
+
+ if (!parser.ParseConfig(argv[1] + "/root/init.rc"s)) {
+ LOG(ERROR) << "Failed to find root init.rc script";
+ return -1;
+ }
+ if (parser.parse_error_count() > 0) {
+ LOG(ERROR) << "Init script parsing failed with " << parser.parse_error_count() << " errors";
+ return -1;
+ }
+ return 0;
+}
+
+} // namespace init
+} // namespace android
+
+int main(int argc, char** argv) {
+ android::init::main(argc, argv);
+}
diff --git a/init/import_parser.cpp b/init/import_parser.cpp
index e335fd1..fb3185e 100644
--- a/init/import_parser.cpp
+++ b/init/import_parser.cpp
@@ -41,14 +41,15 @@
return Success();
}
+Result<Success> ImportParser::ParseLineSection(std::vector<std::string>&&, int) {
+ return Error() << "Unexpected line found after import statement";
+}
+
void ImportParser::EndFile() {
auto current_imports = std::move(imports_);
imports_.clear();
for (const auto& [import, line_num] : current_imports) {
- if (!parser_->ParseConfig(import)) {
- PLOG(ERROR) << filename_ << ": " << line_num << ": Could not import file '" << import
- << "'";
- }
+ parser_->ParseConfig(import);
}
}
diff --git a/init/import_parser.h b/init/import_parser.h
index 5a2f894..7bc72e6 100644
--- a/init/import_parser.h
+++ b/init/import_parser.h
@@ -30,6 +30,7 @@
ImportParser(Parser* parser) : parser_(parser) {}
Result<Success> ParseSection(std::vector<std::string>&& args, const std::string& filename,
int line) override;
+ Result<Success> ParseLineSection(std::vector<std::string>&&, int) override;
void EndFile() override;
private:
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
index 34de640..db60ce1 100644
--- a/init/init_first_stage.cpp
+++ b/init/init_first_stage.cpp
@@ -123,7 +123,7 @@
bool enabled = false;
import_kernel_cmdline(
false, [&enabled](const std::string& key, const std::string& value, bool in_qemu) {
- if (key == "androidboot.lrap" && value == "1") {
+ if (key == "androidboot.logical_partitions" && value == "1") {
enabled = true;
}
});
diff --git a/init/parser.cpp b/init/parser.cpp
index 4453aaa..ee6ee06 100644
--- a/init/parser.cpp
+++ b/init/parser.cpp
@@ -39,7 +39,7 @@
line_callbacks_.emplace_back(prefix, callback);
}
-void Parser::ParseData(const std::string& filename, const std::string& data, size_t* parse_errors) {
+void Parser::ParseData(const std::string& filename, const std::string& data) {
// TODO: Use a parser with const input and remove this copy
std::vector<char> data_copy(data.begin(), data.end());
data_copy.push_back('\0');
@@ -57,7 +57,7 @@
if (section_parser == nullptr) return;
if (auto result = section_parser->EndSection(); !result) {
- (*parse_errors)++;
+ parse_error_count_++;
LOG(ERROR) << filename << ": " << section_start_line << ": " << result.error();
}
@@ -81,7 +81,7 @@
end_section();
if (auto result = callback(std::move(args)); !result) {
- (*parse_errors)++;
+ parse_error_count_++;
LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
}
break;
@@ -94,16 +94,20 @@
if (auto result =
section_parser->ParseSection(std::move(args), filename, state.line);
!result) {
- (*parse_errors)++;
+ parse_error_count_++;
LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
section_parser = nullptr;
}
} else if (section_parser) {
if (auto result = section_parser->ParseLineSection(std::move(args), state.line);
!result) {
- (*parse_errors)++;
+ parse_error_count_++;
LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
}
+ } else {
+ parse_error_count_++;
+ LOG(ERROR) << filename << ": " << state.line
+ << ": Invalid section keyword found";
}
args.clear();
break;
@@ -114,17 +118,17 @@
}
}
-bool Parser::ParseConfigFile(const std::string& path, size_t* parse_errors) {
+bool Parser::ParseConfigFile(const std::string& path) {
LOG(INFO) << "Parsing file " << path << "...";
android::base::Timer t;
auto config_contents = ReadFile(path);
if (!config_contents) {
- LOG(ERROR) << "Unable to read config file '" << path << "': " << config_contents.error();
+ LOG(INFO) << "Unable to read config file '" << path << "': " << config_contents.error();
return false;
}
config_contents->push_back('\n'); // TODO: fix parse_config.
- ParseData(path, *config_contents, parse_errors);
+ ParseData(path, *config_contents);
for (const auto& [section_name, section_parser] : section_parsers_) {
section_parser->EndFile();
}
@@ -133,11 +137,11 @@
return true;
}
-bool Parser::ParseConfigDir(const std::string& path, size_t* parse_errors) {
+bool Parser::ParseConfigDir(const std::string& path) {
LOG(INFO) << "Parsing directory " << path << "...";
std::unique_ptr<DIR, decltype(&closedir)> config_dir(opendir(path.c_str()), closedir);
if (!config_dir) {
- PLOG(ERROR) << "Could not import directory '" << path << "'";
+ PLOG(INFO) << "Could not import directory '" << path << "'";
return false;
}
dirent* current_file;
@@ -153,7 +157,7 @@
// Sort first so we load files in a consistent order (bug 31996208)
std::sort(files.begin(), files.end());
for (const auto& file : files) {
- if (!ParseConfigFile(file, parse_errors)) {
+ if (!ParseConfigFile(file)) {
LOG(ERROR) << "could not import file '" << file << "'";
}
}
@@ -161,16 +165,10 @@
}
bool Parser::ParseConfig(const std::string& path) {
- size_t parse_errors;
- return ParseConfig(path, &parse_errors);
-}
-
-bool Parser::ParseConfig(const std::string& path, size_t* parse_errors) {
- *parse_errors = 0;
if (is_dir(path.c_str())) {
- return ParseConfigDir(path, parse_errors);
+ return ParseConfigDir(path);
}
- return ParseConfigFile(path, parse_errors);
+ return ParseConfigFile(path);
}
} // namespace init
diff --git a/init/parser.h b/init/parser.h
index f6e237f..3501d8c 100644
--- a/init/parser.h
+++ b/init/parser.h
@@ -72,17 +72,19 @@
Parser();
bool ParseConfig(const std::string& path);
- bool ParseConfig(const std::string& path, size_t* parse_errors);
void AddSectionParser(const std::string& name, std::unique_ptr<SectionParser> parser);
void AddSingleLineParser(const std::string& prefix, LineCallback callback);
+ size_t parse_error_count() const { return parse_error_count_; }
+
private:
- void ParseData(const std::string& filename, const std::string& data, size_t* parse_errors);
- bool ParseConfigFile(const std::string& path, size_t* parse_errors);
- bool ParseConfigDir(const std::string& path, size_t* parse_errors);
+ void ParseData(const std::string& filename, const std::string& data);
+ bool ParseConfigFile(const std::string& path);
+ bool ParseConfigDir(const std::string& path);
std::map<std::string, std::unique_ptr<SectionParser>> section_parsers_;
std::vector<std::pair<std::string, LineCallback>> line_callbacks_;
+ size_t parse_error_count_ = 0;
};
} // namespace init
diff --git a/mkbootimg/include/bootimg/bootimg.h b/mkbootimg/include/bootimg/bootimg.h
index 406e208..bce308b 100644
--- a/mkbootimg/include/bootimg/bootimg.h
+++ b/mkbootimg/include/bootimg/bootimg.h
@@ -111,7 +111,7 @@
struct boot_img_hdr_v1 : public boot_img_hdr_v0 {
uint32_t recovery_dtbo_size; /* size in bytes for recovery DTBO image */
- uint64_t recovery_dtbo_offset; /* physical load addr */
+ uint64_t recovery_dtbo_offset; /* offset to recovery dtbo in boot image */
uint32_t header_size;
} __attribute__((packed));
@@ -138,11 +138,14 @@
* 1. kernel and ramdisk are required (size != 0)
* 2. recovery_dtbo is required for recovery.img in non-A/B devices(recovery_dtbo_size != 0)
* 3. second is optional (second_size == 0 -> no second)
- * 4. load each element (kernel, ramdisk, second, recovery_dtbo) at
+ * 4. load each element (kernel, ramdisk, second) at
* the specified physical address (kernel_addr, etc)
- * 5. prepare tags at tag_addr. kernel_args[] is
+ * 5. If booting to recovery mode in a non-A/B device, extract recovery dtbo and
+ * apply the correct set of overlays on the base device tree depending on the
+ * hardware/product revision.
+ * 6. prepare tags at tag_addr. kernel_args[] is
* appended to the kernel commandline in the tags.
- * 6. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
- * 7. if second_size != 0: jump to second_addr
+ * 7. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
+ * 8. if second_size != 0: jump to second_addr
* else: jump to kernel_addr
*/