Move host flags from linux -> host
am: cd58088ccf
Change-Id: If60258b3bf78cd9ed1c9b9dcbfb2d7bfa650d10d
diff --git a/adb/Android.mk b/adb/Android.mk
index 05b0284..2b6df70 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -133,7 +133,7 @@
# Even though we're building a static library (and thus there's no link step for
# this to take effect), this adds the includes to our path.
-LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libbase
+LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libqemu_pipe libbase
LOCAL_WHOLE_STATIC_LIBRARIES := libadbd_usb
@@ -363,6 +363,7 @@
libasyncio \
libavb_user \
libbase \
+ libqemu_pipe \
libbootloader_message \
libfs_mgr \
libfec \
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 8c24bbb..6b30be8 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -257,19 +257,6 @@
send_packet(cp, t);
}
-#if ADB_HOST
-
-void SendConnectOnHost(atransport* t) {
- // Send an empty message before A_CNXN message. This is because the data toggle of the ep_out on
- // host and ep_in on device may not be the same.
- apacket* p = get_apacket();
- CHECK(p);
- send_packet(p, t);
- send_connect(t);
-}
-
-#endif
-
// qual_overwrite is used to overwrite a qualifier string. dst is a
// pointer to a char pointer. It is assumed that if *dst is non-NULL, it
// was malloc'ed and needs to freed. *dst will be set to a dup of src.
@@ -370,7 +357,7 @@
if (p->msg.arg0){
send_packet(p, t);
#if ADB_HOST
- SendConnectOnHost(t);
+ send_connect(t);
#endif
} else {
t->SetConnectionState(kCsOffline);
diff --git a/adb/adb.h b/adb/adb.h
index 6a9897f..a4d233e 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -224,9 +224,6 @@
void handle_offline(atransport *t);
void send_connect(atransport *t);
-#if ADB_HOST
-void SendConnectOnHost(atransport* t);
-#endif
void parse_banner(const std::string&, atransport* t);
diff --git a/adb/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp
index 7025f28..8120199 100644
--- a/adb/client/usb_libusb.cpp
+++ b/adb/client/usb_libusb.cpp
@@ -333,6 +333,13 @@
return;
}
+ rc = libusb_set_interface_alt_setting(handle.get(), interface_num, 0);
+ if (rc != 0) {
+ LOG(WARNING) << "failed to set interface alt setting for device '" << device_serial
+ << "'" << libusb_error_name(rc);
+ return;
+ }
+
for (uint8_t endpoint : {bulk_in, bulk_out}) {
rc = libusb_clear_halt(handle.get(), endpoint);
if (rc != 0) {
diff --git a/adb/framebuffer_service.cpp b/adb/framebuffer_service.cpp
index 7baad8b..6c3a225 100644
--- a/adb/framebuffer_service.cpp
+++ b/adb/framebuffer_service.cpp
@@ -37,10 +37,11 @@
*/
/* This version number defines the format of the fbinfo struct.
It must match versioning in ddms where this data is consumed. */
-#define DDMS_RAWIMAGE_VERSION 1
+#define DDMS_RAWIMAGE_VERSION 2
struct fbinfo {
unsigned int version;
unsigned int bpp;
+ unsigned int colorSpace;
unsigned int size;
unsigned int width;
unsigned int height;
@@ -60,7 +61,7 @@
unsigned int i, bsize;
char buf[640];
int fd_screencap;
- int w, h, f;
+ int w, h, f, c;
int fds[2];
pid_t pid;
@@ -82,12 +83,14 @@
adb_close(fds[1]);
fd_screencap = fds[0];
- /* read w, h & format */
+ /* read w, h, format & color space */
if(!ReadFdExactly(fd_screencap, &w, 4)) goto done;
if(!ReadFdExactly(fd_screencap, &h, 4)) goto done;
if(!ReadFdExactly(fd_screencap, &f, 4)) goto done;
+ if(!ReadFdExactly(fd_screencap, &c, 4)) goto done;
fbinfo.version = DDMS_RAWIMAGE_VERSION;
+ fbinfo.colorSpace = c;
/* see hardware/hardware.h */
switch (f) {
case 1: /* RGBA_8888 */
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 34cc026..089a1ec 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -1101,11 +1101,4 @@
keys_.pop_front();
return result;
}
-bool atransport::SetSendConnectOnError() {
- if (has_send_connect_on_error_) {
- return false;
- }
- has_send_connect_on_error_ = true;
- return true;
-}
#endif
diff --git a/adb/transport.h b/adb/transport.h
index 79e3075..8c101fd 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -122,7 +122,6 @@
#if ADB_HOST
std::shared_ptr<RSA> NextKey();
- bool SetSendConnectOnError();
#endif
char token[TOKEN_SIZE] = {};
@@ -181,7 +180,6 @@
std::atomic<ConnectionState> connection_state_;
#if ADB_HOST
std::deque<std::shared_ptr<RSA>> keys_;
- bool has_send_connect_on_error_ = false;
#endif
DISALLOW_COPY_AND_ASSIGN(atransport);
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 6cedd92..9cd378c 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -288,7 +288,7 @@
#define open adb_open
#define read adb_read
#define write adb_write
-#include <system/qemu_pipe.h>
+#include <qemu_pipe.h>
#undef open
#undef read
#undef write
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index 6768d31..fdecccf 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -103,13 +103,6 @@
err_msg:
p->msg.command = 0;
- if (t->GetConnectionState() == kCsOffline) {
- // If the data toggle of ep_out on device and ep_in on host are not the same, we may receive
- // an error message. In this case, resend one A_CNXN message to connect the device.
- if (t->SetSendConnectOnError()) {
- SendConnectOnHost(t);
- }
- }
return 0;
}
@@ -162,8 +155,7 @@
return 0;
}
-static void remote_close(atransport *t)
-{
+static void remote_close(atransport* t) {
usb_close(t->usb);
t->usb = 0;
}
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 874189a..c9af421 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -745,6 +745,12 @@
return false;
}
+static bool should_use_metadata_encryption(const struct fstab_rec* rec) {
+ if (!(rec->fs_mgr_flags & (MF_FILEENCRYPTION | MF_FORCEFDEORFBE))) return false;
+ if (!(rec->fs_mgr_flags & MF_KEYDIRECTORY)) return false;
+ return true;
+}
+
// Check to see if a mountable volume has encryption requirements
static int handle_encryptable(const struct fstab_rec* rec)
{
@@ -757,8 +763,14 @@
<< " - allow continue unencrypted";
return FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
}
+ } else if (should_use_metadata_encryption(rec)) {
+ if (umount(rec->mount_point) == 0) {
+ return FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION;
+ } else {
+ PERROR << "Could not umount " << rec->mount_point << " - fail since can't encrypt";
+ return FS_MGR_MNTALL_FAIL;
+ }
} else if (rec->fs_mgr_flags & (MF_FILEENCRYPTION | MF_FORCEFDEORFBE)) {
- // Deal with file level encryption
LINFO << rec->mount_point << " is file encrypted";
return FS_MGR_MNTALL_DEV_FILE_ENCRYPTED;
} else if (fs_mgr_is_encryptable(rec)) {
@@ -897,7 +909,6 @@
continue;
}
- /* mount(2) returned an error, handle the encryptable/formattable case */
bool wiped = partition_wiped(fstab->recs[top_idx].blk_device);
bool crypt_footer = false;
if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
@@ -937,6 +948,8 @@
continue;
}
}
+
+ /* mount(2) returned an error, handle the encryptable/formattable case */
if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
fs_mgr_is_encryptable(&fstab->recs[attempted_idx])) {
if (wiped) {
@@ -962,6 +975,9 @@
}
}
encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
+ } else if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
+ should_use_metadata_encryption(&fstab->recs[attempted_idx])) {
+ encryptable = FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED;
} else {
// fs_options might be null so we cannot use PERROR << directly.
// Use StringPrintf to output "(null)" instead.
@@ -1244,48 +1260,46 @@
return ret;
}
-/*
- * key_loc must be at least PROPERTY_VALUE_MAX bytes long
- *
- * real_blk_device must be at least PROPERTY_VALUE_MAX bytes long
- */
-int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc, char *real_blk_device, int size)
-{
- int i = 0;
+struct fstab_rec const* fs_mgr_get_crypt_entry(struct fstab const* fstab) {
+ int i;
if (!fstab) {
- return -1;
- }
- /* Initialize return values to null strings */
- if (key_loc) {
- *key_loc = '\0';
- }
- if (real_blk_device) {
- *real_blk_device = '\0';
+ return NULL;
}
/* Look for the encryptable partition to find the data */
for (i = 0; i < fstab->num_entries; i++) {
/* Don't deal with vold managed enryptable partitions here */
- if (fstab->recs[i].fs_mgr_flags & MF_VOLDMANAGED) {
- continue;
+ if (!(fstab->recs[i].fs_mgr_flags & MF_VOLDMANAGED) &&
+ (fstab->recs[i].fs_mgr_flags &
+ (MF_CRYPT | MF_FORCECRYPT | MF_FORCEFDEORFBE | MF_FILEENCRYPTION))) {
+ return &fstab->recs[i];
}
- if (!(fstab->recs[i].fs_mgr_flags
- & (MF_CRYPT | MF_FORCECRYPT | MF_FORCEFDEORFBE))) {
- continue;
- }
-
- /* We found a match */
- if (key_loc) {
- strlcpy(key_loc, fstab->recs[i].key_loc, size);
- }
- if (real_blk_device) {
- strlcpy(real_blk_device, fstab->recs[i].blk_device, size);
- }
- break;
}
+ return NULL;
+}
- return 0;
+/*
+ * key_loc must be at least PROPERTY_VALUE_MAX bytes long
+ *
+ * real_blk_device must be at least PROPERTY_VALUE_MAX bytes long
+ */
+void fs_mgr_get_crypt_info(struct fstab* fstab, char* key_loc, char* real_blk_device, size_t size) {
+ struct fstab_rec const* rec = fs_mgr_get_crypt_entry(fstab);
+ if (key_loc) {
+ if (rec) {
+ strlcpy(key_loc, rec->key_loc, size);
+ } else {
+ *key_loc = '\0';
+ }
+ }
+ if (real_blk_device) {
+ if (rec) {
+ strlcpy(real_blk_device, rec->blk_device, size);
+ } else {
+ *real_blk_device = '\0';
+ }
+ }
}
bool fs_mgr_load_verity_state(int* mode) {
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index bce245c..92c6ee8 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -33,6 +33,7 @@
struct fs_mgr_flag_values {
char *key_loc;
+ char* key_dir;
char *verity_loc;
long long part_length;
char *label;
@@ -72,34 +73,35 @@
};
static struct flag_list fs_mgr_flags[] = {
- { "wait", MF_WAIT },
- { "check", MF_CHECK },
- { "encryptable=", MF_CRYPT },
- { "forceencrypt=", MF_FORCECRYPT },
- { "fileencryption=", MF_FILEENCRYPTION },
- { "forcefdeorfbe=", MF_FORCEFDEORFBE },
- { "nonremovable", MF_NONREMOVABLE },
- { "voldmanaged=", MF_VOLDMANAGED},
- { "length=", MF_LENGTH },
- { "recoveryonly", MF_RECOVERYONLY },
- { "swapprio=", MF_SWAPPRIO },
- { "zramsize=", MF_ZRAMSIZE },
- { "max_comp_streams=", MF_MAX_COMP_STREAMS },
- { "verifyatboot", MF_VERIFYATBOOT },
- { "verify", MF_VERIFY },
- { "avb", MF_AVB },
- { "noemulatedsd", MF_NOEMULATEDSD },
- { "notrim", MF_NOTRIM },
- { "formattable", MF_FORMATTABLE },
- { "slotselect", MF_SLOTSELECT },
- { "nofail", MF_NOFAIL },
- { "latemount", MF_LATEMOUNT },
- { "reservedsize=", MF_RESERVEDSIZE },
- { "quota", MF_QUOTA },
- { "eraseblk=", MF_ERASEBLKSIZE },
- { "logicalblk=", MF_LOGICALBLKSIZE },
- { "defaults", 0 },
- { 0, 0 },
+ {"wait", MF_WAIT},
+ {"check", MF_CHECK},
+ {"encryptable=", MF_CRYPT},
+ {"forceencrypt=", MF_FORCECRYPT},
+ {"fileencryption=", MF_FILEENCRYPTION},
+ {"forcefdeorfbe=", MF_FORCEFDEORFBE},
+ {"keydirectory=", MF_KEYDIRECTORY},
+ {"nonremovable", MF_NONREMOVABLE},
+ {"voldmanaged=", MF_VOLDMANAGED},
+ {"length=", MF_LENGTH},
+ {"recoveryonly", MF_RECOVERYONLY},
+ {"swapprio=", MF_SWAPPRIO},
+ {"zramsize=", MF_ZRAMSIZE},
+ {"max_comp_streams=", MF_MAX_COMP_STREAMS},
+ {"verifyatboot", MF_VERIFYATBOOT},
+ {"verify", MF_VERIFY},
+ {"avb", MF_AVB},
+ {"noemulatedsd", MF_NOEMULATEDSD},
+ {"notrim", MF_NOTRIM},
+ {"formattable", MF_FORMATTABLE},
+ {"slotselect", MF_SLOTSELECT},
+ {"nofail", MF_NOFAIL},
+ {"latemount", MF_LATEMOUNT},
+ {"reservedsize=", MF_RESERVEDSIZE},
+ {"quota", MF_QUOTA},
+ {"eraseblk=", MF_ERASEBLKSIZE},
+ {"logicalblk=", MF_LOGICALBLKSIZE},
+ {"defaults", 0},
+ {0, 0},
};
#define EM_AES_256_XTS 1
@@ -268,6 +270,11 @@
} else {
flag_vals->file_names_mode = EM_AES_256_CTS;
}
+ } else if ((fl[i].flag == MF_KEYDIRECTORY) && flag_vals) {
+ /* The metadata flag is followed by an = and the
+ * directory for the keys. Get it and return it.
+ */
+ flag_vals->key_dir = strdup(strchr(p, '=') + 1);
} else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
/* The length flag is followed by an = and the
* size of the partition. Get it and return it.
@@ -577,6 +584,7 @@
fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
&flag_vals, NULL, 0);
fstab->recs[cnt].key_loc = flag_vals.key_loc;
+ fstab->recs[cnt].key_dir = flag_vals.key_dir;
fstab->recs[cnt].verity_loc = flag_vals.verity_loc;
fstab->recs[cnt].length = flag_vals.part_length;
fstab->recs[cnt].label = flag_vals.label;
@@ -736,6 +744,7 @@
free(fstab->recs[i].fs_type);
free(fstab->recs[i].fs_options);
free(fstab->recs[i].key_loc);
+ free(fstab->recs[i].key_dir);
free(fstab->recs[i].label);
}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 7423c1f..0f62e18 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -109,6 +109,7 @@
#define MF_ERASEBLKSIZE 0x800000
#define MF_LOGICALBLKSIZE 0X1000000
#define MF_AVB 0X2000000
+#define MF_KEYDIRECTORY 0X4000000
#define DM_BUF_SIZE 4096
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 3d3faf3..c74f6c8 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -53,6 +53,8 @@
typedef void (*fs_mgr_verity_state_callback)(struct fstab_rec *fstab,
const char *mount_point, int mode, int status);
+#define FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED 7
+#define FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION 6
#define FS_MGR_MNTALL_DEV_FILE_ENCRYPTED 5
#define FS_MGR_MNTALL_DEV_NEEDS_RECOVERY 4
#define FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION 3
@@ -71,8 +73,8 @@
int fs_mgr_do_mount_one(struct fstab_rec *rec);
int fs_mgr_do_tmpfs_mount(const char *n_name);
int fs_mgr_unmount_all(struct fstab *fstab);
-int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc,
- char *real_blk_device, int size);
+struct fstab_rec const* fs_mgr_get_crypt_entry(struct fstab const* fstab);
+void fs_mgr_get_crypt_info(struct fstab* fstab, char* key_loc, char* real_blk_device, size_t size);
bool fs_mgr_load_verity_state(int* mode);
bool fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback);
int fs_mgr_swapon_all(struct fstab *fstab);
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index ef51724..0a8496b 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -49,6 +49,7 @@
char* fs_options;
int fs_mgr_flags;
char* key_loc;
+ char* key_dir;
char* verity_loc;
long long length;
char* label;
diff --git a/gatekeeperd/IGateKeeperService.cpp b/gatekeeperd/IGateKeeperService.cpp
index 95fbfd1..1c339f4 100644
--- a/gatekeeperd/IGateKeeperService.cpp
+++ b/gatekeeperd/IGateKeeperService.cpp
@@ -158,6 +158,12 @@
reply->writeNoException();
return NO_ERROR;
}
+ case REPORT_DEVICE_SETUP_COMPLETE: {
+ CHECK_INTERFACE(IGateKeeperService, data, reply);
+ reportDeviceSetupComplete();
+ reply->writeNoException();
+ return NO_ERROR;
+ }
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/gatekeeperd/IGateKeeperService.h b/gatekeeperd/IGateKeeperService.h
index f070486..2816efc 100644
--- a/gatekeeperd/IGateKeeperService.h
+++ b/gatekeeperd/IGateKeeperService.h
@@ -33,6 +33,7 @@
VERIFY_CHALLENGE = IBinder::FIRST_CALL_TRANSACTION + 2,
GET_SECURE_USER_ID = IBinder::FIRST_CALL_TRANSACTION + 3,
CLEAR_SECURE_USER_ID = IBinder::FIRST_CALL_TRANSACTION + 4,
+ REPORT_DEVICE_SETUP_COMPLETE = IBinder::FIRST_CALL_TRANSACTION + 5,
};
enum {
@@ -95,6 +96,12 @@
* Clears the secure user ID associated with the user.
*/
virtual void clearSecureUserId(uint32_t uid) = 0;
+
+ /**
+ * Notifies gatekeeper that device setup has been completed and any potentially still existing
+ * state from before a factory reset can be cleaned up (if it has not been already).
+ */
+ virtual void reportDeviceSetupComplete() = 0;
};
// ----------------------------------------------------------------------------
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp
index 73dab9b..d581736 100644
--- a/gatekeeperd/gatekeeperd.cpp
+++ b/gatekeeperd/gatekeeperd.cpp
@@ -57,19 +57,13 @@
class GateKeeperProxy : public BnGateKeeperService {
public:
GateKeeperProxy() {
+ clear_state_if_needed_done = false;
hw_device = IGatekeeper::getService();
if (hw_device == nullptr) {
ALOGW("falling back to software GateKeeper");
soft_device.reset(new SoftGateKeeperDevice());
}
-
- if (mark_cold_boot()) {
- ALOGI("cold boot: clearing state");
- if (hw_device != nullptr) {
- hw_device->deleteAllUsers([](const GatekeeperResponse &){});
- }
- }
}
virtual ~GateKeeperProxy() {
@@ -87,6 +81,21 @@
close(fd);
}
+ void clear_state_if_needed() {
+ if (clear_state_if_needed_done) {
+ return;
+ }
+
+ if (mark_cold_boot()) {
+ ALOGI("cold boot: clearing state");
+ if (hw_device != nullptr) {
+ hw_device->deleteAllUsers([](const GatekeeperResponse &){});
+ }
+ }
+
+ clear_state_if_needed_done = true;
+ }
+
bool mark_cold_boot() {
const char *filename = ".coldboot";
if (access(filename, F_OK) == -1) {
@@ -141,6 +150,10 @@
return PERMISSION_DENIED;
}
+ // Make sure to clear any state from before factory reset as soon as a credential is
+ // enrolled (which may happen during device setup).
+ clear_state_if_needed();
+
// need a desired password to enroll
if (desired_password_length == 0) return -EINVAL;
@@ -355,6 +368,18 @@
}
}
+ virtual void reportDeviceSetupComplete() {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int calling_pid = ipc->getCallingPid();
+ const int calling_uid = ipc->getCallingUid();
+ if (!PermissionCache::checkPermission(KEYGUARD_PERMISSION, calling_pid, calling_uid)) {
+ ALOGE("%s: permission denied for [%d:%d]", __func__, calling_pid, calling_uid);
+ return;
+ }
+
+ clear_state_if_needed();
+ }
+
virtual status_t dump(int fd, const Vector<String16> &) {
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
@@ -377,6 +402,8 @@
private:
sp<IGatekeeper> hw_device;
std::unique_ptr<SoftGateKeeperDevice> soft_device;
+
+ bool clear_state_if_needed_done;
};
}// namespace android
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 8b59964..6b14289 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -33,6 +33,30 @@
include $(CLEAR_VARS)
+LOCAL_MODULE := libhealthd_draw
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+LOCAL_STATIC_LIBRARIES := \
+ libminui \
+ libbase
+LOCAL_SRC_FILES := healthd_draw.cpp
+
+ifneq ($(TARGET_HEALTHD_DRAW_SPLIT_SCREEN),)
+LOCAL_CFLAGS += -DHEALTHD_DRAW_SPLIT_SCREEN=$(TARGET_HEALTHD_DRAW_SPLIT_SCREEN)
+else
+LOCAL_CFLAGS += -DHEALTHD_DRAW_SPLIT_SCREEN=0
+endif
+
+ifneq ($(TARGET_HEALTHD_DRAW_SPLIT_OFFSET),)
+LOCAL_CFLAGS += -DHEALTHD_DRAW_SPLIT_OFFSET=$(TARGET_HEALTHD_DRAW_SPLIT_OFFSET)
+else
+LOCAL_CFLAGS += -DHEALTHD_DRAW_SPLIT_OFFSET=0
+endif
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
LOCAL_CFLAGS := -Werror
ifeq ($(strip $(BOARD_CHARGER_DISABLE_INIT_BLANK)),true)
LOCAL_CFLAGS += -DCHARGER_DISABLE_INIT_BLANK
@@ -58,6 +82,7 @@
libutils \
libbase \
libcutils \
+ libhealthd_draw \
liblog \
libm \
libc \
@@ -101,6 +126,7 @@
LOCAL_STATIC_LIBRARIES := \
libhealthd_charger \
+ libhealthd_draw \
libbatterymonitor \
libbase \
libutils \
diff --git a/healthd/healthd_draw.cpp b/healthd/healthd_draw.cpp
new file mode 100644
index 0000000..ea3d991
--- /dev/null
+++ b/healthd/healthd_draw.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2017 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 <android-base/stringprintf.h>
+#include <batteryservice/BatteryService.h>
+#include <cutils/klog.h>
+
+#include "healthd_draw.h"
+
+#define LOGE(x...) KLOG_ERROR("charger", x);
+#define LOGV(x...) KLOG_DEBUG("charger", x);
+
+HealthdDraw::HealthdDraw(animation* anim)
+ : kSplitScreen(HEALTHD_DRAW_SPLIT_SCREEN),
+ kSplitOffset(HEALTHD_DRAW_SPLIT_OFFSET) {
+ gr_init();
+ gr_font_size(gr_sys_font(), &char_width_, &char_height_);
+
+ screen_width_ = gr_fb_width() / (kSplitScreen ? 2 : 1);
+ screen_height_ = gr_fb_height();
+
+ int res;
+ if (!anim->text_clock.font_file.empty() &&
+ (res = gr_init_font(anim->text_clock.font_file.c_str(),
+ &anim->text_clock.font)) < 0) {
+ LOGE("Could not load time font (%d)\n", res);
+ }
+ if (!anim->text_percent.font_file.empty() &&
+ (res = gr_init_font(anim->text_percent.font_file.c_str(),
+ &anim->text_percent.font)) < 0) {
+ LOGE("Could not load percent font (%d)\n", res);
+ }
+}
+
+HealthdDraw::~HealthdDraw() {}
+
+void HealthdDraw::redraw_screen(const animation* batt_anim, GRSurface* surf_unknown) {
+ clear_screen();
+
+ /* try to display *something* */
+ if (batt_anim->cur_level < 0 || batt_anim->num_frames == 0)
+ draw_unknown(surf_unknown);
+ else
+ draw_battery(batt_anim);
+ gr_flip();
+}
+
+void HealthdDraw::blank_screen(bool blank) { gr_fb_blank(blank); }
+
+void HealthdDraw::clear_screen(void) {
+ gr_color(0, 0, 0, 255);
+ gr_clear();
+}
+
+int HealthdDraw::draw_surface_centered(GRSurface* surface) {
+ int w = gr_get_width(surface);
+ int h = gr_get_height(surface);
+ int x = (screen_width_ - w) / 2 + kSplitOffset;
+ int y = (screen_height_ - h) / 2;
+
+ LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y);
+ gr_blit(surface, 0, 0, w, h, x, y);
+ if (kSplitScreen) {
+ x += screen_width_ - 2 * kSplitOffset;
+ LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y);
+ gr_blit(surface, 0, 0, w, h, x, y);
+ }
+
+ return y + h;
+}
+
+int HealthdDraw::draw_text(const GRFont* font, int x, int y, const char* str) {
+ int str_len_px = gr_measure(font, str);
+
+ if (x < 0) x = (screen_width_ - str_len_px) / 2;
+ if (y < 0) y = (screen_height_ - char_height_) / 2;
+ gr_text(font, x + kSplitOffset, y, str, false /* bold */);
+ if (kSplitScreen)
+ gr_text(font, x - kSplitOffset + screen_width_, y, str, false /* bold */);
+
+ return y + char_height_;
+}
+
+void HealthdDraw::determine_xy(const animation::text_field& field,
+ const int length, int* x, int* y) {
+ *x = field.pos_x;
+
+ int str_len_px = length * field.font->char_width;
+ if (field.pos_x == CENTER_VAL) {
+ *x = (screen_width_ - str_len_px) / 2;
+ } else if (field.pos_x >= 0) {
+ *x = field.pos_x;
+ } else { // position from max edge
+ *x = screen_width_ + field.pos_x - str_len_px - kSplitOffset;
+ }
+
+ *y = field.pos_y;
+
+ if (field.pos_y == CENTER_VAL) {
+ *y = (screen_height_ - field.font->char_height) / 2;
+ } else if (field.pos_y >= 0) {
+ *y = field.pos_y;
+ } else { // position from max edge
+ *y = screen_height_ + field.pos_y - field.font->char_height;
+ }
+}
+
+void HealthdDraw::draw_clock(const animation* anim) {
+ static constexpr char CLOCK_FORMAT[] = "%H:%M";
+ static constexpr int CLOCK_LENGTH = 6;
+
+ const animation::text_field& field = anim->text_clock;
+
+ if (field.font == nullptr || field.font->char_width == 0 ||
+ field.font->char_height == 0)
+ return;
+
+ time_t rawtime;
+ time(&rawtime);
+ tm* time_info = localtime(&rawtime);
+
+ char clock_str[CLOCK_LENGTH];
+ size_t length = strftime(clock_str, CLOCK_LENGTH, CLOCK_FORMAT, time_info);
+ if (length != CLOCK_LENGTH - 1) {
+ LOGE("Could not format time\n");
+ return;
+ }
+
+ int x, y;
+ determine_xy(field, length, &x, &y);
+
+ LOGV("drawing clock %s %d %d\n", clock_str, x, y);
+ gr_color(field.color_r, field.color_g, field.color_b, field.color_a);
+ draw_text(field.font, x, y, clock_str);
+}
+
+void HealthdDraw::draw_percent(const animation* anim) {
+ int cur_level = anim->cur_level;
+ if (anim->cur_status == BATTERY_STATUS_FULL) {
+ cur_level = 100;
+ }
+
+ if (cur_level <= 0) return;
+
+ const animation::text_field& field = anim->text_percent;
+ if (field.font == nullptr || field.font->char_width == 0 ||
+ field.font->char_height == 0) {
+ return;
+ }
+
+ std::string str = base::StringPrintf("%d%%", cur_level);
+
+ int x, y;
+ determine_xy(field, str.size(), &x, &y);
+
+ LOGV("drawing percent %s %d %d\n", str.c_str(), x, y);
+ gr_color(field.color_r, field.color_g, field.color_b, field.color_a);
+ draw_text(field.font, x, y, str.c_str());
+}
+
+void HealthdDraw::draw_battery(const animation* anim) {
+ const animation::frame& frame = anim->frames[anim->cur_frame];
+
+ if (anim->num_frames != 0) {
+ draw_surface_centered(frame.surface);
+ LOGV("drawing frame #%d min_cap=%d time=%d\n", anim->cur_frame,
+ frame.min_level, frame.disp_time);
+ }
+ draw_clock(anim);
+ draw_percent(anim);
+}
+
+void HealthdDraw::draw_unknown(GRSurface* surf_unknown) {
+ int y;
+ if (surf_unknown) {
+ draw_surface_centered(surf_unknown);
+ } else {
+ gr_color(0xa4, 0xc6, 0x39, 255);
+ y = draw_text(gr_sys_font(), -1, -1, "Charging!");
+ draw_text(gr_sys_font(), -1, y + 25, "?\?/100");
+ }
+}
diff --git a/healthd/healthd_draw.h b/healthd/healthd_draw.h
new file mode 100644
index 0000000..6a6ba76
--- /dev/null
+++ b/healthd/healthd_draw.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2017 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 HEALTHD_DRAW_H
+#define HEALTHD_DRAW_H
+
+#include <linux/input.h>
+#include <minui/minui.h>
+
+#include "animation.h"
+
+using namespace android;
+
+class HealthdDraw {
+ public:
+ // Configures font using given animation.
+ HealthdDraw(animation* anim);
+ virtual ~HealthdDraw();
+
+ // Redraws screen.
+ void redraw_screen(const animation* batt_anim, GRSurface* surf_unknown);
+
+ // Blanks screen if true, unblanks if false.
+ virtual void blank_screen(bool blank);
+
+ protected:
+ virtual void clear_screen();
+
+ // returns the last y-offset of where the surface ends.
+ virtual int draw_surface_centered(GRSurface* surface);
+ // Negative x or y coordinates center text.
+ virtual int draw_text(const GRFont* font, int x, int y, const char* str);
+
+ // Negative x or y coordinates position the text away from the opposite edge
+ // that positive ones do.
+ virtual void determine_xy(const animation::text_field& field,
+ const int length, int* x, int* y);
+
+ // Draws battery animation, if it exists.
+ virtual void draw_battery(const animation* anim);
+ // Draws clock text, if animation contains text_field data.
+ virtual void draw_clock(const animation* anim);
+ // Draws battery percentage text if animation contains text_field data.
+ virtual void draw_percent(const animation* anim);
+ // Draws charger->surf_unknown or basic text.
+ virtual void draw_unknown(GRSurface* surf_unknown);
+
+ // Pixel sizes of characters for default font.
+ int char_width_;
+ int char_height_;
+
+ // Width and height of screen in pixels.
+ int screen_width_;
+ int screen_height_;
+
+ // Device screen is split vertically.
+ const bool kSplitScreen;
+ // Pixels to offset graphics towards center split.
+ const int kSplitOffset;
+};
+
+#endif // HEALTHD_DRAW_H
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index c76762d..6c6d738 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2013 The Android Open Source Project
+ * Copyright (C) 2011-2017 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.
@@ -18,7 +18,6 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
-#include <linux/input.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@@ -34,56 +33,54 @@
#include <android-base/file.h>
#include <android-base/macros.h>
-#include <android-base/stringprintf.h>
-#include <sys/socket.h>
#include <linux/netlink.h>
+#include <sys/socket.h>
-#include <batteryservice/BatteryService.h>
#include <cutils/klog.h>
#include <cutils/misc.h>
-#include <cutils/uevent.h>
#include <cutils/properties.h>
-#include <minui/minui.h>
+#include <cutils/uevent.h>
#include <sys/reboot.h>
#ifdef CHARGER_ENABLE_SUSPEND
#include <suspend/autosuspend.h>
#endif
-#include "animation.h"
#include "AnimationParser.h"
+#include "healthd_draw.h"
#include <healthd/healthd.h>
using namespace android;
-char *locale;
+char* locale;
#ifndef max
-#define max(a,b) ((a) > (b) ? (a) : (b))
+#define max(a, b) ((a) > (b) ? (a) : (b))
#endif
#ifndef min
-#define min(a,b) ((a) < (b) ? (a) : (b))
+#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-#define MSEC_PER_SEC (1000LL)
-#define NSEC_PER_MSEC (1000000LL)
+#define MSEC_PER_SEC (1000LL)
+#define NSEC_PER_MSEC (1000000LL)
-#define BATTERY_UNKNOWN_TIME (2 * MSEC_PER_SEC)
-#define POWER_ON_KEY_TIME (2 * MSEC_PER_SEC)
+#define BATTERY_UNKNOWN_TIME (2 * MSEC_PER_SEC)
+#define POWER_ON_KEY_TIME (2 * MSEC_PER_SEC)
#define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC)
-#define LAST_KMSG_MAX_SZ (32 * 1024)
+#define LAST_KMSG_MAX_SZ (32 * 1024)
-#define LOGE(x...) do { KLOG_ERROR("charger", x); } while (0)
-#define LOGW(x...) do { KLOG_WARNING("charger", x); } while (0)
-#define LOGV(x...) do { KLOG_DEBUG("charger", x); } while (0)
+#define LOGE(x...) KLOG_ERROR("charger", x);
+#define LOGW(x...) KLOG_WARNING("charger", x);
+#define LOGV(x...) KLOG_DEBUG("charger", x);
-static constexpr const char* animation_desc_path = "/res/values/charger/animation.txt";
+static constexpr const char* animation_desc_path =
+ "/res/values/charger/animation.txt";
struct key_state {
bool pending;
@@ -98,34 +95,36 @@
int64_t next_key_check;
int64_t next_pwr_check;
- struct key_state keys[KEY_MAX + 1];
+ key_state keys[KEY_MAX + 1];
- struct animation *batt_anim;
+ animation* batt_anim;
GRSurface* surf_unknown;
int boot_min_cap;
};
-static const struct animation BASE_ANIMATION = {
- .text_clock = {
- .pos_x = 0,
- .pos_y = 0,
+static const animation BASE_ANIMATION = {
+ .text_clock =
+ {
+ .pos_x = 0,
+ .pos_y = 0,
- .color_r = 255,
- .color_g = 255,
- .color_b = 255,
- .color_a = 255,
+ .color_r = 255,
+ .color_g = 255,
+ .color_b = 255,
+ .color_a = 255,
- .font = nullptr,
- },
- .text_percent = {
- .pos_x = 0,
- .pos_y = 0,
+ .font = nullptr,
+ },
+ .text_percent =
+ {
+ .pos_x = 0,
+ .pos_y = 0,
- .color_r = 255,
- .color_g = 255,
- .color_b = 255,
- .color_a = 255,
- },
+ .color_r = 255,
+ .color_g = 255,
+ .color_b = 255,
+ .color_a = 255,
+ },
.run = false,
@@ -141,8 +140,7 @@
.cur_status = BATTERY_STATUS_UNKNOWN,
};
-
-static struct animation::frame default_animation_frames[] = {
+static animation::frame default_animation_frames[] = {
{
.disp_time = 750,
.min_level = 0,
@@ -181,35 +179,25 @@
},
};
-static struct animation battery_animation = BASE_ANIMATION;
+static animation battery_animation = BASE_ANIMATION;
-static struct charger charger_state;
-static struct healthd_config *healthd_config;
-static struct android::BatteryProperties *batt_prop;
-static int char_width;
-static int char_height;
-static bool minui_inited;
+static charger charger_state;
+static healthd_config* healthd_config;
+static android::BatteryProperties* batt_prop;
+static std::unique_ptr<HealthdDraw> healthd_draw;
/* current time in milliseconds */
-static int64_t curr_time_ms(void)
-{
- struct timespec tm;
+static int64_t curr_time_ms() {
+ timespec tm;
clock_gettime(CLOCK_MONOTONIC, &tm);
return tm.tv_sec * MSEC_PER_SEC + (tm.tv_nsec / NSEC_PER_MSEC);
}
-static void clear_screen(void)
-{
- gr_color(0, 0, 0, 255);
- gr_clear();
-}
-
#define MAX_KLOG_WRITE_BUF_SZ 256
-static void dump_last_kmsg(void)
-{
- char *buf;
- char *ptr;
+static void dump_last_kmsg(void) {
+ char* buf;
+ char* ptr;
unsigned sz = 0;
int len;
@@ -239,11 +227,10 @@
while (len > 0) {
int cnt = min(len, MAX_KLOG_WRITE_BUF_SZ);
char yoink;
- char *nl;
+ char* nl;
- nl = (char *)memrchr(ptr, '\n', cnt - 1);
- if (nl)
- cnt = nl - ptr + 1;
+ nl = (char*)memrchr(ptr, '\n', cnt - 1);
+ if (nl) cnt = nl - ptr + 1;
yoink = ptr[cnt];
ptr[cnt] = '\0';
@@ -263,241 +250,59 @@
}
#ifdef CHARGER_ENABLE_SUSPEND
-static int request_suspend(bool enable)
-{
+static int request_suspend(bool enable) {
if (enable)
return autosuspend_enable();
else
return autosuspend_disable();
}
#else
-static int request_suspend(bool /*enable*/)
-{
+static int request_suspend(bool /*enable*/) {
return 0;
}
#endif
-static int draw_text(const char *str, int x, int y)
-{
- int str_len_px = gr_measure(gr_sys_font(), str);
-
- if (x < 0)
- x = (gr_fb_width() - str_len_px) / 2;
- if (y < 0)
- y = (gr_fb_height() - char_height) / 2;
- gr_text(gr_sys_font(), x, y, str, 0);
-
- return y + char_height;
-}
-
-static void android_green(void)
-{
- gr_color(0xa4, 0xc6, 0x39, 255);
-}
-
-// Negative x or y coordinates position the text away from the opposite edge that positive ones do.
-void determine_xy(const animation::text_field& field, const int length, int* x, int* y)
-{
- *x = field.pos_x;
- *y = field.pos_y;
-
- int str_len_px = length * field.font->char_width;
- if (field.pos_x == CENTER_VAL) {
- *x = (gr_fb_width() - str_len_px) / 2;
- } else if (field.pos_x >= 0) {
- *x = field.pos_x;
- } else { // position from max edge
- *x = gr_fb_width() + field.pos_x - str_len_px;
- }
-
- if (field.pos_y == CENTER_VAL) {
- *y = (gr_fb_height() - field.font->char_height) / 2;
- } else if (field.pos_y >= 0) {
- *y = field.pos_y;
- } else { // position from max edge
- *y = gr_fb_height() + field.pos_y - field.font->char_height;
- }
-}
-
-static void draw_clock(const animation& anim)
-{
- static constexpr char CLOCK_FORMAT[] = "%H:%M";
- static constexpr int CLOCK_LENGTH = 6;
-
- const animation::text_field& field = anim.text_clock;
-
- if (field.font == nullptr || field.font->char_width == 0 || field.font->char_height == 0) return;
-
- time_t rawtime;
- time(&rawtime);
- struct tm* time_info = localtime(&rawtime);
-
- char clock_str[CLOCK_LENGTH];
- size_t length = strftime(clock_str, CLOCK_LENGTH, CLOCK_FORMAT, time_info);
- if (length != CLOCK_LENGTH - 1) {
- LOGE("Could not format time\n");
- return;
- }
-
- int x, y;
- determine_xy(field, length, &x, &y);
-
- LOGV("drawing clock %s %d %d\n", clock_str, x, y);
- gr_color(field.color_r, field.color_g, field.color_b, field.color_a);
- gr_text(field.font, x, y, clock_str, false);
-}
-
-static void draw_percent(const animation& anim)
-{
- int cur_level = anim.cur_level;
- if (anim.cur_status == BATTERY_STATUS_FULL) {
- cur_level = 100;
- }
-
- if (cur_level <= 0) return;
-
- const animation::text_field& field = anim.text_percent;
- if (field.font == nullptr || field.font->char_width == 0 || field.font->char_height == 0) {
- return;
- }
-
- std::string str = base::StringPrintf("%d%%", cur_level);
-
- int x, y;
- determine_xy(field, str.size(), &x, &y);
-
- LOGV("drawing percent %s %d %d\n", str.c_str(), x, y);
- gr_color(field.color_r, field.color_g, field.color_b, field.color_a);
- gr_text(field.font, x, y, str.c_str(), false);
-}
-
-/* returns the last y-offset of where the surface ends */
-static int draw_surface_centered(GRSurface* surface)
-{
- int w;
- int h;
- int x;
- int y;
-
- w = gr_get_width(surface);
- h = gr_get_height(surface);
- x = (gr_fb_width() - w) / 2 ;
- y = (gr_fb_height() - h) / 2 ;
-
- LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y);
- gr_blit(surface, 0, 0, w, h, x, y);
- return y + h;
-}
-
-static void draw_unknown(struct charger *charger)
-{
- int y;
- if (charger->surf_unknown) {
- draw_surface_centered(charger->surf_unknown);
- } else {
- android_green();
- y = draw_text("Charging!", -1, -1);
- draw_text("?\?/100", -1, y + 25);
- }
-}
-
-static void draw_battery(const struct charger* charger)
-{
- const struct animation& anim = *charger->batt_anim;
- const struct animation::frame& frame = anim.frames[anim.cur_frame];
-
- if (anim.num_frames != 0) {
- draw_surface_centered(frame.surface);
- LOGV("drawing frame #%d min_cap=%d time=%d\n",
- anim.cur_frame, frame.min_level,
- frame.disp_time);
- }
- draw_clock(anim);
- draw_percent(anim);
-}
-
-static void redraw_screen(struct charger *charger)
-{
- struct animation *batt_anim = charger->batt_anim;
-
- clear_screen();
-
- /* try to display *something* */
- if (batt_anim->cur_level < 0 || batt_anim->num_frames == 0)
- draw_unknown(charger);
- else
- draw_battery(charger);
- gr_flip();
-}
-
-static void kick_animation(struct animation *anim)
-{
+static void kick_animation(animation* anim) {
anim->run = true;
}
-static void reset_animation(struct animation *anim)
-{
+static void reset_animation(animation* anim) {
anim->cur_cycle = 0;
anim->cur_frame = 0;
anim->run = false;
}
-static void init_status_display(struct animation* anim)
-{
- int res;
-
- if (!anim->text_clock.font_file.empty()) {
- if ((res =
- gr_init_font(anim->text_clock.font_file.c_str(), &anim->text_clock.font)) < 0) {
- LOGE("Could not load time font (%d)\n", res);
- }
- }
-
- if (!anim->text_percent.font_file.empty()) {
- if ((res =
- gr_init_font(anim->text_percent.font_file.c_str(), &anim->text_percent.font)) < 0) {
- LOGE("Could not load percent font (%d)\n", res);
- }
- }
-}
-
-static void update_screen_state(struct charger *charger, int64_t now)
-{
- struct animation *batt_anim = charger->batt_anim;
+static void update_screen_state(charger* charger, int64_t now) {
+ animation* batt_anim = charger->batt_anim;
int disp_time;
if (!batt_anim->run || now < charger->next_screen_transition) return;
- if (!minui_inited) {
+ if (healthd_draw == nullptr) {
if (healthd_config && healthd_config->screen_on) {
if (!healthd_config->screen_on(batt_prop)) {
LOGV("[%" PRId64 "] leave screen off\n", now);
batt_anim->run = false;
charger->next_screen_transition = -1;
- if (charger->charger_connected)
- request_suspend(true);
+ if (charger->charger_connected) request_suspend(true);
return;
}
}
- gr_init();
- gr_font_size(gr_sys_font(), &char_width, &char_height);
- init_status_display(batt_anim);
+ healthd_draw.reset(new HealthdDraw(batt_anim));
#ifndef CHARGER_DISABLE_INIT_BLANK
- gr_fb_blank(true);
+ healthd_draw->blank_screen(true);
#endif
- minui_inited = true;
}
/* animation is over, blank screen and leave */
if (batt_anim->num_cycles > 0 && batt_anim->cur_cycle == batt_anim->num_cycles) {
reset_animation(batt_anim);
charger->next_screen_transition = -1;
- gr_fb_blank(true);
+ healthd_draw->blank_screen(true);
LOGV("[%" PRId64 "] animation done\n", now);
- if (charger->charger_connected)
- request_suspend(true);
+ if (charger->charger_connected) request_suspend(true);
return;
}
@@ -505,7 +310,6 @@
/* animation starting, set up the animation */
if (batt_anim->cur_frame == 0) {
-
LOGV("[%" PRId64 "] animation starting\n", now);
if (batt_prop) {
batt_anim->cur_level = batt_prop->batteryLevel;
@@ -522,17 +326,16 @@
// repeat the first frame first_frame_repeats times
disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time *
- batt_anim->first_frame_repeats;
+ batt_anim->first_frame_repeats;
}
}
}
/* unblank the screen on first cycle */
- if (batt_anim->cur_cycle == 0)
- gr_fb_blank(false);
+ if (batt_anim->cur_cycle == 0) healthd_draw->blank_screen(false);
/* draw the new frame (@ cur_frame) */
- redraw_screen(charger);
+ healthd_draw->redraw_screen(charger->batt_anim, charger->surf_unknown);
/* if we don't have anim frames, we only have one image, so just bump
* the cycle counter and exit
@@ -576,22 +379,18 @@
}
}
-static int set_key_callback(struct charger *charger, int code, int value)
-{
+static int set_key_callback(charger* charger, int code, int value) {
int64_t now = curr_time_ms();
int down = !!value;
- if (code > KEY_MAX)
- return -1;
+ if (code > KEY_MAX) return -1;
/* ignore events that don't modify our state */
- if (charger->keys[code].down == down)
- return 0;
+ if (charger->keys[code].down == down) return 0;
/* only record the down even timestamp, as the amount
* of time the key spent not being pressed is not useful */
- if (down)
- charger->keys[code].timestamp = now;
+ if (down) charger->keys[code].timestamp = now;
charger->keys[code].down = down;
charger->keys[code].pending = true;
if (down) {
@@ -600,34 +399,27 @@
int64_t duration = now - charger->keys[code].timestamp;
int64_t secs = duration / 1000;
int64_t msecs = duration - secs * 1000;
- LOGV("[%" PRId64 "] key[%d] up (was down for %" PRId64 ".%" PRId64 "sec)\n",
- now, code, secs, msecs);
+ LOGV("[%" PRId64 "] key[%d] up (was down for %" PRId64 ".%" PRId64 "sec)\n", now, code,
+ secs, msecs);
}
return 0;
}
-static void update_input_state(struct charger *charger,
- struct input_event *ev)
-{
- if (ev->type != EV_KEY)
- return;
+static void update_input_state(charger* charger, input_event* ev) {
+ if (ev->type != EV_KEY) return;
set_key_callback(charger, ev->code, ev->value);
}
-static void set_next_key_check(struct charger *charger,
- struct key_state *key,
- int64_t timeout)
-{
+static void set_next_key_check(charger* charger, key_state* key, int64_t timeout) {
int64_t then = key->timestamp + timeout;
if (charger->next_key_check == -1 || then < charger->next_key_check)
charger->next_key_check = then;
}
-static void process_key(struct charger *charger, int code, int64_t now)
-{
- struct key_state *key = &charger->keys[code];
+static void process_key(charger* charger, int code, int64_t now) {
+ key_state* key = &charger->keys[code];
if (code == KEY_POWER) {
if (key->down) {
@@ -644,8 +436,10 @@
LOGW("[%" PRId64 "] rebooting\n", now);
reboot(RB_AUTOBOOT);
} else {
- LOGV("[%" PRId64 "] ignore power-button press, battery level "
- "less than minimum\n", now);
+ LOGV("[%" PRId64
+ "] ignore power-button press, battery level "
+ "less than minimum\n",
+ now);
}
}
} else {
@@ -654,9 +448,9 @@
*/
set_next_key_check(charger, key, POWER_ON_KEY_TIME);
- /* Turn on the display and kick animation on power-key press
- * rather than on key release
- */
+ /* Turn on the display and kick animation on power-key press
+ * rather than on key release
+ */
kick_animation(charger->batt_anim);
request_suspend(false);
}
@@ -671,21 +465,17 @@
key->pending = false;
}
-static void handle_input_state(struct charger *charger, int64_t now)
-{
+static void handle_input_state(charger* charger, int64_t now) {
process_key(charger, KEY_POWER, now);
if (charger->next_key_check != -1 && now > charger->next_key_check)
charger->next_key_check = -1;
}
-static void handle_power_supply_state(struct charger *charger, int64_t now)
-{
- if (!charger->have_battery_state)
- return;
+static void handle_power_supply_state(charger* charger, int64_t now) {
+ if (!charger->have_battery_state) return;
if (!charger->charger_connected) {
-
/* Last cycle would have stopped at the extreme top of battery-icon
* Need to show the correct level corresponding to capacity.
*/
@@ -711,9 +501,8 @@
}
}
-void healthd_mode_charger_heartbeat()
-{
- struct charger *charger = &charger_state;
+void healthd_mode_charger_heartbeat() {
+ charger* charger = &charger_state;
int64_t now = curr_time_ms();
handle_input_state(charger, now);
@@ -725,14 +514,11 @@
update_screen_state(charger, now);
}
-void healthd_mode_charger_battery_update(
- struct android::BatteryProperties *props)
-{
- struct charger *charger = &charger_state;
+void healthd_mode_charger_battery_update(android::BatteryProperties* props) {
+ charger* charger = &charger_state;
charger->charger_connected =
- props->chargerAcOnline || props->chargerUsbOnline ||
- props->chargerWirelessOnline;
+ props->chargerAcOnline || props->chargerUsbOnline || props->chargerWirelessOnline;
if (!charger->have_battery_state) {
charger->have_battery_state = true;
@@ -743,19 +529,16 @@
batt_prop = props;
}
-int healthd_mode_charger_preparetowait(void)
-{
- struct charger *charger = &charger_state;
+int healthd_mode_charger_preparetowait(void) {
+ charger* charger = &charger_state;
int64_t now = curr_time_ms();
int64_t next_event = INT64_MAX;
int64_t timeout;
- LOGV("[%" PRId64 "] next screen: %" PRId64 " next key: %" PRId64 " next pwr: %" PRId64 "\n", now,
- charger->next_screen_transition, charger->next_key_check,
- charger->next_pwr_check);
+ LOGV("[%" PRId64 "] next screen: %" PRId64 " next key: %" PRId64 " next pwr: %" PRId64 "\n",
+ now, charger->next_screen_transition, charger->next_key_check, charger->next_pwr_check);
- if (charger->next_screen_transition != -1)
- next_event = charger->next_screen_transition;
+ if (charger->next_screen_transition != -1) next_event = charger->next_screen_transition;
if (charger->next_key_check != -1 && charger->next_key_check < next_event)
next_event = charger->next_key_check;
if (charger->next_pwr_check != -1 && charger->next_pwr_check < next_event)
@@ -766,32 +549,27 @@
else
timeout = -1;
- return (int)timeout;
+ return (int)timeout;
}
-static int input_callback(struct charger *charger, int fd, unsigned int epevents)
-{
- struct input_event ev;
+static int input_callback(charger* charger, int fd, unsigned int epevents) {
+ input_event ev;
int ret;
ret = ev_get_input(fd, epevents, &ev);
- if (ret)
- return -1;
+ if (ret) return -1;
update_input_state(charger, &ev);
return 0;
}
-static void charger_event_handler(uint32_t /*epevents*/)
-{
+static void charger_event_handler(uint32_t /*epevents*/) {
int ret;
ret = ev_wait(-1);
- if (!ret)
- ev_dispatch();
+ if (!ret) ev_dispatch();
}
-animation* init_animation()
-{
+animation* init_animation() {
bool parse_success;
std::string content;
@@ -814,32 +592,29 @@
}
LOGV("Animation Description:\n");
- LOGV(" animation: %d %d '%s' (%d)\n",
- battery_animation.num_cycles, battery_animation.first_frame_repeats,
- battery_animation.animation_file.c_str(), battery_animation.num_frames);
+ LOGV(" animation: %d %d '%s' (%d)\n", battery_animation.num_cycles,
+ battery_animation.first_frame_repeats, battery_animation.animation_file.c_str(),
+ battery_animation.num_frames);
LOGV(" fail_file: '%s'\n", battery_animation.fail_file.c_str());
- LOGV(" clock: %d %d %d %d %d %d '%s'\n",
- battery_animation.text_clock.pos_x, battery_animation.text_clock.pos_y,
- battery_animation.text_clock.color_r, battery_animation.text_clock.color_g,
- battery_animation.text_clock.color_b, battery_animation.text_clock.color_a,
- battery_animation.text_clock.font_file.c_str());
- LOGV(" percent: %d %d %d %d %d %d '%s'\n",
- battery_animation.text_percent.pos_x, battery_animation.text_percent.pos_y,
- battery_animation.text_percent.color_r, battery_animation.text_percent.color_g,
- battery_animation.text_percent.color_b, battery_animation.text_percent.color_a,
- battery_animation.text_percent.font_file.c_str());
+ LOGV(" clock: %d %d %d %d %d %d '%s'\n", battery_animation.text_clock.pos_x,
+ battery_animation.text_clock.pos_y, battery_animation.text_clock.color_r,
+ battery_animation.text_clock.color_g, battery_animation.text_clock.color_b,
+ battery_animation.text_clock.color_a, battery_animation.text_clock.font_file.c_str());
+ LOGV(" percent: %d %d %d %d %d %d '%s'\n", battery_animation.text_percent.pos_x,
+ battery_animation.text_percent.pos_y, battery_animation.text_percent.color_r,
+ battery_animation.text_percent.color_g, battery_animation.text_percent.color_b,
+ battery_animation.text_percent.color_a, battery_animation.text_percent.font_file.c_str());
for (int i = 0; i < battery_animation.num_frames; i++) {
LOGV(" frame %.2d: %d %d %d\n", i, battery_animation.frames[i].disp_time,
- battery_animation.frames[i].min_level, battery_animation.frames[i].max_level);
+ battery_animation.frames[i].min_level, battery_animation.frames[i].max_level);
}
return &battery_animation;
}
-void healthd_mode_charger_init(struct healthd_config* config)
-{
+void healthd_mode_charger_init(struct healthd_config* config) {
int ret;
- struct charger *charger = &charger_state;
+ charger* charger = &charger_state;
int i;
int epollfd;
@@ -847,14 +622,13 @@
LOGW("--------------- STARTING CHARGER MODE ---------------\n");
- ret = ev_init(std::bind(&input_callback, charger, std::placeholders::_1,
- std::placeholders::_2));
+ ret = ev_init(std::bind(&input_callback, charger, std::placeholders::_1, std::placeholders::_2));
if (!ret) {
epollfd = ev_get_epollfd();
healthd_register_event(epollfd, charger_event_handler, EVENT_WAKEUP_FD);
}
- struct animation* anim = init_animation();
+ animation* anim = init_animation();
charger->batt_anim = anim;
ret = res_create_display_surface(anim->fail_file.c_str(), &charger->surf_unknown);
@@ -871,15 +645,15 @@
int scale_count;
int scale_fps; // Not in use (charger/battery_scale doesn't have FPS text
// chunk). We are using hard-coded frame.disp_time instead.
- ret = res_create_multi_display_surface(anim->animation_file.c_str(),
- &scale_count, &scale_fps, &scale_frames);
+ ret = res_create_multi_display_surface(anim->animation_file.c_str(), &scale_count, &scale_fps,
+ &scale_frames);
if (ret < 0) {
LOGE("Cannot load battery_scale image\n");
anim->num_frames = 0;
anim->num_cycles = 1;
} else if (scale_count != anim->num_frames) {
- LOGE("battery_scale image has unexpected frame count (%d, expected %d)\n",
- scale_count, anim->num_frames);
+ LOGE("battery_scale image has unexpected frame count (%d, expected %d)\n", scale_count,
+ anim->num_frames);
anim->num_frames = 0;
anim->num_cycles = 1;
} else {
@@ -887,8 +661,8 @@
anim->frames[i].surface = scale_frames[i];
}
}
- ev_sync_key_state(std::bind(&set_key_callback, charger, std::placeholders::_1,
- std::placeholders::_2));
+ ev_sync_key_state(
+ std::bind(&set_key_callback, charger, std::placeholders::_1, std::placeholders::_2));
charger->next_screen_transition = -1;
charger->next_key_check = -1;
diff --git a/init/Android.bp b/init/Android.bp
index 0e580fc..e906771 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -78,6 +78,8 @@
"security.cpp",
"selinux.cpp",
"service.cpp",
+ "subcontext.cpp",
+ "subcontext.proto",
"rlimit_parser.cpp",
"tokenizer.cpp",
"uevent_listener.cpp",
@@ -173,6 +175,7 @@
"result_test.cpp",
"rlimit_parser_test.cpp",
"service_test.cpp",
+ "subcontext_test.cpp",
"ueventd_test.cpp",
"util_test.cpp",
],
@@ -188,4 +191,22 @@
],
}
+cc_benchmark {
+ name: "init_benchmarks",
+ defaults: ["init_defaults"],
+ srcs: [
+ "subcontext_benchmark.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ ],
+ static_libs: [
+ "libinit",
+ "libselinux",
+ "libcrypto",
+ "libprotobuf-cpp-lite",
+ ],
+}
+
subdirs = ["*"]
diff --git a/init/action.cpp b/init/action.cpp
index 60204a8..2617d00 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -24,34 +24,48 @@
#include "util.h"
using android::base::Join;
+using android::base::StartsWith;
namespace android {
namespace init {
-Command::Command(BuiltinFunction f, const std::vector<std::string>& args, int line)
- : func_(f), args_(args), line_(line) {}
+Result<Success> RunBuiltinFunction(const BuiltinFunction& function,
+ const std::vector<std::string>& args,
+ const std::string& context) {
+ auto builtin_arguments = BuiltinArguments(context);
-Result<Success> Command::InvokeFunc() const {
- std::vector<std::string> expanded_args;
- expanded_args.resize(args_.size());
- expanded_args[0] = args_[0];
- for (std::size_t i = 1; i < args_.size(); ++i) {
- if (!expand_props(args_[i], &expanded_args[i])) {
- return Error() << "cannot expand '" << args_[i] << "'";
+ builtin_arguments.args.resize(args.size());
+ builtin_arguments.args[0] = args[0];
+ for (std::size_t i = 1; i < args.size(); ++i) {
+ if (!expand_props(args[i], &builtin_arguments.args[i])) {
+ return Error() << "cannot expand '" << args[i] << "'";
}
}
- return func_(expanded_args);
+ return function(builtin_arguments);
+}
+
+Command::Command(BuiltinFunction f, bool execute_in_subcontext,
+ const std::vector<std::string>& args, int line)
+ : func_(std::move(f)), execute_in_subcontext_(execute_in_subcontext), args_(args), line_(line) {}
+
+Result<Success> Command::InvokeFunc(Subcontext* subcontext) const {
+ if (execute_in_subcontext_ && subcontext) {
+ return subcontext->Execute(args_);
+ } else {
+ const std::string& context = subcontext ? subcontext->context() : kInitContext;
+ return RunBuiltinFunction(func_, args_, context);
+ }
}
std::string Command::BuildCommandString() const {
return Join(args_, ' ');
}
-Action::Action(bool oneshot, const std::string& filename, int line)
- : oneshot_(oneshot), filename_(filename), line_(line) {}
+Action::Action(bool oneshot, Subcontext* subcontext, const std::string& filename, int line)
+ : oneshot_(oneshot), subcontext_(subcontext), filename_(filename), line_(line) {}
-const KeywordMap<BuiltinFunction>* Action::function_map_ = nullptr;
+const KeywordFunctionMap* Action::function_map_ = nullptr;
Result<Success> Action::AddCommand(const std::vector<std::string>& args, int line) {
if (!function_map_) {
@@ -61,12 +75,12 @@
auto function = function_map_->FindFunction(args);
if (!function) return Error() << function.error();
- AddCommand(*function, args, line);
+ commands_.emplace_back(function->second, function->first, args, line);
return Success();
}
void Action::AddCommand(BuiltinFunction f, const std::vector<std::string>& args, int line) {
- commands_.emplace_back(f, args, line);
+ commands_.emplace_back(f, false, args, line);
}
std::size_t Action::NumCommands() const {
@@ -88,7 +102,7 @@
void Action::ExecuteCommand(const Command& command) const {
android::base::Timer t;
- auto result = command.InvokeFunc();
+ auto result = command.InvokeFunc(subcontext_);
auto duration = t.duration();
// There are many legacy paths in rootdir/init.rc that will virtually never exist on a new
@@ -261,7 +275,7 @@
}
void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) {
- auto action = std::make_unique<Action>(true, "<Builtin Action>", 0);
+ auto action = std::make_unique<Action>(true, nullptr, "<Builtin Action>", 0);
std::vector<std::string> name_vector{name};
if (auto result = action->InitSingleTrigger(name); !result) {
@@ -341,7 +355,17 @@
return Error() << "Actions must have a trigger";
}
- auto action = std::make_unique<Action>(false, filename, line);
+ Subcontext* action_subcontext = nullptr;
+ if (subcontexts_) {
+ for (auto& subcontext : *subcontexts_) {
+ if (StartsWith(filename, subcontext.path_prefix().c_str())) {
+ action_subcontext = &subcontext;
+ break;
+ }
+ }
+ }
+
+ auto action = std::make_unique<Action>(false, action_subcontext, filename, line);
if (auto result = action->InitTriggers(triggers); !result) {
return Error() << "InitTriggers() failed: " << result.error();
diff --git a/init/action.h b/init/action.h
index d977f82..cdfc6a0 100644
--- a/init/action.h
+++ b/init/action.h
@@ -27,21 +27,27 @@
#include "keyword_map.h"
#include "parser.h"
#include "result.h"
+#include "subcontext.h"
namespace android {
namespace init {
+Result<Success> RunBuiltinFunction(const BuiltinFunction& function,
+ const std::vector<std::string>& args, const std::string& context);
+
class Command {
public:
- Command(BuiltinFunction f, const std::vector<std::string>& args, int line);
+ Command(BuiltinFunction f, bool execute_in_subcontext, const std::vector<std::string>& args,
+ int line);
- Result<Success> InvokeFunc() const;
+ Result<Success> InvokeFunc(Subcontext* subcontext) const;
std::string BuildCommandString() const;
int line() const { return line_; }
private:
BuiltinFunction func_;
+ bool execute_in_subcontext_;
std::vector<std::string> args_;
int line_;
};
@@ -52,7 +58,7 @@
class Action {
public:
- explicit Action(bool oneshot, const std::string& filename, int line);
+ Action(bool oneshot, Subcontext* subcontext, const std::string& filename, int line);
Result<Success> AddCommand(const std::vector<std::string>& args, int line);
void AddCommand(BuiltinFunction f, const std::vector<std::string>& args, int line);
@@ -70,12 +76,11 @@
bool oneshot() const { return oneshot_; }
const std::string& filename() const { return filename_; }
int line() const { return line_; }
- static void set_function_map(const KeywordMap<BuiltinFunction>* function_map) {
+ static void set_function_map(const KeywordFunctionMap* function_map) {
function_map_ = function_map;
}
-
-private:
+ private:
void ExecuteCommand(const Command& command) const;
bool CheckPropertyTriggers(const std::string& name = "",
const std::string& value = "") const;
@@ -85,9 +90,10 @@
std::string event_trigger_;
std::vector<Command> commands_;
bool oneshot_;
+ Subcontext* subcontext_;
std::string filename_;
int line_;
- static const KeywordMap<BuiltinFunction>* function_map_;
+ static const KeywordFunctionMap* function_map_;
};
class ActionManager {
@@ -119,8 +125,8 @@
class ActionParser : public SectionParser {
public:
- ActionParser(ActionManager* action_manager)
- : action_manager_(action_manager), action_(nullptr) {}
+ ActionParser(ActionManager* action_manager, std::vector<Subcontext>* subcontexts)
+ : action_manager_(action_manager), subcontexts_(subcontexts), action_(nullptr) {}
Result<Success> ParseSection(std::vector<std::string>&& args, const std::string& filename,
int line) override;
Result<Success> ParseLineSection(std::vector<std::string>&& args, int line) override;
@@ -128,6 +134,7 @@
private:
ActionManager* action_manager_;
+ std::vector<Subcontext>* subcontexts_;
std::unique_ptr<Action> action_;
};
diff --git a/init/bootchart.cpp b/init/bootchart.cpp
index ec84317..379b4fa 100644
--- a/init/bootchart.cpp
+++ b/init/bootchart.cpp
@@ -191,7 +191,7 @@
return Success();
}
-Result<Success> do_bootchart(const std::vector<std::string>& args) {
+Result<Success> do_bootchart(const BuiltinArguments& args) {
if (args[1] == "start") return do_bootchart_start();
return do_bootchart_stop();
}
diff --git a/init/bootchart.h b/init/bootchart.h
index f614f71..05474ca 100644
--- a/init/bootchart.h
+++ b/init/bootchart.h
@@ -20,12 +20,13 @@
#include <string>
#include <vector>
+#include "builtin_arguments.h"
#include "result.h"
namespace android {
namespace init {
-Result<Success> do_bootchart(const std::vector<std::string>& args);
+Result<Success> do_bootchart(const BuiltinArguments& args);
} // namespace init
} // namespace android
diff --git a/init/builtin_arguments.h b/init/builtin_arguments.h
new file mode 100644
index 0000000..1742b78
--- /dev/null
+++ b/init/builtin_arguments.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2017 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_BUILTIN_ARGUMENTS_H
+#define _INIT_BUILTIN_ARGUMENTS_H
+
+#include <string>
+#include <vector>
+
+namespace android {
+namespace init {
+
+struct BuiltinArguments {
+ BuiltinArguments(const std::string& context) : context(context) {}
+ BuiltinArguments(std::vector<std::string> args, const std::string& context)
+ : args(std::move(args)), context(context) {}
+
+ const std::string& operator[](std::size_t i) const { return args[i]; }
+ auto begin() const { return args.begin(); }
+ auto end() const { return args.end(); }
+ auto size() const { return args.size(); }
+
+ std::vector<std::string> args;
+ const std::string& context;
+};
+
+} // namespace init
+} // namespace android
+
+#endif
diff --git a/init/builtins.cpp b/init/builtins.cpp
index be24573..4c2dc9a 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -66,6 +66,7 @@
#include "reboot.h"
#include "rlimit_parser.h"
#include "service.h"
+#include "subcontext.h"
#include "util.h"
using namespace std::literals::string_literals;
@@ -95,36 +96,36 @@
}
}
-static Result<Success> do_class_start(const std::vector<std::string>& args) {
+static Result<Success> do_class_start(const BuiltinArguments& args) {
// Starting a class does not start services which are explicitly disabled.
// They must be started individually.
ForEachServiceInClass(args[1], &Service::StartIfNotDisabled);
return Success();
}
-static Result<Success> do_class_stop(const std::vector<std::string>& args) {
+static Result<Success> do_class_stop(const BuiltinArguments& args) {
ForEachServiceInClass(args[1], &Service::Stop);
return Success();
}
-static Result<Success> do_class_reset(const std::vector<std::string>& args) {
+static Result<Success> do_class_reset(const BuiltinArguments& args) {
ForEachServiceInClass(args[1], &Service::Reset);
return Success();
}
-static Result<Success> do_class_restart(const std::vector<std::string>& args) {
+static Result<Success> do_class_restart(const BuiltinArguments& args) {
ForEachServiceInClass(args[1], &Service::Restart);
return Success();
}
-static Result<Success> do_domainname(const std::vector<std::string>& args) {
+static Result<Success> do_domainname(const BuiltinArguments& args) {
if (auto result = WriteFile("/proc/sys/kernel/domainname", args[1]); !result) {
return Error() << "Unable to write to /proc/sys/kernel/domainname: " << result.error();
}
return Success();
}
-static Result<Success> do_enable(const std::vector<std::string>& args) {
+static Result<Success> do_enable(const BuiltinArguments& args) {
Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) return Error() << "Could not find service";
@@ -135,8 +136,8 @@
return Success();
}
-static Result<Success> do_exec(const std::vector<std::string>& args) {
- auto service = Service::MakeTemporaryOneshotService(args);
+static Result<Success> do_exec(const BuiltinArguments& args) {
+ auto service = Service::MakeTemporaryOneshotService(args.args);
if (!service) {
return Error() << "Could not create exec service";
}
@@ -148,8 +149,8 @@
return Success();
}
-static Result<Success> do_exec_background(const std::vector<std::string>& args) {
- auto service = Service::MakeTemporaryOneshotService(args);
+static Result<Success> do_exec_background(const BuiltinArguments& args) {
+ auto service = Service::MakeTemporaryOneshotService(args.args);
if (!service) {
return Error() << "Could not create exec background service";
}
@@ -161,7 +162,7 @@
return Success();
}
-static Result<Success> do_exec_start(const std::vector<std::string>& args) {
+static Result<Success> do_exec_start(const BuiltinArguments& args) {
Service* service = ServiceList::GetInstance().FindService(args[1]);
if (!service) {
return Error() << "Service not found";
@@ -174,21 +175,21 @@
return Success();
}
-static Result<Success> do_export(const std::vector<std::string>& args) {
+static Result<Success> do_export(const BuiltinArguments& args) {
if (setenv(args[1].c_str(), args[2].c_str(), 1) == -1) {
return ErrnoError() << "setenv() failed";
}
return Success();
}
-static Result<Success> do_hostname(const std::vector<std::string>& args) {
+static Result<Success> do_hostname(const BuiltinArguments& args) {
if (auto result = WriteFile("/proc/sys/kernel/hostname", args[1]); !result) {
return Error() << "Unable to write to /proc/sys/kernel/hostname: " << result.error();
}
return Success();
}
-static Result<Success> do_ifup(const std::vector<std::string>& args) {
+static Result<Success> do_ifup(const BuiltinArguments& args) {
struct ifreq ifr;
strlcpy(ifr.ifr_name, args[1].c_str(), IFNAMSIZ);
@@ -209,7 +210,7 @@
return Success();
}
-static Result<Success> do_insmod(const std::vector<std::string>& args) {
+static Result<Success> do_insmod(const BuiltinArguments& args) {
int flags = 0;
auto it = args.begin() + 1;
@@ -231,7 +232,7 @@
}
// mkdir <path> [mode] [owner] [group]
-static Result<Success> do_mkdir(const std::vector<std::string>& args) {
+static Result<Success> do_mkdir(const BuiltinArguments& args) {
mode_t mode = 0755;
if (args.size() >= 3) {
mode = std::strtoul(args[2].c_str(), 0, 8);
@@ -287,7 +288,7 @@
}
/* umount <path> */
-static Result<Success> do_umount(const std::vector<std::string>& args) {
+static Result<Success> do_umount(const BuiltinArguments& args) {
if (umount(args[1].c_str()) < 0) {
return ErrnoError() << "umount() failed";
}
@@ -319,7 +320,7 @@
#define DATA_MNT_POINT "/data"
/* mount <type> <device> <path> <flags ...> <options> */
-static Result<Success> do_mount(const std::vector<std::string>& args) {
+static Result<Success> do_mount(const BuiltinArguments& args) {
const char* options = nullptr;
unsigned flags = 0;
bool wait = false;
@@ -498,6 +499,25 @@
// do anything different from the nonencrypted case.
ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
return Success();
+ } else if (code == FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED) {
+ if (e4crypt_install_keyring()) {
+ return Error() << "e4crypt_install_keyring() failed";
+ }
+ property_set("ro.crypto.state", "encrypted");
+ property_set("ro.crypto.type", "file");
+
+ // defaultcrypto detects file/block encryption. init flow is same for each.
+ ActionManager::GetInstance().QueueEventTrigger("defaultcrypto");
+ return Success();
+ } else if (code == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) {
+ if (e4crypt_install_keyring()) {
+ return Error() << "e4crypt_install_keyring() failed";
+ }
+ property_set("ro.crypto.type", "file");
+
+ // encrypt detects file/block encryption. init flow is same for each.
+ ActionManager::GetInstance().QueueEventTrigger("encrypt");
+ return Success();
} else if (code > 0) {
Error() << "fs_mgr_mount_all() returned unexpected error " << code;
}
@@ -511,7 +531,7 @@
* This function might request a reboot, in which case it will
* not return.
*/
-static Result<Success> do_mount_all(const std::vector<std::string>& args) {
+static Result<Success> do_mount_all(const BuiltinArguments& args) {
std::size_t na = 0;
bool import_rc = true;
bool queue_event = true;
@@ -544,7 +564,7 @@
if (import_rc) {
/* Paths of .rc files are specified at the 2nd argument and beyond */
- import_late(args, 2, path_arg_end);
+ import_late(args.args, 2, path_arg_end);
}
if (queue_event) {
@@ -559,7 +579,7 @@
return Success();
}
-static Result<Success> do_swapon_all(const std::vector<std::string>& args) {
+static Result<Success> do_swapon_all(const BuiltinArguments& args) {
struct fstab *fstab;
int ret;
@@ -571,13 +591,13 @@
return Success();
}
-static Result<Success> do_setprop(const std::vector<std::string>& args) {
+static Result<Success> do_setprop(const BuiltinArguments& args) {
property_set(args[1], args[2]);
return Success();
}
-static Result<Success> do_setrlimit(const std::vector<std::string>& args) {
- auto rlimit = ParseRlimit(args);
+static Result<Success> do_setrlimit(const BuiltinArguments& args) {
+ auto rlimit = ParseRlimit(args.args);
if (!rlimit) return rlimit.error();
if (setrlimit(rlimit->first, &rlimit->second) == -1) {
@@ -586,7 +606,7 @@
return Success();
}
-static Result<Success> do_start(const std::vector<std::string>& args) {
+static Result<Success> do_start(const BuiltinArguments& args) {
Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) return Error() << "service " << args[1] << " not found";
if (auto result = svc->Start(); !result) {
@@ -595,26 +615,26 @@
return Success();
}
-static Result<Success> do_stop(const std::vector<std::string>& args) {
+static Result<Success> do_stop(const BuiltinArguments& args) {
Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) return Error() << "service " << args[1] << " not found";
svc->Stop();
return Success();
}
-static Result<Success> do_restart(const std::vector<std::string>& args) {
+static Result<Success> do_restart(const BuiltinArguments& args) {
Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) return Error() << "service " << args[1] << " not found";
svc->Restart();
return Success();
}
-static Result<Success> do_trigger(const std::vector<std::string>& args) {
+static Result<Success> do_trigger(const BuiltinArguments& args) {
ActionManager::GetInstance().QueueEventTrigger(args[1]);
return Success();
}
-static Result<Success> do_symlink(const std::vector<std::string>& args) {
+static Result<Success> do_symlink(const BuiltinArguments& args) {
if (symlink(args[1].c_str(), args[2].c_str()) < 0) {
// The symlink builtin is often used to create symlinks for older devices to be backwards
// compatible with new paths, therefore we skip reporting this error.
@@ -626,21 +646,21 @@
return Success();
}
-static Result<Success> do_rm(const std::vector<std::string>& args) {
+static Result<Success> do_rm(const BuiltinArguments& args) {
if (unlink(args[1].c_str()) < 0) {
return ErrnoError() << "unlink() failed";
}
return Success();
}
-static Result<Success> do_rmdir(const std::vector<std::string>& args) {
+static Result<Success> do_rmdir(const BuiltinArguments& args) {
if (rmdir(args[1].c_str()) < 0) {
return ErrnoError() << "rmdir() failed";
}
return Success();
}
-static Result<Success> do_sysclktz(const std::vector<std::string>& args) {
+static Result<Success> do_sysclktz(const BuiltinArguments& args) {
struct timezone tz = {};
if (!android::base::ParseInt(args[1], &tz.tz_minuteswest)) {
return Error() << "Unable to parse mins_west_of_gmt";
@@ -652,7 +672,7 @@
return Success();
}
-static Result<Success> do_verity_load_state(const std::vector<std::string>& args) {
+static Result<Success> do_verity_load_state(const BuiltinArguments& args) {
int mode = -1;
bool loaded = fs_mgr_load_verity_state(&mode);
if (loaded && mode != VERITY_MODE_DEFAULT) {
@@ -668,14 +688,14 @@
property_set("partition."s + mount_point + ".verified", std::to_string(mode));
}
-static Result<Success> do_verity_update_state(const std::vector<std::string>& args) {
+static Result<Success> do_verity_update_state(const BuiltinArguments& args) {
if (!fs_mgr_update_verity_state(verity_update_property)) {
return Error() << "fs_mgr_update_verity_state() failed";
}
return Success();
}
-static Result<Success> do_write(const std::vector<std::string>& args) {
+static Result<Success> do_write(const BuiltinArguments& args) {
if (auto result = WriteFile(args[1], args[2]); !result) {
return Error() << "Unable to write to file '" << args[1] << "': " << result.error();
}
@@ -706,7 +726,7 @@
return Success();
}
-static Result<Success> do_readahead(const std::vector<std::string>& args) {
+static Result<Success> do_readahead(const BuiltinArguments& args) {
struct stat sb;
if (stat(args[1].c_str(), &sb)) {
@@ -765,7 +785,7 @@
return Success();
}
-static Result<Success> do_copy(const std::vector<std::string>& args) {
+static Result<Success> do_copy(const BuiltinArguments& args) {
auto file_contents = ReadFile(args[1]);
if (!file_contents) {
return Error() << "Could not read input file '" << args[1] << "': " << file_contents.error();
@@ -777,7 +797,7 @@
return Success();
}
-static Result<Success> do_chown(const std::vector<std::string>& args) {
+static Result<Success> do_chown(const BuiltinArguments& args) {
auto uid = DecodeUid(args[1]);
if (!uid) {
return Error() << "Unable to decode UID for '" << args[1] << "': " << uid.error();
@@ -814,7 +834,7 @@
return mode;
}
-static Result<Success> do_chmod(const std::vector<std::string>& args) {
+static Result<Success> do_chmod(const BuiltinArguments& args) {
mode_t mode = get_mode(args[1].c_str());
if (fchmodat(AT_FDCWD, args[2].c_str(), mode, AT_SYMLINK_NOFOLLOW) < 0) {
return ErrnoError() << "fchmodat() failed";
@@ -822,7 +842,7 @@
return Success();
}
-static Result<Success> do_restorecon(const std::vector<std::string>& args) {
+static Result<Success> do_restorecon(const BuiltinArguments& args) {
int ret = 0;
struct flag_type {const char* name; int value;};
@@ -864,13 +884,13 @@
return Success();
}
-static Result<Success> do_restorecon_recursive(const std::vector<std::string>& args) {
- std::vector<std::string> non_const_args(args);
+static Result<Success> do_restorecon_recursive(const BuiltinArguments& args) {
+ std::vector<std::string> non_const_args(args.args);
non_const_args.insert(std::next(non_const_args.begin()), "--recursive");
- return do_restorecon(non_const_args);
+ return do_restorecon({std::move(non_const_args), args.context});
}
-static Result<Success> do_loglevel(const std::vector<std::string>& args) {
+static Result<Success> do_loglevel(const BuiltinArguments& args) {
// TODO: support names instead/as well?
int log_level = -1;
android::base::ParseInt(args[1], &log_level);
@@ -891,17 +911,17 @@
return Success();
}
-static Result<Success> do_load_persist_props(const std::vector<std::string>& args) {
+static Result<Success> do_load_persist_props(const BuiltinArguments& args) {
load_persist_props();
return Success();
}
-static Result<Success> do_load_system_props(const std::vector<std::string>& args) {
+static Result<Success> do_load_system_props(const BuiltinArguments& args) {
load_system_props();
return Success();
}
-static Result<Success> do_wait(const std::vector<std::string>& args) {
+static Result<Success> do_wait(const BuiltinArguments& args) {
auto timeout = kCommandRetryTimeout;
if (args.size() == 3) {
int timeout_int;
@@ -918,7 +938,7 @@
return Success();
}
-static Result<Success> do_wait_for_prop(const std::vector<std::string>& args) {
+static Result<Success> do_wait_for_prop(const BuiltinArguments& args) {
const char* name = args[1].c_str();
const char* value = args[2].c_str();
size_t value_len = strlen(value);
@@ -939,7 +959,7 @@
return android::base::GetProperty("ro.crypto.type", "") == "file";
}
-static Result<Success> do_installkey(const std::vector<std::string>& args) {
+static Result<Success> do_installkey(const BuiltinArguments& args) {
if (!is_file_crypto()) return Success();
auto unencrypted_dir = args[1] + e4crypt_unencrypted_folder;
@@ -948,64 +968,66 @@
}
std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs",
"enablefilecrypto"};
- return do_exec(exec_args);
+ return do_exec({std::move(exec_args), args.context});
}
-static Result<Success> do_init_user0(const std::vector<std::string>& args) {
+static Result<Success> do_init_user0(const BuiltinArguments& args) {
std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs",
"init_user0"};
- return do_exec(exec_args);
+ return do_exec({std::move(exec_args), args.context});
}
const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
// clang-format off
static const Map builtin_functions = {
- {"bootchart", {1, 1, do_bootchart}},
- {"chmod", {2, 2, do_chmod}},
- {"chown", {2, 3, do_chown}},
- {"class_reset", {1, 1, do_class_reset}},
- {"class_restart", {1, 1, do_class_restart}},
- {"class_start", {1, 1, do_class_start}},
- {"class_stop", {1, 1, do_class_stop}},
- {"copy", {2, 2, do_copy}},
- {"domainname", {1, 1, do_domainname}},
- {"enable", {1, 1, do_enable}},
- {"exec", {1, kMax, do_exec}},
- {"exec_background", {1, kMax, do_exec_background}},
- {"exec_start", {1, 1, do_exec_start}},
- {"export", {2, 2, do_export}},
- {"hostname", {1, 1, do_hostname}},
- {"ifup", {1, 1, do_ifup}},
- {"init_user0", {0, 0, do_init_user0}},
- {"insmod", {1, kMax, do_insmod}},
- {"installkey", {1, 1, do_installkey}},
- {"load_persist_props", {0, 0, do_load_persist_props}},
- {"load_system_props", {0, 0, do_load_system_props}},
- {"loglevel", {1, 1, do_loglevel}},
- {"mkdir", {1, 4, do_mkdir}},
- {"mount_all", {1, kMax, do_mount_all}},
- {"mount", {3, kMax, do_mount}},
- {"umount", {1, 1, do_umount}},
- {"readahead", {1, 2, do_readahead}},
- {"restart", {1, 1, do_restart}},
- {"restorecon", {1, kMax, do_restorecon}},
- {"restorecon_recursive", {1, kMax, do_restorecon_recursive}},
- {"rm", {1, 1, do_rm}},
- {"rmdir", {1, 1, do_rmdir}},
- {"setprop", {2, 2, do_setprop}},
- {"setrlimit", {3, 3, do_setrlimit}},
- {"start", {1, 1, do_start}},
- {"stop", {1, 1, do_stop}},
- {"swapon_all", {1, 1, do_swapon_all}},
- {"symlink", {2, 2, do_symlink}},
- {"sysclktz", {1, 1, do_sysclktz}},
- {"trigger", {1, 1, do_trigger}},
- {"verity_load_state", {0, 0, do_verity_load_state}},
- {"verity_update_state", {0, 0, do_verity_update_state}},
- {"wait", {1, 2, do_wait}},
- {"wait_for_prop", {2, 2, do_wait_for_prop}},
- {"write", {2, 2, do_write}},
+ {"bootchart", {1, 1, {false, do_bootchart}}},
+ {"chmod", {2, 2, {true, do_chmod}}},
+ {"chown", {2, 3, {true, do_chown}}},
+ {"class_reset", {1, 1, {false, do_class_reset}}},
+ {"class_restart", {1, 1, {false, do_class_restart}}},
+ {"class_start", {1, 1, {false, do_class_start}}},
+ {"class_stop", {1, 1, {false, do_class_stop}}},
+ {"copy", {2, 2, {true, do_copy}}},
+ {"domainname", {1, 1, {true, do_domainname}}},
+ {"enable", {1, 1, {false, do_enable}}},
+ {"exec", {1, kMax, {false, do_exec}}},
+ {"exec_background", {1, kMax, {false, do_exec_background}}},
+ {"exec_start", {1, 1, {false, do_exec_start}}},
+ {"export", {2, 2, {false, do_export}}},
+ {"hostname", {1, 1, {true, do_hostname}}},
+ {"ifup", {1, 1, {true, do_ifup}}},
+ {"init_user0", {0, 0, {false, do_init_user0}}},
+ {"insmod", {1, kMax, {true, do_insmod}}},
+ {"installkey", {1, 1, {false, do_installkey}}},
+ {"load_persist_props", {0, 0, {false, do_load_persist_props}}},
+ {"load_system_props", {0, 0, {false, do_load_system_props}}},
+ {"loglevel", {1, 1, {false, do_loglevel}}},
+ {"mkdir", {1, 4, {true, do_mkdir}}},
+ {"mount_all", {1, kMax, {false, do_mount_all}}},
+ {"mount", {3, kMax, {false, do_mount}}},
+ {"umount", {1, 1, {false, do_umount}}},
+ {"readahead", {1, 2, {true, do_readahead}}},
+ {"restart", {1, 1, {false, do_restart}}},
+ {"restorecon", {1, kMax, {true, do_restorecon}}},
+ {"restorecon_recursive", {1, kMax, {true, do_restorecon_recursive}}},
+ {"rm", {1, 1, {true, do_rm}}},
+ {"rmdir", {1, 1, {true, do_rmdir}}},
+ // TODO: setprop should be run in the subcontext, but property service needs to be split
+ // out from init before that is possible.
+ {"setprop", {2, 2, {false, do_setprop}}},
+ {"setrlimit", {3, 3, {false, do_setrlimit}}},
+ {"start", {1, 1, {false, do_start}}},
+ {"stop", {1, 1, {false, do_stop}}},
+ {"swapon_all", {1, 1, {false, do_swapon_all}}},
+ {"symlink", {2, 2, {true, do_symlink}}},
+ {"sysclktz", {1, 1, {false, do_sysclktz}}},
+ {"trigger", {1, 1, {false, do_trigger}}},
+ {"verity_load_state", {0, 0, {false, do_verity_load_state}}},
+ {"verity_update_state", {0, 0, {false, do_verity_update_state}}},
+ {"wait", {1, 2, {true, do_wait}}},
+ {"wait_for_prop", {2, 2, {true, do_wait_for_prop}}},
+ {"write", {2, 2, {true, do_write}}},
};
// clang-format on
return builtin_functions;
diff --git a/init/builtins.h b/init/builtins.h
index f66ae19..814b2d5 100644
--- a/init/builtins.h
+++ b/init/builtins.h
@@ -22,14 +22,17 @@
#include <string>
#include <vector>
+#include "builtin_arguments.h"
#include "keyword_map.h"
#include "result.h"
namespace android {
namespace init {
-using BuiltinFunction = std::function<Result<Success>(const std::vector<std::string>&)>;
-class BuiltinFunctionMap : public KeywordMap<BuiltinFunction> {
+using BuiltinFunction = std::function<Result<Success>(const BuiltinArguments&)>;
+
+using KeywordFunctionMap = KeywordMap<std::pair<bool, BuiltinFunction>>;
+class BuiltinFunctionMap : public KeywordFunctionMap {
public:
BuiltinFunctionMap() {}
diff --git a/init/init.cpp b/init/init.cpp
index ad045b1..51a98a2 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -84,6 +84,8 @@
std::vector<std::string> late_import_paths;
+static std::vector<Subcontext>* subcontexts;
+
void DumpState() {
ServiceList::GetInstance().DumpState();
ActionManager::GetInstance().DumpState();
@@ -92,8 +94,8 @@
Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {
Parser parser;
- parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list));
- parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager));
+ parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list, subcontexts));
+ parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, subcontexts));
parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
return parser;
@@ -220,7 +222,7 @@
}
}
-static Result<Success> wait_for_coldboot_done_action(const std::vector<std::string>& args) {
+static Result<Success> wait_for_coldboot_done_action(const BuiltinArguments& args) {
Timer t;
LOG(VERBOSE) << "Waiting for " COLDBOOT_DONE "...";
@@ -241,12 +243,12 @@
return Success();
}
-static Result<Success> keychord_init_action(const std::vector<std::string>& args) {
+static Result<Success> keychord_init_action(const BuiltinArguments& args) {
keychord_init();
return Success();
}
-static Result<Success> console_init_action(const std::vector<std::string>& args) {
+static Result<Success> console_init_action(const BuiltinArguments& args) {
std::string console = GetProperty("ro.boot.console", "");
if (!console.empty()) {
default_console = "/dev/" + console;
@@ -333,13 +335,13 @@
if (qemu[0]) import_kernel_cmdline(true, import_kernel_nv);
}
-static Result<Success> property_enable_triggers_action(const std::vector<std::string>& args) {
+static Result<Success> property_enable_triggers_action(const BuiltinArguments& args) {
/* Enable property triggers. */
property_triggers_enabled = 1;
return Success();
}
-static Result<Success> queue_property_triggers_action(const std::vector<std::string>& args) {
+static Result<Success> queue_property_triggers_action(const BuiltinArguments& args) {
ActionManager::GetInstance().QueueBuiltinAction(property_enable_triggers_action, "enable_property_trigger");
ActionManager::GetInstance().QueueAllPropertyActions();
return Success();
@@ -446,6 +448,12 @@
return watchdogd_main(argc, argv);
}
+ if (argc > 1 && !strcmp(argv[1], "subcontext")) {
+ InitKernelLogging(argv);
+ const BuiltinFunctionMap function_map;
+ return SubcontextMain(argc, argv, &function_map);
+ }
+
if (REBOOT_BOOTLOADER_ON_PANIC) {
InstallRebootSignalHandlers();
}
@@ -587,6 +595,8 @@
const BuiltinFunctionMap function_map;
Action::set_function_map(&function_map);
+ subcontexts = InitializeSubcontexts();
+
ActionManager& am = ActionManager::GetInstance();
ServiceList& sm = ServiceList::GetInstance();
diff --git a/init/init_test.cpp b/init/init_test.cpp
index 27659f9..29a65ab 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -25,33 +25,12 @@
#include "import_parser.h"
#include "keyword_map.h"
#include "parser.h"
+#include "test_function_map.h"
#include "util.h"
namespace android {
namespace init {
-class TestFunctionMap : public KeywordMap<BuiltinFunction> {
- public:
- // Helper for argument-less functions
- using BuiltinFunctionNoArgs = std::function<void(void)>;
- void Add(const std::string& name, const BuiltinFunctionNoArgs function) {
- Add(name, 0, 0, [function](const std::vector<std::string>&) {
- function();
- return Success();
- });
- }
-
- void Add(const std::string& name, std::size_t min_parameters, std::size_t max_parameters,
- const BuiltinFunction function) {
- builtin_functions_[name] = make_tuple(min_parameters, max_parameters, function);
- }
-
- private:
- Map builtin_functions_ = {};
-
- const Map& map() const override { return builtin_functions_; }
-};
-
using ActionManagerCommand = std::function<void(ActionManager&)>;
void TestInit(const std::string& init_script_file, const TestFunctionMap& test_function_map,
@@ -61,7 +40,7 @@
Action::set_function_map(&test_function_map);
Parser parser;
- parser.AddSectionParser("on", std::make_unique<ActionParser>(&am));
+ parser.AddSectionParser("on", std::make_unique<ActionParser>(&am, nullptr));
parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
ASSERT_TRUE(parser.ParseConfig(init_script_file));
@@ -171,14 +150,14 @@
ASSERT_TRUE(android::base::WriteStringToFd(start_script, start.fd));
int num_executed = 0;
- auto execute_command = [&num_executed](const std::vector<std::string>& args) {
+ auto execute_command = [&num_executed](const BuiltinArguments& args) {
EXPECT_EQ(2U, args.size());
EXPECT_EQ(++num_executed, std::stoi(args[1]));
return Success();
};
TestFunctionMap test_function_map;
- test_function_map.Add("execute", 1, 1, execute_command);
+ test_function_map.Add("execute", 1, 1, false, execute_command);
ActionManagerCommand trigger_boot = [](ActionManager& am) { am.QueueEventTrigger("boot"); };
std::vector<ActionManagerCommand> commands{trigger_boot};
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 0df96bf..6321fb2 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -513,7 +513,7 @@
}
}
-static void load_properties_from_file(const char *, const char *);
+static bool load_properties_from_file(const char *, const char *);
/*
* Filter is used to decide which properties to load: NULL loads all keys,
@@ -577,17 +577,18 @@
// Filter is used to decide which properties to load: NULL loads all keys,
// "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match.
-static void load_properties_from_file(const char* filename, const char* filter) {
+static bool load_properties_from_file(const char* filename, const char* filter) {
Timer t;
auto file_contents = ReadFile(filename);
if (!file_contents) {
PLOG(WARNING) << "Couldn't load property file '" << filename
<< "': " << file_contents.error();
- return;
+ return false;
}
file_contents->push_back('\n');
load_properties(file_contents->data(), filter);
LOG(VERBOSE) << "(Loading properties from " << filename << " took " << t << ".)";
+ return true;
}
// persist.sys.usb.config values can't be combined on build-time when property
@@ -607,7 +608,13 @@
}
void property_load_boot_defaults() {
- load_properties_from_file("/default.prop", NULL);
+ if (!load_properties_from_file("/system/etc/prop.default", NULL)) {
+ // Try recovery path
+ if (!load_properties_from_file("/prop.default", NULL)) {
+ // Try legacy path
+ load_properties_from_file("/default.prop", NULL);
+ }
+ }
load_properties_from_file("/odm/default.prop", NULL);
load_properties_from_file("/vendor/default.prop", NULL);
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 18f493a..d06dcc5 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -521,8 +521,7 @@
// Queue shutdown trigger first
ActionManager::GetInstance().QueueEventTrigger("shutdown");
// Queue built-in shutdown_done
- auto shutdown_handler = [cmd, command, reboot_target,
- run_fsck](const std::vector<std::string>&) {
+ auto shutdown_handler = [cmd, command, reboot_target, run_fsck](const BuiltinArguments&) {
DoReboot(cmd, command, reboot_target, run_fsck);
return Success();
};
diff --git a/init/security.cpp b/init/security.cpp
index aac8f2e..a3494a2 100644
--- a/init/security.cpp
+++ b/init/security.cpp
@@ -43,7 +43,7 @@
// devices/configurations where these I/O operations are blocking for a long
// time. We do not reboot or halt on failures, as this is a best-effort
// attempt.
-Result<Success> MixHwrngIntoLinuxRngAction(const std::vector<std::string>& args) {
+Result<Success> MixHwrngIntoLinuxRngAction(const BuiltinArguments&) {
unique_fd hwrandom_fd(
TEMP_FAILURE_RETRY(open("/dev/hw_random", O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
if (hwrandom_fd == -1) {
@@ -147,7 +147,7 @@
// 9e08f57d684a x86: mm: support ARCH_MMAP_RND_BITS
// ec9ee4acd97c drivers: char: random: add get_random_long()
// 5ef11c35ce86 mm: ASLR: use get_random_long()
-Result<Success> SetMmapRndBitsAction(const std::vector<std::string>& args) {
+Result<Success> SetMmapRndBitsAction(const BuiltinArguments&) {
// values are arch-dependent
#if defined(USER_MODE_LINUX)
// uml does not support mmap_rnd_bits
@@ -187,7 +187,7 @@
// Set kptr_restrict to the highest available level.
//
// Aborts if unable to set this to an acceptable value.
-Result<Success> SetKptrRestrictAction(const std::vector<std::string>& args) {
+Result<Success> SetKptrRestrictAction(const BuiltinArguments&) {
std::string path = KPTR_RESTRICT_PATH;
if (!SetHighestAvailableOptionValue(path, KPTR_RESTRICT_MINVALUE, KPTR_RESTRICT_MAXVALUE)) {
diff --git a/init/security.h b/init/security.h
index 31e5790..6f6b944 100644
--- a/init/security.h
+++ b/init/security.h
@@ -20,14 +20,15 @@
#include <string>
#include <vector>
+#include "builtin_arguments.h"
#include "result.h"
namespace android {
namespace init {
-Result<Success> MixHwrngIntoLinuxRngAction(const std::vector<std::string>& args);
-Result<Success> SetMmapRndBitsAction(const std::vector<std::string>& args);
-Result<Success> SetKptrRestrictAction(const std::vector<std::string>& args);
+Result<Success> MixHwrngIntoLinuxRngAction(const BuiltinArguments&);
+Result<Success> SetMmapRndBitsAction(const BuiltinArguments&);
+Result<Success> SetKptrRestrictAction(const BuiltinArguments&);
} // namespace init
} // namespace android
diff --git a/init/service.cpp b/init/service.cpp
index 86b910a..b339bc0 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -155,13 +155,14 @@
unsigned long Service::next_start_order_ = 1;
bool Service::is_exec_service_running_ = false;
-Service::Service(const std::string& name, const std::vector<std::string>& args)
- : Service(name, 0, 0, 0, {}, 0, 0, "", args) {}
+Service::Service(const std::string& name, Subcontext* subcontext_for_restart_commands,
+ const std::vector<std::string>& args)
+ : Service(name, 0, 0, 0, {}, 0, 0, "", subcontext_for_restart_commands, args) {}
Service::Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid,
const std::vector<gid_t>& supp_gids, const CapSet& capabilities,
unsigned namespace_flags, const std::string& seclabel,
- const std::vector<std::string>& args)
+ Subcontext* subcontext_for_restart_commands, const std::vector<std::string>& args)
: name_(name),
classnames_({"default"}),
flags_(flags),
@@ -173,7 +174,7 @@
capabilities_(capabilities),
namespace_flags_(namespace_flags),
seclabel_(seclabel),
- onrestart_(false, "<Service '" + name + "' onrestart>", 0),
+ onrestart_(false, subcontext_for_restart_commands, "<Service '" + name + "' onrestart>", 0),
keychord_id_(0),
ioprio_class_(IoSchedClass_NONE),
ioprio_pri_(0),
@@ -1007,7 +1008,7 @@
}
return std::make_unique<Service>(name, flags, *uid, *gid, supp_gids, no_capabilities,
- namespace_flags, seclabel, str_args);
+ namespace_flags, seclabel, nullptr, str_args);
}
// Shutdown services in the opposite order that they were started.
@@ -1055,8 +1056,18 @@
return Error() << "ignored duplicate definition of service '" << name << "'";
}
+ Subcontext* restart_action_subcontext = nullptr;
+ if (subcontexts_) {
+ for (auto& subcontext : *subcontexts_) {
+ if (StartsWith(filename, subcontext.path_prefix().c_str())) {
+ restart_action_subcontext = &subcontext;
+ break;
+ }
+ }
+ }
+
std::vector<std::string> str_args(args.begin() + 2, args.end());
- service_ = std::make_unique<Service>(name, str_args);
+ service_ = std::make_unique<Service>(name, restart_action_subcontext, str_args);
return Success();
}
diff --git a/init/service.h b/init/service.h
index 67542ca..89dd780 100644
--- a/init/service.h
+++ b/init/service.h
@@ -33,6 +33,7 @@
#include "descriptors.h"
#include "keyword_map.h"
#include "parser.h"
+#include "subcontext.h"
#define SVC_DISABLED 0x001 // do not autostart with class
#define SVC_ONESHOT 0x002 // do not restart on exit
@@ -60,12 +61,13 @@
class Service {
public:
- Service(const std::string& name, const std::vector<std::string>& args);
+ Service(const std::string& name, Subcontext* subcontext_for_restart_commands,
+ const std::vector<std::string>& args);
Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid,
const std::vector<gid_t>& supp_gids, const CapSet& capabilities,
unsigned namespace_flags, const std::string& seclabel,
- const std::vector<std::string>& args);
+ Subcontext* subcontext_for_restart_commands, const std::vector<std::string>& args);
static std::unique_ptr<Service> MakeTemporaryOneshotService(const std::vector<std::string>& args);
@@ -237,7 +239,8 @@
class ServiceParser : public SectionParser {
public:
- ServiceParser(ServiceList* service_list) : service_list_(service_list), service_(nullptr) {}
+ ServiceParser(ServiceList* service_list, std::vector<Subcontext>* subcontexts)
+ : service_list_(service_list), subcontexts_(subcontexts), service_(nullptr) {}
Result<Success> ParseSection(std::vector<std::string>&& args, const std::string& filename,
int line) override;
Result<Success> ParseLineSection(std::vector<std::string>&& args, int line) override;
@@ -247,6 +250,7 @@
bool IsValidName(const std::string& name) const;
ServiceList* service_list_;
+ std::vector<Subcontext>* subcontexts_;
std::unique_ptr<Service> service_;
};
diff --git a/init/service_test.cpp b/init/service_test.cpp
index 98d876f..b43c2e9 100644
--- a/init/service_test.cpp
+++ b/init/service_test.cpp
@@ -37,7 +37,8 @@
}
std::vector<std::string> dummy_args{"/bin/test"};
- Service* service_in_old_memory = new (old_memory) Service("test_old_memory", dummy_args);
+ Service* service_in_old_memory =
+ new (old_memory) Service("test_old_memory", nullptr, dummy_args);
EXPECT_EQ(0U, service_in_old_memory->flags());
EXPECT_EQ(0, service_in_old_memory->pid());
@@ -56,8 +57,8 @@
old_memory[i] = 0xFF;
}
- Service* service_in_old_memory2 = new (old_memory)
- Service("test_old_memory", 0U, 0U, 0U, std::vector<gid_t>(), CapSet(), 0U, "", dummy_args);
+ Service* service_in_old_memory2 = new (old_memory) Service(
+ "test_old_memory", 0U, 0U, 0U, std::vector<gid_t>(), CapSet(), 0U, "", nullptr, dummy_args);
EXPECT_EQ(0U, service_in_old_memory2->flags());
EXPECT_EQ(0, service_in_old_memory2->pid());
diff --git a/init/sigchld_handler.cpp b/init/sigchld_handler.cpp
index fa67199..072a0fb 100644
--- a/init/sigchld_handler.cpp
+++ b/init/sigchld_handler.cpp
@@ -60,22 +60,28 @@
// want the pid to remain valid throughout that (and potentially future) usages.
auto reaper = make_scope_guard([pid] { TEMP_FAILURE_RETRY(waitpid(pid, nullptr, WNOHANG)); });
- if (PropertyChildReap(pid)) return true;
-
- Service* service = ServiceList::GetInstance().FindService(pid, &Service::pid);
-
std::string name;
std::string wait_string;
- if (service) {
- name = StringPrintf("Service '%s' (pid %d)", service->name().c_str(), pid);
- if (service->flags() & SVC_EXEC) {
- auto exec_duration = boot_clock::now() - service->time_started();
- auto exec_duration_ms =
- std::chrono::duration_cast<std::chrono::milliseconds>(exec_duration).count();
- wait_string = StringPrintf(" waiting took %f seconds", exec_duration_ms / 1000.0f);
- }
+ Service* service = nullptr;
+
+ if (PropertyChildReap(pid)) {
+ name = "Async property child";
+ } else if (SubcontextChildReap(pid)) {
+ name = "Subcontext";
} else {
- name = StringPrintf("Untracked pid %d", pid);
+ service = ServiceList::GetInstance().FindService(pid, &Service::pid);
+
+ if (service) {
+ name = StringPrintf("Service '%s' (pid %d)", service->name().c_str(), pid);
+ if (service->flags() & SVC_EXEC) {
+ auto exec_duration = boot_clock::now() - service->time_started();
+ auto exec_duration_ms =
+ std::chrono::duration_cast<std::chrono::milliseconds>(exec_duration).count();
+ wait_string = StringPrintf(" waiting took %f seconds", exec_duration_ms / 1000.0f);
+ }
+ } else {
+ name = StringPrintf("Untracked pid %d", pid);
+ }
}
auto status = siginfo.si_status;
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
new file mode 100644
index 0000000..85da237
--- /dev/null
+++ b/init/subcontext.cpp
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2017 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 "subcontext.h"
+
+#include <fcntl.h>
+#include <poll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <selinux/android.h>
+
+#include "action.h"
+#include "system/core/init/subcontext.pb.h"
+#include "util.h"
+
+using android::base::GetExecutablePath;
+using android::base::Join;
+using android::base::Socketpair;
+using android::base::Split;
+using android::base::StartsWith;
+using android::base::unique_fd;
+
+namespace android {
+namespace init {
+
+const std::string kInitContext = "u:r:init:s0";
+const std::string kVendorContext = "u:r:vendor_init:s0";
+
+namespace {
+
+constexpr size_t kBufferSize = 4096;
+
+Result<std::string> ReadMessage(int socket) {
+ char buffer[kBufferSize] = {};
+ auto result = TEMP_FAILURE_RETRY(recv(socket, buffer, sizeof(buffer), 0));
+ if (result <= 0) {
+ return ErrnoError();
+ }
+ return std::string(buffer, result);
+}
+
+template <typename T>
+Result<Success> SendMessage(int socket, const T& message) {
+ std::string message_string;
+ if (!message.SerializeToString(&message_string)) {
+ return Error() << "Unable to serialize message";
+ }
+
+ if (message_string.size() > kBufferSize) {
+ return Error() << "Serialized message too long to send";
+ }
+
+ if (auto result =
+ TEMP_FAILURE_RETRY(send(socket, message_string.c_str(), message_string.size(), 0));
+ result != static_cast<long>(message_string.size())) {
+ return ErrnoError() << "send() failed to send message contents";
+ }
+ return Success();
+}
+
+class SubcontextProcess {
+ public:
+ SubcontextProcess(const KeywordFunctionMap* function_map, std::string context, int init_fd)
+ : function_map_(function_map), context_(std::move(context)), init_fd_(init_fd){};
+ void MainLoop();
+
+ private:
+ void RunCommand(const SubcontextCommand::ExecuteCommand& execute_command,
+ SubcontextReply::ResultMessage* result_message) const;
+
+ const KeywordFunctionMap* function_map_;
+ const std::string context_;
+ const int init_fd_;
+};
+
+void SubcontextProcess::RunCommand(const SubcontextCommand::ExecuteCommand& execute_command,
+ SubcontextReply::ResultMessage* result_message) const {
+ // Need to use ArraySplice instead of this code.
+ auto args = std::vector<std::string>();
+ for (const auto& string : execute_command.args()) {
+ args.emplace_back(string);
+ }
+
+ auto map_result = function_map_->FindFunction(args);
+ Result<Success> result;
+ if (!map_result) {
+ result = Error() << "Cannot find command: " << map_result.error();
+ } else {
+ result = RunBuiltinFunction(map_result->second, args, context_);
+ }
+
+ if (result) {
+ result_message->set_success(true);
+ } else {
+ result_message->set_success(false);
+ result_message->set_error_string(result.error_string());
+ result_message->set_error_errno(result.error_errno());
+ }
+}
+
+void SubcontextProcess::MainLoop() {
+ pollfd ufd[1];
+ ufd[0].events = POLLIN;
+ ufd[0].fd = init_fd_;
+
+ while (true) {
+ ufd[0].revents = 0;
+ int nr = TEMP_FAILURE_RETRY(poll(ufd, arraysize(ufd), -1));
+ if (nr == 0) continue;
+ if (nr < 0) {
+ PLOG(FATAL) << "poll() of subcontext socket failed, continuing";
+ }
+
+ auto init_message = ReadMessage(init_fd_);
+ if (!init_message) {
+ LOG(FATAL) << "Could not read message from init: " << init_message.error();
+ }
+
+ auto subcontext_command = SubcontextCommand();
+ if (!subcontext_command.ParseFromString(*init_message)) {
+ LOG(FATAL) << "Unable to parse message from init";
+ }
+
+ auto reply = SubcontextReply();
+ switch (subcontext_command.command_case()) {
+ case SubcontextCommand::kExecuteCommand: {
+ RunCommand(subcontext_command.execute_command(), reply.mutable_result());
+ break;
+ }
+ default:
+ LOG(FATAL) << "Unknown message type from init: "
+ << subcontext_command.command_case();
+ }
+
+ if (auto result = SendMessage(init_fd_, reply); !result) {
+ LOG(FATAL) << "Failed to send message to init: " << result.error();
+ }
+ }
+}
+
+} // namespace
+
+int SubcontextMain(int argc, char** argv, const KeywordFunctionMap* function_map) {
+ if (argc < 4) LOG(FATAL) << "Fewer than 4 args specified to subcontext (" << argc << ")";
+
+ auto context = std::string(argv[2]);
+ auto init_fd = std::atoi(argv[3]);
+
+ auto subcontext_process = SubcontextProcess(function_map, context, init_fd);
+ subcontext_process.MainLoop();
+ return 0;
+}
+
+void Subcontext::Fork() {
+ unique_fd subcontext_socket;
+ if (!Socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, &socket_, &subcontext_socket)) {
+ LOG(FATAL) << "Could not create socket pair to communicate to subcontext";
+ return;
+ }
+
+ auto result = fork();
+
+ if (result == -1) {
+ LOG(FATAL) << "Could not fork subcontext";
+ } else if (result == 0) {
+ socket_.reset();
+
+ // We explicitly do not use O_CLOEXEC here, such that we can reference this FD by number
+ // in the subcontext process after we exec.
+ int child_fd = dup(subcontext_socket);
+ if (child_fd < 0) {
+ PLOG(FATAL) << "Could not dup child_fd";
+ }
+
+ if (setexeccon(context_.c_str()) < 0) {
+ PLOG(FATAL) << "Could not set execcon for '" << context_ << "'";
+ }
+
+ auto init_path = GetExecutablePath();
+ auto child_fd_string = std::to_string(child_fd);
+ const char* args[] = {init_path.c_str(), "subcontext", context_.c_str(),
+ child_fd_string.c_str(), nullptr};
+ execv(init_path.data(), const_cast<char**>(args));
+
+ PLOG(FATAL) << "Could not execv subcontext init";
+ } else {
+ subcontext_socket.reset();
+ pid_ = result;
+ LOG(INFO) << "Forked subcontext for '" << context_ << "' with pid " << pid_;
+ }
+}
+
+void Subcontext::Restart() {
+ LOG(ERROR) << "Restarting subcontext '" << context_ << "'";
+ if (pid_) {
+ kill(pid_, SIGKILL);
+ }
+ pid_ = 0;
+ socket_.reset();
+ Fork();
+}
+
+Result<Success> Subcontext::Execute(const std::vector<std::string>& args) {
+ auto subcontext_command = SubcontextCommand();
+ std::copy(
+ args.begin(), args.end(),
+ RepeatedPtrFieldBackInserter(subcontext_command.mutable_execute_command()->mutable_args()));
+
+ if (auto result = SendMessage(socket_, subcontext_command); !result) {
+ Restart();
+ return ErrnoError() << "Failed to send message to subcontext";
+ }
+
+ auto subcontext_message = ReadMessage(socket_);
+ if (!subcontext_message) {
+ Restart();
+ return Error() << "Failed to receive result from subcontext: " << subcontext_message.error();
+ }
+
+ auto subcontext_reply = SubcontextReply();
+ if (!subcontext_reply.ParseFromString(*subcontext_message)) {
+ Restart();
+ return Error() << "Unable to parse message from subcontext";
+ }
+
+ switch (subcontext_reply.reply_case()) {
+ case SubcontextReply::kResult: {
+ auto result = subcontext_reply.result();
+ if (result.success()) {
+ return Success();
+ } else {
+ return ResultError(result.error_string(), result.error_errno());
+ }
+ }
+ default:
+ return Error() << "Unknown message type from subcontext: "
+ << subcontext_reply.reply_case();
+ }
+}
+
+static std::vector<Subcontext> subcontexts;
+
+std::vector<Subcontext>* InitializeSubcontexts() {
+ static const char* const paths_and_secontexts[][2] = {
+ // TODO: Enable this once the SEPolicy is in place.
+ // {"/vendor", kVendorContext.c_str()},
+ };
+ for (const auto& [path_prefix, secontext] : paths_and_secontexts) {
+ subcontexts.emplace_back(path_prefix, secontext);
+ }
+ return &subcontexts;
+}
+
+bool SubcontextChildReap(pid_t pid) {
+ for (auto& subcontext : subcontexts) {
+ if (subcontext.pid() == pid) {
+ subcontext.Restart();
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace init
+} // namespace android
diff --git a/init/subcontext.h b/init/subcontext.h
new file mode 100644
index 0000000..ac77e08
--- /dev/null
+++ b/init/subcontext.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 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_SUBCONTEXT_H
+#define _INIT_SUBCONTEXT_H
+
+#include <signal.h>
+
+#include <string>
+#include <vector>
+
+#include <android-base/unique_fd.h>
+
+#include "builtins.h"
+
+namespace android {
+namespace init {
+
+extern const std::string kInitContext;
+extern const std::string kVendorContext;
+
+class Subcontext {
+ public:
+ Subcontext(std::string path_prefix, std::string context)
+ : path_prefix_(path_prefix), context_(std::move(context)) {
+ Fork();
+ }
+
+ Result<Success> Execute(const std::vector<std::string>& command);
+ void Restart();
+
+ const std::string& path_prefix() const { return path_prefix_; }
+ const std::string& context() const { return context_; }
+ pid_t pid() const { return pid_; }
+
+ private:
+ void Fork();
+
+ std::string path_prefix_;
+ std::string context_;
+ pid_t pid_;
+ android::base::unique_fd socket_;
+};
+
+// For testing, to kill the subcontext after the test has completed.
+class SubcontextKiller {
+ public:
+ SubcontextKiller(const Subcontext& subcontext) : subcontext_(subcontext) {}
+ ~SubcontextKiller() {
+ if (subcontext_.pid() > 0) {
+ kill(subcontext_.pid(), SIGTERM);
+ kill(subcontext_.pid(), SIGKILL);
+ }
+ }
+
+ private:
+ const Subcontext& subcontext_;
+};
+
+int SubcontextMain(int argc, char** argv, const KeywordFunctionMap* function_map);
+std::vector<Subcontext>* InitializeSubcontexts();
+bool SubcontextChildReap(pid_t pid);
+
+} // namespace init
+} // namespace android
+
+#endif
diff --git a/init/subcontext.proto b/init/subcontext.proto
new file mode 100644
index 0000000..0d89734
--- /dev/null
+++ b/init/subcontext.proto
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+message SubcontextCommand {
+ message ExecuteCommand { repeated string args = 1; }
+ oneof command { ExecuteCommand execute_command = 1; }
+}
+
+message SubcontextReply {
+ message ResultMessage {
+ optional bool success = 1;
+ optional string error_string = 2;
+ optional int32 error_errno = 3;
+ }
+
+ oneof reply { ResultMessage result = 1; }
+}
\ No newline at end of file
diff --git a/init/subcontext_benchmark.cpp b/init/subcontext_benchmark.cpp
new file mode 100644
index 0000000..a62b959
--- /dev/null
+++ b/init/subcontext_benchmark.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2017 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 "subcontext.h"
+
+#include <benchmark/benchmark.h>
+
+#include "test_function_map.h"
+
+namespace android {
+namespace init {
+
+static void BenchmarkSuccess(benchmark::State& state) {
+ auto subcontext = Subcontext("path", kVendorContext);
+ auto subcontext_killer = SubcontextKiller(subcontext);
+
+ while (state.KeepRunning()) {
+ subcontext.Execute(std::vector<std::string>{"return_success"});
+ }
+}
+
+BENCHMARK(BenchmarkSuccess);
+
+TestFunctionMap BuildTestFunctionMap() {
+ TestFunctionMap test_function_map;
+ test_function_map.Add("return_success", 0, 0, true,
+ [](const BuiltinArguments& args) { return Success(); });
+
+ return test_function_map;
+}
+
+} // namespace init
+} // namespace android
+
+int main(int argc, char** argv) {
+ if (argc > 1 && !strcmp(basename(argv[1]), "subcontext")) {
+ auto test_function_map = android::init::BuildTestFunctionMap();
+ return android::init::SubcontextMain(argc, argv, &test_function_map);
+ }
+
+ ::benchmark::Initialize(&argc, argv);
+ if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1;
+ ::benchmark::RunSpecifiedBenchmarks();
+}
diff --git a/init/subcontext_test.cpp b/init/subcontext_test.cpp
new file mode 100644
index 0000000..60b45b9
--- /dev/null
+++ b/init/subcontext_test.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2017 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 "subcontext.h"
+
+#include <unistd.h>
+
+#include <chrono>
+
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <gtest/gtest.h>
+
+#include "builtin_arguments.h"
+#include "test_function_map.h"
+
+using namespace std::literals;
+
+using android::base::GetProperty;
+using android::base::Join;
+using android::base::SetProperty;
+using android::base::Split;
+using android::base::WaitForProperty;
+
+namespace android {
+namespace init {
+
+TEST(subcontext, CheckDifferentPid) {
+ auto subcontext = Subcontext("path", kVendorContext);
+ auto subcontext_killer = SubcontextKiller(subcontext);
+
+ auto result = subcontext.Execute(std::vector<std::string>{"return_pids_as_error"});
+ ASSERT_FALSE(result);
+
+ auto pids = Split(result.error_string(), " ");
+ ASSERT_EQ(2U, pids.size());
+ auto our_pid = std::to_string(getpid());
+ EXPECT_NE(our_pid, pids[0]);
+ EXPECT_EQ(our_pid, pids[1]);
+}
+
+TEST(subcontext, SetProp) {
+ auto subcontext = Subcontext("path", kVendorContext);
+ auto subcontext_killer = SubcontextKiller(subcontext);
+
+ SetProperty("init.test.subcontext", "fail");
+ WaitForProperty("init.test.subcontext", "fail");
+
+ auto args = std::vector<std::string>{
+ "setprop",
+ "init.test.subcontext",
+ "success",
+ };
+ auto result = subcontext.Execute(args);
+ ASSERT_TRUE(result) << result.error();
+
+ EXPECT_TRUE(WaitForProperty("init.test.subcontext", "success", 10s));
+}
+
+TEST(subcontext, MultipleCommands) {
+ auto subcontext = Subcontext("path", kVendorContext);
+ auto subcontext_killer = SubcontextKiller(subcontext);
+
+ auto first_pid = subcontext.pid();
+
+ auto expected_words = std::vector<std::string>{
+ "this",
+ "is",
+ "a",
+ "test",
+ };
+
+ for (const auto& word : expected_words) {
+ auto args = std::vector<std::string>{
+ "add_word",
+ word,
+ };
+ auto result = subcontext.Execute(args);
+ ASSERT_TRUE(result) << result.error();
+ }
+
+ auto result = subcontext.Execute(std::vector<std::string>{"return_words_as_error"});
+ ASSERT_FALSE(result);
+ EXPECT_EQ(Join(expected_words, " "), result.error_string());
+ EXPECT_EQ(first_pid, subcontext.pid());
+}
+
+TEST(subcontext, RecoverAfterAbort) {
+ auto subcontext = Subcontext("path", kVendorContext);
+ auto subcontext_killer = SubcontextKiller(subcontext);
+
+ auto first_pid = subcontext.pid();
+
+ auto result = subcontext.Execute(std::vector<std::string>{"cause_log_fatal"});
+ ASSERT_FALSE(result);
+
+ auto result2 = subcontext.Execute(std::vector<std::string>{"generate_sane_error"});
+ ASSERT_FALSE(result2);
+ EXPECT_EQ("Sane error!", result2.error_string());
+ EXPECT_NE(subcontext.pid(), first_pid);
+}
+
+TEST(subcontext, ContextString) {
+ auto subcontext = Subcontext("path", kVendorContext);
+ auto subcontext_killer = SubcontextKiller(subcontext);
+
+ auto result = subcontext.Execute(std::vector<std::string>{"return_context_as_error"});
+ ASSERT_FALSE(result);
+ ASSERT_EQ(kVendorContext, result.error_string());
+}
+
+TestFunctionMap BuildTestFunctionMap() {
+ TestFunctionMap test_function_map;
+ // For CheckDifferentPid
+ test_function_map.Add("return_pids_as_error", 0, 0, true,
+ [](const BuiltinArguments& args) -> Result<Success> {
+ return Error() << getpid() << " " << getppid();
+ });
+
+ // For SetProp
+ test_function_map.Add("setprop", 2, 2, true, [](const BuiltinArguments& args) {
+ android::base::SetProperty(args[1], args[2]);
+ return Success();
+ });
+
+ // For MultipleCommands
+ // Using a shared_ptr to extend lifetime of words to both lambdas
+ auto words = std::make_shared<std::vector<std::string>>();
+ test_function_map.Add("add_word", 1, 1, true, [words](const BuiltinArguments& args) {
+ words->emplace_back(args[1]);
+ return Success();
+ });
+ test_function_map.Add("return_words_as_error", 0, 0, true,
+ [words](const BuiltinArguments& args) -> Result<Success> {
+ return Error() << Join(*words, " ");
+ });
+
+ // For RecoverAfterAbort
+ test_function_map.Add("cause_log_fatal", 0, 0, true,
+ [](const BuiltinArguments& args) -> Result<Success> {
+ return Error() << std::string(4097, 'f');
+ });
+ test_function_map.Add(
+ "generate_sane_error", 0, 0, true,
+ [](const BuiltinArguments& args) -> Result<Success> { return Error() << "Sane error!"; });
+
+ // For ContextString
+ test_function_map.Add(
+ "return_context_as_error", 0, 0, true,
+ [](const BuiltinArguments& args) -> Result<Success> { return Error() << args.context; });
+
+ return test_function_map;
+}
+
+} // namespace init
+} // namespace android
+
+int main(int argc, char** argv) {
+ if (argc > 1 && !strcmp(basename(argv[1]), "subcontext")) {
+ auto test_function_map = android::init::BuildTestFunctionMap();
+ return android::init::SubcontextMain(argc, argv, &test_function_map);
+ }
+
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/init/test_function_map.h b/init/test_function_map.h
new file mode 100644
index 0000000..583df1a
--- /dev/null
+++ b/init/test_function_map.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2017 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_TEST_FUNCTION_MAP_H
+#define _INIT_TEST_FUNCTION_MAP_H
+
+#include <string>
+#include <vector>
+
+#include "builtin_arguments.h"
+#include "keyword_map.h"
+
+namespace android {
+namespace init {
+
+class TestFunctionMap : public KeywordFunctionMap {
+ public:
+ // Helper for argument-less functions
+ using BuiltinFunctionNoArgs = std::function<void(void)>;
+ void Add(const std::string& name, const BuiltinFunctionNoArgs function) {
+ Add(name, 0, 0, false, [function](const BuiltinArguments&) {
+ function();
+ return Success();
+ });
+ }
+
+ void Add(const std::string& name, std::size_t min_parameters, std::size_t max_parameters,
+ bool run_in_subcontext, const BuiltinFunction function) {
+ builtin_functions_[name] =
+ make_tuple(min_parameters, max_parameters, make_pair(run_in_subcontext, function));
+ }
+
+ private:
+ Map builtin_functions_ = {};
+
+ const Map& map() const override { return builtin_functions_; }
+};
+
+} // namespace init
+} // namespace android
+
+#endif
diff --git a/libappfuse/FuseBridgeLoop.cc b/libappfuse/FuseBridgeLoop.cc
index 3f47066..0792307 100644
--- a/libappfuse/FuseBridgeLoop.cc
+++ b/libappfuse/FuseBridgeLoop.cc
@@ -57,6 +57,12 @@
return;
}
}
+
+void LogResponseError(const std::string& message, const FuseResponse& response) {
+ LOG(ERROR) << message << ": header.len=" << response.header.len
+ << " header.error=" << response.header.error
+ << " header.unique=" << response.header.unique;
+}
}
class FuseBridgeEntry {
@@ -135,6 +141,7 @@
}
if (!buffer_.response.Write(device_fd_)) {
+ LogResponseError("Failed to write a reply from proxy to device", buffer_.response);
return FuseBridgeState::kClosing;
}
@@ -200,6 +207,7 @@
}
if (!buffer_.response.Write(device_fd_)) {
+ LogResponseError("Failed to write a response to device", buffer_.response);
return FuseBridgeState::kClosing;
}
@@ -215,6 +223,11 @@
case ResultOrAgain::kSuccess:
return FuseBridgeState::kWaitToReadEither;
case ResultOrAgain::kFailure:
+ LOG(ERROR) << "Failed to write a request to proxy:"
+ << " header.len=" << buffer_.request.header.len
+ << " header.opcode=" << buffer_.request.header.opcode
+ << " header.unique=" << buffer_.request.header.unique
+ << " header.nodeid=" << buffer_.request.header.nodeid;
return FuseBridgeState::kClosing;
case ResultOrAgain::kAgain:
return FuseBridgeState::kWaitToWriteProxy;
diff --git a/libappfuse/FuseBuffer.cc b/libappfuse/FuseBuffer.cc
index 653e96b..1eab46c 100644
--- a/libappfuse/FuseBuffer.cc
+++ b/libappfuse/FuseBuffer.cc
@@ -115,7 +115,10 @@
case EAGAIN:
return ResultOrAgain::kAgain;
default:
- PLOG(ERROR) << "Failed to write a FUSE message";
+ PLOG(ERROR) << "Failed to write a FUSE message: "
+ << "fd=" << fd << " "
+ << "sockflag=" << sockflag << " "
+ << "data=" << data;
return ResultOrAgain::kFailure;
}
}
@@ -248,7 +251,9 @@
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;
+ // Add volatile as a workaround for compiler issue which removes the temporary
+ // variable.
+ const volatile uint64_t unique = request.header.unique;
response.Reset(0, -ENOSYS, unique);
}
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index bab095e..1d3e5ea 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -133,7 +133,8 @@
{ 00640, AID_ROOT, AID_SHELL, 0, "data/nativetest64/tests.txt" },
{ 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest/*" },
{ 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest64/*" },
- { 00600, AID_ROOT, AID_ROOT, 0, "default.prop" },
+ { 00600, AID_ROOT, AID_ROOT, 0, "default.prop" }, // legacy
+ { 00600, AID_ROOT, AID_ROOT, 0, "system/etc/prop.default" },
{ 00600, AID_ROOT, AID_ROOT, 0, "odm/build.prop" },
{ 00600, AID_ROOT, AID_ROOT, 0, "odm/default.prop" },
{ 00444, AID_ROOT, AID_ROOT, 0, odm_conf_dir + 1 },
diff --git a/libcutils/include/cutils/native_handle.h b/libcutils/include/cutils/native_handle.h
index 55754b5..10f5bc0 100644
--- a/libcutils/include/cutils/native_handle.h
+++ b/libcutils/include/cutils/native_handle.h
@@ -43,6 +43,8 @@
#endif
} native_handle_t;
+typedef const native_handle_t* buffer_handle_t;
+
/*
* native_handle_close
*
diff --git a/libcutils/include/cutils/sched_policy.h b/libcutils/include/cutils/sched_policy.h
index cf8f5c3..4c1113b 100644
--- a/libcutils/include/cutils/sched_policy.h
+++ b/libcutils/include/cutils/sched_policy.h
@@ -47,6 +47,7 @@
SP_AUDIO_APP = 3,
SP_AUDIO_SYS = 4,
SP_TOP_APP = 5,
+ SP_RT_APP = 6,
SP_CNT,
SP_MAX = SP_CNT - 1,
SP_SYSTEM_DEFAULT = SP_FOREGROUND,
diff --git a/libcutils/sched_policy.cpp b/libcutils/sched_policy.cpp
index f733e90..b00fa85 100644
--- a/libcutils/sched_policy.cpp
+++ b/libcutils/sched_policy.cpp
@@ -63,6 +63,7 @@
static int bg_schedboost_fd = -1;
static int fg_schedboost_fd = -1;
static int ta_schedboost_fd = -1;
+static int rt_schedboost_fd = -1;
/* Add tid to the scheduling group defined by the policy */
static int add_tid_to_cgroup(int tid, int fd)
@@ -159,6 +160,8 @@
fg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
filename = "/dev/stune/background/tasks";
bg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
+ filename = "/dev/stune/rt/tasks";
+ rt_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
}
}
}
@@ -394,6 +397,9 @@
case SP_SYSTEM:
SLOGD("/// tid %d (%s)", tid, thread_name);
break;
+ case SP_RT_APP:
+ SLOGD("RT tid %d (%s)", tid, thread_name);
+ break;
default:
SLOGD("??? tid %d (%s)", tid, thread_name);
break;
@@ -414,6 +420,9 @@
case SP_TOP_APP:
boost_fd = ta_schedboost_fd;
break;
+ case SP_RT_APP:
+ boost_fd = rt_schedboost_fd;
+ break;
default:
boost_fd = -1;
break;
@@ -458,6 +467,7 @@
[SP_AUDIO_APP] = "aa",
[SP_AUDIO_SYS] = "as",
[SP_TOP_APP] = "ta",
+ [SP_RT_APP] = "rt",
};
if ((policy < SP_CNT) && (strings[policy] != NULL))
return strings[policy];
diff --git a/liblog/Android.bp b/liblog/Android.bp
index d5bb29e..6584c95 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -42,24 +42,6 @@
"logd_writer.c",
]
-cc_library_headers {
- name: "liblog_headers",
- host_supported: true,
- vendor_available: true,
- export_include_dirs: ["include"],
- target: {
- windows: {
- enabled: true,
- },
- linux_bionic: {
- enabled: true,
- },
- vendor: {
- export_include_dirs: ["include_vndk"],
- },
- },
-}
-
// Shared and static library for host and device
// ========================================================
cc_library {
@@ -96,8 +78,7 @@
},
},
- header_libs: ["liblog_headers"],
- export_header_lib_headers: ["liblog_headers"],
+ export_include_dirs: ["include"],
cflags: [
"-Werror",
@@ -116,7 +97,7 @@
}
ndk_headers {
- name: "liblog_ndk_headers",
+ name: "liblog_headers",
from: "include/android",
to: "android",
srcs: ["include/android/log.h"],
diff --git a/libsuspend/autosuspend_wakeup_count.c b/libsuspend/autosuspend_wakeup_count.c
index 4dedf7f..2da204a 100644
--- a/libsuspend/autosuspend_wakeup_count.c
+++ b/libsuspend/autosuspend_wakeup_count.c
@@ -24,6 +24,7 @@
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
+#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
@@ -35,12 +36,24 @@
#define SYS_POWER_STATE "/sys/power/state"
#define SYS_POWER_WAKEUP_COUNT "/sys/power/wakeup_count"
+#define BASE_SLEEP_TIME 100000
+
static int state_fd;
static int wakeup_count_fd;
static pthread_t suspend_thread;
static sem_t suspend_lockout;
static const char *sleep_state = "mem";
static void (*wakeup_func)(bool success) = NULL;
+static int sleep_time = BASE_SLEEP_TIME;
+
+static void update_sleep_time(bool success) {
+ if (success) {
+ sleep_time = BASE_SLEEP_TIME;
+ return;
+ }
+ // double sleep time after each failure up to one minute
+ sleep_time = MIN(sleep_time * 2, 60000000);
+}
static void *suspend_thread_func(void *arg __attribute__((unused)))
{
@@ -48,10 +61,12 @@
char wakeup_count[20];
int wakeup_count_len;
int ret;
- bool success;
+ bool success = true;
while (1) {
- usleep(100000);
+ update_sleep_time(success);
+ usleep(sleep_time);
+ success = false;
ALOGV("%s: read wakeup_count\n", __func__);
lseek(wakeup_count_fd, 0, SEEK_SET);
wakeup_count_len = TEMP_FAILURE_RETRY(read(wakeup_count_fd, wakeup_count,
@@ -75,7 +90,6 @@
continue;
}
- success = true;
ALOGV("%s: write %*s to wakeup_count\n", __func__, wakeup_count_len, wakeup_count);
ret = TEMP_FAILURE_RETRY(write(wakeup_count_fd, wakeup_count, wakeup_count_len));
if (ret < 0) {
@@ -84,8 +98,8 @@
} else {
ALOGV("%s: write %s to %s\n", __func__, sleep_state, SYS_POWER_STATE);
ret = TEMP_FAILURE_RETRY(write(state_fd, sleep_state, strlen(sleep_state)));
- if (ret < 0) {
- success = false;
+ if (ret >= 0) {
+ success = true;
}
void (*func)(bool success) = wakeup_func;
if (func != NULL) {
diff --git a/libsystem/include/system/qemu_pipe.h b/libsystem/include/system/qemu_pipe.h
deleted file mode 100644
index af25079..0000000
--- a/libsystem/include/system/qemu_pipe.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2011 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 ANDROID_INCLUDE_SYSTEM_QEMU_PIPE_H
-#define ANDROID_INCLUDE_SYSTEM_QEMU_PIPE_H
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <errno.h>
-
-// Define QEMU_PIPE_DEBUG if you want to print error messages when an error
-// occurs during pipe operations. The macro should simply take a printf-style
-// formatting string followed by optional arguments.
-#ifndef QEMU_PIPE_DEBUG
-# define QEMU_PIPE_DEBUG(...) (void)0
-#endif
-
-// Try to open a new Qemu fast-pipe. This function returns a file descriptor
-// that can be used to communicate with a named service managed by the
-// emulator.
-//
-// This file descriptor can be used as a standard pipe/socket descriptor.
-//
-// 'pipeName' is the name of the emulator service you want to connect to,
-// and must begin with 'pipe:' (e.g. 'pipe:camera' or 'pipe:opengles').
-//
-// On success, return a valid file descriptor, or -1/errno on failure. E.g.:
-//
-// EINVAL -> unknown/unsupported pipeName
-// ENOSYS -> fast pipes not available in this system.
-//
-// ENOSYS should never happen, except if you're trying to run within a
-// misconfigured emulator.
-//
-// You should be able to open several pipes to the same pipe service,
-// except for a few special cases (e.g. GSM modem), where EBUSY will be
-// returned if more than one client tries to connect to it.
-static __inline__ int qemu_pipe_open(const char* pipeName) {
- // Sanity check.
- if (!pipeName || memcmp(pipeName, "pipe:", 5) != 0) {
- errno = EINVAL;
- return -1;
- }
-
- int fd = TEMP_FAILURE_RETRY(open("/dev/qemu_pipe", O_RDWR));
- if (fd < 0) {
- QEMU_PIPE_DEBUG("%s: Could not open /dev/qemu_pipe: %s", __FUNCTION__,
- strerror(errno));
- return -1;
- }
-
- // Write the pipe name, *including* the trailing zero which is necessary.
- size_t pipeNameLen = strlen(pipeName);
- ssize_t ret = TEMP_FAILURE_RETRY(write(fd, pipeName, pipeNameLen + 1U));
- if (ret != (ssize_t)pipeNameLen + 1) {
- QEMU_PIPE_DEBUG("%s: Could not connect to %s pipe service: %s",
- __FUNCTION__, pipeName, strerror(errno));
- if (ret == 0) {
- errno = ECONNRESET;
- } else if (ret > 0) {
- errno = EINVAL;
- }
- return -1;
- }
- return fd;
-}
-
-// Send a framed message |buff| of |len| bytes through the |fd| descriptor.
-// This really adds a 4-hexchar prefix describing the payload size.
-// Returns 0 on success, and -1 on error.
-static int __inline__ qemu_pipe_frame_send(int fd,
- const void* buff,
- size_t len) {
- char header[5];
- snprintf(header, sizeof(header), "%04zx", len);
- ssize_t ret = TEMP_FAILURE_RETRY(write(fd, header, 4));
- if (ret != 4) {
- QEMU_PIPE_DEBUG("Can't write qemud frame header: %s", strerror(errno));
- return -1;
- }
- ret = TEMP_FAILURE_RETRY(write(fd, buff, len));
- if (ret != (ssize_t)len) {
- QEMU_PIPE_DEBUG("Can't write qemud frame payload: %s", strerror(errno));
- return -1;
- }
- return 0;
-}
-
-// Read a frame message from |fd|, and store it into |buff| of |len| bytes.
-// If the framed message is larger than |len|, then this returns -1 and the
-// content is lost. Otherwise, this returns the size of the message. NOTE:
-// empty messages are possible in a framed wire protocol and do not mean
-// end-of-stream.
-static int __inline__ qemu_pipe_frame_recv(int fd, void* buff, size_t len) {
- char header[5];
- ssize_t ret = TEMP_FAILURE_RETRY(read(fd, header, 4));
- if (ret != 4) {
- QEMU_PIPE_DEBUG("Can't read qemud frame header: %s", strerror(errno));
- return -1;
- }
- header[4] = '\0';
- size_t size;
- if (sscanf(header, "%04zx", &size) != 1) {
- QEMU_PIPE_DEBUG("Malformed qemud frame header: [%.*s]", 4, header);
- return -1;
- }
- if (size > len) {
- QEMU_PIPE_DEBUG("Oversized qemud frame (% bytes, expected <= %)", size,
- len);
- return -1;
- }
- ret = TEMP_FAILURE_RETRY(read(fd, buff, size));
- if (ret != (ssize_t)size) {
- QEMU_PIPE_DEBUG("Could not read qemud frame payload: %s",
- strerror(errno));
- return -1;
- }
- return size;
-}
-
-#endif /* ANDROID_INCLUDE_HARDWARE_QEMUD_PIPE_H */
diff --git a/libsystem/include/system/window-deprecated.h b/libsystem/include/system/window-deprecated.h
deleted file mode 100644
index e836aea..0000000
--- a/libsystem/include/system/window-deprecated.h
+++ /dev/null
@@ -1,1114 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/**************************************************************************************************
- **************************************************************************************************
- **** ****
- **** DEPRECATED ****
- **** ****
- **** THIS FILE EXISTS ONLY FOR BACKWARD SOURCE COMPATIBILITY. ****
- **** ****
- **** DO NOT ADD TO THIS FILE. ****
- **** ****
- **** Driver implementors (vendors) should use vndk/window.h ****
- **** (frameworks/native/libs/nativewindow/include/vndk/window.h) ****
- **** ****
- **** Internal definition can be found here: ****
- **** frameworks/native/libs/nativewindow/include/system/window.h ****
- **** ****
- **************************************************************************************************
- **************************************************************************************************/
-
-#pragma once
-
-#include <cutils/native_handle.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/cdefs.h>
-#include <system/graphics.h>
-#include <unistd.h>
-#include <stdbool.h>
-
-#ifndef __UNUSED
-#define __UNUSED __attribute__((__unused__))
-#endif
-#ifndef __deprecated
-#define __deprecated __attribute__((__deprecated__))
-#endif
-
-__BEGIN_DECLS
-
-/*****************************************************************************/
-
-#ifdef __cplusplus
-#define ANDROID_NATIVE_UNSIGNED_CAST(x) static_cast<unsigned int>(x)
-#else
-#define ANDROID_NATIVE_UNSIGNED_CAST(x) ((unsigned int)(x))
-#endif
-
-#define ANDROID_NATIVE_MAKE_CONSTANT(a,b,c,d) \
- ((ANDROID_NATIVE_UNSIGNED_CAST(a) << 24) | \
- (ANDROID_NATIVE_UNSIGNED_CAST(b) << 16) | \
- (ANDROID_NATIVE_UNSIGNED_CAST(c) << 8) | \
- (ANDROID_NATIVE_UNSIGNED_CAST(d)))
-
-#define ANDROID_NATIVE_WINDOW_MAGIC \
- ANDROID_NATIVE_MAKE_CONSTANT('_','w','n','d')
-
-#define ANDROID_NATIVE_BUFFER_MAGIC \
- ANDROID_NATIVE_MAKE_CONSTANT('_','b','f','r')
-
-// ---------------------------------------------------------------------------
-
-// This #define may be used to conditionally compile device-specific code to
-// support either the prior ANativeWindow interface, which did not pass libsync
-// fences around, or the new interface that does. This #define is only present
-// when the ANativeWindow interface does include libsync support.
-#define ANDROID_NATIVE_WINDOW_HAS_SYNC 1
-
-// ---------------------------------------------------------------------------
-
-typedef const native_handle_t* buffer_handle_t;
-
-// ---------------------------------------------------------------------------
-
-typedef struct android_native_rect_t
-{
- int32_t left;
- int32_t top;
- int32_t right;
- int32_t bottom;
-} android_native_rect_t;
-
-// ---------------------------------------------------------------------------
-
-typedef struct android_native_base_t
-{
- /* a magic value defined by the actual EGL native type */
- int magic;
-
- /* the sizeof() of the actual EGL native type */
- int version;
-
- void* reserved[4];
-
- /* reference-counting interface */
- void (*incRef)(struct android_native_base_t* base);
- void (*decRef)(struct android_native_base_t* base);
-} android_native_base_t;
-
-typedef struct ANativeWindowBuffer
-{
-#ifdef __cplusplus
- ANativeWindowBuffer() {
- common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
- common.version = sizeof(ANativeWindowBuffer);
- memset(common.reserved, 0, sizeof(common.reserved));
- }
-
- // Implement the methods that sp<ANativeWindowBuffer> expects so that it
- // can be used to automatically refcount ANativeWindowBuffer's.
- void incStrong(const void* /*id*/) const {
- common.incRef(const_cast<android_native_base_t*>(&common));
- }
- void decStrong(const void* /*id*/) const {
- common.decRef(const_cast<android_native_base_t*>(&common));
- }
-#endif
-
- struct android_native_base_t common;
-
- int width;
- int height;
- int stride;
- int format;
- int usage;
- uintptr_t layerCount;
-
- void* reserved[1];
-
- buffer_handle_t handle;
-
- void* reserved_proc[8];
-} ANativeWindowBuffer_t;
-
-// Old typedef for backwards compatibility.
-typedef ANativeWindowBuffer_t android_native_buffer_t;
-
-// ---------------------------------------------------------------------------
-
-/* attributes queriable with query() */
-enum {
- NATIVE_WINDOW_WIDTH = 0,
- NATIVE_WINDOW_HEIGHT = 1,
- NATIVE_WINDOW_FORMAT = 2,
-
- /* The minimum number of buffers that must remain un-dequeued after a buffer
- * has been queued. This value applies only if set_buffer_count was used to
- * override the number of buffers and if a buffer has since been queued.
- * Users of the set_buffer_count ANativeWindow method should query this
- * value before calling set_buffer_count. If it is necessary to have N
- * buffers simultaneously dequeued as part of the steady-state operation,
- * and this query returns M then N+M buffers should be requested via
- * native_window_set_buffer_count.
- *
- * Note that this value does NOT apply until a single buffer has been
- * queued. In particular this means that it is possible to:
- *
- * 1. Query M = min undequeued buffers
- * 2. Set the buffer count to N + M
- * 3. Dequeue all N + M buffers
- * 4. Cancel M buffers
- * 5. Queue, dequeue, queue, dequeue, ad infinitum
- */
- NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS = 3,
-
- /* Check whether queueBuffer operations on the ANativeWindow send the buffer
- * to the window compositor. The query sets the returned 'value' argument
- * to 1 if the ANativeWindow DOES send queued buffers directly to the window
- * compositor and 0 if the buffers do not go directly to the window
- * compositor.
- *
- * This can be used to determine whether protected buffer content should be
- * sent to the ANativeWindow. Note, however, that a result of 1 does NOT
- * indicate that queued buffers will be protected from applications or users
- * capturing their contents. If that behavior is desired then some other
- * mechanism (e.g. the GRALLOC_USAGE_PROTECTED flag) should be used in
- * conjunction with this query.
- */
- NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER = 4,
-
- /* Get the concrete type of a ANativeWindow. See below for the list of
- * possible return values.
- *
- * This query should not be used outside the Android framework and will
- * likely be removed in the near future.
- */
- NATIVE_WINDOW_CONCRETE_TYPE = 5,
-
-
- /*
- * Default width and height of ANativeWindow buffers, these are the
- * dimensions of the window buffers irrespective of the
- * NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS call and match the native window
- * size unless overridden by NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS.
- */
- NATIVE_WINDOW_DEFAULT_WIDTH = 6,
- NATIVE_WINDOW_DEFAULT_HEIGHT = 7,
-
- /*
- * transformation that will most-likely be applied to buffers. This is only
- * a hint, the actual transformation applied might be different.
- *
- * INTENDED USE:
- *
- * The transform hint can be used by a producer, for instance the GLES
- * driver, to pre-rotate the rendering such that the final transformation
- * in the composer is identity. This can be very useful when used in
- * conjunction with the h/w composer HAL, in situations where it
- * cannot handle arbitrary rotations.
- *
- * 1. Before dequeuing a buffer, the GL driver (or any other ANW client)
- * queries the ANW for NATIVE_WINDOW_TRANSFORM_HINT.
- *
- * 2. The GL driver overrides the width and height of the ANW to
- * account for NATIVE_WINDOW_TRANSFORM_HINT. This is done by querying
- * NATIVE_WINDOW_DEFAULT_{WIDTH | HEIGHT}, swapping the dimensions
- * according to NATIVE_WINDOW_TRANSFORM_HINT and calling
- * native_window_set_buffers_dimensions().
- *
- * 3. The GL driver dequeues a buffer of the new pre-rotated size.
- *
- * 4. The GL driver renders to the buffer such that the image is
- * already transformed, that is applying NATIVE_WINDOW_TRANSFORM_HINT
- * to the rendering.
- *
- * 5. The GL driver calls native_window_set_transform to apply
- * inverse transformation to the buffer it just rendered.
- * In order to do this, the GL driver needs
- * to calculate the inverse of NATIVE_WINDOW_TRANSFORM_HINT, this is
- * done easily:
- *
- * int hintTransform, inverseTransform;
- * query(..., NATIVE_WINDOW_TRANSFORM_HINT, &hintTransform);
- * inverseTransform = hintTransform;
- * if (hintTransform & HAL_TRANSFORM_ROT_90)
- * inverseTransform ^= HAL_TRANSFORM_ROT_180;
- *
- *
- * 6. The GL driver queues the pre-transformed buffer.
- *
- * 7. The composer combines the buffer transform with the display
- * transform. If the buffer transform happens to cancel out the
- * display transform then no rotation is needed.
- *
- */
- NATIVE_WINDOW_TRANSFORM_HINT = 8,
-
- /*
- * Boolean that indicates whether the consumer is running more than
- * one buffer behind the producer.
- */
- NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND = 9,
-
- /*
- * The consumer gralloc usage bits currently set by the consumer.
- * The values are defined in hardware/libhardware/include/gralloc.h.
- */
- NATIVE_WINDOW_CONSUMER_USAGE_BITS = 10,
-
- /**
- * Transformation that will by applied to buffers by the hwcomposer.
- * This must not be set or checked by producer endpoints, and will
- * disable the transform hint set in SurfaceFlinger (see
- * NATIVE_WINDOW_TRANSFORM_HINT).
- *
- * INTENDED USE:
- * Temporary - Please do not use this. This is intended only to be used
- * by the camera's LEGACY mode.
- *
- * In situations where a SurfaceFlinger client wishes to set a transform
- * that is not visible to the producer, and will always be applied in the
- * hardware composer, the client can set this flag with
- * native_window_set_buffers_sticky_transform. This can be used to rotate
- * and flip buffers consumed by hardware composer without actually changing
- * the aspect ratio of the buffers produced.
- */
- NATIVE_WINDOW_STICKY_TRANSFORM = 11,
-
- /**
- * The default data space for the buffers as set by the consumer.
- * The values are defined in graphics.h.
- */
- NATIVE_WINDOW_DEFAULT_DATASPACE = 12,
-
- /*
- * Returns the age of the contents of the most recently dequeued buffer as
- * the number of frames that have elapsed since it was last queued. For
- * example, if the window is double-buffered, the age of any given buffer in
- * steady state will be 2. If the dequeued buffer has never been queued, its
- * age will be 0.
- */
- NATIVE_WINDOW_BUFFER_AGE = 13,
-
- /*
- * Returns the duration of the last dequeueBuffer call in microseconds
- */
- NATIVE_WINDOW_LAST_DEQUEUE_DURATION = 14,
-
- /*
- * Returns the duration of the last queueBuffer call in microseconds
- */
- NATIVE_WINDOW_LAST_QUEUE_DURATION = 15,
-
- /*
- * Returns the number of image layers that the ANativeWindow buffer
- * contains. By default this is 1, unless a buffer is explicitly allocated
- * to contain multiple layers.
- */
- NATIVE_WINDOW_LAYER_COUNT = 16,
-
- /*
- * Returns 1 if the native window is valid, 0 otherwise. native window is valid
- * if it is safe (i.e. no crash will occur) to call any method on it.
- */
- NATIVE_WINDOW_IS_VALID = 17,
-
- /*
- * Returns 1 if NATIVE_WINDOW_GET_FRAME_TIMESTAMPS will return display
- * present info, 0 if it won't.
- */
- NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT = 18,
-
- /*
- * The consumer end is capable of handling protected buffers, i.e. buffer
- * with GRALLOC_USAGE_PROTECTED usage bits on.
- */
- NATIVE_WINDOW_CONSUMER_IS_PROTECTED = 19,
-};
-
-/* Valid operations for the (*perform)() hook.
- *
- * Values marked as 'deprecated' are supported, but have been superceded by
- * other functionality.
- *
- * Values marked as 'private' should be considered private to the framework.
- * HAL implementation code with access to an ANativeWindow should not use these,
- * as it may not interact properly with the framework's use of the
- * ANativeWindow.
- */
-enum {
-// clang-format off
- NATIVE_WINDOW_SET_USAGE = 0,
- NATIVE_WINDOW_CONNECT = 1, /* deprecated */
- NATIVE_WINDOW_DISCONNECT = 2, /* deprecated */
- NATIVE_WINDOW_SET_CROP = 3, /* private */
- NATIVE_WINDOW_SET_BUFFER_COUNT = 4,
- NATIVE_WINDOW_SET_BUFFERS_GEOMETRY = 5, /* deprecated */
- NATIVE_WINDOW_SET_BUFFERS_TRANSFORM = 6,
- NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP = 7,
- NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS = 8,
- NATIVE_WINDOW_SET_BUFFERS_FORMAT = 9,
- NATIVE_WINDOW_SET_SCALING_MODE = 10, /* private */
- NATIVE_WINDOW_LOCK = 11, /* private */
- NATIVE_WINDOW_UNLOCK_AND_POST = 12, /* private */
- NATIVE_WINDOW_API_CONNECT = 13, /* private */
- NATIVE_WINDOW_API_DISCONNECT = 14, /* private */
- NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */
- NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* private */
- NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17,/* private */
- NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18,
- NATIVE_WINDOW_SET_BUFFERS_DATASPACE = 19,
- NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */
- NATIVE_WINDOW_SET_SHARED_BUFFER_MODE = 21,
- NATIVE_WINDOW_SET_AUTO_REFRESH = 22,
- NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION= 23,
- NATIVE_WINDOW_GET_NEXT_FRAME_ID = 24,
- NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS = 25,
- NATIVE_WINDOW_GET_COMPOSITOR_TIMING = 26,
- NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27,
- NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28,
- NATIVE_WINDOW_GET_HDR_SUPPORT = 29,
-// clang-format on
-};
-
-/* parameter for NATIVE_WINDOW_[API_][DIS]CONNECT */
-enum {
- /* Buffers will be queued by EGL via eglSwapBuffers after being filled using
- * OpenGL ES.
- */
- NATIVE_WINDOW_API_EGL = 1,
-
- /* Buffers will be queued after being filled using the CPU
- */
- NATIVE_WINDOW_API_CPU = 2,
-
- /* Buffers will be queued by Stagefright after being filled by a video
- * decoder. The video decoder can either be a software or hardware decoder.
- */
- NATIVE_WINDOW_API_MEDIA = 3,
-
- /* Buffers will be queued by the the camera HAL.
- */
- NATIVE_WINDOW_API_CAMERA = 4,
-};
-
-/* parameter for NATIVE_WINDOW_SET_BUFFERS_TRANSFORM */
-enum {
- /* flip source image horizontally */
- NATIVE_WINDOW_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H ,
- /* flip source image vertically */
- NATIVE_WINDOW_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V,
- /* rotate source image 90 degrees clock-wise, and is applied after TRANSFORM_FLIP_{H|V} */
- NATIVE_WINDOW_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90,
- /* rotate source image 180 degrees */
- NATIVE_WINDOW_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180,
- /* rotate source image 270 degrees clock-wise */
- NATIVE_WINDOW_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270,
- /* transforms source by the inverse transform of the screen it is displayed onto. This
- * transform is applied last */
- NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY = 0x08
-};
-
-/* parameter for NATIVE_WINDOW_SET_SCALING_MODE
- * keep in sync with Surface.java in frameworks/base */
-enum {
- /* the window content is not updated (frozen) until a buffer of
- * the window size is received (enqueued)
- */
- NATIVE_WINDOW_SCALING_MODE_FREEZE = 0,
- /* the buffer is scaled in both dimensions to match the window size */
- NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW = 1,
- /* the buffer is scaled uniformly such that the smaller dimension
- * of the buffer matches the window size (cropping in the process)
- */
- NATIVE_WINDOW_SCALING_MODE_SCALE_CROP = 2,
- /* the window is clipped to the size of the buffer's crop rectangle; pixels
- * outside the crop rectangle are treated as if they are completely
- * transparent.
- */
- NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP = 3,
-};
-
-/* values returned by the NATIVE_WINDOW_CONCRETE_TYPE query */
-enum {
- NATIVE_WINDOW_FRAMEBUFFER = 0, /* FramebufferNativeWindow */
- NATIVE_WINDOW_SURFACE = 1, /* Surface */
-};
-
-/* parameter for NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP
- *
- * Special timestamp value to indicate that timestamps should be auto-generated
- * by the native window when queueBuffer is called. This is equal to INT64_MIN,
- * defined directly to avoid problems with C99/C++ inclusion of stdint.h.
- */
-static const int64_t NATIVE_WINDOW_TIMESTAMP_AUTO = (-9223372036854775807LL-1);
-
-/* parameter for NATIVE_WINDOW_GET_FRAME_TIMESTAMPS
- *
- * Special timestamp value to indicate the timestamps aren't yet known or
- * that they are invalid.
- */
-static const int64_t NATIVE_WINDOW_TIMESTAMP_PENDING = -2;
-static const int64_t NATIVE_WINDOW_TIMESTAMP_INVALID = -1;
-
-struct ANativeWindow
-{
-#ifdef __cplusplus
- ANativeWindow()
- : flags(0), minSwapInterval(0), maxSwapInterval(0), xdpi(0), ydpi(0)
- {
- common.magic = ANDROID_NATIVE_WINDOW_MAGIC;
- common.version = sizeof(ANativeWindow);
- memset(common.reserved, 0, sizeof(common.reserved));
- }
-
- /* Implement the methods that sp<ANativeWindow> expects so that it
- can be used to automatically refcount ANativeWindow's. */
- void incStrong(const void* /*id*/) const {
- common.incRef(const_cast<android_native_base_t*>(&common));
- }
- void decStrong(const void* /*id*/) const {
- common.decRef(const_cast<android_native_base_t*>(&common));
- }
-#endif
-
- struct android_native_base_t common;
-
- /* flags describing some attributes of this surface or its updater */
- const uint32_t flags;
-
- /* min swap interval supported by this updated */
- const int minSwapInterval;
-
- /* max swap interval supported by this updated */
- const int maxSwapInterval;
-
- /* horizontal and vertical resolution in DPI */
- const float xdpi;
- const float ydpi;
-
- /* Some storage reserved for the OEM's driver. */
- intptr_t oem[4];
-
- /*
- * Set the swap interval for this surface.
- *
- * Returns 0 on success or -errno on error.
- */
- int (*setSwapInterval)(struct ANativeWindow* window,
- int interval);
-
- /*
- * Hook called by EGL to acquire a buffer. After this call, the buffer
- * is not locked, so its content cannot be modified. This call may block if
- * no buffers are available.
- *
- * The window holds a reference to the buffer between dequeueBuffer and
- * either queueBuffer or cancelBuffer, so clients only need their own
- * reference if they might use the buffer after queueing or canceling it.
- * Holding a reference to a buffer after queueing or canceling it is only
- * allowed if a specific buffer count has been set.
- *
- * Returns 0 on success or -errno on error.
- *
- * XXX: This function is deprecated. It will continue to work for some
- * time for binary compatibility, but the new dequeueBuffer function that
- * outputs a fence file descriptor should be used in its place.
- */
- int (*dequeueBuffer_DEPRECATED)(struct ANativeWindow* window,
- struct ANativeWindowBuffer** buffer);
-
- /*
- * hook called by EGL to lock a buffer. This MUST be called before modifying
- * the content of a buffer. The buffer must have been acquired with
- * dequeueBuffer first.
- *
- * Returns 0 on success or -errno on error.
- *
- * XXX: This function is deprecated. It will continue to work for some
- * time for binary compatibility, but it is essentially a no-op, and calls
- * to it should be removed.
- */
- int (*lockBuffer_DEPRECATED)(struct ANativeWindow* window,
- struct ANativeWindowBuffer* buffer);
-
- /*
- * Hook called by EGL when modifications to the render buffer are done.
- * This unlocks and post the buffer.
- *
- * The window holds a reference to the buffer between dequeueBuffer and
- * either queueBuffer or cancelBuffer, so clients only need their own
- * reference if they might use the buffer after queueing or canceling it.
- * Holding a reference to a buffer after queueing or canceling it is only
- * allowed if a specific buffer count has been set.
- *
- * Buffers MUST be queued in the same order than they were dequeued.
- *
- * Returns 0 on success or -errno on error.
- *
- * XXX: This function is deprecated. It will continue to work for some
- * time for binary compatibility, but the new queueBuffer function that
- * takes a fence file descriptor should be used in its place (pass a value
- * of -1 for the fence file descriptor if there is no valid one to pass).
- */
- int (*queueBuffer_DEPRECATED)(struct ANativeWindow* window,
- struct ANativeWindowBuffer* buffer);
-
- /*
- * hook used to retrieve information about the native window.
- *
- * Returns 0 on success or -errno on error.
- */
- int (*query)(const struct ANativeWindow* window,
- int what, int* value);
-
- /*
- * hook used to perform various operations on the surface.
- * (*perform)() is a generic mechanism to add functionality to
- * ANativeWindow while keeping backward binary compatibility.
- *
- * DO NOT CALL THIS HOOK DIRECTLY. Instead, use the helper functions
- * defined below.
- *
- * (*perform)() returns -ENOENT if the 'what' parameter is not supported
- * by the surface's implementation.
- *
- * See above for a list of valid operations, such as
- * NATIVE_WINDOW_SET_USAGE or NATIVE_WINDOW_CONNECT
- */
- int (*perform)(struct ANativeWindow* window,
- int operation, ... );
-
- /*
- * Hook used to cancel a buffer that has been dequeued.
- * No synchronization is performed between dequeue() and cancel(), so
- * either external synchronization is needed, or these functions must be
- * called from the same thread.
- *
- * The window holds a reference to the buffer between dequeueBuffer and
- * either queueBuffer or cancelBuffer, so clients only need their own
- * reference if they might use the buffer after queueing or canceling it.
- * Holding a reference to a buffer after queueing or canceling it is only
- * allowed if a specific buffer count has been set.
- *
- * XXX: This function is deprecated. It will continue to work for some
- * time for binary compatibility, but the new cancelBuffer function that
- * takes a fence file descriptor should be used in its place (pass a value
- * of -1 for the fence file descriptor if there is no valid one to pass).
- */
- int (*cancelBuffer_DEPRECATED)(struct ANativeWindow* window,
- struct ANativeWindowBuffer* buffer);
-
- /*
- * Hook called by EGL to acquire a buffer. This call may block if no
- * buffers are available.
- *
- * The window holds a reference to the buffer between dequeueBuffer and
- * either queueBuffer or cancelBuffer, so clients only need their own
- * reference if they might use the buffer after queueing or canceling it.
- * Holding a reference to a buffer after queueing or canceling it is only
- * allowed if a specific buffer count has been set.
- *
- * The libsync fence file descriptor returned in the int pointed to by the
- * fenceFd argument will refer to the fence that must signal before the
- * dequeued buffer may be written to. A value of -1 indicates that the
- * caller may access the buffer immediately without waiting on a fence. If
- * a valid file descriptor is returned (i.e. any value except -1) then the
- * caller is responsible for closing the file descriptor.
- *
- * Returns 0 on success or -errno on error.
- */
- int (*dequeueBuffer)(struct ANativeWindow* window,
- struct ANativeWindowBuffer** buffer, int* fenceFd);
-
- /*
- * Hook called by EGL when modifications to the render buffer are done.
- * This unlocks and post the buffer.
- *
- * The window holds a reference to the buffer between dequeueBuffer and
- * either queueBuffer or cancelBuffer, so clients only need their own
- * reference if they might use the buffer after queueing or canceling it.
- * Holding a reference to a buffer after queueing or canceling it is only
- * allowed if a specific buffer count has been set.
- *
- * The fenceFd argument specifies a libsync fence file descriptor for a
- * fence that must signal before the buffer can be accessed. If the buffer
- * can be accessed immediately then a value of -1 should be used. The
- * caller must not use the file descriptor after it is passed to
- * queueBuffer, and the ANativeWindow implementation is responsible for
- * closing it.
- *
- * Returns 0 on success or -errno on error.
- */
- int (*queueBuffer)(struct ANativeWindow* window,
- struct ANativeWindowBuffer* buffer, int fenceFd);
-
- /*
- * Hook used to cancel a buffer that has been dequeued.
- * No synchronization is performed between dequeue() and cancel(), so
- * either external synchronization is needed, or these functions must be
- * called from the same thread.
- *
- * The window holds a reference to the buffer between dequeueBuffer and
- * either queueBuffer or cancelBuffer, so clients only need their own
- * reference if they might use the buffer after queueing or canceling it.
- * Holding a reference to a buffer after queueing or canceling it is only
- * allowed if a specific buffer count has been set.
- *
- * The fenceFd argument specifies a libsync fence file decsriptor for a
- * fence that must signal before the buffer can be accessed. If the buffer
- * can be accessed immediately then a value of -1 should be used.
- *
- * Note that if the client has not waited on the fence that was returned
- * from dequeueBuffer, that same fence should be passed to cancelBuffer to
- * ensure that future uses of the buffer are preceded by a wait on that
- * fence. The caller must not use the file descriptor after it is passed
- * to cancelBuffer, and the ANativeWindow implementation is responsible for
- * closing it.
- *
- * Returns 0 on success or -errno on error.
- */
- int (*cancelBuffer)(struct ANativeWindow* window,
- struct ANativeWindowBuffer* buffer, int fenceFd);
-};
-
- /* Backwards compatibility: use ANativeWindow (struct ANativeWindow in C).
- * android_native_window_t is deprecated.
- */
-typedef struct ANativeWindow ANativeWindow;
-typedef struct ANativeWindow android_native_window_t __deprecated;
-
-/*
- * native_window_set_usage(..., usage)
- * Sets the intended usage flags for the next buffers
- * acquired with (*lockBuffer)() and on.
- * By default (if this function is never called), a usage of
- * GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE
- * is assumed.
- * Calling this function will usually cause following buffers to be
- * reallocated.
- */
-
-static inline int native_window_set_usage(
- struct ANativeWindow* window, int usage)
-{
- return window->perform(window, NATIVE_WINDOW_SET_USAGE, usage);
-}
-
-/* deprecated. Always returns 0. Don't call. */
-static inline int native_window_connect(
- struct ANativeWindow* window __UNUSED, int api __UNUSED) __deprecated;
-
-static inline int native_window_connect(
- struct ANativeWindow* window __UNUSED, int api __UNUSED) {
- return 0;
-}
-
-/* deprecated. Always returns 0. Don't call. */
-static inline int native_window_disconnect(
- struct ANativeWindow* window __UNUSED, int api __UNUSED) __deprecated;
-
-static inline int native_window_disconnect(
- struct ANativeWindow* window __UNUSED, int api __UNUSED) {
- return 0;
-}
-
-/*
- * native_window_set_crop(..., crop)
- * Sets which region of the next queued buffers needs to be considered.
- * Depending on the scaling mode, a buffer's crop region is scaled and/or
- * cropped to match the surface's size. This function sets the crop in
- * pre-transformed buffer pixel coordinates.
- *
- * The specified crop region applies to all buffers queued after it is called.
- *
- * If 'crop' is NULL, subsequently queued buffers won't be cropped.
- *
- * An error is returned if for instance the crop region is invalid, out of the
- * buffer's bound or if the window is invalid.
- */
-static inline int native_window_set_crop(
- struct ANativeWindow* window,
- android_native_rect_t const * crop)
-{
- return window->perform(window, NATIVE_WINDOW_SET_CROP, crop);
-}
-
-/*
- * native_window_set_post_transform_crop(..., crop)
- * Sets which region of the next queued buffers needs to be considered.
- * Depending on the scaling mode, a buffer's crop region is scaled and/or
- * cropped to match the surface's size. This function sets the crop in
- * post-transformed pixel coordinates.
- *
- * The specified crop region applies to all buffers queued after it is called.
- *
- * If 'crop' is NULL, subsequently queued buffers won't be cropped.
- *
- * An error is returned if for instance the crop region is invalid, out of the
- * buffer's bound or if the window is invalid.
- */
-static inline int native_window_set_post_transform_crop(
- struct ANativeWindow* window,
- android_native_rect_t const * crop)
-{
- return window->perform(window, NATIVE_WINDOW_SET_POST_TRANSFORM_CROP, crop);
-}
-
-/*
- * native_window_set_active_rect(..., active_rect)
- *
- * This function is deprecated and will be removed soon. For now it simply
- * sets the post-transform crop for compatibility while multi-project commits
- * get checked.
- */
-static inline int native_window_set_active_rect(
- struct ANativeWindow* window,
- android_native_rect_t const * active_rect) __deprecated;
-
-static inline int native_window_set_active_rect(
- struct ANativeWindow* window,
- android_native_rect_t const * active_rect)
-{
- return native_window_set_post_transform_crop(window, active_rect);
-}
-
-/*
- * native_window_set_buffer_count(..., count)
- * Sets the number of buffers associated with this native window.
- */
-static inline int native_window_set_buffer_count(
- struct ANativeWindow* window,
- size_t bufferCount)
-{
- return window->perform(window, NATIVE_WINDOW_SET_BUFFER_COUNT, bufferCount);
-}
-
-/*
- * native_window_set_buffers_geometry(..., int w, int h, int format)
- * All buffers dequeued after this call will have the dimensions and format
- * specified. A successful call to this function has the same effect as calling
- * native_window_set_buffers_size and native_window_set_buffers_format.
- *
- * XXX: This function is deprecated. The native_window_set_buffers_dimensions
- * and native_window_set_buffers_format functions should be used instead.
- */
-static inline int native_window_set_buffers_geometry(
- struct ANativeWindow* window,
- int w, int h, int format) __deprecated;
-
-static inline int native_window_set_buffers_geometry(
- struct ANativeWindow* window,
- int w, int h, int format)
-{
- return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,
- w, h, format);
-}
-
-/*
- * native_window_set_buffers_dimensions(..., int w, int h)
- * All buffers dequeued after this call will have the dimensions specified.
- * In particular, all buffers will have a fixed-size, independent from the
- * native-window size. They will be scaled according to the scaling mode
- * (see native_window_set_scaling_mode) upon window composition.
- *
- * If w and h are 0, the normal behavior is restored. That is, dequeued buffers
- * following this call will be sized to match the window's size.
- *
- * Calling this function will reset the window crop to a NULL value, which
- * disables cropping of the buffers.
- */
-static inline int native_window_set_buffers_dimensions(
- struct ANativeWindow* window,
- int w, int h)
-{
- return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS,
- w, h);
-}
-
-/*
- * native_window_set_buffers_user_dimensions(..., int w, int h)
- *
- * Sets the user buffer size for the window, which overrides the
- * window's size. All buffers dequeued after this call will have the
- * dimensions specified unless overridden by
- * native_window_set_buffers_dimensions. All buffers will have a
- * fixed-size, independent from the native-window size. They will be
- * scaled according to the scaling mode (see
- * native_window_set_scaling_mode) upon window composition.
- *
- * If w and h are 0, the normal behavior is restored. That is, the
- * default buffer size will match the windows's size.
- *
- * Calling this function will reset the window crop to a NULL value, which
- * disables cropping of the buffers.
- */
-static inline int native_window_set_buffers_user_dimensions(
- struct ANativeWindow* window,
- int w, int h)
-{
- return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS,
- w, h);
-}
-
-/*
- * native_window_set_buffers_format(..., int format)
- * All buffers dequeued after this call will have the format specified.
- *
- * If the specified format is 0, the default buffer format will be used.
- */
-static inline int native_window_set_buffers_format(
- struct ANativeWindow* window,
- int format)
-{
- return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_FORMAT, format);
-}
-
-/*
- * native_window_set_buffers_data_space(..., int dataSpace)
- * All buffers queued after this call will be associated with the dataSpace
- * parameter specified.
- *
- * dataSpace specifies additional information about the buffer that's dependent
- * on the buffer format and the endpoints. For example, it can be used to convey
- * the color space of the image data in the buffer, or it can be used to
- * indicate that the buffers contain depth measurement data instead of color
- * images. The default dataSpace is 0, HAL_DATASPACE_UNKNOWN, unless it has been
- * overridden by the consumer.
- */
-static inline int native_window_set_buffers_data_space(
- struct ANativeWindow* window,
- android_dataspace_t dataSpace)
-{
- return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_DATASPACE,
- dataSpace);
-}
-
-/*
- * native_window_set_buffers_transform(..., int transform)
- * All buffers queued after this call will be displayed transformed according
- * to the transform parameter specified.
- */
-static inline int native_window_set_buffers_transform(
- struct ANativeWindow* window,
- int transform)
-{
- return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TRANSFORM,
- transform);
-}
-
-/*
- * native_window_set_buffers_sticky_transform(..., int transform)
- * All buffers queued after this call will be displayed transformed according
- * to the transform parameter specified applied on top of the regular buffer
- * transform. Setting this transform will disable the transform hint.
- *
- * Temporary - This is only intended to be used by the LEGACY camera mode, do
- * not use this for anything else.
- */
-static inline int native_window_set_buffers_sticky_transform(
- struct ANativeWindow* window,
- int transform)
-{
- return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM,
- transform);
-}
-
-/*
- * native_window_set_buffers_timestamp(..., int64_t timestamp)
- * All buffers queued after this call will be associated with the timestamp
- * parameter specified. If the timestamp is set to NATIVE_WINDOW_TIMESTAMP_AUTO
- * (the default), timestamps will be generated automatically when queueBuffer is
- * called. The timestamp is measured in nanoseconds, and is normally monotonically
- * increasing. The timestamp should be unaffected by time-of-day adjustments,
- * and for a camera should be strictly monotonic but for a media player may be
- * reset when the position is set.
- */
-static inline int native_window_set_buffers_timestamp(
- struct ANativeWindow* window,
- int64_t timestamp)
-{
- return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP,
- timestamp);
-}
-
-/*
- * native_window_set_scaling_mode(..., int mode)
- * All buffers queued after this call will be associated with the scaling mode
- * specified.
- */
-static inline int native_window_set_scaling_mode(
- struct ANativeWindow* window,
- int mode)
-{
- return window->perform(window, NATIVE_WINDOW_SET_SCALING_MODE,
- mode);
-}
-
-/*
- * native_window_api_connect(..., int api)
- * connects an API to this window. only one API can be connected at a time.
- * Returns -EINVAL if for some reason the window cannot be connected, which
- * can happen if it's connected to some other API.
- */
-static inline int native_window_api_connect(
- struct ANativeWindow* window, int api)
-{
- return window->perform(window, NATIVE_WINDOW_API_CONNECT, api);
-}
-
-/*
- * native_window_api_disconnect(..., int api)
- * disconnect the API from this window.
- * An error is returned if for instance the window wasn't connected in the
- * first place.
- */
-static inline int native_window_api_disconnect(
- struct ANativeWindow* window, int api)
-{
- return window->perform(window, NATIVE_WINDOW_API_DISCONNECT, api);
-}
-
-/*
- * native_window_dequeue_buffer_and_wait(...)
- * Dequeue a buffer and wait on the fence associated with that buffer. The
- * buffer may safely be accessed immediately upon this function returning. An
- * error is returned if either of the dequeue or the wait operations fail.
- */
-static inline int native_window_dequeue_buffer_and_wait(ANativeWindow *anw,
- struct ANativeWindowBuffer** anb) {
- return anw->dequeueBuffer_DEPRECATED(anw, anb);
-}
-
-/*
- * native_window_set_sideband_stream(..., native_handle_t*)
- * Attach a sideband buffer stream to a native window.
- */
-static inline int native_window_set_sideband_stream(
- struct ANativeWindow* window,
- native_handle_t* sidebandHandle)
-{
- return window->perform(window, NATIVE_WINDOW_SET_SIDEBAND_STREAM,
- sidebandHandle);
-}
-
-/*
- * native_window_set_surface_damage(..., android_native_rect_t* rects, int numRects)
- * Set the surface damage (i.e., the region of the surface that has changed
- * since the previous frame). The damage set by this call will be reset (to the
- * default of full-surface damage) after calling queue, so this must be called
- * prior to every frame with damage that does not cover the whole surface if the
- * caller desires downstream consumers to use this optimization.
- *
- * The damage region is specified as an array of rectangles, with the important
- * caveat that the origin of the surface is considered to be the bottom-left
- * corner, as in OpenGL ES.
- *
- * If numRects is set to 0, rects may be NULL, and the surface damage will be
- * set to the full surface (the same as if this function had not been called for
- * this frame).
- */
-static inline int native_window_set_surface_damage(
- struct ANativeWindow* window,
- const android_native_rect_t* rects, size_t numRects)
-{
- return window->perform(window, NATIVE_WINDOW_SET_SURFACE_DAMAGE,
- rects, numRects);
-}
-
-/*
- * native_window_set_shared_buffer_mode(..., bool sharedBufferMode)
- * Enable/disable shared buffer mode
- */
-static inline int native_window_set_shared_buffer_mode(
- struct ANativeWindow* window,
- bool sharedBufferMode)
-{
- return window->perform(window, NATIVE_WINDOW_SET_SHARED_BUFFER_MODE,
- sharedBufferMode);
-}
-
-/*
- * native_window_set_auto_refresh(..., autoRefresh)
- * Enable/disable auto refresh when in shared buffer mode
- */
-static inline int native_window_set_auto_refresh(
- struct ANativeWindow* window,
- bool autoRefresh)
-{
- return window->perform(window, NATIVE_WINDOW_SET_AUTO_REFRESH, autoRefresh);
-}
-
-static inline int native_window_get_refresh_cycle_duration(
- struct ANativeWindow* window,
- int64_t* outRefreshDuration)
-{
- return window->perform(window, NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION,
- outRefreshDuration);
-}
-
-static inline int native_window_get_next_frame_id(
- struct ANativeWindow* window, uint64_t* frameId)
-{
- return window->perform(window, NATIVE_WINDOW_GET_NEXT_FRAME_ID, frameId);
-}
-
-static inline int native_window_enable_frame_timestamps(
- struct ANativeWindow* window, bool enable)
-{
- return window->perform(window, NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS,
- enable);
-}
-
-static inline int native_window_get_compositor_timing(
- struct ANativeWindow* window,
- int64_t* compositeDeadline, int64_t* compositeInterval,
- int64_t* compositeToPresentLatency)
-{
- return window->perform(window, NATIVE_WINDOW_GET_COMPOSITOR_TIMING,
- compositeDeadline, compositeInterval, compositeToPresentLatency);
-}
-
-static inline int native_window_get_frame_timestamps(
- struct ANativeWindow* window, uint64_t frameId,
- int64_t* outRequestedPresentTime, int64_t* outAcquireTime,
- int64_t* outLatchTime, int64_t* outFirstRefreshStartTime,
- int64_t* outLastRefreshStartTime, int64_t* outGpuCompositionDoneTime,
- int64_t* outDisplayPresentTime, int64_t* outDequeueReadyTime,
- int64_t* outReleaseTime)
-{
- return window->perform(window, NATIVE_WINDOW_GET_FRAME_TIMESTAMPS,
- frameId, outRequestedPresentTime, outAcquireTime, outLatchTime,
- outFirstRefreshStartTime, outLastRefreshStartTime,
- outGpuCompositionDoneTime, outDisplayPresentTime,
- outDequeueReadyTime, outReleaseTime);
-}
-
-static inline int native_window_get_wide_color_support(
- struct ANativeWindow* window, bool* outSupport) {
- return window->perform(window, NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT,
- outSupport);
-}
-
-static inline int native_window_get_hdr_support(struct ANativeWindow* window,
- bool* outSupport) {
- return window->perform(window, NATIVE_WINDOW_GET_HDR_SUPPORT, outSupport);
-}
-
-__END_DECLS
diff --git a/libsystem/include/system/window.h b/libsystem/include/system/window.h
deleted file mode 100644
index efa10d6..0000000
--- a/libsystem/include/system/window.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2011 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 SYSTEM_CORE_INCLUDE_ANDROID_WINDOW_H
-#define SYSTEM_CORE_INCLUDE_ANDROID_WINDOW_H
-
-#include <system/window-deprecated.h>
-
-#endif /* SYSTEM_CORE_INCLUDE_ANDROID_WINDOW_H */
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 038fd73..adcde81 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -18,12 +18,10 @@
host_supported: true,
header_libs: [
- "liblog_headers",
"libsystem_headers",
"libcutils_headers"
],
export_header_lib_headers: [
- "liblog_headers",
"libsystem_headers",
"libcutils_headers"
],
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index 24737b9..f5f881f 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -442,6 +442,11 @@
// and all accesses to refs happen before its deletion in the final decWeak.
// The destructor can safely access mRefs because either it's deleting
// mRefs itself, or it's running entirely before the final mWeak decrement.
+ //
+ // Since we're doing atomic loads of `flags`, the static analyzer assumes
+ // they can change between `delete this;` and `refs->decWeak(id);`. This is
+ // not the case. The analyzer may become more okay with this patten when
+ // https://bugs.llvm.org/show_bug.cgi?id=34365 gets resolved. NOLINTNEXTLINE
refs->decWeak(id);
}
diff --git a/libvndksupport/linker.c b/libvndksupport/linker.c
index 289f153..696e978 100644
--- a/libvndksupport/linker.c
+++ b/libvndksupport/linker.c
@@ -31,7 +31,9 @@
};
void* handle = android_dlopen_ext(name, flag, &dlextinfo);
if (!handle) {
- ALOGE("Could not load %s from sphal namespace: %s.", name, dlerror());
+ ALOGE(
+ "Could not load %s from sphal namespace: %s. ",
+ name, dlerror());
}
return handle;
} else {
@@ -43,4 +45,6 @@
}
}
-int android_unload_sphal_library(void* handle) { return dlclose(handle); }
+int android_unload_sphal_library(void* handle) {
+ return dlclose(handle);
+}
diff --git a/logd/tests/AndroidTest.xml b/logd/tests/AndroidTest.xml
index b16bdfd..8704611 100644
--- a/logd/tests/AndroidTest.xml
+++ b/logd/tests/AndroidTest.xml
@@ -14,6 +14,7 @@
limitations under the License.
-->
<configuration description="Config for CTS Logging Daemon test cases">
+ <option name="config-descriptor:metadata" key="component" value="systems" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
<option name="cleanup" value="true" />
<option name="push" value="CtsLogdTestCases->/data/local/tmp/CtsLogdTestCases" />
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 8ee5ea1..9e1541b 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -1099,7 +1099,7 @@
// and dac_read_search on every try to get past the message
// de-duper. We will also rotate the file name in the directory
// as another measure.
- static const char file[] = "/data/backup/cannot_access_directory_%u";
+ static const char file[] = "/data/drm/cannot_access_directory_%u";
static const unsigned avc_requests_per_access = 2;
rate /= avc_requests_per_access;
diff --git a/qemu_pipe/Android.bp b/qemu_pipe/Android.bp
new file mode 100644
index 0000000..93c347b
--- /dev/null
+++ b/qemu_pipe/Android.bp
@@ -0,0 +1,14 @@
+// Copyright 2011 The Android Open Source Project
+
+cc_library_static {
+ name: "libqemu_pipe",
+ vendor_available: true,
+ sanitize: {
+ misc_undefined: ["integer"],
+ },
+ srcs: ["qemu_pipe.cpp"],
+ local_include_dirs: ["include"],
+ static_libs: ["libbase"],
+ export_include_dirs: ["include"],
+ cflags: ["-Werror"],
+}
diff --git a/qemu_pipe/include/qemu_pipe.h b/qemu_pipe/include/qemu_pipe.h
new file mode 100644
index 0000000..0987498
--- /dev/null
+++ b/qemu_pipe/include/qemu_pipe.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 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 ANDROID_CORE_INCLUDE_QEMU_PIPE_H
+#define ANDROID_CORE_INCLUDE_QEMU_PIPE_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+// Try to open a new Qemu fast-pipe. This function returns a file descriptor
+// that can be used to communicate with a named service managed by the
+// emulator.
+//
+// This file descriptor can be used as a standard pipe/socket descriptor.
+//
+// 'pipeName' is the name of the emulator service you want to connect to,
+// and should begin with 'pipe:' (e.g. 'pipe:camera' or 'pipe:opengles').
+// For backward compatibility, the 'pipe:' prefix can be omitted, and in
+// that case, qemu_pipe_open will add it for you.
+
+// On success, return a valid file descriptor, or -1/errno on failure. E.g.:
+//
+// EINVAL -> unknown/unsupported pipeName
+// ENOSYS -> fast pipes not available in this system.
+//
+// ENOSYS should never happen, except if you're trying to run within a
+// misconfigured emulator.
+//
+// You should be able to open several pipes to the same pipe service,
+// except for a few special cases (e.g. GSM modem), where EBUSY will be
+// returned if more than one client tries to connect to it.
+int qemu_pipe_open(const char* pipeName);
+
+// Send a framed message |buff| of |len| bytes through the |fd| descriptor.
+// This really adds a 4-hexchar prefix describing the payload size.
+// Returns 0 on success, and -1 on error.
+int qemu_pipe_frame_send(int fd, const void* buff, size_t len);
+
+// Read a frame message from |fd|, and store it into |buff| of |len| bytes.
+// If the framed message is larger than |len|, then this returns -1 and the
+// content is lost. Otherwise, this returns the size of the message. NOTE:
+// empty messages are possible in a framed wire protocol and do not mean
+// end-of-stream.
+int qemu_pipe_frame_recv(int fd, void* buff, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ANDROID_CORE_INCLUDE_QEMU_PIPE_H */
diff --git a/qemu_pipe/qemu_pipe.cpp b/qemu_pipe/qemu_pipe.cpp
new file mode 100644
index 0000000..beeccb0
--- /dev/null
+++ b/qemu_pipe/qemu_pipe.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2011 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 "qemu_pipe.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include <android-base/file.h>
+
+using android::base::ReadFully;
+using android::base::WriteFully;
+
+// Define QEMU_PIPE_DEBUG if you want to print error messages when an error
+// occurs during pipe operations. The macro should simply take a printf-style
+// formatting string followed by optional arguments.
+#ifndef QEMU_PIPE_DEBUG
+# define QEMU_PIPE_DEBUG(...) (void)0
+#endif
+
+int qemu_pipe_open(const char* pipeName) {
+ // Sanity check.
+ if (!pipeName) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ int fd = TEMP_FAILURE_RETRY(open("/dev/qemu_pipe", O_RDWR));
+ if (fd < 0) {
+ QEMU_PIPE_DEBUG("%s: Could not open /dev/qemu_pipe: %s", __FUNCTION__,
+ strerror(errno));
+ return -1;
+ }
+
+ // Write the pipe name, *including* the trailing zero which is necessary.
+ size_t pipeNameLen = strlen(pipeName);
+ if (WriteFully(fd, pipeName, pipeNameLen + 1U)) {
+ return fd;
+ }
+
+ // now, add 'pipe:' prefix and try again
+ // Note: host side will wait for the trailing '\0' to start
+ // service lookup.
+ const char pipe_prefix[] = "pipe:";
+ if (WriteFully(fd, pipe_prefix, strlen(pipe_prefix)) &&
+ WriteFully(fd, pipeName, pipeNameLen + 1U)) {
+ return fd;
+ }
+ QEMU_PIPE_DEBUG("%s: Could not write to %s pipe service: %s",
+ __FUNCTION__, pipeName, strerror(errno));
+ close(fd);
+ return -1;
+}
+
+int qemu_pipe_frame_send(int fd, const void* buff, size_t len) {
+ char header[5];
+ snprintf(header, sizeof(header), "%04zx", len);
+ if (!WriteFully(fd, header, 4)) {
+ QEMU_PIPE_DEBUG("Can't write qemud frame header: %s", strerror(errno));
+ return -1;
+ }
+ if (!WriteFully(fd, buff, len)) {
+ QEMU_PIPE_DEBUG("Can't write qemud frame payload: %s", strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+int qemu_pipe_frame_recv(int fd, void* buff, size_t len) {
+ char header[5];
+ if (!ReadFully(fd, header, 4)) {
+ QEMU_PIPE_DEBUG("Can't read qemud frame header: %s", strerror(errno));
+ return -1;
+ }
+ header[4] = '\0';
+ size_t size;
+ if (sscanf(header, "%04zx", &size) != 1) {
+ QEMU_PIPE_DEBUG("Malformed qemud frame header: [%.*s]", 4, header);
+ return -1;
+ }
+ if (size > len) {
+ QEMU_PIPE_DEBUG("Oversized qemud frame (% bytes, expected <= %)", size,
+ len);
+ return -1;
+ }
+ if (!ReadFully(fd, buff, size)) {
+ QEMU_PIPE_DEBUG("Could not read qemud frame payload: %s",
+ strerror(errno));
+ return -1;
+ }
+ return size;
+}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index e199ed4..1bac36c 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -101,6 +101,21 @@
$(foreach binary, $(SANITIZE_ASAN_OPTIONS_FOR), $(eval $(call create-asan-options-module,$(binary))))
endif
+# ASAN extration.
+ASAN_EXTRACT_FILES :=
+ifeq ($(SANITIZE_TARGET_SYSTEM),true)
+include $(CLEAR_VARS)
+LOCAL_MODULE:= asan_extract
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_SRC_FILES := asan_extract.sh
+LOCAL_INIT_RC := asan_extract.rc
+# We need bzip2 on device for extraction.
+LOCAL_REQUIRED_MODULES := bzip2
+include $(BUILD_PREBUILT)
+ASAN_EXTRACT_FILES := asan_extract
+endif
+
endif
#######################################
@@ -114,7 +129,7 @@
EXPORT_GLOBAL_ASAN_OPTIONS :=
ifneq ($(filter address,$(SANITIZE_TARGET)),)
EXPORT_GLOBAL_ASAN_OPTIONS := export ASAN_OPTIONS include=/system/asan.options
- LOCAL_REQUIRED_MODULES := asan.options $(ASAN_OPTIONS_FILES)
+ LOCAL_REQUIRED_MODULES := asan.options $(ASAN_OPTIONS_FILES) $(ASAN_EXTRACT_FILES)
endif
EXPORT_GLOBAL_GCOV_OPTIONS :=
diff --git a/rootdir/asan_extract.rc b/rootdir/asan_extract.rc
new file mode 100644
index 0000000..4aea6a3
--- /dev/null
+++ b/rootdir/asan_extract.rc
@@ -0,0 +1,3 @@
+# When /data is available, look for /system/asan.tar.gz and potentially extract.
+on post-fs-data
+ exec - system system -- /system/bin/asan_extract
diff --git a/rootdir/asan_extract.sh b/rootdir/asan_extract.sh
new file mode 100644
index 0000000..2d72320
--- /dev/null
+++ b/rootdir/asan_extract.sh
@@ -0,0 +1,95 @@
+#!/system/bin/sh
+
+#
+# Copyright (C) 2017 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.
+#
+
+# This script will extract ASAN libraries from /system/asan.tar.gz to /data and then reboot.
+
+# TODO:
+# * Timestamp or something to know when to run this again. Right now take the existence of
+# /data/lib as we're already done.
+# * Need to distinguish pre- from post-decryption for FDE.
+
+SRC=/system/asan.tar.bz2
+MD5_FILE=/data/asan.md5sum
+ASAN_DIR=/data/asan
+# Minimum /data size in blocks. Arbitrarily 512M.
+MIN_DATA_SIZE=131072
+
+# Checks for FDE pre-decrypt state.
+
+VOLD_STATUS=$(getprop vold.decrypt)
+if [ "$VOLD_STATUS" = "trigger_restart_min_framework" ] ; then
+ log -p i -t asan_install "Pre-decrypt FDE detected (by vold property)!"
+ exit 1
+fi
+
+STATFS_BLOCKS=$(stat -f -c '%b' /data)
+if [ "$STATFS_BLOCKS" -le "$MIN_DATA_SIZE" ] ; then
+ log -p i -t asan_install "Pre-decrypt FDE detected (by /data size)!"
+ exit 1
+fi
+
+# Check for ASAN source.
+
+if ! test -f $SRC ; then
+ log -p i -t asan_install "Did not find $SRC!"
+ exit 1
+fi
+
+log -p i -t asan_install "Found $SRC, checking whether we need to apply it."
+
+# Checksum check.
+
+ASAN_TAR_MD5=$(md5sum $SRC)
+if test -f $MD5_FILE ; then
+ INSTALLED_MD5=$(cat $MD5_FILE)
+ if [ "x$ASAN_TAR_MD5" = "x$INSTALLED_MD5" ] ; then
+ log -p i -t asan_install "Checksums match, nothing to be done here."
+ exit 0
+ fi
+fi
+
+# Actually apply the source.
+
+# Just clean up, helps with restorecon.
+rm -rf $ASAN_DIR
+
+log -p i -t asan_install "Untarring $SRC..."
+
+# Unzip from /system/asan.tar.gz into data. Need to pipe as gunzip is not on device.
+bzip2 -c -d $SRC | tar -x -f - --no-same-owner -C / || exit 1
+
+# Cannot log here, log would run with system_data_file.
+
+# Set correct permission bits.
+chmod -R 744 $ASAN_DIR
+cd $ASAN_DIR ; find . -type d -exec chmod 755 {} \;
+
+restorecon -R -F $ASAN_DIR/*/lib*
+
+log -p i -t asan_install "Fixed selinux labels..."
+
+
+# Now write down our checksum to mark the extraction complete.
+echo "$ASAN_TAR_MD5" > $MD5_FILE
+
+# We want to reboot now. It seems it is not possible to run "reboot" here, the device will
+# just be stuck.
+
+log -p i -t asan_install "Signaling init to reboot..."
+
+setprop sys.powerctl reboot
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 436589e..56066bc 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -7,6 +7,10 @@
dir.system = /system/bin/
dir.system = /system/xbin/
dir.vendor = /vendor/bin/
+dir.test = /data/nativetest/
+dir.test = /data/nativetest64/
+dir.test = /data/benchmarktest/
+dir.test = /data/benchmarktest64/
[system]
additional.namespaces = sphal,vndk,rs
@@ -84,7 +88,7 @@
namespace.rs.asan.permitted.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}:/data
namespace.rs.links = default,vndk
-namespace.rs.link.default.shared_libs = libc.so:libz.so:libm.so:libdl.so:libstdc++.so:liblog.so:libnativewindow.so:libEGL.so:libsync.so:libGLESv1_CM.so:libGLESv2.so:libmediandk.so:libui.so:libvndksupport.so
+namespace.rs.link.default.shared_libs = libc.so:libz.so:libm.so:libdl.so:libstdc++.so:liblog.so:libnativewindow.so:libEGL.so:libsync.so:libGLESv1_CM.so:libGLESv2.so:libmediandk.so:libvndksupport.so
namespace.rs.link.vndk.shared_libs = android.hardware.renderscript@1.0.so:android.hardware.graphics.allocator@2.0.so:android.hardware.graphics.mapper@2.0.so:android.hardware.graphics.common@1.0.so:android.hidl.memory@1.0.so:libhwbinder.so:libbase.so:libcutils.so:libhardware.so:libhidlbase.so:libhidlmemory.so:libhidltransport.so:libion.so:libutils.so:libc++.so
###############################################################################
@@ -105,9 +109,23 @@
namespace.vndk.links = default
namespace.vndk.link.default.shared_libs = android.hidl.memory@1.0-impl.so:libc.so:libz.so:libm.so:libdl.so:libstdc++.so:liblog.so:libnativewindow.so:libEGL.so:libsync.so:libvndksupport.so
-
+###############################################################################
+# Namespace config for vendor processes. In O, no restriction is enforced for
+# them. However, in O-MR1, access to /system/${LIB} will not be allowed to
+# the default namespace. 'system' namespace will be added to give limited
+# (LL-NDK only) access.
+###############################################################################
[vendor]
namespace.default.isolated = false
namespace.default.search.paths = /vendor/${LIB}:/vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/system/${LIB}
namespace.default.asan.search.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/data/asan/system/${LIB}:/system/${LIB}
+
+###############################################################################
+# Namespace config for tests. No VNDK restriction is enforced for these tests.
+###############################################################################
+[test]
+namespace.default.isolated = false
+namespace.default.search.paths = /vendor/${LIB}:/vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/system/${LIB}
+
+namespace.default.asan.search.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/data/asan/system/${LIB}:/system/${LIB}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index fb1fbd4..87920fb 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -61,18 +61,22 @@
mkdir /dev/stune/foreground
mkdir /dev/stune/background
mkdir /dev/stune/top-app
+ mkdir /dev/stune/rt
chown system system /dev/stune
chown system system /dev/stune/foreground
chown system system /dev/stune/background
chown system system /dev/stune/top-app
+ chown system system /dev/stune/rt
chown system system /dev/stune/tasks
chown system system /dev/stune/foreground/tasks
chown system system /dev/stune/background/tasks
chown system system /dev/stune/top-app/tasks
+ chown system system /dev/stune/rt/tasks
chmod 0664 /dev/stune/tasks
chmod 0664 /dev/stune/foreground/tasks
chmod 0664 /dev/stune/background/tasks
chmod 0664 /dev/stune/top-app/tasks
+ chmod 0664 /dev/stune/rt/tasks
# Mount staging areas for devices managed by vold
# See storage config details at http://source.android.com/tech/storage/
diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp
index 3b6867c..6b9d723 100644
--- a/trusty/keymaster/Android.bp
+++ b/trusty/keymaster/Android.bp
@@ -33,7 +33,8 @@
shared_libs: [
"libcrypto",
"libcutils",
- "libkeymaster1",
+ "libkeymaster_portable",
+ "libkeymaster_staging",
"libtrusty",
"libkeymaster_messages",
"libsoftkeymasterdevice",
diff --git a/trusty/keymaster/trusty_keymaster_device_test.cpp b/trusty/keymaster/trusty_keymaster_device_test.cpp
index e8f5c0b..9227964 100644
--- a/trusty/keymaster/trusty_keymaster_device_test.cpp
+++ b/trusty/keymaster/trusty_keymaster_device_test.cpp
@@ -15,9 +15,9 @@
*/
#include <algorithm>
#include <fstream>
+#include <memory>
#include <gtest/gtest.h>
-#include <nativehelper/UniquePtr.h>
#include <openssl/engine.h>
#include <hardware/keymaster0.h>
@@ -181,7 +181,7 @@
keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
size_t message_len = params.modulus_size / 8;
- UniquePtr<uint8_t[]> message(build_message(message_len));
+ std::unique_ptr<uint8_t[]> message(build_message(message_len));
uint8_t* signature;
size_t siglen;
EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
@@ -200,7 +200,7 @@
keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
size_t message_len = params.modulus_size / 8 - 1;
- UniquePtr<uint8_t[]> message(build_message(message_len));
+ std::unique_ptr<uint8_t[]> message(build_message(message_len));
uint8_t* signature;
size_t siglen;
EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, device.sign_data(&sig_params, ptr, size, message.get(),
@@ -217,7 +217,7 @@
keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
size_t message_len = params.modulus_size / 8 + 1;
- UniquePtr<uint8_t[]> message(build_message(message_len));
+ std::unique_ptr<uint8_t[]> message(build_message(message_len));
uint8_t* signature;
size_t siglen;
EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, device.sign_data(&sig_params, ptr, size, message.get(),
@@ -272,7 +272,7 @@
keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
size_t message_len = 1024 * 7;
- UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
+ std::unique_ptr<uint8_t[]> message(new uint8_t[message_len]);
// contents of message don't matter.
uint8_t* signature;
size_t siglen;
@@ -294,7 +294,7 @@
keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
size_t message_len = params.modulus_size / 8;
- UniquePtr<uint8_t[]> message(build_message(message_len));
+ std::unique_ptr<uint8_t[]> message(build_message(message_len));
uint8_t* signature;
size_t siglen;
EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
@@ -315,7 +315,7 @@
keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
size_t message_len = params.modulus_size / 8;
- UniquePtr<uint8_t[]> message(build_message(message_len));
+ std::unique_ptr<uint8_t[]> message(build_message(message_len));
uint8_t* signature;
size_t siglen;
EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
@@ -338,7 +338,7 @@
keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
size_t message_len = params.modulus_size / 8;
- UniquePtr<uint8_t[]> message(build_message(message_len));
+ std::unique_ptr<uint8_t[]> message(build_message(message_len));
uint8_t* signature;
size_t siglen;
EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
@@ -360,7 +360,7 @@
keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
size_t message_len = params.modulus_size / 8;
- UniquePtr<uint8_t[]> message(build_message(message_len));
+ std::unique_ptr<uint8_t[]> message(build_message(message_len));
uint8_t* signature;
size_t siglen;
EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
@@ -382,7 +382,7 @@
keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
size_t message_len = params.modulus_size / 8;
- UniquePtr<uint8_t[]> message(build_message(message_len + 1));
+ std::unique_ptr<uint8_t[]> message(build_message(message_len + 1));
uint8_t* signature;
size_t siglen;
EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
@@ -422,7 +422,7 @@
keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
size_t message_len = 1024 * 7;
- UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
+ std::unique_ptr<uint8_t[]> message(new uint8_t[message_len]);
// contents of message don't matter.
uint8_t* signature;
size_t siglen;
@@ -453,7 +453,7 @@
keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
size_t message_size = 1024 /* key size */ / 8;
- UniquePtr<uint8_t[]> message(new uint8_t[message_size]);
+ std::unique_ptr<uint8_t[]> message(new uint8_t[message_size]);
memset(message.get(), 'a', message_size);
uint8_t* signature;
size_t siglen;
@@ -491,9 +491,9 @@
static void VerifySignature(const uint8_t* key, size_t key_len, const uint8_t* signature,
size_t signature_len, const uint8_t* message, size_t message_len) {
- UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(d2i_PUBKEY(NULL, &key, key_len));
+ std::unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(d2i_PUBKEY(NULL, &key, key_len));
ASSERT_TRUE(pkey.get() != NULL);
- UniquePtr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL));
+ std::unique_ptr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL));
ASSERT_TRUE(ctx.get() != NULL);
ASSERT_EQ(1, EVP_PKEY_verify_init(ctx.get()));
if (EVP_PKEY_type(pkey->type) == EVP_PKEY_RSA)
@@ -518,7 +518,7 @@
// Sign a message so we can verify it with the exported pubkey.
keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
size_t message_len = params.modulus_size / 8;
- UniquePtr<uint8_t[]> message(build_message(message_len));
+ std::unique_ptr<uint8_t[]> message(build_message(message_len));
uint8_t* signature;
size_t siglen;
EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,