Merge "Revert "init: use ro.init.subcontexts_enabled to enable subcontexts""
diff --git a/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh
index c1d5430..79702a6 100755
--- a/bootstat/boot_reason_test.sh
+++ b/bootstat/boot_reason_test.sh
@@ -778,7 +778,12 @@
checkDebugBuild || return
duration_test ">90"
panic_msg="kernel_panic,sysrq"
- enterPstore || panic_msg="\(kernel_panic,sysrq\|kernel_panic\)"
+ enterPstore
+ if [ ${?} != 0 ]; then
+ echo " or functional bootloader" >&2
+ panic_msg="\(kernel_panic,sysrq\|kernel_panic\)"
+ pstore_ok=true
+ fi
echo c | adb shell su root tee /proc/sysrq-trigger >/dev/null
wait_for_screen
EXPECT_PROPERTY sys.boot.reason ${panic_msg}
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index d6b6d58..bd202ff 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -429,7 +429,12 @@
abort_message = g_callbacks.get_abort_message();
}
- if (prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0) == 1) {
+ // If sival_int is ~0, it means that the fallback handler has been called
+ // once before and this function is being called again to dump the stack
+ // of a specific thread. It is possible that the prctl call might return 1,
+ // then return 0 in subsequent calls, so check the sival_int to determine if
+ // the fallback handler should be called first.
+ if (info->si_value.sival_int == ~0 || prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0) == 1) {
// This check might be racy if another thread sets NO_NEW_PRIVS, but this should be unlikely,
// you can only set NO_NEW_PRIVS to 1, and the effect should be at worst a single missing
// ANR trace.
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 7723ec6..b0b2337 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -39,7 +39,7 @@
LOCAL_MODULE_TAGS := debug
LOCAL_MODULE_HOST_OS := darwin linux windows
LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
-LOCAL_REQUIRED_MODULES := mke2fs e2fsdroid
+LOCAL_REQUIRED_MODULES := mke2fs e2fsdroid make_f2fs
LOCAL_SRC_FILES_linux := usb_linux.cpp
LOCAL_STATIC_LIBRARIES_linux := libselinux
@@ -66,8 +66,6 @@
libcutils \
libgtest_host \
-LOCAL_CFLAGS_linux := -DUSE_F2FS
-
LOCAL_CXX_STL := libc++_static
# Don't add anything here, we don't want additional shared dependencies
@@ -80,6 +78,7 @@
my_dist_files := $(LOCAL_BUILT_MODULE)
my_dist_files += $(HOST_OUT_EXECUTABLES)/mke2fs$(HOST_EXECUTABLE_SUFFIX)
my_dist_files += $(HOST_OUT_EXECUTABLES)/e2fsdroid$(HOST_EXECUTABLE_SUFFIX)
+my_dist_files += $(HOST_OUT_EXECUTABLES)/make_f2fs$(HOST_EXECUTABLE_SUFFIX)
$(call dist-for-goals,dist_files sdk win_sdk,$(my_dist_files))
ifdef HOST_CROSS_OS
# Archive fastboot.exe for win_sdk build.
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index 8877b09..4141a3b 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -154,10 +154,10 @@
return 0;
}
-#ifdef USE_F2FS
static int generate_f2fs_image(const char* fileName, long long partSize, const std::string& initial_dir,
unsigned /* unused */, unsigned /* unused */)
{
+#ifndef WIN32
const std::string exec_dir = android::base::GetExecutableDirectory();
const std::string mkf2fs_path = exec_dir + "/make_f2fs";
std::vector<const char*> mkf2fs_args = {mkf2fs_path.c_str()};
@@ -180,12 +180,15 @@
}
if (!initial_dir.empty()) {
- fprintf(stderr, "Unable to set initial directory on F2FS filesystem: %s\n", strerror(errno));
- return -1;
+ fprintf(stderr, "sload.f2s not supported yet\n");
+ return 0;
}
return 0;
-}
+#else
+ fprintf(stderr, "make_f2fs not supported on Windows\n");
+ return -1;
#endif
+}
static const struct fs_generator {
const char* fs_type; //must match what fastboot reports for partition type
@@ -196,9 +199,7 @@
} generators[] = {
{ "ext4", generate_ext4_image},
-#ifdef USE_F2FS
{ "f2fs", generate_f2fs_image},
-#endif
};
const struct fs_generator* fs_get_generator(const std::string& fs_type) {
diff --git a/init/action.cpp b/init/action.cpp
index 2617d00..5fa6bec 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -379,10 +379,12 @@
return action_ ? action_->AddCommand(std::move(args), line) : Success();
}
-void ActionParser::EndSection() {
+Result<Success> ActionParser::EndSection() {
if (action_ && action_->NumCommands() > 0) {
action_manager_->AddAction(std::move(action_));
}
+
+ return Success();
}
} // namespace init
diff --git a/init/action.h b/init/action.h
index cdfc6a0..1bfc6c7 100644
--- a/init/action.h
+++ b/init/action.h
@@ -130,7 +130,7 @@
Result<Success> ParseSection(std::vector<std::string>&& args, const std::string& filename,
int line) override;
Result<Success> ParseLineSection(std::vector<std::string>&& args, int line) override;
- void EndSection() override;
+ Result<Success> EndSection() override;
private:
ActionManager* action_manager_;
diff --git a/init/capabilities.cpp b/init/capabilities.cpp
index 642a364..50987db 100644
--- a/init/capabilities.cpp
+++ b/init/capabilities.cpp
@@ -194,5 +194,18 @@
return SetAmbientCaps(to_keep);
}
+bool DropInheritableCaps() {
+ ScopedCaps caps(cap_get_proc());
+ if (cap_clear_flag(caps.get(), CAP_INHERITABLE) == -1) {
+ PLOG(ERROR) << "cap_clear_flag(INHERITABLE) failed";
+ return false;
+ }
+ if (cap_set_proc(caps.get()) != 0) {
+ PLOG(ERROR) << "cap_set_proc() failed";
+ return false;
+ }
+ return true;
+}
+
} // namespace init
} // namespace android
diff --git a/init/capabilities.h b/init/capabilities.h
index ede85c3..fc80c98 100644
--- a/init/capabilities.h
+++ b/init/capabilities.h
@@ -35,6 +35,7 @@
bool CapAmbientSupported();
unsigned int GetLastValidCap();
bool SetCapsForExec(const CapSet& to_keep);
+bool DropInheritableCaps();
} // namespace init
} // namespace android
diff --git a/init/init_test.cpp b/init/init_test.cpp
index 29a65ab..268873c 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -25,6 +25,7 @@
#include "import_parser.h"
#include "keyword_map.h"
#include "parser.h"
+#include "service.h"
#include "test_function_map.h"
#include "util.h"
@@ -34,12 +35,13 @@
using ActionManagerCommand = std::function<void(ActionManager&)>;
void TestInit(const std::string& init_script_file, const TestFunctionMap& test_function_map,
- const std::vector<ActionManagerCommand>& commands) {
+ const std::vector<ActionManagerCommand>& commands, ServiceList* service_list) {
ActionManager am;
Action::set_function_map(&test_function_map);
Parser parser;
+ parser.AddSectionParser("service", std::make_unique<ServiceParser>(service_list, nullptr));
parser.AddSectionParser("on", std::make_unique<ActionParser>(&am, nullptr));
parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
@@ -55,11 +57,11 @@
}
void TestInitText(const std::string& init_script, const TestFunctionMap& test_function_map,
- const std::vector<ActionManagerCommand>& commands) {
+ const std::vector<ActionManagerCommand>& commands, ServiceList* service_list) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
ASSERT_TRUE(android::base::WriteStringToFd(init_script, tf.fd));
- TestInit(tf.path, test_function_map, commands);
+ TestInit(tf.path, test_function_map, commands, service_list);
}
TEST(init, SimpleEventTrigger) {
@@ -76,7 +78,8 @@
ActionManagerCommand trigger_boot = [](ActionManager& am) { am.QueueEventTrigger("boot"); };
std::vector<ActionManagerCommand> commands{trigger_boot};
- TestInitText(init_script, test_function_map, commands);
+ ServiceList service_list;
+ TestInitText(init_script, test_function_map, commands, &service_list);
EXPECT_TRUE(expect_true);
}
@@ -104,7 +107,30 @@
ActionManagerCommand trigger_boot = [](ActionManager& am) { am.QueueEventTrigger("boot"); };
std::vector<ActionManagerCommand> commands{trigger_boot};
- TestInitText(init_script, test_function_map, commands);
+ ServiceList service_list;
+ TestInitText(init_script, test_function_map, commands, &service_list);
+}
+
+TEST(init, OverrideService) {
+ std::string init_script = R"init(
+service A something
+ class first
+
+service A something
+ class second
+ override
+
+)init";
+
+ ServiceList service_list;
+ TestInitText(init_script, TestFunctionMap(), {}, &service_list);
+ ASSERT_EQ(1, std::distance(service_list.begin(), service_list.end()));
+
+ auto service = service_list.begin()->get();
+ ASSERT_NE(nullptr, service);
+ EXPECT_EQ(std::set<std::string>({"second"}), service->classnames());
+ EXPECT_EQ("A", service->name());
+ EXPECT_TRUE(service->is_override());
}
TEST(init, EventTriggerOrderMultipleFiles) {
@@ -162,7 +188,9 @@
ActionManagerCommand trigger_boot = [](ActionManager& am) { am.QueueEventTrigger("boot"); };
std::vector<ActionManagerCommand> commands{trigger_boot};
- TestInit(start.path, test_function_map, commands);
+ ServiceList service_list;
+
+ TestInit(start.path, test_function_map, commands, &service_list);
EXPECT_EQ(6, num_executed);
}
diff --git a/init/parser.cpp b/init/parser.cpp
index 8a4e798..6ddb09f 100644
--- a/init/parser.cpp
+++ b/init/parser.cpp
@@ -50,12 +50,24 @@
state.nexttoken = 0;
SectionParser* section_parser = nullptr;
+ int section_start_line = -1;
std::vector<std::string> args;
+ auto end_section = [&] {
+ if (section_parser == nullptr) return;
+
+ if (auto result = section_parser->EndSection(); !result) {
+ LOG(ERROR) << filename << ": " << section_start_line << ": " << result.error();
+ }
+
+ section_parser = nullptr;
+ section_start_line = -1;
+ };
+
for (;;) {
switch (next_token(&state)) {
case T_EOF:
- if (section_parser) section_parser->EndSection();
+ end_section();
return;
case T_NEWLINE:
state.line++;
@@ -65,18 +77,18 @@
// uevent.
for (const auto& [prefix, callback] : line_callbacks_) {
if (android::base::StartsWith(args[0], prefix.c_str())) {
- if (section_parser) section_parser->EndSection();
+ end_section();
if (auto result = callback(std::move(args)); !result) {
LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
}
- section_parser = nullptr;
break;
}
}
if (section_parsers_.count(args[0])) {
- if (section_parser) section_parser->EndSection();
+ end_section();
section_parser = section_parsers_[args[0]].get();
+ section_start_line = state.line;
if (auto result =
section_parser->ParseSection(std::move(args), filename, state.line);
!result) {
diff --git a/init/parser.h b/init/parser.h
index 4ab24a4..110a468 100644
--- a/init/parser.h
+++ b/init/parser.h
@@ -26,24 +26,22 @@
// SectionParser is an interface that can parse a given 'section' in init.
//
-// You can implement up to 4 functions below, with ParseSection() being mandatory.
-// The first two function return bool with false indicating a failure and has a std::string* err
-// parameter into which an error string can be written. It will be reported along with the
-// filename and line number of where the error occurred.
+// You can implement up to 4 functions below, with ParseSection being mandatory. The first two
+// functions return Result<Success> indicating if they have an error. It will be reported along
+// with the filename and line number of where the error occurred.
//
-// 1) bool ParseSection(std::vector<std::string>&& args, const std::string& filename,
-// int line, std::string* err)
+// 1) ParseSection
// This function is called when a section is first encountered.
//
-// 2) bool ParseLineSection(std::vector<std::string>&& args, int line, std::string* err)
+// 2) ParseLineSection
// This function is called on each subsequent line until the next section is encountered.
//
-// 3) bool EndSection()
+// 3) EndSection
// This function is called either when a new section is found or at the end of the file.
// It indicates that parsing of the current section is complete and any relevant objects should
// be committed.
//
-// 4) bool EndFile()
+// 4) EndFile
// This function is called at the end of the file.
// It indicates that the parsing has completed and any relevant objects should be committed.
@@ -56,7 +54,7 @@
virtual Result<Success> ParseSection(std::vector<std::string>&& args,
const std::string& filename, int line) = 0;
virtual Result<Success> ParseLineSection(std::vector<std::string>&&, int) { return Success(); };
- virtual void EndSection(){};
+ virtual Result<Success> EndSection() { return Success(); };
virtual void EndFile(){};
};
diff --git a/init/service.cpp b/init/service.cpp
index 12acfc6..331b859 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -291,6 +291,11 @@
if (!SetCapsForExec(capabilities_)) {
LOG(FATAL) << "cannot set capabilities for " << name_;
}
+ } else if (uid_) {
+ // Inheritable caps can be non-zero when running in a container.
+ if (!DropInheritableCaps()) {
+ LOG(FATAL) << "cannot drop inheritable caps for " << name_;
+ }
}
}
@@ -530,6 +535,11 @@
return Success();
}
+Result<Success> Service::ParseOverride(const std::vector<std::string>& args) {
+ override_ = true;
+ return Success();
+}
+
Result<Success> Service::ParseMemcgSwappiness(const std::vector<std::string>& args) {
if (!ParseInt(args[1], &swappiness_, 0)) {
return Error() << "swappiness value must be equal or greater than 0";
@@ -671,6 +681,7 @@
{"keycodes", {1, kMax, &Service::ParseKeycodes}},
{"oneshot", {0, 0, &Service::ParseOneshot}},
{"onrestart", {1, kMax, &Service::ParseOnrestart}},
+ {"override", {0, 0, &Service::ParseOverride}},
{"oom_score_adjust",
{1, 1, &Service::ParseOomScoreAdjust}},
{"memcg.swappiness",
@@ -1111,11 +1122,6 @@
return Error() << "invalid service name '" << name << "'";
}
- Service* old_service = service_list_->FindService(name);
- if (old_service) {
- return Error() << "ignored duplicate definition of service '" << name << "'";
- }
-
Subcontext* restart_action_subcontext = nullptr;
if (subcontexts_) {
for (auto& subcontext : *subcontexts_) {
@@ -1135,10 +1141,23 @@
return service_ ? service_->ParseLine(std::move(args)) : Success();
}
-void ServiceParser::EndSection() {
+Result<Success> ServiceParser::EndSection() {
if (service_) {
+ Service* old_service = service_list_->FindService(service_->name());
+ if (old_service) {
+ if (!service_->is_override()) {
+ return Error() << "ignored duplicate definition of service '" << service_->name()
+ << "'";
+ }
+
+ service_list_->RemoveService(*old_service);
+ old_service = nullptr;
+ }
+
service_list_->AddService(std::move(service_));
}
+
+ return Success();
}
bool ServiceParser::IsValidName(const std::string& name) const {
diff --git a/init/service.h b/init/service.h
index 593f782..d46a413 100644
--- a/init/service.h
+++ b/init/service.h
@@ -111,6 +111,7 @@
const std::set<std::string>& interfaces() const { return interfaces_; }
int priority() const { return priority_; }
int oom_score_adjust() const { return oom_score_adjust_; }
+ bool is_override() const { return override_; }
bool process_cgroup_empty() const { return process_cgroup_empty_; }
unsigned long start_order() const { return start_order_; }
const std::vector<std::string>& args() const { return args_; }
@@ -139,6 +140,7 @@
Result<Success> ParseOneshot(const std::vector<std::string>& args);
Result<Success> ParseOnrestart(const std::vector<std::string>& args);
Result<Success> ParseOomScoreAdjust(const std::vector<std::string>& args);
+ Result<Success> ParseOverride(const std::vector<std::string>& args);
Result<Success> ParseMemcgLimitInBytes(const std::vector<std::string>& args);
Result<Success> ParseMemcgSoftLimitInBytes(const std::vector<std::string>& args);
Result<Success> ParseMemcgSwappiness(const std::vector<std::string>& args);
@@ -201,6 +203,8 @@
bool process_cgroup_empty_ = false;
+ bool override_ = false;
+
unsigned long start_order_;
std::vector<std::pair<int, rlimit>> rlimits_;
@@ -248,7 +252,7 @@
Result<Success> ParseSection(std::vector<std::string>&& args, const std::string& filename,
int line) override;
Result<Success> ParseLineSection(std::vector<std::string>&& args, int line) override;
- void EndSection() override;
+ Result<Success> EndSection() override;
private:
bool IsValidName(const std::string& name) const;
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index cd7adb4..f74c878 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -132,8 +132,10 @@
return std::invoke(*parser, this, std::move(args));
}
-void SubsystemParser::EndSection() {
+Result<Success> SubsystemParser::EndSection() {
subsystems_->emplace_back(std::move(subsystem_));
+
+ return Success();
}
} // namespace init
diff --git a/init/ueventd_parser.h b/init/ueventd_parser.h
index 18d1027..83684f3 100644
--- a/init/ueventd_parser.h
+++ b/init/ueventd_parser.h
@@ -32,7 +32,7 @@
Result<Success> ParseSection(std::vector<std::string>&& args, const std::string& filename,
int line) override;
Result<Success> ParseLineSection(std::vector<std::string>&& args, int line) override;
- void EndSection() override;
+ Result<Success> EndSection() override;
private:
Result<Success> ParseDevName(std::vector<std::string>&& args);
diff --git a/liblog/include/log/log.h b/liblog/include/log/log.h
index d01708d..3813e6e 100644
--- a/liblog/include/log/log.h
+++ b/liblog/include/log/log.h
@@ -95,6 +95,8 @@
size_t len);
int __android_log_bswrite(int32_t tag, const char* payload);
+int __android_log_stats_bwrite(int32_t tag, const void* payload, size_t len);
+
#define android_bWriteLog(tag, payload, len) \
__android_log_bwrite(tag, payload, len)
#define android_btWriteLog(tag, type, payload, len) \
diff --git a/liblog/include/log/log_id.h b/liblog/include/log/log_id.h
index 7bfa277..c44f5a2 100644
--- a/liblog/include/log/log_id.h
+++ b/liblog/include/log/log_id.h
@@ -31,8 +31,9 @@
LOG_ID_EVENTS = 2,
LOG_ID_SYSTEM = 3,
LOG_ID_CRASH = 4,
- LOG_ID_SECURITY = 5,
- LOG_ID_KERNEL = 6, /* place last, third-parties can not use it */
+ LOG_ID_STATS = 5,
+ LOG_ID_SECURITY = 6,
+ LOG_ID_KERNEL = 7, /* place last, third-parties can not use it */
LOG_ID_MAX
} log_id_t;
diff --git a/liblog/log_event_list.c b/liblog/log_event_list.c
index 59ea5ef..a59cb87 100644
--- a/liblog/log_event_list.c
+++ b/liblog/log_event_list.c
@@ -301,7 +301,7 @@
const char* msg;
ssize_t len;
- if ((id != LOG_ID_EVENTS) && (id != LOG_ID_SECURITY)) {
+ if ((id != LOG_ID_EVENTS) && (id != LOG_ID_SECURITY) && (id != LOG_ID_STATS)) {
return -EINVAL;
}
@@ -326,7 +326,9 @@
}
return (id == LOG_ID_EVENTS)
? __android_log_bwrite(context->tag, msg, len)
- : __android_log_security_bwrite(context->tag, msg, len);
+ : ((id == LOG_ID_STATS)
+ ? __android_log_stats_bwrite(context->tag, msg, len)
+ : __android_log_security_bwrite(context->tag, msg, len));
}
LIBLOG_ABI_PRIVATE int android_log_write_list_buffer(android_log_context ctx,
diff --git a/liblog/logger_name.c b/liblog/logger_name.c
index a5a83e0..479bbfe 100644
--- a/liblog/logger_name.c
+++ b/liblog/logger_name.c
@@ -22,12 +22,13 @@
/* In the future, we would like to make this list extensible */
static const char* LOG_NAME[LOG_ID_MAX] = {
- /* clang-format off */
+ /* clang-format off */
[LOG_ID_MAIN] = "main",
[LOG_ID_RADIO] = "radio",
[LOG_ID_EVENTS] = "events",
[LOG_ID_SYSTEM] = "system",
[LOG_ID_CRASH] = "crash",
+ [LOG_ID_STATS] = "stats",
[LOG_ID_SECURITY] = "security",
[LOG_ID_KERNEL] = "kernel",
/* clang-format on */
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
index 84feb20..589ce84 100644
--- a/liblog/logger_write.c
+++ b/liblog/logger_write.c
@@ -546,6 +546,19 @@
return write_to_log(LOG_ID_EVENTS, vec, 2);
}
+LIBLOG_ABI_PUBLIC int __android_log_stats_bwrite(int32_t tag,
+ const void* payload,
+ size_t len) {
+ struct iovec vec[2];
+
+ vec[0].iov_base = &tag;
+ vec[0].iov_len = sizeof(tag);
+ vec[1].iov_base = (void*)payload;
+ vec[1].iov_len = len;
+
+ return write_to_log(LOG_ID_STATS, vec, 2);
+}
+
LIBLOG_ABI_PUBLIC int __android_log_security_bwrite(int32_t tag,
const void* payload,
size_t len) {
diff --git a/logcat/event.logtags b/logcat/event.logtags
index efcc817..0983676 100644
--- a/logcat/event.logtags
+++ b/logcat/event.logtags
@@ -140,5 +140,8 @@
1397638484 snet_event_log (subtag|3) (uid|1) (message|3)
+# for events that go to stats log buffer
+1937006964 stats_log (atom_id|1|5),(data|4)
+
# NOTE - the range 1000000-2000000 is reserved for partners and others who
# want to define their own log tags without conflicting with the core platform.
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index a2aa486..ff85f54 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -1126,8 +1126,9 @@
}
if (found) continue;
- bool binary =
- !strcmp(name, "events") || !strcmp(name, "security");
+ bool binary = !strcmp(name, "events") ||
+ !strcmp(name, "security") ||
+ !strcmp(name, "stats");
log_device_t* d = new log_device_t(name, binary);
if (dev) {
diff --git a/rootdir/init.rc b/rootdir/init.rc
index ca7b991..11b8383 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -409,6 +409,7 @@
mkdir /data/misc/net 0750 root shell
mkdir /data/misc/radio 0770 system radio
mkdir /data/misc/sms 0770 system radio
+ mkdir /data/misc/carrierid 0770 system radio
mkdir /data/misc/zoneinfo 0775 system system
mkdir /data/misc/textclassifier 0771 system system
mkdir /data/misc/vpn 0770 system vpn
@@ -432,6 +433,8 @@
mkdir /data/misc/update_engine 0700 root root
mkdir /data/misc/update_engine_log 02750 root log
mkdir /data/misc/trace 0700 root root
+ # create location to store surface and window trace files
+ mkdir /data/misc/wmtrace 0700 system system
# profile file layout
mkdir /data/misc/profiles 0771 system system
mkdir /data/misc/profiles/cur 0771 system system
@@ -481,6 +484,10 @@
mkdir /data/anr 0775 system system
+ # NFC: create data/nfc for nv storage
+ mkdir /data/nfc 0770 nfc nfc
+ mkdir /data/nfc/param 0770 nfc nfc
+
# Create all remaining /data root dirs so that they are made through init
# and get proper encryption policy installed
mkdir /data/backup 0700 system system
@@ -726,6 +733,8 @@
# Give writes to anyone for the trace folder on debug builds.
# The folder is used to store method traces.
chmod 0773 /data/misc/trace
+ # Give reads to anyone for the window trace folder on debug builds.
+ chmod 0775 /data/misc/wmtrace
start console
service flash_recovery /system/bin/install-recovery.sh