Merge "fs_mgr: Ignore invalid DT device nodes"
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 9b25a07..4314dae 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -159,7 +159,8 @@
adbd_cloexec_auth_socket();
#if defined(ALLOW_ADBD_NO_AUTH)
- auth_required = android::base::GetBoolProperty("ro.adb.secure", true);
+ // If ro.adb.secure is unset, default to no authentication required.
+ auth_required = android::base::GetBoolProperty("ro.adb.secure", false);
#endif
adbd_auth_init();
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h
index afff2c9..cc7aaf6 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -105,6 +105,9 @@
void DefaultAborter(const char* abort_message);
+std::string GetDefaultTag();
+void SetDefaultTag(const std::string& tag);
+
#ifdef __ANDROID__
// We expose this even though it is the default because a user that wants to
// override the default log buffer will have to construct this themselves.
diff --git a/base/logging.cpp b/base/logging.cpp
index 1f7bc2a..a31feef 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -139,9 +139,27 @@
return aborter;
}
-static std::string& ProgramInvocationName() {
- static auto& programInvocationName = *new std::string(getprogname());
- return programInvocationName;
+static std::recursive_mutex& TagLock() {
+ static auto& tag_lock = *new std::recursive_mutex();
+ return tag_lock;
+}
+static std::string* gDefaultTag;
+std::string GetDefaultTag() {
+ std::lock_guard<std::recursive_mutex> lock(TagLock());
+ if (gDefaultTag == nullptr) {
+ return "";
+ }
+ return *gDefaultTag;
+}
+void SetDefaultTag(const std::string& tag) {
+ std::lock_guard<std::recursive_mutex> lock(TagLock());
+ if (gDefaultTag != nullptr) {
+ delete gDefaultTag;
+ gDefaultTag = nullptr;
+ }
+ if (!tag.empty()) {
+ gDefaultTag = new std::string(tag);
+ }
}
static bool gInitialized = false;
@@ -269,8 +287,7 @@
// Linux to recover this, but we don't have that luxury on the Mac/Windows,
// and there are a couple of argv[0] variants that are commonly used.
if (argv != nullptr) {
- std::lock_guard<std::mutex> lock(LoggingLock());
- ProgramInvocationName() = basename(argv[0]);
+ SetDefaultTag(basename(argv[0]));
}
const char* tags = getenv("ANDROID_LOG_TAGS");
@@ -448,8 +465,15 @@
void LogMessage::LogLine(const char* file, unsigned int line, LogId id, LogSeverity severity,
const char* tag, const char* message) {
- if (tag == nullptr) tag = ProgramInvocationName().c_str();
- Logger()(id, severity, tag, file, line, message);
+ if (tag == nullptr) {
+ std::lock_guard<std::recursive_mutex> lock(TagLock());
+ if (gDefaultTag == nullptr) {
+ gDefaultTag = new std::string(getprogname());
+ }
+ Logger()(id, severity, gDefaultTag->c_str(), file, line, message);
+ } else {
+ Logger()(id, severity, tag, file, line, message);
+ }
}
void LogMessage::LogLine(const char* file, unsigned int line, LogId id, LogSeverity severity,
diff --git a/base/logging_test.cpp b/base/logging_test.cpp
index 6f05d9b..5f689fa 100644
--- a/base/logging_test.cpp
+++ b/base/logging_test.cpp
@@ -206,8 +206,8 @@
}
#endif
-static void CheckMessage(const CapturedStderr& cap,
- android::base::LogSeverity severity, const char* expected) {
+static void CheckMessage(const CapturedStderr& cap, android::base::LogSeverity severity,
+ const char* expected, const char* expected_tag = nullptr) {
std::string output;
ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
android::base::ReadFdToString(cap.fd(), &output);
@@ -217,9 +217,18 @@
// many characters are in the log message.
ASSERT_GT(output.length(), strlen(expected));
ASSERT_NE(nullptr, strstr(output.c_str(), expected)) << output;
+ if (expected_tag != nullptr) {
+ ASSERT_NE(nullptr, strstr(output.c_str(), expected_tag)) << output;
+ }
#if !defined(_WIN32)
- std::regex message_regex(make_log_pattern(severity, expected));
+ std::string regex_str;
+ if (expected_tag != nullptr) {
+ regex_str.append(expected_tag);
+ regex_str.append(" ");
+ }
+ regex_str.append(make_log_pattern(severity, expected));
+ std::regex message_regex(regex_str);
ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
#endif
}
@@ -600,3 +609,17 @@
__attribute__((constructor)) void TestLoggingInConstructor() {
LOG(ERROR) << "foobar";
}
+
+TEST(logging, SetDefaultTag) {
+ constexpr const char* expected_tag = "test_tag";
+ constexpr const char* expected_msg = "foobar";
+ CapturedStderr cap;
+ {
+ std::string old_default_tag = android::base::GetDefaultTag();
+ android::base::SetDefaultTag(expected_tag);
+ android::base::ScopedLogSeverity sls(android::base::LogSeverity::INFO);
+ LOG(INFO) << expected_msg;
+ android::base::SetDefaultTag(old_default_tag);
+ }
+ CheckMessage(cap, android::base::LogSeverity::INFO, expected_msg, expected_tag);
+}
diff --git a/init/README.md b/init/README.md
index 5c2352b..59ddd77 100644
--- a/init/README.md
+++ b/init/README.md
@@ -161,6 +161,25 @@
Options are modifiers to services. They affect how and when init
runs the service.
+`capabilities <capability> [ <capability>\* ]`
+> Set capabilities when exec'ing this service. 'capability' should be a Linux
+ capability without the "CAP\_" prefix, like "NET\_ADMIN" or "SETPCAP". See
+ http://man7.org/linux/man-pages/man7/capabilities.7.html for a list of Linux
+ capabilities.
+
+`class <name> [ <name>\* ]`
+> Specify class names for the service. All services in a
+ named class may be started or stopped together. A service
+ is in the class "default" if one is not specified via the
+ class option. Additional classnames beyond the (required) first
+ one are used to group services.
+ The `animation` class should include all services necessary for both
+ boot animation and shutdown animation. As these services can be
+ launched very early during bootup and can run until the last stage
+ of shutdown, access to /data partition is not guaranteed. These
+ services can check files under /data but it should not keep files opened
+ and should work when /data is not available.
+
`console [<console>]`
> This service needs a console. The optional second parameter chooses a
specific console instead of the default. The default "/dev/console" can
@@ -176,9 +195,93 @@
> This service will not automatically start with its class.
It must be explicitly started by name.
+`file <path> <type>`
+> Open a file path and pass its fd to the launched process. _type_ must be
+ "r", "w" or "rw". For native executables see libcutils
+ android\_get\_control\_file().
+
+`group <groupname> [ <groupname>\* ]`
+> Change to 'groupname' before exec'ing this service. Additional
+ groupnames beyond the (required) first one are used to set the
+ supplemental groups of the process (via setgroups()).
+ Currently defaults to root. (??? probably should default to nobody)
+
+`interface <interface name> <instance name>`
+> Associates this service with a list of the HIDL services that it provides. The interface name
+ must be a fully-qualified name and not a value name. This is used to allow hwservicemanager to
+ lazily start services.
+ For example: interface vendor.foo.bar@1.0::IBaz default
+
+`ioprio <class> <priority>`
+> Sets the IO priority and IO priority class for this service via the SYS_ioprio_set syscall.
+ _class_ must be one of "rt", "be", or "idle". _priority_ must be an integer in the range 0 - 7.
+
+`keycodes <keycode> [ <keycode>\* ]`
+> Sets the keycodes that will trigger this service. If all of the keys corresponding to the passed
+ keycodes are pressed at once, the service will start. This is typically used to start the
+ bugreport service.
+
+`memcg.limit_in_bytes <value>`
+> Sets the child's memory.limit_in_bytes to the specified value (only if memcg is mounted),
+ which must be equal or greater than 0.
+
+`memcg.soft_limit_in_bytes <value>`
+> Sets the child's memory.soft_limit_in_bytes to the specified value (only if memcg is mounted),
+ which must be equal or greater than 0.
+
+`memcg.swappiness <value>`
+> Sets the child's memory.swappiness to the specified value (only if memcg is mounted),
+ which must be equal or greater than 0.
+
+`namespace <pid|mnt>`
+> Enter a new PID or mount namespace when forking the service.
+
+`oneshot`
+> Do not restart the service when it exits.
+
+`onrestart`
+> Execute a Command (see below) when service restarts.
+
+`oom_score_adjust <value>`
+> Sets the child's /proc/self/oom\_score\_adj to the specified value,
+ which must range from -1000 to 1000.
+
+`override`
+> Indicates that this service definition is meant to override a previous definition for a service
+ with the same name. This is typically meant for services on /odm to override those defined on
+ /vendor. The last service definition that init parses with this keyword is the service definition
+ will use for this service. Pay close attention to the order in which init.rc files are parsed,
+ since it has some peculiarities for backwards compatibility reasons. The 'imports' section of
+ this file has more details on the order.
+
+`priority <priority>`
+> Scheduling priority of the service process. This value has to be in range
+ -20 to 19. Default priority is 0. Priority is set via setpriority().
+
+`rlimit <resource> <cur> <max>`
+> This applies the given rlimit to the service. rlimits are inherited by child
+ processes, so this effectively applies the given rlimit to the process tree
+ started by this service.
+ It is parsed similarly to the setrlimit command specified below.
+
+`seclabel <seclabel>`
+> Change to 'seclabel' before exec'ing this service.
+ Primarily for use by services run from the rootfs, e.g. ueventd, adbd.
+ Services on the system partition can instead use policy-defined transitions
+ based on their file security context.
+ If not specified and no transition is defined in policy, defaults to the init context.
+
`setenv <name> <value>`
> Set the environment variable _name_ to _value_ in the launched process.
+`shutdown <shutdown_behavior>`
+> Set shutdown behavior of the service process. When this is not specified,
+ the service is killed during shutdown process by using SIGTERM and SIGKILL.
+ The service with shutdown_behavior of "critical" is not killed during shutdown
+ until shutdown times out. When shutdown times out, even services tagged with
+ "shutdown critical" will be killed. When the service tagged with "shutdown critical"
+ is not running when shut down starts, it will be started.
+
`socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]`
> Create a unix domain socket named /dev/socket/_name_ and pass its fd to the
launched process. _type_ must be "dgram", "stream" or "seqpacket". User and
@@ -187,11 +290,6 @@
seclabel or computed based on the service executable file security context.
For native executables see libcutils android\_get\_control\_socket().
-`file <path> <type>`
-> Open a file path and pass its fd to the launched process. _type_ must be
- "r", "w" or "rw". For native executables see libcutils
- android\_get\_control\_file().
-
`user <username>`
> Change to 'username' before exec'ing this service.
Currently defaults to root. (??? probably should default to nobody)
@@ -208,88 +306,12 @@
As of Android O, processes can also request capabilities directly in their .rc
files. See the "capabilities" option below.
-`group <groupname> [ <groupname>\* ]`
-> Change to 'groupname' before exec'ing this service. Additional
- groupnames beyond the (required) first one are used to set the
- supplemental groups of the process (via setgroups()).
- Currently defaults to root. (??? probably should default to nobody)
-
-`capabilities <capability> [ <capability>\* ]`
-> Set capabilities when exec'ing this service. 'capability' should be a Linux
- capability without the "CAP\_" prefix, like "NET\_ADMIN" or "SETPCAP". See
- http://man7.org/linux/man-pages/man7/capabilities.7.html for a list of Linux
- capabilities.
-
-`setrlimit <resource> <cur> <max>`
-> This applies the given rlimit to the service. rlimits are inherited by child
- processes, so this effectively applies the given rlimit to the process tree
- started by this service.
- It is parsed similarly to the setrlimit command specified below.
-
-`seclabel <seclabel>`
-> Change to 'seclabel' before exec'ing this service.
- Primarily for use by services run from the rootfs, e.g. ueventd, adbd.
- Services on the system partition can instead use policy-defined transitions
- based on their file security context.
- If not specified and no transition is defined in policy, defaults to the init context.
-
-`oneshot`
-> Do not restart the service when it exits.
-
-`class <name> [ <name>\* ]`
-> Specify class names for the service. All services in a
- named class may be started or stopped together. A service
- is in the class "default" if one is not specified via the
- class option. Additional classnames beyond the (required) first
- one are used to group services.
-`animation class`
-> 'animation' class should include all services necessary for both
- boot animation and shutdown animation. As these services can be
- launched very early during bootup and can run until the last stage
- of shutdown, access to /data partition is not guaranteed. These
- services can check files under /data but it should not keep files opened
- and should work when /data is not available.
-
-`onrestart`
-> Execute a Command (see below) when service restarts.
-
`writepid <file> [ <file>\* ]`
> Write the child's pid to the given files when it forks. Meant for
cgroup/cpuset usage. If no files under /dev/cpuset/ are specified, but the
system property 'ro.cpuset.default' is set to a non-empty cpuset name (e.g.
'/foreground'), then the pid is written to file /dev/cpuset/_cpuset\_name_/tasks.
-`priority <priority>`
-> Scheduling priority of the service process. This value has to be in range
- -20 to 19. Default priority is 0. Priority is set via setpriority().
-
-`namespace <pid|mnt>`
-> Enter a new PID or mount namespace when forking the service.
-
-`oom_score_adjust <value>`
-> Sets the child's /proc/self/oom\_score\_adj to the specified value,
- which must range from -1000 to 1000.
-
-`memcg.swappiness <value>`
-> Sets the child's memory.swappiness to the specified value (only if memcg is mounted),
- which must be equal or greater than 0.
-
-`memcg.soft_limit_in_bytes <value>`
-> Sets the child's memory.soft_limit_in_bytes to the specified value (only if memcg is mounted),
- which must be equal or greater than 0.
-
-`memcg.limit_in_bytes <value>`
-> Sets the child's memory.limit_in_bytes to the specified value (only if memcg is mounted),
- which must be equal or greater than 0.
-
-`shutdown <shutdown_behavior>`
-> Set shutdown behavior of the service process. When this is not specified,
- the service is killed during shutdown process by using SIGTERM and SIGKILL.
- The service with shutdown_behavior of "critical" is not killed during shutdown
- until shutdown times out. When shutdown times out, even services tagged with
- "shutdown critical" will be killed. When the service tagged with "shutdown critical"
- is not running when shut down starts, it will be started.
-
Triggers
--------
diff --git a/init/service.cpp b/init/service.cpp
index 8130e73..694e5e7 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -446,8 +446,8 @@
const std::string& interface_name = args[1];
const std::string& instance_name = args[2];
- const FQName fq_name = FQName(interface_name);
- if (!fq_name.isValid()) {
+ FQName fq_name;
+ if (!FQName::parse(interface_name, &fq_name)) {
return Error() << "Invalid fully-qualified name for interface '" << interface_name << "'";
}
@@ -678,29 +678,29 @@
{"console", {0, 1, &Service::ParseConsole}},
{"critical", {0, 0, &Service::ParseCritical}},
{"disabled", {0, 0, &Service::ParseDisabled}},
+ {"file", {2, 2, &Service::ParseFile}},
{"group", {1, NR_SVC_SUPP_GIDS + 1, &Service::ParseGroup}},
{"interface", {2, 2, &Service::ParseInterface}},
{"ioprio", {2, 2, &Service::ParseIoprio}},
- {"priority", {1, 1, &Service::ParsePriority}},
{"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",
- {1, 1, &Service::ParseMemcgSwappiness}},
- {"memcg.soft_limit_in_bytes",
- {1, 1, &Service::ParseMemcgSoftLimitInBytes}},
{"memcg.limit_in_bytes",
{1, 1, &Service::ParseMemcgLimitInBytes}},
+ {"memcg.soft_limit_in_bytes",
+ {1, 1, &Service::ParseMemcgSoftLimitInBytes}},
+ {"memcg.swappiness",
+ {1, 1, &Service::ParseMemcgSwappiness}},
{"namespace", {1, 2, &Service::ParseNamespace}},
+ {"oneshot", {0, 0, &Service::ParseOneshot}},
+ {"onrestart", {1, kMax, &Service::ParseOnrestart}},
+ {"oom_score_adjust",
+ {1, 1, &Service::ParseOomScoreAdjust}},
+ {"override", {0, 0, &Service::ParseOverride}},
+ {"priority", {1, 1, &Service::ParsePriority}},
{"rlimit", {3, 3, &Service::ParseProcessRlimit}},
{"seclabel", {1, 1, &Service::ParseSeclabel}},
{"setenv", {2, 2, &Service::ParseSetenv}},
{"shutdown", {1, 1, &Service::ParseShutdown}},
{"socket", {3, 6, &Service::ParseSocket}},
- {"file", {2, 2, &Service::ParseFile}},
{"user", {1, 1, &Service::ParseUser}},
{"writepid", {1, kMax, &Service::ParseWritepid}},
};
diff --git a/libion/ion.c b/libion/ion.c
index 5836128..b8de5a4 100644
--- a/libion/ion.c
+++ b/libion/ion.c
@@ -55,7 +55,7 @@
int ion_open() {
int fd = open("/dev/ion", O_RDONLY | O_CLOEXEC);
- if (fd < 0) ALOGE("open /dev/ion failed!\n");
+ if (fd < 0) ALOGE("open /dev/ion failed: %s", strerror(errno));
return fd;
}
@@ -69,7 +69,7 @@
static int ion_ioctl(int fd, int req, void* arg) {
int ret = ioctl(fd, req, arg);
if (ret < 0) {
- ALOGE("ioctl %x failed with code %d: %s\n", req, ret, strerror(errno));
+ ALOGE("ioctl %x failed with code %d: %s", req, ret, strerror(errno));
return -errno;
}
return ret;
@@ -115,12 +115,12 @@
ret = ion_ioctl(fd, ION_IOC_MAP, &data);
if (ret < 0) return ret;
if (data.fd < 0) {
- ALOGE("map ioctl returned negative fd\n");
+ ALOGE("map ioctl returned negative fd");
return -EINVAL;
}
tmp_ptr = mmap(NULL, length, prot, flags, data.fd, offset);
if (tmp_ptr == MAP_FAILED) {
- ALOGE("mmap failed: %s\n", strerror(errno));
+ ALOGE("mmap failed: %s", strerror(errno));
return -errno;
}
*map_fd = data.fd;
@@ -140,7 +140,7 @@
ret = ion_ioctl(fd, ION_IOC_SHARE, &data);
if (ret < 0) return ret;
if (data.fd < 0) {
- ALOGE("share ioctl returned negative fd\n");
+ ALOGE("share ioctl returned negative fd");
return -EINVAL;
}
*share_fd = data.fd;
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
index d03a2b6..2754e6e 100644
--- a/liblog/logger_write.c
+++ b/liblog/logger_write.c
@@ -243,7 +243,7 @@
static int __write_to_log_daemon(log_id_t log_id, struct iovec* vec, size_t nr) {
struct android_log_transport_write* node;
- int ret;
+ int ret, save_errno;
struct timespec ts;
size_t len, i;
@@ -254,20 +254,24 @@
return -EINVAL;
}
+ save_errno = errno;
#if defined(__ANDROID__)
clock_gettime(android_log_clockid(), &ts);
if (log_id == LOG_ID_SECURITY) {
if (vec[0].iov_len < 4) {
+ errno = save_errno;
return -EINVAL;
}
ret = check_log_uid_permissions();
if (ret < 0) {
+ errno = save_errno;
return ret;
}
if (!__android_log_security()) {
/* If only we could reset downstream logd counter */
+ errno = save_errno;
return -EPERM;
}
} else if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS) {
@@ -276,6 +280,7 @@
EventTagMap *m, *f;
if (vec[0].iov_len < 4) {
+ errno = save_errno;
return -EINVAL;
}
@@ -311,6 +316,7 @@
android_closeEventTagMap(f);
}
if (!ret) {
+ errno = save_errno;
return -EPERM;
}
} else {
@@ -340,6 +346,7 @@
}
if (!__android_log_is_loggable_len(prio, tag, len - 1, ANDROID_LOG_VERBOSE)) {
+ errno = save_errno;
return -EPERM;
}
}
@@ -371,21 +378,23 @@
}
}
+ errno = save_errno;
return ret;
}
static int __write_to_log_init(log_id_t log_id, struct iovec* vec, size_t nr) {
+ int ret, save_errno = errno;
+
__android_log_lock();
if (write_to_log == __write_to_log_init) {
- int ret;
-
ret = __write_to_log_initialize();
if (ret < 0) {
__android_log_unlock();
if (!list_empty(&__android_log_persist_write)) {
__write_to_log_daemon(log_id, vec, nr);
}
+ errno = save_errno;
return ret;
}
@@ -394,7 +403,9 @@
__android_log_unlock();
- return write_to_log(log_id, vec, nr);
+ ret = write_to_log(log_id, vec, nr);
+ errno = save_errno;
+ return ret;
}
LIBLOG_ABI_PUBLIC int __android_log_write(int prio, const char* tag,
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 80dcdcb..32caa69 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -129,7 +129,6 @@
"PropertyMap.cpp",
"RefBase.cpp",
"SharedBuffer.cpp",
- "Static.cpp",
"StopWatch.cpp",
"String8.cpp",
"String16.cpp",
diff --git a/libutils/Static.cpp b/libutils/Static.cpp
deleted file mode 100644
index 3ed07a1..0000000
--- a/libutils/Static.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2008 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.
- */
-
-// All static variables go here, to control initialization and
-// destruction order in the library.
-
-namespace android {
-
-// For String8.cpp
-extern void initialize_string8();
-extern void terminate_string8();
-
-// For String16.cpp
-extern void initialize_string16();
-extern void terminate_string16();
-
-class LibUtilsFirstStatics
-{
-public:
- LibUtilsFirstStatics()
- {
- initialize_string8();
- initialize_string16();
- }
-
- ~LibUtilsFirstStatics()
- {
- terminate_string16();
- terminate_string8();
- }
-};
-
-static LibUtilsFirstStatics gFirstStatics;
-int gDarwinCantLoadAllObjects = 1;
-
-} // namespace android
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index ad335c3..84d53dd 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -24,29 +24,16 @@
namespace android {
-static SharedBuffer* gEmptyStringBuf = NULL;
-static char16_t* gEmptyString = NULL;
+static inline char16_t* getEmptyString() {
+ static SharedBuffer* gEmptyStringBuf = [] {
+ SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t));
+ char16_t* str = static_cast<char16_t*>(buf->data());
+ *str = 0;
+ return buf;
+ }();
-static inline char16_t* getEmptyString()
-{
gEmptyStringBuf->acquire();
- return gEmptyString;
-}
-
-void initialize_string16()
-{
- SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t));
- char16_t* str = (char16_t*)buf->data();
- *str = 0;
- gEmptyStringBuf = buf;
- gEmptyString = str;
-}
-
-void terminate_string16()
-{
- SharedBuffer::bufferFromData(gEmptyString)->release();
- gEmptyStringBuf = NULL;
- gEmptyString = NULL;
+ return static_cast<char16_t*>(gEmptyStringBuf->data());
}
// ---------------------------------------------------------------------------
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index ad0e72e..580e870 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -40,40 +40,16 @@
// to OS_PATH_SEPARATOR.
#define RES_PATH_SEPARATOR '/'
-static SharedBuffer* gEmptyStringBuf = NULL;
-static char* gEmptyString = NULL;
+static inline char* getEmptyString() {
+ static SharedBuffer* gEmptyStringBuf = [] {
+ SharedBuffer* buf = SharedBuffer::alloc(1);
+ char* str = static_cast<char*>(buf->data());
+ *str = 0;
+ return buf;
+ }();
-extern int gDarwinCantLoadAllObjects;
-int gDarwinIsReallyAnnoying;
-
-void initialize_string8();
-
-static inline char* getEmptyString()
-{
gEmptyStringBuf->acquire();
- return gEmptyString;
-}
-
-void initialize_string8()
-{
- // HACK: This dummy dependency forces linking libutils Static.cpp,
- // which is needed to initialize String8/String16 classes.
- // These variables are named for Darwin, but are needed elsewhere too,
- // including static linking on any platform.
- gDarwinIsReallyAnnoying = gDarwinCantLoadAllObjects;
-
- SharedBuffer* buf = SharedBuffer::alloc(1);
- char* str = (char*)buf->data();
- *str = 0;
- gEmptyStringBuf = buf;
- gEmptyString = str;
-}
-
-void terminate_string8()
-{
- SharedBuffer::bufferFromData(gEmptyString)->release();
- gEmptyStringBuf = NULL;
- gEmptyString = NULL;
+ return static_cast<char*>(gEmptyStringBuf->data());
}
// ---------------------------------------------------------------------------