Merge "debuggerd: Dump list of open files on process crash."
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 8b6b2b5..3cd50ba 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -30,7 +30,9 @@
#include <sys/time.h>
#include <time.h>
+#include <chrono>
#include <string>
+#include <thread>
#include <vector>
#include <android-base/errors.h>
@@ -51,6 +53,7 @@
#include <sys/capability.h>
#include <sys/mount.h>
#include <android-base/properties.h>
+using namespace std::chrono_literals;
#endif
std::string adb_version() {
@@ -375,7 +378,7 @@
adbd_auth_verified(t);
t->failed_auth_attempts = 0;
} else {
- if (t->failed_auth_attempts++ > 256) adb_sleep_ms(1000);
+ if (t->failed_auth_attempts++ > 256) std::this_thread::sleep_for(1s);
send_auth_request(t);
}
break;
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index 919e1c1..0b1ba32 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -29,6 +29,7 @@
#include <sys/types.h>
#include <string>
+#include <thread>
#include <vector>
#include <android-base/stringprintf.h>
@@ -38,6 +39,7 @@
#include "adb_io.h"
#include "adb_utils.h"
#include "socket_spec.h"
+#include "sysdeps/chrono.h"
static TransportType __adb_transport = kTransportAny;
static const char* __adb_serial = NULL;
@@ -188,8 +190,8 @@
} else {
fprintf(stdout,"* daemon started successfully *\n");
}
- /* give the server some time to start properly and detect devices */
- adb_sleep_ms(3000);
+ // Give the server some time to start properly and detect devices.
+ std::this_thread::sleep_for(3s);
// fall through to _adb_connect
} else {
// If a server is already running, check its version matches.
@@ -234,7 +236,7 @@
}
/* XXX can we better detect its death? */
- adb_sleep_ms(2000);
+ std::this_thread::sleep_for(2s);
goto start_server;
}
}
diff --git a/adb/adb_io.cpp b/adb/adb_io.cpp
index ae16834..ca8729e 100644
--- a/adb/adb_io.cpp
+++ b/adb/adb_io.cpp
@@ -20,6 +20,8 @@
#include <unistd.h>
+#include <thread>
+
#include <android-base/stringprintf.h>
#include "adb.h"
@@ -104,7 +106,7 @@
if (r == -1) {
D("writex: fd=%d error %d: %s", fd, errno, strerror(errno));
if (errno == EAGAIN) {
- adb_sleep_ms(1); // just yield some cpu time
+ std::this_thread::yield();
continue;
} else if (errno == EPIPE) {
D("writex: fd=%d disconnected", fd);
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index e15bcad..a064de2 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -33,6 +33,7 @@
#include <memory>
#include <string>
+#include <thread>
#include <vector>
#include <android-base/file.h>
@@ -59,6 +60,7 @@
#include "file_sync_service.h"
#include "services.h"
#include "shell_service.h"
+#include "sysdeps/chrono.h"
static int install_app(TransportType t, const char* serial, int argc, const char** argv);
static int install_multiple_app(TransportType t, const char* serial, int argc, const char** argv);
@@ -1080,7 +1082,7 @@
// Give adbd some time to kill itself and come back up.
// We can't use wait-for-device because devices (e.g. adb over network) might not come back.
- adb_sleep_ms(3000);
+ std::this_thread::sleep_for(3s);
return true;
}
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index f1e4179..caa7a5f 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -43,6 +43,7 @@
#include "adb_utils.h"
#include "file_sync_service.h"
#include "line_printer.h"
+#include "sysdeps/stat.h"
#include <android-base/file.h>
#include <android-base/strings.h>
@@ -64,15 +65,11 @@
}
static bool should_pull_file(mode_t mode) {
- return mode & (S_IFREG | S_IFBLK | S_IFCHR);
+ return S_ISREG(mode) || S_ISBLK(mode) || S_ISCHR(mode);
}
static bool should_push_file(mode_t mode) {
- mode_t mask = S_IFREG;
-#if !defined(_WIN32)
- mask |= S_IFLNK;
-#endif
- return mode & mask;
+ return S_ISREG(mode) || S_ISLNK(mode);
}
struct copyinfo {
@@ -149,7 +146,7 @@
void ReportProgress(LinePrinter& lp, const std::string& file, uint64_t file_copied_bytes,
uint64_t file_total_bytes) {
char overall_percentage_str[5] = "?";
- if (bytes_expected != 0) {
+ if (bytes_expected != 0 && bytes_transferred <= bytes_expected) {
int overall_percentage = static_cast<int>(bytes_transferred * 100 / bytes_expected);
// If we're pulling symbolic links, we'll pull the target of the link rather than
// just create a local link, and that will cause us to go over 100%.
diff --git a/adb/shell_service.cpp b/adb/shell_service.cpp
index e2b388b..4975fab 100644
--- a/adb/shell_service.cpp
+++ b/adb/shell_service.cpp
@@ -106,20 +106,6 @@
namespace {
-void init_subproc_child()
-{
- setsid();
-
- // Set OOM score adjustment to prevent killing
- int fd = adb_open("/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC);
- if (fd >= 0) {
- adb_write(fd, "0", 1);
- adb_close(fd);
- } else {
- D("adb: unable to update oom_score_adj");
- }
-}
-
// Reads from |fd| until close or failure.
std::string ReadAll(int fd) {
char buffer[512];
@@ -316,7 +302,7 @@
if (pid_ == 0) {
// Subprocess child.
- init_subproc_child();
+ setsid();
if (type_ == SubprocessType::kPty) {
child_stdinout_sfd.reset(OpenPtyChildFd(pts_name, &child_error_sfd));
diff --git a/adb/socket_test.cpp b/adb/socket_test.cpp
index 5e79b5e..f56f7f7 100644
--- a/adb/socket_test.cpp
+++ b/adb/socket_test.cpp
@@ -22,6 +22,7 @@
#include <limits>
#include <queue>
#include <string>
+#include <thread>
#include <vector>
#include <unistd.h>
@@ -31,6 +32,7 @@
#include "fdevent_test.h"
#include "socket.h"
#include "sysdeps.h"
+#include "sysdeps/chrono.h"
struct ThreadArg {
int first_read_fd;
@@ -44,7 +46,7 @@
fdevent_loop();
}
-const size_t SLEEP_FOR_FDEVENT_IN_MS = 100;
+constexpr auto SLEEP_FOR_FDEVENT = 100ms;
TEST_F(LocalSocketTest, smoke) {
// Join two socketpairs with a chain of intermediate socketpairs.
@@ -101,7 +103,7 @@
ASSERT_EQ(0, adb_close(last[1]));
// Wait until the local sockets are closed.
- adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+ std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
TerminateThread(thread);
}
@@ -154,12 +156,12 @@
ASSERT_TRUE(adb_thread_create(reinterpret_cast<void (*)(void*)>(CloseWithPacketThreadFunc),
&arg, &thread));
// Wait until the fdevent_loop() starts.
- adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+ std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
ASSERT_EQ(0, adb_close(cause_close_fd[0]));
- adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+ std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
ASSERT_EQ(0, adb_close(socket_fd[0]));
- adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+ std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
TerminateThread(thread);
}
@@ -179,9 +181,9 @@
ASSERT_TRUE(adb_thread_create(reinterpret_cast<void (*)(void*)>(CloseWithPacketThreadFunc),
&arg, &thread));
// Wait until the fdevent_loop() starts.
- adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+ std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
ASSERT_EQ(0, adb_close(cause_close_fd[0]));
- adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+ std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
// Verify if we can read successfully.
@@ -190,7 +192,7 @@
ASSERT_EQ(true, ReadFdExactly(socket_fd[0], buf.data(), buf.size()));
ASSERT_EQ(0, adb_close(socket_fd[0]));
- adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+ std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
TerminateThread(thread);
}
@@ -214,11 +216,11 @@
&arg, &thread));
// Wait until the fdevent_loop() starts.
- adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+ std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
EXPECT_EQ(2u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
ASSERT_EQ(0, adb_close(socket_fd[0]));
- adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+ std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
TerminateThread(thread);
}
@@ -229,7 +231,7 @@
std::string error;
int fd = network_loopback_client(5038, SOCK_STREAM, &error);
ASSERT_GE(fd, 0) << error;
- adb_sleep_ms(200);
+ std::this_thread::sleep_for(200ms);
ASSERT_EQ(0, adb_close(fd));
}
@@ -265,13 +267,13 @@
&arg, &thread));
// Wait until the fdevent_loop() starts.
- adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+ std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
// Wait until the client closes its socket.
ASSERT_TRUE(adb_thread_join(client_thread));
- adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+ std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
TerminateThread(thread);
}
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index ad9b9fd..05d9fde 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -180,8 +180,6 @@
/* nothing really */
}
-#define S_ISLNK(m) 0 /* no symlinks on Win32 */
-
extern int adb_unlink(const char* path);
#undef unlink
#define unlink ___xxx_unlink
@@ -248,11 +246,6 @@
int unix_isatty(int fd);
#define isatty ___xxx_isatty
-static __inline__ void adb_sleep_ms( int mseconds )
-{
- Sleep( mseconds );
-}
-
int network_loopback_client(int port, int type, std::string* error);
int network_loopback_server(int port, int type, std::string* error);
int network_inaddr_any_server(int port, int type, std::string* error);
@@ -766,11 +759,6 @@
#define poll ___xxx_poll
-static __inline__ void adb_sleep_ms( int mseconds )
-{
- usleep( mseconds*1000 );
-}
-
static __inline__ int adb_mkdir(const std::string& path, int mode)
{
return mkdir(path.c_str(), mode);
diff --git a/adb/sysdeps/chrono.h b/adb/sysdeps/chrono.h
new file mode 100644
index 0000000..c73a638
--- /dev/null
+++ b/adb/sysdeps/chrono.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2016 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 <chrono>
+
+#if defined(_WIN32)
+// We don't have C++14 on Windows yet.
+// Reimplement std::chrono_literals ourselves until we do.
+
+// Silence the following warning (which gets promoted to an error):
+// error: literal operator suffixes not preceded by ‘_’ are reserved for future standardization
+#pragma GCC system_header
+
+constexpr std::chrono::seconds operator"" s(unsigned long long s) {
+ return std::chrono::seconds(s);
+}
+
+constexpr std::chrono::duration<long double> operator"" s(long double s) {
+ return std::chrono::duration<long double>(s);
+}
+
+constexpr std::chrono::milliseconds operator"" ms(unsigned long long ms) {
+ return std::chrono::milliseconds(ms);
+}
+
+constexpr std::chrono::duration<long double, std::milli> operator"" ms(long double ms) {
+ return std::chrono::duration<long double, std::milli>(ms);
+}
+#else
+using namespace std::chrono_literals;
+#endif
diff --git a/adb/sysdeps/stat.h b/adb/sysdeps/stat.h
index 5953595..ed2cf25fb 100644
--- a/adb/sysdeps/stat.h
+++ b/adb/sysdeps/stat.h
@@ -43,4 +43,21 @@
// Windows doesn't have lstat.
#define lstat adb_stat
+// mingw doesn't define S_IFLNK or S_ISLNK.
+#define S_IFLNK 0120000
+#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
+
+// mingw defines S_IFBLK to a different value from bionic.
+#undef S_IFBLK
+#define S_IFBLK 0060000
+#undef S_ISBLK
+#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
#endif
+
+// Make sure that host file mode values match the ones on the device.
+static_assert(S_IFMT == 00170000, "");
+static_assert(S_IFLNK == 0120000, "");
+static_assert(S_IFREG == 0100000, "");
+static_assert(S_IFBLK == 0060000, "");
+static_assert(S_IFDIR == 0040000, "");
+static_assert(S_IFCHR == 0020000, "");
diff --git a/adb/sysdeps_test.cpp b/adb/sysdeps_test.cpp
index 9f77942..9007e75 100644
--- a/adb/sysdeps_test.cpp
+++ b/adb/sysdeps_test.cpp
@@ -16,14 +16,17 @@
#include <gtest/gtest.h>
#include <unistd.h>
+
#include <atomic>
#include <condition_variable>
+#include <thread>
#include "adb_io.h"
#include "sysdeps.h"
+#include "sysdeps/chrono.h"
static void increment_atomic_int(void* c) {
- sleep(1);
+ std::this_thread::sleep_for(1s);
reinterpret_cast<std::atomic<int>*>(c)->fetch_add(1);
}
@@ -34,7 +37,7 @@
ASSERT_TRUE(adb_thread_create(increment_atomic_int, &counter));
}
- sleep(2);
+ std::this_thread::sleep_for(2s);
ASSERT_EQ(100, counter.load());
}
@@ -255,15 +258,15 @@
ASSERT_FALSE(m.try_lock());
m.lock();
finished.store(true);
- adb_sleep_ms(200);
+ std::this_thread::sleep_for(200ms);
m.unlock();
}, nullptr);
ASSERT_FALSE(finished.load());
- adb_sleep_ms(100);
+ std::this_thread::sleep_for(100ms);
ASSERT_FALSE(finished.load());
m.unlock();
- adb_sleep_ms(100);
+ std::this_thread::sleep_for(100ms);
m.lock();
ASSERT_TRUE(finished.load());
m.unlock();
@@ -279,13 +282,13 @@
adb_thread_create([](void*) {
ASSERT_FALSE(m.try_lock());
m.lock();
- adb_sleep_ms(500);
+ std::this_thread::sleep_for(500ms);
m.unlock();
}, nullptr);
- adb_sleep_ms(100);
+ std::this_thread::sleep_for(100ms);
m.unlock();
- adb_sleep_ms(100);
+ std::this_thread::sleep_for(100ms);
ASSERT_FALSE(m.try_lock());
m.lock();
m.unlock();
diff --git a/adb/test_device.py b/adb/test_device.py
index 02a16e4..e76aaed 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -890,7 +890,8 @@
except subprocess.CalledProcessError as e:
output = e.output
- self.assertIn('Permission denied', output)
+ self.assertTrue('Permission denied' in output or
+ 'Read-only file system' in output)
def _test_pull(self, remote_file, checksum):
tmp_write = tempfile.NamedTemporaryFile(mode='wb', delete=False)
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index ba2b28d..c17f869 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -27,6 +27,7 @@
#include <condition_variable>
#include <mutex>
+#include <thread>
#include <vector>
#include <android-base/stringprintf.h>
@@ -39,6 +40,7 @@
#include "adb.h"
#include "adb_io.h"
#include "adb_utils.h"
+#include "sysdeps/chrono.h"
#if ADB_HOST
@@ -144,7 +146,7 @@
// Retry the disconnected local port for 60 times, and sleep 1 second between two retries.
constexpr uint32_t LOCAL_PORT_RETRY_COUNT = 60;
-constexpr uint32_t LOCAL_PORT_RETRY_INTERVAL_IN_MS = 1000;
+constexpr auto LOCAL_PORT_RETRY_INTERVAL = 1s;
struct RetryPort {
int port;
@@ -173,7 +175,7 @@
// Sleep here instead of the end of loop, because if we immediately try to reconnect
// the emulator just kicked, the adbd on the emulator may not have time to remove the
// just kicked transport.
- adb_sleep_ms(LOCAL_PORT_RETRY_INTERVAL_IN_MS);
+ std::this_thread::sleep_for(LOCAL_PORT_RETRY_INTERVAL);
// Try connecting retry ports.
std::vector<RetryPort> next_ports;
@@ -214,7 +216,7 @@
serverfd = network_inaddr_any_server(port, SOCK_STREAM, &error);
if(serverfd < 0) {
D("server: cannot bind socket yet: %s", error.c_str());
- adb_sleep_ms(1000);
+ std::this_thread::sleep_for(1s);
continue;
}
close_on_exec(serverfd);
diff --git a/adb/usb_linux.cpp b/adb/usb_linux.cpp
index 3e5028d..e7f1338 100644
--- a/adb/usb_linux.cpp
+++ b/adb/usb_linux.cpp
@@ -38,6 +38,7 @@
#include <list>
#include <mutex>
#include <string>
+#include <thread>
#include <android-base/file.h>
#include <android-base/stringprintf.h>
@@ -46,6 +47,7 @@
#include "adb.h"
#include "transport.h"
+using namespace std::chrono_literals;
using namespace std::literals;
/* usb scan debugging is waaaay too verbose */
@@ -577,7 +579,7 @@
// TODO: Use inotify.
find_usb_device("/dev/bus/usb", register_device);
kick_disconnected_devices();
- sleep(1);
+ std::this_thread::sleep_for(1s);
}
}
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index 6de10f5..1cc7f68 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -31,8 +31,10 @@
#include <algorithm>
#include <atomic>
+#include <chrono>
#include <condition_variable>
#include <mutex>
+#include <thread>
#include <android-base/logging.h>
#include <android-base/properties.h>
@@ -40,6 +42,8 @@
#include "adb.h"
#include "transport.h"
+using namespace std::chrono_literals;
+
#define MAX_PACKET_SIZE_FS 64
#define MAX_PACKET_SIZE_HS 512
#define MAX_PACKET_SIZE_SS 1024
@@ -268,7 +272,7 @@
fd = unix_open("/dev/android", O_RDWR);
}
if (fd < 0) {
- adb_sleep_ms(1000);
+ std::this_thread::sleep_for(1s);
}
} while (fd < 0);
D("[ opening device succeeded ]");
@@ -476,7 +480,7 @@
if (init_functionfs(usb)) {
break;
}
- adb_sleep_ms(1000);
+ std::this_thread::sleep_for(1s);
}
android::base::SetProperty("sys.usb.ffs.ready", "1");
diff --git a/adb/usb_osx.cpp b/adb/usb_osx.cpp
index 2ee2aae..e541f6e 100644
--- a/adb/usb_osx.cpp
+++ b/adb/usb_osx.cpp
@@ -30,8 +30,10 @@
#include <stdio.h>
#include <atomic>
+#include <chrono>
#include <memory>
#include <mutex>
+#include <thread>
#include <vector>
#include <android-base/logging.h>
@@ -40,6 +42,8 @@
#include "adb.h"
#include "transport.h"
+using namespace std::chrono_literals;
+
struct usb_handle
{
UInt8 bulkIn;
@@ -411,7 +415,7 @@
}
// Signal the parent that we are running
usb_inited_flag = true;
- adb_sleep_ms(1000);
+ std::this_thread::sleep_for(1s);
}
VLOG(USB) << "RunLoopThread done";
}
@@ -436,7 +440,7 @@
// Wait for initialization to finish
while (!usb_inited_flag) {
- adb_sleep_ms(100);
+ std::this_thread::sleep_for(100ms);
}
initialized = true;
diff --git a/adb/usb_windows.cpp b/adb/usb_windows.cpp
index 755f07e..640e91e 100644
--- a/adb/usb_windows.cpp
+++ b/adb/usb_windows.cpp
@@ -28,12 +28,14 @@
#include <stdlib.h>
#include <mutex>
+#include <thread>
#include <adb_api.h>
#include <android-base/errors.h>
#include "adb.h"
+#include "sysdeps/chrono.h"
#include "transport.h"
/** Structure usb_handle describes our connection to the usb device via
@@ -176,9 +178,9 @@
adb_thread_setname("Device Poll");
D("Created device thread");
- while(1) {
+ while (true) {
find_devices();
- adb_sleep_ms(1000);
+ std::this_thread::sleep_for(1s);
}
}
diff --git a/base/Android.bp b/base/Android.bp
index e6ad15b..b9a6e0b 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -49,6 +49,11 @@
srcs: ["errors_unix.cpp"],
cppflags: ["-Wexit-time-destructors"],
},
+ linux_bionic: {
+ srcs: ["errors_unix.cpp"],
+ cppflags: ["-Wexit-time-destructors"],
+ enabled: true,
+ },
linux: {
srcs: ["errors_unix.cpp"],
cppflags: ["-Wexit-time-destructors"],
diff --git a/bootstat/histogram_logger.cpp b/bootstat/histogram_logger.cpp
index 6a9ef2b..73f3295 100644
--- a/bootstat/histogram_logger.cpp
+++ b/bootstat/histogram_logger.cpp
@@ -19,13 +19,13 @@
#include <cstdlib>
#include <android-base/logging.h>
-#include <log/log.h>
+#include <log/log_event_list.h>
namespace bootstat {
void LogHistogram(const std::string& event, int32_t data) {
LOG(INFO) << "Logging histogram: " << event << " " << data;
- android_log_event_context log(HISTOGRAM_LOG_TAG);
+ android_log_event_list log(HISTOGRAM_LOG_TAG);
log << event << data << LOG_ID_EVENTS;
}
diff --git a/debuggerd/crasher.cpp b/debuggerd/crasher.cpp
index 3db67b3..b0e8b17 100644
--- a/debuggerd/crasher.cpp
+++ b/debuggerd/crasher.cpp
@@ -160,7 +160,11 @@
{
fprintf(stderr, "%s: init pid=%d tid=%d\n", __progname, getpid(), gettid());
- if (!strncmp(arg, "exhaustfd-", strlen("exhaustfd-"))) {
+ if (!strncmp(arg, "wait-", strlen("wait-"))) {
+ char buf[1];
+ TEMP_FAILURE_RETRY(read(STDIN_FILENO, buf, sizeof(buf)));
+ return do_action(arg + strlen("wait-"));
+ } else if (!strncmp(arg, "exhaustfd-", strlen("exhaustfd-"))) {
errno = 0;
while (errno != EMFILE) {
open("/dev/null", O_RDONLY);
@@ -235,6 +239,8 @@
fprintf(stderr, "on the process' main thread.\n");
fprintf(stderr, "prefix any of the above with 'exhaustfd-' to exhaust\n");
fprintf(stderr, "all available file descriptors before crashing.\n");
+ fprintf(stderr, "prefix any of the above with 'wait-' to wait until input is received on stdin\n");
+
return EXIT_SUCCESS;
}
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index 03b3a17..e76edb9 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -572,7 +572,7 @@
if (log_entry.id() == LOG_ID_EVENTS) {
if (!g_eventTagMap) {
- g_eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+ g_eventTagMap = android_openEventTagMap(NULL);
}
AndroidLogEntry e;
char buf[512];
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 4cd423a..7f4a0dd 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -43,7 +43,9 @@
#include <sys/types.h>
#include <unistd.h>
+#include <chrono>
#include <functional>
+#include <thread>
#include <utility>
#include <vector>
@@ -301,7 +303,7 @@
announce = false;
fprintf(stderr, "< waiting for %s >\n", serial ? serial : "any device");
}
- usleep(1000);
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
diff --git a/fastboot/usb_linux.cpp b/fastboot/usb_linux.cpp
index 6db1e27..cdab4f1 100644
--- a/fastboot/usb_linux.cpp
+++ b/fastboot/usb_linux.cpp
@@ -43,11 +43,15 @@
#include <linux/version.h>
#include <linux/usb/ch9.h>
+#include <chrono>
#include <memory>
+#include <thread>
#include "fastboot.h"
#include "usb.h"
+using namespace std::chrono_literals;
+
#define MAX_RETRIES 5
/* Timeout in seconds for usb_wait_for_disconnect.
@@ -426,7 +430,7 @@
return -1;
}
- while(len > 0) {
+ while (len > 0) {
int xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
bulk.ep = handle_->ep_in;
@@ -435,18 +439,17 @@
bulk.timeout = 0;
retry = 0;
- do{
- DBG("[ usb read %d fd = %d], fname=%s\n", xfer, handle_->desc, handle_->fname);
- n = ioctl(handle_->desc, USBDEVFS_BULK, &bulk);
- DBG("[ usb read %d ] = %d, fname=%s, Retry %d \n", xfer, n, handle_->fname, retry);
+ do {
+ DBG("[ usb read %d fd = %d], fname=%s\n", xfer, handle_->desc, handle_->fname);
+ n = ioctl(handle_->desc, USBDEVFS_BULK, &bulk);
+ DBG("[ usb read %d ] = %d, fname=%s, Retry %d \n", xfer, n, handle_->fname, retry);
- if( n < 0 ) {
- DBG1("ERROR: n = %d, errno = %d (%s)\n",n, errno, strerror(errno));
- if ( ++retry > MAX_RETRIES ) return -1;
- sleep( 1 );
- }
- }
- while( n < 0 );
+ if (n < 0) {
+ DBG1("ERROR: n = %d, errno = %d (%s)\n",n, errno, strerror(errno));
+ if (++retry > MAX_RETRIES) return -1;
+ std::this_thread::sleep_for(1s);
+ }
+ } while (n < 0);
count += n;
len -= n;
@@ -488,9 +491,8 @@
{
double deadline = now() + WAIT_FOR_DISCONNECT_TIMEOUT;
while (now() < deadline) {
- if (access(handle_->fname, F_OK))
- return 0;
- usleep(50000);
+ if (access(handle_->fname, F_OK)) return 0;
+ std::this_thread::sleep_for(50ms);
}
return -1;
}
diff --git a/fastboot/usb_windows.cpp b/fastboot/usb_windows.cpp
index 1cdeb32..3dab5ac 100644
--- a/fastboot/usb_windows.cpp
+++ b/fastboot/usb_windows.cpp
@@ -362,9 +362,3 @@
std::unique_ptr<usb_handle> handle = find_usb_device(callback);
return handle ? new WindowsUsbTransport(std::move(handle)) : nullptr;
}
-
-// called from fastboot.c
-void sleep(int seconds)
-{
- Sleep(seconds * 1000);
-}
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index d570255..e0d46d3 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -56,6 +56,7 @@
#define FSCK_LOG_FILE "/dev/fscklogs/log"
#define ZRAM_CONF_DEV "/sys/block/zram0/disksize"
+#define ZRAM_CONF_MCS "/sys/block/zram0/max_comp_streams"
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
@@ -241,7 +242,7 @@
return ret;
}
-static int fs_match(char *in1, char *in2)
+static int fs_match(const char *in1, const char *in2)
{
char *n1;
char *n2;
@@ -651,7 +652,7 @@
* If multiple fstab entries are to be mounted on "n_name", it will try to mount each one
* in turn, and stop on 1st success, or no more match.
*/
-int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
+int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
char *tmp_mount_point)
{
int i = 0;
@@ -802,6 +803,18 @@
* we can assume the device number is 0.
*/
FILE *zram_fp;
+ FILE *zram_mcs_fp;
+
+ if (fstab->recs[i].max_comp_streams >= 0) {
+ zram_mcs_fp = fopen(ZRAM_CONF_MCS, "r+");
+ if (zram_mcs_fp == NULL) {
+ ERROR("Unable to open zram conf comp device %s\n", ZRAM_CONF_MCS);
+ ret = -1;
+ continue;
+ }
+ fprintf(zram_mcs_fp, "%d\n", fstab->recs[i].max_comp_streams);
+ fclose(zram_mcs_fp);
+ }
zram_fp = fopen(ZRAM_CONF_DEV, "r+");
if (zram_fp == NULL) {
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index 313bc5a..b219b38 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -31,6 +31,7 @@
char *label;
int partnum;
int swap_prio;
+ int max_comp_streams;
unsigned int zram_size;
};
@@ -71,6 +72,7 @@
{ "recoveryonly",MF_RECOVERYONLY },
{ "swapprio=", MF_SWAPPRIO },
{ "zramsize=", MF_ZRAMSIZE },
+ { "max_comp_streams=", MF_MAX_COMP_STREAMS },
{ "verify", MF_VERIFY },
{ "noemulatedsd", MF_NOEMULATEDSD },
{ "notrim", MF_NOTRIM },
@@ -180,6 +182,8 @@
}
} else if ((fl[i].flag == MF_SWAPPRIO) && flag_vals) {
flag_vals->swap_prio = strtoll(strchr(p, '=') + 1, NULL, 0);
+ } else if ((fl[i].flag == MF_MAX_COMP_STREAMS) && flag_vals) {
+ flag_vals->max_comp_streams = strtoll(strchr(p, '=') + 1, NULL, 0);
} else if ((fl[i].flag == MF_ZRAMSIZE) && flag_vals) {
int is_percent = !!strrchr(p, '%');
unsigned int val = strtoll(strchr(p, '=') + 1, NULL, 0);
@@ -329,6 +333,7 @@
fstab->recs[cnt].label = flag_vals.label;
fstab->recs[cnt].partnum = flag_vals.partnum;
fstab->recs[cnt].swap_prio = flag_vals.swap_prio;
+ fstab->recs[cnt].max_comp_streams = flag_vals.max_comp_streams;
fstab->recs[cnt].zram_size = flag_vals.zram_size;
cnt++;
}
diff --git a/fs_mgr/fs_mgr_main.c b/fs_mgr/fs_mgr_main.c
index 33a7496..4bfe202 100644
--- a/fs_mgr/fs_mgr_main.c
+++ b/fs_mgr/fs_mgr_main.c
@@ -14,12 +14,17 @@
* limitations under the License.
*/
+#define _GNU_SOURCE
+
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
-#include <libgen.h>
#include "fs_mgr_priv.h"
+#ifdef _LIBGEN_H
+#warning "libgen.h must not be included"
+#endif
+
char *me = "";
static void usage(void)
@@ -32,10 +37,10 @@
* and exit the program, do not return to the caller.
* Return the number of argv[] entries consumed.
*/
-static void parse_options(int argc, char *argv[], int *a_flag, int *u_flag, int *n_flag,
- char **n_name, char **n_blk_dev)
+static void parse_options(int argc, char * const argv[], int *a_flag, int *u_flag, int *n_flag,
+ const char **n_name, const char **n_blk_dev)
{
- me = basename(strdup(argv[0]));
+ me = basename(argv[0]);
if (argc <= 1) {
usage();
@@ -75,14 +80,14 @@
return;
}
-int main(int argc, char *argv[])
+int main(int argc, char * const argv[])
{
int a_flag=0;
int u_flag=0;
int n_flag=0;
- char *n_name=NULL;
- char *n_blk_dev=NULL;
- char *fstab_file=NULL;
+ const char *n_name=NULL;
+ const char *n_blk_dev=NULL;
+ const char *fstab_file=NULL;
struct fstab *fstab=NULL;
klog_set_level(6);
@@ -97,7 +102,7 @@
if (a_flag) {
return fs_mgr_mount_all(fstab, MOUNT_MODE_DEFAULT);
} else if (n_flag) {
- return fs_mgr_do_mount(fstab, n_name, n_blk_dev, 0);
+ return fs_mgr_do_mount(fstab, n_name, (char *)n_blk_dev, 0);
} else if (u_flag) {
return fs_mgr_unmount_all(fstab);
} else {
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 6d9492b..741f5e9 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -85,6 +85,7 @@
#define MF_FORCEFDEORFBE 0x10000
#define MF_LATEMOUNT 0x20000
#define MF_NOFAIL 0x40000
+#define MF_MAX_COMP_STREAMS 0x100000
#define DM_BUF_SIZE 4096
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index c0116ef..37df8f8 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -73,6 +73,7 @@
char *label;
int partnum;
int swap_prio;
+ int max_comp_streams;
unsigned int zram_size;
};
@@ -95,7 +96,7 @@
#define FS_MGR_DOMNT_FAILED (-1)
#define FS_MGR_DOMNT_BUSY (-2)
-int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
+int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
char *tmp_mount_point);
int fs_mgr_do_tmpfs_mount(char *n_name);
int fs_mgr_unmount_all(struct fstab *fstab);
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 612885b..857bcb2 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -257,13 +257,13 @@
static int draw_text(const char *str, int x, int y)
{
- int str_len_px = gr_measure(str);
+ int str_len_px = gr_measure(gr_sys_font(), str);
if (x < 0)
x = (gr_fb_width() - str_len_px) / 2;
if (y < 0)
y = (gr_fb_height() - char_height) / 2;
- gr_text(x, y, str, 0);
+ gr_text(gr_sys_font(), x, y, str, 0);
return y + char_height;
}
@@ -364,7 +364,7 @@
}
gr_init();
- gr_font_size(&char_width, &char_height);
+ gr_font_size(gr_sys_font(), &char_width, &char_height);
#ifndef CHARGER_DISABLE_INIT_BLANK
gr_fb_blank(true);
diff --git a/include/cutils/files.h b/include/cutils/android_get_control_file.h
similarity index 87%
rename from include/cutils/files.h
rename to include/cutils/android_get_control_file.h
index 0210e30..ed8fbf8 100644
--- a/include/cutils/files.h
+++ b/include/cutils/android_get_control_file.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef __CUTILS_FILES_H
-#define __CUTILS_FILES_H
+#ifndef __CUTILS_ANDROID_GET_CONTROL_FILE_H
+#define __CUTILS_ANDROID_GET_CONTROL_FILE_H
#define ANDROID_FILE_ENV_PREFIX "ANDROID_FILE_"
@@ -34,4 +34,4 @@
}
#endif
-#endif /* __CUTILS_FILES_H */
+#endif /* __CUTILS_ANDROID_GET_CONTROL_FILE_H */
diff --git a/include/cutils/sockets.h b/include/cutils/sockets.h
index 4626e7a..d724dd6 100644
--- a/include/cutils/sockets.h
+++ b/include/cutils/sockets.h
@@ -35,6 +35,7 @@
#else
#include <sys/socket.h>
+#include <netinet/in.h>
typedef int cutils_socket_t;
#define INVALID_SOCKET (-1)
diff --git a/include/log/log.h b/include/log/log.h
index a44aba8..d6f0eb5 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -27,15 +27,8 @@
#include <time.h> /* clock_gettime */
#include <unistd.h>
-#include <log/uio.h> /* helper to define iovec for portability */
-
-#if (defined(__cplusplus) && defined(_USING_LIBCXX))
-extern "C++" {
-#include <string>
-}
-#endif
-
#include <android/log.h>
+#include <log/uio.h> /* helper to define iovec for portability */
#ifdef __cplusplus
extern "C" {
@@ -774,207 +767,6 @@
/* --------------------------------------------------------------------- */
-#ifndef __ANDROID_USE_LIBLOG_EVENT_INTERFACE
-#ifndef __ANDROID_API__
-#define __ANDROID_USE_LIBLOG_EVENT_INTERFACE 1
-#elif __ANDROID_API__ > 23 /* > Marshmallow */
-#define __ANDROID_USE_LIBLOG_EVENT_INTERFACE 1
-#else
-#define __ANDROID_USE_LIBLOG_EVENT_INTERFACE 0
-#endif
-#endif
-
-#if __ANDROID_USE_LIBLOG_EVENT_INTERFACE
-
-/* For manipulating lists of events. */
-
-#define ANDROID_MAX_LIST_NEST_DEPTH 8
-
-/*
- * The opaque context used to manipulate lists of events.
- */
-#ifndef __android_log_context_defined
-#define __android_log_context_defined
-typedef struct android_log_context_internal* android_log_context;
-#endif
-
-/*
- * Elements returned when reading a list of events.
- */
-#ifndef __android_log_list_element_defined
-#define __android_log_list_element_defined
-typedef struct {
- AndroidEventLogType type;
- uint16_t complete;
- uint16_t len;
- union {
- int32_t int32;
- int64_t int64;
- char* string;
- float float32;
- } data;
-} android_log_list_element;
-#endif
-
-/*
- * Creates a context associated with an event tag to write elements to
- * the list of events.
- */
-android_log_context create_android_logger(uint32_t tag);
-
-/* All lists must be braced by a begin and end call */
-/*
- * NB: If the first level braces are missing when specifying multiple
- * elements, we will manufacturer a list to embrace it for your API
- * convenience. For a single element, it will remain solitary.
- */
-int android_log_write_list_begin(android_log_context ctx);
-int android_log_write_list_end(android_log_context ctx);
-
-int android_log_write_int32(android_log_context ctx, int32_t value);
-int android_log_write_int64(android_log_context ctx, int64_t value);
-int android_log_write_string8(android_log_context ctx, const char* value);
-int android_log_write_string8_len(android_log_context ctx,
- const char* value, size_t maxlen);
-int android_log_write_float32(android_log_context ctx, float value);
-
-/* Submit the composed list context to the specified logger id */
-/* NB: LOG_ID_EVENTS and LOG_ID_SECURITY only valid binary buffers */
-int android_log_write_list(android_log_context ctx, log_id_t id);
-
-/*
- * Creates a context from a raw buffer representing a list of events to be read.
- */
-android_log_context create_android_log_parser(const char* msg, size_t len);
-
-android_log_list_element android_log_read_next(android_log_context ctx);
-android_log_list_element android_log_peek_next(android_log_context ctx);
-
-/* Finished with reader or writer context */
-int android_log_destroy(android_log_context* ctx);
-
-#ifdef __cplusplus
-#ifndef __class_android_log_event_context
-#define __class_android_log_event_context
-/* android_log_context C++ helpers */
-extern "C++" {
-class android_log_event_context {
- android_log_context ctx;
- int ret;
-
- android_log_event_context(const android_log_event_context&) = delete;
- void operator =(const android_log_event_context&) = delete;
-
-public:
- explicit android_log_event_context(int tag) : ret(0) {
- ctx = create_android_logger(static_cast<uint32_t>(tag));
- }
- explicit android_log_event_context(log_msg& log_msg) : ret(0) {
- ctx = create_android_log_parser(log_msg.msg() + sizeof(uint32_t),
- log_msg.entry.len - sizeof(uint32_t));
- }
- ~android_log_event_context() { android_log_destroy(&ctx); }
-
- int close() {
- int retval = android_log_destroy(&ctx);
- if (retval < 0) ret = retval;
- return retval;
- }
-
- /* To allow above C calls to use this class as parameter */
- operator android_log_context() const { return ctx; }
-
- int status() const { return ret; }
-
- int begin() {
- int retval = android_log_write_list_begin(ctx);
- if (retval < 0) ret = retval;
- return ret;
- }
- int end() {
- int retval = android_log_write_list_end(ctx);
- if (retval < 0) ret = retval;
- return ret;
- }
-
- android_log_event_context& operator <<(int32_t value) {
- int retval = android_log_write_int32(ctx, value);
- if (retval < 0) ret = retval;
- return *this;
- }
- android_log_event_context& operator <<(uint32_t value) {
- int retval = android_log_write_int32(ctx, static_cast<int32_t>(value));
- if (retval < 0) ret = retval;
- return *this;
- }
- android_log_event_context& operator <<(int64_t value) {
- int retval = android_log_write_int64(ctx, value);
- if (retval < 0) ret = retval;
- return *this;
- }
- android_log_event_context& operator <<(uint64_t value) {
- int retval = android_log_write_int64(ctx, static_cast<int64_t>(value));
- if (retval < 0) ret = retval;
- return *this;
- }
- android_log_event_context& operator <<(const char* value) {
- int retval = android_log_write_string8(ctx, value);
- if (retval < 0) ret = retval;
- return *this;
- }
-#if defined(_USING_LIBCXX)
- android_log_event_context& operator <<(const std::string& value) {
- int retval = android_log_write_string8_len(ctx,
- value.data(),
- value.length());
- if (retval < 0) ret = retval;
- return *this;
- }
-#endif
- android_log_event_context& operator <<(float value) {
- int retval = android_log_write_float32(ctx, value);
- if (retval < 0) ret = retval;
- return *this;
- }
-
- int write(log_id_t id = LOG_ID_EVENTS) {
- int retval = android_log_write_list(ctx, id);
- if (retval < 0) ret = retval;
- return ret;
- }
-
- int operator <<(log_id_t id) {
- int retval = android_log_write_list(ctx, id);
- if (retval < 0) ret = retval;
- android_log_destroy(&ctx);
- return ret;
- }
-
- /*
- * Append should be a lesser-used interface, but adds
- * access to string with length. So we offer all types.
- */
- template <typename Tvalue>
- bool Append(Tvalue value) { *this << value; return ret >= 0; }
-
- bool Append(const char* value, size_t len) {
- int retval = android_log_write_string8_len(ctx, value, len);
- if (retval < 0) ret = retval;
- return ret >= 0;
- }
-
- android_log_list_element read() { return android_log_read_next(ctx); }
- android_log_list_element peek() { return android_log_peek_next(ctx); }
-
-};
-}
-#endif
-#endif
-
-#endif /* __ANDROID_USE_LIBLOG_EVENT_INTERFACE */
-
-/* --------------------------------------------------------------------- */
-
#ifndef _ANDROID_USE_LIBLOG_SAFETYNET_INTERFACE
#ifndef __ANDROID_API__
#define __ANDROID_USE_LIBLOG_SAFETYNET_INTERFACE 1
diff --git a/include/log/log_event_list.h b/include/log/log_event_list.h
new file mode 100644
index 0000000..31d49b2
--- /dev/null
+++ b/include/log/log_event_list.h
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2005-2016 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.
+ */
+
+#ifndef _LIBS_LOG_EVENT_LIST_H
+#define _LIBS_LOG_EVENT_LIST_H
+
+#include <stdint.h>
+
+#if (defined(__cplusplus) && defined(_USING_LIBCXX))
+extern "C++" {
+#include <string>
+}
+#endif
+
+#include <log/log.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef __ANDROID_USE_LIBLOG_EVENT_INTERFACE
+#ifndef __ANDROID_API__
+#define __ANDROID_USE_LIBLOG_EVENT_INTERFACE 1
+#elif __ANDROID_API__ > 23 /* > Marshmallow */
+#define __ANDROID_USE_LIBLOG_EVENT_INTERFACE 1
+#else
+#define __ANDROID_USE_LIBLOG_EVENT_INTERFACE 0
+#endif
+#endif
+
+#if __ANDROID_USE_LIBLOG_EVENT_INTERFACE
+
+/* For manipulating lists of events. */
+
+#define ANDROID_MAX_LIST_NEST_DEPTH 8
+
+/*
+ * The opaque context used to manipulate lists of events.
+ */
+#ifndef __android_log_context_defined
+#define __android_log_context_defined
+typedef struct android_log_context_internal* android_log_context;
+#endif
+
+/*
+ * Elements returned when reading a list of events.
+ */
+#ifndef __android_log_list_element_defined
+#define __android_log_list_element_defined
+typedef struct {
+ AndroidEventLogType type;
+ uint16_t complete;
+ uint16_t len;
+ union {
+ int32_t int32;
+ int64_t int64;
+ char* string;
+ float float32;
+ } data;
+} android_log_list_element;
+#endif
+
+/*
+ * Creates a context associated with an event tag to write elements to
+ * the list of events.
+ */
+android_log_context create_android_logger(uint32_t tag);
+
+/* All lists must be braced by a begin and end call */
+/*
+ * NB: If the first level braces are missing when specifying multiple
+ * elements, we will manufacturer a list to embrace it for your API
+ * convenience. For a single element, it will remain solitary.
+ */
+int android_log_write_list_begin(android_log_context ctx);
+int android_log_write_list_end(android_log_context ctx);
+
+int android_log_write_int32(android_log_context ctx, int32_t value);
+int android_log_write_int64(android_log_context ctx, int64_t value);
+int android_log_write_string8(android_log_context ctx, const char* value);
+int android_log_write_string8_len(android_log_context ctx,
+ const char* value, size_t maxlen);
+int android_log_write_float32(android_log_context ctx, float value);
+
+/* Submit the composed list context to the specified logger id */
+/* NB: LOG_ID_EVENTS and LOG_ID_SECURITY only valid binary buffers */
+int android_log_write_list(android_log_context ctx, log_id_t id);
+
+/*
+ * Creates a context from a raw buffer representing a list of events to be read.
+ */
+android_log_context create_android_log_parser(const char* msg, size_t len);
+
+android_log_list_element android_log_read_next(android_log_context ctx);
+android_log_list_element android_log_peek_next(android_log_context ctx);
+
+/* Finished with reader or writer context */
+int android_log_destroy(android_log_context* ctx);
+
+#ifdef __cplusplus
+#ifndef __class_android_log_event_list_defined
+#define __class_android_log_event_list_defined
+/* android_log_list C++ helpers */
+extern "C++" {
+class android_log_event_list {
+friend class __android_log_event_list;
+
+private:
+ android_log_context ctx;
+ int ret;
+
+ android_log_event_list(const android_log_event_list&) = delete;
+ void operator =(const android_log_event_list&) = delete;
+
+public:
+ explicit android_log_event_list(int tag) : ret(0) {
+ ctx = create_android_logger(static_cast<uint32_t>(tag));
+ }
+ explicit android_log_event_list(log_msg& log_msg) : ret(0) {
+ ctx = create_android_log_parser(log_msg.msg() + sizeof(uint32_t),
+ log_msg.entry.len - sizeof(uint32_t));
+ }
+ ~android_log_event_list() { android_log_destroy(&ctx); }
+
+ int close() {
+ int retval = android_log_destroy(&ctx);
+ if (retval < 0) ret = retval;
+ return retval;
+ }
+
+ /* To allow above C calls to use this class as parameter */
+ operator android_log_context() const { return ctx; }
+
+ int status() const { return ret; }
+
+ int begin() {
+ int retval = android_log_write_list_begin(ctx);
+ if (retval < 0) ret = retval;
+ return ret;
+ }
+ int end() {
+ int retval = android_log_write_list_end(ctx);
+ if (retval < 0) ret = retval;
+ return ret;
+ }
+
+ android_log_event_list& operator <<(int32_t value) {
+ int retval = android_log_write_int32(ctx, value);
+ if (retval < 0) ret = retval;
+ return *this;
+ }
+
+ android_log_event_list& operator <<(uint32_t value) {
+ int retval = android_log_write_int32(ctx, static_cast<int32_t>(value));
+ if (retval < 0) ret = retval;
+ return *this;
+ }
+
+ android_log_event_list& operator <<(int64_t value) {
+ int retval = android_log_write_int64(ctx, value);
+ if (retval < 0) ret = retval;
+ return *this;
+ }
+
+ android_log_event_list& operator <<(uint64_t value) {
+ int retval = android_log_write_int64(ctx, static_cast<int64_t>(value));
+ if (retval < 0) ret = retval;
+ return *this;
+ }
+
+ android_log_event_list& operator <<(const char* value) {
+ int retval = android_log_write_string8(ctx, value);
+ if (retval < 0) ret = retval;
+ return *this;
+ }
+
+#if defined(_USING_LIBCXX)
+ android_log_event_list& operator <<(const std::string& value) {
+ int retval = android_log_write_string8_len(ctx,
+ value.data(),
+ value.length());
+ if (retval < 0) ret = retval;
+ return *this;
+ }
+#endif
+
+ android_log_event_list& operator <<(float value) {
+ int retval = android_log_write_float32(ctx, value);
+ if (retval < 0) ret = retval;
+ return *this;
+ }
+
+ int write(log_id_t id = LOG_ID_EVENTS) {
+ int retval = android_log_write_list(ctx, id);
+ if (retval < 0) ret = retval;
+ return ret;
+ }
+
+ int operator <<(log_id_t id) {
+ int retval = android_log_write_list(ctx, id);
+ if (retval < 0) ret = retval;
+ android_log_destroy(&ctx);
+ return ret;
+ }
+
+ /*
+ * Append<Type> methods removes any integer promotion
+ * confusion, and adds access to string with length.
+ * Append methods are also added for all types for
+ * convenience.
+ */
+
+ bool AppendInt(int32_t value) {
+ int retval = android_log_write_int32(ctx, value);
+ if (retval < 0) ret = retval;
+ return ret >= 0;
+ }
+
+ bool AppendLong(int64_t value) {
+ int retval = android_log_write_int64(ctx, value);
+ if (retval < 0) ret = retval;
+ return ret >= 0;
+ }
+
+ bool AppendString(const char* value) {
+ int retval = android_log_write_string8(ctx, value);
+ if (retval < 0) ret = retval;
+ return ret >= 0;
+ }
+
+ bool AppendString(const char* value, size_t len) {
+ int retval = android_log_write_string8_len(ctx, value, len);
+ if (retval < 0) ret = retval;
+ return ret >= 0;
+ }
+
+#if defined(_USING_LIBCXX)
+ bool AppendString(const std::string& value) {
+ int retval = android_log_write_string8_len(ctx,
+ value.data(),
+ value.length());
+ if (retval < 0) ret = retval;
+ return ret;
+ }
+
+ bool Append(const std::string& value) {
+ int retval = android_log_write_string8_len(ctx,
+ value.data(),
+ value.length());
+ if (retval < 0) ret = retval;
+ return ret;
+ }
+#endif
+
+ bool AppendFloat(float value) {
+ int retval = android_log_write_float32(ctx, value);
+ if (retval < 0) ret = retval;
+ return ret >= 0;
+ }
+
+ template <typename Tvalue>
+ bool Append(Tvalue value) { *this << value; return ret >= 0; }
+
+ bool Append(const char* value, size_t len) {
+ int retval = android_log_write_string8_len(ctx, value, len);
+ if (retval < 0) ret = retval;
+ return ret >= 0;
+ }
+
+ android_log_list_element read() { return android_log_read_next(ctx); }
+ android_log_list_element peek() { return android_log_peek_next(ctx); }
+
+};
+}
+#endif
+#endif
+
+#endif /* __ANDROID_USE_LIBLOG_EVENT_INTERFACE */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBS_LOG_EVENT_LIST_H */
diff --git a/include/private/android_logger.h b/include/private/android_logger.h
index f3c6cf7..9f81b1f 100644
--- a/include/private/android_logger.h
+++ b/include/private/android_logger.h
@@ -25,6 +25,13 @@
#include <stdint.h>
#include <sys/types.h>
+#if (defined(__cplusplus) && defined(_USING_LIBCXX))
+extern "C++" {
+#include <string>
+}
+#endif
+
+#include <log/log_event_list.h>
#include <log/log.h>
#define LOGGER_MAGIC 'l'
@@ -146,6 +153,40 @@
unsigned long __android_logger_get_buffer_size(log_id_t logId);
bool __android_logger_valid_buffer_size(unsigned long value);
+/* Retrieve the composed event buffer */
+int android_log_write_list_buffer(android_log_context ctx, const char** msg);
+
+#ifdef __cplusplus
+#ifdef __class_android_log_event_list_defined
+#ifndef __class_android_log_event_list_private_defined
+#define __class_android_log_event_list_private_defined
+/* android_log_context C++ helpers */
+extern "C++" {
+class __android_log_event_list : public android_log_event_list {
+ __android_log_event_list(const android_log_event_list&) = delete;
+ void operator =(const __android_log_event_list&) = delete;
+
+public:
+ explicit __android_log_event_list(int tag) : android_log_event_list(tag) { }
+ explicit __android_log_event_list(log_msg& log_msg) : android_log_event_list(log_msg) { }
+
+#if defined(_USING_LIBCXX)
+ operator std::string() {
+ if (ret) return std::string("");
+ const char* cp = NULL;
+ ssize_t len = android_log_write_list_buffer(ctx, &cp);
+ if (len < 0) ret = len;
+ if (!cp || (len <= 0)) return std::string("");
+ return std::string(cp, len);
+ }
+#endif
+
+};
+}
+#endif
+#endif
+#endif
+
#if defined(__cplusplus)
}
#endif
diff --git a/include/ziparchive/zip_archive.h b/include/ziparchive/zip_archive.h
index fc845a4..54946fc 100644
--- a/include/ziparchive/zip_archive.h
+++ b/include/ziparchive/zip_archive.h
@@ -195,7 +195,8 @@
* Uncompress and write an entry to an open file identified by |fd|.
* |entry->uncompressed_length| bytes will be written to the file at
* its current offset, and the file will be truncated at the end of
- * the uncompressed data.
+ * the uncompressed data (no truncation if |fd| references a block
+ * device).
*
* Returns 0 on success and negative values on failure.
*/
diff --git a/init/action.cpp b/init/action.cpp
index ed88f6d..0ea7e14 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -105,7 +105,10 @@
}
void Action::ExecuteOneCommand(std::size_t command) const {
- ExecuteCommand(commands_[command]);
+ // We need a copy here since some Command execution may result in
+ // changing commands_ vector by importing .rc files through parser
+ Command cmd = commands_[command];
+ ExecuteCommand(cmd);
}
void Action::ExecuteAllCommands() const {
@@ -118,14 +121,16 @@
Timer t;
int result = command.InvokeFunc();
- // TODO: this should probably be changed to "if (failed || took a long time)"...
- if (android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
+ double duration_ms = t.duration() * 1000;
+ // Any action longer than 50ms will be warned to user as slow operation
+ if (duration_ms > 50.0 ||
+ android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
std::string trigger_name = BuildTriggersString();
std::string cmd_str = command.BuildCommandString();
std::string source = command.BuildSourceString();
LOG(INFO) << "Command '" << cmd_str << "' action=" << trigger_name << source
- << " returned " << result << " took " << t.duration() << "s";
+ << " returned " << result << " took " << duration_ms << "ms.";
}
}
@@ -152,6 +157,11 @@
bool Action::InitTriggers(const std::vector<std::string>& args, std::string* err) {
const static std::string prop_str("property:");
for (std::size_t i = 0; i < args.size(); ++i) {
+ if (args[i].empty()) {
+ *err = "empty trigger is not valid";
+ return false;
+ }
+
if (i % 2) {
if (args[i] != "&&") {
*err = "&& is the only symbol allowed to concatenate actions";
@@ -181,7 +191,11 @@
bool Action::InitSingleTrigger(const std::string& trigger) {
std::vector<std::string> name_vector{trigger};
std::string err;
- return InitTriggers(name_vector, &err);
+ bool ret = InitTriggers(name_vector, &err);
+ if (!ret) {
+ LOG(ERROR) << "InitSingleTrigger failed due to: " << err;
+ }
+ return ret;
}
// This function checks that all property triggers are satisfied, that is
diff --git a/init/builtins.cpp b/init/builtins.cpp
index f37ccc2..6d58754 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -38,6 +38,9 @@
#include <linux/loop.h>
#include <linux/module.h>
+#include <thread>
+
+#include <selinux/android.h>
#include <selinux/selinux.h>
#include <selinux/label.h>
@@ -65,10 +68,9 @@
#include "util.h"
#define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW
-#define UNMOUNT_CHECK_MS 5000
#define UNMOUNT_CHECK_TIMES 10
-static const int kTerminateServiceDelayMicroSeconds = 50000;
+static constexpr std::chrono::nanoseconds kCommandRetryTimeout = 5s;
static int insmod(const char *filename, const char *options, int flags) {
int fd = open(filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
@@ -192,11 +194,9 @@
close(fd);
break;
} else if (errno == EBUSY) {
- /* Some processes using |entry->mnt_dir| are still alive. Wait for a
- * while then retry.
- */
- TEMP_FAILURE_RETRY(
- usleep(UNMOUNT_CHECK_MS * 1000 / UNMOUNT_CHECK_TIMES));
+ // Some processes using |entry->mnt_dir| are still alive. Wait for a
+ // while then retry.
+ std::this_thread::sleep_for(5000ms / UNMOUNT_CHECK_TIMES);
continue;
} else {
/* Cannot open the device. Give up. */
@@ -444,7 +444,7 @@
return -1;
} else {
if (wait)
- wait_for_file(source, COMMAND_RETRY_TIMEOUT);
+ wait_for_file(source, kCommandRetryTimeout);
if (mount(source, target, system, flags, options) < 0) {
return -1;
}
@@ -590,9 +590,9 @@
for (na = args.size() - 1; na > 1; --na) {
if (args[na] == "--early") {
- path_arg_end = na;
- queue_event = false;
- mount_mode = MOUNT_MODE_EARLY;
+ path_arg_end = na;
+ queue_event = false;
+ mount_mode = MOUNT_MODE_EARLY;
} else if (args[na] == "--late") {
path_arg_end = na;
import_rc = false;
@@ -703,6 +703,15 @@
callback_on_ro_remount = unmount_and_fsck;
} else if (cmd == ANDROID_RB_RESTART2) {
reboot_target = &command[len + 1];
+ // When rebooting to the bootloader notify the bootloader writing
+ // also the BCB.
+ if (strcmp(reboot_target, "bootloader") == 0) {
+ std::string err;
+ if (!write_reboot_bootloader(&err)) {
+ LOG(ERROR) << "reboot-bootloader: Error writing "
+ "bootloader_message: " << err;
+ }
+ }
}
} else if (command[len] != '\0') {
LOG(ERROR) << "powerctl: unrecognized reboot target '" << &command[len] << "'";
@@ -740,7 +749,7 @@
}
// Wait a bit before recounting the number or running services.
- usleep(kTerminateServiceDelayMicroSeconds);
+ std::this_thread::sleep_for(50ms);
}
LOG(VERBOSE) << "Terminating running services took " << t.duration() << " seconds";
}
@@ -896,21 +905,49 @@
static int do_restorecon(const std::vector<std::string>& args) {
int ret = 0;
- for (auto it = std::next(args.begin()); it != args.end(); ++it) {
- if (restorecon(it->c_str()) < 0)
- ret = -errno;
+ struct flag_type {const char* name; int value;};
+ static const flag_type flags[] = {
+ {"--recursive", SELINUX_ANDROID_RESTORECON_RECURSE},
+ {"--skip-ce", SELINUX_ANDROID_RESTORECON_SKIPCE},
+ {"--cross-filesystems", SELINUX_ANDROID_RESTORECON_CROSS_FILESYSTEMS},
+ {0, 0}
+ };
+
+ int flag = 0;
+
+ bool in_flags = true;
+ for (size_t i = 1; i < args.size(); ++i) {
+ if (android::base::StartsWith(args[i], "--")) {
+ if (!in_flags) {
+ LOG(ERROR) << "restorecon - flags must precede paths";
+ return -1;
+ }
+ bool found = false;
+ for (size_t j = 0; flags[j].name; ++j) {
+ if (args[i] == flags[j].name) {
+ flag |= flags[j].value;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ LOG(ERROR) << "restorecon - bad flag " << args[i];
+ return -1;
+ }
+ } else {
+ in_flags = false;
+ if (restorecon(args[i].c_str(), flag) < 0) {
+ ret = -errno;
+ }
+ }
}
return ret;
}
static int do_restorecon_recursive(const std::vector<std::string>& args) {
- int ret = 0;
-
- for (auto it = std::next(args.begin()); it != args.end(); ++it) {
- if (restorecon_recursive(it->c_str()) < 0)
- ret = -errno;
- }
- return ret;
+ std::vector<std::string> non_const_args(args);
+ non_const_args.insert(std::next(non_const_args.begin()), "--recursive");
+ return do_restorecon(non_const_args);
}
static int do_loglevel(const std::vector<std::string>& args) {
@@ -947,11 +984,11 @@
static int do_wait(const std::vector<std::string>& args) {
if (args.size() == 2) {
- return wait_for_file(args[1].c_str(), COMMAND_RETRY_TIMEOUT);
+ return wait_for_file(args[1].c_str(), kCommandRetryTimeout);
} else if (args.size() == 3) {
int timeout;
if (android::base::ParseInt(args[2], &timeout)) {
- return wait_for_file(args[1].c_str(), timeout);
+ return wait_for_file(args[1].c_str(), std::chrono::seconds(timeout));
}
}
return -1;
diff --git a/init/descriptors.cpp b/init/descriptors.cpp
index 10aae88..429a76e 100644
--- a/init/descriptors.cpp
+++ b/init/descriptors.cpp
@@ -23,7 +23,7 @@
#include <unistd.h>
#include <android-base/stringprintf.h>
-#include <cutils/files.h>
+#include <cutils/android_get_control_file.h>
#include <cutils/sockets.h>
#include "init.h"
diff --git a/init/devices.cpp b/init/devices.cpp
index 1a6912f..2db24b7 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -23,6 +23,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/sendfile.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
@@ -34,6 +35,7 @@
#include <linux/netlink.h>
#include <memory>
+#include <thread>
#include <selinux/selinux.h>
#include <selinux/label.h>
@@ -109,13 +111,18 @@
return -ENOMEM;
node->dp.name = strdup(name);
- if (!node->dp.name)
+ if (!node->dp.name) {
+ free(node);
return -ENOMEM;
+ }
if (attr) {
node->dp.attr = strdup(attr);
- if (!node->dp.attr)
+ if (!node->dp.attr) {
+ free(node->dp.name);
+ free(node);
return -ENOMEM;
+ }
}
node->dp.perm = perm;
@@ -183,7 +190,7 @@
if (access(path.c_str(), F_OK) == 0) {
LOG(VERBOSE) << "restorecon_recursive: " << path;
- restorecon_recursive(path.c_str());
+ restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE);
}
}
@@ -784,139 +791,87 @@
}
}
-static int load_firmware(int fw_fd, int loading_fd, int data_fd)
-{
- struct stat st;
- long len_to_copy;
- int ret = 0;
+static void load_firmware(uevent* uevent, const std::string& root,
+ int fw_fd, size_t fw_size,
+ int loading_fd, int data_fd) {
+ // Start transfer.
+ android::base::WriteFully(loading_fd, "1", 1);
- if(fstat(fw_fd, &st) < 0)
- return -1;
- len_to_copy = st.st_size;
-
- write(loading_fd, "1", 1); /* start transfer */
-
- while (len_to_copy > 0) {
- char buf[PAGE_SIZE];
- ssize_t nr;
-
- nr = read(fw_fd, buf, sizeof(buf));
- if(!nr)
- break;
- if(nr < 0) {
- ret = -1;
- break;
- }
- if (!android::base::WriteFully(data_fd, buf, nr)) {
- ret = -1;
- break;
- }
- len_to_copy -= nr;
+ // Copy the firmware.
+ int rc = sendfile(data_fd, fw_fd, nullptr, fw_size);
+ if (rc == -1) {
+ PLOG(ERROR) << "firmware: sendfile failed { '" << root << "', '" << uevent->firmware << "' }";
}
- if(!ret)
- write(loading_fd, "0", 1); /* successful end of transfer */
- else
- write(loading_fd, "-1", 2); /* abort transfer */
-
- return ret;
+ // Tell the firmware whether to abort or commit.
+ const char* response = (rc != -1) ? "0" : "-1";
+ android::base::WriteFully(loading_fd, response, strlen(response));
}
-static int is_booting(void)
-{
+static int is_booting() {
return access("/dev/.booting", F_OK) == 0;
}
-static void process_firmware_event(struct uevent *uevent)
-{
- char *root, *loading, *data;
- int l, loading_fd, data_fd, fw_fd;
- size_t i;
+static void process_firmware_event(uevent* uevent) {
int booting = is_booting();
LOG(INFO) << "firmware: loading '" << uevent->firmware << "' for '" << uevent->path << "'";
- l = asprintf(&root, SYSFS_PREFIX"%s/", uevent->path);
- if (l == -1)
+ std::string root = android::base::StringPrintf("/sys%s", uevent->path);
+ std::string loading = root + "/loading";
+ std::string data = root + "/data";
+
+ android::base::unique_fd loading_fd(open(loading.c_str(), O_WRONLY|O_CLOEXEC));
+ if (loading_fd == -1) {
+ PLOG(ERROR) << "couldn't open firmware loading fd for " << uevent->firmware;
return;
+ }
- l = asprintf(&loading, "%sloading", root);
- if (l == -1)
- goto root_free_out;
-
- l = asprintf(&data, "%sdata", root);
- if (l == -1)
- goto loading_free_out;
-
- loading_fd = open(loading, O_WRONLY|O_CLOEXEC);
- if(loading_fd < 0)
- goto data_free_out;
-
- data_fd = open(data, O_WRONLY|O_CLOEXEC);
- if(data_fd < 0)
- goto loading_close_out;
+ android::base::unique_fd data_fd(open(data.c_str(), O_WRONLY|O_CLOEXEC));
+ if (data_fd == -1) {
+ PLOG(ERROR) << "couldn't open firmware data fd for " << uevent->firmware;
+ return;
+ }
try_loading_again:
- for (i = 0; i < arraysize(firmware_dirs); i++) {
- char *file = NULL;
- l = asprintf(&file, "%s/%s", firmware_dirs[i], uevent->firmware);
- if (l == -1)
- goto data_free_out;
- fw_fd = open(file, O_RDONLY|O_CLOEXEC);
- free(file);
- if (fw_fd >= 0) {
- if (!load_firmware(fw_fd, loading_fd, data_fd)) {
- LOG(INFO) << "firmware: copy success { '" << root << "', '" << uevent->firmware << "' }";
- } else {
- LOG(ERROR) << "firmware: copy failure { '" << root << "', '" << uevent->firmware << "' }";
- }
- break;
+ for (size_t i = 0; i < arraysize(firmware_dirs); i++) {
+ std::string file = android::base::StringPrintf("%s/%s", firmware_dirs[i], uevent->firmware);
+ android::base::unique_fd fw_fd(open(file.c_str(), O_RDONLY|O_CLOEXEC));
+ struct stat sb;
+ if (fw_fd != -1 && fstat(fw_fd, &sb) != -1) {
+ load_firmware(uevent, root, fw_fd, sb.st_size, loading_fd, data_fd);
+ return;
}
}
- if (fw_fd < 0) {
- if (booting) {
- /* If we're not fully booted, we may be missing
- * filesystems needed for firmware, wait and retry.
- */
- usleep(100000);
- booting = is_booting();
- goto try_loading_again;
- }
- PLOG(ERROR) << "firmware: could not open '" << uevent->firmware << "'";
- write(loading_fd, "-1", 2);
- goto data_close_out;
- }
- close(fw_fd);
-data_close_out:
- close(data_fd);
-loading_close_out:
- close(loading_fd);
-data_free_out:
- free(data);
-loading_free_out:
- free(loading);
-root_free_out:
- free(root);
+ if (booting) {
+ // If we're not fully booted, we may be missing
+ // filesystems needed for firmware, wait and retry.
+ std::this_thread::sleep_for(100ms);
+ booting = is_booting();
+ goto try_loading_again;
+ }
+
+ LOG(ERROR) << "firmware: could not find firmware for " << uevent->firmware;
+
+ // Write "-1" as our response to the kernel's firmware request, since we have nothing for it.
+ write(loading_fd, "-1", 2);
}
-static void handle_firmware_event(struct uevent *uevent)
-{
- pid_t pid;
+static void handle_firmware_event(uevent* uevent) {
+ if (strcmp(uevent->subsystem, "firmware")) return;
+ if (strcmp(uevent->action, "add")) return;
- if(strcmp(uevent->subsystem, "firmware"))
- return;
-
- if(strcmp(uevent->action, "add"))
- return;
-
- /* we fork, to avoid making large memory allocations in init proper */
- pid = fork();
- if (!pid) {
+ // Loading the firmware in a child means we can do that in parallel...
+ // (We ignore SIGCHLD rather than wait for our children.)
+ pid_t pid = fork();
+ if (pid == 0) {
+ Timer t;
process_firmware_event(uevent);
+ LOG(INFO) << "loading " << uevent->path << " took " << t.duration() << "s";
_exit(EXIT_SUCCESS);
- } else if (pid < 0) {
- PLOG(ERROR) << "could not fork to process firmware event";
+ } else if (pid == -1) {
+ PLOG(ERROR) << "could not fork to process firmware event for " << uevent->firmware;
}
}
@@ -1091,7 +1046,6 @@
LOG(INFO) << "Coldboot took " << t.duration() << "s.";
}
-int get_device_fd()
-{
+int get_device_fd() {
return device_fd;
}
diff --git a/init/init.cpp b/init/init.cpp
index 7c37d28..734f129 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -18,6 +18,7 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <libgen.h>
#include <paths.h>
#include <signal.h>
@@ -67,6 +68,8 @@
#include "util.h"
#include "watchdogd.h"
+using android::base::StringPrintf;
+
struct selabel_handle *sehandle;
struct selabel_handle *sehandle_prop;
@@ -75,7 +78,7 @@
static char qemu[32];
std::string default_console = "/dev/console";
-static time_t process_needs_restart;
+static time_t process_needs_restart_at;
const char *ENV[32];
@@ -132,11 +135,10 @@
static void restart_processes()
{
- process_needs_restart = 0;
- ServiceManager::GetInstance().
- ForEachServiceWithFlags(SVC_RESTARTING, [] (Service* s) {
- s->RestartIfNeeded(process_needs_restart);
- });
+ process_needs_restart_at = 0;
+ ServiceManager::GetInstance().ForEachServiceWithFlags(SVC_RESTARTING, [](Service* s) {
+ s->RestartIfNeeded(&process_needs_restart_at);
+ });
}
void handle_control_message(const std::string& msg, const std::string& name) {
@@ -164,7 +166,7 @@
// Any longer than 1s is an unreasonable length of time to delay booting.
// If you're hitting this timeout, check that you didn't make your
// sepolicy regular expressions too expensive (http://b/19899875).
- if (wait_for_file(COLDBOOT_DONE, 1)) {
+ if (wait_for_file(COLDBOOT_DONE, 1s)) {
LOG(ERROR) << "Timed out waiting for " COLDBOOT_DONE;
}
@@ -268,15 +270,14 @@
if (for_emulator) {
// In the emulator, export any kernel option with the "ro.kernel." prefix.
- property_set(android::base::StringPrintf("ro.kernel.%s", key.c_str()).c_str(), value.c_str());
+ property_set(StringPrintf("ro.kernel.%s", key.c_str()).c_str(), value.c_str());
return;
}
if (key == "qemu") {
strlcpy(qemu, value.c_str(), sizeof(qemu));
} else if (android::base::StartsWith(key, "androidboot.")) {
- property_set(android::base::StringPrintf("ro.boot.%s", key.c_str() + 12).c_str(),
- value.c_str());
+ property_set(StringPrintf("ro.boot.%s", key.c_str() + 12).c_str(), value.c_str());
}
}
@@ -314,7 +315,7 @@
static void process_kernel_dt() {
static const char android_dir[] = "/proc/device-tree/firmware/android";
- std::string file_name = android::base::StringPrintf("%s/compatible", android_dir);
+ std::string file_name = StringPrintf("%s/compatible", android_dir);
std::string dt_file;
android::base::ReadFileToString(file_name, &dt_file);
@@ -332,12 +333,12 @@
continue;
}
- file_name = android::base::StringPrintf("%s/%s", android_dir, dp->d_name);
+ file_name = StringPrintf("%s/%s", android_dir, dp->d_name);
android::base::ReadFileToString(file_name, &dt_file);
std::replace(dt_file.begin(), dt_file.end(), ',', '.');
- std::string property_name = android::base::StringPrintf("ro.boot.%s", dp->d_name);
+ std::string property_name = StringPrintf("ro.boot.%s", dp->d_name);
property_set(property_name.c_str(), dt_file.c_str());
}
}
@@ -566,12 +567,14 @@
return watchdogd_main(argc, argv);
}
+ boot_clock::time_point start_time = boot_clock::now();
+
// Clear the umask.
umask(0);
add_environment("PATH", _PATH_DEFPATH);
- bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0);
+ bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
// Don't expose the raw commandline to unprivileged processes.
chmod("/proc/cmdline", 0440);
@@ -590,38 +593,42 @@
mount("sysfs", "/sys", "sysfs", 0, NULL);
mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
+ mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
+ mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));
}
// Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
// talk to the outside world...
InitKernelLogging(argv);
- if (is_first_stage) {
- LOG(INFO) << "init first stage started!";
+ LOG(INFO) << "init " << (is_first_stage ? "first" : "second") << " stage started!";
+ if (is_first_stage) {
// Mount devices defined in android.early.* kernel commandline
early_mount();
- // Set up SELinux, including loading the SELinux policy if we're in the kernel domain.
+ // Set up SELinux, loading the SELinux policy.
selinux_initialize(true);
- // If we're in the kernel domain, re-exec init to transition to the init domain now
+ // We're in the kernel domain, so re-exec init to transition to the init domain now
// that the SELinux policy has been loaded.
-
if (restorecon("/init") == -1) {
PLOG(ERROR) << "restorecon failed";
security_failure();
}
+
+ setenv("INIT_SECOND_STAGE", "true", 1);
+
+ uint64_t start_ns = start_time.time_since_epoch().count();
+ setenv("INIT_STARTED_AT", StringPrintf("%" PRIu64, start_ns).c_str(), 1);
+
char* path = argv[0];
- char* args[] = { path, const_cast<char*>("--second-stage"), nullptr };
+ char* args[] = { path, nullptr };
if (execv(path, args) == -1) {
PLOG(ERROR) << "execv(\"" << path << "\") failed";
security_failure();
}
-
} else {
- LOG(INFO) << "init second stage started!";
-
// Indicate that booting is in progress to background fw loaders, etc.
close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
@@ -636,7 +643,10 @@
// used by init as well as the current required properties.
export_kernel_boot_props();
- // Now set up SELinux for second stage
+ // Make the time that init started available for bootstat to log.
+ property_set("init.start", getenv("INIT_STARTED_AT"));
+
+ // Now set up SELinux for second stage.
selinux_initialize(false);
}
@@ -647,10 +657,12 @@
restorecon("/dev");
restorecon("/dev/kmsg");
restorecon("/dev/socket");
+ restorecon("/dev/random");
+ restorecon("/dev/urandom");
restorecon("/dev/__properties__");
restorecon("/property_contexts");
- restorecon_recursive("/sys");
- restorecon_recursive("/dev/block");
+ restorecon("/sys", SELINUX_ANDROID_RESTORECON_RECURSE);
+ restorecon("/dev/block", SELINUX_ANDROID_RESTORECON_RECURSE);
restorecon("/dev/device-mapper");
epoll_fd = epoll_create1(EPOLL_CLOEXEC);
@@ -710,21 +722,22 @@
restart_processes();
}
- int timeout = -1;
- if (process_needs_restart) {
- timeout = (process_needs_restart - gettime()) * 1000;
- if (timeout < 0)
- timeout = 0;
+ // By default, sleep until something happens.
+ int epoll_timeout_ms = -1;
+
+ // If there's more work to do, wake up again immediately.
+ if (am.HasMoreCommands()) epoll_timeout_ms = 0;
+
+ // If there's a process that needs restarting, wake up in time for that.
+ if (process_needs_restart_at != 0) {
+ epoll_timeout_ms = (process_needs_restart_at - time(nullptr)) * 1000;
+ if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
}
- if (am.HasMoreCommands()) {
- timeout = 0;
- }
-
- bootchart_sample(&timeout);
+ bootchart_sample(&epoll_timeout_ms);
epoll_event ev;
- int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));
+ int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms));
if (nr == -1) {
PLOG(ERROR) << "epoll_wait failed";
} else if (nr == 1) {
diff --git a/init/init.h b/init/init.h
index 0019337..cfb3139 100644
--- a/init/init.h
+++ b/init/init.h
@@ -22,8 +22,6 @@
class Action;
class Service;
-#define COMMAND_RETRY_TIMEOUT 5
-
extern const char *ENV[32];
extern bool waiting_for_exec;
extern std::string default_console;
diff --git a/init/property_service.cpp b/init/property_service.cpp
index e7176c6..e198297 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -42,6 +42,7 @@
#include <netinet/in.h>
#include <sys/mman.h>
+#include <selinux/android.h>
#include <selinux/selinux.h>
#include <selinux/label.h>
@@ -175,7 +176,7 @@
if (valuelen >= PROP_VALUE_MAX) return -1;
if (strcmp("selinux.restorecon_recursive", name) == 0 && valuelen > 0) {
- if (restorecon_recursive(value) != 0) {
+ if (restorecon(value, SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
LOG(ERROR) << "Failed to restorecon_recursive " << value;
}
}
diff --git a/init/readme.txt b/init/readme.txt
index 500b1d8..7e9d21b 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -440,8 +440,16 @@
Init provides information about the services that it is responsible
for via the below properties.
+init.start
+ Time after boot in ns (via the CLOCK_BOOTTIME clock) at which the first
+ stage of init started.
+
init.svc.<name>
- State of a named service ("stopped", "stopping", "running", "restarting")
+ State of a named service ("stopped", "stopping", "running", "restarting")
+
+init.svc.<name>.start
+ Time after boot in ns (via the CLOCK_BOOTTIME clock) that the service was
+ most recently started.
Bootcharting
@@ -537,10 +545,10 @@
For quicker turnaround when working on init itself, use:
- mm -j
- m ramdisk-nodeps
- m bootimage-nodeps
- adb reboot bootloader
+ mm -j &&
+ m ramdisk-nodeps &&
+ m bootimage-nodeps &&
+ adb reboot bootloader &&
fastboot boot $ANDROID_PRODUCT_OUT/boot.img
Alternatively, use the emulator:
diff --git a/init/service.cpp b/init/service.cpp
index 9fa11b8..1f53a1b 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -17,6 +17,7 @@
#include "service.h"
#include <fcntl.h>
+#include <inttypes.h>
#include <linux/securebits.h>
#include <sched.h>
#include <sys/mount.h>
@@ -51,9 +52,6 @@
using android::base::StringPrintf;
using android::base::WriteStringToFile;
-#define CRITICAL_CRASH_THRESHOLD 4 // if we crash >4 times ...
-#define CRITICAL_CRASH_WINDOW (4*60) // ... in 4 minutes, goto recovery
-
static std::string ComputeContextFromExecutable(std::string& service_name,
const std::string& service_path) {
std::string computed_context;
@@ -154,8 +152,8 @@
Service::Service(const std::string& name, const std::string& classname,
const std::vector<std::string>& args)
- : name_(name), classname_(classname), flags_(0), pid_(0), time_started_(0),
- time_crashed_(0), nr_crashed_(0), uid_(0), gid_(0), namespace_flags_(0),
+ : name_(name), classname_(classname), flags_(0), pid_(0),
+ crash_count_(0), uid_(0), gid_(0), namespace_flags_(0),
seclabel_(""), ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0),
priority_(0), oom_score_adjust_(-1000), args_(args) {
onrestart_.InitSingleTrigger("onrestart");
@@ -168,7 +166,7 @@
const std::string& seclabel,
const std::vector<std::string>& args)
: name_(name), classname_(classname), flags_(flags), pid_(0),
- time_started_(0), time_crashed_(0), nr_crashed_(0), uid_(uid), gid_(gid),
+ crash_count_(0), uid_(uid), gid_(gid),
supp_gids_(supp_gids), capabilities_(capabilities),
namespace_flags_(namespace_flags), seclabel_(seclabel),
ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0), priority_(0),
@@ -190,6 +188,12 @@
}
property_set(prop_name.c_str(), new_state.c_str());
+
+ if (new_state == "running") {
+ prop_name += ".start";
+ uint64_t start_ns = time_started_.time_since_epoch().count();
+ property_set(prop_name.c_str(), StringPrintf("%" PRIu64, start_ns).c_str());
+ }
}
void Service::KillProcessGroup(int signal) {
@@ -274,20 +278,19 @@
return false;
}
- time_t now = gettime();
+ // If we crash > 4 times in 4 minutes, reboot into recovery.
+ boot_clock::time_point now = boot_clock::now();
if ((flags_ & SVC_CRITICAL) && !(flags_ & SVC_RESTART)) {
- if (time_crashed_ + CRITICAL_CRASH_WINDOW >= now) {
- if (++nr_crashed_ > CRITICAL_CRASH_THRESHOLD) {
- LOG(ERROR) << "critical process '" << name_ << "' exited "
- << CRITICAL_CRASH_THRESHOLD << " times in "
- << (CRITICAL_CRASH_WINDOW / 60) << " minutes; "
+ if (now < time_crashed_ + 4min) {
+ if (++crash_count_ > 4) {
+ LOG(ERROR) << "critical process '" << name_ << "' exited 4 times in 4 minutes; "
<< "rebooting into recovery mode";
android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
return false;
}
} else {
time_crashed_ = now;
- nr_crashed_ = 1;
+ crash_count_ = 1;
}
}
@@ -357,8 +360,8 @@
bool Service::ParsePriority(const std::vector<std::string>& args, std::string* err) {
priority_ = 0;
if (!ParseInt(args[1], &priority_,
- static_cast<int>(ANDROID_PRIORITY_LOWEST),
- static_cast<int>(ANDROID_PRIORITY_HIGHEST))) {
+ static_cast<int>(ANDROID_PRIORITY_HIGHEST), // highest is negative
+ static_cast<int>(ANDROID_PRIORITY_LOWEST))) {
*err = StringPrintf("process priority value must be range %d - %d",
ANDROID_PRIORITY_HIGHEST, ANDROID_PRIORITY_LOWEST);
return false;
@@ -553,7 +556,6 @@
// Starting a service removes it from the disabled or reset state and
// immediately takes it out of the restarting state if it was in there.
flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
- time_started_ = 0;
// Running processes require no additional work --- if they're in the
// process of exiting, we've ensured that they will immediately restart
@@ -667,7 +669,7 @@
}
}
- time_started_ = gettime();
+ time_started_ = boot_clock::now();
pid_ = pid;
flags_ |= SVC_RUNNING;
@@ -731,18 +733,19 @@
} /* else: Service is restarting anyways. */
}
-void Service::RestartIfNeeded(time_t& process_needs_restart) {
- time_t next_start_time = time_started_ + 5;
-
- if (next_start_time <= gettime()) {
+void Service::RestartIfNeeded(time_t* process_needs_restart_at) {
+ boot_clock::time_point now = boot_clock::now();
+ boot_clock::time_point next_start = time_started_ + 5s;
+ if (now > next_start) {
flags_ &= (~SVC_RESTARTING);
Start();
return;
}
- if ((next_start_time < process_needs_restart) ||
- (process_needs_restart == 0)) {
- process_needs_restart = next_start_time;
+ time_t next_start_time_t = time(nullptr) +
+ time_t(std::chrono::duration_cast<std::chrono::seconds>(next_start - now).count());
+ if (next_start_time_t < *process_needs_restart_at || *process_needs_restart_at == 0) {
+ *process_needs_restart_at = next_start_time_t;
}
}
diff --git a/init/service.h b/init/service.h
index d9e8f57..013e65f 100644
--- a/init/service.h
+++ b/init/service.h
@@ -30,6 +30,7 @@
#include "descriptors.h"
#include "init_parser.h"
#include "keyword_map.h"
+#include "util.h"
#define SVC_DISABLED 0x001 // do not autostart with class
#define SVC_ONESHOT 0x002 // do not restart on exit
@@ -75,7 +76,7 @@
void Stop();
void Terminate();
void Restart();
- void RestartIfNeeded(time_t& process_needs_restart);
+ void RestartIfNeeded(time_t* process_needs_restart_at);
bool Reap();
void DumpState() const;
@@ -134,9 +135,9 @@
unsigned flags_;
pid_t pid_;
- time_t time_started_; // time of last start
- time_t time_crashed_; // first crash within inspection window
- int nr_crashed_; // number of times crashed within window
+ boot_clock::time_point time_started_; // time of last start
+ boot_clock::time_point time_crashed_; // first crash within inspection window
+ int crash_count_; // number of times crashed within window
uid_t uid_;
gid_t gid_;
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index e7794ec..361b925 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -95,7 +95,6 @@
int prefix = 0;
int wildcard = 0;
char *endptr;
- char *tmp = 0;
if (nargs == 0)
return;
@@ -129,14 +128,12 @@
perm = strtol(args[1], &endptr, 8);
if (!endptr || *endptr != '\0') {
LOG(ERROR) << "invalid mode '" << args[1] << "'";
- free(tmp);
return;
}
struct passwd* pwd = getpwnam(args[2]);
if (!pwd) {
LOG(ERROR) << "invalid uid '" << args[2] << "'";
- free(tmp);
return;
}
uid = pwd->pw_uid;
@@ -144,11 +141,17 @@
struct group* grp = getgrnam(args[3]);
if (!grp) {
LOG(ERROR) << "invalid gid '" << args[3] << "'";
- free(tmp);
return;
}
gid = grp->gr_gid;
- add_dev_perms(name, attr, perm, uid, gid, prefix, wildcard);
- free(tmp);
+ if (add_dev_perms(name, attr, perm, uid, gid, prefix, wildcard) != 0) {
+ PLOG(ERROR) << "add_dev_perms(name=" << name <<
+ ", attr=" << attr <<
+ ", perm=" << std::oct << perm << std::dec <<
+ ", uid=" << uid << ", gid=" << gid <<
+ ", prefix=" << prefix << ", wildcard=" << wildcard <<
+ ")";
+ return;
+ }
}
diff --git a/init/util.cpp b/init/util.cpp
index ab6837d..5205ea0 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -34,10 +34,13 @@
#include <sys/types.h>
#include <sys/un.h>
+#include <thread>
+
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
/* for ANDROID_SOCKET_* */
#include <cutils/sockets.h>
@@ -89,10 +92,6 @@
int create_socket(const char *name, int type, mode_t perm, uid_t uid,
gid_t gid, const char *socketcon)
{
- struct sockaddr_un addr;
- int fd, ret, savederrno;
- char *filecon;
-
if (socketcon) {
if (setsockcreatecon(socketcon) == -1) {
PLOG(ERROR) << "setsockcreatecon(\"" << socketcon << "\") failed";
@@ -100,52 +99,49 @@
}
}
- fd = socket(PF_UNIX, type, 0);
+ android::base::unique_fd fd(socket(PF_UNIX, type, 0));
if (fd < 0) {
PLOG(ERROR) << "Failed to open socket '" << name << "'";
return -1;
}
- if (socketcon)
- setsockcreatecon(NULL);
+ if (socketcon) setsockcreatecon(NULL);
+ struct sockaddr_un addr;
memset(&addr, 0 , sizeof(addr));
addr.sun_family = AF_UNIX;
snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",
name);
- ret = unlink(addr.sun_path);
- if (ret != 0 && errno != ENOENT) {
+ if ((unlink(addr.sun_path) != 0) && (errno != ENOENT)) {
PLOG(ERROR) << "Failed to unlink old socket '" << name << "'";
- goto out_close;
+ return -1;
}
- filecon = NULL;
+ char *filecon = NULL;
if (sehandle) {
- ret = selabel_lookup(sehandle, &filecon, addr.sun_path, S_IFSOCK);
- if (ret == 0)
+ if (selabel_lookup(sehandle, &filecon, addr.sun_path, S_IFSOCK) == 0) {
setfscreatecon(filecon);
+ }
}
- ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
- savederrno = errno;
+ int ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
+ int savederrno = errno;
setfscreatecon(NULL);
freecon(filecon);
if (ret) {
- errno = savederrno;
+ errno = savederrno;
PLOG(ERROR) << "Failed to bind socket '" << name << "'";
goto out_unlink;
}
- ret = lchown(addr.sun_path, uid, gid);
- if (ret) {
+ if (lchown(addr.sun_path, uid, gid)) {
PLOG(ERROR) << "Failed to lchown socket '" << addr.sun_path << "'";
goto out_unlink;
}
- ret = fchmodat(AT_FDCWD, addr.sun_path, perm, AT_SYMLINK_NOFOLLOW);
- if (ret) {
+ if (fchmodat(AT_FDCWD, addr.sun_path, perm, AT_SYMLINK_NOFOLLOW)) {
PLOG(ERROR) << "Failed to fchmodat socket '" << addr.sun_path << "'";
goto out_unlink;
}
@@ -155,12 +151,10 @@
<< ", user " << uid
<< ", group " << gid;
- return fd;
+ return fd.release();
out_unlink:
unlink(addr.sun_path);
-out_close:
- close(fd);
return -1;
}
@@ -173,7 +167,6 @@
gid_t gid, const char *filecon)
{
char *secontext = NULL;
- int ret;
if (filecon) {
if (setsockcreatecon(filecon) == -1) {
@@ -181,18 +174,17 @@
return -1;
}
} else if (sehandle) {
- ret = selabel_lookup(sehandle, &secontext, path, perm);
- if (ret != -1) {
- ret = setfscreatecon(secontext);
- if (ret == -1) {
- freecon(secontext);
+ if (selabel_lookup(sehandle, &secontext, path, perm) != -1) {
+ if (setfscreatecon(secontext) == -1) {
+ freecon(secontext); // does not upset errno value
PLOG(ERROR) << "setfscreatecon(\"" << secontext << "\") failed";
return -1;
}
}
}
- int fd = TEMP_FAILURE_RETRY(open(path, flags | O_NDELAY, perm));
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path, flags | O_NDELAY, perm)));
+ int savederrno = errno;
if (filecon) {
setsockcreatecon(NULL);
@@ -202,23 +194,22 @@
freecon(secontext);
}
- if (fd == -1) {
+ if (fd < 0) {
+ errno = savederrno;
PLOG(ERROR) << "Failed to open/create file '" << path << "'";
- goto out_close;
+ return -1;
}
if (!(flags & O_NDELAY)) fcntl(fd, F_SETFD, flags);
- ret = lchown(path, uid, gid);
- if (ret) {
+ if (lchown(path, uid, gid)) {
PLOG(ERROR) << "Failed to lchown file '" << path << "'";
- goto out_close;
+ return -1;
}
if (perm != static_cast<mode_t>(-1)) {
- ret = fchmodat(AT_FDCWD, path, perm, AT_SYMLINK_NOFOLLOW);
- if (ret) {
+ if (fchmodat(AT_FDCWD, path, perm, AT_SYMLINK_NOFOLLOW)) {
PLOG(ERROR) << "Failed to fchmodat file '" << path << "'";
- goto out_close;
+ return -1;
}
}
@@ -227,11 +218,7 @@
<< ", user " << uid
<< ", group " << gid;
- return fd;
-
-out_close:
- if (fd >= 0) close(fd);
- return -1;
+ return fd.release();
}
bool read_file(const char* path, std::string* content) {
@@ -273,16 +260,11 @@
return result;
}
-time_t gettime() {
- timespec now;
- clock_gettime(CLOCK_MONOTONIC, &now);
- return now.tv_sec;
-}
-
-uint64_t gettime_ns() {
- timespec now;
- clock_gettime(CLOCK_MONOTONIC, &now);
- return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_nsec;
+boot_clock::time_point boot_clock::now() {
+ timespec ts;
+ clock_gettime(CLOCK_BOOTTIME, &ts);
+ return boot_clock::time_point(std::chrono::seconds(ts.tv_sec) +
+ std::chrono::nanoseconds(ts.tv_nsec));
}
int mkdir_recursive(const char *pathname, mode_t mode)
@@ -340,16 +322,15 @@
}
}
-int wait_for_file(const char *filename, int timeout)
-{
- struct stat info;
- uint64_t timeout_time_ns = gettime_ns() + timeout * UINT64_C(1000000000);
- int ret = -1;
+int wait_for_file(const char* filename, std::chrono::nanoseconds timeout) {
+ boot_clock::time_point timeout_time = boot_clock::now() + timeout;
+ while (boot_clock::now() < timeout_time) {
+ struct stat sb;
+ if (stat(filename, &sb) != -1) return 0;
- while (gettime_ns() < timeout_time_ns && ((ret = stat(filename, &info)) < 0))
- usleep(10000);
-
- return ret;
+ std::this_thread::sleep_for(10ms);
+ }
+ return -1;
}
void import_kernel_cmdline(bool in_qemu,
@@ -388,14 +369,9 @@
return rc;
}
-int restorecon(const char* pathname)
+int restorecon(const char* pathname, int flags)
{
- return selinux_android_restorecon(pathname, 0);
-}
-
-int restorecon_recursive(const char* pathname)
-{
- return selinux_android_restorecon(pathname, SELINUX_ANDROID_RESTORECON_RECURSE);
+ return selinux_android_restorecon(pathname, flags);
}
/*
diff --git a/init/util.h b/init/util.h
index 12ab173..d56da39 100644
--- a/init/util.h
+++ b/init/util.h
@@ -20,11 +20,14 @@
#include <sys/stat.h>
#include <sys/types.h>
+#include <chrono>
#include <string>
#include <functional>
#define COLDBOOT_DONE "/dev/.coldboot_done"
+using namespace std::chrono_literals;
+
int create_socket(const char *name, int type, mode_t perm,
uid_t uid, gid_t gid, const char *socketcon);
int create_file(const char *path, int mode, mode_t perm,
@@ -33,32 +36,39 @@
bool read_file(const char* path, std::string* content);
int write_file(const char* path, const char* content);
-time_t gettime();
-uint64_t gettime_ns();
+// A std::chrono clock based on CLOCK_BOOTTIME.
+class boot_clock {
+ public:
+ typedef std::chrono::nanoseconds duration;
+ typedef std::chrono::time_point<boot_clock, duration> time_point;
+ static constexpr bool is_steady = true;
+
+ static time_point now();
+};
class Timer {
public:
- Timer() : t0(gettime_ns()) {
+ Timer() : start_(boot_clock::now()) {
}
double duration() {
- return static_cast<double>(gettime_ns() - t0) / 1000000000.0;
+ typedef std::chrono::duration<double> double_duration;
+ return std::chrono::duration_cast<double_duration>(boot_clock::now() - start_).count();
}
private:
- uint64_t t0;
+ boot_clock::time_point start_;
};
unsigned int decode_uid(const char *s);
int mkdir_recursive(const char *pathname, mode_t mode);
void sanitize(char *p);
-int wait_for_file(const char *filename, int timeout);
+int wait_for_file(const char *filename, std::chrono::nanoseconds timeout);
void import_kernel_cmdline(bool in_qemu,
const std::function<void(const std::string&, const std::string&, bool)>&);
int make_dir(const char *path, mode_t mode);
-int restorecon(const char *pathname);
-int restorecon_recursive(const char *pathname);
+int restorecon(const char *pathname, int flags = 0);
std::string bytes_to_hex(const uint8_t *bytes, size_t bytes_len);
bool is_dir(const char* pathname);
bool expand_props(const std::string& src, std::string* dst);
diff --git a/init/util_test.cpp b/init/util_test.cpp
index 6ecbf90..e9f164d 100644
--- a/init/util_test.cpp
+++ b/init/util_test.cpp
@@ -16,6 +16,7 @@
#include "util.h"
+#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
@@ -23,7 +24,9 @@
#include <sys/types.h>
#include <unistd.h>
-#include <cutils/files.h>
+#include <android-base/stringprintf.h>
+#include <android-base/test_utils.h>
+#include <cutils/android_get_control_file.h>
#include <gtest/gtest.h>
#include <selinux/android.h>
@@ -55,45 +58,48 @@
TEST(util, create_file) {
if (!sehandle) sehandle = selinux_android_file_context_handle();
- static const char path[] = "/data/local/tmp/util.create_file.test";
- static const char key[] = ANDROID_FILE_ENV_PREFIX "_data_local_tmp_util_create_file_test";
- EXPECT_EQ(unsetenv(key), 0);
- unlink(path);
+ TemporaryFile tf;
+ close(tf.fd);
+ EXPECT_GE(unlink(tf.path), 0);
- int fd;
+ std::string key(ANDROID_FILE_ENV_PREFIX);
+ key += tf.path;
+
+ std::for_each(key.begin(), key.end(), [] (char& c) { c = isalnum(c) ? c : '_'; });
+
+ EXPECT_EQ(unsetenv(key.c_str()), 0);
+
uid_t uid = decode_uid("logd");
gid_t gid = decode_uid("system");
mode_t perms = S_IRWXU | S_IWGRP | S_IRGRP | S_IROTH;
static const char context[] = "u:object_r:misc_logd_file:s0";
- EXPECT_GE(fd = create_file(path, O_RDWR | O_CREAT, perms, uid, gid, context), 0);
- if (fd < 0) return;
+ EXPECT_GE(tf.fd = create_file(tf.path, O_RDWR | O_CREAT, perms, uid, gid, context), 0);
+ if (tf.fd < 0) return;
static const char hello[] = "hello world\n";
static const ssize_t len = strlen(hello);
- EXPECT_EQ(write(fd, hello, len), len);
- char buffer[sizeof(hello)];
+ EXPECT_EQ(write(tf.fd, hello, len), len);
+ char buffer[sizeof(hello) + 1];
memset(buffer, 0, sizeof(buffer));
- EXPECT_GE(lseek(fd, 0, SEEK_SET), 0);
- EXPECT_EQ(read(fd, buffer, sizeof(buffer)), len);
- EXPECT_EQ(strcmp(hello, buffer), 0);
- char val[32];
- snprintf(val, sizeof(val), "%d", fd);
- EXPECT_EQ(android_get_control_file(path), -1);
- setenv(key, val, true);
- EXPECT_EQ(android_get_control_file(path), fd);
- close(fd);
- EXPECT_EQ(android_get_control_file(path), -1);
- EXPECT_EQ(unsetenv(key), 0);
+ EXPECT_GE(lseek(tf.fd, 0, SEEK_SET), 0);
+ EXPECT_EQ(read(tf.fd, buffer, sizeof(buffer)), len);
+ EXPECT_EQ(std::string(hello), buffer);
+ EXPECT_EQ(android_get_control_file(tf.path), -1);
+ EXPECT_EQ(setenv(key.c_str(), android::base::StringPrintf("%d", tf.fd).c_str(), true), 0);
+ EXPECT_EQ(android_get_control_file(tf.path), tf.fd);
+ close(tf.fd);
+ EXPECT_EQ(android_get_control_file(tf.path), -1);
+ EXPECT_EQ(unsetenv(key.c_str()), 0);
struct stat st;
- EXPECT_EQ(stat(path, &st), 0);
+ EXPECT_EQ(stat(tf.path, &st), 0);
EXPECT_EQ(st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO), perms);
EXPECT_EQ(st.st_uid, uid);
EXPECT_EQ(st.st_gid, gid);
security_context_t con;
- EXPECT_GE(getfilecon(path, &con), 0);
+ EXPECT_GE(getfilecon(tf.path, &con), 0);
EXPECT_NE(con, static_cast<security_context_t>(NULL));
if (con) {
EXPECT_EQ(context, std::string(con));
}
freecon(con);
- EXPECT_EQ(unlink(path), 0);
+ EXPECT_EQ(unlink(tf.path), 0);
}
diff --git a/libappfuse/Android.bp b/libappfuse/Android.bp
index 8b46154..f729faf 100644
--- a/libappfuse/Android.bp
+++ b/libappfuse/Android.bp
@@ -15,12 +15,20 @@
name: "libappfuse",
defaults: ["libappfuse_defaults"],
export_include_dirs: ["include"],
- srcs: ["FuseBuffer.cc", "FuseBridgeLoop.cc"]
+ srcs: [
+ "FuseAppLoop.cc",
+ "FuseBuffer.cc",
+ "FuseBridgeLoop.cc",
+ ]
}
cc_test {
name: "libappfuse_test",
defaults: ["libappfuse_defaults"],
shared_libs: ["libappfuse"],
- srcs: ["tests/FuseBridgeLoopTest.cc", "tests/FuseBufferTest.cc"]
+ srcs: [
+ "tests/FuseAppLoopTest.cc",
+ "tests/FuseBridgeLoopTest.cc",
+ "tests/FuseBufferTest.cc",
+ ]
}
diff --git a/libappfuse/FuseAppLoop.cc b/libappfuse/FuseAppLoop.cc
new file mode 100644
index 0000000..a31880e
--- /dev/null
+++ b/libappfuse/FuseAppLoop.cc
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2016 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 specic language governing permissions and
+ * limitations under the License.
+ */
+
+#include "libappfuse/FuseAppLoop.h"
+
+#include <sys/stat.h>
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+
+namespace android {
+namespace fuse {
+
+namespace {
+
+void HandleLookUp(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+ // AppFuse does not support directory structure now.
+ // It can lookup only files under the mount point.
+ if (buffer->request.header.nodeid != FUSE_ROOT_ID) {
+ LOG(ERROR) << "Nodeid is not FUSE_ROOT_ID.";
+ buffer->response.Reset(0, -ENOENT, buffer->request.header.unique);
+ return;
+ }
+
+ // Ensure that the filename ends with 0.
+ const size_t filename_length =
+ buffer->request.header.len - sizeof(fuse_in_header);
+ if (buffer->request.lookup_name[filename_length - 1] != 0) {
+ LOG(ERROR) << "File name does not end with 0.";
+ buffer->response.Reset(0, -ENOENT, buffer->request.header.unique);
+ return;
+ }
+
+ const uint64_t inode =
+ static_cast<uint64_t>(atol(buffer->request.lookup_name));
+ if (inode == 0 || inode == LONG_MAX) {
+ LOG(ERROR) << "Invalid filename";
+ buffer->response.Reset(0, -ENOENT, buffer->request.header.unique);
+ return;
+ }
+
+ const int64_t size = callback->OnGetSize(inode);
+ if (size < 0) {
+ buffer->response.Reset(0, size, buffer->request.header.unique);
+ return;
+ }
+
+ buffer->response.Reset(sizeof(fuse_entry_out), 0,
+ buffer->request.header.unique);
+ buffer->response.entry_out.nodeid = inode;
+ buffer->response.entry_out.attr_valid = 10;
+ buffer->response.entry_out.entry_valid = 10;
+ buffer->response.entry_out.attr.ino = inode;
+ buffer->response.entry_out.attr.mode = S_IFREG | 0777;
+ buffer->response.entry_out.attr.size = size;
+}
+
+void HandleGetAttr(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+ const uint64_t nodeid = buffer->request.header.nodeid;
+ int64_t size;
+ uint32_t mode;
+ if (nodeid == FUSE_ROOT_ID) {
+ size = 0;
+ mode = S_IFDIR | 0777;
+ } else {
+ size = callback->OnGetSize(buffer->request.header.nodeid);
+ if (size < 0) {
+ buffer->response.Reset(0, size, buffer->request.header.unique);
+ return;
+ }
+ mode = S_IFREG | 0777;
+ }
+
+ buffer->response.Reset(sizeof(fuse_attr_out), 0,
+ buffer->request.header.unique);
+ buffer->response.attr_out.attr_valid = 10;
+ buffer->response.attr_out.attr.ino = nodeid;
+ buffer->response.attr_out.attr.mode = mode;
+ buffer->response.attr_out.attr.size = size;
+}
+
+void HandleOpen(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+ const int32_t file_handle = callback->OnOpen(buffer->request.header.nodeid);
+ if (file_handle < 0) {
+ buffer->response.Reset(0, file_handle, buffer->request.header.unique);
+ return;
+ }
+ buffer->response.Reset(sizeof(fuse_open_out), kFuseSuccess,
+ buffer->request.header.unique);
+ buffer->response.open_out.fh = file_handle;
+}
+
+void HandleFsync(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+ buffer->response.Reset(0, callback->OnFsync(buffer->request.header.nodeid),
+ buffer->request.header.unique);
+}
+
+void HandleRelease(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+ buffer->response.Reset(0, callback->OnRelease(buffer->request.header.nodeid),
+ buffer->request.header.unique);
+}
+
+void HandleRead(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+ const uint64_t unique = buffer->request.header.unique;
+ const uint64_t nodeid = buffer->request.header.nodeid;
+ const uint64_t offset = buffer->request.read_in.offset;
+ const uint32_t size = buffer->request.read_in.size;
+
+ if (size > kFuseMaxRead) {
+ buffer->response.Reset(0, -EINVAL, buffer->request.header.unique);
+ return;
+ }
+
+ const int32_t read_size = callback->OnRead(nodeid, offset, size,
+ buffer->response.read_data);
+ if (read_size < 0) {
+ buffer->response.Reset(0, read_size, buffer->request.header.unique);
+ return;
+ }
+
+ buffer->response.ResetHeader(read_size, kFuseSuccess, unique);
+}
+
+void HandleWrite(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+ const uint64_t unique = buffer->request.header.unique;
+ const uint64_t nodeid = buffer->request.header.nodeid;
+ const uint64_t offset = buffer->request.write_in.offset;
+ const uint32_t size = buffer->request.write_in.size;
+
+ if (size > kFuseMaxWrite) {
+ buffer->response.Reset(0, -EINVAL, buffer->request.header.unique);
+ return;
+ }
+
+ const int32_t write_size = callback->OnWrite(nodeid, offset, size,
+ buffer->request.write_data);
+ if (write_size < 0) {
+ buffer->response.Reset(0, write_size, buffer->request.header.unique);
+ return;
+ }
+
+ buffer->response.Reset(sizeof(fuse_write_out), kFuseSuccess, unique);
+ buffer->response.write_out.size = write_size;
+}
+
+} // namespace
+
+bool StartFuseAppLoop(int raw_fd, FuseAppLoopCallback* callback) {
+ base::unique_fd fd(raw_fd);
+ FuseBuffer buffer;
+
+ LOG(DEBUG) << "Start fuse loop.";
+ while (callback->IsActive()) {
+ if (!buffer.request.Read(fd)) {
+ return false;
+ }
+
+ const uint32_t opcode = buffer.request.header.opcode;
+ LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode;
+ switch (opcode) {
+ case FUSE_FORGET:
+ // Do not reply to FUSE_FORGET.
+ continue;
+
+ case FUSE_LOOKUP:
+ HandleLookUp(&buffer, callback);
+ break;
+
+ case FUSE_GETATTR:
+ HandleGetAttr(&buffer, callback);
+ break;
+
+ case FUSE_OPEN:
+ HandleOpen(&buffer, callback);
+ break;
+
+ case FUSE_READ:
+ HandleRead(&buffer, callback);
+ break;
+
+ case FUSE_WRITE:
+ HandleWrite(&buffer, callback);
+ break;
+
+ case FUSE_RELEASE:
+ HandleRelease(&buffer, callback);
+ break;
+
+ case FUSE_FSYNC:
+ HandleFsync(&buffer, callback);
+ break;
+
+ default:
+ buffer.HandleNotImpl();
+ break;
+ }
+
+ if (!buffer.response.Write(fd)) {
+ LOG(ERROR) << "Failed to write a response to the device.";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // namespace fuse
+} // namespace android
diff --git a/libappfuse/FuseBridgeLoop.cc b/libappfuse/FuseBridgeLoop.cc
index 332556d..2386bf8 100644
--- a/libappfuse/FuseBridgeLoop.cc
+++ b/libappfuse/FuseBridgeLoop.cc
@@ -20,19 +20,22 @@
#include <android-base/unique_fd.h>
namespace android {
+namespace fuse {
-bool FuseBridgeLoop::Start(
- int raw_dev_fd, int raw_proxy_fd, FuseBridgeLoop::Callback* callback) {
+bool StartFuseBridgeLoop(
+ int raw_dev_fd, int raw_proxy_fd, FuseBridgeLoopCallback* callback) {
base::unique_fd dev_fd(raw_dev_fd);
base::unique_fd proxy_fd(raw_proxy_fd);
+ FuseBuffer buffer;
+ size_t open_count = 0;
LOG(DEBUG) << "Start fuse loop.";
while (true) {
- if (!buffer_.request.Read(dev_fd)) {
+ if (!buffer.request.Read(dev_fd)) {
return false;
}
- const uint32_t opcode = buffer_.request.header.opcode;
+ const uint32_t opcode = buffer.request.header.opcode;
LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode;
switch (opcode) {
case FUSE_FORGET:
@@ -45,35 +48,54 @@
case FUSE_READ:
case FUSE_WRITE:
case FUSE_RELEASE:
- case FUSE_FLUSH:
- if (!buffer_.request.Write(proxy_fd)) {
+ case FUSE_FSYNC:
+ if (!buffer.request.Write(proxy_fd)) {
LOG(ERROR) << "Failed to write a request to the proxy.";
return false;
}
- if (!buffer_.response.Read(proxy_fd)) {
+ if (!buffer.response.Read(proxy_fd)) {
LOG(ERROR) << "Failed to read a response from the proxy.";
return false;
}
break;
case FUSE_INIT:
- buffer_.HandleInit();
+ buffer.HandleInit();
break;
default:
- buffer_.HandleNotImpl();
+ buffer.HandleNotImpl();
break;
}
- if (!buffer_.response.Write(dev_fd)) {
+ if (!buffer.response.Write(dev_fd)) {
LOG(ERROR) << "Failed to write a response to the device.";
return false;
}
- if (opcode == FUSE_INIT) {
- callback->OnMount();
+ switch (opcode) {
+ case FUSE_INIT:
+ callback->OnMount();
+ break;
+ case FUSE_OPEN:
+ if (buffer.response.header.error == fuse::kFuseSuccess) {
+ open_count++;
+ }
+ break;
+ case FUSE_RELEASE:
+ if (open_count != 0) {
+ open_count--;
+ } else {
+ LOG(WARNING) << "Unexpected FUSE_RELEASE before opening a file.";
+ break;
+ }
+ if (open_count == 0) {
+ return true;
+ }
+ break;
}
}
}
+} // namespace fuse
} // namespace android
diff --git a/libappfuse/FuseBuffer.cc b/libappfuse/FuseBuffer.cc
index 45280a5..3ade31c 100644
--- a/libappfuse/FuseBuffer.cc
+++ b/libappfuse/FuseBuffer.cc
@@ -21,15 +21,22 @@
#include <unistd.h>
#include <algorithm>
+#include <type_traits>
#include <android-base/logging.h>
#include <android-base/macros.h>
namespace android {
+namespace fuse {
-template <typename T, typename Header>
-bool FuseMessage<T, Header>::CheckHeaderLength() const {
- if (sizeof(Header) <= header.len && header.len <= sizeof(T)) {
+static_assert(
+ std::is_standard_layout<FuseBuffer>::value,
+ "FuseBuffer must be standard layout union.");
+
+template <typename T>
+bool FuseMessage<T>::CheckHeaderLength() const {
+ const auto& header = static_cast<const T*>(this)->header;
+ if (sizeof(header) <= header.len && header.len <= sizeof(T)) {
return true;
} else {
LOG(ERROR) << "Packet size is invalid=" << header.len;
@@ -37,27 +44,29 @@
}
}
-template <typename T, typename Header>
-bool FuseMessage<T, Header>::CheckResult(
+template <typename T>
+bool FuseMessage<T>::CheckResult(
int result, const char* operation_name) const {
+ const auto& header = static_cast<const T*>(this)->header;
if (result >= 0 && static_cast<uint32_t>(result) == header.len) {
return true;
} else {
PLOG(ERROR) << "Failed to " << operation_name
- << " a packet from FD. result=" << result << " header.len="
+ << " a packet. result=" << result << " header.len="
<< header.len;
return false;
}
}
-template <typename T, typename Header>
-bool FuseMessage<T, Header>::Read(int fd) {
+template <typename T>
+bool FuseMessage<T>::Read(int fd) {
const ssize_t result = TEMP_FAILURE_RETRY(::read(fd, this, sizeof(T)));
return CheckHeaderLength() && CheckResult(result, "read");
}
-template <typename T, typename Header>
-bool FuseMessage<T, Header>::Write(int fd) const {
+template <typename T>
+bool FuseMessage<T>::Write(int fd) const {
+ const auto& header = static_cast<const T*>(this)->header;
if (!CheckHeaderLength()) {
return false;
}
@@ -65,8 +74,16 @@
return CheckResult(result, "write");
}
-template struct FuseMessage<FuseRequest, fuse_in_header>;
-template struct FuseMessage<FuseResponse, fuse_out_header>;
+template class FuseMessage<FuseRequest>;
+template class FuseMessage<FuseResponse>;
+
+void FuseRequest::Reset(
+ uint32_t data_length, uint32_t opcode, uint64_t unique) {
+ memset(this, 0, sizeof(fuse_in_header) + data_length);
+ header.len = sizeof(fuse_in_header) + data_length;
+ header.opcode = opcode;
+ header.unique = unique;
+}
void FuseResponse::ResetHeader(
uint32_t data_length, int32_t error, uint64_t unique) {
@@ -101,23 +118,18 @@
return;
}
- // We limit ourselves to 15 because we don't handle BATCH_FORGET yet
- size_t response_size = sizeof(fuse_init_out);
+ // We limit ourselves to minor=15 because we don't handle BATCH_FORGET yet.
+ // Thus we need to use FUSE_COMPAT_22_INIT_OUT_SIZE.
#if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
// FUSE_KERNEL_VERSION >= 23.
-
- // If the kernel only works on minor revs older than or equal to 22,
- // then use the older structure size since this code only uses the 7.22
- // version of the structure.
- if (minor <= 22) {
- response_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
- }
+ const size_t response_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
+#else
+ const size_t response_size = sizeof(fuse_init_out);
#endif
response.Reset(response_size, kFuseSuccess, unique);
fuse_init_out* const out = &response.init_out;
out->major = FUSE_KERNEL_VERSION;
- // We limit ourselves to 15 because we don't handle BATCH_FORGET yet.
out->minor = std::min(minor, 15u);
out->max_readahead = max_readahead;
out->flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
@@ -133,4 +145,5 @@
response.Reset(0, -ENOSYS, unique);
}
+} // namespace fuse
} // namespace android
diff --git a/libappfuse/include/libappfuse/FuseAppLoop.h b/libappfuse/include/libappfuse/FuseAppLoop.h
new file mode 100644
index 0000000..c3edfcc
--- /dev/null
+++ b/libappfuse/include/libappfuse/FuseAppLoop.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 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 specic language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_LIBAPPFUSE_FUSEAPPLOOP_H_
+#define ANDROID_LIBAPPFUSE_FUSEAPPLOOP_H_
+
+#include "libappfuse/FuseBuffer.h"
+
+namespace android {
+namespace fuse {
+
+class FuseAppLoopCallback {
+ public:
+ virtual bool IsActive() = 0;
+ virtual int64_t OnGetSize(uint64_t inode) = 0;
+ virtual int32_t OnFsync(uint64_t inode) = 0;
+ virtual int32_t OnWrite(
+ uint64_t inode, uint64_t offset, uint32_t size, const void* data) = 0;
+ virtual int32_t OnRead(
+ uint64_t inode, uint64_t offset, uint32_t size, void* data) = 0;
+ virtual int32_t OnOpen(uint64_t inode) = 0;
+ virtual int32_t OnRelease(uint64_t inode) = 0;
+ virtual ~FuseAppLoopCallback() = default;
+};
+
+bool StartFuseAppLoop(int fd, FuseAppLoopCallback* callback);
+
+} // namespace fuse
+} // namespace android
+
+#endif // ANDROID_LIBAPPFUSE_FUSEAPPLOOP_H_
diff --git a/libappfuse/include/libappfuse/FuseBridgeLoop.h b/libappfuse/include/libappfuse/FuseBridgeLoop.h
index 2006532..1f71cf2 100644
--- a/libappfuse/include/libappfuse/FuseBridgeLoop.h
+++ b/libappfuse/include/libappfuse/FuseBridgeLoop.h
@@ -20,21 +20,18 @@
#include "libappfuse/FuseBuffer.h"
namespace android {
+namespace fuse {
-class FuseBridgeLoop {
+class FuseBridgeLoopCallback {
public:
- class Callback {
- public:
- virtual void OnMount() = 0;
- virtual ~Callback() = default;
- };
-
- bool Start(int dev_fd, int proxy_fd, Callback* callback);
-
- private:
- FuseBuffer buffer_;
+ virtual void OnMount() = 0;
+ virtual ~FuseBridgeLoopCallback() = default;
};
+bool StartFuseBridgeLoop(
+ int dev_fd, int proxy_fd, FuseBridgeLoopCallback* callback);
+
+} // namespace fuse
} // namespace android
#endif // ANDROID_LIBAPPFUSE_FUSEBRIDGELOOP_H_
diff --git a/libappfuse/include/libappfuse/FuseBuffer.h b/libappfuse/include/libappfuse/FuseBuffer.h
index 071b777..e7f620c 100644
--- a/libappfuse/include/libappfuse/FuseBuffer.h
+++ b/libappfuse/include/libappfuse/FuseBuffer.h
@@ -20,6 +20,7 @@
#include <linux/fuse.h>
namespace android {
+namespace fuse {
// The numbers came from sdcard.c.
// Maximum number of bytes to write/read in one request/one reply.
@@ -27,9 +28,9 @@
constexpr size_t kFuseMaxRead = 128 * 1024;
constexpr int32_t kFuseSuccess = 0;
-template<typename T, typename Header>
-struct FuseMessage {
- Header header;
+template<typename T>
+class FuseMessage {
+ public:
bool Read(int fd);
bool Write(int fd) const;
private:
@@ -37,33 +38,53 @@
bool CheckResult(int result, const char* operation_name) const;
};
-struct FuseRequest : public FuseMessage<FuseRequest, fuse_in_header> {
+// FuseRequest represents file operation requests from /dev/fuse. It starts
+// from fuse_in_header. The body layout depends on the operation code.
+struct FuseRequest : public FuseMessage<FuseRequest> {
+ fuse_in_header header;
union {
+ // for FUSE_WRITE
struct {
fuse_write_in write_in;
char write_data[kFuseMaxWrite];
};
+ // for FUSE_OPEN
fuse_open_in open_in;
+ // for FUSE_INIT
fuse_init_in init_in;
+ // for FUSE_READ
fuse_read_in read_in;
+ // for FUSE_LOOKUP
char lookup_name[0];
};
+ void Reset(uint32_t data_length, uint32_t opcode, uint64_t unique);
};
-struct FuseResponse : public FuseMessage<FuseResponse, fuse_out_header> {
+// FuseResponse represents file operation responses to /dev/fuse. It starts
+// from fuse_out_header. The body layout depends on the operation code.
+struct FuseResponse : public FuseMessage<FuseResponse> {
+ fuse_out_header header;
union {
+ // for FUSE_INIT
fuse_init_out init_out;
+ // for FUSE_LOOKUP
fuse_entry_out entry_out;
+ // for FUSE_GETATTR
fuse_attr_out attr_out;
+ // for FUSE_OPEN
fuse_open_out open_out;
+ // for FUSE_READ
char read_data[kFuseMaxRead];
+ // for FUSE_WRITE
fuse_write_out write_out;
};
void Reset(uint32_t data_length, int32_t error, uint64_t unique);
void ResetHeader(uint32_t data_length, int32_t error, uint64_t unique);
};
-union FuseBuffer {
+// To reduce memory usage, FuseBuffer shares the memory region for request and
+// response.
+union FuseBuffer final {
FuseRequest request;
FuseResponse response;
@@ -71,19 +92,7 @@
void HandleNotImpl();
};
-class FuseProxyLoop {
- class IFuseProxyLoopCallback {
- public:
- virtual void OnMount() = 0;
- virtual ~IFuseProxyLoopCallback() = default;
- };
-
- bool Start(int dev_fd, int proxy_fd, IFuseProxyLoopCallback* callback);
-
- private:
- FuseBuffer buffer_;
-};
-
+} // namespace fuse
} // namespace android
#endif // ANDROID_LIBAPPFUSE_FUSEBUFFER_H_
diff --git a/libappfuse/tests/FuseAppLoopTest.cc b/libappfuse/tests/FuseAppLoopTest.cc
new file mode 100644
index 0000000..25906cf
--- /dev/null
+++ b/libappfuse/tests/FuseAppLoopTest.cc
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2016 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 specic language governing permissions and
+ * limitations under the License.
+ */
+
+#include "libappfuse/FuseAppLoop.h"
+
+#include <sys/socket.h>
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <gtest/gtest.h>
+#include <thread>
+
+namespace android {
+namespace fuse {
+namespace {
+
+constexpr unsigned int kTestFileSize = 1024;
+
+struct CallbackRequest {
+ uint32_t code;
+ uint64_t inode;
+};
+
+class Callback : public FuseAppLoopCallback {
+ public:
+ std::vector<CallbackRequest> requests;
+
+ bool IsActive() override {
+ return true;
+ }
+
+ int64_t OnGetSize(uint64_t inode) override {
+ if (inode == FUSE_ROOT_ID) {
+ return 0;
+ } else {
+ return kTestFileSize;
+ }
+ }
+
+ int32_t OnFsync(uint64_t inode) override {
+ requests.push_back({
+ .code = FUSE_FSYNC,
+ .inode = inode
+ });
+ return 0;
+ }
+
+ int32_t OnWrite(uint64_t inode,
+ uint64_t offset ATTRIBUTE_UNUSED,
+ uint32_t size ATTRIBUTE_UNUSED,
+ const void* data ATTRIBUTE_UNUSED) override {
+ requests.push_back({
+ .code = FUSE_WRITE,
+ .inode = inode
+ });
+ return 0;
+ }
+
+ int32_t OnRead(uint64_t inode,
+ uint64_t offset ATTRIBUTE_UNUSED,
+ uint32_t size ATTRIBUTE_UNUSED,
+ void* data ATTRIBUTE_UNUSED) override {
+ requests.push_back({
+ .code = FUSE_READ,
+ .inode = inode
+ });
+ return 0;
+ }
+
+ int32_t OnOpen(uint64_t inode) override {
+ requests.push_back({
+ .code = FUSE_OPEN,
+ .inode = inode
+ });
+ return 0;
+ }
+
+ int32_t OnRelease(uint64_t inode) override {
+ requests.push_back({
+ .code = FUSE_RELEASE,
+ .inode = inode
+ });
+ return 0;
+ }
+};
+
+class FuseAppLoopTest : public ::testing::Test {
+ private:
+ std::thread thread_;
+
+ protected:
+ base::unique_fd sockets_[2];
+ Callback callback_;
+ FuseRequest request_;
+ FuseResponse response_;
+
+ void SetUp() override {
+ base::SetMinimumLogSeverity(base::VERBOSE);
+ int sockets[2];
+ ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets));
+ sockets_[0].reset(sockets[0]);
+ sockets_[1].reset(sockets[1]);
+ thread_ = std::thread([this] {
+ StartFuseAppLoop(sockets_[1].release(), &callback_);
+ });
+ }
+
+ void CheckCallback(
+ size_t data_size, uint32_t code, size_t expected_out_size) {
+ request_.Reset(data_size, code, 1);
+ request_.header.nodeid = 10;
+
+ ASSERT_TRUE(request_.Write(sockets_[0]));
+ ASSERT_TRUE(response_.Read(sockets_[0]));
+
+ Close();
+
+ EXPECT_EQ(kFuseSuccess, response_.header.error);
+ EXPECT_EQ(sizeof(fuse_out_header) + expected_out_size,
+ response_.header.len);
+ EXPECT_EQ(1u, response_.header.unique);
+
+ ASSERT_EQ(1u, callback_.requests.size());
+ EXPECT_EQ(code, callback_.requests[0].code);
+ EXPECT_EQ(10u, callback_.requests[0].inode);
+ }
+
+ void Close() {
+ sockets_[0].reset();
+ sockets_[1].reset();
+ if (thread_.joinable()) {
+ thread_.join();
+ }
+ }
+
+ void TearDown() override {
+ Close();
+ }
+};
+
+} // namespace
+
+TEST_F(FuseAppLoopTest, LookUp) {
+ request_.Reset(3u, FUSE_LOOKUP, 1);
+ request_.header.nodeid = FUSE_ROOT_ID;
+ strcpy(request_.lookup_name, "10");
+
+ ASSERT_TRUE(request_.Write(sockets_[0].get()));
+ ASSERT_TRUE(response_.Read(sockets_[0].get()));
+
+ EXPECT_EQ(kFuseSuccess, response_.header.error);
+ EXPECT_EQ(sizeof(fuse_out_header) + sizeof(fuse_entry_out),
+ response_.header.len);
+ EXPECT_EQ(1u, response_.header.unique);
+
+ EXPECT_EQ(10u, response_.entry_out.nodeid);
+ EXPECT_EQ(0u, response_.entry_out.generation);
+ EXPECT_EQ(10u, response_.entry_out.entry_valid);
+ EXPECT_EQ(10u, response_.entry_out.attr_valid);
+ EXPECT_EQ(0u, response_.entry_out.entry_valid_nsec);
+ EXPECT_EQ(0u, response_.entry_out.attr_valid_nsec);
+
+ EXPECT_EQ(10u, response_.entry_out.attr.ino);
+ EXPECT_EQ(kTestFileSize, response_.entry_out.attr.size);
+ EXPECT_EQ(0u, response_.entry_out.attr.blocks);
+ EXPECT_EQ(0u, response_.entry_out.attr.atime);
+ EXPECT_EQ(0u, response_.entry_out.attr.mtime);
+ EXPECT_EQ(0u, response_.entry_out.attr.ctime);
+ EXPECT_EQ(0u, response_.entry_out.attr.atimensec);
+ EXPECT_EQ(0u, response_.entry_out.attr.mtimensec);
+ EXPECT_EQ(0u, response_.entry_out.attr.ctimensec);
+ EXPECT_EQ(S_IFREG | 0777u, response_.entry_out.attr.mode);
+ EXPECT_EQ(0u, response_.entry_out.attr.nlink);
+ EXPECT_EQ(0u, response_.entry_out.attr.uid);
+ EXPECT_EQ(0u, response_.entry_out.attr.gid);
+ EXPECT_EQ(0u, response_.entry_out.attr.rdev);
+ EXPECT_EQ(0u, response_.entry_out.attr.blksize);
+ EXPECT_EQ(0u, response_.entry_out.attr.padding);
+}
+
+TEST_F(FuseAppLoopTest, LookUp_InvalidName) {
+ request_.Reset(3u, FUSE_LOOKUP, 1);
+ request_.header.nodeid = FUSE_ROOT_ID;
+ strcpy(request_.lookup_name, "aa");
+
+ ASSERT_TRUE(request_.Write(sockets_[0].get()));
+ ASSERT_TRUE(response_.Read(sockets_[0].get()));
+
+ EXPECT_EQ(sizeof(fuse_out_header), response_.header.len);
+ EXPECT_EQ(-ENOENT, response_.header.error);
+ EXPECT_EQ(1u, response_.header.unique);
+}
+
+TEST_F(FuseAppLoopTest, LookUp_TooLargeName) {
+ request_.Reset(21u, FUSE_LOOKUP, 1);
+ request_.header.nodeid = FUSE_ROOT_ID;
+ strcpy(request_.lookup_name, "18446744073709551616");
+
+ ASSERT_TRUE(request_.Write(sockets_[0].get()));
+ ASSERT_TRUE(response_.Read(sockets_[0].get()));
+
+ EXPECT_EQ(sizeof(fuse_out_header), response_.header.len);
+ EXPECT_EQ(-ENOENT, response_.header.error);
+ EXPECT_EQ(1u, response_.header.unique);
+}
+
+TEST_F(FuseAppLoopTest, GetAttr) {
+ request_.Reset(sizeof(fuse_getattr_in), FUSE_GETATTR, 1);
+ request_.header.nodeid = 10;
+
+ ASSERT_TRUE(request_.Write(sockets_[0].get()));
+ ASSERT_TRUE(response_.Read(sockets_[0].get()));
+
+ EXPECT_EQ(kFuseSuccess, response_.header.error);
+ EXPECT_EQ(sizeof(fuse_out_header) + sizeof(fuse_attr_out),
+ response_.header.len);
+ EXPECT_EQ(1u, response_.header.unique);
+
+ EXPECT_EQ(10u, response_.attr_out.attr_valid);
+ EXPECT_EQ(0u, response_.attr_out.attr_valid_nsec);
+
+ EXPECT_EQ(10u, response_.attr_out.attr.ino);
+ EXPECT_EQ(kTestFileSize, response_.attr_out.attr.size);
+ EXPECT_EQ(0u, response_.attr_out.attr.blocks);
+ EXPECT_EQ(0u, response_.attr_out.attr.atime);
+ EXPECT_EQ(0u, response_.attr_out.attr.mtime);
+ EXPECT_EQ(0u, response_.attr_out.attr.ctime);
+ EXPECT_EQ(0u, response_.attr_out.attr.atimensec);
+ EXPECT_EQ(0u, response_.attr_out.attr.mtimensec);
+ EXPECT_EQ(0u, response_.attr_out.attr.ctimensec);
+ EXPECT_EQ(S_IFREG | 0777u, response_.attr_out.attr.mode);
+ EXPECT_EQ(0u, response_.attr_out.attr.nlink);
+ EXPECT_EQ(0u, response_.attr_out.attr.uid);
+ EXPECT_EQ(0u, response_.attr_out.attr.gid);
+ EXPECT_EQ(0u, response_.attr_out.attr.rdev);
+ EXPECT_EQ(0u, response_.attr_out.attr.blksize);
+ EXPECT_EQ(0u, response_.attr_out.attr.padding);
+}
+
+TEST_F(FuseAppLoopTest, GetAttr_Root) {
+ request_.Reset(sizeof(fuse_getattr_in), FUSE_GETATTR, 1);
+ request_.header.nodeid = FUSE_ROOT_ID;
+
+ ASSERT_TRUE(request_.Write(sockets_[0].get()));
+ ASSERT_TRUE(response_.Read(sockets_[0].get()));
+
+ EXPECT_EQ(kFuseSuccess, response_.header.error);
+ EXPECT_EQ(sizeof(fuse_out_header) + sizeof(fuse_attr_out),
+ response_.header.len);
+ EXPECT_EQ(1u, response_.header.unique);
+
+ EXPECT_EQ(10u, response_.attr_out.attr_valid);
+ EXPECT_EQ(0u, response_.attr_out.attr_valid_nsec);
+
+ EXPECT_EQ(static_cast<unsigned>(FUSE_ROOT_ID), response_.attr_out.attr.ino);
+ EXPECT_EQ(0u, response_.attr_out.attr.size);
+ EXPECT_EQ(0u, response_.attr_out.attr.blocks);
+ EXPECT_EQ(0u, response_.attr_out.attr.atime);
+ EXPECT_EQ(0u, response_.attr_out.attr.mtime);
+ EXPECT_EQ(0u, response_.attr_out.attr.ctime);
+ EXPECT_EQ(0u, response_.attr_out.attr.atimensec);
+ EXPECT_EQ(0u, response_.attr_out.attr.mtimensec);
+ EXPECT_EQ(0u, response_.attr_out.attr.ctimensec);
+ EXPECT_EQ(S_IFDIR | 0777u, response_.attr_out.attr.mode);
+ EXPECT_EQ(0u, response_.attr_out.attr.nlink);
+ EXPECT_EQ(0u, response_.attr_out.attr.uid);
+ EXPECT_EQ(0u, response_.attr_out.attr.gid);
+ EXPECT_EQ(0u, response_.attr_out.attr.rdev);
+ EXPECT_EQ(0u, response_.attr_out.attr.blksize);
+ EXPECT_EQ(0u, response_.attr_out.attr.padding);
+}
+
+TEST_F(FuseAppLoopTest, Open) {
+ CheckCallback(sizeof(fuse_open_in), FUSE_OPEN, sizeof(fuse_open_out));
+}
+
+TEST_F(FuseAppLoopTest, Fsync) {
+ CheckCallback(0u, FUSE_FSYNC, 0u);
+}
+
+TEST_F(FuseAppLoopTest, Release) {
+ CheckCallback(0u, FUSE_RELEASE, 0u);
+}
+
+TEST_F(FuseAppLoopTest, Read) {
+ CheckCallback(sizeof(fuse_read_in), FUSE_READ, 0u);
+}
+
+TEST_F(FuseAppLoopTest, Write) {
+ CheckCallback(sizeof(fuse_write_in), FUSE_WRITE, sizeof(fuse_write_out));
+}
+
+} // namespace fuse
+} // namespace android
diff --git a/libappfuse/tests/FuseBridgeLoopTest.cc b/libappfuse/tests/FuseBridgeLoopTest.cc
index 31e3690..e74d9e7 100644
--- a/libappfuse/tests/FuseBridgeLoopTest.cc
+++ b/libappfuse/tests/FuseBridgeLoopTest.cc
@@ -21,11 +21,15 @@
#include <sstream>
#include <thread>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
#include <gtest/gtest.h>
namespace android {
+namespace fuse {
+namespace {
-class Callback : public FuseBridgeLoop::Callback {
+class Callback : public FuseBridgeLoopCallback {
public:
bool mounted;
Callback() : mounted(false) {}
@@ -36,20 +40,28 @@
class FuseBridgeLoopTest : public ::testing::Test {
protected:
- int dev_sockets_[2];
- int proxy_sockets_[2];
+ base::unique_fd dev_sockets_[2];
+ base::unique_fd proxy_sockets_[2];
Callback callback_;
std::thread thread_;
FuseRequest request_;
FuseResponse response_;
- void SetUp() {
- ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, dev_sockets_));
- ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, proxy_sockets_));
+ void SetUp() override {
+ base::SetMinimumLogSeverity(base::VERBOSE);
+ int dev_sockets[2];
+ int proxy_sockets[2];
+ ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, dev_sockets));
+ ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, proxy_sockets));
+ dev_sockets_[0].reset(dev_sockets[0]);
+ dev_sockets_[1].reset(dev_sockets[1]);
+ proxy_sockets_[0].reset(proxy_sockets[0]);
+ proxy_sockets_[1].reset(proxy_sockets[1]);
+
thread_ = std::thread([this] {
- FuseBridgeLoop loop;
- loop.Start(dev_sockets_[1], proxy_sockets_[0], &callback_);
+ StartFuseBridgeLoop(
+ dev_sockets_[1].release(), proxy_sockets_[0].release(), &callback_);
});
}
@@ -103,20 +115,22 @@
}
void Close() {
- close(dev_sockets_[0]);
- close(dev_sockets_[1]);
- close(proxy_sockets_[0]);
- close(proxy_sockets_[1]);
+ dev_sockets_[0].reset();
+ dev_sockets_[1].reset();
+ proxy_sockets_[0].reset();
+ proxy_sockets_[1].reset();
if (thread_.joinable()) {
thread_.join();
}
}
- void TearDown() {
+ void TearDown() override {
Close();
}
};
+} // namespace
+
TEST_F(FuseBridgeLoopTest, FuseInit) {
SendInitRequest(1u);
@@ -156,11 +170,11 @@
CheckNotImpl(FUSE_RENAME);
CheckNotImpl(FUSE_LINK);
CheckNotImpl(FUSE_STATFS);
- CheckNotImpl(FUSE_FSYNC);
CheckNotImpl(FUSE_SETXATTR);
CheckNotImpl(FUSE_GETXATTR);
CheckNotImpl(FUSE_LISTXATTR);
CheckNotImpl(FUSE_REMOVEXATTR);
+ CheckNotImpl(FUSE_FLUSH);
CheckNotImpl(FUSE_OPENDIR);
CheckNotImpl(FUSE_READDIR);
CheckNotImpl(FUSE_RELEASEDIR);
@@ -186,11 +200,17 @@
TEST_F(FuseBridgeLoopTest, Proxy) {
CheckProxy(FUSE_LOOKUP);
CheckProxy(FUSE_GETATTR);
- CheckProxy(FUSE_OPEN);
CheckProxy(FUSE_READ);
CheckProxy(FUSE_WRITE);
+ CheckProxy(FUSE_FSYNC);
+
+ // Invoke FUSE_OPEN and FUSE_RELEASE at last as the loop will exit when all files are closed.
+ CheckProxy(FUSE_OPEN);
CheckProxy(FUSE_RELEASE);
- CheckProxy(FUSE_FLUSH);
+
+ // Ensure the loop exits.
+ Close();
}
-} // android
+} // namespace fuse
+} // namespace android
diff --git a/libappfuse/tests/FuseBufferTest.cc b/libappfuse/tests/FuseBufferTest.cc
index 1aacfe3..c822135 100644
--- a/libappfuse/tests/FuseBufferTest.cc
+++ b/libappfuse/tests/FuseBufferTest.cc
@@ -24,6 +24,7 @@
#include <gtest/gtest.h>
namespace android {
+namespace fuse {
constexpr char kTempFile[] = "/data/local/tmp/appfuse_test_dump";
@@ -163,7 +164,7 @@
buffer.HandleInit();
- ASSERT_EQ(sizeof(fuse_out_header) + sizeof(fuse_init_out),
+ ASSERT_EQ(sizeof(fuse_out_header) + FUSE_COMPAT_22_INIT_OUT_SIZE,
buffer.response.header.len);
EXPECT_EQ(kFuseSuccess, buffer.response.header.error);
EXPECT_EQ(static_cast<unsigned int>(FUSE_KERNEL_VERSION),
@@ -183,5 +184,6 @@
ASSERT_EQ(sizeof(fuse_out_header), buffer.response.header.len);
EXPECT_EQ(-ENOSYS, buffer.response.header.error);
}
-}
- // namespace android
+
+} // namespace fuse
+} // namespace android
diff --git a/libbacktrace/BacktracePtrace.cpp b/libbacktrace/BacktracePtrace.cpp
index 148c418..fd8b713 100644
--- a/libbacktrace/BacktracePtrace.cpp
+++ b/libbacktrace/BacktracePtrace.cpp
@@ -17,7 +17,6 @@
#include <errno.h>
#include <stdint.h>
#include <string.h>
-#include <sys/uio.h>
#include <sys/param.h>
#include <sys/ptrace.h>
#include <sys/types.h>
@@ -73,20 +72,42 @@
if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) {
return 0;
}
+
bytes = MIN(map.end - addr, bytes);
-
- struct iovec local_io;
- local_io.iov_base = buffer;
- local_io.iov_len = bytes;
-
- struct iovec remote_io;
- remote_io.iov_base = reinterpret_cast<void*>(addr);
- remote_io.iov_len = bytes;
-
- ssize_t bytes_read = process_vm_readv(Tid(), &local_io, 1, &remote_io, 1, 0);
- if (bytes_read == -1) {
- return 0;
+ size_t bytes_read = 0;
+ word_t data_word;
+ size_t align_bytes = addr & (sizeof(word_t) - 1);
+ if (align_bytes != 0) {
+ if (!PtraceRead(Tid(), addr & ~(sizeof(word_t) - 1), &data_word)) {
+ return 0;
+ }
+ size_t copy_bytes = MIN(sizeof(word_t) - align_bytes, bytes);
+ memcpy(buffer, reinterpret_cast<uint8_t*>(&data_word) + align_bytes, copy_bytes);
+ addr += copy_bytes;
+ buffer += copy_bytes;
+ bytes -= copy_bytes;
+ bytes_read += copy_bytes;
}
- return static_cast<size_t>(bytes_read);
+
+ size_t num_words = bytes / sizeof(word_t);
+ for (size_t i = 0; i < num_words; i++) {
+ if (!PtraceRead(Tid(), addr, &data_word)) {
+ return bytes_read;
+ }
+ memcpy(buffer, &data_word, sizeof(word_t));
+ buffer += sizeof(word_t);
+ addr += sizeof(word_t);
+ bytes_read += sizeof(word_t);
+ }
+
+ size_t left_over = bytes & (sizeof(word_t) - 1);
+ if (left_over) {
+ if (!PtraceRead(Tid(), addr, &data_word)) {
+ return bytes_read;
+ }
+ memcpy(buffer, &data_word, left_over);
+ bytes_read += left_over;
+ }
+ return bytes_read;
#endif
}
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index f7b497d..39f8aba 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -18,6 +18,7 @@
// they correspond to features not used by our host development tools
// which are also hard or even impossible to port to native Win32
libcutils_nonwindows_sources = [
+ "android_get_control_file.cpp",
"fs.c",
"multiuser.c",
"socket_inaddr_any_server_unix.c",
@@ -34,7 +35,6 @@
host_supported: true,
srcs: [
"config_utils.c",
- "files.cpp",
"fs_config.c",
"canned_fs_config.c",
"hashmap.c",
diff --git a/include/cutils/files.h b/libcutils/android_get_control_env.h
similarity index 63%
copy from include/cutils/files.h
copy to libcutils/android_get_control_env.h
index 0210e30..638c831 100644
--- a/include/cutils/files.h
+++ b/libcutils/android_get_control_env.h
@@ -14,24 +14,20 @@
* limitations under the License.
*/
-#ifndef __CUTILS_FILES_H
-#define __CUTILS_FILES_H
+#ifndef __CUTILS_ANDROID_GET_CONTROL_ENV_H
+#define __CUTILS_ANDROID_GET_CONTROL_ENV_H
-#define ANDROID_FILE_ENV_PREFIX "ANDROID_FILE_"
+/* To declare library function hidden and internal */
+#define LIBCUTILS_HIDDEN __attribute__((visibility("hidden")))
#ifdef __cplusplus
extern "C" {
#endif
-/*
- * android_get_control_file - simple helper function to get the file
- * descriptor of our init-managed file. `path' is the filename path as
- * given in init.rc. Returns -1 on error.
- */
-int android_get_control_file(const char* path);
-
+LIBCUTILS_HIDDEN int __android_get_control_from_env(const char* prefix,
+ const char* name);
#ifdef __cplusplus
}
#endif
-#endif /* __CUTILS_FILES_H */
+#endif /* __CUTILS_ANDROID_GET_CONTROL_ENV_H */
diff --git a/libcutils/files.cpp b/libcutils/android_get_control_file.cpp
similarity index 74%
rename from libcutils/files.cpp
rename to libcutils/android_get_control_file.cpp
index bf15b42..780d9f1 100644
--- a/libcutils/files.cpp
+++ b/libcutils/android_get_control_file.cpp
@@ -25,11 +25,6 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-
-// This file contains files implementation that can be shared between
-// platforms as long as the correct headers are included.
-#define _GNU_SOURCE 1 // for asprintf
-
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
@@ -41,17 +36,20 @@
#include <sys/types.h>
#include <unistd.h>
-#include <cutils/files.h>
+#include <cutils/android_get_control_file.h>
-#ifndef TEMP_FAILURE_RETRY // _WIN32 does not define
-#define TEMP_FAILURE_RETRY(exp) (exp)
+#include "android_get_control_env.h"
+
+#ifndef TEMP_FAILURE_RETRY
+#define TEMP_FAILURE_RETRY(exp) (exp) // KISS implementation
#endif
-int android_get_control_file(const char* path) {
- if (!path) return -1;
+LIBCUTILS_HIDDEN int __android_get_control_from_env(const char* prefix,
+ const char* name) {
+ if (!prefix || !name) return -1;
char *key = NULL;
- if (asprintf(&key, ANDROID_FILE_ENV_PREFIX "%s", path) < 0) return -1;
+ if (asprintf(&key, "%s%s", prefix, name) < 0) return -1;
if (!key) return -1;
char *cp = key;
@@ -70,29 +68,33 @@
// validity checking
if ((fd < 0) || (fd > INT_MAX)) return -1;
-#if defined(_SC_OPEN_MAX)
- if (fd >= sysconf(_SC_OPEN_MAX)) return -1;
-#elif defined(OPEN_MAX)
- if (fd >= OPEN_MAX) return -1;
-#elif defined(_POSIX_OPEN_MAX)
- if (fd >= _POSIX_OPEN_MAX) return -1;
-#endif
-#if defined(F_GETFD)
+ // Since we are inheriting an fd, it could legitimately exceed _SC_OPEN_MAX
+
+ // Still open?
+#if defined(F_GETFD) // Lowest overhead
if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD)) < 0) return -1;
-#elif defined(F_GETFL)
+#elif defined(F_GETFL) // Alternate lowest overhead
if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL)) < 0) return -1;
-#else
+#else // Hail Mary pass
struct stat s;
if (TEMP_FAILURE_RETRY(fstat(fd, &s)) < 0) return -1;
#endif
+ return static_cast<int>(fd);
+}
+
+int android_get_control_file(const char* path) {
+ int fd = __android_get_control_from_env(ANDROID_FILE_ENV_PREFIX, path);
+
#if defined(__linux__)
+ // Find file path from /proc and make sure it is correct
char *proc = NULL;
- if (asprintf(&proc, "/proc/self/fd/%ld", fd) < 0) return -1;
+ if (asprintf(&proc, "/proc/self/fd/%d", fd) < 0) return -1;
if (!proc) return -1;
size_t len = strlen(path);
+ // readlink() does not guarantee a nul byte, len+2 so we catch truncation.
char *buf = static_cast<char *>(calloc(1, len + 2));
if (!buf) {
free(proc);
@@ -104,8 +106,8 @@
free(buf);
if (ret < 0) return -1;
if (cmp != 0) return -1;
+ // It is what we think it is
#endif
- // It is what we think it is
- return static_cast<int>(fd);
+ return fd;
}
diff --git a/libcutils/klog.cpp b/libcutils/klog.cpp
index 9d823cf..4bad28a 100644
--- a/libcutils/klog.cpp
+++ b/libcutils/klog.cpp
@@ -24,7 +24,7 @@
#include <sys/types.h>
#include <unistd.h>
-#include <cutils/files.h>
+#include <cutils/android_get_control_file.h>
#include <cutils/klog.h>
static int klog_level = KLOG_DEFAULT_LEVEL;
diff --git a/libcutils/sockets.cpp b/libcutils/sockets.cpp
index 63761a2..23a447b 100644
--- a/libcutils/sockets.cpp
+++ b/libcutils/sockets.cpp
@@ -28,33 +28,9 @@
// This file contains socket implementation that can be shared between
// platforms as long as the correct headers are included.
-#define _GNU_SOURCE 1 // For asprintf
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#if !defined(_WIN32)
-#include <netinet/in.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#if !defined(_WIN32)
-#include <sys/un.h>
-#endif
-#include <unistd.h>
-
-#include <string>
#include <cutils/sockets.h>
-#ifndef TEMP_FAILURE_RETRY // _WIN32 does not define
-#define TEMP_FAILURE_RETRY(exp) (exp)
-#endif
-
int socket_get_local_port(cutils_socket_t sock) {
sockaddr_storage addr;
socklen_t addr_size = sizeof(addr);
@@ -65,58 +41,3 @@
}
return -1;
}
-
-int android_get_control_socket(const char* name) {
- char *key = NULL;
- if (asprintf(&key, ANDROID_SOCKET_ENV_PREFIX "%s", name) < 0) return -1;
- if (!key) return -1;
-
- char *cp = key;
- while (*cp) {
- if (!isalnum(*cp)) *cp = '_';
- ++cp;
- }
-
- const char* val = getenv(key);
- free(key);
- if (!val) return -1;
-
- errno = 0;
- long fd = strtol(val, NULL, 10);
- if (errno) return -1;
-
- // validity checking
- if ((fd < 0) || (fd > INT_MAX)) return -1;
-#if defined(_SC_OPEN_MAX)
- if (fd >= sysconf(_SC_OPEN_MAX)) return -1;
-#elif defined(OPEN_MAX)
- if (fd >= OPEN_MAX) return -1;
-#elif defined(_POSIX_OPEN_MAX)
- if (fd >= _POSIX_OPEN_MAX) return -1;
-#endif
-
-#if defined(F_GETFD)
- if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD)) < 0) return -1;
-#elif defined(F_GETFL)
- if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL)) < 0) return -1;
-#else
- struct stat s;
- if (TEMP_FAILURE_RETRY(fstat(fd, &s)) < 0) return -1;
-#endif
-
-#if !defined(_WIN32)
- struct sockaddr_un addr;
- socklen_t addrlen = sizeof(addr);
- int ret = TEMP_FAILURE_RETRY(getsockname(fd, (struct sockaddr *)&addr, &addrlen));
- if (ret < 0) return -1;
- char *path = NULL;
- if (asprintf(&path, ANDROID_SOCKET_DIR"/%s", name) < 0) return -1;
- if (!path) return -1;
- int cmp = strcmp(addr.sun_path, path);
- free(path);
- if (cmp != 0) return -1;
-#endif
-
- // It is what we think it is
- return static_cast<int>(fd);
-}
diff --git a/libcutils/sockets_unix.cpp b/libcutils/sockets_unix.cpp
index 3545403..5a14a5c 100644
--- a/libcutils/sockets_unix.cpp
+++ b/libcutils/sockets_unix.cpp
@@ -16,13 +16,25 @@
#define LOG_TAG "socket-unix"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
#include <sys/uio.h>
+#include <sys/un.h>
#include <time.h>
#include <unistd.h>
#include <android/log.h>
+#include <cutils/android_get_control_file.h>
#include <cutils/sockets.h>
+#include "android_get_control_env.h"
+
+#ifndef TEMP_FAILURE_RETRY
+#define TEMP_FAILURE_RETRY(exp) (exp) // KISS implementation
+#endif
+
#if defined(__ANDROID__)
/* For the socket trust (credentials) check */
#include <private/android_filesystem_config.h>
@@ -80,3 +92,24 @@
return writev(sock, iovec_buffers, num_buffers);
}
+
+int android_get_control_socket(const char* name) {
+ int fd = __android_get_control_from_env(ANDROID_SOCKET_ENV_PREFIX, name);
+
+ if (fd < 0) return fd;
+
+ // Compare to UNIX domain socket name, must match!
+ struct sockaddr_un addr;
+ socklen_t addrlen = sizeof(addr);
+ int ret = TEMP_FAILURE_RETRY(getsockname(fd, (struct sockaddr *)&addr, &addrlen));
+ if (ret < 0) return -1;
+ char *path = NULL;
+ if (asprintf(&path, ANDROID_SOCKET_DIR "/%s", name) < 0) return -1;
+ if (!path) return -1;
+ int cmp = strcmp(addr.sun_path, path);
+ free(path);
+ if (cmp != 0) return -1;
+
+ // It is what we think it is
+ return fd;
+}
diff --git a/libcutils/sockets_windows.cpp b/libcutils/sockets_windows.cpp
index ed6b1a7..3064c70 100644
--- a/libcutils/sockets_windows.cpp
+++ b/libcutils/sockets_windows.cpp
@@ -84,3 +84,7 @@
return -1;
}
+
+int android_get_control_socket(const char* name) {
+ return -1;
+}
diff --git a/libcutils/tests/Android.bp b/libcutils/tests/Android.bp
index bd35412..72e2eac 100644
--- a/libcutils/tests/Android.bp
+++ b/libcutils/tests/Android.bp
@@ -14,7 +14,7 @@
cc_defaults {
name: "libcutils_test_default",
- srcs: ["sockets_test.cpp", "files_test.cpp"],
+ srcs: ["sockets_test.cpp"],
target: {
android: {
@@ -28,7 +28,11 @@
},
not_windows: {
- srcs: ["test_str_parms.cpp"],
+ srcs: [
+ "test_str_parms.cpp",
+ "android_get_control_socket_test.cpp",
+ "android_get_control_file_test.cpp"
+ ],
},
},
diff --git a/libcutils/tests/android_get_control_file_test.cpp b/libcutils/tests/android_get_control_file_test.cpp
new file mode 100644
index 0000000..6c6fd2a
--- /dev/null
+++ b/libcutils/tests/android_get_control_file_test.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 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 <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include <string>
+
+#include <android-base/stringprintf.h>
+#include <android-base/test_utils.h>
+#include <cutils/android_get_control_file.h>
+#include <gtest/gtest.h>
+
+TEST(FilesTest, android_get_control_file) {
+ TemporaryFile tf;
+ ASSERT_GE(tf.fd, 0);
+
+ std::string key(ANDROID_FILE_ENV_PREFIX);
+ key += tf.path;
+
+ std::for_each(key.begin(), key.end(), [] (char& c) { c = isalnum(c) ? c : '_'; });
+
+ EXPECT_EQ(unsetenv(key.c_str()), 0);
+ EXPECT_EQ(android_get_control_file(tf.path), -1);
+
+ EXPECT_EQ(setenv(key.c_str(), android::base::StringPrintf("%d", tf.fd).c_str(), true), 0);
+
+ EXPECT_EQ(android_get_control_file(tf.path), tf.fd);
+ close(tf.fd);
+ EXPECT_EQ(android_get_control_file(tf.path), -1);
+ EXPECT_EQ(unsetenv(key.c_str()), 0);
+ EXPECT_EQ(android_get_control_file(tf.path), -1);
+}
diff --git a/libcutils/tests/android_get_control_socket_test.cpp b/libcutils/tests/android_get_control_socket_test.cpp
new file mode 100644
index 0000000..e586748
--- /dev/null
+++ b/libcutils/tests/android_get_control_socket_test.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2016 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 <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <time.h>
+
+#include <cutils/sockets.h>
+#include <gtest/gtest.h>
+
+#ifndef SOCK_NONBLOCK
+#define SOCK_NONBLOCK 0
+#endif
+
+#ifndef SOCK_CLOEXEC
+#define SOCK_CLOEXEC 0
+#endif
+
+TEST(SocketsTest, android_get_control_socket) {
+ static const char key[] = ANDROID_SOCKET_ENV_PREFIX "SocketsTest_android_get_control_socket";
+ static const char* name = key + strlen(ANDROID_SOCKET_ENV_PREFIX);
+
+ EXPECT_EQ(unsetenv(key), 0);
+ EXPECT_EQ(android_get_control_socket(name), -1);
+
+ int fd;
+ ASSERT_GE(fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0), 0);
+#ifdef F_GETFL
+ int flags;
+ ASSERT_GE(flags = fcntl(fd, F_GETFL), 0);
+ ASSERT_GE(fcntl(fd, F_SETFL, flags | O_NONBLOCK), 0);
+#endif
+ EXPECT_EQ(android_get_control_socket(name), -1);
+
+ struct sockaddr_un addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s", name);
+ unlink(addr.sun_path);
+
+ EXPECT_EQ(bind(fd, (struct sockaddr*)&addr, sizeof(addr)), 0);
+ EXPECT_EQ(android_get_control_socket(name), -1);
+
+ char val[32];
+ snprintf(val, sizeof(val), "%d", fd);
+ EXPECT_EQ(setenv(key, val, true), 0);
+
+ EXPECT_EQ(android_get_control_socket(name), fd);
+ socket_close(fd);
+ EXPECT_EQ(android_get_control_socket(name), -1);
+ EXPECT_EQ(unlink(addr.sun_path), 0);
+ EXPECT_EQ(android_get_control_socket(name), -1);
+ EXPECT_EQ(unsetenv(key), 0);
+ EXPECT_EQ(android_get_control_socket(name), -1);
+}
diff --git a/libcutils/tests/files_test.cpp b/libcutils/tests/files_test.cpp
deleted file mode 100644
index 1a7d673..0000000
--- a/libcutils/tests/files_test.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2016 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 <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <time.h>
-
-#include <cutils/files.h>
-#include <gtest/gtest.h>
-
-TEST(FilesTest, android_get_control_file) {
- static const char key[] = ANDROID_FILE_ENV_PREFIX "_dev_kmsg";
- static const char name[] = "/dev/kmsg";
-
- EXPECT_EQ(unsetenv(key), 0);
- EXPECT_EQ(android_get_control_file(name), -1);
-
- int fd;
- ASSERT_GE(fd = open(name, O_RDONLY | O_CLOEXEC), 0);
- EXPECT_EQ(android_get_control_file(name), -1);
-
- char val[32];
- snprintf(val, sizeof(val), "%d", fd);
- EXPECT_EQ(setenv(key, val, true), 0);
-
- EXPECT_EQ(android_get_control_file(name), fd);
- close(fd);
- EXPECT_EQ(android_get_control_file(name), -1);
- EXPECT_EQ(unsetenv(key), 0);
- EXPECT_EQ(android_get_control_file(name), -1);
-}
diff --git a/libcutils/tests/sockets_test.cpp b/libcutils/tests/sockets_test.cpp
index adfbf4a..0441fb6 100644
--- a/libcutils/tests/sockets_test.cpp
+++ b/libcutils/tests/sockets_test.cpp
@@ -18,11 +18,9 @@
// IPv6 capabilities. These tests assume that no UDP packets are lost, which
// should be the case for loopback communication, but is not guaranteed.
-#include <stdio.h>
-#include <stdlib.h>
+#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
-#include <sys/un.h>
#include <time.h>
#include <cutils/sockets.h>
@@ -189,49 +187,3 @@
TEST(SocketsTest, TestSocketSendBuffersFailure) {
EXPECT_EQ(-1, socket_send_buffers(INVALID_SOCKET, nullptr, 0));
}
-
-#ifndef SOCK_NONBLOCK
-#define SOCK_NONBLOCK 0
-#endif
-
-#ifndef SOCK_CLOEXEC
-#define SOCK_CLOEXEC 0
-#endif
-
-TEST(SocketsTest, android_get_control_socket) {
- static const char key[] = ANDROID_SOCKET_ENV_PREFIX "SocketsTest_android_get_control_socket";
- static const char* name = key + strlen(ANDROID_SOCKET_ENV_PREFIX);
-
- EXPECT_EQ(unsetenv(key), 0);
- EXPECT_EQ(android_get_control_socket(name), -1);
-
- int fd;
- ASSERT_GE(fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0), 0);
-#ifdef F_GETFL
- int flags;
- ASSERT_GE(flags = fcntl(fd, F_GETFL), 0);
- ASSERT_GE(fcntl(fd, F_SETFL, flags | O_NONBLOCK), 0);
-#endif
- EXPECT_EQ(android_get_control_socket(name), -1);
-
- struct sockaddr_un addr;
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s", name);
- unlink(addr.sun_path);
-
- EXPECT_EQ(bind(fd, (struct sockaddr*)&addr, sizeof(addr)), 0);
- EXPECT_EQ(android_get_control_socket(name), -1);
-
- char val[32];
- snprintf(val, sizeof(val), "%d", fd);
- EXPECT_EQ(setenv(key, val, true), 0);
-
- EXPECT_EQ(android_get_control_socket(name), fd);
- socket_close(fd);
- EXPECT_EQ(android_get_control_socket(name), -1);
- EXPECT_EQ(unlink(addr.sun_path), 0);
- EXPECT_EQ(android_get_control_socket(name), -1);
- EXPECT_EQ(unsetenv(key), 0);
- EXPECT_EQ(android_get_control_socket(name), -1);
-}
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 16aa4fa..c498153 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -73,6 +73,9 @@
linux: {
host_ldlibs: ["-lrt"],
},
+ linux_bionic: {
+ enabled: true,
+ },
},
cflags: [
diff --git a/liblog/event_tag_map.c b/liblog/event_tag_map.c
index f9cad99..e8e0335 100644
--- a/liblog/event_tag_map.c
+++ b/liblog/event_tag_map.c
@@ -73,12 +73,13 @@
EventTagMap* newTagMap;
off_t end;
int save_errno;
+ const char* tagfile = fileName ? fileName : EVENT_TAG_MAP_FILE;
- int fd = open(fileName, O_RDONLY | O_CLOEXEC);
+ int fd = open(tagfile, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
save_errno = errno;
fprintf(stderr, "%s: unable to open map '%s': %s\n",
- OUT_TAG, fileName, strerror(save_errno));
+ OUT_TAG, tagfile, strerror(save_errno));
goto fail_errno;
}
@@ -87,7 +88,7 @@
(void) lseek(fd, 0L, SEEK_SET);
if (end < 0) {
fprintf(stderr, "%s: unable to seek map '%s' %s\n",
- OUT_TAG, fileName, strerror(save_errno));
+ OUT_TAG, tagfile, strerror(save_errno));
goto fail_close;
}
@@ -103,7 +104,7 @@
fd = -1;
if ((newTagMap->mapAddr == MAP_FAILED) || (newTagMap->mapAddr == NULL)) {
fprintf(stderr, "%s: mmap(%s) failed: %s\n",
- OUT_TAG, fileName, strerror(save_errno));
+ OUT_TAG, tagfile, strerror(save_errno));
goto fail_free;
}
diff --git a/liblog/log_event_list.c b/liblog/log_event_list.c
index 11d8afb..9ac1d30 100644
--- a/liblog/log_event_list.c
+++ b/liblog/log_event_list.c
@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <string.h>
+#include <log/log_event_list.h>
#include <private/android_logger.h>
#include "log_portability.h"
@@ -319,7 +320,7 @@
context->storage[1] = context->count[0];
len = context->len = context->pos;
msg = (const char *)context->storage;
- /* it'snot a list */
+ /* it's not a list */
if (context->count[0] <= 1) {
len -= sizeof(uint8_t) + sizeof(uint8_t);
if (len < 0) {
@@ -332,6 +333,38 @@
__android_log_security_bwrite(context->tag, msg, len);
}
+LIBLOG_ABI_PRIVATE int android_log_write_list_buffer(android_log_context ctx,
+ const char **buffer) {
+ android_log_context_internal *context;
+ const char *msg;
+ ssize_t len;
+
+ context = (android_log_context_internal *)ctx;
+ if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+ return -EBADF;
+ }
+ if (context->list_nest_depth) {
+ return -EIO;
+ }
+ if (buffer == NULL) {
+ return -EFAULT;
+ }
+ /* NB: if there was overflow, then log is truncated. Nothing reported */
+ context->storage[1] = context->count[0];
+ len = context->len = context->pos;
+ msg = (const char *)context->storage;
+ /* it's not a list */
+ if (context->count[0] <= 1) {
+ len -= sizeof(uint8_t) + sizeof(uint8_t);
+ if (len < 0) {
+ len = 0;
+ }
+ msg += sizeof(uint8_t) + sizeof(uint8_t);
+ }
+ *buffer = msg;
+ return len;
+}
+
/*
* Extract a 4-byte value from a byte stream.
*/
diff --git a/liblog/log_event_write.c b/liblog/log_event_write.c
index 7262fc5..14d6482 100644
--- a/liblog/log_event_write.c
+++ b/liblog/log_event_write.c
@@ -18,6 +18,7 @@
#include <stdint.h>
#include <log/log.h>
+#include <log/log_event_list.h>
#include "log_portability.h"
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
index c481e36..f19c3ab 100644
--- a/liblog/logger_write.c
+++ b/liblog/logger_write.c
@@ -48,7 +48,7 @@
static int check_log_uid_permissions()
{
-#if defined(__BIONIC__)
+#if defined(__ANDROID__)
uid_t uid = __android_log_uid();
/* Matches clientHasLogCredentials() in logd */
@@ -130,7 +130,7 @@
return kLogNotAvailable;
}
-#if defined(__BIONIC__)
+#if defined(__ANDROID__)
static atomic_uintptr_t tagMap;
#endif
@@ -140,7 +140,7 @@
LIBLOG_ABI_PUBLIC void __android_log_close()
{
struct android_log_transport_write *transport;
-#if defined(__BIONIC__)
+#if defined(__ANDROID__)
EventTagMap *m;
#endif
@@ -170,7 +170,7 @@
}
}
-#if defined(__BIONIC__)
+#if defined(__ANDROID__)
/*
* Additional risk here somewhat mitigated by immediately unlock flushing
* the processor cache. The multi-threaded race that we choose to accept,
@@ -188,8 +188,8 @@
__android_log_unlock();
-#if defined(__BIONIC__)
- android_closeEventTagMap(m);
+#if defined(__ANDROID__)
+ if (m != (EventTagMap *)(uintptr_t)-1LL) android_closeEventTagMap(m);
#endif
}
@@ -261,7 +261,7 @@
return -EINVAL;
}
-#if defined(__BIONIC__)
+#if defined(__ANDROID__)
if (log_id == LOG_ID_SECURITY) {
if (vec[0].iov_len < 4) {
return -EINVAL;
@@ -293,7 +293,7 @@
ret = __android_log_trylock();
m = (EventTagMap *)atomic_load(&tagMap); /* trylock flush cache */
if (!m) {
- m = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+ m = android_openEventTagMap(NULL);
if (ret) { /* trylock failed, use local copy, mark for close */
f = m;
} else {
diff --git a/liblog/logprint.c b/liblog/logprint.c
index fb942a1..da80e36 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -632,8 +632,8 @@
size_t len;
int64_t lval;
- if (eventDataLen < 1)
- return -1;
+ if (eventDataLen < 1) return -1;
+
type = *eventData++;
eventDataLen--;
@@ -729,8 +729,7 @@
{
int32_t ival;
- if (eventDataLen < 4)
- return -1;
+ if (eventDataLen < 4) return -1;
ival = get4LE(eventData);
eventData += 4;
eventDataLen -= 4;
@@ -740,8 +739,7 @@
goto pr_lval;
case EVENT_TYPE_LONG:
/* 64-bit signed long */
- if (eventDataLen < 8)
- return -1;
+ if (eventDataLen < 8) return -1;
lval = get8LE(eventData);
eventData += 8;
eventDataLen -= 8;
@@ -761,8 +759,7 @@
uint32_t ival;
float fval;
- if (eventDataLen < 4)
- return -1;
+ if (eventDataLen < 4) return -1;
ival = get4LE(eventData);
fval = *(float*)&ival;
eventData += 4;
@@ -783,14 +780,12 @@
{
unsigned int strLen;
- if (eventDataLen < 4)
- return -1;
+ if (eventDataLen < 4) return -1;
strLen = get4LE(eventData);
eventData += 4;
eventDataLen -= 4;
- if (eventDataLen < strLen)
- return -1;
+ if (eventDataLen < strLen) return -1;
if (cp && (strLen == 0)) {
/* reset the format if no content */
@@ -818,41 +813,32 @@
unsigned char count;
int i;
- if (eventDataLen < 1)
- return -1;
+ if (eventDataLen < 1) return -1;
count = *eventData++;
eventDataLen--;
- if (outBufLen > 0) {
- *outBuf++ = '[';
- outBufLen--;
- } else {
- goto no_room;
- }
+ if (outBufLen <= 0) goto no_room;
+
+ *outBuf++ = '[';
+ outBufLen--;
for (i = 0; i < count; i++) {
result = android_log_printBinaryEvent(&eventData, &eventDataLen,
&outBuf, &outBufLen, fmtStr, fmtLen);
- if (result != 0)
- goto bail;
+ if (result != 0) goto bail;
- if (i < count-1) {
- if (outBufLen > 0) {
- *outBuf++ = ',';
- outBufLen--;
- } else {
- goto no_room;
- }
+ if (i < (count - 1)) {
+ if (outBufLen <= 0) goto no_room;
+ *outBuf++ = ',';
+ outBufLen--;
}
}
- if (outBufLen > 0) {
- *outBuf++ = ']';
- outBufLen--;
- } else {
- goto no_room;
- }
+ if (outBufLen <= 0) goto no_room;
+
+ *outBuf++ = ']';
+ outBufLen--;
}
break;
default:
@@ -997,8 +983,7 @@
}
}
inCount = buf->len;
- if (inCount < 4)
- return -1;
+ if (inCount < 4) return -1;
tagIndex = get4LE(eventData);
eventData += 4;
inCount -= 4;
@@ -1031,16 +1016,20 @@
/*
* Format the event log data into the buffer.
*/
- char* outBuf = messageBuf;
- size_t outRemaining = messageBufLen - 1; /* leave one for nul byte */
- int result;
const char* fmtStr = NULL;
size_t fmtLen = 0;
if (descriptive_output && map) {
fmtStr = android_lookupEventFormat_len(map, &fmtLen, tagIndex);
}
- result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
- &outRemaining, &fmtStr, &fmtLen);
+
+ char* outBuf = messageBuf;
+ size_t outRemaining = messageBufLen - 1; /* leave one for nul byte */
+ int result = 0;
+
+ if ((inCount > 0) || fmtLen) {
+ result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
+ &outRemaining, &fmtStr, &fmtLen);
+ }
if ((result == 1) && fmtStr) {
/* We overflowed :-(, let's repaint the line w/o format dressings */
eventData = (const unsigned char*)buf->msg;
@@ -1055,18 +1044,18 @@
}
if (result < 0) {
fprintf(stderr, "Binary log entry conversion failed\n");
- return -1;
- } else if (result == 1) {
- if (outBuf > messageBuf) {
- /* leave an indicator */
- *(outBuf-1) = '!';
- } else {
- /* no room to output anything at all */
- *outBuf++ = '!';
- outRemaining--;
+ }
+ if (result) {
+ if (!outRemaining) {
+ /* make space to leave an indicator */
+ --outBuf;
+ ++outRemaining;
}
- /* pretend we ate all the data */
+ *outBuf++ = (result < 0) ? '!' : '^'; /* Error or Truncation? */
+ outRemaining--;
+ /* pretend we ate all the data to prevent log stutter */
inCount = 0;
+ if (result > 0) result = 0;
}
/* eat the silly terminating '\n' */
@@ -1090,7 +1079,7 @@
entry->message = messageBuf;
- return 0;
+ return result;
}
/*
@@ -1802,8 +1791,7 @@
outBuffer = android_log_formatLogLine(p_format, defaultBuffer,
sizeof(defaultBuffer), entry, &totalLen);
- if (!outBuffer)
- return -1;
+ if (!outBuffer) return -1;
do {
ret = write(fd, outBuffer, totalLen);
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 9c09523..02a572d 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -33,6 +33,7 @@
#include <cutils/properties.h>
#include <gtest/gtest.h>
#include <log/logprint.h>
+#include <log/log_event_list.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
@@ -328,6 +329,9 @@
EXPECT_TRUE(NULL != logformat);
AndroidLogEntry entry;
char msgBuf[1024];
+ if (length != total) {
+ fprintf(stderr, "Expect \"Binary log entry conversion failed\"\n");
+ }
int processBinaryLogBuffer = android_log_processBinaryLogBuffer(
&log_msg.entry_v1, &entry, NULL, msgBuf, sizeof(msgBuf));
EXPECT_EQ((length == total) ? 0 : -1, processBinaryLogBuffer);
@@ -2647,6 +2651,19 @@
ASSERT_TRUE(NULL == ctx);
}
+TEST(liblog, android_log_write_list_buffer) {
+ __android_log_event_list ctx(1005);
+ ctx << 1005 << "tag_def" << "(tag|1),(name|3),(format|3)";
+ std::string buffer(ctx);
+ ctx.close();
+
+ char msgBuf[1024];
+ memset(msgBuf, 0, sizeof(msgBuf));
+ EXPECT_EQ(android_log_buffer_to_string(buffer.data(), buffer.length(),
+ msgBuf, sizeof(msgBuf)), 0);
+ EXPECT_STREQ(msgBuf, "[1005,tag_def,(tag|1),(name|3),(format|3)]");
+}
+
static const char __pmsg_file[] =
"/data/william-shakespeare/MuchAdoAboutNothing.txt";
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 7c15429..eb66727 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -31,12 +31,15 @@
#include <chrono>
#include <memory>
#include <mutex>
+#include <thread>
#include <android-base/logging.h>
#include <private/android_filesystem_config.h>
#include <processgroup/processgroup.h>
+using namespace std::chrono_literals;
+
// Uncomment line below use memory cgroups for keeping track of (forked) PIDs
// #define USE_MEMCG 1
@@ -288,7 +291,7 @@
while ((processes = killProcessGroupOnce(uid, initialPid, signal)) > 0) {
LOG(VERBOSE) << "killed " << processes << " processes for processgroup " << initialPid;
if (retry > 0) {
- usleep(5 * 1000); // 5ms
+ std::this_thread::sleep_for(5ms);
--retry;
} else {
LOG(ERROR) << "failed to kill " << processes << " processes for processgroup "
diff --git a/libprocinfo/.clang-format b/libprocinfo/.clang-format
new file mode 100644
index 0000000..b8c6428
--- /dev/null
+++ b/libprocinfo/.clang-format
@@ -0,0 +1,14 @@
+BasedOnStyle: Google
+AllowShortBlocksOnASingleLine: false
+AllowShortFunctionsOnASingleLine: false
+
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+IndentWidth: 2
+PointerAlignment: Left
+TabWidth: 2
+UseTab: Never
+PenaltyExcessCharacter: 32
+
+Cpp11BracedListStyle: false
diff --git a/libprocinfo/Android.bp b/libprocinfo/Android.bp
new file mode 100644
index 0000000..8e17f1b
--- /dev/null
+++ b/libprocinfo/Android.bp
@@ -0,0 +1,73 @@
+//
+// Copyright (C) 2015 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.
+//
+
+libprocinfo_cppflags = [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+]
+
+cc_library {
+ name: "libprocinfo",
+ host_supported: true,
+ srcs: [
+ "process.cpp",
+ ],
+ cppflags: libprocinfo_cppflags,
+
+ local_include_dirs: ["include"],
+ export_include_dirs: ["include"],
+ shared_libs: ["libbase"],
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ windows: {
+ enabled: false,
+ },
+ },
+}
+
+// Tests
+// ------------------------------------------------------------------------------
+cc_test {
+ name: "libprocinfo_test",
+ host_supported: true,
+ srcs: [
+ "process_test.cpp",
+ ],
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ windows: {
+ enabled: false,
+ },
+ },
+
+ cppflags: libprocinfo_cppflags,
+ shared_libs: ["libbase", "libprocinfo"],
+
+ compile_multilib: "both",
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
+}
diff --git a/libprocinfo/include/procinfo/process.h b/libprocinfo/include/procinfo/process.h
new file mode 100644
index 0000000..fb140ff
--- /dev/null
+++ b/libprocinfo/include/procinfo/process.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2016 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 <dirent.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+#include <string>
+#include <type_traits>
+
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/unique_fd.h>
+
+namespace android {
+namespace procinfo {
+
+#if defined(__linux__)
+
+struct ProcessInfo {
+ std::string name;
+ pid_t tid;
+ pid_t pid;
+ pid_t ppid;
+ pid_t tracer;
+ uid_t uid;
+ uid_t gid;
+};
+
+// Parse the contents of /proc/<tid>/status into |process_info|.
+bool GetProcessInfo(pid_t tid, ProcessInfo* process_info);
+
+// Parse the contents of <fd>/status into |process_info|.
+// |fd| should be an fd pointing at a /proc/<pid> directory.
+bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info);
+
+// Fetch the list of threads from a given process's /proc/<pid> directory.
+// |fd| should be an fd pointing at a /proc/<pid> directory.
+template <typename Collection>
+auto GetProcessTidsFromProcPidFd(int fd, Collection* out) ->
+ typename std::enable_if<sizeof(typename Collection::value_type) >= sizeof(pid_t), bool>::type {
+ out->clear();
+
+ int task_fd = openat(fd, "task", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
+ std::unique_ptr<DIR, int (*)(DIR*)> dir(fdopendir(task_fd), closedir);
+ if (!dir) {
+ PLOG(ERROR) << "failed to open task directory";
+ return false;
+ }
+
+ struct dirent* dent;
+ while ((dent = readdir(dir.get()))) {
+ if (strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0) {
+ pid_t tid;
+ if (!android::base::ParseInt(dent->d_name, &tid, 1, std::numeric_limits<pid_t>::max())) {
+ LOG(ERROR) << "failed to parse task id: " << dent->d_name;
+ return false;
+ }
+
+ out->insert(out->end(), tid);
+ }
+ }
+
+ return true;
+}
+
+template <typename Collection>
+auto GetProcessTids(pid_t pid, Collection* out) ->
+ typename std::enable_if<sizeof(typename Collection::value_type) >= sizeof(pid_t), bool>::type {
+ char task_path[PATH_MAX];
+ if (snprintf(task_path, PATH_MAX, "/proc/%d", pid) >= PATH_MAX) {
+ LOG(ERROR) << "task path overflow (pid = " << pid << ")";
+ return false;
+ }
+
+ android::base::unique_fd fd(open(task_path, O_DIRECTORY | O_RDONLY | O_CLOEXEC));
+ if (fd == -1) {
+ PLOG(ERROR) << "failed to open " << task_path;
+ return false;
+ }
+
+ return GetProcessTidsFromProcPidFd(fd.get(), out);
+}
+
+#endif
+
+} /* namespace procinfo */
+} /* namespace android */
diff --git a/libprocinfo/process.cpp b/libprocinfo/process.cpp
new file mode 100644
index 0000000..c513e16
--- /dev/null
+++ b/libprocinfo/process.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2016 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 <procinfo/process.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <android-base/unique_fd.h>
+
+using android::base::unique_fd;
+
+namespace android {
+namespace procinfo {
+
+bool GetProcessInfo(pid_t tid, ProcessInfo* process_info) {
+ char path[PATH_MAX];
+ snprintf(path, sizeof(path), "/proc/%d", tid);
+
+ unique_fd dirfd(open(path, O_DIRECTORY | O_RDONLY));
+ if (dirfd == -1) {
+ PLOG(ERROR) << "failed to open " << path;
+ return false;
+ }
+
+ return GetProcessInfoFromProcPidFd(dirfd.get(), process_info);
+}
+
+bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info) {
+ int status_fd = openat(fd, "status", O_RDONLY | O_CLOEXEC);
+
+ if (status_fd == -1) {
+ PLOG(ERROR) << "failed to open status fd in GetProcessInfoFromProcPidFd";
+ return false;
+ }
+
+ std::unique_ptr<FILE, decltype(&fclose)> fp(fdopen(status_fd, "r"), fclose);
+ if (!fp) {
+ PLOG(ERROR) << "failed to open status file in GetProcessInfoFromProcPidFd";
+ close(status_fd);
+ return false;
+ }
+
+ int field_bitmap = 0;
+ static constexpr int finished_bitmap = 127;
+ char* line = nullptr;
+ size_t len = 0;
+
+ while (getline(&line, &len, fp.get()) != -1 && field_bitmap != finished_bitmap) {
+ char* tab = strchr(line, '\t');
+ if (tab == nullptr) {
+ continue;
+ }
+
+ size_t header_len = tab - line;
+ std::string header = std::string(line, header_len);
+ if (header == "Name:") {
+ std::string name = line + header_len + 1;
+
+ // line includes the trailing newline.
+ name.pop_back();
+ process_info->name = std::move(name);
+
+ field_bitmap |= 1;
+ } else if (header == "Pid:") {
+ process_info->tid = atoi(tab + 1);
+ field_bitmap |= 2;
+ } else if (header == "Tgid:") {
+ process_info->pid = atoi(tab + 1);
+ field_bitmap |= 4;
+ } else if (header == "PPid:") {
+ process_info->ppid = atoi(tab + 1);
+ field_bitmap |= 8;
+ } else if (header == "TracerPid:") {
+ process_info->tracer = atoi(tab + 1);
+ field_bitmap |= 16;
+ } else if (header == "Uid:") {
+ process_info->uid = atoi(tab + 1);
+ field_bitmap |= 32;
+ } else if (header == "Gid:") {
+ process_info->gid = atoi(tab + 1);
+ field_bitmap |= 64;
+ }
+ }
+
+ free(line);
+ return field_bitmap == finished_bitmap;
+}
+
+} /* namespace procinfo */
+} /* namespace android */
diff --git a/libprocinfo/process_test.cpp b/libprocinfo/process_test.cpp
new file mode 100644
index 0000000..5ffd236
--- /dev/null
+++ b/libprocinfo/process_test.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 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 <procinfo/process.h>
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <set>
+#include <thread>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <android-base/stringprintf.h>
+
+#if !defined(__BIONIC__)
+#include <syscall.h>
+static pid_t gettid() {
+ return syscall(__NR_gettid);
+}
+#endif
+
+TEST(process_info, process_info_smoke) {
+ android::procinfo::ProcessInfo self;
+ ASSERT_TRUE(android::procinfo::GetProcessInfo(gettid(), &self));
+ ASSERT_EQ(gettid(), self.tid);
+ ASSERT_EQ(getpid(), self.pid);
+ ASSERT_EQ(getppid(), self.ppid);
+ ASSERT_EQ(getuid(), self.uid);
+ ASSERT_EQ(getgid(), self.gid);
+}
+
+TEST(process_info, process_info_proc_pid_fd_smoke) {
+ android::procinfo::ProcessInfo self;
+ int fd = open(android::base::StringPrintf("/proc/%d", gettid()).c_str(), O_DIRECTORY | O_RDONLY);
+ ASSERT_NE(-1, fd);
+ ASSERT_TRUE(android::procinfo::GetProcessInfoFromProcPidFd(fd, &self));
+
+ // Process name is capped at 15 bytes.
+ ASSERT_EQ("libprocinfo_tes", self.name);
+ ASSERT_EQ(gettid(), self.tid);
+ ASSERT_EQ(getpid(), self.pid);
+ ASSERT_EQ(getppid(), self.ppid);
+ ASSERT_EQ(getuid(), self.uid);
+ ASSERT_EQ(getgid(), self.gid);
+ close(fd);
+}
+
+TEST(process_info, process_tids_smoke) {
+ pid_t main_tid = gettid();
+ std::thread([main_tid]() {
+ pid_t thread_tid = gettid();
+
+ {
+ std::vector<pid_t> vec;
+ ASSERT_TRUE(android::procinfo::GetProcessTids(getpid(), &vec));
+ ASSERT_EQ(1, std::count(vec.begin(), vec.end(), main_tid));
+ ASSERT_EQ(1, std::count(vec.begin(), vec.end(), thread_tid));
+ }
+
+ {
+ std::set<pid_t> set;
+ ASSERT_TRUE(android::procinfo::GetProcessTids(getpid(), &set));
+ ASSERT_EQ(1, std::count(set.begin(), set.end(), main_tid));
+ ASSERT_EQ(1, std::count(set.begin(), set.end(), thread_tid));
+ }
+ }).join();
+}
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 25c779e..217b8c3 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -86,6 +86,13 @@
"ProcessCallStack.cpp",
],
},
+ linux_bionic: {
+ enabled: true,
+ srcs: [
+ "Looper.cpp",
+ "ProcessCallStack.cpp",
+ ],
+ },
darwin: {
cflags: ["-Wno-unused-parameter"],
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 5ed0fe8..fce1378 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -62,7 +62,17 @@
android: {
static_libs: ["libz"],
},
- host: {
+ linux_bionic: {
+ static_libs: ["libz"],
+ enabled: true,
+ },
+ linux: {
+ shared_libs: ["libz-host"],
+ },
+ darwin: {
+ shared_libs: ["libz-host"],
+ },
+ windows: {
shared_libs: ["libz-host"],
},
},
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index d36cc3f..e6e0276 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -781,7 +781,8 @@
// Creates a FileWriter for |fd| and prepare to write |entry| to it,
// guaranteeing that the file descriptor is valid and that there's enough
// space on the volume to write out the entry completely and that the file
- // is truncated to the correct length.
+ // is truncated to the correct length (no truncation if |fd| references a
+ // block device).
//
// Returns a valid FileWriter on success, |nullptr| if an error occurred.
static std::unique_ptr<FileWriter> Create(int fd, const ZipEntry* entry) {
@@ -814,13 +815,22 @@
}
#endif // __linux__
- result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
- if (result == -1) {
- ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
- static_cast<int64_t>(declared_length + current_offset), strerror(errno));
+ struct stat sb;
+ if (fstat(fd, &sb) == -1) {
+ ALOGW("Zip: unable to fstat file: %s", strerror(errno));
return std::unique_ptr<FileWriter>(nullptr);
}
+ // Block device doesn't support ftruncate(2).
+ if (!S_ISBLK(sb.st_mode)) {
+ result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
+ if (result == -1) {
+ ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
+ static_cast<int64_t>(declared_length + current_offset), strerror(errno));
+ return std::unique_ptr<FileWriter>(nullptr);
+ }
+ }
+
return std::unique_ptr<FileWriter>(new FileWriter(fd, declared_length));
}
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index d0c693d..94b8691 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -81,6 +81,7 @@
static size_t g_maxCount;
static size_t g_printCount;
static bool g_printItAnyways;
+static bool g_debug;
enum helpType {
HELP_FALSE,
@@ -176,7 +177,7 @@
static EventTagMap *eventTagMap = NULL;
if (!eventTagMap && !hasOpenedEventTagMap) {
- eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+ eventTagMap = android_openEventTagMap(NULL);
hasOpenedEventTagMap = true;
}
err = android_log_processBinaryLogBuffer(&buf->entry_v1, &entry,
@@ -188,7 +189,7 @@
} else {
err = android_log_processLogBuffer(&buf->entry_v1, &entry);
}
- if (err < 0) {
+ if ((err < 0) && !g_debug) {
goto error;
}
@@ -619,6 +620,7 @@
int option_index = 0;
// list of long-argument only strings for later comparison
static const char pid_str[] = "pid";
+ static const char debug_str[] = "debug";
static const char id_str[] = "id";
static const char wrap_str[] = "wrap";
static const char print_str[] = "print";
@@ -627,6 +629,7 @@
{ "buffer", required_argument, NULL, 'b' },
{ "buffer-size", optional_argument, NULL, 'g' },
{ "clear", no_argument, NULL, 'c' },
+ { debug_str, no_argument, NULL, 0 },
{ "dividers", no_argument, NULL, 'D' },
{ "file", required_argument, NULL, 'f' },
{ "format", required_argument, NULL, 'v' },
@@ -691,6 +694,10 @@
g_printItAnyways = true;
break;
}
+ if (long_options[option_index].name == debug_str) {
+ g_debug = true;
+ break;
+ }
if (long_options[option_index].name == id_str) {
setId = optarg && optarg[0] ? optarg : NULL;
break;
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 18067dc..11cffe6 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -29,6 +29,7 @@
#include <gtest/gtest.h>
#include <log/log.h>
+#include <log/log_event_list.h>
#define BIG_BUFFER (5 * 1024)
@@ -1091,7 +1092,7 @@
while (fgets(buffer, sizeof(buffer), fp)) {
char *hold = *list;
char *buf = buffer;
- while (isspace(*buf)) {
+ while (isspace(*buf)) {
++buf;
}
char *end = buf + strlen(buf);
@@ -1126,7 +1127,7 @@
while (fgets(buffer, sizeof(buffer), fp)) {
char *buf = buffer;
- while (isspace(*buf)) {
+ while (isspace(*buf)) {
++buf;
}
char *end = buf + strlen(buf);
@@ -1255,19 +1256,25 @@
va_end(ap);
char *str = NULL;
- asprintf(&str, "I/%s ( %%d): %s%%c", tag, buffer);
+ asprintf(&str, "I/%s ( %%d):%%c%s%%c", tag, buffer);
std::string expect(str);
free(str);
int count = 0;
pid_t pid = getpid();
std::string lastMatch;
+ int maxMatch = 1;
while (fgets(buffer, sizeof(buffer), fp)) {
+ char space;
char newline;
int p;
- int ret = sscanf(buffer, expect.c_str(), &p, &newline);
- if ((2 == ret) && (p == pid) && (newline == '\n')) ++count;
- else if ((1 == ret) && (p == pid) && (count == 0)) lastMatch = buffer;
+ int ret = sscanf(buffer, expect.c_str(), &p, &space, &newline);
+ if ((ret == 3) && (p == pid) && (space == ' ') && (newline == '\n')) {
+ ++count;
+ } else if ((ret >= maxMatch) && (p == pid) && (count == 0)) {
+ lastMatch = buffer;
+ maxMatch = ret;
+ }
}
pclose(fp);
@@ -1289,7 +1296,7 @@
{
static const struct tag hhgtg = { 42, "answer" };
- android_log_event_context ctx(hhgtg.tagNo);
+ android_log_event_list ctx(hhgtg.tagNo);
static const char theAnswer[] = "what is five by seven";
ctx << theAnswer;
ctx.write();
@@ -1301,7 +1308,7 @@
static const struct tag sync = { 2720, "sync" };
static const char id[] = "logcat.decriptive";
{
- android_log_event_context ctx(sync.tagNo);
+ android_log_event_list ctx(sync.tagNo);
ctx << id << (int32_t)42 << (int32_t)-1 << (int32_t)0;
ctx.write();
EXPECT_TRUE(End_to_End(sync.tagStr,
@@ -1311,7 +1318,7 @@
// Partial match to description
{
- android_log_event_context ctx(sync.tagNo);
+ android_log_event_list ctx(sync.tagNo);
ctx << id << (int32_t)43 << (int64_t)-1 << (int32_t)0;
ctx.write();
EXPECT_TRUE(End_to_End(sync.tagStr,
@@ -1321,7 +1328,7 @@
// Negative Test of End_to_End, ensure it is working
{
- android_log_event_context ctx(sync.tagNo);
+ android_log_event_list ctx(sync.tagNo);
ctx << id << (int32_t)44 << (int32_t)-1 << (int64_t)0;
ctx.write();
fprintf(stderr, "Expect a \"Closest match\" message\n");
@@ -1334,7 +1341,7 @@
{
static const struct tag sync = { 2747, "contacts_aggregation" };
{
- android_log_event_context ctx(sync.tagNo);
+ android_log_event_list ctx(sync.tagNo);
ctx << (uint64_t)30 << (int32_t)2;
ctx.write();
EXPECT_TRUE(End_to_End(sync.tagStr,
@@ -1342,7 +1349,7 @@
}
{
- android_log_event_context ctx(sync.tagNo);
+ android_log_event_list ctx(sync.tagNo);
ctx << (uint64_t)31570 << (int32_t)911;
ctx.write();
EXPECT_TRUE(End_to_End(sync.tagStr,
@@ -1353,46 +1360,52 @@
{
static const struct tag sync = { 75000, "sqlite_mem_alarm_current" };
{
- android_log_event_context ctx(sync.tagNo);
+ android_log_event_list ctx(sync.tagNo);
ctx << (uint32_t)512;
ctx.write();
EXPECT_TRUE(End_to_End(sync.tagStr, "current=512B"));
}
{
- android_log_event_context ctx(sync.tagNo);
+ android_log_event_list ctx(sync.tagNo);
ctx << (uint32_t)3072;
ctx.write();
EXPECT_TRUE(End_to_End(sync.tagStr, "current=3KB"));
}
{
- android_log_event_context ctx(sync.tagNo);
+ android_log_event_list ctx(sync.tagNo);
ctx << (uint32_t)2097152;
ctx.write();
EXPECT_TRUE(End_to_End(sync.tagStr, "current=2MB"));
}
{
- android_log_event_context ctx(sync.tagNo);
+ android_log_event_list ctx(sync.tagNo);
ctx << (uint32_t)2097153;
ctx.write();
EXPECT_TRUE(End_to_End(sync.tagStr, "current=2097153B"));
}
{
- android_log_event_context ctx(sync.tagNo);
+ android_log_event_list ctx(sync.tagNo);
ctx << (uint32_t)1073741824;
ctx.write();
EXPECT_TRUE(End_to_End(sync.tagStr, "current=1GB"));
}
{
- android_log_event_context ctx(sync.tagNo);
+ android_log_event_list ctx(sync.tagNo);
ctx << (uint32_t)3221225472; // 3MB, but on purpose overflowed
ctx.write();
EXPECT_TRUE(End_to_End(sync.tagStr, "current=-1GB"));
}
}
+ {
+ static const struct tag sync = { 27501, "notification_panel_hidden" };
+ android_log_event_list ctx(sync.tagNo);
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr, ""));
+ }
}
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index 7394f11..52c6742 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -48,6 +48,7 @@
registerCmd(new SetPruneListCmd(buf));
registerCmd(new GetPruneListCmd(buf));
registerCmd(new ReinitCmd());
+ registerCmd(new ExitCmd(this));
}
CommandListener::ShutdownCmd::ShutdownCmd(LogReader *reader,
@@ -297,6 +298,21 @@
return 0;
}
+CommandListener::ExitCmd::ExitCmd(CommandListener *parent) :
+ LogCommand("EXIT"),
+ mParent(*parent) {
+}
+
+int CommandListener::ExitCmd::runCommand(SocketClient * cli,
+ int /*argc*/, char ** /*argv*/) {
+ setname();
+
+ cli->sendMsg("success");
+ release(cli);
+
+ return 0;
+}
+
int CommandListener::getLogSocket() {
static const char socketName[] = "logd";
int sock = android_get_control_socket(socketName);
diff --git a/logd/CommandListener.h b/logd/CommandListener.h
index cbcd601..5d50177 100644
--- a/logd/CommandListener.h
+++ b/logd/CommandListener.h
@@ -52,22 +52,38 @@
explicit name##Cmd(LogBuffer *buf); \
virtual ~name##Cmd() {} \
int runCommand(SocketClient *c, int argc, char ** argv); \
- };
+ }
- LogBufferCmd(Clear)
- LogBufferCmd(GetBufSize)
- LogBufferCmd(SetBufSize)
- LogBufferCmd(GetBufSizeUsed)
- LogBufferCmd(GetStatistics)
- LogBufferCmd(GetPruneList)
- LogBufferCmd(SetPruneList)
+ LogBufferCmd(Clear);
+ LogBufferCmd(GetBufSize);
+ LogBufferCmd(SetBufSize);
+ LogBufferCmd(GetBufSizeUsed);
+ LogBufferCmd(GetStatistics);
+ LogBufferCmd(GetPruneList);
+ LogBufferCmd(SetPruneList);
- class ReinitCmd : public LogCommand {
- public:
- ReinitCmd();
- virtual ~ReinitCmd() {}
- int runCommand(SocketClient *c, int argc, char ** argv);
- };
+#define LogCmd(name) \
+ class name##Cmd : public LogCommand { \
+ public: \
+ name##Cmd(); \
+ virtual ~name##Cmd() {} \
+ int runCommand(SocketClient *c, int argc, char ** argv); \
+ }
+
+ LogCmd(Reinit);
+
+#define LogParentCmd(name) \
+ class name##Cmd : public LogCommand { \
+ CommandListener &mParent; \
+ public: \
+ name##Cmd(); \
+ explicit name##Cmd(CommandListener *parent); \
+ virtual ~name##Cmd() {} \
+ int runCommand(SocketClient *c, int argc, char ** argv); \
+ void release(SocketClient *c) { mParent.release(c); } \
+ }
+
+ LogParentCmd(Exit);
};
diff --git a/logd/main.cpp b/logd/main.cpp
index d698976..c3343d7 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -37,9 +37,9 @@
#include <memory>
#include <android-base/macros.h>
+#include <cutils/android_get_control_file.h>
#include <cutils/properties.h>
#include <cutils/sched_policy.h>
-#include <cutils/files.h>
#include <cutils/sockets.h>
#include <log/event_tag_map.h>
#include <packagelistparser/packagelistparser.h>
@@ -311,7 +311,7 @@
if (!map) {
sem_wait(&sem_name);
if (!map) {
- map = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+ map = android_openEventTagMap(NULL);
}
sem_post(&sem_name);
if (!map) {
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index e060a2c..0fc701a 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -56,6 +56,7 @@
LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
sbin dev proc sys system data oem acct cache config storage mnt root $(BOARD_ROOT_EXTRA_FOLDERS)); \
ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \
+ ln -sf /data/user_de/0/com.android.shell/files/bugreports $(TARGET_ROOT_OUT)/bugreports; \
ln -sf /sys/kernel/debug $(TARGET_ROOT_OUT)/d; \
ln -sf /storage/self/primary $(TARGET_ROOT_OUT)/sdcard
ifdef BOARD_USES_VENDORIMAGE
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 4c49791..ecc3ccd 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -293,11 +293,8 @@
mount none /mnt/runtime/default /storage slave bind rec
# Make sure /sys/kernel/debug (if present) is labeled properly
- restorecon_recursive /sys/kernel/debug
-
- # On systems with tracefs, tracing is a separate mount, so make sure
- # it too is correctly labeled
- restorecon_recursive /sys/kernel/debug/tracing
+ # Note that tracefs may be mounted under debug, so we need to cross filesystems
+ restorecon --recursive --cross-filesystems /sys/kernel/debug
# We chown/chmod /cache again so because mount is run as root + defaults
chown system cache /cache
@@ -433,10 +430,6 @@
mkdir /data/anr 0775 system system
- # symlink to bugreport storage location
- rm /data/bugreports
- symlink /data/user_de/0/com.android.shell/files/bugreports /data/bugreports
-
# 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
@@ -462,7 +455,7 @@
init_user0
# Set SELinux security contexts on upgrade or policy update.
- restorecon_recursive /data
+ restorecon --recursive --skip-ce /data
# Check any timezone data in /data is newer than the copy in /system, delete if not.
exec - system system -- /system/bin/tzdatacheck /system/usr/share/zoneinfo /data/misc/zoneinfo
@@ -566,7 +559,7 @@
on nonencrypted
# A/B update verifier that marks a successful boot.
- exec - root -- /system/bin/update_verifier nonencrypted
+ exec - root cache -- /system/bin/update_verifier nonencrypted
class_start main
class_start late_start
@@ -589,12 +582,12 @@
on property:vold.decrypt=trigger_restart_min_framework
# A/B update verifier that marks a successful boot.
- exec - root -- /system/bin/update_verifier trigger_restart_min_framework
+ exec - root cache -- /system/bin/update_verifier trigger_restart_min_framework
class_start main
on property:vold.decrypt=trigger_restart_framework
# A/B update verifier that marks a successful boot.
- exec - root -- /system/bin/update_verifier trigger_restart_framework
+ exec - root cache -- /system/bin/update_verifier trigger_restart_framework
class_start main
class_start late_start
diff --git a/sdcard/fuse.cpp b/sdcard/fuse.cpp
index d4c51fd..9393846 100644
--- a/sdcard/fuse.cpp
+++ b/sdcard/fuse.cpp
@@ -1262,12 +1262,9 @@
#if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
/* FUSE_KERNEL_VERSION >= 23. */
- /* If the kernel only works on minor revs older than or equal to 22,
- * then use the older structure size since this code only uses the 7.22
- * version of the structure. */
- if (req->minor <= 22) {
- fuse_struct_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
- }
+ /* Since we return minor version 15, the kernel does not accept the latest
+ * fuse_init_out size. We need to use FUSE_COMPAT_22_INIT_OUT_SIZE always.*/
+ fuse_struct_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
#endif
out.major = FUSE_KERNEL_VERSION;
diff --git a/sdcard/sdcard.cpp b/sdcard/sdcard.cpp
index bc502a0..df3ce85 100644
--- a/sdcard/sdcard.cpp
+++ b/sdcard/sdcard.cpp
@@ -331,6 +331,27 @@
return true;
}
+static bool sdcardfs_setup_bind_remount(const std::string& source_path, const std::string& dest_path,
+ gid_t gid, mode_t mask) {
+ std::string opts = android::base::StringPrintf("mask=%d,gid=%d", mask, gid);
+
+ if (mount(source_path.c_str(), dest_path.c_str(), nullptr,
+ MS_BIND, nullptr) != 0) {
+ PLOG(ERROR) << "failed to bind mount sdcardfs filesystem";
+ return false;
+ }
+
+ if (mount(source_path.c_str(), dest_path.c_str(), "none",
+ MS_REMOUNT | MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()) != 0) {
+ PLOG(ERROR) << "failed to mount sdcardfs filesystem";
+ if (umount2(dest_path.c_str(), MNT_DETACH))
+ PLOG(WARNING) << "Failed to unmount bind";
+ return false;
+ }
+
+ return true;
+}
+
static void run_sdcardfs(const std::string& source_path, const std::string& label, uid_t uid,
gid_t gid, userid_t userid, bool multi_user, bool full_write) {
std::string dest_path_default = "/mnt/runtime/default/" + label;
@@ -343,9 +364,8 @@
// permissions are completely masked off.
if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid,
AID_SDCARD_RW, 0006)
- || !sdcardfs_setup(source_path, dest_path_read, uid, gid, multi_user, userid,
- AID_EVERYBODY, 0027)
- || !sdcardfs_setup(source_path, dest_path_write, uid, gid, multi_user, userid,
+ || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_read, AID_EVERYBODY, 0027)
+ || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_write,
AID_EVERYBODY, full_write ? 0007 : 0027)) {
LOG(FATAL) << "failed to sdcardfs_setup";
}
@@ -355,9 +375,9 @@
// deep inside attr_from_stat().
if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid,
AID_SDCARD_RW, 0006)
- || !sdcardfs_setup(source_path, dest_path_read, uid, gid, multi_user, userid,
+ || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_read,
AID_EVERYBODY, full_write ? 0027 : 0022)
- || !sdcardfs_setup(source_path, dest_path_write, uid, gid, multi_user, userid,
+ || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_write,
AID_EVERYBODY, full_write ? 0007 : 0022)) {
LOG(FATAL) << "failed to sdcardfs_setup";
}
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 5319ff4..d6ead1a 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -81,15 +81,6 @@
$(INPUT_H_LABELS_H):
$(transform-generated-source)
-# We only want 'r' on userdebug and eng builds.
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := r.c
-LOCAL_CFLAGS += $(common_cflags)
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/upstream-netbsd/include/
-LOCAL_MODULE := r
-LOCAL_MODULE_TAGS := debug
-include $(BUILD_EXECUTABLE)
-
# We build BSD grep separately, so it can provide egrep and fgrep too.
include $(CLEAR_VARS)
diff --git a/toolbox/getevent.c b/toolbox/getevent.c
index 30053af..e6def6b 100644
--- a/toolbox/getevent.c
+++ b/toolbox/getevent.c
@@ -9,6 +9,7 @@
#include <sys/limits.h>
#include <sys/poll.h>
#include <linux/input.h>
+#include <err.h>
#include <errno.h>
#include <unistd.h>
@@ -110,10 +111,8 @@
break;
bits_size = res + 16;
bits = realloc(bits, bits_size * 2);
- if(bits == NULL) {
- fprintf(stderr, "failed to allocate buffer of size %d\n", (int)bits_size);
- return 1;
- }
+ if(bits == NULL)
+ err(1, "failed to allocate buffer of size %d\n", (int)bits_size);
}
res2 = 0;
switch(i) {
diff --git a/toolbox/newfs_msdos.c b/toolbox/newfs_msdos.c
index 27ea9e8..d7047e2 100644
--- a/toolbox/newfs_msdos.c
+++ b/toolbox/newfs_msdos.c
@@ -741,6 +741,7 @@
exit(1);
}
}
+ free(img);
}
return 0;
}
diff --git a/toolbox/r.c b/toolbox/r.c
deleted file mode 100644
index b96cdb2..0000000
--- a/toolbox/r.c
+++ /dev/null
@@ -1,102 +0,0 @@
-#include <fcntl.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-#if __LP64__
-#define strtoptr strtoull
-#else
-#define strtoptr strtoul
-#endif
-
-static int usage()
-{
- fprintf(stderr,"r [-b|-s] <address> [<value>]\n");
- return -1;
-}
-
-int main(int argc, char *argv[])
-{
- if(argc < 2) return usage();
-
- int width = 4;
- if(!strcmp(argv[1], "-b")) {
- width = 1;
- argc--;
- argv++;
- } else if(!strcmp(argv[1], "-s")) {
- width = 2;
- argc--;
- argv++;
- }
-
- if(argc < 2) return usage();
- uintptr_t addr = strtoptr(argv[1], 0, 16);
-
- uintptr_t endaddr = 0;
- char* end = strchr(argv[1], '-');
- if (end)
- endaddr = strtoptr(end + 1, 0, 16);
-
- if (!endaddr)
- endaddr = addr + width - 1;
-
- if (endaddr <= addr) {
- fprintf(stderr, "end address <= start address\n");
- return -1;
- }
-
- bool set = false;
- uint32_t value = 0;
- if(argc > 2) {
- set = true;
- value = strtoul(argv[2], 0, 16);
- }
-
- int fd = open("/dev/mem", O_RDWR | O_SYNC);
- if(fd < 0) {
- fprintf(stderr,"cannot open /dev/mem\n");
- return -1;
- }
-
- off64_t mmap_start = addr & ~(PAGE_SIZE - 1);
- size_t mmap_size = endaddr - mmap_start + 1;
- mmap_size = (mmap_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
-
- void* page = mmap64(0, mmap_size, PROT_READ | PROT_WRITE,
- MAP_SHARED, fd, mmap_start);
-
- if(page == MAP_FAILED){
- fprintf(stderr,"cannot mmap region\n");
- return -1;
- }
-
- while (addr <= endaddr) {
- switch(width){
- case 4: {
- uint32_t* x = (uint32_t*) (((uintptr_t) page) + (addr & 4095));
- if(set) *x = value;
- fprintf(stderr,"%08"PRIxPTR": %08x\n", addr, *x);
- break;
- }
- case 2: {
- uint16_t* x = (uint16_t*) (((uintptr_t) page) + (addr & 4095));
- if(set) *x = value;
- fprintf(stderr,"%08"PRIxPTR": %04x\n", addr, *x);
- break;
- }
- case 1: {
- uint8_t* x = (uint8_t*) (((uintptr_t) page) + (addr & 4095));
- if(set) *x = value;
- fprintf(stderr,"%08"PRIxPTR": %02x\n", addr, *x);
- break;
- }
- }
- addr += width;
- }
- return 0;
-}