Merge changes from topic 'healthd-charger-split'
* changes:
healthd: refactor healthd code to split into 'charger' and 'healthd'
healthd: build 'charger' and 'healthd' binaries
healthd: refactor to split charger and framework facing code
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 29d6e65..8b6b2b5 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -1089,6 +1089,31 @@
return 1;
}
+ if (!strcmp(service, "reconnect-offline")) {
+ std::string response;
+ close_usb_devices([&response](const atransport* transport) {
+ switch (transport->connection_state) {
+ case kCsOffline:
+ case kCsUnauthorized:
+ response += "reconnecting ";
+ if (transport->serial) {
+ response += transport->serial;
+ } else {
+ response += "<unknown>";
+ }
+ response += "\n";
+ return true;
+ default:
+ return false;
+ }
+ });
+ if (!response.empty()) {
+ response.resize(response.size() - 1);
+ }
+ SendOkay(reply_fd, response);
+ return 0;
+ }
+
if (!strcmp(service, "features")) {
std::string error;
atransport* t = acquire_one_transport(type, serial, nullptr, &error);
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 1f03c1a..e15bcad 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -1950,10 +1950,17 @@
} else if (!strcmp(argv[0], "reconnect")) {
if (argc == 1) {
return adb_query_command("host:reconnect");
- } else if (argc == 2 && !strcmp(argv[1], "device")) {
- std::string err;
- adb_connect("reconnect", &err);
- return 0;
+ } else if (argc == 2) {
+ if (!strcmp(argv[1], "device")) {
+ std::string err;
+ adb_connect("reconnect", &err);
+ return 0;
+ } else if (!strcmp(argv[1], "offline")) {
+ std::string err;
+ return adb_query_command("host:reconnect-offline");
+ } else {
+ return usage();
+ }
}
}
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index 837902a..7a92d2e 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -198,11 +198,6 @@
// Ignore the result of calling fchmod. It's not supported
// by all filesystems, so we don't check for success. b/12441485
fchmod(fd, mode);
-
- if (!update_capabilities(path, capabilities)) {
- SendSyncFailErrno(s, "update_capabilities failed");
- goto fail;
- }
}
while (true) {
@@ -232,6 +227,11 @@
adb_close(fd);
+ if (!update_capabilities(path, capabilities)) {
+ SendSyncFailErrno(s, "update_capabilities failed");
+ goto fail;
+ }
+
utimbuf u;
u.actime = timestamp;
u.modtime = timestamp;
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 3a57174..c05903f 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -791,11 +791,14 @@
}
#endif
- if (!(s->transport) || (s->transport->connection_state == kCsOffline)) {
+ if (!s->transport) {
+ SendFail(s->peer->fd, "device offline (no transport)");
+ goto fail;
+ } else if (s->transport->connection_state == kCsOffline) {
/* if there's no remote we fail the connection
** right here and terminate it
*/
- SendFail(s->peer->fd, "device offline (x)");
+ SendFail(s->peer->fd, "device offline (transport offline)");
goto fail;
}
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 7b4bb1c..132702d 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -908,12 +908,18 @@
return result;
}
+void close_usb_devices(std::function<bool(const atransport*)> predicate) {
+ std::lock_guard<std::mutex> lock(transport_lock);
+ for (auto& t : transport_list) {
+ if (predicate(t)) {
+ t->Kick();
+ }
+ }
+}
+
/* hack for osx */
void close_usb_devices() {
- std::lock_guard<std::mutex> lock(transport_lock);
- for (const auto& t : transport_list) {
- t->Kick();
- }
+ close_usb_devices([](const atransport*) { return true; });
}
#endif // ADB_HOST
diff --git a/adb/transport.h b/adb/transport.h
index 621516c..b2df838 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -20,6 +20,7 @@
#include <sys/types.h>
#include <deque>
+#include <functional>
#include <list>
#include <memory>
#include <string>
@@ -199,8 +200,8 @@
int check_header(apacket* p, atransport* t);
int check_data(apacket* p);
-/* for MacOS X cleanup */
void close_usb_devices();
+void close_usb_devices(std::function<bool(const atransport*)> predicate);
void send_packet(apacket* p, atransport* t);
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index d570255..b1511fe 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -241,7 +241,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 +651,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;
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index f03b2dd..2434c78 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -72,6 +72,7 @@
{ "recoveryonly",MF_RECOVERYONLY },
{ "swapprio=", MF_SWAPPRIO },
{ "zramsize=", MF_ZRAMSIZE },
+ { "verifyatboot", MF_VERIFYATBOOT },
{ "verify", MF_VERIFY },
{ "noemulatedsd", MF_NOEMULATEDSD },
{ "notrim", MF_NOTRIM },
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..120ec5a 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_VERIFYATBOOT 0x80000
#define DM_BUF_SIZE 4096
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 031b042..af57a55 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -32,6 +32,7 @@
#include <android-base/file.h>
#include <android-base/strings.h>
#include <crypto_utils/android_pubkey.h>
+#include <android-base/unique_fd.h>
#include <cutils/properties.h>
#include <logwrap/logwrap.h>
#include <openssl/obj_mac.h>
@@ -73,6 +74,8 @@
#define VERITY_KMSG_RESTART "dm-verity device corrupted"
#define VERITY_KMSG_BUFSIZE 1024
+#define READ_BUF_SIZE 4096
+
#define __STRINGIFY(x) #x
#define STRINGIFY(x) __STRINGIFY(x)
@@ -205,6 +208,16 @@
return 0;
}
+static int destroy_verity_device(struct dm_ioctl *io, char *name, int fd)
+{
+ verity_ioctl_init(io, name, 0);
+ if (ioctl(fd, DM_DEV_REMOVE, io)) {
+ ERROR("Error removing device mapping (%s)", strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
static int get_verity_device_name(struct dm_ioctl *io, char *name, int fd, char **dev_name)
{
verity_ioctl_init(io, name, 0);
@@ -606,6 +619,30 @@
return rc;
}
+static int read_partition(const char *path, uint64_t size)
+{
+ char buf[READ_BUF_SIZE];
+ ssize_t size_read;
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC)));
+
+ if (fd == -1) {
+ ERROR("Failed to open %s: %s\n", path, strerror(errno));
+ return -errno;
+ }
+
+ while (size) {
+ size_read = TEMP_FAILURE_RETRY(read(fd, buf, READ_BUF_SIZE));
+ if (size_read == -1) {
+ ERROR("Error in reading partition %s: %s\n", path,
+ strerror(errno));
+ return -errno;
+ }
+ size -= size_read;
+ }
+
+ return 0;
+}
+
static int compare_last_signature(struct fstab_rec *fstab, int *match)
{
char tag[METADATA_TAG_MAX_LENGTH + 1];
@@ -900,6 +937,7 @@
struct fec_handle *f = NULL;
struct fec_verity_metadata verity;
struct verity_table_params params = { .table = NULL };
+ bool verified_at_boot = false;
alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
struct dm_ioctl *io = (struct dm_ioctl *) buffer;
@@ -1037,10 +1075,26 @@
// mark the underlying block device as read-only
fs_mgr_set_blk_ro(fstab->blk_device);
+ // Verify the entire partition in one go
+ // If there is an error, allow it to mount as a normal verity partition.
+ if (fstab->fs_mgr_flags & MF_VERIFYATBOOT) {
+ INFO("Verifying partition %s at boot\n", fstab->blk_device);
+ int err = read_partition(verity_blk_name, verity.data_size);
+ if (!err) {
+ INFO("Verified verity partition %s at boot\n", fstab->blk_device);
+ verified_at_boot = true;
+ }
+ }
+
// assign the new verity block device as the block device
- free(fstab->blk_device);
- fstab->blk_device = verity_blk_name;
- verity_blk_name = 0;
+ if (!verified_at_boot) {
+ free(fstab->blk_device);
+ fstab->blk_device = verity_blk_name;
+ verity_blk_name = 0;
+ } else if (destroy_verity_device(io, mount_point, fd) < 0) {
+ ERROR("Failed to remove verity device %s\n", mount_point);
+ goto out;
+ }
// make sure we've set everything up properly
if (test_access(fstab->blk_device) < 0) {
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index b43847c..38c931e 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -97,7 +97,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/include/cutils/files.h b/include/cutils/files.h
new file mode 100644
index 0000000..0210e30
--- /dev/null
+++ b/include/cutils/files.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#ifndef __CUTILS_FILES_H
+#define __CUTILS_FILES_H
+
+#define ANDROID_FILE_ENV_PREFIX "ANDROID_FILE_"
+
+#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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_FILES_H */
diff --git a/include/log/event_tag_map.h b/include/log/event_tag_map.h
index 69774ba..22e62ec 100644
--- a/include/log/event_tag_map.h
+++ b/include/log/event_tag_map.h
@@ -48,7 +48,15 @@
* Look up a tag by index. Returns the tag string & string length, or NULL if
* not found. Returned string is not guaranteed to be nul terminated.
*/
-const char* android_lookupEventTag_len(const EventTagMap* map, size_t* len, unsigned int tag);
+const char* android_lookupEventTag_len(const EventTagMap* map,
+ size_t* len, unsigned int tag);
+
+/*
+ * Look up a format by index. Returns the format string & string length,
+ * or NULL if not found. Returned string is not guaranteed to be nul terminated.
+ */
+const char* android_lookupEventFormat_len(const EventTagMap* map,
+ size_t* len, unsigned int tag);
#ifdef __cplusplus
}
diff --git a/include/log/logprint.h b/include/log/logprint.h
index 493f9f8..3509e7f 100644
--- a/include/log/logprint.h
+++ b/include/log/logprint.h
@@ -46,6 +46,7 @@
FORMAT_MODIFIER_EPOCH, /* Print time as seconds since Jan 1 1970 */
FORMAT_MODIFIER_MONOTONIC, /* Print cpu time as seconds since start */
FORMAT_MODIFIER_UID, /* Adds uid */
+ FORMAT_MODIFIER_DESCRIPT, /* Adds descriptive */
} AndroidLogPrintFormat;
typedef struct AndroidLogFormat_t AndroidLogFormat;
diff --git a/include/nativebridge/native_bridge.h b/include/nativebridge/native_bridge.h
index 26556f0..45266de 100644
--- a/include/nativebridge/native_bridge.h
+++ b/include/nativebridge/native_bridge.h
@@ -104,7 +104,7 @@
// Get last error message of native bridge when fail to load library or search symbol.
// This is reflection of dlerror() for native bridge.
-char* NativeBridgeGetError();
+const char* NativeBridgeGetError();
struct native_bridge_namespace_t;
@@ -244,7 +244,7 @@
// Returns:
// A string describing the most recent error that occurred when load library
// or lookup symbol via native bridge.
- char* (*getError)();
+ const char* (*getError)();
// Check whether library paths are supported by native bridge.
//
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 167a6d9..c364317 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -95,6 +95,7 @@
#define AID_DNS 1051 /* DNS resolution daemon (system: netd) */
#define AID_DNS_TETHER 1052 /* DNS resolution daemon (tether: dnsmasq) */
#define AID_WEBVIEW_ZYGOTE 1053 /* WebView zygote process */
+#define AID_VEHICLE_NETWORK 1054 /* Vehicle network service */
/* Changes to this file must be made in AOSP, *not* in internal branches. */
#define AID_SHELL 2000 /* adb and debug shell user */
@@ -208,6 +209,7 @@
{ "dns", AID_DNS, },
{ "dns_tether", AID_DNS_TETHER, },
{ "webview_zygote", AID_WEBVIEW_ZYGOTE, },
+ { "vehicle_network", AID_VEHICLE_NETWORK, },
{ "shell", AID_SHELL, },
{ "cache", AID_CACHE, },
diff --git a/include/system/graphics-base.h b/include/system/graphics-base.h
new file mode 100644
index 0000000..cebd2f9
--- /dev/null
+++ b/include/system/graphics-base.h
@@ -0,0 +1,120 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+#ifndef HIDL_GENERATED_android_hardware_graphics_common_V1_0_EXPORTED_CONSTANTS_H_
+#define HIDL_GENERATED_android_hardware_graphics_common_V1_0_EXPORTED_CONSTANTS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ HAL_PIXEL_FORMAT_RGBA_8888 = 1,
+ HAL_PIXEL_FORMAT_RGBX_8888 = 2,
+ HAL_PIXEL_FORMAT_RGB_888 = 3,
+ HAL_PIXEL_FORMAT_RGB_565 = 4,
+ HAL_PIXEL_FORMAT_BGRA_8888 = 5,
+ HAL_PIXEL_FORMAT_YV12 = 842094169, // 0x32315659
+ HAL_PIXEL_FORMAT_Y8 = 538982489, // 0x20203859
+ HAL_PIXEL_FORMAT_Y16 = 540422489, // 0x20363159
+ HAL_PIXEL_FORMAT_RAW16 = 32, // 0x20
+ HAL_PIXEL_FORMAT_RAW10 = 37, // 0x25
+ HAL_PIXEL_FORMAT_RAW12 = 38, // 0x26
+ HAL_PIXEL_FORMAT_RAW_OPAQUE = 36, // 0x24
+ HAL_PIXEL_FORMAT_BLOB = 33, // 0x21
+ HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 34, // 0x22
+ HAL_PIXEL_FORMAT_YCBCR_420_888 = 35, // 0x23
+ HAL_PIXEL_FORMAT_YCBCR_422_888 = 39, // 0x27
+ HAL_PIXEL_FORMAT_YCBCR_444_888 = 40, // 0x28
+ HAL_PIXEL_FORMAT_FLEX_RGB_888 = 41, // 0x29
+ HAL_PIXEL_FORMAT_FLEX_RGBA_8888 = 42, // 0x2A
+ HAL_PIXEL_FORMAT_YCBCR_422_SP = 16, // 0x10
+ HAL_PIXEL_FORMAT_YCRCB_420_SP = 17, // 0x11
+ HAL_PIXEL_FORMAT_YCBCR_422_I = 20, // 0x14
+} android_pixel_format_t;
+
+typedef enum {
+ HAL_TRANSFORM_FLIP_H = 1, // 0x01
+ HAL_TRANSFORM_FLIP_V = 2, // 0x02
+ HAL_TRANSFORM_ROT_90 = 4, // 0x04
+ HAL_TRANSFORM_ROT_180 = 3, // 0x03
+ HAL_TRANSFORM_ROT_270 = 7, // 0x07
+} android_transform_t;
+
+typedef enum {
+ HAL_DATASPACE_UNKNOWN = 0, // 0x0
+ HAL_DATASPACE_ARBITRARY = 1, // 0x1
+ HAL_DATASPACE_STANDARD_SHIFT = 16,
+ HAL_DATASPACE_STANDARD_MASK = 4128768, // (63 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_UNSPECIFIED = 0, // (0 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_BT709 = 65536, // (1 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_BT601_625 = 131072, // (2 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED = 196608, // (3 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_BT601_525 = 262144, // (4 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED = 327680, // (5 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_BT2020 = 393216, // (6 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE = 458752, // (7 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_BT470M = 524288, // (8 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_FILM = 589824, // (9 << STANDARD_SHIFT)
+ HAL_DATASPACE_TRANSFER_SHIFT = 22,
+ HAL_DATASPACE_TRANSFER_MASK = 130023424, // (31 << TRANSFER_SHIFT)
+ HAL_DATASPACE_TRANSFER_UNSPECIFIED = 0, // (0 << TRANSFER_SHIFT)
+ HAL_DATASPACE_TRANSFER_LINEAR = 4194304, // (1 << TRANSFER_SHIFT)
+ HAL_DATASPACE_TRANSFER_SRGB = 8388608, // (2 << TRANSFER_SHIFT)
+ HAL_DATASPACE_TRANSFER_SMPTE_170M = 12582912, // (3 << TRANSFER_SHIFT)
+ HAL_DATASPACE_TRANSFER_GAMMA2_2 = 16777216, // (4 << TRANSFER_SHIFT)
+ HAL_DATASPACE_TRANSFER_GAMMA2_8 = 20971520, // (5 << TRANSFER_SHIFT)
+ HAL_DATASPACE_TRANSFER_ST2084 = 25165824, // (6 << TRANSFER_SHIFT)
+ HAL_DATASPACE_TRANSFER_HLG = 29360128, // (7 << TRANSFER_SHIFT)
+ HAL_DATASPACE_RANGE_SHIFT = 27,
+ HAL_DATASPACE_RANGE_MASK = 939524096, // (7 << RANGE_SHIFT)
+ HAL_DATASPACE_RANGE_UNSPECIFIED = 0, // (0 << RANGE_SHIFT)
+ HAL_DATASPACE_RANGE_FULL = 134217728, // (1 << RANGE_SHIFT)
+ HAL_DATASPACE_RANGE_LIMITED = 268435456, // (2 << RANGE_SHIFT)
+ HAL_DATASPACE_SRGB_LINEAR = 512, // 0x200
+ HAL_DATASPACE_V0_SRGB_LINEAR = 138477568, // ((STANDARD_BT709 | TRANSFER_LINEAR) | RANGE_FULL)
+ HAL_DATASPACE_SRGB = 513, // 0x201
+ HAL_DATASPACE_V0_SRGB = 142671872, // ((STANDARD_BT709 | TRANSFER_SRGB) | RANGE_FULL)
+ HAL_DATASPACE_JFIF = 257, // 0x101
+ HAL_DATASPACE_V0_JFIF = 146931712, // ((STANDARD_BT601_625 | TRANSFER_SMPTE_170M) | RANGE_FULL)
+ HAL_DATASPACE_BT601_625 = 258, // 0x102
+ HAL_DATASPACE_V0_BT601_625 = 281149440, // ((STANDARD_BT601_625 | TRANSFER_SMPTE_170M) | RANGE_LIMITED)
+ HAL_DATASPACE_BT601_525 = 259, // 0x103
+ HAL_DATASPACE_V0_BT601_525 = 281280512, // ((STANDARD_BT601_525 | TRANSFER_SMPTE_170M) | RANGE_LIMITED)
+ HAL_DATASPACE_BT709 = 260, // 0x104
+ HAL_DATASPACE_V0_BT709 = 281083904, // ((STANDARD_BT709 | TRANSFER_SMPTE_170M) | RANGE_LIMITED)
+ HAL_DATASPACE_DEPTH = 4096, // 0x1000
+} android_dataspace_t;
+
+typedef enum {
+ HAL_COLOR_MODE_NATIVE = 0,
+ HAL_COLOR_MODE_STANDARD_BT601_625 = 1,
+ HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED = 2,
+ HAL_COLOR_MODE_STANDARD_BT601_525 = 3,
+ HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED = 4,
+ HAL_COLOR_MODE_STANDARD_BT709 = 5,
+ HAL_COLOR_MODE_DCI_P3 = 6,
+ HAL_COLOR_MODE_SRGB = 7,
+ HAL_COLOR_MODE_ADOBE_RGB = 8,
+} android_color_mode_t;
+
+typedef enum {
+ HAL_COLOR_TRANSFORM_IDENTITY = 0,
+ HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX = 1,
+ HAL_COLOR_TRANSFORM_VALUE_INVERSE = 2,
+ HAL_COLOR_TRANSFORM_GRAYSCALE = 3,
+ HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA = 4,
+ HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA = 5,
+ HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA = 6,
+} android_color_transform_t;
+
+typedef enum {
+ HAL_HDR_DOLBY_VISION = 1,
+ HAL_HDR_HDR10 = 2,
+ HAL_HDR_HLG = 3,
+} android_hdr_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // HIDL_GENERATED_android_hardware_graphics_common_V1_0_EXPORTED_CONSTANTS_H_
diff --git a/include/system/graphics.h b/include/system/graphics.h
index ae10fa0..449b8c7 100644
--- a/include/system/graphics.h
+++ b/include/system/graphics.h
@@ -20,10 +20,30 @@
#include <stddef.h>
#include <stdint.h>
+/*
+ * Some of the enums are now defined in HIDL in hardware/interfaces and are
+ * generated.
+ */
+#include "graphics-base.h"
+
#ifdef __cplusplus
extern "C" {
#endif
+/* for compatibility */
+#define HAL_PIXEL_FORMAT_YCbCr_420_888 HAL_PIXEL_FORMAT_YCBCR_420_888
+#define HAL_PIXEL_FORMAT_YCbCr_422_888 HAL_PIXEL_FORMAT_YCBCR_422_888
+#define HAL_PIXEL_FORMAT_YCbCr_444_888 HAL_PIXEL_FORMAT_YCBCR_444_888
+#define HAL_PIXEL_FORMAT_YCbCr_422_SP HAL_PIXEL_FORMAT_YCBCR_422_SP
+#define HAL_PIXEL_FORMAT_YCrCb_420_SP HAL_PIXEL_FORMAT_YCRCB_420_SP
+#define HAL_PIXEL_FORMAT_YCbCr_422_I HAL_PIXEL_FORMAT_YCBCR_422_I
+typedef android_pixel_format_t android_pixel_format;
+typedef android_transform_t android_transform;
+typedef android_dataspace_t android_dataspace;
+typedef android_color_mode_t android_color_mode;
+typedef android_color_transform_t android_color_transform;
+typedef android_hdr_t android_hdr;
+
/*
* If the HAL needs to create service threads to handle graphics related
* tasks, these threads need to run at HAL_PRIORITY_URGENT_DISPLAY priority
@@ -38,411 +58,6 @@
#define HAL_PRIORITY_URGENT_DISPLAY (-8)
-/**
- * pixel format definitions
- */
-
-typedef enum android_pixel_format {
- /*
- * "linear" color pixel formats:
- *
- * When used with ANativeWindow, the dataSpace field describes the color
- * space of the buffer.
- *
- * The color space determines, for example, if the formats are linear or
- * gamma-corrected; or whether any special operations are performed when
- * reading or writing into a buffer in one of these formats.
- */
- HAL_PIXEL_FORMAT_RGBA_8888 = 1,
- HAL_PIXEL_FORMAT_RGBX_8888 = 2,
- HAL_PIXEL_FORMAT_RGB_888 = 3,
- HAL_PIXEL_FORMAT_RGB_565 = 4,
- HAL_PIXEL_FORMAT_BGRA_8888 = 5,
-
- /*
- * 0x100 - 0x1FF
- *
- * This range is reserved for pixel formats that are specific to the HAL
- * implementation. Implementations can use any value in this range to
- * communicate video pixel formats between their HAL modules. These formats
- * must not have an alpha channel. Additionally, an EGLimage created from a
- * gralloc buffer of one of these formats must be supported for use with the
- * GL_OES_EGL_image_external OpenGL ES extension.
- */
-
- /*
- * Android YUV format:
- *
- * This format is exposed outside of the HAL to software decoders and
- * applications. EGLImageKHR must support it in conjunction with the
- * OES_EGL_image_external extension.
- *
- * YV12 is a 4:2:0 YCrCb planar format comprised of a WxH Y plane followed
- * by (W/2) x (H/2) Cr and Cb planes.
- *
- * This format assumes
- * - an even width
- * - an even height
- * - a horizontal stride multiple of 16 pixels
- * - a vertical stride equal to the height
- *
- * y_size = stride * height
- * c_stride = ALIGN(stride/2, 16)
- * c_size = c_stride * height/2
- * size = y_size + c_size * 2
- * cr_offset = y_size
- * cb_offset = y_size + c_size
- *
- * When used with ANativeWindow, the dataSpace field describes the color
- * space of the buffer.
- */
- HAL_PIXEL_FORMAT_YV12 = 0x32315659, // YCrCb 4:2:0 Planar
-
-
- /*
- * Android Y8 format:
- *
- * This format is exposed outside of the HAL to the framework.
- * The expected gralloc usage flags are SW_* and HW_CAMERA_*,
- * and no other HW_ flags will be used.
- *
- * Y8 is a YUV planar format comprised of a WxH Y plane,
- * with each pixel being represented by 8 bits.
- *
- * It is equivalent to just the Y plane from YV12.
- *
- * This format assumes
- * - an even width
- * - an even height
- * - a horizontal stride multiple of 16 pixels
- * - a vertical stride equal to the height
- *
- * size = stride * height
- *
- * When used with ANativeWindow, the dataSpace field describes the color
- * space of the buffer.
- */
- HAL_PIXEL_FORMAT_Y8 = 0x20203859,
-
- /*
- * Android Y16 format:
- *
- * This format is exposed outside of the HAL to the framework.
- * The expected gralloc usage flags are SW_* and HW_CAMERA_*,
- * and no other HW_ flags will be used.
- *
- * Y16 is a YUV planar format comprised of a WxH Y plane,
- * with each pixel being represented by 16 bits.
- *
- * It is just like Y8, but has double the bits per pixel (little endian).
- *
- * This format assumes
- * - an even width
- * - an even height
- * - a horizontal stride multiple of 16 pixels
- * - a vertical stride equal to the height
- * - strides are specified in pixels, not in bytes
- *
- * size = stride * height * 2
- *
- * When used with ANativeWindow, the dataSpace field describes the color
- * space of the buffer, except that dataSpace field
- * HAL_DATASPACE_DEPTH indicates that this buffer contains a depth
- * image where each sample is a distance value measured by a depth camera,
- * plus an associated confidence value.
- */
- HAL_PIXEL_FORMAT_Y16 = 0x20363159,
-
- /*
- * Android RAW sensor format:
- *
- * This format is exposed outside of the camera HAL to applications.
- *
- * RAW16 is a single-channel, 16-bit, little endian format, typically
- * representing raw Bayer-pattern images from an image sensor, with minimal
- * processing.
- *
- * The exact pixel layout of the data in the buffer is sensor-dependent, and
- * needs to be queried from the camera device.
- *
- * Generally, not all 16 bits are used; more common values are 10 or 12
- * bits. If not all bits are used, the lower-order bits are filled first.
- * All parameters to interpret the raw data (black and white points,
- * color space, etc) must be queried from the camera device.
- *
- * This format assumes
- * - an even width
- * - an even height
- * - a horizontal stride multiple of 16 pixels
- * - a vertical stride equal to the height
- * - strides are specified in pixels, not in bytes
- *
- * size = stride * height * 2
- *
- * This format must be accepted by the gralloc module when used with the
- * following usage flags:
- * - GRALLOC_USAGE_HW_CAMERA_*
- * - GRALLOC_USAGE_SW_*
- * - GRALLOC_USAGE_RENDERSCRIPT
- *
- * When used with ANativeWindow, the dataSpace should be
- * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
- * extra metadata to define.
- */
- HAL_PIXEL_FORMAT_RAW16 = 0x20,
-
- /*
- * Android RAW10 format:
- *
- * This format is exposed outside of the camera HAL to applications.
- *
- * RAW10 is a single-channel, 10-bit per pixel, densely packed in each row,
- * unprocessed format, usually representing raw Bayer-pattern images coming from
- * an image sensor.
- *
- * In an image buffer with this format, starting from the first pixel of each
- * row, each 4 consecutive pixels are packed into 5 bytes (40 bits). Each one
- * of the first 4 bytes contains the top 8 bits of each pixel, The fifth byte
- * contains the 2 least significant bits of the 4 pixels, the exact layout data
- * for each 4 consecutive pixels is illustrated below (Pi[j] stands for the jth
- * bit of the ith pixel):
- *
- * bit 7 bit 0
- * =====|=====|=====|=====|=====|=====|=====|=====|
- * Byte 0: |P0[9]|P0[8]|P0[7]|P0[6]|P0[5]|P0[4]|P0[3]|P0[2]|
- * |-----|-----|-----|-----|-----|-----|-----|-----|
- * Byte 1: |P1[9]|P1[8]|P1[7]|P1[6]|P1[5]|P1[4]|P1[3]|P1[2]|
- * |-----|-----|-----|-----|-----|-----|-----|-----|
- * Byte 2: |P2[9]|P2[8]|P2[7]|P2[6]|P2[5]|P2[4]|P2[3]|P2[2]|
- * |-----|-----|-----|-----|-----|-----|-----|-----|
- * Byte 3: |P3[9]|P3[8]|P3[7]|P3[6]|P3[5]|P3[4]|P3[3]|P3[2]|
- * |-----|-----|-----|-----|-----|-----|-----|-----|
- * Byte 4: |P3[1]|P3[0]|P2[1]|P2[0]|P1[1]|P1[0]|P0[1]|P0[0]|
- * ===============================================
- *
- * This format assumes
- * - a width multiple of 4 pixels
- * - an even height
- * - a vertical stride equal to the height
- * - strides are specified in bytes, not in pixels
- *
- * size = stride * height
- *
- * When stride is equal to width * (10 / 8), there will be no padding bytes at
- * the end of each row, the entire image data is densely packed. When stride is
- * larger than width * (10 / 8), padding bytes will be present at the end of each
- * row (including the last row).
- *
- * This format must be accepted by the gralloc module when used with the
- * following usage flags:
- * - GRALLOC_USAGE_HW_CAMERA_*
- * - GRALLOC_USAGE_SW_*
- * - GRALLOC_USAGE_RENDERSCRIPT
- *
- * When used with ANativeWindow, the dataSpace field should be
- * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
- * extra metadata to define.
- */
- HAL_PIXEL_FORMAT_RAW10 = 0x25,
-
- /*
- * Android RAW12 format:
- *
- * This format is exposed outside of camera HAL to applications.
- *
- * RAW12 is a single-channel, 12-bit per pixel, densely packed in each row,
- * unprocessed format, usually representing raw Bayer-pattern images coming from
- * an image sensor.
- *
- * In an image buffer with this format, starting from the first pixel of each
- * row, each two consecutive pixels are packed into 3 bytes (24 bits). The first
- * and second byte contains the top 8 bits of first and second pixel. The third
- * byte contains the 4 least significant bits of the two pixels, the exact layout
- * data for each two consecutive pixels is illustrated below (Pi[j] stands for
- * the jth bit of the ith pixel):
- *
- * bit 7 bit 0
- * ======|======|======|======|======|======|======|======|
- * Byte 0: |P0[11]|P0[10]|P0[ 9]|P0[ 8]|P0[ 7]|P0[ 6]|P0[ 5]|P0[ 4]|
- * |------|------|------|------|------|------|------|------|
- * Byte 1: |P1[11]|P1[10]|P1[ 9]|P1[ 8]|P1[ 7]|P1[ 6]|P1[ 5]|P1[ 4]|
- * |------|------|------|------|------|------|------|------|
- * Byte 2: |P1[ 3]|P1[ 2]|P1[ 1]|P1[ 0]|P0[ 3]|P0[ 2]|P0[ 1]|P0[ 0]|
- * =======================================================
- *
- * This format assumes:
- * - a width multiple of 4 pixels
- * - an even height
- * - a vertical stride equal to the height
- * - strides are specified in bytes, not in pixels
- *
- * size = stride * height
- *
- * When stride is equal to width * (12 / 8), there will be no padding bytes at
- * the end of each row, the entire image data is densely packed. When stride is
- * larger than width * (12 / 8), padding bytes will be present at the end of
- * each row (including the last row).
- *
- * This format must be accepted by the gralloc module when used with the
- * following usage flags:
- * - GRALLOC_USAGE_HW_CAMERA_*
- * - GRALLOC_USAGE_SW_*
- * - GRALLOC_USAGE_RENDERSCRIPT
- *
- * When used with ANativeWindow, the dataSpace field should be
- * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
- * extra metadata to define.
- */
- HAL_PIXEL_FORMAT_RAW12 = 0x26,
-
- /*
- * Android opaque RAW format:
- *
- * This format is exposed outside of the camera HAL to applications.
- *
- * RAW_OPAQUE is a format for unprocessed raw image buffers coming from an
- * image sensor. The actual structure of buffers of this format is
- * implementation-dependent.
- *
- * This format must be accepted by the gralloc module when used with the
- * following usage flags:
- * - GRALLOC_USAGE_HW_CAMERA_*
- * - GRALLOC_USAGE_SW_*
- * - GRALLOC_USAGE_RENDERSCRIPT
- *
- * When used with ANativeWindow, the dataSpace field should be
- * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
- * extra metadata to define.
- */
- HAL_PIXEL_FORMAT_RAW_OPAQUE = 0x24,
-
- /*
- * Android binary blob graphics buffer format:
- *
- * This format is used to carry task-specific data which does not have a
- * standard image structure. The details of the format are left to the two
- * endpoints.
- *
- * A typical use case is for transporting JPEG-compressed images from the
- * Camera HAL to the framework or to applications.
- *
- * Buffers of this format must have a height of 1, and width equal to their
- * size in bytes.
- *
- * When used with ANativeWindow, the mapping of the dataSpace field to
- * buffer contents for BLOB is as follows:
- *
- * dataSpace value | Buffer contents
- * -------------------------------+-----------------------------------------
- * HAL_DATASPACE_JFIF | An encoded JPEG image
- * HAL_DATASPACE_DEPTH | An android_depth_points buffer
- * Other | Unsupported
- *
- */
- HAL_PIXEL_FORMAT_BLOB = 0x21,
-
- /*
- * Android format indicating that the choice of format is entirely up to the
- * device-specific Gralloc implementation.
- *
- * The Gralloc implementation should examine the usage bits passed in when
- * allocating a buffer with this format, and it should derive the pixel
- * format from those usage flags. This format will never be used with any
- * of the GRALLOC_USAGE_SW_* usage flags.
- *
- * If a buffer of this format is to be used as an OpenGL ES texture, the
- * framework will assume that sampling the texture will always return an
- * alpha value of 1.0 (i.e. the buffer contains only opaque pixel values).
- *
- * When used with ANativeWindow, the dataSpace field describes the color
- * space of the buffer.
- */
- HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22,
-
- /*
- * Android flexible YCbCr 4:2:0 formats
- *
- * This format allows platforms to use an efficient YCbCr/YCrCb 4:2:0
- * buffer layout, while still describing the general format in a
- * layout-independent manner. While called YCbCr, it can be
- * used to describe formats with either chromatic ordering, as well as
- * whole planar or semiplanar layouts.
- *
- * struct android_ycbcr (below) is the the struct used to describe it.
- *
- * This format must be accepted by the gralloc module when
- * USAGE_SW_WRITE_* or USAGE_SW_READ_* are set.
- *
- * This format is locked for use by gralloc's (*lock_ycbcr) method, and
- * locking with the (*lock) method will return an error.
- *
- * When used with ANativeWindow, the dataSpace field describes the color
- * space of the buffer.
- */
- HAL_PIXEL_FORMAT_YCbCr_420_888 = 0x23,
-
- /*
- * Android flexible YCbCr 4:2:2 formats
- *
- * This format allows platforms to use an efficient YCbCr/YCrCb 4:2:2
- * buffer layout, while still describing the general format in a
- * layout-independent manner. While called YCbCr, it can be
- * used to describe formats with either chromatic ordering, as well as
- * whole planar or semiplanar layouts.
- *
- * This format is currently only used by SW readable buffers
- * produced by MediaCodecs, so the gralloc module can ignore this format.
- */
- HAL_PIXEL_FORMAT_YCbCr_422_888 = 0x27,
-
- /*
- * Android flexible YCbCr 4:4:4 formats
- *
- * This format allows platforms to use an efficient YCbCr/YCrCb 4:4:4
- * buffer layout, while still describing the general format in a
- * layout-independent manner. While called YCbCr, it can be
- * used to describe formats with either chromatic ordering, as well as
- * whole planar or semiplanar layouts.
- *
- * This format is currently only used by SW readable buffers
- * produced by MediaCodecs, so the gralloc module can ignore this format.
- */
- HAL_PIXEL_FORMAT_YCbCr_444_888 = 0x28,
-
- /*
- * Android flexible RGB 888 formats
- *
- * This format allows platforms to use an efficient RGB/BGR/RGBX/BGRX
- * buffer layout, while still describing the general format in a
- * layout-independent manner. While called RGB, it can be
- * used to describe formats with either color ordering and optional
- * padding, as well as whole planar layout.
- *
- * This format is currently only used by SW readable buffers
- * produced by MediaCodecs, so the gralloc module can ignore this format.
- */
- HAL_PIXEL_FORMAT_FLEX_RGB_888 = 0x29,
-
- /*
- * Android flexible RGBA 8888 formats
- *
- * This format allows platforms to use an efficient RGBA/BGRA/ARGB/ABGR
- * buffer layout, while still describing the general format in a
- * layout-independent manner. While called RGBA, it can be
- * used to describe formats with any of the component orderings, as
- * well as whole planar layout.
- *
- * This format is currently only used by SW readable buffers
- * produced by MediaCodecs, so the gralloc module can ignore this format.
- */
- HAL_PIXEL_FORMAT_FLEX_RGBA_8888 = 0x2A,
-
- /* Legacy formats (deprecated), used by ImageFormat.java */
- HAL_PIXEL_FORMAT_YCbCr_422_SP = 0x10, // NV16
- HAL_PIXEL_FORMAT_YCrCb_420_SP = 0x11, // NV21
- HAL_PIXEL_FORMAT_YCbCr_422_I = 0x14, // YUY2
-} android_pixel_format_t;
-
/*
* Structure for describing YCbCr formats for consumption by applications.
* This is used with HAL_PIXEL_FORMAT_YCbCr_*_888.
@@ -622,797 +237,6 @@
#endif
};
-/**
- * Transformation definitions
- *
- * IMPORTANT NOTE:
- * HAL_TRANSFORM_ROT_90 is applied CLOCKWISE and AFTER HAL_TRANSFORM_FLIP_{H|V}.
- *
- */
-
-typedef enum android_transform {
- /* flip source image horizontally (around the vertical axis) */
- HAL_TRANSFORM_FLIP_H = 0x01,
- /* flip source image vertically (around the horizontal axis)*/
- HAL_TRANSFORM_FLIP_V = 0x02,
- /* rotate source image 90 degrees clockwise */
- HAL_TRANSFORM_ROT_90 = 0x04,
- /* rotate source image 180 degrees */
- HAL_TRANSFORM_ROT_180 = 0x03,
- /* rotate source image 270 degrees clockwise */
- HAL_TRANSFORM_ROT_270 = 0x07,
- /* don't use. see system/window.h */
- HAL_TRANSFORM_RESERVED = 0x08,
-} android_transform_t;
-
-/**
- * Dataspace Definitions
- * ======================
- *
- * Dataspace is the definition of how pixel values should be interpreted.
- *
- * For many formats, this is the colorspace of the image data, which includes
- * primaries (including white point) and the transfer characteristic function,
- * which describes both gamma curve and numeric range (within the bit depth).
- *
- * Other dataspaces include depth measurement data from a depth camera.
- *
- * A dataspace is comprised of a number of fields.
- *
- * Version
- * --------
- * The top 2 bits represent the revision of the field specification. This is
- * currently always 0.
- *
- *
- * bits 31-30 29 - 0
- * +-----+----------------------------------------------------+
- * fields | Rev | Revision specific fields |
- * +-----+----------------------------------------------------+
- *
- * Field layout for version = 0:
- * ----------------------------
- *
- * A dataspace is comprised of the following fields:
- * Standard
- * Transfer function
- * Range
- *
- * bits 31-30 29-27 26 - 22 21 - 16 15 - 0
- * +-----+-----+--------+--------+----------------------------+
- * fields | 0 |Range|Transfer|Standard| Legacy and custom |
- * +-----+-----+--------+--------+----------------------------+
- * VV RRR TTTTT SSSSSS LLLLLLLL LLLLLLLL
- *
- * If range, transfer and standard fields are all 0 (e.g. top 16 bits are
- * all zeroes), the bottom 16 bits contain either a legacy dataspace value,
- * or a custom value.
- */
-
-typedef enum android_dataspace {
- /*
- * Default-assumption data space, when not explicitly specified.
- *
- * It is safest to assume the buffer is an image with sRGB primaries and
- * encoding ranges, but the consumer and/or the producer of the data may
- * simply be using defaults. No automatic gamma transform should be
- * expected, except for a possible display gamma transform when drawn to a
- * screen.
- */
- HAL_DATASPACE_UNKNOWN = 0x0,
-
- /*
- * Arbitrary dataspace with manually defined characteristics. Definition
- * for colorspaces or other meaning must be communicated separately.
- *
- * This is used when specifying primaries, transfer characteristics,
- * etc. separately.
- *
- * A typical use case is in video encoding parameters (e.g. for H.264),
- * where a colorspace can have separately defined primaries, transfer
- * characteristics, etc.
- */
- HAL_DATASPACE_ARBITRARY = 0x1,
-
- /*
- * Color-description aspects
- *
- * The following aspects define various characteristics of the color
- * specification. These represent bitfields, so that a data space value
- * can specify each of them independently.
- */
-
- HAL_DATASPACE_STANDARD_SHIFT = 16,
-
- /*
- * Standard aspect
- *
- * Defines the chromaticity coordinates of the source primaries in terms of
- * the CIE 1931 definition of x and y specified in ISO 11664-1.
- */
- HAL_DATASPACE_STANDARD_MASK = 63 << HAL_DATASPACE_STANDARD_SHIFT, // 0x3F
-
- /*
- * Chromacity coordinates are unknown or are determined by the application.
- * Implementations shall use the following suggested standards:
- *
- * All YCbCr formats: BT709 if size is 720p or larger (since most video
- * content is letterboxed this corresponds to width is
- * 1280 or greater, or height is 720 or greater).
- * BT601_625 if size is smaller than 720p or is JPEG.
- * All RGB formats: BT709.
- *
- * For all other formats standard is undefined, and implementations should use
- * an appropriate standard for the data represented.
- */
- HAL_DATASPACE_STANDARD_UNSPECIFIED = 0 << HAL_DATASPACE_STANDARD_SHIFT,
-
- /*
- * Primaries: x y
- * green 0.300 0.600
- * blue 0.150 0.060
- * red 0.640 0.330
- * white (D65) 0.3127 0.3290
- *
- * Use the unadjusted KR = 0.2126, KB = 0.0722 luminance interpretation
- * for RGB conversion.
- */
- HAL_DATASPACE_STANDARD_BT709 = 1 << HAL_DATASPACE_STANDARD_SHIFT,
-
- /*
- * Primaries: x y
- * green 0.290 0.600
- * blue 0.150 0.060
- * red 0.640 0.330
- * white (D65) 0.3127 0.3290
- *
- * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
- * for RGB conversion from the one purely determined by the primaries
- * to minimize the color shift into RGB space that uses BT.709
- * primaries.
- */
- HAL_DATASPACE_STANDARD_BT601_625 = 2 << HAL_DATASPACE_STANDARD_SHIFT,
-
- /*
- * Primaries: x y
- * green 0.290 0.600
- * blue 0.150 0.060
- * red 0.640 0.330
- * white (D65) 0.3127 0.3290
- *
- * Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation
- * for RGB conversion.
- */
- HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED = 3 << HAL_DATASPACE_STANDARD_SHIFT,
-
- /*
- * Primaries: x y
- * green 0.310 0.595
- * blue 0.155 0.070
- * red 0.630 0.340
- * white (D65) 0.3127 0.3290
- *
- * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
- * for RGB conversion from the one purely determined by the primaries
- * to minimize the color shift into RGB space that uses BT.709
- * primaries.
- */
- HAL_DATASPACE_STANDARD_BT601_525 = 4 << HAL_DATASPACE_STANDARD_SHIFT,
-
- /*
- * Primaries: x y
- * green 0.310 0.595
- * blue 0.155 0.070
- * red 0.630 0.340
- * white (D65) 0.3127 0.3290
- *
- * Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation
- * for RGB conversion (as in SMPTE 240M).
- */
- HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED = 5 << HAL_DATASPACE_STANDARD_SHIFT,
-
- /*
- * Primaries: x y
- * green 0.170 0.797
- * blue 0.131 0.046
- * red 0.708 0.292
- * white (D65) 0.3127 0.3290
- *
- * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
- * for RGB conversion.
- */
- HAL_DATASPACE_STANDARD_BT2020 = 6 << HAL_DATASPACE_STANDARD_SHIFT,
-
- /*
- * Primaries: x y
- * green 0.170 0.797
- * blue 0.131 0.046
- * red 0.708 0.292
- * white (D65) 0.3127 0.3290
- *
- * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
- * for RGB conversion using the linear domain.
- */
- HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE = 7 << HAL_DATASPACE_STANDARD_SHIFT,
-
- /*
- * Primaries: x y
- * green 0.21 0.71
- * blue 0.14 0.08
- * red 0.67 0.33
- * white (C) 0.310 0.316
- *
- * Use the unadjusted KR = 0.30, KB = 0.11 luminance interpretation
- * for RGB conversion.
- */
- HAL_DATASPACE_STANDARD_BT470M = 8 << HAL_DATASPACE_STANDARD_SHIFT,
-
- /*
- * Primaries: x y
- * green 0.243 0.692
- * blue 0.145 0.049
- * red 0.681 0.319
- * white (C) 0.310 0.316
- *
- * Use the unadjusted KR = 0.254, KB = 0.068 luminance interpretation
- * for RGB conversion.
- */
- HAL_DATASPACE_STANDARD_FILM = 9 << HAL_DATASPACE_STANDARD_SHIFT,
-
- HAL_DATASPACE_TRANSFER_SHIFT = 22,
-
- /*
- * Transfer aspect
- *
- * Transfer characteristics are the opto-electronic transfer characteristic
- * at the source as a function of linear optical intensity (luminance).
- *
- * For digital signals, E corresponds to the recorded value. Normally, the
- * transfer function is applied in RGB space to each of the R, G and B
- * components independently. This may result in color shift that can be
- * minized by applying the transfer function in Lab space only for the L
- * component. Implementation may apply the transfer function in RGB space
- * for all pixel formats if desired.
- */
-
- HAL_DATASPACE_TRANSFER_MASK = 31 << HAL_DATASPACE_TRANSFER_SHIFT, // 0x1F
-
- /*
- * Transfer characteristics are unknown or are determined by the
- * application.
- *
- * Implementations should use the following transfer functions:
- *
- * For YCbCr formats: use HAL_DATASPACE_TRANSFER_SMPTE_170M
- * For RGB formats: use HAL_DATASPACE_TRANSFER_SRGB
- *
- * For all other formats transfer function is undefined, and implementations
- * should use an appropriate standard for the data represented.
- */
- HAL_DATASPACE_TRANSFER_UNSPECIFIED = 0 << HAL_DATASPACE_TRANSFER_SHIFT,
-
- /*
- * Transfer characteristic curve:
- * E = L
- * L - luminance of image 0 <= L <= 1 for conventional colorimetry
- * E - corresponding electrical signal
- */
- HAL_DATASPACE_TRANSFER_LINEAR = 1 << HAL_DATASPACE_TRANSFER_SHIFT,
-
- /*
- * Transfer characteristic curve:
- *
- * E = 1.055 * L^(1/2.4) - 0.055 for 0.0031308 <= L <= 1
- * = 12.92 * L for 0 <= L < 0.0031308
- * L - luminance of image 0 <= L <= 1 for conventional colorimetry
- * E - corresponding electrical signal
- */
- HAL_DATASPACE_TRANSFER_SRGB = 2 << HAL_DATASPACE_TRANSFER_SHIFT,
-
- /*
- * BT.601 525, BT.601 625, BT.709, BT.2020
- *
- * Transfer characteristic curve:
- * E = 1.099 * L ^ 0.45 - 0.099 for 0.018 <= L <= 1
- * = 4.500 * L for 0 <= L < 0.018
- * L - luminance of image 0 <= L <= 1 for conventional colorimetry
- * E - corresponding electrical signal
- */
- HAL_DATASPACE_TRANSFER_SMPTE_170M = 3 << HAL_DATASPACE_TRANSFER_SHIFT,
-
- /*
- * Assumed display gamma 2.2.
- *
- * Transfer characteristic curve:
- * E = L ^ (1/2.2)
- * L - luminance of image 0 <= L <= 1 for conventional colorimetry
- * E - corresponding electrical signal
- */
- HAL_DATASPACE_TRANSFER_GAMMA2_2 = 4 << HAL_DATASPACE_TRANSFER_SHIFT,
-
- /*
- * display gamma 2.8.
- *
- * Transfer characteristic curve:
- * E = L ^ (1/2.8)
- * L - luminance of image 0 <= L <= 1 for conventional colorimetry
- * E - corresponding electrical signal
- */
- HAL_DATASPACE_TRANSFER_GAMMA2_8 = 5 << HAL_DATASPACE_TRANSFER_SHIFT,
-
- /*
- * SMPTE ST 2084
- *
- * Transfer characteristic curve:
- * E = ((c1 + c2 * L^n) / (1 + c3 * L^n)) ^ m
- * c1 = c3 - c2 + 1 = 3424 / 4096 = 0.8359375
- * c2 = 32 * 2413 / 4096 = 18.8515625
- * c3 = 32 * 2392 / 4096 = 18.6875
- * m = 128 * 2523 / 4096 = 78.84375
- * n = 0.25 * 2610 / 4096 = 0.1593017578125
- * L - luminance of image 0 <= L <= 1 for HDR colorimetry.
- * L = 1 corresponds to 10000 cd/m2
- * E - corresponding electrical signal
- */
- HAL_DATASPACE_TRANSFER_ST2084 = 6 << HAL_DATASPACE_TRANSFER_SHIFT,
-
- /*
- * ARIB STD-B67 Hybrid Log Gamma
- *
- * Transfer characteristic curve:
- * E = r * L^0.5 for 0 <= L <= 1
- * = a * ln(L - b) + c for 1 < L
- * a = 0.17883277
- * b = 0.28466892
- * c = 0.55991073
- * r = 0.5
- * L - luminance of image 0 <= L for HDR colorimetry. L = 1 corresponds
- * to reference white level of 100 cd/m2
- * E - corresponding electrical signal
- */
- HAL_DATASPACE_TRANSFER_HLG = 7 << HAL_DATASPACE_TRANSFER_SHIFT,
-
- HAL_DATASPACE_RANGE_SHIFT = 27,
-
- /*
- * Range aspect
- *
- * Defines the range of values corresponding to the unit range of 0-1.
- * This is defined for YCbCr only, but can be expanded to RGB space.
- */
- HAL_DATASPACE_RANGE_MASK = 7 << HAL_DATASPACE_RANGE_SHIFT, // 0x7
-
- /*
- * Range is unknown or are determined by the application. Implementations
- * shall use the following suggested ranges:
- *
- * All YCbCr formats: limited range.
- * All RGB or RGBA formats (including RAW and Bayer): full range.
- * All Y formats: full range
- *
- * For all other formats range is undefined, and implementations should use
- * an appropriate range for the data represented.
- */
- HAL_DATASPACE_RANGE_UNSPECIFIED = 0 << HAL_DATASPACE_RANGE_SHIFT,
-
- /*
- * Full range uses all values for Y, Cb and Cr from
- * 0 to 2^b-1, where b is the bit depth of the color format.
- */
- HAL_DATASPACE_RANGE_FULL = 1 << HAL_DATASPACE_RANGE_SHIFT,
-
- /*
- * Limited range uses values 16/256*2^b to 235/256*2^b for Y, and
- * 1/16*2^b to 15/16*2^b for Cb, Cr, R, G and B, where b is the bit depth of
- * the color format.
- *
- * E.g. For 8-bit-depth formats:
- * Luma (Y) samples should range from 16 to 235, inclusive
- * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
- *
- * For 10-bit-depth formats:
- * Luma (Y) samples should range from 64 to 940, inclusive
- * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
- */
- HAL_DATASPACE_RANGE_LIMITED = 2 << HAL_DATASPACE_RANGE_SHIFT,
-
- /*
- * Legacy dataspaces
- */
-
- /*
- * sRGB linear encoding:
- *
- * The red, green, and blue components are stored in sRGB space, but
- * are linear, not gamma-encoded.
- * The RGB primaries and the white point are the same as BT.709.
- *
- * The values are encoded using the full range ([0,255] for 8-bit) for all
- * components.
- */
- HAL_DATASPACE_SRGB_LINEAR = 0x200, // deprecated, use HAL_DATASPACE_V0_SRGB_LINEAR
-
- HAL_DATASPACE_V0_SRGB_LINEAR = HAL_DATASPACE_STANDARD_BT709 |
- HAL_DATASPACE_TRANSFER_LINEAR | HAL_DATASPACE_RANGE_FULL,
-
-
- /*
- * sRGB gamma encoding:
- *
- * The red, green and blue components are stored in sRGB space, and
- * converted to linear space when read, using the SRGB transfer function
- * for each of the R, G and B components. When written, the inverse
- * transformation is performed.
- *
- * The alpha component, if present, is always stored in linear space and
- * is left unmodified when read or written.
- *
- * Use full range and BT.709 standard.
- */
- HAL_DATASPACE_SRGB = 0x201, // deprecated, use HAL_DATASPACE_V0_SRGB
-
- HAL_DATASPACE_V0_SRGB = HAL_DATASPACE_STANDARD_BT709 |
- HAL_DATASPACE_TRANSFER_SRGB | HAL_DATASPACE_RANGE_FULL,
-
-
- /*
- * YCbCr Colorspaces
- * -----------------
- *
- * Primaries are given using (x,y) coordinates in the CIE 1931 definition
- * of x and y specified by ISO 11664-1.
- *
- * Transfer characteristics are the opto-electronic transfer characteristic
- * at the source as a function of linear optical intensity (luminance).
- */
-
- /*
- * JPEG File Interchange Format (JFIF)
- *
- * Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255
- *
- * Use full range, BT.601 transfer and BT.601_625 standard.
- */
- HAL_DATASPACE_JFIF = 0x101, // deprecated, use HAL_DATASPACE_V0_JFIF
-
- HAL_DATASPACE_V0_JFIF = HAL_DATASPACE_STANDARD_BT601_625 |
- HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_FULL,
-
- /*
- * ITU-R Recommendation 601 (BT.601) - 625-line
- *
- * Standard-definition television, 625 Lines (PAL)
- *
- * Use limited range, BT.601 transfer and BT.601_625 standard.
- */
- HAL_DATASPACE_BT601_625 = 0x102, // deprecated, use HAL_DATASPACE_V0_BT601_625
-
- HAL_DATASPACE_V0_BT601_625 = HAL_DATASPACE_STANDARD_BT601_625 |
- HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_LIMITED,
-
-
- /*
- * ITU-R Recommendation 601 (BT.601) - 525-line
- *
- * Standard-definition television, 525 Lines (NTSC)
- *
- * Use limited range, BT.601 transfer and BT.601_525 standard.
- */
- HAL_DATASPACE_BT601_525 = 0x103, // deprecated, use HAL_DATASPACE_V0_BT601_525
-
- HAL_DATASPACE_V0_BT601_525 = HAL_DATASPACE_STANDARD_BT601_525 |
- HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_LIMITED,
-
- /*
- * ITU-R Recommendation 709 (BT.709)
- *
- * High-definition television
- *
- * Use limited range, BT.709 transfer and BT.709 standard.
- */
- HAL_DATASPACE_BT709 = 0x104, // deprecated, use HAL_DATASPACE_V0_BT709
-
- HAL_DATASPACE_V0_BT709 = HAL_DATASPACE_STANDARD_BT709 |
- HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_LIMITED,
-
- /*
- * Data spaces for non-color formats
- */
-
- /*
- * The buffer contains depth ranging measurements from a depth camera.
- * This value is valid with formats:
- * HAL_PIXEL_FORMAT_Y16: 16-bit samples, consisting of a depth measurement
- * and an associated confidence value. The 3 MSBs of the sample make
- * up the confidence value, and the low 13 LSBs of the sample make up
- * the depth measurement.
- * For the confidence section, 0 means 100% confidence, 1 means 0%
- * confidence. The mapping to a linear float confidence value between
- * 0.f and 1.f can be obtained with
- * float confidence = (((depthSample >> 13) - 1) & 0x7) / 7.0f;
- * The depth measurement can be extracted simply with
- * uint16_t range = (depthSample & 0x1FFF);
- * HAL_PIXEL_FORMAT_BLOB: A depth point cloud, as
- * a variable-length float (x,y,z, confidence) coordinate point list.
- * The point cloud will be represented with the android_depth_points
- * structure.
- */
- HAL_DATASPACE_DEPTH = 0x1000
-
-} android_dataspace_t;
-
-/*
- * Color modes that may be supported by a display.
- *
- * Definitions:
- * Rendering intent generally defines the goal in mapping a source (input)
- * color to a destination device color for a given color mode.
- *
- * It is important to keep in mind three cases where mapping may be applied:
- * 1. The source gamut is much smaller than the destination (display) gamut
- * 2. The source gamut is much larger than the destination gamut (this will
- * ordinarily be handled using colorimetric rendering, below)
- * 3. The source and destination gamuts are roughly equal, although not
- * completely overlapping
- * Also, a common requirement for mappings is that skin tones should be
- * preserved, or at least remain natural in appearance.
- *
- * Colorimetric Rendering Intent (All cases):
- * Colorimetric indicates that colors should be preserved. In the case
- * that the source gamut lies wholly within the destination gamut or is
- * about the same (#1, #3), this will simply mean that no manipulations
- * (no saturation boost, for example) are applied. In the case where some
- * source colors lie outside the destination gamut (#2, #3), those will
- * need to be mapped to colors that are within the destination gamut,
- * while the already in-gamut colors remain unchanged.
- *
- * Non-colorimetric transforms can take many forms. There are no hard
- * rules and it's left to the implementation to define.
- * Two common intents are described below.
- *
- * Stretched-Gamut Enhancement Intent (Source < Destination):
- * When the destination gamut is much larger than the source gamut (#1), the
- * source primaries may be redefined to reflect the full extent of the
- * destination space, or to reflect an intermediate gamut.
- * Skin-tone preservation would likely be applied. An example might be sRGB
- * input displayed on a DCI-P3 capable device, with skin-tone preservation.
- *
- * Within-Gamut Enhancement Intent (Source >= Destination):
- * When the device (destination) gamut is not larger than the source gamut
- * (#2 or #3), but the appearance of a larger gamut is desired, techniques
- * such as saturation boost may be applied to the source colors. Skin-tone
- * preservation may be applied. There is no unique method for within-gamut
- * enhancement; it would be defined within a flexible color mode.
- *
- */
-typedef enum android_color_mode {
-
- /*
- * HAL_COLOR_MODE_DEFAULT is the "native" gamut of the display.
- * White Point: Vendor/OEM defined
- * Panel Gamma: Vendor/OEM defined (typically 2.2)
- * Rendering Intent: Vendor/OEM defined (typically 'enhanced')
- */
- HAL_COLOR_MODE_NATIVE = 0,
-
- /*
- * HAL_COLOR_MODE_STANDARD_BT601_625 corresponds with display
- * settings that implement the ITU-R Recommendation BT.601
- * or Rec 601. Using 625 line version
- * Rendering Intent: Colorimetric
- * Primaries:
- * x y
- * green 0.290 0.600
- * blue 0.150 0.060
- * red 0.640 0.330
- * white (D65) 0.3127 0.3290
- *
- * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
- * for RGB conversion from the one purely determined by the primaries
- * to minimize the color shift into RGB space that uses BT.709
- * primaries.
- *
- * Gamma Correction (GC):
- *
- * if Vlinear < 0.018
- * Vnonlinear = 4.500 * Vlinear
- * else
- * Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
- */
- HAL_COLOR_MODE_STANDARD_BT601_625 = 1,
-
- /*
- * Primaries:
- * x y
- * green 0.290 0.600
- * blue 0.150 0.060
- * red 0.640 0.330
- * white (D65) 0.3127 0.3290
- *
- * Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation
- * for RGB conversion.
- *
- * Gamma Correction (GC):
- *
- * if Vlinear < 0.018
- * Vnonlinear = 4.500 * Vlinear
- * else
- * Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
- */
- HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED = 2,
-
- /*
- * Primaries:
- * x y
- * green 0.310 0.595
- * blue 0.155 0.070
- * red 0.630 0.340
- * white (D65) 0.3127 0.3290
- *
- * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
- * for RGB conversion from the one purely determined by the primaries
- * to minimize the color shift into RGB space that uses BT.709
- * primaries.
- *
- * Gamma Correction (GC):
- *
- * if Vlinear < 0.018
- * Vnonlinear = 4.500 * Vlinear
- * else
- * Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
- */
- HAL_COLOR_MODE_STANDARD_BT601_525 = 3,
-
- /*
- * Primaries:
- * x y
- * green 0.310 0.595
- * blue 0.155 0.070
- * red 0.630 0.340
- * white (D65) 0.3127 0.3290
- *
- * Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation
- * for RGB conversion (as in SMPTE 240M).
- *
- * Gamma Correction (GC):
- *
- * if Vlinear < 0.018
- * Vnonlinear = 4.500 * Vlinear
- * else
- * Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
- */
- HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED = 4,
-
- /*
- * HAL_COLOR_MODE_REC709 corresponds with display settings that implement
- * the ITU-R Recommendation BT.709 / Rec. 709 for high-definition television.
- * Rendering Intent: Colorimetric
- * Primaries:
- * x y
- * green 0.300 0.600
- * blue 0.150 0.060
- * red 0.640 0.330
- * white (D65) 0.3127 0.3290
- *
- * HDTV REC709 Inverse Gamma Correction (IGC): V represents normalized
- * (with [0 to 1] range) value of R, G, or B.
- *
- * if Vnonlinear < 0.081
- * Vlinear = Vnonlinear / 4.5
- * else
- * Vlinear = ((Vnonlinear + 0.099) / 1.099) ^ (1/0.45)
- *
- * HDTV REC709 Gamma Correction (GC):
- *
- * if Vlinear < 0.018
- * Vnonlinear = 4.5 * Vlinear
- * else
- * Vnonlinear = 1.099 * (Vlinear) ^ 0.45 – 0.099
- */
- HAL_COLOR_MODE_STANDARD_BT709 = 5,
-
- /*
- * HAL_COLOR_MODE_DCI_P3 corresponds with display settings that implement
- * SMPTE EG 432-1 and SMPTE RP 431-2
- * Rendering Intent: Colorimetric
- * Primaries:
- * x y
- * green 0.265 0.690
- * blue 0.150 0.060
- * red 0.680 0.320
- * white (D65) 0.3127 0.3290
- *
- * Gamma: 2.2
- */
- HAL_COLOR_MODE_DCI_P3 = 6,
-
- /*
- * HAL_COLOR_MODE_SRGB corresponds with display settings that implement
- * the sRGB color space. Uses the same primaries as ITU-R Recommendation
- * BT.709
- * Rendering Intent: Colorimetric
- * Primaries:
- * x y
- * green 0.300 0.600
- * blue 0.150 0.060
- * red 0.640 0.330
- * white (D65) 0.3127 0.3290
- *
- * PC/Internet (sRGB) Inverse Gamma Correction (IGC):
- *
- * if Vnonlinear ≤ 0.03928
- * Vlinear = Vnonlinear / 12.92
- * else
- * Vlinear = ((Vnonlinear + 0.055)/1.055) ^ 2.4
- *
- * PC/Internet (sRGB) Gamma Correction (GC):
- *
- * if Vlinear ≤ 0.0031308
- * Vnonlinear = 12.92 * Vlinear
- * else
- * Vnonlinear = 1.055 * (Vlinear)^(1/2.4) – 0.055
- */
- HAL_COLOR_MODE_SRGB = 7,
-
- /*
- * HAL_COLOR_MODE_ADOBE_RGB corresponds with the RGB color space developed
- * by Adobe Systems, Inc. in 1998.
- * Rendering Intent: Colorimetric
- * Primaries:
- * x y
- * green 0.210 0.710
- * blue 0.150 0.060
- * red 0.640 0.330
- * white (D65) 0.3127 0.3290
- *
- * Gamma: 2.2
- */
- HAL_COLOR_MODE_ADOBE_RGB = 8
-
-} android_color_mode_t;
-
-/*
- * Color transforms that may be applied by hardware composer to the whole
- * display.
- */
-typedef enum android_color_transform {
- /* Applies no transform to the output color */
- HAL_COLOR_TRANSFORM_IDENTITY = 0,
-
- /* Applies an arbitrary transform defined by a 4x4 affine matrix */
- HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX = 1,
-
- /* Applies a transform that inverts the value or luminance of the color, but
- * does not modify hue or saturation */
- HAL_COLOR_TRANSFORM_VALUE_INVERSE = 2,
-
- /* Applies a transform that maps all colors to shades of gray */
- HAL_COLOR_TRANSFORM_GRAYSCALE = 3,
-
- /* Applies a transform which corrects for protanopic color blindness */
- HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA = 4,
-
- /* Applies a transform which corrects for deuteranopic color blindness */
- HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA = 5,
-
- /* Applies a transform which corrects for tritanopic color blindness */
- HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA = 6
-} android_color_transform_t;
-
-/*
- * Supported HDR formats. Must be kept in sync with equivalents in Display.java.
- */
-typedef enum android_hdr {
- /* Device supports Dolby Vision HDR */
- HAL_HDR_DOLBY_VISION = 1,
-
- /* Device supports HDR10 */
- HAL_HDR_HDR10 = 2,
-
- /* Device supports hybrid log-gamma HDR */
- HAL_HDR_HLG = 3
-} android_hdr_t;
-
#ifdef __cplusplus
}
#endif
diff --git a/init/Android.mk b/init/Android.mk
index 1be064c..442a5f3 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -45,6 +45,8 @@
LOCAL_CPPFLAGS := $(init_cflags)
LOCAL_SRC_FILES:= \
action.cpp \
+ capabilities.cpp \
+ descriptors.cpp \
import_parser.cpp \
init_parser.cpp \
log.cpp \
@@ -53,6 +55,7 @@
util.cpp \
LOCAL_STATIC_LIBRARIES := libbase libselinux liblog libprocessgroup
+LOCAL_WHOLE_STATIC_LIBRARIES := libcap
LOCAL_MODULE := libinit
LOCAL_SANITIZE := integer
LOCAL_CLANG := true
@@ -102,7 +105,7 @@
libz \
libprocessgroup
-# Create symlinks
+# Create symlinks.
LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \
ln -sf ../init $(TARGET_ROOT_OUT)/sbin/ueventd; \
ln -sf ../init $(TARGET_ROOT_OUT)/sbin/watchdogd
@@ -112,8 +115,8 @@
include $(BUILD_EXECUTABLE)
-
-
+# Unit tests.
+# =========================================================
include $(CLEAR_VARS)
LOCAL_MODULE := init_tests
LOCAL_SRC_FILES := \
@@ -123,8 +126,10 @@
LOCAL_SHARED_LIBRARIES += \
libcutils \
libbase \
+ libselinux \
LOCAL_STATIC_LIBRARIES := libinit
LOCAL_SANITIZE := integer
LOCAL_CLANG := true
+LOCAL_CPPFLAGS := -Wall -Wextra -Werror
include $(BUILD_NATIVE_TEST)
diff --git a/init/bootchart.cpp b/init/bootchart.cpp
index 467a838..8fb55f0 100644
--- a/init/bootchart.cpp
+++ b/init/bootchart.cpp
@@ -241,6 +241,7 @@
fclose(log_disks);
fclose(log_procs);
acct(NULL);
+ LOG(INFO) << "Bootcharting finished";
}
void bootchart_sample(int* timeout) {
@@ -253,12 +254,12 @@
int elapsed_time = current_time - g_last_bootchart_time;
if (elapsed_time >= BOOTCHART_POLLING_MS) {
- /* count missed samples */
+ // Count missed samples.
while (elapsed_time >= BOOTCHART_POLLING_MS) {
elapsed_time -= BOOTCHART_POLLING_MS;
g_remaining_samples--;
}
- /* count may be negative, take a sample anyway */
+ // Count may be negative, take a sample anyway.
g_last_bootchart_time = current_time;
if (bootchart_step() < 0 || g_remaining_samples <= 0) {
bootchart_finish();
diff --git a/init/capabilities.cpp b/init/capabilities.cpp
new file mode 100644
index 0000000..4592adc
--- /dev/null
+++ b/init/capabilities.cpp
@@ -0,0 +1,166 @@
+// 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 "capabilities.h"
+
+#include <sys/capability.h>
+#include <sys/prctl.h>
+
+#include <map>
+#include <memory>
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+
+#define CAP_MAP_ENTRY(cap) { #cap, CAP_##cap }
+
+namespace {
+const std::map<std::string, int> cap_map = {
+ CAP_MAP_ENTRY(CHOWN),
+ CAP_MAP_ENTRY(DAC_OVERRIDE),
+ CAP_MAP_ENTRY(DAC_READ_SEARCH),
+ CAP_MAP_ENTRY(FOWNER),
+ CAP_MAP_ENTRY(FSETID),
+ CAP_MAP_ENTRY(KILL),
+ CAP_MAP_ENTRY(SETGID),
+ CAP_MAP_ENTRY(SETUID),
+ CAP_MAP_ENTRY(SETPCAP),
+ CAP_MAP_ENTRY(LINUX_IMMUTABLE),
+ CAP_MAP_ENTRY(NET_BIND_SERVICE),
+ CAP_MAP_ENTRY(NET_BROADCAST),
+ CAP_MAP_ENTRY(NET_ADMIN),
+ CAP_MAP_ENTRY(NET_RAW),
+ CAP_MAP_ENTRY(IPC_LOCK),
+ CAP_MAP_ENTRY(IPC_OWNER),
+ CAP_MAP_ENTRY(SYS_MODULE),
+ CAP_MAP_ENTRY(SYS_RAWIO),
+ CAP_MAP_ENTRY(SYS_CHROOT),
+ CAP_MAP_ENTRY(SYS_PTRACE),
+ CAP_MAP_ENTRY(SYS_PACCT),
+ CAP_MAP_ENTRY(SYS_ADMIN),
+ CAP_MAP_ENTRY(SYS_BOOT),
+ CAP_MAP_ENTRY(SYS_NICE),
+ CAP_MAP_ENTRY(SYS_RESOURCE),
+ CAP_MAP_ENTRY(SYS_TIME),
+ CAP_MAP_ENTRY(SYS_TTY_CONFIG),
+ CAP_MAP_ENTRY(MKNOD),
+ CAP_MAP_ENTRY(LEASE),
+ CAP_MAP_ENTRY(AUDIT_WRITE),
+ CAP_MAP_ENTRY(AUDIT_CONTROL),
+ CAP_MAP_ENTRY(SETFCAP),
+ CAP_MAP_ENTRY(MAC_OVERRIDE),
+ CAP_MAP_ENTRY(MAC_ADMIN),
+ CAP_MAP_ENTRY(SYSLOG),
+ CAP_MAP_ENTRY(WAKE_ALARM),
+ CAP_MAP_ENTRY(BLOCK_SUSPEND),
+ CAP_MAP_ENTRY(AUDIT_READ),
+};
+
+static_assert(CAP_LAST_CAP == CAP_AUDIT_READ, "CAP_LAST_CAP is not CAP_AUDIT_READ");
+
+bool DropBoundingSet(const CapSet& to_keep) {
+ for (size_t cap = 0; cap < to_keep.size(); ++cap) {
+ if (to_keep.test(cap)) {
+ // No need to drop this capability.
+ continue;
+ }
+ if (cap_drop_bound(cap) == -1) {
+ PLOG(ERROR) << "cap_drop_bound(" << cap << ") failed";
+ return false;
+ }
+ }
+ return true;
+}
+
+bool SetProcCaps(const CapSet& to_keep, bool add_setpcap) {
+ cap_t caps = cap_init();
+ auto deleter = [](cap_t* p) { cap_free(*p); };
+ std::unique_ptr<cap_t, decltype(deleter)> ptr_caps(&caps, deleter);
+
+ cap_clear(caps);
+ cap_value_t value[1];
+ for (size_t cap = 0; cap <= to_keep.size(); ++cap) {
+ if (to_keep.test(cap)) {
+ value[0] = cap;
+ if (cap_set_flag(caps, CAP_INHERITABLE, arraysize(value), value, CAP_SET) != 0 ||
+ cap_set_flag(caps, CAP_PERMITTED, arraysize(value), value, CAP_SET) != 0) {
+ PLOG(ERROR) << "cap_set_flag(INHERITABLE|PERMITTED, " << cap << ") failed";
+ return false;
+ }
+ }
+ }
+
+ if (add_setpcap) {
+ value[0] = CAP_SETPCAP;
+ if (cap_set_flag(caps, CAP_PERMITTED, arraysize(value), value, CAP_SET) != 0 ||
+ cap_set_flag(caps, CAP_EFFECTIVE, arraysize(value), value, CAP_SET) != 0) {
+ PLOG(ERROR) << "cap_set_flag(PERMITTED|EFFECTIVE, " << CAP_SETPCAP << ") failed";
+ return false;
+ }
+ }
+
+ if (cap_set_proc(caps) != 0) {
+ PLOG(ERROR) << "cap_set_proc(" << to_keep.to_ulong() << ") failed";
+ return false;
+ }
+ return true;
+}
+
+bool SetAmbientCaps(const CapSet& to_raise) {
+ for (size_t cap = 0; cap < to_raise.size(); ++cap) {
+ if (to_raise.test(cap)) {
+ if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0) != 0) {
+ PLOG(ERROR) << "prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, " << cap << ") failed";
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+} // namespace anonymous
+
+int LookupCap(const std::string& cap_name) {
+ auto e = cap_map.find(cap_name);
+ if (e != cap_map.end()) {
+ return e->second;
+ } else {
+ return -1;
+ }
+}
+
+bool SetCapsForExec(const CapSet& to_keep) {
+ // Need to keep SETPCAP to drop bounding set below.
+ bool add_setpcap = true;
+ if (!SetProcCaps(to_keep, add_setpcap)) {
+ LOG(ERROR) << "failed to apply initial capset";
+ return false;
+ }
+
+ if (!DropBoundingSet(to_keep)) {
+ return false;
+ }
+
+ // If SETPCAP wasn't specifically requested, drop it now.
+ add_setpcap = false;
+ if (!SetProcCaps(to_keep, add_setpcap)) {
+ LOG(ERROR) << "failed to apply final capset";
+ return false;
+ }
+
+ // Add the capabilities to the ambient set so that they are preserved across
+ // execve(2).
+ // See http://man7.org/linux/man-pages/man7/capabilities.7.html.
+ return SetAmbientCaps(to_keep);
+}
diff --git a/init/capabilities.h b/init/capabilities.h
new file mode 100644
index 0000000..368178d
--- /dev/null
+++ b/init/capabilities.h
@@ -0,0 +1,23 @@
+// 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 <linux/capability.h>
+
+#include <bitset>
+#include <string>
+
+using CapSet = std::bitset<CAP_LAST_CAP + 1>;
+
+int LookupCap(const std::string& cap_name);
+bool SetCapsForExec(const CapSet& to_keep);
diff --git a/init/descriptors.cpp b/init/descriptors.cpp
new file mode 100644
index 0000000..10aae88
--- /dev/null
+++ b/init/descriptors.cpp
@@ -0,0 +1,104 @@
+/*
+ * 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 "descriptors.h"
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <android-base/stringprintf.h>
+#include <cutils/files.h>
+#include <cutils/sockets.h>
+
+#include "init.h"
+#include "log.h"
+#include "util.h"
+
+DescriptorInfo::DescriptorInfo(const std::string& name, const std::string& type, uid_t uid,
+ gid_t gid, int perm, const std::string& context)
+ : name_(name), type_(type), uid_(uid), gid_(gid), perm_(perm), context_(context) {
+}
+
+DescriptorInfo::~DescriptorInfo() {
+}
+
+std::ostream& operator<<(std::ostream& os, const DescriptorInfo& info) {
+ return os << " descriptors " << info.name_ << " " << info.type_ << " " << std::oct << info.perm_;
+}
+
+bool DescriptorInfo::operator==(const DescriptorInfo& other) const {
+ return name_ == other.name_ && type_ == other.type_ && key() == other.key();
+}
+
+void DescriptorInfo::CreateAndPublish(const std::string& globalContext) const {
+ // Create
+ const std::string& contextStr = context_.empty() ? globalContext : context_;
+ int fd = Create(contextStr);
+ if (fd < 0) return;
+
+ // Publish
+ std::string publishedName = key() + name_;
+ std::for_each(publishedName.begin(), publishedName.end(),
+ [] (char& c) { c = isalnum(c) ? c : '_'; });
+
+ std::string val = android::base::StringPrintf("%d", fd);
+ add_environment(publishedName.c_str(), val.c_str());
+
+ // make sure we don't close on exec
+ fcntl(fd, F_SETFD, 0);
+}
+
+void DescriptorInfo::Clean() const {
+}
+
+SocketInfo::SocketInfo(const std::string& name, const std::string& type, uid_t uid,
+ gid_t gid, int perm, const std::string& context)
+ : DescriptorInfo(name, type, uid, gid, perm, context) {
+}
+
+void SocketInfo::Clean() const {
+ unlink(android::base::StringPrintf(ANDROID_SOCKET_DIR "/%s", name().c_str()).c_str());
+}
+
+int SocketInfo::Create(const std::string& context) const {
+ int flags = ((type() == "stream" ? SOCK_STREAM :
+ (type() == "dgram" ? SOCK_DGRAM :
+ SOCK_SEQPACKET)));
+ return create_socket(name().c_str(), flags, perm(), uid(), gid(), context.c_str());
+}
+
+const std::string SocketInfo::key() const {
+ return ANDROID_SOCKET_ENV_PREFIX;
+}
+
+FileInfo::FileInfo(const std::string& name, const std::string& type, uid_t uid,
+ gid_t gid, int perm, const std::string& context)
+ : DescriptorInfo(name, type, uid, gid, perm, context) {
+}
+
+int FileInfo::Create(const std::string& context) const {
+ int flags = ((type() == "r" ? O_RDONLY :
+ (type() == "w" ? (O_WRONLY | O_CREAT) :
+ (O_RDWR | O_CREAT))));
+ return create_file(name().c_str(), flags, perm(), uid(), gid(), context.c_str());
+}
+
+const std::string FileInfo::key() const {
+ return ANDROID_FILE_ENV_PREFIX;
+}
diff --git a/init/descriptors.h b/init/descriptors.h
new file mode 100644
index 0000000..ff276fb
--- /dev/null
+++ b/init/descriptors.h
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+
+#ifndef _INIT_DESCRIPTORS_H
+#define _INIT_DESCRIPTORS_H
+
+#include <sys/types.h>
+
+#include <string>
+
+class DescriptorInfo {
+ public:
+ DescriptorInfo(const std::string& name, const std::string& type, uid_t uid,
+ gid_t gid, int perm, const std::string& context);
+ virtual ~DescriptorInfo();
+
+ friend std::ostream& operator<<(std::ostream& os, const class DescriptorInfo& info);
+ bool operator==(const DescriptorInfo& other) const;
+
+ void CreateAndPublish(const std::string& globalContext) const;
+ virtual void Clean() const;
+
+ protected:
+ const std::string& name() const { return name_; }
+ const std::string& type() const { return type_; }
+ uid_t uid() const { return uid_; }
+ gid_t gid() const { return gid_; }
+ int perm() const { return perm_; }
+ const std::string& context() const { return context_; }
+
+ private:
+ std::string name_;
+ std::string type_;
+ uid_t uid_;
+ gid_t gid_;
+ int perm_;
+ std::string context_;
+
+ virtual int Create(const std::string& globalContext) const = 0;
+ virtual const std::string key() const = 0;
+};
+
+std::ostream& operator<<(std::ostream& os, const DescriptorInfo& info);
+
+class SocketInfo : public DescriptorInfo {
+ public:
+ SocketInfo(const std::string& name, const std::string& type, uid_t uid,
+ gid_t gid, int perm, const std::string& context);
+ void Clean() const override;
+ private:
+ virtual int Create(const std::string& context) const override;
+ virtual const std::string key() const override;
+};
+
+class FileInfo : public DescriptorInfo {
+ public:
+ FileInfo(const std::string& name, const std::string& type, uid_t uid,
+ gid_t gid, int perm, const std::string& context);
+ private:
+ virtual int Create(const std::string& context) const override;
+ virtual const std::string key() const override;
+};
+
+#endif
diff --git a/init/init.cpp b/init/init.cpp
index 7a0e114..809a6f5 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -687,19 +687,43 @@
mount("devpts", "/dev/pts", "devpts", 0, NULL);
#define MAKE_STR(x) __STRING(x)
mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));
+ gid_t groups[] = { AID_READPROC };
+ setgroups(arraysize(groups), groups);
mount("sysfs", "/sys", "sysfs", 0, NULL);
mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
- early_mount();
}
// Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
// talk to the outside world...
InitKernelLogging(argv);
- LOG(INFO) << "init " << (is_first_stage ? "first stage" : "second stage") << " started!";
+ if (is_first_stage) {
+ LOG(INFO) << "init first 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.
+ selinux_initialize(true);
+
+ // If we're in the kernel domain, 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();
+ }
+ char* path = argv[0];
+ char* args[] = { path, const_cast<char*>("--second-stage"), 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));
@@ -713,24 +737,9 @@
// Propagate the kernel variables to internal variables
// used by init as well as the current required properties.
export_kernel_boot_props();
- }
- // Set up SELinux, including loading the SELinux policy if we're in the kernel domain.
- selinux_initialize(is_first_stage);
-
- // If we're in the kernel domain, re-exec init to transition to the init domain now
- // that the SELinux policy has been loaded.
- if (is_first_stage) {
- if (restorecon("/init") == -1) {
- PLOG(ERROR) << "restorecon failed";
- security_failure();
- }
- char* path = argv[0];
- char* args[] = { path, const_cast<char*>("--second-stage"), nullptr };
- if (execv(path, args) == -1) {
- PLOG(ERROR) << "execv(\"" << path << "\") failed";
- security_failure();
- }
+ // Now set up SELinux for second stage
+ selinux_initialize(false);
}
// These directories were necessarily created before initial policy load
diff --git a/init/readme.txt b/init/readme.txt
index 77e5de2..5173ca6 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -141,33 +141,49 @@
Set the environment variable <name> to <value> in the launched process.
socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]
- Create a unix domain socket named /dev/socket/<name> and pass
- its fd to the launched process. <type> must be "dgram", "stream" or "seqpacket".
- User and group default to 0.
- 'seclabel' is the SELinux security context for the socket.
- It defaults to the service security context, as specified by seclabel or
- computed based on the service executable file security context.
+ Create a unix domain socket named /dev/socket/<name> and pass its fd to the
+ launched process. <type> must be "dgram", "stream" or "seqpacket". User and
+ group default to 0. 'seclabel' is the SELinux security context for the
+ socket. It defaults to the service security context, as specified by
+ seclabel or computed based on the service executable file security context.
+ For native executables see libcutils android_get_control_socket().
+
+file <path> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]
+ Open/Create a file path and pass its fd to the launched process. <type> must
+ be "r", "w" or "rw". User and group default to 0. 'seclabel' is the SELinux
+ security context for the file if it must be created. It defaults to the
+ service security context, as specified by seclabel or computed based on the
+ service executable file security context. For native executables see
+ libcutils android_get_control_file().
user <username>
- Change to username before exec'ing this service.
+ Change to 'username' before exec'ing this service.
Currently defaults to root. (??? probably should default to nobody)
As of Android M, processes should use this option even if they
- require linux capabilities. Previously, to acquire linux
+ require Linux capabilities. Previously, to acquire Linux
capabilities, a process would need to run as root, request the
capabilities, then drop to its desired uid. There is a new
mechanism through fs_config that allows device manufacturers to add
- linux capabilities to specific binaries on a file system that should
+ Linux capabilities to specific binaries on a file system that should
be used instead. This mechanism is described on
http://source.android.com/devices/tech/config/filesystem.html. When
using this new mechanism, processes can use the user option to
select their desired uid without ever running as root.
+ As of Android O, processes can also request capabilities directly in their .rc
+ files. See the "capabilities" option below.
group <groupname> [ <groupname> ]*
- Change to groupname before exec'ing this service. Additional
+ Change to 'groupname' before exec'ing this service. Additional
groupnames beyond the (required) first one are used to set the
supplemental groups of the process (via setgroups()).
Currently defaults to root. (??? probably should default to nobody)
+capabilities <capability> [ <capability> ]*
+ Set capabilities when exec'ing this service. 'capability' should be a Linux
+ capability without the "CAP_" prefix, like "NET_ADMIN" or "SETPCAP". See
+ http://man7.org/linux/man-pages/man7/capabilities.7.html for a list of Linux
+ capabilities.
+
seclabel <seclabel>
Change to 'seclabel' before exec'ing this service.
Primarily for use by services run from the rootfs, e.g. ueventd, adbd.
diff --git a/init/service.cpp b/init/service.cpp
index 6460e71..9fa11b8 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -17,6 +17,7 @@
#include "service.h"
#include <fcntl.h>
+#include <linux/securebits.h>
#include <sched.h>
#include <sys/mount.h>
#include <sys/prctl.h>
@@ -35,7 +36,6 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <cutils/android_reboot.h>
-#include <cutils/sockets.h>
#include <system/thread_defs.h>
#include <processgroup/processgroup.h>
@@ -144,14 +144,6 @@
strs->push_back(nullptr);
}
-SocketInfo::SocketInfo() : uid(0), gid(0), perm(0) {
-}
-
-SocketInfo::SocketInfo(const std::string& name, const std::string& type, uid_t uid,
- gid_t gid, int perm, const std::string& socketcon)
- : name(name), type(type), uid(uid), gid(gid), perm(perm), socketcon(socketcon) {
-}
-
ServiceEnvironmentInfo::ServiceEnvironmentInfo() {
}
@@ -171,14 +163,16 @@
Service::Service(const std::string& name, const std::string& classname,
unsigned flags, uid_t uid, gid_t gid,
- const std::vector<gid_t>& supp_gids, unsigned namespace_flags,
+ const std::vector<gid_t>& supp_gids,
+ const CapSet& capabilities, unsigned namespace_flags,
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),
- supp_gids_(supp_gids), namespace_flags_(namespace_flags),
- seclabel_(seclabel), ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0),
- priority_(0), oom_score_adjust_(-1000), args_(args) {
+ supp_gids_(supp_gids), capabilities_(capabilities),
+ namespace_flags_(namespace_flags), seclabel_(seclabel),
+ ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0), priority_(0),
+ oom_score_adjust_(-1000), args_(args) {
onrestart_.InitSingleTrigger("onrestart");
}
@@ -210,21 +204,14 @@
}
}
-void Service::CreateSockets(const std::string& context) {
- for (const auto& si : sockets_) {
- int socket_type = ((si.type == "stream" ? SOCK_STREAM :
- (si.type == "dgram" ? SOCK_DGRAM :
- SOCK_SEQPACKET)));
- const char* socketcon = !si.socketcon.empty() ? si.socketcon.c_str() : context.c_str();
-
- int s = create_socket(si.name.c_str(), socket_type, si.perm, si.uid, si.gid, socketcon);
- if (s >= 0) {
- PublishSocket(si.name, s);
+void Service::SetProcessAttributes() {
+ // Keep capabilites on uid change.
+ if (capabilities_.any() && uid_) {
+ if (prctl(PR_SET_SECUREBITS, SECBIT_KEEP_CAPS | SECBIT_KEEP_CAPS_LOCKED) != 0) {
+ PLOG(FATAL) << "prtcl(PR_SET_KEEPCAPS) failed for " << name_;
}
}
-}
-void Service::SetProcessAttributes() {
// TODO: work out why this fails for `console` then upgrade to FATAL.
if (setpgid(0, getpid()) == -1) PLOG(ERROR) << "setpgid failed for " << name_;
@@ -233,10 +220,8 @@
PLOG(FATAL) << "setgid failed for " << name_;
}
}
- if (!supp_gids_.empty()) {
- if (setgroups(supp_gids_.size(), &supp_gids_[0]) != 0) {
- PLOG(FATAL) << "setgroups failed for " << name_;
- }
+ if (setgroups(supp_gids_.size(), &supp_gids_[0]) != 0) {
+ PLOG(FATAL) << "setgroups failed for " << name_;
}
if (uid_) {
if (setuid(uid_) != 0) {
@@ -253,6 +238,11 @@
PLOG(FATAL) << "setpriority failed for " << name_;
}
}
+ if (capabilities_.any()) {
+ if (!SetCapsForExec(capabilities_)) {
+ LOG(FATAL) << "cannot set capabilities for " << name_;
+ }
+ }
}
bool Service::Reap() {
@@ -260,11 +250,9 @@
KillProcessGroup(SIGKILL);
}
- // Remove any sockets we may have created.
- for (const auto& si : sockets_) {
- std::string tmp = StringPrintf(ANDROID_SOCKET_DIR "/%s", si.name.c_str());
- unlink(tmp.c_str());
- }
+ // Remove any descriptor resources we may have created.
+ std::for_each(descriptors_.begin(), descriptors_.end(),
+ std::bind(&DescriptorInfo::Clean, std::placeholders::_1));
if (flags_ & SVC_EXEC) {
LOG(INFO) << "SVC_EXEC pid " << pid_ << " finished...";
@@ -317,9 +305,23 @@
LOG(INFO) << "service " << name_;
LOG(INFO) << " class '" << classname_ << "'";
LOG(INFO) << " exec "<< android::base::Join(args_, " ");
- for (const auto& si : sockets_) {
- LOG(INFO) << " socket " << si.name << " " << si.type << " " << std::oct << si.perm;
+ std::for_each(descriptors_.begin(), descriptors_.end(),
+ [] (const auto& info) { LOG(INFO) << *info; });
+}
+
+bool Service::ParseCapabilities(const std::vector<std::string>& args, std::string* err) {
+ capabilities_ = 0;
+
+ for (size_t i = 1; i < args.size(); i++) {
+ const std::string& arg = args[i];
+ int cap = LookupCap(arg);
+ if (cap == -1) {
+ *err = StringPrintf("invalid capability '%s'", arg.c_str());
+ return false;
+ }
+ capabilities_[cap] = true;
}
+ return true;
}
bool Service::ParseClass(const std::vector<std::string>& args, std::string* err) {
@@ -441,20 +443,48 @@
return true;
}
-/* name type perm [ uid gid context ] */
+template <typename T>
+bool Service::AddDescriptor(const std::vector<std::string>& args, std::string* err) {
+ int perm = args.size() > 3 ? std::strtoul(args[3].c_str(), 0, 8) : -1;
+ uid_t uid = args.size() > 4 ? decode_uid(args[4].c_str()) : 0;
+ gid_t gid = args.size() > 5 ? decode_uid(args[5].c_str()) : 0;
+ std::string context = args.size() > 6 ? args[6] : "";
+
+ auto descriptor = std::make_unique<T>(args[1], args[2], uid, gid, perm, context);
+
+ auto old =
+ std::find_if(descriptors_.begin(), descriptors_.end(),
+ [&descriptor] (const auto& other) { return descriptor.get() == other.get(); });
+
+ if (old != descriptors_.end()) {
+ *err = "duplicate descriptor " + args[1] + " " + args[2];
+ return false;
+ }
+
+ descriptors_.emplace_back(std::move(descriptor));
+ return true;
+}
+
+// name type perm [ uid gid context ]
bool Service::ParseSocket(const std::vector<std::string>& args, std::string* err) {
if (args[2] != "dgram" && args[2] != "stream" && args[2] != "seqpacket") {
*err = "socket type must be 'dgram', 'stream' or 'seqpacket'";
return false;
}
+ return AddDescriptor<SocketInfo>(args, err);
+}
- int perm = std::strtoul(args[3].c_str(), 0, 8);
- uid_t uid = args.size() > 4 ? decode_uid(args[4].c_str()) : 0;
- gid_t gid = args.size() > 5 ? decode_uid(args[5].c_str()) : 0;
- std::string socketcon = args.size() > 6 ? args[6] : "";
-
- sockets_.emplace_back(args[1], args[2], uid, gid, perm, socketcon);
- return true;
+// name type perm [ uid gid context ]
+bool Service::ParseFile(const std::vector<std::string>& args, std::string* err) {
+ if (args[2] != "r" && args[2] != "w" && args[2] != "rw") {
+ *err = "file type must be 'r', 'w' or 'rw'";
+ return false;
+ }
+ if ((args[1][0] != '/') || (args[1].find("../") != std::string::npos)) {
+ *err = "file name must not be relative";
+ return false;
+ }
+ return AddDescriptor<FileInfo>(args, err);
}
bool Service::ParseUser(const std::vector<std::string>& args, std::string* err) {
@@ -478,6 +508,8 @@
Service::OptionParserMap::Map& Service::OptionParserMap::map() const {
constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
static const Map option_parsers = {
+ {"capabilities",
+ {1, kMax, &Service::ParseCapabilities}},
{"class", {1, 1, &Service::ParseClass}},
{"console", {0, 1, &Service::ParseConsole}},
{"critical", {0, 0, &Service::ParseCritical}},
@@ -494,6 +526,7 @@
{"seclabel", {1, 1, &Service::ParseSeclabel}},
{"setenv", {2, 2, &Service::ParseSetenv}},
{"socket", {3, 6, &Service::ParseSocket}},
+ {"file", {2, 6, &Service::ParseFile}},
{"user", {1, 1, &Service::ParseUser}},
{"writepid", {1, kMax, &Service::ParseWritepid}},
};
@@ -583,7 +616,8 @@
add_environment(ei.name.c_str(), ei.value.c_str());
}
- CreateSockets(scon);
+ std::for_each(descriptors_.begin(), descriptors_.end(),
+ std::bind(&DescriptorInfo::CreateAndPublish, std::placeholders::_1, scon));
std::string pid_str = StringPrintf("%d", getpid());
for (const auto& file : writepid_files_) {
@@ -757,15 +791,6 @@
close(fd);
}
-void Service::PublishSocket(const std::string& name, int fd) const {
- std::string key = StringPrintf(ANDROID_SOCKET_ENV_PREFIX "%s", name.c_str());
- std::string val = StringPrintf("%d", fd);
- add_environment(key.c_str(), val.c_str());
-
- /* make sure we don't close-on-exec */
- fcntl(fd, F_SETFD, 0);
-}
-
int ServiceManager::exec_count_ = 0;
ServiceManager::ServiceManager() {
@@ -809,6 +834,7 @@
exec_count_++;
std::string name = StringPrintf("exec %d (%s)", exec_count_, str_args[0].c_str());
unsigned flags = SVC_EXEC | SVC_ONESHOT;
+ CapSet no_capabilities;
unsigned namespace_flags = 0;
std::string seclabel = "";
@@ -829,9 +855,9 @@
}
}
- std::unique_ptr<Service> svc_p(new Service(name, "default", flags, uid, gid,
- supp_gids, namespace_flags,
- seclabel, str_args));
+ std::unique_ptr<Service> svc_p(new Service(name, "default", flags, uid, gid, supp_gids,
+ no_capabilities, namespace_flags, seclabel,
+ str_args));
if (!svc_p) {
LOG(ERROR) << "Couldn't allocate service for exec of '" << str_args[0] << "'";
return nullptr;
diff --git a/init/service.h b/init/service.h
index 4a3412c..d9e8f57 100644
--- a/init/service.h
+++ b/init/service.h
@@ -26,6 +26,8 @@
#include <vector>
#include "action.h"
+#include "capabilities.h"
+#include "descriptors.h"
#include "init_parser.h"
#include "keyword_map.h"
@@ -47,18 +49,6 @@
class Action;
class ServiceManager;
-struct SocketInfo {
- SocketInfo();
- SocketInfo(const std::string& name, const std::string& type, uid_t uid,
- gid_t gid, int perm, const std::string& socketcon);
- std::string name;
- std::string type;
- uid_t uid;
- gid_t gid;
- int perm;
- std::string socketcon;
-};
-
struct ServiceEnvironmentInfo {
ServiceEnvironmentInfo();
ServiceEnvironmentInfo(const std::string& name, const std::string& value);
@@ -73,8 +63,9 @@
Service(const std::string& name, const std::string& classname,
unsigned flags, uid_t uid, gid_t gid,
- const std::vector<gid_t>& supp_gids, unsigned namespace_flags,
- const std::string& seclabel, const std::vector<std::string>& args);
+ const std::vector<gid_t>& supp_gids, const CapSet& capabilities,
+ unsigned namespace_flags, const std::string& seclabel,
+ const std::vector<std::string>& args);
bool ParseLine(const std::vector<std::string>& args, std::string* err);
bool Start();
@@ -111,11 +102,10 @@
void StopOrReset(int how);
void ZapStdio() const;
void OpenConsole() const;
- void PublishSocket(const std::string& name, int fd) const;
void KillProcessGroup(int signal);
- void CreateSockets(const std::string& scon);
void SetProcessAttributes();
+ bool ParseCapabilities(const std::vector<std::string>& args, std::string *err);
bool ParseClass(const std::vector<std::string>& args, std::string* err);
bool ParseConsole(const std::vector<std::string>& args, std::string* err);
bool ParseCritical(const std::vector<std::string>& args, std::string* err);
@@ -131,9 +121,13 @@
bool ParseSeclabel(const std::vector<std::string>& args, std::string* err);
bool ParseSetenv(const std::vector<std::string>& args, std::string* err);
bool ParseSocket(const std::vector<std::string>& args, std::string* err);
+ bool ParseFile(const std::vector<std::string>& args, std::string* err);
bool ParseUser(const std::vector<std::string>& args, std::string* err);
bool ParseWritepid(const std::vector<std::string>& args, std::string* err);
+ template <typename T>
+ bool AddDescriptor(const std::vector<std::string>& args, std::string* err);
+
std::string name_;
std::string classname_;
std::string console_;
@@ -147,11 +141,12 @@
uid_t uid_;
gid_t gid_;
std::vector<gid_t> supp_gids_;
+ CapSet capabilities_;
unsigned namespace_flags_;
std::string seclabel_;
- std::vector<SocketInfo> sockets_;
+ std::vector<std::unique_ptr<DescriptorInfo>> descriptors_;
std::vector<ServiceEnvironmentInfo> envvars_;
Action onrestart_; // Commands to execute on restart.
diff --git a/init/util.cpp b/init/util.cpp
index 660a66f..b280244 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -14,32 +14,32 @@
* limitations under the License.
*/
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <ftw.h>
+#include <pwd.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <errno.h>
#include <time.h>
-#include <ftw.h>
-#include <pwd.h>
+#include <unistd.h>
-#include <selinux/label.h>
#include <selinux/android.h>
+#include <selinux/label.h>
+#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <sys/socket.h>
#include <sys/un.h>
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include <android-base/strings.h>
-
/* for ANDROID_SOCKET_* */
#include <cutils/sockets.h>
-#include <android-base/stringprintf.h>
#include "init.h"
#include "log.h"
@@ -164,6 +164,76 @@
return -1;
}
+/*
+ * create_file - opens and creates a file as dictated in init.rc.
+ * This file is inherited by the daemon. We communicate the file
+ * descriptor's value via the environment variable ANDROID_FILE_<basename>
+ */
+int create_file(const char *path, int flags, mode_t perm, uid_t uid,
+ gid_t gid, const char *filecon)
+{
+ char *secontext = NULL;
+ int ret;
+
+ if (filecon) {
+ if (setsockcreatecon(filecon) == -1) {
+ PLOG(ERROR) << "setsockcreatecon(\"" << filecon << "\") failed";
+ return -1;
+ }
+ } else if (sehandle) {
+ ret = selabel_lookup(sehandle, &secontext, path, perm);
+ if (ret != -1) {
+ ret = setfscreatecon(secontext);
+ if (ret == -1) {
+ freecon(secontext);
+ PLOG(ERROR) << "setfscreatecon(\"" << secontext << "\") failed";
+ return -1;
+ }
+ }
+ }
+
+ int fd = TEMP_FAILURE_RETRY(open(path, flags | O_NDELAY, perm));
+
+ if (filecon) {
+ setsockcreatecon(NULL);
+ lsetfilecon(path, filecon);
+ } else {
+ setfscreatecon(NULL);
+ freecon(secontext);
+ }
+
+ if (fd == -1) {
+ PLOG(ERROR) << "Failed to open/create file '" << path << "'";
+ goto out_close;
+ }
+
+ if (!(flags & O_NDELAY)) fcntl(fd, F_SETFD, flags);
+
+ ret = lchown(path, uid, gid);
+ if (ret) {
+ PLOG(ERROR) << "Failed to lchown file '" << path << "'";
+ goto out_close;
+ }
+ if (perm != static_cast<mode_t>(-1)) {
+ ret = fchmodat(AT_FDCWD, path, perm, AT_SYMLINK_NOFOLLOW);
+ if (ret) {
+ PLOG(ERROR) << "Failed to fchmodat file '" << path << "'";
+ goto out_close;
+ }
+ }
+
+ LOG(INFO) << "Created file '" << path << "'"
+ << ", mode " << std::oct << perm << std::dec
+ << ", user " << uid
+ << ", group " << gid;
+
+ return fd;
+
+out_close:
+ if (fd >= 0) close(fd);
+ return -1;
+}
+
bool read_file(const char* path, std::string* content) {
content->clear();
diff --git a/init/util.h b/init/util.h
index b83b9a0..b7531cc 100644
--- a/init/util.h
+++ b/init/util.h
@@ -27,6 +27,8 @@
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,
+ uid_t uid, gid_t gid, const char *filecon);
bool read_file(const char* path, std::string* content);
int write_file(const char* path, const char* content);
diff --git a/init/util_test.cpp b/init/util_test.cpp
index 228954b..6ecbf90 100644
--- a/init/util_test.cpp
+++ b/init/util_test.cpp
@@ -17,7 +17,15 @@
#include "util.h"
#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cutils/files.h>
#include <gtest/gtest.h>
+#include <selinux/android.h>
TEST(util, read_file_ENOENT) {
std::string s("hello");
@@ -41,3 +49,51 @@
EXPECT_EQ(UINT_MAX, decode_uid("toot"));
EXPECT_EQ(123U, decode_uid("123"));
}
+
+struct selabel_handle *sehandle;
+
+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);
+
+ int fd;
+ 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;
+ 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)];
+ 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);
+ struct stat st;
+ EXPECT_EQ(stat(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_NE(con, static_cast<security_context_t>(NULL));
+ if (con) {
+ EXPECT_EQ(context, std::string(con));
+ }
+ freecon(con);
+ EXPECT_EQ(unlink(path), 0);
+}
diff --git a/libappfuse/Android.bp b/libappfuse/Android.bp
new file mode 100644
index 0000000..8b46154
--- /dev/null
+++ b/libappfuse/Android.bp
@@ -0,0 +1,26 @@
+// Copyright 2016 The Android Open Source Project
+
+cc_defaults {
+ name: "libappfuse_defaults",
+ local_include_dirs: ["include"],
+ shared_libs: ["libbase"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ clang: true
+}
+
+cc_library_shared {
+ name: "libappfuse",
+ defaults: ["libappfuse_defaults"],
+ export_include_dirs: ["include"],
+ srcs: ["FuseBuffer.cc", "FuseBridgeLoop.cc"]
+}
+
+cc_test {
+ name: "libappfuse_test",
+ defaults: ["libappfuse_defaults"],
+ shared_libs: ["libappfuse"],
+ srcs: ["tests/FuseBridgeLoopTest.cc", "tests/FuseBufferTest.cc"]
+}
diff --git a/libappfuse/FuseBridgeLoop.cc b/libappfuse/FuseBridgeLoop.cc
new file mode 100644
index 0000000..332556d
--- /dev/null
+++ b/libappfuse/FuseBridgeLoop.cc
@@ -0,0 +1,79 @@
+/*
+ * 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/FuseBridgeLoop.h"
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+
+namespace android {
+
+bool FuseBridgeLoop::Start(
+ int raw_dev_fd, int raw_proxy_fd, FuseBridgeLoop::Callback* callback) {
+ base::unique_fd dev_fd(raw_dev_fd);
+ base::unique_fd proxy_fd(raw_proxy_fd);
+
+ LOG(DEBUG) << "Start fuse loop.";
+ while (true) {
+ if (!buffer_.request.Read(dev_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:
+ case FUSE_GETATTR:
+ case FUSE_OPEN:
+ case FUSE_READ:
+ case FUSE_WRITE:
+ case FUSE_RELEASE:
+ case FUSE_FLUSH:
+ if (!buffer_.request.Write(proxy_fd)) {
+ LOG(ERROR) << "Failed to write a request to the proxy.";
+ return false;
+ }
+ if (!buffer_.response.Read(proxy_fd)) {
+ LOG(ERROR) << "Failed to read a response from the proxy.";
+ return false;
+ }
+ break;
+
+ case FUSE_INIT:
+ buffer_.HandleInit();
+ break;
+
+ default:
+ buffer_.HandleNotImpl();
+ break;
+ }
+
+ if (!buffer_.response.Write(dev_fd)) {
+ LOG(ERROR) << "Failed to write a response to the device.";
+ return false;
+ }
+
+ if (opcode == FUSE_INIT) {
+ callback->OnMount();
+ }
+ }
+}
+
+} // namespace android
diff --git a/libappfuse/FuseBuffer.cc b/libappfuse/FuseBuffer.cc
new file mode 100644
index 0000000..45280a5
--- /dev/null
+++ b/libappfuse/FuseBuffer.cc
@@ -0,0 +1,136 @@
+/*
+ * 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/FuseBuffer.h"
+
+#include <inttypes.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <algorithm>
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+
+namespace android {
+
+template <typename T, typename Header>
+bool FuseMessage<T, Header>::CheckHeaderLength() const {
+ if (sizeof(Header) <= header.len && header.len <= sizeof(T)) {
+ return true;
+ } else {
+ LOG(ERROR) << "Packet size is invalid=" << header.len;
+ return false;
+ }
+}
+
+template <typename T, typename Header>
+bool FuseMessage<T, Header>::CheckResult(
+ int result, const char* operation_name) const {
+ 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="
+ << header.len;
+ return false;
+ }
+}
+
+template <typename T, typename Header>
+bool FuseMessage<T, Header>::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 {
+ if (!CheckHeaderLength()) {
+ return false;
+ }
+ const ssize_t result = TEMP_FAILURE_RETRY(::write(fd, this, header.len));
+ return CheckResult(result, "write");
+}
+
+template struct FuseMessage<FuseRequest, fuse_in_header>;
+template struct FuseMessage<FuseResponse, fuse_out_header>;
+
+void FuseResponse::ResetHeader(
+ uint32_t data_length, int32_t error, uint64_t unique) {
+ CHECK_LE(error, 0) << "error should be zero or negative.";
+ header.len = sizeof(fuse_out_header) + data_length;
+ header.error = error;
+ header.unique = unique;
+}
+
+void FuseResponse::Reset(uint32_t data_length, int32_t error, uint64_t unique) {
+ memset(this, 0, sizeof(fuse_out_header) + data_length);
+ ResetHeader(data_length, error, unique);
+}
+
+void FuseBuffer::HandleInit() {
+ const fuse_init_in* const in = &request.init_in;
+
+ // Before writing |out|, we need to copy data from |in|.
+ const uint64_t unique = request.header.unique;
+ const uint32_t minor = in->minor;
+ const uint32_t max_readahead = in->max_readahead;
+
+ // Kernel 2.6.16 is the first stable kernel with struct fuse_init_out
+ // defined (fuse version 7.6). The structure is the same from 7.6 through
+ // 7.22. Beginning with 7.23, the structure increased in size and added
+ // new parameters.
+ if (in->major != FUSE_KERNEL_VERSION || in->minor < 6) {
+ LOG(ERROR) << "Fuse kernel version mismatch: Kernel version " << in->major
+ << "." << in->minor << " Expected at least " << FUSE_KERNEL_VERSION
+ << ".6";
+ response.Reset(0, -EPERM, unique);
+ return;
+ }
+
+ // We limit ourselves to 15 because we don't handle BATCH_FORGET yet
+ size_t response_size = sizeof(fuse_init_out);
+#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;
+ }
+#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;
+ out->max_background = 32;
+ out->congestion_threshold = 32;
+ out->max_write = kFuseMaxWrite;
+}
+
+void FuseBuffer::HandleNotImpl() {
+ LOG(VERBOSE) << "NOTIMPL op=" << request.header.opcode << " uniq="
+ << request.header.unique << " nid=" << request.header.nodeid;
+ const uint64_t unique = request.header.unique;
+ response.Reset(0, -ENOSYS, unique);
+}
+
+} // namespace android
diff --git a/libappfuse/include/libappfuse/FuseBridgeLoop.h b/libappfuse/include/libappfuse/FuseBridgeLoop.h
new file mode 100644
index 0000000..2006532
--- /dev/null
+++ b/libappfuse/include/libappfuse/FuseBridgeLoop.h
@@ -0,0 +1,40 @@
+/*
+ * 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_FUSEBRIDGELOOP_H_
+#define ANDROID_LIBAPPFUSE_FUSEBRIDGELOOP_H_
+
+#include "libappfuse/FuseBuffer.h"
+
+namespace android {
+
+class FuseBridgeLoop {
+ public:
+ class Callback {
+ public:
+ virtual void OnMount() = 0;
+ virtual ~Callback() = default;
+ };
+
+ bool Start(int dev_fd, int proxy_fd, Callback* callback);
+
+ private:
+ FuseBuffer buffer_;
+};
+
+} // namespace android
+
+#endif // ANDROID_LIBAPPFUSE_FUSEBRIDGELOOP_H_
diff --git a/libappfuse/include/libappfuse/FuseBuffer.h b/libappfuse/include/libappfuse/FuseBuffer.h
new file mode 100644
index 0000000..071b777
--- /dev/null
+++ b/libappfuse/include/libappfuse/FuseBuffer.h
@@ -0,0 +1,89 @@
+/*
+ * 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_FUSEBUFFER_H_
+#define ANDROID_LIBAPPFUSE_FUSEBUFFER_H_
+
+#include <linux/fuse.h>
+
+namespace android {
+
+// The numbers came from sdcard.c.
+// Maximum number of bytes to write/read in one request/one reply.
+constexpr size_t kFuseMaxWrite = 256 * 1024;
+constexpr size_t kFuseMaxRead = 128 * 1024;
+constexpr int32_t kFuseSuccess = 0;
+
+template<typename T, typename Header>
+struct FuseMessage {
+ Header header;
+ bool Read(int fd);
+ bool Write(int fd) const;
+ private:
+ bool CheckHeaderLength() const;
+ bool CheckResult(int result, const char* operation_name) const;
+};
+
+struct FuseRequest : public FuseMessage<FuseRequest, fuse_in_header> {
+ union {
+ struct {
+ fuse_write_in write_in;
+ char write_data[kFuseMaxWrite];
+ };
+ fuse_open_in open_in;
+ fuse_init_in init_in;
+ fuse_read_in read_in;
+ char lookup_name[0];
+ };
+};
+
+struct FuseResponse : public FuseMessage<FuseResponse, fuse_out_header> {
+ union {
+ fuse_init_out init_out;
+ fuse_entry_out entry_out;
+ fuse_attr_out attr_out;
+ fuse_open_out open_out;
+ char read_data[kFuseMaxRead];
+ 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 {
+ FuseRequest request;
+ FuseResponse response;
+
+ void HandleInit();
+ 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 android
+
+#endif // ANDROID_LIBAPPFUSE_FUSEBUFFER_H_
diff --git a/libappfuse/tests/FuseBridgeLoopTest.cc b/libappfuse/tests/FuseBridgeLoopTest.cc
new file mode 100644
index 0000000..31e3690
--- /dev/null
+++ b/libappfuse/tests/FuseBridgeLoopTest.cc
@@ -0,0 +1,196 @@
+/*
+ * 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/FuseBridgeLoop.h"
+
+#include <sys/socket.h>
+
+#include <sstream>
+#include <thread>
+
+#include <gtest/gtest.h>
+
+namespace android {
+
+class Callback : public FuseBridgeLoop::Callback {
+ public:
+ bool mounted;
+ Callback() : mounted(false) {}
+ void OnMount() override {
+ mounted = true;
+ }
+};
+
+class FuseBridgeLoopTest : public ::testing::Test {
+ protected:
+ int dev_sockets_[2];
+ int 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_));
+ thread_ = std::thread([this] {
+ FuseBridgeLoop loop;
+ loop.Start(dev_sockets_[1], proxy_sockets_[0], &callback_);
+ });
+ }
+
+ void CheckNotImpl(uint32_t opcode) {
+ SCOPED_TRACE((std::ostringstream() << "opcode: " << opcode).str());
+
+ memset(&request_, 0, sizeof(FuseRequest));
+ request_.header.opcode = opcode;
+ request_.header.len = sizeof(fuse_in_header);
+ ASSERT_TRUE(request_.Write(dev_sockets_[0]));
+
+ memset(&response_, 0, sizeof(FuseResponse));
+ ASSERT_TRUE(response_.Read(dev_sockets_[0]));
+ EXPECT_EQ(-ENOSYS, response_.header.error);
+ }
+
+ void CheckProxy(uint32_t opcode) {
+ SCOPED_TRACE((std::ostringstream() << "opcode: " << opcode).str());
+
+ memset(&request_, 0, sizeof(FuseRequest));
+ request_.header.opcode = opcode;
+ request_.header.unique = opcode; // Use opcode as unique.
+ request_.header.len = sizeof(fuse_in_header);
+ ASSERT_TRUE(request_.Write(dev_sockets_[0]));
+
+ memset(&request_, 0, sizeof(FuseRequest));
+ ASSERT_TRUE(request_.Read(proxy_sockets_[1]));
+ EXPECT_EQ(opcode, request_.header.opcode);
+ EXPECT_EQ(opcode, request_.header.unique);
+
+ memset(&response_, 0, sizeof(FuseResponse));
+ response_.header.len = sizeof(fuse_out_header);
+ response_.header.unique = opcode; // Use opcode as unique.
+ response_.header.error = kFuseSuccess;
+ ASSERT_TRUE(response_.Write(proxy_sockets_[1]));
+
+ memset(&response_, 0, sizeof(FuseResponse));
+ ASSERT_TRUE(response_.Read(dev_sockets_[0]));
+ EXPECT_EQ(opcode, response_.header.unique);
+ EXPECT_EQ(kFuseSuccess, response_.header.error);
+ }
+
+ void SendInitRequest(uint64_t unique) {
+ memset(&request_, 0, sizeof(FuseRequest));
+ request_.header.opcode = FUSE_INIT;
+ request_.header.unique = unique;
+ request_.header.len = sizeof(fuse_in_header) + sizeof(fuse_init_in);
+ request_.init_in.major = FUSE_KERNEL_VERSION;
+ request_.init_in.minor = FUSE_KERNEL_MINOR_VERSION;
+ ASSERT_TRUE(request_.Write(dev_sockets_[0]));
+ }
+
+ void Close() {
+ close(dev_sockets_[0]);
+ close(dev_sockets_[1]);
+ close(proxy_sockets_[0]);
+ close(proxy_sockets_[1]);
+ if (thread_.joinable()) {
+ thread_.join();
+ }
+ }
+
+ void TearDown() {
+ Close();
+ }
+};
+
+TEST_F(FuseBridgeLoopTest, FuseInit) {
+ SendInitRequest(1u);
+
+ memset(&response_, 0, sizeof(FuseResponse));
+ ASSERT_TRUE(response_.Read(dev_sockets_[0]));
+ EXPECT_EQ(kFuseSuccess, response_.header.error);
+ EXPECT_EQ(1u, response_.header.unique);
+
+ // Unmount.
+ Close();
+ EXPECT_TRUE(callback_.mounted);
+}
+
+TEST_F(FuseBridgeLoopTest, FuseForget) {
+ memset(&request_, 0, sizeof(FuseRequest));
+ request_.header.opcode = FUSE_FORGET;
+ request_.header.unique = 1u;
+ request_.header.len = sizeof(fuse_in_header) + sizeof(fuse_forget_in);
+ ASSERT_TRUE(request_.Write(dev_sockets_[0]));
+
+ SendInitRequest(2u);
+
+ memset(&response_, 0, sizeof(FuseResponse));
+ ASSERT_TRUE(response_.Read(dev_sockets_[0]));
+ EXPECT_EQ(2u, response_.header.unique) <<
+ "The loop must not respond to FUSE_FORGET";
+}
+
+TEST_F(FuseBridgeLoopTest, FuseNotImpl) {
+ CheckNotImpl(FUSE_SETATTR);
+ CheckNotImpl(FUSE_READLINK);
+ CheckNotImpl(FUSE_SYMLINK);
+ CheckNotImpl(FUSE_MKNOD);
+ CheckNotImpl(FUSE_MKDIR);
+ CheckNotImpl(FUSE_UNLINK);
+ CheckNotImpl(FUSE_RMDIR);
+ 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_OPENDIR);
+ CheckNotImpl(FUSE_READDIR);
+ CheckNotImpl(FUSE_RELEASEDIR);
+ CheckNotImpl(FUSE_FSYNCDIR);
+ CheckNotImpl(FUSE_GETLK);
+ CheckNotImpl(FUSE_SETLK);
+ CheckNotImpl(FUSE_SETLKW);
+ CheckNotImpl(FUSE_ACCESS);
+ CheckNotImpl(FUSE_CREATE);
+ CheckNotImpl(FUSE_INTERRUPT);
+ CheckNotImpl(FUSE_BMAP);
+ CheckNotImpl(FUSE_DESTROY);
+ CheckNotImpl(FUSE_IOCTL);
+ CheckNotImpl(FUSE_POLL);
+ CheckNotImpl(FUSE_NOTIFY_REPLY);
+ CheckNotImpl(FUSE_BATCH_FORGET);
+ CheckNotImpl(FUSE_FALLOCATE);
+ CheckNotImpl(FUSE_READDIRPLUS);
+ CheckNotImpl(FUSE_RENAME2);
+ CheckNotImpl(FUSE_LSEEK);
+}
+
+TEST_F(FuseBridgeLoopTest, Proxy) {
+ CheckProxy(FUSE_LOOKUP);
+ CheckProxy(FUSE_GETATTR);
+ CheckProxy(FUSE_OPEN);
+ CheckProxy(FUSE_READ);
+ CheckProxy(FUSE_WRITE);
+ CheckProxy(FUSE_RELEASE);
+ CheckProxy(FUSE_FLUSH);
+}
+
+} // android
diff --git a/libappfuse/tests/FuseBufferTest.cc b/libappfuse/tests/FuseBufferTest.cc
new file mode 100644
index 0000000..1aacfe3
--- /dev/null
+++ b/libappfuse/tests/FuseBufferTest.cc
@@ -0,0 +1,187 @@
+/*
+ * 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/FuseBuffer.h"
+
+#include <fcntl.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include <android-base/unique_fd.h>
+#include <gtest/gtest.h>
+
+namespace android {
+
+constexpr char kTempFile[] = "/data/local/tmp/appfuse_test_dump";
+
+void OpenTempFile(android::base::unique_fd* fd) {
+ fd->reset(open(kTempFile, O_CREAT | O_RDWR));
+ ASSERT_NE(-1, *fd) << strerror(errno);
+ unlink(kTempFile);
+ ASSERT_NE(-1, *fd) << strerror(errno);
+}
+
+void TestReadInvalidLength(size_t headerSize, size_t write_size) {
+ android::base::unique_fd fd;
+ OpenTempFile(&fd);
+
+ char buffer[std::max(headerSize, sizeof(FuseRequest))];
+ FuseRequest* const packet = reinterpret_cast<FuseRequest*>(buffer);
+ packet->header.len = headerSize;
+ ASSERT_NE(-1, write(fd, packet, write_size)) << strerror(errno);
+
+ lseek(fd, 0, SEEK_SET);
+ EXPECT_FALSE(packet->Read(fd));
+}
+
+void TestWriteInvalidLength(size_t size) {
+ android::base::unique_fd fd;
+ OpenTempFile(&fd);
+
+ char buffer[std::max(size, sizeof(FuseRequest))];
+ FuseRequest* const packet = reinterpret_cast<FuseRequest*>(buffer);
+ packet->header.len = size;
+ EXPECT_FALSE(packet->Write(fd));
+}
+
+// Use FuseRequest as a template instance of FuseMessage.
+
+TEST(FuseMessageTest, ReadAndWrite) {
+ android::base::unique_fd fd;
+ OpenTempFile(&fd);
+
+ FuseRequest request;
+ request.header.len = sizeof(FuseRequest);
+ request.header.opcode = 1;
+ request.header.unique = 2;
+ request.header.nodeid = 3;
+ request.header.uid = 4;
+ request.header.gid = 5;
+ request.header.pid = 6;
+ strcpy(request.lookup_name, "test");
+
+ ASSERT_TRUE(request.Write(fd));
+
+ memset(&request, 0, sizeof(FuseRequest));
+ lseek(fd, 0, SEEK_SET);
+
+ ASSERT_TRUE(request.Read(fd));
+ EXPECT_EQ(sizeof(FuseRequest), request.header.len);
+ EXPECT_EQ(1u, request.header.opcode);
+ EXPECT_EQ(2u, request.header.unique);
+ EXPECT_EQ(3u, request.header.nodeid);
+ EXPECT_EQ(4u, request.header.uid);
+ EXPECT_EQ(5u, request.header.gid);
+ EXPECT_EQ(6u, request.header.pid);
+ EXPECT_STREQ("test", request.lookup_name);
+}
+
+TEST(FuseMessageTest, Read_InconsistentLength) {
+ TestReadInvalidLength(sizeof(fuse_in_header), sizeof(fuse_in_header) + 1);
+}
+
+TEST(FuseMessageTest, Read_TooLong) {
+ TestReadInvalidLength(sizeof(FuseRequest) + 1, sizeof(FuseRequest) + 1);
+}
+
+TEST(FuseMessageTest, Read_TooShort) {
+ TestReadInvalidLength(sizeof(fuse_in_header) - 1, sizeof(fuse_in_header) - 1);
+}
+
+TEST(FuseMessageTest, Write_TooLong) {
+ TestWriteInvalidLength(sizeof(FuseRequest) + 1);
+}
+
+TEST(FuseMessageTest, Write_TooShort) {
+ TestWriteInvalidLength(sizeof(fuse_in_header) - 1);
+}
+
+TEST(FuseResponseTest, Reset) {
+ FuseResponse response;
+ // Write 1 to the first ten bytes.
+ memset(response.read_data, 'a', 10);
+
+ response.Reset(0, -1, 2);
+ EXPECT_EQ(sizeof(fuse_out_header), response.header.len);
+ EXPECT_EQ(-1, response.header.error);
+ EXPECT_EQ(2u, response.header.unique);
+ EXPECT_EQ('a', response.read_data[0]);
+ EXPECT_EQ('a', response.read_data[9]);
+
+ response.Reset(5, -4, 3);
+ EXPECT_EQ(sizeof(fuse_out_header) + 5, response.header.len);
+ EXPECT_EQ(-4, response.header.error);
+ EXPECT_EQ(3u, response.header.unique);
+ EXPECT_EQ(0, response.read_data[0]);
+ EXPECT_EQ(0, response.read_data[1]);
+ EXPECT_EQ(0, response.read_data[2]);
+ EXPECT_EQ(0, response.read_data[3]);
+ EXPECT_EQ(0, response.read_data[4]);
+ EXPECT_EQ('a', response.read_data[5]);
+}
+
+TEST(FuseResponseTest, ResetHeader) {
+ FuseResponse response;
+ // Write 1 to the first ten bytes.
+ memset(response.read_data, 'a', 10);
+
+ response.ResetHeader(0, -1, 2);
+ EXPECT_EQ(sizeof(fuse_out_header), response.header.len);
+ EXPECT_EQ(-1, response.header.error);
+ EXPECT_EQ(2u, response.header.unique);
+ EXPECT_EQ('a', response.read_data[0]);
+ EXPECT_EQ('a', response.read_data[9]);
+
+ response.ResetHeader(5, -4, 3);
+ EXPECT_EQ(sizeof(fuse_out_header) + 5, response.header.len);
+ EXPECT_EQ(-4, response.header.error);
+ EXPECT_EQ(3u, response.header.unique);
+ EXPECT_EQ('a', response.read_data[0]);
+ EXPECT_EQ('a', response.read_data[9]);
+}
+
+TEST(FuseBufferTest, HandleInit) {
+ FuseBuffer buffer;
+ memset(&buffer, 0, sizeof(FuseBuffer));
+
+ buffer.request.header.opcode = FUSE_INIT;
+ buffer.request.init_in.major = FUSE_KERNEL_VERSION;
+ buffer.request.init_in.minor = FUSE_KERNEL_MINOR_VERSION;
+
+ buffer.HandleInit();
+
+ ASSERT_EQ(sizeof(fuse_out_header) + sizeof(fuse_init_out),
+ buffer.response.header.len);
+ EXPECT_EQ(kFuseSuccess, buffer.response.header.error);
+ EXPECT_EQ(static_cast<unsigned int>(FUSE_KERNEL_VERSION),
+ buffer.response.init_out.major);
+ EXPECT_EQ(15u, buffer.response.init_out.minor);
+ EXPECT_EQ(static_cast<unsigned int>(FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES),
+ buffer.response.init_out.flags);
+ EXPECT_EQ(kFuseMaxWrite, buffer.response.init_out.max_write);
+}
+
+TEST(FuseBufferTest, HandleNotImpl) {
+ FuseBuffer buffer;
+ memset(&buffer, 0, sizeof(FuseBuffer));
+
+ buffer.HandleNotImpl();
+
+ ASSERT_EQ(sizeof(fuse_out_header), buffer.response.header.len);
+ EXPECT_EQ(-ENOSYS, buffer.response.header.error);
+}
+}
+ // namespace android
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 943926b..f7b497d 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -34,6 +34,7 @@
host_supported: true,
srcs: [
"config_utils.c",
+ "files.cpp",
"fs_config.c",
"canned_fs_config.c",
"hashmap.c",
diff --git a/libcutils/files.cpp b/libcutils/files.cpp
new file mode 100644
index 0000000..bf15b42
--- /dev/null
+++ b/libcutils/files.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * 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>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cutils/files.h>
+
+#ifndef TEMP_FAILURE_RETRY // _WIN32 does not define
+#define TEMP_FAILURE_RETRY(exp) (exp)
+#endif
+
+int android_get_control_file(const char* path) {
+ if (!path) return -1;
+
+ char *key = NULL;
+ if (asprintf(&key, ANDROID_FILE_ENV_PREFIX "%s", path) < 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(__linux__)
+ char *proc = NULL;
+ if (asprintf(&proc, "/proc/self/fd/%ld", fd) < 0) return -1;
+ if (!proc) return -1;
+
+ size_t len = strlen(path);
+ char *buf = static_cast<char *>(calloc(1, len + 2));
+ if (!buf) {
+ free(proc);
+ return -1;
+ }
+ ssize_t ret = TEMP_FAILURE_RETRY(readlink(proc, buf, len + 1));
+ free(proc);
+ int cmp = (len != static_cast<size_t>(ret)) || strcmp(buf, path);
+ free(buf);
+ if (ret < 0) return -1;
+ if (cmp != 0) return -1;
+#endif
+
+ // It is what we think it is
+ return static_cast<int>(fd);
+}
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 293e78a..99f97d1 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -140,18 +140,39 @@
{ 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procmem" },
/* the following files have enhanced capabilities and ARE included in user builds. */
- { 00750, AID_ROOT, AID_SHELL, CAP_MASK_LONG(CAP_SETUID) | CAP_MASK_LONG(CAP_SETGID), "system/bin/run-as" },
- { 00700, AID_SYSTEM, AID_SHELL, CAP_MASK_LONG(CAP_BLOCK_SUSPEND), "system/bin/inputflinger" },
+ { 00550, AID_LOGD, AID_LOGD, CAP_MASK_LONG(CAP_SYSLOG) |
+ CAP_MASK_LONG(CAP_AUDIT_CONTROL) |
+ CAP_MASK_LONG(CAP_SETGID),
+ "system/bin/logd" },
+ { 00750, AID_ROOT, AID_SHELL, CAP_MASK_LONG(CAP_SETUID) |
+ CAP_MASK_LONG(CAP_SETGID),
+ "system/bin/run-as" },
+ { 00700, AID_SYSTEM, AID_SHELL, CAP_MASK_LONG(CAP_BLOCK_SUSPEND),
+ "system/bin/inputflinger" },
/* Support FIFO scheduling mode in SurfaceFlinger. */
- { 00755, AID_SYSTEM, AID_GRAPHICS, CAP_MASK_LONG(CAP_SYS_NICE), "system/bin/surfaceflinger" },
+ { 00755, AID_SYSTEM, AID_GRAPHICS, CAP_MASK_LONG(CAP_SYS_NICE),
+ "system/bin/surfaceflinger" },
/* Support hostapd administering a network interface. */
- { 00755, AID_WIFI, AID_WIFI, CAP_MASK_LONG(CAP_NET_ADMIN) |
- CAP_MASK_LONG(CAP_NET_RAW), "system/bin/hostapd" },
+ { 00755, AID_WIFI, AID_WIFI, CAP_MASK_LONG(CAP_NET_ADMIN) |
+ CAP_MASK_LONG(CAP_NET_RAW),
+ "system/bin/hostapd" },
/* Support wifi_hal_legacy administering a network interface. */
- { 00755, AID_WIFI, AID_WIFI, CAP_MASK_LONG(CAP_NET_ADMIN) | CAP_MASK_LONG(CAP_NET_RAW), "system/bin/hw/android.hardware.wifi@1.0-service" },
+ { 00755, AID_WIFI, AID_WIFI, CAP_MASK_LONG(CAP_NET_ADMIN) |
+ CAP_MASK_LONG(CAP_NET_RAW),
+ "system/bin/hw/android.hardware.wifi@1.0-service" },
+
+ /* A non-privileged zygote that spawns isolated processes for web rendering. */
+ { 0750, AID_ROOT, AID_ROOT, CAP_MASK_LONG(CAP_SETUID) |
+ CAP_MASK_LONG(CAP_SETGID) |
+ CAP_MASK_LONG(CAP_SETPCAP),
+ "system/bin/webview_zygote32" },
+ { 0750, AID_ROOT, AID_ROOT, CAP_MASK_LONG(CAP_SETUID) |
+ CAP_MASK_LONG(CAP_SETGID) |
+ CAP_MASK_LONG(CAP_SETPCAP),
+ "system/bin/webview_zygote64" },
{ 00750, AID_ROOT, AID_ROOT, 0, "system/bin/uncrypt" },
{ 00750, AID_ROOT, AID_ROOT, 0, "system/bin/install-recovery.sh" },
diff --git a/libcutils/klog.cpp b/libcutils/klog.cpp
index 061af1b..9d823cf 100644
--- a/libcutils/klog.cpp
+++ b/libcutils/klog.cpp
@@ -24,6 +24,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include <cutils/files.h>
#include <cutils/klog.h>
static int klog_level = KLOG_DEFAULT_LEVEL;
@@ -37,7 +38,11 @@
}
static int __open_klog(void) {
- return TEMP_FAILURE_RETRY(open("/dev/kmsg", O_WRONLY | O_CLOEXEC));
+ static const char kmsg_device[] = "/dev/kmsg";
+
+ int ret = android_get_control_file(kmsg_device);
+ if (ret >= 0) return ret;
+ return TEMP_FAILURE_RETRY(open(kmsg_device, O_WRONLY | O_CLOEXEC));
}
#define LOG_BUF_MAX 512
diff --git a/libcutils/sockets.cpp b/libcutils/sockets.cpp
index bba63ac..63761a2 100644
--- a/libcutils/sockets.cpp
+++ b/libcutils/sockets.cpp
@@ -28,11 +28,31 @@
// 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>
-#if !defined(_WIN32)
-#include <netinet/in.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) {
@@ -47,22 +67,56 @@
}
int android_get_control_socket(const char* name) {
- char key[64];
- snprintf(key, sizeof(key), ANDROID_SOCKET_ENV_PREFIX "%s", 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);
- if (!val) {
- return -1;
- }
+ free(key);
+ if (!val) return -1;
errno = 0;
- long ret = strtol(val, NULL, 10);
- if (errno) {
- return -1;
- }
- if (ret < 0 || ret > INT_MAX) {
- return -1;
- }
+ long fd = strtol(val, NULL, 10);
+ if (errno) return -1;
- return static_cast<int>(ret);
+ // 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/tests/Android.bp b/libcutils/tests/Android.bp
index 06d0e28..bd35412 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"],
+ srcs: ["sockets_test.cpp", "files_test.cpp"],
target: {
android: {
diff --git a/libcutils/tests/files_test.cpp b/libcutils/tests/files_test.cpp
new file mode 100644
index 0000000..1a7d673
--- /dev/null
+++ b/libcutils/tests/files_test.cpp
@@ -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.
+ */
+
+#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 0f682a2..adfbf4a 100644
--- a/libcutils/tests/sockets_test.cpp
+++ b/libcutils/tests/sockets_test.cpp
@@ -18,10 +18,14 @@
// IPv6 capabilities. These tests assume that no UDP packets are lost, which
// should be the case for loopback communication, but is not guaranteed.
-#include <cutils/sockets.h>
-
+#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>
// Makes sure the passed sockets are valid, sends data between them, and closes
@@ -185,3 +189,49 @@
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/event_tag_map.c b/liblog/event_tag_map.c
index 0e5a281..f9cad99 100644
--- a/liblog/event_tag_map.c
+++ b/liblog/event_tag_map.c
@@ -38,6 +38,8 @@
uint32_t tagIndex;
char* tagStr;
size_t tagLen;
+ char* fmtStr;
+ size_t fmtLen;
} EventTag;
/*
@@ -176,6 +178,39 @@
return NULL;
}
+/*
+ * Look up an entry in the map.
+ *
+ * The entries are sorted by tag number, so we can do a binary search.
+ */
+LIBLOG_ABI_PUBLIC const char* android_lookupEventFormat_len(
+ const EventTagMap* map, size_t *len, unsigned int tag)
+{
+ int lo = 0;
+ int hi = map->numTags - 1;
+
+ while (lo <= hi) {
+ int mid = (lo + hi) / 2;
+ int cmp = map->tagArray[mid].tagIndex - tag;
+
+ if (cmp < 0) {
+ /* tag is bigger */
+ lo = mid + 1;
+ } else if (cmp > 0) {
+ /* tag is smaller */
+ hi = mid - 1;
+ } else {
+ /* found */
+ if (len) *len = map->tagArray[mid].fmtLen;
+ return map->tagArray[mid].fmtStr;
+ }
+ }
+
+ errno = ENOENT;
+ if (len) *len = 0;
+ return NULL;
+}
+
LIBLOG_ABI_PUBLIC const char* android_lookupEventTag(const EventTagMap* map,
unsigned int tag)
{
@@ -364,17 +399,21 @@
}
tag->tagLen = cp - tag->tagStr;
- if (isspace(*cp)) {
- /* just ignore the rest of the line till \n
- TODO: read the tag description that follows the tag name
- */
- while (*cp != '\n') ++cp;
- } else {
+ if (!isspace(*cp)) {
fprintf(stderr, "%s: invalid tag chars on line %d\n", OUT_TAG, lineNum);
errno = EINVAL;
return -1;
}
+ while (isspace(*cp) && (*cp != '\n')) ++cp;
+ if (*cp != '#') {
+ tag->fmtStr = cp;
+ while ((*cp != '\n') && (*cp != '#')) ++cp;
+ while ((cp > tag->fmtStr) && isspace(*(cp - 1))) --cp;
+ tag->fmtLen = cp - tag->fmtStr;
+ }
+
+ while (*cp != '\n') ++cp;
*pData = cp;
return 0;
@@ -406,12 +445,14 @@
for (i = 1; i < map->numTags; i++) {
if (map->tagArray[i].tagIndex == map->tagArray[i - 1].tagIndex) {
fprintf(stderr,
- "%s: duplicate tag entries (%" PRIu32 ":%.*s and %" PRIu32 ":%.*s)\n",
+ "%s: duplicate tag entries (%" PRIu32 ":%.*s:%.*s and %" PRIu32 ":%.*s:%.*s)\n",
OUT_TAG,
- map->tagArray[i].tagIndex, (int)map->tagArray[i].tagLen,
- map->tagArray[i].tagStr,
- map->tagArray[i - 1].tagIndex, (int)map->tagArray[i - 1].tagLen,
- map->tagArray[i - 1].tagStr);
+ map->tagArray[i].tagIndex,
+ (int)map->tagArray[i].tagLen, map->tagArray[i].tagStr,
+ (int)map->tagArray[i].fmtLen, map->tagArray[i].fmtStr,
+ map->tagArray[i - 1].tagIndex,
+ (int)map->tagArray[i - 1].tagLen, map->tagArray[i - 1].fmtStr,
+ (int)map->tagArray[i - 1].fmtLen, map->tagArray[i - 1].fmtStr);
errno = EMLINK;
return -1;
}
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 1ff7136..fb942a1 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -21,13 +21,13 @@
#include <assert.h>
#include <ctype.h>
#include <errno.h>
+#include <inttypes.h>
#include <pwd.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <inttypes.h>
#include <sys/param.h>
#include <sys/types.h>
@@ -58,9 +58,16 @@
bool epoch_output;
bool monotonic_output;
bool uid_output;
+ bool descriptive_output;
};
/*
+ * API issues prevent us from exposing "descriptive" in AndroidLogFormat_t
+ * during android_log_processBinaryLogBuffer(), so we break layering.
+ */
+static bool descriptive_output = false;
+
+/*
* gnome-terminal color tags
* See http://misc.flogisoft.com/bash/tip_colors_and_formatting
* for ideas on how to set the forground color of the text for xterm.
@@ -209,6 +216,8 @@
p_ret->epoch_output = false;
p_ret->monotonic_output = android_log_clockid() == CLOCK_MONOTONIC;
p_ret->uid_output = false;
+ p_ret->descriptive_output = false;
+ descriptive_output = false;
return p_ret;
}
@@ -267,6 +276,10 @@
case FORMAT_MODIFIER_UID:
p_format->uid_output = true;
return 0;
+ case FORMAT_MODIFIER_DESCRIPT:
+ p_format->descriptive_output = true;
+ descriptive_output = true;
+ return 0;
default:
break;
}
@@ -294,6 +307,7 @@
else if (strcmp(formatString, "threadtime") == 0) format = FORMAT_THREADTIME;
else if (strcmp(formatString, "long") == 0) format = FORMAT_LONG;
else if (strcmp(formatString, "color") == 0) format = FORMAT_MODIFIER_COLOR;
+ else if (strcmp(formatString, "colour") == 0) format = FORMAT_MODIFIER_COLOR;
else if (strcmp(formatString, "usec") == 0) format = FORMAT_MODIFIER_TIME_USEC;
else if (strcmp(formatString, "printable") == 0) format = FORMAT_MODIFIER_PRINTABLE;
else if (strcmp(formatString, "year") == 0) format = FORMAT_MODIFIER_YEAR;
@@ -301,6 +315,7 @@
else if (strcmp(formatString, "epoch") == 0) format = FORMAT_MODIFIER_EPOCH;
else if (strcmp(formatString, "monotonic") == 0) format = FORMAT_MODIFIER_MONOTONIC;
else if (strcmp(formatString, "uid") == 0) format = FORMAT_MODIFIER_UID;
+ else if (strcmp(formatString, "descriptive") == 0) format = FORMAT_MODIFIER_DESCRIPT;
else {
extern char *tzname[2];
static const char gmt[] = "GMT";
@@ -566,6 +581,19 @@
return ((uint64_t) high << 32) | (uint64_t) low;
}
+static bool findChar(const char** cp, size_t* len, int c) {
+ while (*len && isspace(**cp)) {
+ ++*cp;
+ --*len;
+ }
+ if (c == INT_MAX) return *len;
+ if (*len && (**cp == c)) {
+ ++*cp;
+ --*len;
+ return true;
+ }
+ return false;
+}
/*
* Recursively convert binary log data to printable form.
@@ -578,27 +606,128 @@
*
* Returns 0 on success, 1 on buffer full, -1 on failure.
*/
+enum objectType {
+ TYPE_OBJECTS = '1',
+ TYPE_BYTES = '2',
+ TYPE_MILLISECONDS = '3',
+ TYPE_ALLOCATIONS = '4',
+ TYPE_ID = '5',
+ TYPE_PERCENT = '6'
+};
+
static int android_log_printBinaryEvent(const unsigned char** pEventData,
- size_t* pEventDataLen, char** pOutBuf, size_t* pOutBufLen)
+ size_t* pEventDataLen, char** pOutBuf, size_t* pOutBufLen,
+ const char** fmtStr, size_t* fmtLen)
{
const unsigned char* eventData = *pEventData;
size_t eventDataLen = *pEventDataLen;
char* outBuf = *pOutBuf;
+ char* outBufSave = outBuf;
size_t outBufLen = *pOutBufLen;
+ size_t outBufLenSave = outBufLen;
unsigned char type;
size_t outCount;
int result = 0;
+ const char* cp;
+ size_t len;
+ int64_t lval;
if (eventDataLen < 1)
return -1;
type = *eventData++;
eventDataLen--;
+ cp = NULL;
+ len = 0;
+ if (fmtStr && *fmtStr && fmtLen && *fmtLen && **fmtStr) {
+ cp = *fmtStr;
+ len = *fmtLen;
+ }
+ /*
+ * event.logtag format specification:
+ *
+ * Optionally, after the tag names can be put a description for the value(s)
+ * of the tag. Description are in the format
+ * (<name>|data type[|data unit])
+ * Multiple values are separated by commas.
+ *
+ * The data type is a number from the following values:
+ * 1: int
+ * 2: long
+ * 3: string
+ * 4: list
+ * 5: float
+ *
+ * The data unit is a number taken from the following list:
+ * 1: Number of objects
+ * 2: Number of bytes
+ * 3: Number of milliseconds
+ * 4: Number of allocations
+ * 5: Id
+ * 6: Percent
+ * Default value for data of type int/long is 2 (bytes).
+ */
+ if (!cp || !findChar(&cp, &len, '(')) {
+ len = 0;
+ } else {
+ char* outBufLastSpace = NULL;
+
+ findChar(&cp, &len, INT_MAX);
+ while (len && *cp && (*cp != '|') && (*cp != ')')) {
+ if (outBufLen <= 0) {
+ /* halt output */
+ goto no_room;
+ }
+ outBufLastSpace = isspace(*cp) ? outBuf : NULL;
+ *outBuf = *cp;
+ ++outBuf;
+ ++cp;
+ --outBufLen;
+ --len;
+ }
+ if (outBufLastSpace) {
+ outBufLen += outBuf - outBufLastSpace;
+ outBuf = outBufLastSpace;
+ }
+ if (outBufLen <= 0) {
+ /* halt output */
+ goto no_room;
+ }
+ if (outBufSave != outBuf) {
+ *outBuf = '=';
+ ++outBuf;
+ --outBufLen;
+ }
+
+ if (findChar(&cp, &len, '|') && findChar(&cp, &len, INT_MAX)) {
+ static const unsigned char typeTable[] = {
+ EVENT_TYPE_INT,
+ EVENT_TYPE_LONG,
+ EVENT_TYPE_STRING,
+ EVENT_TYPE_LIST,
+ EVENT_TYPE_FLOAT
+ };
+
+ if ((*cp >= '1') &&
+ (*cp < (char)('1' + (sizeof(typeTable) / sizeof(typeTable[0])))) &&
+ (type != typeTable[(size_t)(*cp - '1')])) len = 0;
+
+ if (len) {
+ ++cp;
+ --len;
+ } else {
+ /* reset the format */
+ outBuf = outBufSave;
+ outBufLen = outBufLenSave;
+ }
+ }
+ }
+ lval = 0;
switch (type) {
case EVENT_TYPE_INT:
/* 32-bit signed int */
{
- int ival;
+ int32_t ival;
if (eventDataLen < 4)
return -1;
@@ -606,35 +735,24 @@
eventData += 4;
eventDataLen -= 4;
- outCount = snprintf(outBuf, outBufLen, "%d", ival);
- if (outCount < outBufLen) {
- outBuf += outCount;
- outBufLen -= outCount;
- } else {
- /* halt output */
- goto no_room;
- }
+ lval = ival;
}
- break;
+ goto pr_lval;
case EVENT_TYPE_LONG:
/* 64-bit signed long */
- {
- uint64_t lval;
-
- if (eventDataLen < 8)
- return -1;
- lval = get8LE(eventData);
- eventData += 8;
- eventDataLen -= 8;
-
- outCount = snprintf(outBuf, outBufLen, "%" PRId64, lval);
- if (outCount < outBufLen) {
- outBuf += outCount;
- outBufLen -= outCount;
- } else {
- /* halt output */
- goto no_room;
- }
+ if (eventDataLen < 8)
+ return -1;
+ lval = get8LE(eventData);
+ eventData += 8;
+ eventDataLen -= 8;
+ pr_lval:
+ outCount = snprintf(outBuf, outBufLen, "%" PRId64, lval);
+ if (outCount < outBufLen) {
+ outBuf += outCount;
+ outBufLen -= outCount;
+ } else {
+ /* halt output */
+ goto no_room;
}
break;
case EVENT_TYPE_FLOAT:
@@ -674,6 +792,11 @@
if (eventDataLen < strLen)
return -1;
+ if (cp && (strLen == 0)) {
+ /* reset the format if no content */
+ outBuf = outBufSave;
+ outBufLen = outBufLenSave;
+ }
if (strLen < outBufLen) {
memcpy(outBuf, eventData, strLen);
outBuf += strLen;
@@ -710,7 +833,7 @@
for (i = 0; i < count; i++) {
result = android_log_printBinaryEvent(&eventData, &eventDataLen,
- &outBuf, &outBufLen);
+ &outBuf, &outBufLen, fmtStr, fmtLen);
if (result != 0)
goto bail;
@@ -736,12 +859,90 @@
fprintf(stderr, "Unknown binary event type %d\n", type);
return -1;
}
+ if (cp && len) {
+ if (findChar(&cp, &len, '|') && findChar(&cp, &len, INT_MAX)) {
+ switch (*cp) {
+ case TYPE_OBJECTS:
+ outCount = 0;
+ /* outCount = snprintf(outBuf, outBufLen, " objects"); */
+ break;
+ case TYPE_BYTES:
+ if ((lval != 0) && ((lval % 1024) == 0)) {
+ /* repaint with multiplier */
+ static const char suffixTable[] = { 'K', 'M', 'G', 'T' };
+ size_t idx = 0;
+ outBuf -= outCount;
+ outBufLen += outCount;
+ do {
+ lval /= 1024;
+ if ((lval % 1024) != 0) break;
+ } while (++idx < ((sizeof(suffixTable) /
+ sizeof(suffixTable[0])) - 1));
+ outCount = snprintf(outBuf, outBufLen,
+ "%" PRId64 "%cB",
+ lval, suffixTable[idx]);
+ } else {
+ outCount = snprintf(outBuf, outBufLen, "B");
+ }
+ break;
+ case TYPE_MILLISECONDS:
+ if (((lval <= -1000) || (1000 <= lval)) &&
+ (outBufLen || (outBuf[-1] == '0'))) {
+ /* repaint as (fractional) seconds, possibly saving space */
+ if (outBufLen) outBuf[0] = outBuf[-1];
+ outBuf[-1] = outBuf[-2];
+ outBuf[-2] = outBuf[-3];
+ outBuf[-3] = '.';
+ while ((outBufLen == 0) || (*outBuf == '0')) {
+ --outBuf;
+ ++outBufLen;
+ }
+ if (*outBuf != '.') {
+ ++outBuf;
+ --outBufLen;
+ }
+ outCount = snprintf(outBuf, outBufLen, "s");
+ } else {
+ outCount = snprintf(outBuf, outBufLen, "ms");
+ }
+ break;
+ case TYPE_ALLOCATIONS:
+ outCount = 0;
+ /* outCount = snprintf(outBuf, outBufLen, " allocations"); */
+ break;
+ case TYPE_ID:
+ outCount = 0;
+ break;
+ case TYPE_PERCENT:
+ outCount = snprintf(outBuf, outBufLen, "%%");
+ break;
+ default: /* ? */
+ outCount = 0;
+ break;
+ }
+ ++cp;
+ --len;
+ if (outCount < outBufLen) {
+ outBuf += outCount;
+ outBufLen -= outCount;
+ } else if (outCount) {
+ /* halt output */
+ goto no_room;
+ }
+ }
+ if (!findChar(&cp, &len, ')')) len = 0;
+ if (!findChar(&cp, &len, ',')) len = 0;
+ }
bail:
*pEventData = eventData;
*pEventDataLen = eventDataLen;
*pOutBuf = outBuf;
*pOutBufLen = outBufLen;
+ if (cp) {
+ *fmtStr = cp;
+ *fmtLen = len;
+ }
return result;
no_room:
@@ -764,7 +965,7 @@
char *messageBuf, int messageBufLen)
{
size_t inCount;
- unsigned int tagIndex;
+ uint32_t tagIndex;
const unsigned char* eventData;
entry->tv_sec = buf->sec;
@@ -817,7 +1018,7 @@
if (entry->tag == NULL) {
size_t tagLen;
- tagLen = snprintf(messageBuf, messageBufLen, "[%d]", tagIndex);
+ tagLen = snprintf(messageBuf, messageBufLen, "[%" PRIu32 "]", tagIndex);
if (tagLen >= (size_t)messageBufLen) {
tagLen = messageBufLen - 1;
}
@@ -831,10 +1032,27 @@
* Format the event log data into the buffer.
*/
char* outBuf = messageBuf;
- size_t outRemaining = messageBufLen-1; /* leave one for nul byte */
+ 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);
+ &outRemaining, &fmtStr, &fmtLen);
+ if ((result == 1) && fmtStr) {
+ /* We overflowed :-(, let's repaint the line w/o format dressings */
+ eventData = (const unsigned char*)buf->msg;
+ if (buf2->hdr_size) {
+ eventData = ((unsigned char *)buf2) + buf2->hdr_size;
+ }
+ eventData += 4;
+ outBuf = messageBuf;
+ outRemaining = messageBufLen - 1;
+ result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
+ &outRemaining, NULL, NULL);
+ }
if (result < 0) {
fprintf(stderr, "Binary log entry conversion failed\n");
return -1;
diff --git a/liblog/tests/libc_test.cpp b/liblog/tests/libc_test.cpp
index 3d58147..f05a955 100644
--- a/liblog/tests/libc_test.cpp
+++ b/liblog/tests/libc_test.cpp
@@ -16,6 +16,7 @@
#include <gtest/gtest.h>
+#include <errno.h>
#include <stdio.h>
TEST(libc, __pstore_append) {
@@ -23,6 +24,22 @@
ASSERT_TRUE(NULL != (fp = fopen("/dev/pmsg0", "a")));
static const char message[] = "libc.__pstore_append\n";
ASSERT_EQ((size_t)1, fwrite(message, sizeof(message), 1, fp));
- ASSERT_EQ(0, fclose(fp));
- fprintf(stderr, "Reboot, ensure string libc.__pstore_append is in /sys/fs/pstore/pmsg-ramoops-0\n");
+ int fflushReturn = fflush(fp);
+ int fflushErrno = fflushReturn ? errno : 0;
+ ASSERT_EQ(0, fflushReturn);
+ ASSERT_EQ(0, fflushErrno);
+ int fcloseReturn = fclose(fp);
+ int fcloseErrno = fcloseReturn ? errno : 0;
+ ASSERT_EQ(0, fcloseReturn);
+ ASSERT_EQ(0, fcloseErrno);
+ if ((fcloseErrno == ENOMEM) || (fflushErrno == ENOMEM)) {
+ fprintf(stderr,
+ "Kernel does not have space allocated to pmsg pstore driver configured\n"
+ );
+ }
+ if (!fcloseReturn && !fcloseErrno && !fflushReturn && !fflushReturn) {
+ fprintf(stderr,
+ "Reboot, ensure string libc.__pstore_append is in /sys/fs/pstore/pmsg-ramoops-0\n"
+ );
+ }
}
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index fd38849..9c09523 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -16,6 +16,7 @@
#include <ctype.h>
#include <dirent.h>
+#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <semaphore.h>
@@ -2655,12 +2656,19 @@
bool logdwActiveAfter__android_log_close = isLogdwActive();
EXPECT_FALSE(pmsgActiveAfter__android_log_close);
EXPECT_FALSE(logdwActiveAfter__android_log_close);
- EXPECT_LT(0, __android_log_pmsg_file_write(
+ int return__android_log_pmsg_file_write = __android_log_pmsg_file_write(
LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
- __pmsg_file, max_payload_buf, sizeof(max_payload_buf)));
- fprintf(stderr, "Reboot, ensure file %s matches\n"
- "with liblog.__android_log_msg_file_read test\n",
- __pmsg_file);
+ __pmsg_file, max_payload_buf, sizeof(max_payload_buf));
+ EXPECT_LT(0, return__android_log_pmsg_file_write);
+ if (return__android_log_pmsg_file_write == -ENOMEM) {
+ fprintf(stderr,
+ "Kernel does not have space allocated to pmsg pstore driver configured\n"
+ );
+ } else if (!return__android_log_pmsg_file_write) {
+ fprintf(stderr, "Reboot, ensure file %s matches\n"
+ "with liblog.__android_log_msg_file_read test\n",
+ __pmsg_file);
+ }
bool pmsgActiveAfter__android_pmsg_file_write = isPmsgActive();
bool logdwActiveAfter__android_pmsg_file_write = isLogdwActive();
EXPECT_FALSE(pmsgActiveAfter__android_pmsg_file_write);
diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc
index 43e6c0a..eafc53d 100644
--- a/libnativebridge/native_bridge.cc
+++ b/libnativebridge/native_bridge.cc
@@ -551,15 +551,15 @@
return -1;
}
-char* NativeBridgeGetError() {
+const char* NativeBridgeGetError() {
if (NativeBridgeInitialized()) {
if (isCompatibleWith(NAMESPACE_VERSION)) {
return callbacks->getError();
} else {
- ALOGE("not compatible with version %d, cannot get message", NAMESPACE_VERSION);
+ return "native bridge implementation is not compatible with version 3, cannot get message";
}
}
- return nullptr;
+ return "native bridge is not initialized";
}
bool NativeBridgeIsPathSupported(const char* path) {
diff --git a/libnativebridge/tests/DummyNativeBridge3.cpp b/libnativebridge/tests/DummyNativeBridge3.cpp
index c538fa0..13fce85 100644
--- a/libnativebridge/tests/DummyNativeBridge3.cpp
+++ b/libnativebridge/tests/DummyNativeBridge3.cpp
@@ -68,7 +68,7 @@
return 0;
}
-extern "C" char* native_bridge3_getError() {
+extern "C" const char* native_bridge3_getError() {
return nullptr;
}
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index fb95cb6..15fe054 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -308,13 +308,17 @@
// code is one example) unknown to linker in which case linker uses anonymous
// namespace. The second argument specifies the search path for the anonymous
// namespace which is the library_path of the classloader.
- if (!is_native_bridge) {
- initialized_ = android_init_namespaces(public_libraries_.c_str(), library_path);
- if (!initialized_) {
- *error_msg = dlerror();
- }
- } else {
- initialized_ = NativeBridgeInitNamespace(public_libraries_.c_str(), library_path);
+ initialized_ = android_init_namespaces(public_libraries_.c_str(),
+ is_native_bridge ? nullptr : library_path);
+ if (!initialized_) {
+ *error_msg = dlerror();
+ return false;
+ }
+
+ // and now initialize native bridge namespaces if necessary.
+ if (NativeBridgeInitialized()) {
+ initialized_ = NativeBridgeInitNamespace(public_libraries_.c_str(),
+ is_native_bridge ? library_path : nullptr);
if (!initialized_) {
*error_msg = NativeBridgeGetError();
}
@@ -473,14 +477,14 @@
}
#if defined(__ANDROID__)
+// native_bridge_namespaces are not supported for callers of this function.
+// This function will return nullptr in the case when application is running
+// on native bridge.
android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
- // native_bridge_namespaces are not supported for callers of this function.
- // At the moment this is libwebviewchromium_loader and vulkan.
NativeLoaderNamespace ns;
if (g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
- CHECK(ns.is_android_namespace());
- return ns.get_android_ns();
+ return ns.is_android_namespace() ? ns.get_android_ns() : nullptr;
}
return nullptr;
diff --git a/libsuspend/Android.bp b/libsuspend/Android.bp
index d27ceea..d442c94 100644
--- a/libsuspend/Android.bp
+++ b/libsuspend/Android.bp
@@ -4,8 +4,6 @@
name: "libsuspend",
srcs: [
"autosuspend.c",
- "autosuspend_autosleep.c",
- "autosuspend_earlysuspend.c",
"autosuspend_wakeup_count.c",
],
export_include_dirs: ["include"],
diff --git a/libsuspend/autosuspend.c b/libsuspend/autosuspend.c
index 64d1bfc..2e1983a 100644
--- a/libsuspend/autosuspend.c
+++ b/libsuspend/autosuspend.c
@@ -34,19 +34,6 @@
return 0;
}
- autosuspend_ops = autosuspend_earlysuspend_init();
- if (autosuspend_ops) {
- goto out;
- }
-
-/* Remove autosleep so userspace can manager suspend/resume and keep stats */
-#if 0
- autosuspend_ops = autosuspend_autosleep_init();
- if (autosuspend_ops) {
- goto out;
- }
-#endif
-
autosuspend_ops = autosuspend_wakeup_count_init();
if (autosuspend_ops) {
goto out;
diff --git a/libsuspend/autosuspend_autosleep.c b/libsuspend/autosuspend_autosleep.c
deleted file mode 100644
index 97109ac..0000000
--- a/libsuspend/autosuspend_autosleep.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#define LOG_TAG "libsuspend"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stddef.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <android/log.h>
-
-#include "autosuspend_ops.h"
-
-#define SYS_POWER_AUTOSLEEP "/sys/power/autosleep"
-
-static int autosleep_fd;
-static const char *sleep_state = "mem";
-static const char *on_state = "off";
-
-static int autosuspend_autosleep_enable(void)
-{
- char buf[80];
- int ret;
-
- ALOGV("autosuspend_autosleep_enable\n");
-
- ret = TEMP_FAILURE_RETRY(write(autosleep_fd, sleep_state, strlen(sleep_state)));
- if (ret < 0) {
- strerror_r(errno, buf, sizeof(buf));
- ALOGE("Error writing to %s: %s\n", SYS_POWER_AUTOSLEEP, buf);
- goto err;
- }
-
- ALOGV("autosuspend_autosleep_enable done\n");
-
- return 0;
-
-err:
- return ret;
-}
-
-static int autosuspend_autosleep_disable(void)
-{
- char buf[80];
- int ret;
-
- ALOGV("autosuspend_autosleep_disable\n");
-
- ret = TEMP_FAILURE_RETRY(write(autosleep_fd, on_state, strlen(on_state)));
- if (ret < 0) {
- strerror_r(errno, buf, sizeof(buf));
- ALOGE("Error writing to %s: %s\n", SYS_POWER_AUTOSLEEP, buf);
- goto err;
- }
-
- ALOGV("autosuspend_autosleep_disable done\n");
-
- return 0;
-
-err:
- return ret;
-}
-
-struct autosuspend_ops autosuspend_autosleep_ops = {
- .enable = autosuspend_autosleep_enable,
- .disable = autosuspend_autosleep_disable,
-};
-
-struct autosuspend_ops *autosuspend_autosleep_init(void)
-{
- char buf[80];
-
- autosleep_fd = TEMP_FAILURE_RETRY(open(SYS_POWER_AUTOSLEEP, O_WRONLY));
- if (autosleep_fd < 0) {
- strerror_r(errno, buf, sizeof(buf));
- ALOGE("Error opening %s: %s\n", SYS_POWER_AUTOSLEEP, buf);
- return NULL;
- }
-
- ALOGI("Selected autosleep\n");
-
- autosuspend_autosleep_disable();
-
- return &autosuspend_autosleep_ops;
-}
diff --git a/libsuspend/autosuspend_earlysuspend.c b/libsuspend/autosuspend_earlysuspend.c
deleted file mode 100644
index 9519e51..0000000
--- a/libsuspend/autosuspend_earlysuspend.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#define LOG_TAG "libsuspend"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <android/log.h>
-
-#include "autosuspend_ops.h"
-
-#define EARLYSUSPEND_SYS_POWER_STATE "/sys/power/state"
-#define EARLYSUSPEND_WAIT_FOR_FB_SLEEP "/sys/power/wait_for_fb_sleep"
-#define EARLYSUSPEND_WAIT_FOR_FB_WAKE "/sys/power/wait_for_fb_wake"
-
-static int sPowerStatefd;
-static const char *pwr_state_mem = "mem";
-static const char *pwr_state_on = "on";
-static pthread_t earlysuspend_thread;
-static pthread_mutex_t earlysuspend_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t earlysuspend_cond = PTHREAD_COND_INITIALIZER;
-static bool wait_for_earlysuspend;
-static enum {
- EARLYSUSPEND_ON,
- EARLYSUSPEND_MEM,
-} earlysuspend_state = EARLYSUSPEND_ON;
-
-int wait_for_fb_wake(void)
-{
- int err = 0;
- char buf;
- int fd = TEMP_FAILURE_RETRY(open(EARLYSUSPEND_WAIT_FOR_FB_WAKE, O_RDONLY, 0));
- // if the file doesn't exist, the error will be caught in read() below
- err = TEMP_FAILURE_RETRY(read(fd, &buf, 1));
- ALOGE_IF(err < 0,
- "*** ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno));
- close(fd);
- return err < 0 ? err : 0;
-}
-
-static int wait_for_fb_sleep(void)
-{
- int err = 0;
- char buf;
- int fd = TEMP_FAILURE_RETRY(open(EARLYSUSPEND_WAIT_FOR_FB_SLEEP, O_RDONLY, 0));
- // if the file doesn't exist, the error will be caught in read() below
- err = TEMP_FAILURE_RETRY(read(fd, &buf, 1));
- ALOGE_IF(err < 0,
- "*** ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno));
- close(fd);
- return err < 0 ? err : 0;
-}
-
-static void *earlysuspend_thread_func(void __unused *arg)
-{
- while (1) {
- if (wait_for_fb_sleep()) {
- ALOGE("Failed reading wait_for_fb_sleep, exiting earlysuspend thread\n");
- return NULL;
- }
- pthread_mutex_lock(&earlysuspend_mutex);
- earlysuspend_state = EARLYSUSPEND_MEM;
- pthread_cond_signal(&earlysuspend_cond);
- pthread_mutex_unlock(&earlysuspend_mutex);
-
- if (wait_for_fb_wake()) {
- ALOGE("Failed reading wait_for_fb_wake, exiting earlysuspend thread\n");
- return NULL;
- }
- pthread_mutex_lock(&earlysuspend_mutex);
- earlysuspend_state = EARLYSUSPEND_ON;
- pthread_cond_signal(&earlysuspend_cond);
- pthread_mutex_unlock(&earlysuspend_mutex);
- }
-}
-static int autosuspend_earlysuspend_enable(void)
-{
- char buf[80];
- int ret;
-
- ALOGV("autosuspend_earlysuspend_enable\n");
-
- ret = write(sPowerStatefd, pwr_state_mem, strlen(pwr_state_mem));
- if (ret < 0) {
- strerror_r(errno, buf, sizeof(buf));
- ALOGE("Error writing to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
- goto err;
- }
-
- if (wait_for_earlysuspend) {
- pthread_mutex_lock(&earlysuspend_mutex);
- while (earlysuspend_state != EARLYSUSPEND_MEM) {
- pthread_cond_wait(&earlysuspend_cond, &earlysuspend_mutex);
- }
- pthread_mutex_unlock(&earlysuspend_mutex);
- }
-
- ALOGV("autosuspend_earlysuspend_enable done\n");
-
- return 0;
-
-err:
- return ret;
-}
-
-static int autosuspend_earlysuspend_disable(void)
-{
- char buf[80];
- int ret;
-
- ALOGV("autosuspend_earlysuspend_disable\n");
-
- ret = TEMP_FAILURE_RETRY(write(sPowerStatefd, pwr_state_on, strlen(pwr_state_on)));
- if (ret < 0) {
- strerror_r(errno, buf, sizeof(buf));
- ALOGE("Error writing to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
- goto err;
- }
-
- if (wait_for_earlysuspend) {
- pthread_mutex_lock(&earlysuspend_mutex);
- while (earlysuspend_state != EARLYSUSPEND_ON) {
- pthread_cond_wait(&earlysuspend_cond, &earlysuspend_mutex);
- }
- pthread_mutex_unlock(&earlysuspend_mutex);
- }
-
- ALOGV("autosuspend_earlysuspend_disable done\n");
-
- return 0;
-
-err:
- return ret;
-}
-
-struct autosuspend_ops autosuspend_earlysuspend_ops = {
- .enable = autosuspend_earlysuspend_enable,
- .disable = autosuspend_earlysuspend_disable,
-};
-
-void start_earlysuspend_thread(void)
-{
- char buf[80];
- int ret;
-
- ret = access(EARLYSUSPEND_WAIT_FOR_FB_SLEEP, F_OK);
- if (ret < 0) {
- return;
- }
-
- ret = access(EARLYSUSPEND_WAIT_FOR_FB_WAKE, F_OK);
- if (ret < 0) {
- return;
- }
-
- wait_for_fb_wake();
-
- ALOGI("Starting early suspend unblocker thread\n");
- ret = pthread_create(&earlysuspend_thread, NULL, earlysuspend_thread_func, NULL);
- if (ret) {
- strerror_r(errno, buf, sizeof(buf));
- ALOGE("Error creating thread: %s\n", buf);
- return;
- }
-
- wait_for_earlysuspend = true;
-}
-
-struct autosuspend_ops *autosuspend_earlysuspend_init(void)
-{
- char buf[80];
- int ret;
-
- sPowerStatefd = TEMP_FAILURE_RETRY(open(EARLYSUSPEND_SYS_POWER_STATE, O_RDWR));
-
- if (sPowerStatefd < 0) {
- strerror_r(errno, buf, sizeof(buf));
- ALOGW("Error opening %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
- return NULL;
- }
-
- ret = TEMP_FAILURE_RETRY(write(sPowerStatefd, "on", 2));
- if (ret < 0) {
- strerror_r(errno, buf, sizeof(buf));
- ALOGW("Error writing 'on' to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
- goto err_write;
- }
-
- ALOGI("Selected early suspend\n");
-
- start_earlysuspend_thread();
-
- return &autosuspend_earlysuspend_ops;
-
-err_write:
- close(sPowerStatefd);
- return NULL;
-}
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index f08a6cd..d0c693d 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -82,8 +82,14 @@
static size_t g_printCount;
static bool g_printItAnyways;
+enum helpType {
+ HELP_FALSE,
+ HELP_TRUE,
+ HELP_FORMAT
+};
+
// if showHelp is set, newline required in fmt statement to transition to usage
-__noreturn static void logcat_panic(bool showHelp, const char *fmt, ...) __printflike(2,3);
+__noreturn static void logcat_panic(enum helpType showHelp, const char *fmt, ...) __printflike(2,3);
static int openLogFile (const char *pathname)
{
@@ -133,7 +139,7 @@
g_outFD = openLogFile(g_outputFileName);
if (g_outFD < 0) {
- logcat_panic(false, "couldn't open output file");
+ logcat_panic(HELP_FALSE, "couldn't open output file");
}
g_outByteCount = 0;
@@ -196,7 +202,7 @@
bytesWritten = android_log_printLogLine(g_logformat, g_outFD, &entry);
if (bytesWritten < 0) {
- logcat_panic(false, "output error");
+ logcat_panic(HELP_FALSE, "output error");
}
}
}
@@ -210,7 +216,6 @@
}
error:
- //fprintf (stderr, "Error processing record\n");
return;
}
@@ -222,7 +227,7 @@
dev->printed ? "switch to" : "beginning of",
dev->device);
if (write(g_outFD, buf, strlen(buf)) < 0) {
- logcat_panic(false, "output error");
+ logcat_panic(HELP_FALSE, "output error");
}
}
dev->printed = true;
@@ -256,18 +261,18 @@
g_outFD = openLogFile (g_outputFileName);
if (g_outFD < 0) {
- logcat_panic(false, "couldn't open output file");
+ logcat_panic(HELP_FALSE, "couldn't open output file");
}
struct stat statbuf;
if (fstat(g_outFD, &statbuf) == -1) {
close(g_outFD);
- logcat_panic(false, "couldn't get output file stat\n");
+ logcat_panic(HELP_FALSE, "couldn't get output file stat\n");
}
if ((size_t) statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) {
close(g_outFD);
- logcat_panic(false, "invalid output file stat\n");
+ logcat_panic(HELP_FALSE, "invalid output file stat\n");
}
g_outByteCount = statbuf.st_size;
@@ -288,9 +293,10 @@
" the fileset and continue\n"
" -v <format>, --format=<format>\n"
" Sets log print format verb and adverbs, where <format> is:\n"
- " brief long process raw tag thread threadtime time\n"
+ " brief help long process raw tag thread threadtime time\n"
" and individually flagged modifying adverbs can be added:\n"
- " color epoch monotonic printable uid usec UTC year zone\n"
+ " color descriptive epoch monotonic printable uid\n"
+ " usec UTC year zone\n"
" -D, --dividers Print dividers between each log buffer\n"
" -c, --clear Clear (flush) the entire log and exit\n"
" if Log to File specified, clear fileset instead\n"
@@ -356,6 +362,40 @@
"or defaults to \"threadtime\"\n\n");
}
+static void show_format_help()
+{
+ fprintf(stderr,
+ "-v <format>, --format=<format> options:\n"
+ " Sets log print format verb and adverbs, where <format> is:\n"
+ " brief long process raw tag thread threadtime time\n"
+ " and individually flagged modifying adverbs can be added:\n"
+ " color descriptive epoch monotonic printable uid usec UTC year zone\n"
+ "\nSingle format verbs:\n"
+ " brief — Display priority/tag and PID of the process issuing the message.\n"
+ " long — Display all metadata fields, separate messages with blank lines.\n"
+ " process — Display PID only.\n"
+ " raw — Display the raw log message, with no other metadata fields.\n"
+ " tag — Display the priority/tag only.\n"
+ " threadtime — Display the date, invocation time, priority, tag, and the PID\n"
+ " and TID of the thread issuing the message. (the default format).\n"
+ " time — Display the date, invocation time, priority/tag, and PID of the\n"
+ " process issuing the message.\n"
+ "\nAdverb modifiers can be used in combination:\n"
+ " color — Display in highlighted color to match priority. i.e. \x1B[38;5;231mVERBOSE\n"
+ " \x1B[38;5;75mDEBUG \x1B[38;5;40mINFO \x1B[38;5;166mWARNING \x1B[38;5;196mERROR FATAL\x1B[0m\n"
+ " descriptive — events logs only, descriptions from event-log-tags database.\n"
+ " epoch — Display time as seconds since Jan 1 1970.\n"
+ " monotonic — Display time as cpu seconds since last boot.\n"
+ " printable — Ensure that any binary logging content is escaped.\n"
+ " uid — If permitted, display the UID or Android ID of logged process.\n"
+ " usec — Display time down the microsecond precision.\n"
+ " UTC — Display time as UTC.\n"
+ " year — Add the year to the displayed time.\n"
+ " zone — Add the local timezone to the displayed time.\n"
+ " \"<zone>\" — Print using this public named timezone (experimental).\n\n"
+ );
+}
+
static int setLogFormat(const char * formatString)
{
static AndroidLogPrintFormat format;
@@ -418,15 +458,23 @@
return true;
}
-static void logcat_panic(bool showHelp, const char *fmt, ...)
+static void logcat_panic(enum helpType showHelp, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
- if (showHelp) {
+ switch (showHelp) {
+ case HELP_TRUE:
show_help(getprogname());
+ break;
+ case HELP_FORMAT:
+ show_format_help();
+ break;
+ case HELP_FALSE:
+ default:
+ break;
}
exit(EXIT_FAILURE);
@@ -616,7 +664,7 @@
if (long_options[option_index].name == pid_str) {
// ToDo: determine runtime PID_MAX?
if (!getSizeTArg(optarg, &pid, 1)) {
- logcat_panic(true, "%s %s out of range\n",
+ logcat_panic(HELP_TRUE, "%s %s out of range\n",
long_options[option_index].name, optarg);
}
break;
@@ -628,7 +676,7 @@
// ToDo: implement API that supports setting a wrap timeout
size_t dummy = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT;
if (optarg && !getSizeTArg(optarg, &dummy, 1)) {
- logcat_panic(true, "%s %s out of range\n",
+ logcat_panic(HELP_TRUE, "%s %s out of range\n",
long_options[option_index].name, optarg);
}
if (dummy != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) {
@@ -675,7 +723,8 @@
if (strspn(optarg, "0123456789") != strlen(optarg)) {
char *cp = parseTime(tail_time, optarg);
if (!cp) {
- logcat_panic(false, "-%c \"%s\" not in time format\n",
+ logcat_panic(HELP_FALSE,
+ "-%c \"%s\" not in time format\n",
ret, optarg);
}
if (*cp) {
@@ -707,7 +756,7 @@
case 'm': {
char *end = NULL;
if (!getSizeTArg(optarg, &g_maxCount)) {
- logcat_panic(false, "-%c \"%s\" isn't an "
+ logcat_panic(HELP_FALSE, "-%c \"%s\" isn't an "
"integer greater than zero\n", ret, optarg);
}
}
@@ -780,7 +829,8 @@
const char *name = android_log_id_to_name(log_id);
if (strcmp(name, optarg) != 0) {
- logcat_panic(true, "unknown buffer %s\n", optarg);
+ logcat_panic(HELP_TRUE,
+ "unknown buffer %s\n", optarg);
}
idMask |= (1 << log_id);
}
@@ -841,20 +891,27 @@
case 'r':
if (!getSizeTArg(optarg, &g_logRotateSizeKBytes, 1)) {
- logcat_panic(true, "Invalid parameter %s to -r\n", optarg);
+ logcat_panic(HELP_TRUE,
+ "Invalid parameter \"%s\" to -r\n", optarg);
}
break;
case 'n':
if (!getSizeTArg(optarg, &g_maxRotatedLogs, 1)) {
- logcat_panic(true, "Invalid parameter %s to -n\n", optarg);
+ logcat_panic(HELP_TRUE,
+ "Invalid parameter \"%s\" to -n\n", optarg);
}
break;
case 'v':
- err = setLogFormat (optarg);
+ if (!strcmp(optarg, "help") || !strcmp(optarg, "--help")) {
+ show_format_help();
+ exit(0);
+ }
+ err = setLogFormat(optarg);
if (err < 0) {
- logcat_panic(true, "Invalid parameter %s to -v\n", optarg);
+ logcat_panic(HELP_FORMAT,
+ "Invalid parameter \"%s\" to -v\n", optarg);
}
hasSetLogFormat |= err;
break;
@@ -932,17 +989,20 @@
break;
case ':':
- logcat_panic(true, "Option -%c needs an argument\n", optopt);
+ logcat_panic(HELP_TRUE,
+ "Option -%c needs an argument\n", optopt);
break;
default:
- logcat_panic(true, "Unrecognized Option %c\n", optopt);
+ logcat_panic(HELP_TRUE,
+ "Unrecognized Option %c\n", optopt);
break;
}
}
if (g_maxCount && got_t) {
- logcat_panic(true, "Cannot use -m (--max-count) and -t together\n");
+ logcat_panic(HELP_TRUE,
+ "Cannot use -m (--max-count) and -t together\n");
}
if (g_printItAnyways && (!g_regex || !g_maxCount)) {
// One day it would be nice if --print -v color and --regex <expr>
@@ -968,12 +1028,12 @@
}
if (g_logRotateSizeKBytes != 0 && g_outputFileName == NULL) {
- logcat_panic(true, "-r requires -f as well\n");
+ logcat_panic(HELP_TRUE, "-r requires -f as well\n");
}
if (setId != NULL) {
if (g_outputFileName == NULL) {
- logcat_panic(true, "--id='%s' requires -f as well\n", setId);
+ logcat_panic(HELP_TRUE, "--id='%s' requires -f as well\n", setId);
}
std::string file_name = android::base::StringPrintf("%s.id", g_outputFileName);
@@ -1003,7 +1063,8 @@
if (forceFilters) {
err = android_log_addFilterString(g_logformat, forceFilters);
if (err < 0) {
- logcat_panic(false, "Invalid filter expression in logcat args\n");
+ logcat_panic(HELP_FALSE,
+ "Invalid filter expression in logcat args\n");
}
} else if (argc == optind) {
// Add from environment variable
@@ -1013,7 +1074,7 @@
err = android_log_addFilterString(g_logformat, env_tags_orig);
if (err < 0) {
- logcat_panic(true,
+ logcat_panic(HELP_TRUE,
"Invalid filter expression in ANDROID_LOG_TAGS\n");
}
}
@@ -1023,7 +1084,8 @@
err = android_log_addFilterString(g_logformat, argv[i]);
if (err < 0) {
- logcat_panic(true, "Invalid filter expression '%s'\n", argv[i]);
+ logcat_panic(HELP_TRUE,
+ "Invalid filter expression '%s'\n", argv[i]);
}
}
}
@@ -1109,17 +1171,20 @@
}
// report any errors in the above loop and exit
if (openDeviceFail) {
- logcat_panic(false, "Unable to open log device '%s'\n", openDeviceFail);
+ logcat_panic(HELP_FALSE,
+ "Unable to open log device '%s'\n", openDeviceFail);
}
if (clearFail) {
- logcat_panic(false, "failed to clear the '%s' log\n", clearFail);
+ logcat_panic(HELP_FALSE,
+ "failed to clear the '%s' log\n", clearFail);
}
if (setSizeFail) {
- logcat_panic(false, "failed to set the '%s' log size\n", setSizeFail);
+ logcat_panic(HELP_FALSE,
+ "failed to set the '%s' log size\n", setSizeFail);
}
if (getSizeFail) {
- logcat_panic(false, "failed to get the readable '%s' log size",
- getSizeFail);
+ logcat_panic(HELP_FALSE,
+ "failed to get the readable '%s' log size", getSizeFail);
}
if (setPruneList) {
@@ -1130,11 +1195,11 @@
if (asprintf(&buf, "%-*s", (int)(bLen - 1), setPruneList) > 0) {
buf[len] = '\0';
if (android_logger_set_prune_list(logger_list, buf, bLen)) {
- logcat_panic(false, "failed to set the prune list");
+ logcat_panic(HELP_FALSE, "failed to set the prune list");
}
free(buf);
} else {
- logcat_panic(false, "failed to set the prune list (alloc)");
+ logcat_panic(HELP_FALSE, "failed to set the prune list (alloc)");
}
}
@@ -1165,7 +1230,7 @@
}
if (!buf) {
- logcat_panic(false, "failed to read data");
+ logcat_panic(HELP_FALSE, "failed to read data");
}
// remove trailing FF
@@ -1217,7 +1282,7 @@
int ret = android_logger_list_read(logger_list, &log_msg);
if (ret == 0) {
- logcat_panic(false, "read: unexpected EOF!\n");
+ logcat_panic(HELP_FALSE, "read: unexpected EOF!\n");
}
if (ret < 0) {
@@ -1226,12 +1291,12 @@
}
if (ret == -EIO) {
- logcat_panic(false, "read: unexpected EOF!\n");
+ logcat_panic(HELP_FALSE, "read: unexpected EOF!\n");
}
if (ret == -EINVAL) {
- logcat_panic(false, "read: unexpected length.\n");
+ logcat_panic(HELP_FALSE, "read: unexpected length.\n");
}
- logcat_panic(false, "logcat read failure");
+ logcat_panic(HELP_FALSE, "logcat read failure");
}
for (d = devices; d; d = d->next) {
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index bc0ea52..18067dc 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -25,6 +25,7 @@
#include <sys/wait.h>
#include <memory>
+#include <string>
#include <gtest/gtest.h>
#include <log/log.h>
@@ -1235,3 +1236,163 @@
ASSERT_EQ(3, count);
}
+
+static bool End_to_End(const char* tag, const char* fmt, ...)
+#if defined(__GNUC__)
+ __attribute__((__format__(printf, 2, 3)))
+#endif
+ ;
+
+static bool End_to_End(const char* tag, const char* fmt, ...) {
+ FILE *fp = popen("logcat -v brief -b events -v descriptive -t 100 2>/dev/null", "r");
+ if (!fp) return false;
+
+ char buffer[BIG_BUFFER];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(buffer, sizeof(buffer), fmt, ap);
+ va_end(ap);
+
+ char *str = NULL;
+ asprintf(&str, "I/%s ( %%d): %s%%c", tag, buffer);
+ std::string expect(str);
+ free(str);
+
+ int count = 0;
+ pid_t pid = getpid();
+ std::string lastMatch;
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ 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;
+ }
+
+ pclose(fp);
+
+ if ((count == 0) && (lastMatch.length() > 0)) {
+ // Help us pinpoint where things went wrong ...
+ fprintf(stderr, "Closest match for\n %s\n is\n %s",
+ expect.c_str(), lastMatch.c_str());
+ }
+
+ return count == 1;
+}
+
+TEST(logcat, descriptive) {
+ struct tag {
+ uint32_t tagNo;
+ const char* tagStr;
+ };
+
+ {
+ static const struct tag hhgtg = { 42, "answer" };
+ android_log_event_context ctx(hhgtg.tagNo);
+ static const char theAnswer[] = "what is five by seven";
+ ctx << theAnswer;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(hhgtg.tagStr,
+ "to life the universe etc=%s", theAnswer));
+ }
+
+ {
+ static const struct tag sync = { 2720, "sync" };
+ static const char id[] = "logcat.decriptive";
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << id << (int32_t)42 << (int32_t)-1 << (int32_t)0;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr,
+ "[id=%s,event=42,source=-1,account=0]",
+ id));
+ }
+
+ // Partial match to description
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << id << (int32_t)43 << (int64_t)-1 << (int32_t)0;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr,
+ "[id=%s,event=43,-1,0]",
+ id));
+ }
+
+ // Negative Test of End_to_End, ensure it is working
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << id << (int32_t)44 << (int32_t)-1 << (int64_t)0;
+ ctx.write();
+ fprintf(stderr, "Expect a \"Closest match\" message\n");
+ EXPECT_FALSE(End_to_End(sync.tagStr,
+ "[id=%s,event=44,source=-1,account=0]",
+ id));
+ }
+ }
+
+ {
+ static const struct tag sync = { 2747, "contacts_aggregation" };
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << (uint64_t)30 << (int32_t)2;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr,
+ "[aggregation time=30ms,count=2]"));
+ }
+
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << (uint64_t)31570 << (int32_t)911;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr,
+ "[aggregation time=31.57s,count=911]"));
+ }
+ }
+
+ {
+ static const struct tag sync = { 75000, "sqlite_mem_alarm_current" };
+ {
+ android_log_event_context 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);
+ ctx << (uint32_t)3072;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr, "current=3KB"));
+ }
+
+ {
+ android_log_event_context 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);
+ ctx << (uint32_t)2097153;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr, "current=2097153B"));
+ }
+
+ {
+ android_log_event_context 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);
+ ctx << (uint32_t)3221225472; // 3MB, but on purpose overflowed
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr, "current=-1GB"));
+ }
+ }
+
+}
diff --git a/logd/Android.mk b/logd/Android.mk
index 81637d2..7fe48d7 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -29,7 +29,7 @@
libcutils \
libbase \
libpackagelistparser \
- libminijail
+ libcap
# This is what we want to do:
# event_logtags = $(shell \
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 3811daa..c3ccd84 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -25,6 +25,7 @@
#include <sys/uio.h>
#include <syslog.h>
+#include <android-base/macros.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
@@ -143,7 +144,7 @@
iov[2].iov_len = strlen(newline);
}
- writev(fdDmesg, iov, sizeof(iov) / sizeof(iov[0]));
+ writev(fdDmesg, iov, arraysize(iov));
free(last_str);
last_str = NULL;
}
@@ -165,7 +166,7 @@
iov[2].iov_base = const_cast<char *>(newline);
iov[2].iov_len = strlen(newline);
- writev(fdDmesg, iov, sizeof(iov) / sizeof(iov[0]));
+ writev(fdDmesg, iov, arraysize(iov));
}
}
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index d68bfee..d4b48ef 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -547,6 +547,7 @@
}
spaces += spaces_total;
}
+ totalSize += sizeOf();
if (spaces < 0) spaces = 0;
output += android::base::StringPrintf("%*s%zu", spaces, "", totalSize);
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index bfaafa4..1f598af 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -42,8 +42,32 @@
std::unordered_map<TKey, TEntry> map;
+ size_t bucket_size() const {
+ size_t count = 0;
+ for (size_t idx = 0; idx < map.bucket_count(); ++idx) {
+ size_t bucket_size = map.bucket_size(idx);
+ if (bucket_size == 0) bucket_size = 1;
+ count += bucket_size;
+ }
+ float load_factor = map.max_load_factor();
+ if (load_factor < 1.0) return count;
+ return count * load_factor;
+ }
+
+ static const size_t unordered_map_per_entry_overhead = sizeof(void*);
+ static const size_t unordered_map_bucket_overhead = sizeof(void*);
+
public:
+ size_t size() const { return map.size(); }
+
+ // Estimate unordered_map memory usage.
+ size_t sizeOf() const {
+ return sizeof(*this) +
+ (size() * (sizeof(TEntry) + unordered_map_per_entry_overhead)) +
+ (bucket_size() * sizeof(size_t) + unordered_map_bucket_overhead);
+ }
+
typedef typename std::unordered_map<TKey, TEntry>::iterator iterator;
typedef typename std::unordered_map<TKey, TEntry>::const_iterator const_iterator;
@@ -155,6 +179,7 @@
}
return output;
}
+
};
namespace EntryBaseConstants {
@@ -472,7 +497,30 @@
// security tag list
tagTable_t securityTagTable;
+ size_t sizeOf() const {
+ size_t size = sizeof(*this) + pidTable.sizeOf() + tidTable.sizeOf() +
+ tagTable.sizeOf() + securityTagTable.sizeOf() +
+ (pidTable.size() * sizeof(pidTable_t::iterator)) +
+ (tagTable.size() * sizeof(tagTable_t::iterator));
+ for(auto it : pidTable) {
+ const char* name = it.second.getName();
+ if (name) size += strlen(name) + 1;
+ }
+ for(auto it : tidTable) {
+ const char* name = it.second.getName();
+ if (name) size += strlen(name) + 1;
+ }
+ log_id_for_each(id) {
+ size += uidTable[id].sizeOf();
+ size += uidTable[id].size() * sizeof(uidTable_t::iterator);
+ size += pidSystemTable[id].sizeOf();
+ size += pidSystemTable[id].size() * sizeof(pidSystemTable_t::iterator);
+ }
+ return size;
+ }
+
public:
+
LogStatistics();
void enableStatistics() { enable = true; }
diff --git a/logd/logd.rc b/logd/logd.rc
index 31ed4df..54349dd 100644
--- a/logd/logd.rc
+++ b/logd/logd.rc
@@ -2,10 +2,15 @@
socket logd stream 0666 logd logd
socket logdr seqpacket 0666 logd logd
socket logdw dgram 0222 logd logd
- group root system readproc
+ file /proc/kmsg r
+ file /dev/kmsg w
+ user logd
+ group logd system readproc
writepid /dev/cpuset/system-background/tasks
service logd-reinit /system/bin/logd --reinit
oneshot
disabled
+ user logd
+ group logd
writepid /dev/cpuset/system-background/tasks
diff --git a/logd/main.cpp b/logd/main.cpp
index 0cb26dc..d698976 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -39,13 +39,12 @@
#include <android-base/macros.h>
#include <cutils/properties.h>
#include <cutils/sched_policy.h>
+#include <cutils/files.h>
#include <cutils/sockets.h>
-#include <libminijail.h>
#include <log/event_tag_map.h>
#include <packagelistparser/packagelistparser.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
-#include <scoped_minijail.h>
#include <utils/threads.h>
#include "CommandListener.h"
@@ -90,29 +89,81 @@
// logd
//
-static int drop_privs() {
+static int drop_privs(bool klogd, bool auditd) {
+ // Tricky, if ro.build.type is "eng" then this is true because of the
+ // side effect that ro.debuggable == 1 as well, else it is false.
+ bool eng = __android_logger_property_get_bool("ro.build.type", BOOL_DEFAULT_FALSE);
+
struct sched_param param;
memset(¶m, 0, sizeof(param));
if (set_sched_policy(0, SP_BACKGROUND) < 0) {
- return -1;
+ android::prdebug("failed to set background scheduling policy");
+ if (!eng) return -1;
}
if (sched_setscheduler((pid_t) 0, SCHED_BATCH, ¶m) < 0) {
- return -1;
+ android::prdebug("failed to set batch scheduler");
+ if (!eng) return -1;
}
if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
+ android::prdebug("failed to set background cgroup");
+ if (!eng) return -1;
+ }
+
+ if (!eng && (prctl(PR_SET_DUMPABLE, 0) < 0)) {
+ android::prdebug("failed to clear PR_SET_DUMPABLE");
return -1;
}
+ if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
+ android::prdebug("failed to set PR_SET_KEEPCAPS");
+ if (!eng) return -1;
+ }
+
+ std::unique_ptr<struct _cap_struct, int(*)(void *)> caps(cap_init(), cap_free);
+ if (cap_clear(caps.get()) < 0) return -1;
+ cap_value_t cap_value[] = {
+ CAP_SETGID, // must be first for below
+ klogd ? CAP_SYSLOG : CAP_SETGID,
+ auditd ? CAP_AUDIT_CONTROL : CAP_SETGID
+ };
+ if (cap_set_flag(caps.get(), CAP_PERMITTED,
+ arraysize(cap_value), cap_value,
+ CAP_SET) < 0) return -1;
+ if (cap_set_flag(caps.get(), CAP_EFFECTIVE,
+ arraysize(cap_value), cap_value,
+ CAP_SET) < 0) return -1;
+ if (cap_set_proc(caps.get()) < 0) {
+ android::prdebug("failed to set CAP_SETGID, CAP_SYSLOG or CAP_AUDIT_CONTROL (%d)", errno);
+ if (!eng) return -1;
+ }
+
gid_t groups[] = { AID_READPROC };
- ScopedMinijail j(minijail_new());
- minijail_set_supplementary_gids(j.get(), arraysize(groups), groups);
- minijail_change_uid(j.get(), AID_LOGD);
- minijail_change_gid(j.get(), AID_LOGD);
- minijail_use_caps(j.get(), CAP_TO_MASK(CAP_SYSLOG) | CAP_TO_MASK(CAP_AUDIT_CONTROL));
- minijail_enter(j.get());
+
+ if (setgroups(arraysize(groups), groups) == -1) {
+ android::prdebug("failed to set AID_READPROC groups");
+ if (!eng) return -1;
+ }
+
+ if (setgid(AID_LOGD) != 0) {
+ android::prdebug("failed to set AID_LOGD gid");
+ if (!eng) return -1;
+ }
+
+ if (setuid(AID_LOGD) != 0) {
+ android::prdebug("failed to set AID_LOGD uid");
+ if (!eng) return -1;
+ }
+
+ if (cap_set_flag(caps.get(), CAP_PERMITTED, 1, cap_value, CAP_CLEAR) < 0) return -1;
+ if (cap_set_flag(caps.get(), CAP_EFFECTIVE, 1, cap_value, CAP_CLEAR) < 0) return -1;
+ if (cap_set_proc(caps.get()) < 0) {
+ android::prdebug("failed to clear CAP_SETGID (%d)", errno);
+ if (!eng) return -1;
+ }
+
return 0;
}
@@ -184,11 +235,16 @@
set_sched_policy(0, SP_BACKGROUND);
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND);
- // If we are AID_ROOT, we should drop to AID_SYSTEM, if we are anything
- // else, we have even lesser privileges and accept our fate. Not worth
- // checking for error returns setting this thread's privileges.
- (void)setgid(AID_SYSTEM);
- (void)setuid(AID_SYSTEM);
+ cap_t caps = cap_init();
+ (void)cap_clear(caps);
+ (void)cap_set_proc(caps);
+ (void)cap_free(caps);
+
+ // If we are AID_ROOT, we should drop to AID_LOGD+AID_SYSTEM, if we are
+ // anything else, we have even lesser privileges and accept our fate. Not
+ // worth checking for error returns setting this thread's privileges.
+ (void)setgid(AID_SYSTEM); // readonly access to /data/system/packages.list
+ (void)setuid(AID_LOGD); // access to everything logd.
while (reinit_running && !sem_wait(&reinit) && reinit_running) {
@@ -306,6 +362,39 @@
}
}
+static int issueReinit() {
+ cap_t caps = cap_init();
+ (void)cap_clear(caps);
+ (void)cap_set_proc(caps);
+ (void)cap_free(caps);
+
+ int sock = TEMP_FAILURE_RETRY(
+ socket_local_client("logd",
+ ANDROID_SOCKET_NAMESPACE_RESERVED,
+ SOCK_STREAM));
+ if (sock < 0) return -errno;
+
+ static const char reinitStr[] = "reinit";
+ ssize_t ret = TEMP_FAILURE_RETRY(write(sock, reinitStr, sizeof(reinitStr)));
+ if (ret < 0) return -errno;
+
+ struct pollfd p;
+ memset(&p, 0, sizeof(p));
+ p.fd = sock;
+ p.events = POLLIN;
+ ret = TEMP_FAILURE_RETRY(poll(&p, 1, 1000));
+ if (ret < 0) return -errno;
+ if ((ret == 0) || !(p.revents & POLLIN)) return -ETIME;
+
+ static const char success[] = "success";
+ char buffer[sizeof(success) - 1];
+ memset(buffer, 0, sizeof(buffer));
+ ret = TEMP_FAILURE_RETRY(read(sock, buffer, sizeof(buffer)));
+ if (ret < 0) return -errno;
+
+ return strncmp(buffer, success, sizeof(success) - 1) != 0;
+}
+
// Foreground waits for exit of the main persistent threads
// that are started here. The threads are created to manage
// UNIX domain client sockets for writing, reading and
@@ -313,6 +402,17 @@
// logging plugins like auditd and restart control. Additional
// transitory per-client threads are created for each reader.
int main(int argc, char *argv[]) {
+ // issue reinit command. KISS argument parsing.
+ if ((argc > 1) && argv[1] && !strcmp(argv[1], "--reinit")) {
+ return issueReinit();
+ }
+
+ static const char dev_kmsg[] = "/dev/kmsg";
+ fdDmesg = android_get_control_file(dev_kmsg);
+ if (fdDmesg < 0) {
+ fdDmesg = TEMP_FAILURE_RETRY(open(dev_kmsg, O_WRONLY | O_CLOEXEC));
+ }
+
int fdPmesg = -1;
bool klogd = __android_logger_property_get_bool("logd.kernel",
BOOL_DEFAULT_TRUE |
@@ -320,43 +420,13 @@
BOOL_DEFAULT_FLAG_ENG |
BOOL_DEFAULT_FLAG_SVELTE);
if (klogd) {
- fdPmesg = open("/proc/kmsg", O_RDONLY | O_NDELAY);
- }
- fdDmesg = open("/dev/kmsg", O_WRONLY);
-
- // issue reinit command. KISS argument parsing.
- if ((argc > 1) && argv[1] && !strcmp(argv[1], "--reinit")) {
- int sock = TEMP_FAILURE_RETRY(
- socket_local_client("logd",
- ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_STREAM));
- if (sock < 0) {
- return -errno;
+ static const char proc_kmsg[] = "/proc/kmsg";
+ fdPmesg = android_get_control_file(proc_kmsg);
+ if (fdPmesg < 0) {
+ fdPmesg = TEMP_FAILURE_RETRY(open(proc_kmsg,
+ O_RDONLY | O_NDELAY | O_CLOEXEC));
}
- static const char reinit[] = "reinit";
- ssize_t ret = TEMP_FAILURE_RETRY(write(sock, reinit, sizeof(reinit)));
- if (ret < 0) {
- return -errno;
- }
- struct pollfd p;
- memset(&p, 0, sizeof(p));
- p.fd = sock;
- p.events = POLLIN;
- ret = TEMP_FAILURE_RETRY(poll(&p, 1, 1000));
- if (ret < 0) {
- return -errno;
- }
- if ((ret == 0) || !(p.revents & POLLIN)) {
- return -ETIME;
- }
- static const char success[] = "success";
- char buffer[sizeof(success) - 1];
- memset(buffer, 0, sizeof(buffer));
- ret = TEMP_FAILURE_RETRY(read(sock, buffer, sizeof(buffer)));
- if (ret < 0) {
- return -errno;
- }
- return strncmp(buffer, success, sizeof(success) - 1) != 0;
+ if (fdPmesg < 0) android::prdebug("Failed to open %s\n", proc_kmsg);
}
// Reinit Thread
@@ -381,7 +451,10 @@
pthread_attr_destroy(&attr);
}
- if (drop_privs() != 0) {
+ bool auditd = __android_logger_property_get_bool("logd.auditd",
+ BOOL_DEFAULT_TRUE |
+ BOOL_DEFAULT_FLAG_PERSIST);
+ if (drop_privs(klogd, auditd) != 0) {
return -1;
}
@@ -436,9 +509,6 @@
// initiated log messages. New log entries are added to LogBuffer
// and LogReader is notified to send updates to connected clients.
- bool auditd = __android_logger_property_get_bool("logd.auditd",
- BOOL_DEFAULT_TRUE |
- BOOL_DEFAULT_FLAG_PERSIST);
LogAudit *al = NULL;
if (auditd) {
al = new LogAudit(logBuf, reader,
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index e0a4cc3..254a3f8 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -23,6 +23,7 @@
#include <string>
+#include <android-base/macros.h>
#include <android-base/stringprintf.h>
#include <cutils/sockets.h>
#include <gtest/gtest.h>
@@ -351,7 +352,7 @@
"/dev/log/system", "/dev/log_system",
};
- for (unsigned int i = 0; i < (sizeof(loggers) / sizeof(loggers[0])); ++i) {
+ for (unsigned int i = 0; i < arraysize(loggers); ++i) {
fd = open(loggers[i], O_RDONLY);
if (fd < 0) {
continue;
@@ -434,12 +435,12 @@
static const unsigned int log_latency = 4;
static const unsigned int log_delay = 5;
- unsigned long ns[sizeof(benchmarks) / sizeof(benchmarks[0])];
+ unsigned long ns[arraysize(benchmarks)];
memset(ns, 0, sizeof(ns));
while (fgets(buffer, sizeof(buffer), fp)) {
- for (unsigned i = 0; i < sizeof(ns) / sizeof(ns[0]); ++i) {
+ for (unsigned i = 0; i < arraysize(ns); ++i) {
char *cp = strstr(buffer, benchmarks[i]);
if (!cp) {
continue;
@@ -470,7 +471,7 @@
EXPECT_GE(20000000UL, ns[log_delay]); // 10500289 user
- for (unsigned i = 0; i < sizeof(ns) / sizeof(ns[0]); ++i) {
+ for (unsigned i = 0; i < arraysize(ns); ++i) {
EXPECT_NE(0UL, ns[i]);
}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index c331781..2f69b42 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -308,6 +308,10 @@
# 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
+
# We chown/chmod /cache again so because mount is run as root + defaults
chown system cache /cache
chmod 0770 /cache
@@ -668,13 +672,3 @@
service flash_recovery /system/bin/install-recovery.sh
class main
oneshot
-
-service hwservicemanager /system/bin/hwservicemanager
- user system
- disabled
- group system readproc
- critical
- writepid /dev/cpuset/system-background/tasks
-
-on property:hwservicemanager.ready=true
- class_start hal
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index 2d7d5c2..eedeba8 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -1,6 +1,8 @@
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
+ user root
+ group root readproc
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index 4156847..84a907f 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -1,6 +1,8 @@
service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
class main
priority -20
+ user root
+ group root readproc
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
@@ -13,6 +15,8 @@
service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
class main
priority -20
+ user root
+ group root readproc
socket zygote_secondary stream 660 root system
onrestart restart zygote
writepid /dev/cpuset/foreground/tasks
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index 8584cbb..76e2b79 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -1,6 +1,8 @@
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
+ user root
+ group root readproc
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 27eaa66..e918b67 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -1,6 +1,8 @@
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
class main
priority -20
+ user root
+ group root readproc
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
@@ -13,6 +15,8 @@
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
class main
priority -20
+ user root
+ group root readproc
socket zygote_secondary stream 660 root system
onrestart restart zygote
writepid /dev/cpuset/foreground/tasks