Merge "Don\'t fail if the new pss is less than stable." am: 26cf352637
am: 4006add727
* commit '4006add7274f3cf29ec212f82137012e32675ee5':
Don't fail if the new pss is less than stable.
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 30a38e3..e522119 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -157,7 +157,7 @@
" (-r: replace existing application)\n"
" (-t: allow test packages)\n"
" (-s: install application on sdcard)\n"
- " (-d: allow version code downgrade)\n"
+ " (-d: allow version code downgrade (debuggable packages only))\n"
" (-g: grant all runtime permissions)\n"
" adb install-multiple [-lrtsdpg] <file...>\n"
" - push this package file to the device and install it\n"
@@ -165,7 +165,7 @@
" (-r: replace existing application)\n"
" (-t: allow test packages)\n"
" (-s: install application on sdcard)\n"
- " (-d: allow version code downgrade)\n"
+ " (-d: allow version code downgrade (debuggable packages only))\n"
" (-p: partial application install)\n"
" (-g: grant all runtime permissions)\n"
" adb uninstall [-k] <package> - remove this app package from the device\n"
diff --git a/adb/transport.cpp b/adb/transport.cpp
index e3340af..f86a222 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -781,9 +781,7 @@
// Local static allocation to avoid global non-POD variables.
static const FeatureSet* features = new FeatureSet{
kFeatureShell2,
- // Internal master has 'cmd'. AOSP master doesn't.
- // kFeatureCmd
-
+ kFeatureCmd
// Increment ADB_SERVER_VERSION whenever the feature list changes to
// make sure that the adb client and server features stay in sync
// (http://b/24370690).
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 7e60a72..636092e 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -85,6 +85,8 @@
static unsigned second_offset = 0x00f00000;
static unsigned tags_offset = 0x00000100;
+static const std::string convert_fbe_marker_filename("convert_fbe");
+
enum fb_buffer_type {
FB_BUFFER,
FB_BUFFER_SPARSE,
@@ -386,11 +388,17 @@
" given by --slot. If slots are not\n"
" supported, this does nothing. This will\n"
" run after all non-reboot commands.\n"
+#if !defined(_WIN32)
+ " --wipe-and-use-fbe On devices which support it,\n"
+ " erase userdata and cache, and\n"
+ " enable file-based encryption\n"
+#endif
" --unbuffered Do not buffer input or output.\n"
" --version Display version.\n"
" -h, --help show this message.\n"
);
}
+
static void* load_bootable_image(const char* kernel, const char* ramdisk,
const char* secondstage, int64_t* sz,
const char* cmdline) {
@@ -510,8 +518,60 @@
#define tmpfile win32_tmpfile
+static std::string make_temporary_directory() {
+ fprintf(stderr, "make_temporary_directory not supported under Windows, sorry!");
+ return "";
+}
+
+#else
+
+static std::string make_temporary_directory() {
+ const char *tmpdir = getenv("TMPDIR");
+ if (tmpdir == nullptr) {
+ tmpdir = P_tmpdir;
+ }
+ std::string result = std::string(tmpdir) + "/fastboot_userdata_XXXXXX";
+ if (mkdtemp(&result[0]) == NULL) {
+ fprintf(stderr, "Unable to create temporary directory: %s\n",
+ strerror(errno));
+ return "";
+ }
+ return result;
+}
+
#endif
+static std::string create_fbemarker_tmpdir() {
+ std::string dir = make_temporary_directory();
+ if (dir.empty()) {
+ fprintf(stderr, "Unable to create local temp directory for FBE marker\n");
+ return "";
+ }
+ std::string marker_file = dir + "/" + convert_fbe_marker_filename;
+ int fd = open(marker_file.c_str(), O_CREAT | O_WRONLY | O_CLOEXEC, 0666);
+ if (fd == -1) {
+ fprintf(stderr, "Unable to create FBE marker file %s locally: %d, %s\n",
+ marker_file.c_str(), errno, strerror(errno));
+ return "";
+ }
+ close(fd);
+ return dir;
+}
+
+static void delete_fbemarker_tmpdir(const std::string& dir) {
+ std::string marker_file = dir + "/" + convert_fbe_marker_filename;
+ if (unlink(marker_file.c_str()) == -1) {
+ fprintf(stderr, "Unable to delete FBE marker file %s locally: %d, %s\n",
+ marker_file.c_str(), errno, strerror(errno));
+ return;
+ }
+ if (rmdir(dir.c_str()) == -1) {
+ fprintf(stderr, "Unable to delete FBE marker directory %s locally: %d, %s\n",
+ dir.c_str(), errno, strerror(errno));
+ return;
+ }
+}
+
static int unzip_to_file(ZipArchiveHandle zip, char* entry_name) {
FILE* fp = tmpfile();
if (fp == nullptr) {
@@ -1097,7 +1157,8 @@
static void fb_perform_format(Transport* transport,
const char* partition, int skip_if_not_supported,
- const char* type_override, const char* size_override) {
+ const char* type_override, const char* size_override,
+ const std::string& initial_dir) {
std::string partition_type, partition_size;
struct fastboot_buffer buf;
@@ -1161,7 +1222,7 @@
}
fd = fileno(tmpfile());
- if (fs_generator_generate(gen, fd, size)) {
+ if (fs_generator_generate(gen, fd, size, initial_dir)) {
fprintf(stderr, "Cannot generate image: %s\n", strerror(errno));
close(fd);
return;
@@ -1190,6 +1251,7 @@
bool wants_reboot_bootloader = false;
bool wants_set_active = false;
bool erase_first = true;
+ bool set_fbe_marker = false;
void *data;
int64_t sz;
int longindex;
@@ -1212,6 +1274,9 @@
{"slot", required_argument, 0, 0},
{"set_active", optional_argument, 0, 'a'},
{"set-active", optional_argument, 0, 'a'},
+#if !defined(_WIN32)
+ {"wipe-and-use-fbe", no_argument, 0, 0},
+#endif
{0, 0, 0, 0}
};
@@ -1293,6 +1358,15 @@
return 0;
} else if (strcmp("slot", longopts[longindex].name) == 0) {
slot_override = std::string(optarg);
+#if !defined(_WIN32)
+ } else if (strcmp("wipe-and-use-fbe", longopts[longindex].name) == 0) {
+ wants_wipe = true;
+ set_fbe_marker = true;
+#endif
+ } else {
+ fprintf(stderr, "Internal error in options processing for %s\n",
+ longopts[longindex].name);
+ return 1;
}
break;
default:
@@ -1390,7 +1464,8 @@
if (erase_first && needs_erase(transport, partition.c_str())) {
fb_queue_erase(partition.c_str());
}
- fb_perform_format(transport, partition.c_str(), 0, type_override, size_override);
+ fb_perform_format(transport, partition.c_str(), 0,
+ type_override, size_override, "");
};
do_for_partitions(transport, argv[1], slot_override.c_str(), format, true);
skip(2);
@@ -1525,13 +1600,23 @@
if (wants_wipe) {
fprintf(stderr, "wiping userdata...\n");
fb_queue_erase("userdata");
- fb_perform_format(transport, "userdata", 1, nullptr, nullptr);
+ if (set_fbe_marker) {
+ fprintf(stderr, "setting FBE marker...\n");
+ std::string initial_userdata_dir = create_fbemarker_tmpdir();
+ if (initial_userdata_dir.empty()) {
+ return 1;
+ }
+ fb_perform_format(transport, "userdata", 1, nullptr, nullptr, initial_userdata_dir);
+ delete_fbemarker_tmpdir(initial_userdata_dir);
+ } else {
+ fb_perform_format(transport, "userdata", 1, nullptr, nullptr, "");
+ }
std::string cache_type;
if (fb_getvar(transport, "partition-type:cache", &cache_type) && !cache_type.empty()) {
fprintf(stderr, "wiping cache...\n");
fb_queue_erase("cache");
- fb_perform_format(transport, "cache", 1, nullptr, nullptr);
+ fb_perform_format(transport, "cache", 1, nullptr, nullptr, "");
}
}
if (wants_set_active) {
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index 90d8474..8539e23 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -1,7 +1,8 @@
+#include "fs.h"
+
#include "fastboot.h"
#include "make_ext4fs.h"
#include "make_f2fs.h"
-#include "fs.h"
#include <errno.h>
#include <stdio.h>
@@ -13,24 +14,32 @@
#include <sparse/sparse.h>
-static int generate_ext4_image(int fd, long long partSize)
+static int generate_ext4_image(int fd, long long partSize, const std::string& initial_dir)
{
- make_ext4fs_sparse_fd(fd, partSize, NULL, NULL);
-
+ if (initial_dir.empty()) {
+ make_ext4fs_sparse_fd(fd, partSize, NULL, NULL);
+ } else {
+ make_ext4fs_sparse_fd_directory(fd, partSize, NULL, NULL, initial_dir.c_str());
+ }
return 0;
}
#ifdef USE_F2FS
-static int generate_f2fs_image(int fd, long long partSize)
+static int generate_f2fs_image(int fd, long long partSize, const std::string& initial_dir)
{
+ if (!initial_dir.empty()) {
+ fprintf(stderr, "Unable to set initial directory on F2FS filesystem\n");
+ return -1;
+ }
return make_f2fs_sparse_fd(fd, partSize, NULL, NULL);
}
#endif
static const struct fs_generator {
-
const char* fs_type; //must match what fastboot reports for partition type
- int (*generate)(int fd, long long partSize); //returns 0 or error value
+
+ //returns 0 or error value
+ int (*generate)(int fd, long long partSize, const std::string& initial_dir);
} generators[] = {
{ "ext4", generate_ext4_image},
@@ -48,7 +57,8 @@
return nullptr;
}
-int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize)
+int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize,
+ const std::string& initial_dir)
{
- return gen->generate(tmpFileNo, partSize);
+ return gen->generate(tmpFileNo, partSize, initial_dir);
}
diff --git a/fastboot/fs.h b/fastboot/fs.h
index 289488b..0a68507 100644
--- a/fastboot/fs.h
+++ b/fastboot/fs.h
@@ -1,11 +1,13 @@
#ifndef _FS_H_
#define _FS_H_
+#include <string>
#include <stdint.h>
struct fs_generator;
const struct fs_generator* fs_get_generator(const std::string& fs_type);
-int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize);
+int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize,
+ const std::string& initial_dir);
#endif
diff --git a/fingerprintd/FingerprintDaemonProxy.cpp b/fingerprintd/FingerprintDaemonProxy.cpp
index beb95de..1c7da30 100644
--- a/fingerprintd/FingerprintDaemonProxy.cpp
+++ b/fingerprintd/FingerprintDaemonProxy.cpp
@@ -88,6 +88,16 @@
msg->data.removed.finger.fid,
msg->data.removed.finger.gid);
break;
+ case FINGERPRINT_TEMPLATE_ENUMERATING:
+ ALOGD("onEnumerate(fid=%d, gid=%d, rem=%d)",
+ msg->data.enumerated.finger.fid,
+ msg->data.enumerated.finger.gid,
+ msg->data.enumerated.remaining_templates);
+ callback->onEnumerate(device,
+ msg->data.enumerated.finger.fid,
+ msg->data.enumerated.finger.gid,
+ msg->data.enumerated.remaining_templates);
+ break;
default:
ALOGE("invalid msg type: %d", msg->type);
return;
@@ -158,6 +168,11 @@
return mDevice->remove(mDevice, groupId, fingerId);
}
+int32_t FingerprintDaemonProxy::enumerate() {
+ ALOG(LOG_VERBOSE, LOG_TAG, "enumerate()\n");
+ return mDevice->enumerate(mDevice);
+}
+
uint64_t FingerprintDaemonProxy::getAuthenticatorId() {
return mDevice->get_authenticator_id(mDevice);
}
diff --git a/fingerprintd/FingerprintDaemonProxy.h b/fingerprintd/FingerprintDaemonProxy.h
index 871c0e6..145b4c9 100644
--- a/fingerprintd/FingerprintDaemonProxy.h
+++ b/fingerprintd/FingerprintDaemonProxy.h
@@ -40,6 +40,7 @@
virtual int32_t authenticate(uint64_t sessionId, uint32_t groupId);
virtual int32_t stopAuthentication();
virtual int32_t remove(int32_t fingerId, int32_t groupId);
+ virtual int32_t enumerate();
virtual uint64_t getAuthenticatorId();
virtual int32_t setActiveGroup(int32_t groupId, const uint8_t* path, ssize_t pathLen);
virtual int64_t openHal();
diff --git a/fingerprintd/IFingerprintDaemon.cpp b/fingerprintd/IFingerprintDaemon.cpp
index 7131793..bc4af56 100644
--- a/fingerprintd/IFingerprintDaemon.cpp
+++ b/fingerprintd/IFingerprintDaemon.cpp
@@ -125,6 +125,16 @@
reply->writeInt32(ret);
return NO_ERROR;
}
+ case ENUMERATE: {
+ CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+ if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+ return PERMISSION_DENIED;
+ }
+ const int32_t ret = enumerate();
+ reply->writeNoException();
+ reply->writeInt32(ret);
+ return NO_ERROR;
+ }
case GET_AUTHENTICATOR_ID: {
CHECK_INTERFACE(IFingerprintDaemon, data, reply);
if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
diff --git a/fingerprintd/IFingerprintDaemon.h b/fingerprintd/IFingerprintDaemon.h
index 1eb4ac1..23c36ff 100644
--- a/fingerprintd/IFingerprintDaemon.h
+++ b/fingerprintd/IFingerprintDaemon.h
@@ -44,6 +44,7 @@
CLOSE_HAL = IBinder::FIRST_CALL_TRANSACTION + 9,
INIT = IBinder::FIRST_CALL_TRANSACTION + 10,
POST_ENROLL = IBinder::FIRST_CALL_TRANSACTION + 11,
+ ENUMERATE = IBinder::FIRST_CALL_TRANSACTION + 12,
};
IFingerprintDaemon() { }
@@ -60,6 +61,7 @@
virtual int32_t authenticate(uint64_t sessionId, uint32_t groupId) = 0;
virtual int32_t stopAuthentication() = 0;
virtual int32_t remove(int32_t fingerId, int32_t groupId) = 0;
+ virtual int32_t enumerate() = 0;
virtual uint64_t getAuthenticatorId() = 0;
virtual int32_t setActiveGroup(int32_t groupId, const uint8_t* path, ssize_t pathLen) = 0;
virtual int64_t openHal() = 0;
diff --git a/fingerprintd/IFingerprintDaemonCallback.cpp b/fingerprintd/IFingerprintDaemonCallback.cpp
index 44d8020..19838c9 100644
--- a/fingerprintd/IFingerprintDaemonCallback.cpp
+++ b/fingerprintd/IFingerprintDaemonCallback.cpp
@@ -74,13 +74,13 @@
return remote()->transact(ON_REMOVED, data, &reply, IBinder::FLAG_ONEWAY);
}
- virtual status_t onEnumerate(int64_t devId, const int32_t* fpIds, const int32_t* gpIds,
- int32_t sz) {
+ virtual status_t onEnumerate(int64_t devId, int32_t fpId, int32_t gpId, int32_t rem) {
Parcel data, reply;
data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor());
data.writeInt64(devId);
- data.writeInt32Array(sz, fpIds);
- data.writeInt32Array(sz, gpIds);
+ data.writeInt32(fpId);
+ data.writeInt32(gpId);
+ data.writeInt32(rem);
return remote()->transact(ON_ENUMERATE, data, &reply, IBinder::FLAG_ONEWAY);
}
};
diff --git a/fingerprintd/IFingerprintDaemonCallback.h b/fingerprintd/IFingerprintDaemonCallback.h
index 6e32213..e343cb4 100644
--- a/fingerprintd/IFingerprintDaemonCallback.h
+++ b/fingerprintd/IFingerprintDaemonCallback.h
@@ -44,8 +44,7 @@
virtual status_t onAuthenticated(int64_t devId, int32_t fingerId, int32_t groupId) = 0;
virtual status_t onError(int64_t devId, int32_t error) = 0;
virtual status_t onRemoved(int64_t devId, int32_t fingerId, int32_t groupId) = 0;
- virtual status_t onEnumerate(int64_t devId, const int32_t* fpIds, const int32_t* gpIds,
- int32_t sz) = 0;
+ virtual status_t onEnumerate(int64_t devId, int32_t fingerId, int32_t groupId, int32_t rem) = 0;
DECLARE_META_INTERFACE(FingerprintDaemonCallback);
};
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 02aff55..2d28b76 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -101,6 +101,7 @@
char tmpmnt_opts[64] = "errors=remount-ro";
char *e2fsck_argv[] = {
E2FSCK_BIN,
+ "-f",
"-y",
blk_device
};
@@ -439,12 +440,32 @@
return ret;
}
+static bool needs_block_encryption(const struct fstab_rec* rec)
+{
+ if (device_is_force_encrypted() && fs_mgr_is_encryptable(rec)) return true;
+ if (rec->fs_mgr_flags & MF_FORCECRYPT) return true;
+ if (rec->fs_mgr_flags & MF_CRYPT) {
+ /* Check for existence of convert_fde breadcrumb file */
+ char convert_fde_name[PATH_MAX];
+ snprintf(convert_fde_name, sizeof(convert_fde_name),
+ "%s/misc/vold/convert_fde", rec->mount_point);
+ if (access(convert_fde_name, F_OK) == 0) return true;
+ }
+ if (rec->fs_mgr_flags & MF_FORCEFDEORFBE) {
+ /* Check for absence of convert_fbe breadcrumb file */
+ char convert_fbe_name[PATH_MAX];
+ snprintf(convert_fbe_name, sizeof(convert_fbe_name),
+ "%s/convert_fbe", rec->mount_point);
+ if (access(convert_fbe_name, F_OK) != 0) return true;
+ }
+ return false;
+}
+
// Check to see if a mountable volume has encryption requirements
-static int handle_encryptable(struct fstab *fstab, const struct fstab_rec* rec)
+static int handle_encryptable(const struct fstab_rec* rec)
{
/* If this is block encryptable, need to trigger encryption */
- if ( (rec->fs_mgr_flags & MF_FORCECRYPT)
- || (device_is_force_encrypted() && fs_mgr_is_encryptable(rec))) {
+ if (needs_block_encryption(rec)) {
if (umount(rec->mount_point) == 0) {
return FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION;
} else {
@@ -452,48 +473,15 @@
rec->mount_point, strerror(errno));
return FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
}
- }
-
+ } else if (rec->fs_mgr_flags & (MF_FILEENCRYPTION | MF_FORCEFDEORFBE)) {
// Deal with file level encryption
- if (rec->fs_mgr_flags & MF_FILEENCRYPTION) {
- // Default or not yet initialized encryption requires no more work here
- if (!e4crypt_non_default_key(rec->mount_point)) {
- INFO("%s is default file encrypted\n", rec->mount_point);
- return FS_MGR_MNTALL_DEV_DEFAULT_FILE_ENCRYPTED;
- }
-
- INFO("%s is non-default file encrypted\n", rec->mount_point);
-
- // Uses non-default key, so must unmount and set up temp file system
- if (umount(rec->mount_point)) {
- ERROR("Failed to umount %s - rebooting\n", rec->mount_point);
- return FS_MGR_MNTALL_FAIL;
- }
-
- if (fs_mgr_do_tmpfs_mount(rec->mount_point) != 0) {
- ERROR("Failed to mount a tmpfs at %s\n", rec->mount_point);
- return FS_MGR_MNTALL_FAIL;
- }
-
- // Mount data temporarily so we can access unencrypted dir
- char tmp_mnt[PATH_MAX];
- strlcpy(tmp_mnt, rec->mount_point, sizeof(tmp_mnt));
- strlcat(tmp_mnt, "/tmp_mnt", sizeof(tmp_mnt));
- if (mkdir(tmp_mnt, 0700)) {
- ERROR("Failed to create temp mount point\n");
- return FS_MGR_MNTALL_FAIL;
- }
-
- if (fs_mgr_do_mount(fstab, rec->mount_point,
- rec->blk_device, tmp_mnt)) {
- ERROR("Error temp mounting encrypted file system\n");
- return FS_MGR_MNTALL_FAIL;
- }
-
- return FS_MGR_MNTALL_DEV_NON_DEFAULT_FILE_ENCRYPTED;
+ INFO("%s is file encrypted\n", rec->mount_point);
+ return FS_MGR_MNTALL_DEV_FILE_ENCRYPTED;
+ } else if (fs_mgr_is_encryptable(rec)) {
+ return FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
+ } else {
+ return FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE;
}
-
- return FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
}
/* When multiple fstab records share the same mount_point, it will
@@ -504,7 +492,7 @@
int fs_mgr_mount_all(struct fstab *fstab)
{
int i = 0;
- int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
+ int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE;
int error_count = 0;
int mret = -1;
int mount_errno = 0;
@@ -568,15 +556,15 @@
/* Deal with encryptability. */
if (!mret) {
- int status = handle_encryptable(fstab, &fstab->recs[attempted_idx]);
+ int status = handle_encryptable(&fstab->recs[attempted_idx]);
if (status == FS_MGR_MNTALL_FAIL) {
/* Fatal error - no point continuing */
return status;
}
- if (status != FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
- if (encryptable != FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
+ if (status != FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
+ if (encryptable != FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
// Log and continue
ERROR("Only one encryptable/encrypted partition supported\n");
}
@@ -881,7 +869,8 @@
if (fstab->recs[i].fs_mgr_flags & MF_VOLDMANAGED) {
continue;
}
- if (!(fstab->recs[i].fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT))) {
+ if (!(fstab->recs[i].fs_mgr_flags
+ & (MF_CRYPT | MF_FORCECRYPT | MF_FORCEFDEORFBE))) {
continue;
}
diff --git a/fs_mgr/fs_mgr_format.c b/fs_mgr/fs_mgr_format.c
index c63ff67..0b52e00 100644
--- a/fs_mgr/fs_mgr_format.c
+++ b/fs_mgr/fs_mgr_format.c
@@ -52,7 +52,7 @@
info.len = (off64_t)dev_sz;
/* Use make_ext4fs_internal to avoid wiping an already-wiped partition. */
- rc = make_ext4fs_internal(fd, NULL, NULL, fs_mnt_point, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
+ rc = make_ext4fs_internal(fd, NULL, NULL, fs_mnt_point, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL);
if (rc) {
ERROR("make_ext4fs returned %d.\n", rc);
}
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index cf35b3f..c8c624d 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -64,6 +64,7 @@
{ "encryptable=",MF_CRYPT },
{ "forceencrypt=",MF_FORCECRYPT },
{ "fileencryption",MF_FILEENCRYPTION },
+ { "forcefdeorfbe=",MF_FORCEFDEORFBE },
{ "nonremovable",MF_NONREMOVABLE },
{ "voldmanaged=",MF_VOLDMANAGED},
{ "length=", MF_LENGTH },
@@ -140,6 +141,11 @@
* location of the keys. Get it and return it.
*/
flag_vals->key_loc = strdup(strchr(p, '=') + 1);
+ } else if ((fl[i].flag == MF_FORCEFDEORFBE) && flag_vals) {
+ /* The forcefdeorfbe flag is followed by an = and the
+ * location of the keys. Get it and return it.
+ */
+ flag_vals->key_loc = 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.
@@ -464,7 +470,7 @@
int fs_mgr_is_encryptable(const struct fstab_rec *fstab)
{
- return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT);
+ return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT | MF_FORCEFDEORFBE);
}
int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab)
@@ -472,6 +478,11 @@
return fstab->fs_mgr_flags & MF_FILEENCRYPTION;
}
+int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab)
+{
+ return fstab->fs_mgr_flags & MF_FORCEFDEORFBE;
+}
+
int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index ba0e097..181b6cd 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -82,6 +82,7 @@
#define MF_FILEENCRYPTION 0x2000
#define MF_FORMATTABLE 0x4000
#define MF_SLOTSELECT 0x8000
+#define MF_FORCEFDEORFBE 0x10000
#define DM_BUF_SIZE 4096
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 27fccf7..0404dbd 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -74,12 +74,12 @@
struct fstab *fs_mgr_read_fstab(const char *fstab_path);
void fs_mgr_free_fstab(struct fstab *fstab);
-#define FS_MGR_MNTALL_DEV_NON_DEFAULT_FILE_ENCRYPTED 5
-#define FS_MGR_MNTALL_DEV_DEFAULT_FILE_ENCRYPTED 4
-#define FS_MGR_MNTALL_DEV_NEEDS_RECOVERY 3
-#define FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION 2
-#define FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED 1
-#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 0
+#define FS_MGR_MNTALL_DEV_FILE_ENCRYPTED 5
+#define FS_MGR_MNTALL_DEV_NEEDS_RECOVERY 4
+#define FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION 3
+#define FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED 2
+#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 1
+#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE 0
#define FS_MGR_MNTALL_FAIL -1
int fs_mgr_mount_all(struct fstab *fstab);
@@ -102,6 +102,7 @@
int fs_mgr_is_verified(const struct fstab_rec *fstab);
int fs_mgr_is_encryptable(const struct fstab_rec *fstab);
int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab);
+int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab);
int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab);
int fs_mgr_is_notrim(struct fstab_rec *fstab);
int fs_mgr_is_formattable(struct fstab_rec *fstab);
diff --git a/gatekeeperd/tests/gatekeeper_test.cpp b/gatekeeperd/tests/gatekeeper_test.cpp
index c504f92..47a8bfa 100644
--- a/gatekeeperd/tests/gatekeeper_test.cpp
+++ b/gatekeeperd/tests/gatekeeper_test.cpp
@@ -18,9 +18,8 @@
#include <iostream>
#include <gtest/gtest.h>
-#include <UniquePtr.h>
-
#include <hardware/hw_auth_token.h>
+#include <UniquePtr.h>
#include "../SoftGateKeeper.h"
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index b33dd28..8fb58dc 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -40,6 +40,8 @@
#define FAKE_BATTERY_CAPACITY 42
#define FAKE_BATTERY_TEMPERATURE 424
#define ALWAYS_PLUGGED_CAPACITY 100
+#define MILLION 1.0e6
+#define DEFAULT_VBUS_VOLTAGE 5000000
namespace android {
@@ -62,6 +64,7 @@
props->chargerUsbOnline = false;
props->chargerWirelessOnline = false;
props->maxChargingCurrent = 0;
+ props->maxChargingVoltage = 0;
props->batteryStatus = BATTERY_STATUS_UNKNOWN;
props->batteryHealth = BATTERY_HEALTH_UNKNOWN;
props->batteryPresent = false;
@@ -255,6 +258,7 @@
props.batteryTechnology = String8(buf);
unsigned int i;
+ double MaxPower = 0;
for (i = 0; i < mChargerNames.size(); i++) {
String8 path;
@@ -283,11 +287,23 @@
path.clear();
path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH,
mChargerNames[i].string());
- if (access(path.string(), R_OK) == 0) {
- int maxChargingCurrent = getIntField(path);
- if (props.maxChargingCurrent < maxChargingCurrent) {
- props.maxChargingCurrent = maxChargingCurrent;
- }
+ int ChargingCurrent =
+ (access(path.string(), R_OK) == 0) ? getIntField(path) : 0;
+
+ path.clear();
+ path.appendFormat("%s/%s/voltage_max", POWER_SUPPLY_SYSFS_PATH,
+ mChargerNames[i].string());
+
+ int ChargingVoltage =
+ (access(path.string(), R_OK) == 0) ? getIntField(path) :
+ DEFAULT_VBUS_VOLTAGE;
+
+ double power = ((double)ChargingCurrent / MILLION) *
+ ((double)ChargingVoltage / MILLION);
+ if (MaxPower < power) {
+ props.maxChargingCurrent = ChargingCurrent;
+ props.maxChargingVoltage = ChargingVoltage;
+ MaxPower = power;
}
}
}
@@ -416,9 +432,10 @@
int v;
char vs[128];
- snprintf(vs, sizeof(vs), "ac: %d usb: %d wireless: %d current_max: %d\n",
+ snprintf(vs, sizeof(vs), "ac: %d usb: %d wireless: %d current_max: %d voltage_max: %d\n",
props.chargerAcOnline, props.chargerUsbOnline,
- props.chargerWirelessOnline, props.maxChargingCurrent);
+ props.chargerWirelessOnline, props.maxChargingCurrent,
+ props.maxChargingVoltage);
write(fd, vs, strlen(vs));
snprintf(vs, sizeof(vs), "status: %d health: %d present: %d\n",
props.batteryStatus, props.batteryHealth, props.batteryPresent);
@@ -641,7 +658,7 @@
KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n");
if (mHealthdConfig->batteryTechnologyPath.isEmpty())
KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n");
- if (mHealthdConfig->batteryCurrentNowPath.isEmpty())
+ if (mHealthdConfig->batteryCurrentNowPath.isEmpty())
KLOG_WARNING(LOG_TAG, "BatteryCurrentNowPath not found\n");
if (mHealthdConfig->batteryFullChargePath.isEmpty())
KLOG_WARNING(LOG_TAG, "BatteryFullChargePath not found\n");
diff --git a/include/cutils/fs.h b/include/cutils/fs.h
index 70f0b92..be9e819 100644
--- a/include/cutils/fs.h
+++ b/include/cutils/fs.h
@@ -40,11 +40,18 @@
#endif
/*
- * Ensure that directory exists with given mode and owners.
+ * Ensure that directory exists with given mode and owners. If it exists
+ * with a different mode or owners, they are fixed to match the given values.
*/
extern int fs_prepare_dir(const char* path, mode_t mode, uid_t uid, gid_t gid);
/*
+ * Ensure that directory exists with given mode and owners. If it exists
+ * with different owners, they are not fixed and -1 is returned.
+ */
+extern int fs_prepare_dir_strict(const char* path, mode_t mode, uid_t uid, gid_t gid);
+
+/*
* Read single plaintext integer from given file, correctly handling files
* partially written with fs_write_atomic_int().
*/
diff --git a/include/cutils/multiuser.h b/include/cutils/multiuser.h
index 635ddb1..7e7f815 100644
--- a/include/cutils/multiuser.h
+++ b/include/cutils/multiuser.h
@@ -26,6 +26,8 @@
// NOTE: keep in sync with android.os.UserId
#define MULTIUSER_APP_PER_USER_RANGE 100000
+#define MULTIUSER_FIRST_SHARED_APPLICATION_GID 50000
+#define MULTIUSER_FIRST_APPLICATION_UID 10000
typedef uid_t userid_t;
typedef uid_t appid_t;
@@ -33,6 +35,7 @@
extern userid_t multiuser_get_user_id(uid_t uid);
extern appid_t multiuser_get_app_id(uid_t uid);
extern uid_t multiuser_get_uid(userid_t userId, appid_t appId);
+extern appid_t multiuser_get_shared_app_gid(uid_t uid);
#ifdef __cplusplus
}
diff --git a/include/cutils/sched_policy.h b/include/cutils/sched_policy.h
index 6a8d570..591bd44 100644
--- a/include/cutils/sched_policy.h
+++ b/include/cutils/sched_policy.h
@@ -29,6 +29,7 @@
SP_SYSTEM = 2, // can't be used with set_sched_policy()
SP_AUDIO_APP = 3,
SP_AUDIO_SYS = 4,
+ SP_TOP_APP = 5,
SP_CNT,
SP_MAX = SP_CNT - 1,
SP_SYSTEM_DEFAULT = SP_FOREGROUND,
diff --git a/include/system/graphics.h b/include/system/graphics.h
index cf2d7de..880cb9f 100644
--- a/include/system/graphics.h
+++ b/include/system/graphics.h
@@ -17,6 +17,7 @@
#ifndef SYSTEM_CORE_INCLUDE_ANDROID_GRAPHICS_H
#define SYSTEM_CORE_INCLUDE_ANDROID_GRAPHICS_H
+#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
@@ -552,6 +553,37 @@
* which describes both gamma curve and numeric range (within the bit depth).
*
* Other dataspaces include depth measurement data from a depth camera.
+ *
+ * A dataspace is comprised of a number of fields.
+ *
+ * Version
+ * --------
+ * The top 2 bits represent the revision of the field specification. This is
+ * currently always 0.
+ *
+ *
+ * bits 31-30 29 - 0
+ * +-----+----------------------------------------------------+
+ * fields | Rev | Revision specific fields |
+ * +-----+----------------------------------------------------+
+ *
+ * Field layout for version = 0:
+ * ----------------------------
+ *
+ * A dataspace is comprised of the following fields:
+ * Standard
+ * Transfer function
+ * Range
+ *
+ * bits 31-30 29-27 26 - 22 21 - 16 15 - 0
+ * +-----+-----+--------+--------+----------------------------+
+ * fields | 0 |Range|Transfer|Standard| Legacy and custom |
+ * +-----+-----+--------+--------+----------------------------+
+ * VV RRR TTTTT SSSSSS LLLLLLLL LLLLLLLL
+ *
+ * If range, transfer and standard fields are all 0 (e.g. top 16 bits are
+ * all zeroes), the bottom 16 bits contain either a legacy dataspace value,
+ * or a custom value.
*/
typedef enum android_dataspace {
@@ -580,14 +612,309 @@
HAL_DATASPACE_ARBITRARY = 0x1,
/*
- * RGB Colorspaces
- * -----------------
+ * Color-description aspects
*
- * Primaries are given using (x,y) coordinates in the CIE 1931 definition
- * of x and y specified by ISO 11664-1.
+ * The following aspects define various characteristics of the color
+ * specification. These represent bitfields, so that a data space value
+ * can specify each of them independently.
+ */
+
+ HAL_DATASPACE_STANDARD_SHIFT = 16,
+
+ /*
+ * Standard aspect
+ *
+ * Defines the chromaticity coordinates of the source primaries in terms of
+ * the CIE 1931 definition of x and y specified in ISO 11664-1.
+ */
+ HAL_DATASPACE_STANDARD_MASK = 63 << HAL_DATASPACE_STANDARD_SHIFT, // 0x3F
+
+ /*
+ * Chromacity coordinates are unknown or are determined by the application.
+ * Implementations shall use the following suggested standards:
+ *
+ * All YCbCr formats: BT709 if size is 720p or larger (since most video
+ * content is letterboxed this corresponds to width is
+ * 1280 or greater, or height is 720 or greater).
+ * BT601_625 if size is smaller than 720p or is JPEG.
+ * All RGB formats: BT709.
+ *
+ * For all other formats standard is undefined, and implementations should use
+ * an appropriate standard for the data represented.
+ */
+ HAL_DATASPACE_STANDARD_UNSPECIFIED = 0 << HAL_DATASPACE_STANDARD_SHIFT,
+
+ /*
+ * Primaries: x y
+ * green 0.300 0.600
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ *
+ * Use the unadjusted KR = 0.2126, KB = 0.0722 luminance interpretation
+ * for RGB conversion.
+ */
+ HAL_DATASPACE_STANDARD_BT709 = 1 << HAL_DATASPACE_STANDARD_SHIFT,
+
+ /*
+ * Primaries: x y
+ * green 0.290 0.600
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ *
+ * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
+ * for RGB conversion from the one purely determined by the primaries
+ * to minimize the color shift into RGB space that uses BT.709
+ * primaries.
+ */
+ HAL_DATASPACE_STANDARD_BT601_625 = 2 << HAL_DATASPACE_STANDARD_SHIFT,
+
+ /*
+ * Primaries: x y
+ * green 0.290 0.600
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ *
+ * Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation
+ * for RGB conversion.
+ */
+ HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED = 3 << HAL_DATASPACE_STANDARD_SHIFT,
+
+ /*
+ * Primaries: x y
+ * green 0.310 0.595
+ * blue 0.155 0.070
+ * red 0.630 0.340
+ * white (D65) 0.3127 0.3290
+ *
+ * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
+ * for RGB conversion from the one purely determined by the primaries
+ * to minimize the color shift into RGB space that uses BT.709
+ * primaries.
+ */
+ HAL_DATASPACE_STANDARD_BT601_525 = 4 << HAL_DATASPACE_STANDARD_SHIFT,
+
+ /*
+ * Primaries: x y
+ * green 0.310 0.595
+ * blue 0.155 0.070
+ * red 0.630 0.340
+ * white (D65) 0.3127 0.3290
+ *
+ * Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation
+ * for RGB conversion (as in SMPTE 240M).
+ */
+ HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED = 5 << HAL_DATASPACE_STANDARD_SHIFT,
+
+ /*
+ * Primaries: x y
+ * green 0.170 0.797
+ * blue 0.131 0.046
+ * red 0.708 0.292
+ * white (D65) 0.3127 0.3290
+ *
+ * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
+ * for RGB conversion.
+ */
+ HAL_DATASPACE_STANDARD_BT2020 = 6 << HAL_DATASPACE_STANDARD_SHIFT,
+
+ /*
+ * Primaries: x y
+ * green 0.170 0.797
+ * blue 0.131 0.046
+ * red 0.708 0.292
+ * white (D65) 0.3127 0.3290
+ *
+ * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
+ * for RGB conversion using the linear domain.
+ */
+ HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE = 7 << HAL_DATASPACE_STANDARD_SHIFT,
+
+ /*
+ * Primaries: x y
+ * green 0.21 0.71
+ * blue 0.14 0.08
+ * red 0.67 0.33
+ * white (C) 0.310 0.316
+ *
+ * Use the unadjusted KR = 0.30, KB = 0.11 luminance interpretation
+ * for RGB conversion.
+ */
+ HAL_DATASPACE_STANDARD_BT470M = 8 << HAL_DATASPACE_STANDARD_SHIFT,
+
+ /*
+ * Primaries: x y
+ * green 0.243 0.692
+ * blue 0.145 0.049
+ * red 0.681 0.319
+ * white (C) 0.310 0.316
+ *
+ * Use the unadjusted KR = 0.254, KB = 0.068 luminance interpretation
+ * for RGB conversion.
+ */
+ HAL_DATASPACE_STANDARD_FILM = 9 << HAL_DATASPACE_STANDARD_SHIFT,
+
+ HAL_DATASPACE_TRANSFER_SHIFT = 22,
+
+ /*
+ * Transfer aspect
*
* Transfer characteristics are the opto-electronic transfer characteristic
* at the source as a function of linear optical intensity (luminance).
+ *
+ * For digital signals, E corresponds to the recorded value. Normally, the
+ * transfer function is applied in RGB space to each of the R, G and B
+ * components independently. This may result in color shift that can be
+ * minized by applying the transfer function in Lab space only for the L
+ * component. Implementation may apply the transfer function in RGB space
+ * for all pixel formats if desired.
+ */
+
+ HAL_DATASPACE_TRANSFER_MASK = 31 << HAL_DATASPACE_TRANSFER_SHIFT, // 0x1F
+
+ /*
+ * Transfer characteristics are unknown or are determined by the
+ * application.
+ *
+ * Implementations should use the following transfer functions:
+ *
+ * For YCbCr formats: use HAL_DATASPACE_TRANSFER_SMPTE_170M
+ * For RGB formats: use HAL_DATASPACE_TRANSFER_SRGB
+ *
+ * For all other formats transfer function is undefined, and implementations
+ * should use an appropriate standard for the data represented.
+ */
+ HAL_DATASPACE_TRANSFER_UNSPECIFIED = 0 << HAL_DATASPACE_TRANSFER_SHIFT,
+
+ /*
+ * Transfer characteristic curve:
+ * E = L
+ * L - luminance of image 0 <= L <= 1 for conventional colorimetry
+ * E - corresponding electrical signal
+ */
+ HAL_DATASPACE_TRANSFER_LINEAR = 1 << HAL_DATASPACE_TRANSFER_SHIFT,
+
+ /*
+ * Transfer characteristic curve:
+ *
+ * E = 1.055 * L^(1/2.4) - 0.055 for 0.0031308 <= L <= 1
+ * = 12.92 * L for 0 <= L < 0.0031308
+ * L - luminance of image 0 <= L <= 1 for conventional colorimetry
+ * E - corresponding electrical signal
+ */
+ HAL_DATASPACE_TRANSFER_SRGB = 2 << HAL_DATASPACE_TRANSFER_SHIFT,
+
+ /*
+ * BT.601 525, BT.601 625, BT.709, BT.2020
+ *
+ * Transfer characteristic curve:
+ * E = 1.099 * L ^ 0.45 - 0.099 for 0.018 <= L <= 1
+ * = 4.500 * L for 0 <= L < 0.018
+ * L - luminance of image 0 <= L <= 1 for conventional colorimetry
+ * E - corresponding electrical signal
+ */
+ HAL_DATASPACE_TRANSFER_SMPTE_170M = 3 << HAL_DATASPACE_TRANSFER_SHIFT,
+
+ /*
+ * Assumed display gamma 2.2.
+ *
+ * Transfer characteristic curve:
+ * E = L ^ (1/2.2)
+ * L - luminance of image 0 <= L <= 1 for conventional colorimetry
+ * E - corresponding electrical signal
+ */
+ HAL_DATASPACE_TRANSFER_GAMMA2_2 = 4 << HAL_DATASPACE_TRANSFER_SHIFT,
+
+ /*
+ * display gamma 2.8.
+ *
+ * Transfer characteristic curve:
+ * E = L ^ (1/2.8)
+ * L - luminance of image 0 <= L <= 1 for conventional colorimetry
+ * E - corresponding electrical signal
+ */
+ HAL_DATASPACE_TRANSFER_GAMMA2_8 = 5 << HAL_DATASPACE_TRANSFER_SHIFT,
+
+ /*
+ * SMPTE ST 2084
+ *
+ * Transfer characteristic curve:
+ * E = ((c1 + c2 * L^n) / (1 + c3 * L^n)) ^ m
+ * c1 = c3 - c2 + 1 = 3424 / 4096 = 0.8359375
+ * c2 = 32 * 2413 / 4096 = 18.8515625
+ * c3 = 32 * 2392 / 4096 = 18.6875
+ * m = 128 * 2523 / 4096 = 78.84375
+ * n = 0.25 * 2610 / 4096 = 0.1593017578125
+ * L - luminance of image 0 <= L <= 1 for HDR colorimetry.
+ * L = 1 corresponds to 10000 cd/m2
+ * E - corresponding electrical signal
+ */
+ HAL_DATASPACE_TRANSFER_ST2084 = 6 << HAL_DATASPACE_TRANSFER_SHIFT,
+
+ /*
+ * ARIB STD-B67 Hybrid Log Gamma
+ *
+ * Transfer characteristic curve:
+ * E = r * L^0.5 for 0 <= L <= 1
+ * = a * ln(L - b) + c for 1 < L
+ * a = 0.17883277
+ * b = 0.28466892
+ * c = 0.55991073
+ * r = 0.5
+ * L - luminance of image 0 <= L for HDR colorimetry. L = 1 corresponds
+ * to reference white level of 100 cd/m2
+ * E - corresponding electrical signal
+ */
+ HAL_DATASPACE_TRANSFER_HLG = 7 << HAL_DATASPACE_TRANSFER_SHIFT,
+
+ HAL_DATASPACE_RANGE_SHIFT = 27,
+
+ /*
+ * Range aspect
+ *
+ * Defines the range of values corresponding to the unit range of 0-1.
+ * This is defined for YCbCr only, but can be expanded to RGB space.
+ */
+ HAL_DATASPACE_RANGE_MASK = 7 << HAL_DATASPACE_RANGE_SHIFT, // 0x7
+
+ /*
+ * Range is unknown or are determined by the application. Implementations
+ * shall use the following suggested ranges:
+ *
+ * All YCbCr formats: limited range.
+ * All RGB or RGBA formats (including RAW and Bayer): full range.
+ * All Y formats: full range
+ *
+ * For all other formats range is undefined, and implementations should use
+ * an appropriate range for the data represented.
+ */
+ HAL_DATASPACE_RANGE_UNSPECIFIED = 0 << HAL_DATASPACE_RANGE_SHIFT,
+
+ /*
+ * Full range uses all values for Y, Cb and Cr from
+ * 0 to 2^b-1, where b is the bit depth of the color format.
+ */
+ HAL_DATASPACE_RANGE_FULL = 1 << HAL_DATASPACE_RANGE_SHIFT,
+
+ /*
+ * Limited range uses values 16/256*2^b to 235/256*2^b for Y, and
+ * 1/16*2^b to 15/16*2^b for Cb, Cr, R, G and B, where b is the bit depth of
+ * the color format.
+ *
+ * E.g. For 8-bit-depth formats:
+ * Luma (Y) samples should range from 16 to 235, inclusive
+ * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
+ *
+ * For 10-bit-depth formats:
+ * Luma (Y) samples should range from 64 to 940, inclusive
+ * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
+ */
+ HAL_DATASPACE_RANGE_LIMITED = 2 << HAL_DATASPACE_RANGE_SHIFT,
+
+ /*
+ * Legacy dataspaces
*/
/*
@@ -600,34 +927,30 @@
* The values are encoded using the full range ([0,255] for 8-bit) for all
* components.
*/
- HAL_DATASPACE_SRGB_LINEAR = 0x200,
+ HAL_DATASPACE_SRGB_LINEAR = 0x200, // deprecated, use HAL_DATASPACE_V0_SRGB_LINEAR
+
+ HAL_DATASPACE_V0_SRGB_LINEAR = HAL_DATASPACE_STANDARD_BT709 |
+ HAL_DATASPACE_TRANSFER_LINEAR | HAL_DATASPACE_RANGE_FULL,
+
/*
* sRGB gamma encoding:
*
* The red, green and blue components are stored in sRGB space, and
- * converted to linear space when read, using the standard sRGB to linear
- * equation:
- *
- * Clinear = Csrgb / 12.92 for Csrgb <= 0.04045
- * = (Csrgb + 0.055 / 1.055)^2.4 for Csrgb > 0.04045
- *
- * When written the inverse transformation is performed:
- *
- * Csrgb = 12.92 * Clinear for Clinear <= 0.0031308
- * = 1.055 * Clinear^(1/2.4) - 0.055 for Clinear > 0.0031308
- *
+ * converted to linear space when read, using the SRGB transfer function
+ * for each of the R, G and B components. When written, the inverse
+ * transformation is performed.
*
* The alpha component, if present, is always stored in linear space and
* is left unmodified when read or written.
*
- * The RGB primaries and the white point are the same as BT.709.
- *
- * The values are encoded using the full range ([0,255] for 8-bit) for all
- * components.
- *
+ * Use full range and BT.709 standard.
*/
- HAL_DATASPACE_SRGB = 0x201,
+ HAL_DATASPACE_SRGB = 0x201, // deprecated, use HAL_DATASPACE_V0_SRGB
+
+ HAL_DATASPACE_V0_SRGB = HAL_DATASPACE_STANDARD_BT709 |
+ HAL_DATASPACE_TRANSFER_SRGB | HAL_DATASPACE_RANGE_FULL,
+
/*
* YCbCr Colorspaces
@@ -645,94 +968,53 @@
*
* Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255
*
- * Transfer characteristic curve:
- * E = 1.099 * L ^ 0.45 - 0.099, 1.00 >= L >= 0.018
- * E = 4.500 L, 0.018 > L >= 0
- * L - luminance of image 0 <= L <= 1 for conventional colorimetry
- * E - corresponding electrical signal
- *
- * Primaries: x y
- * green 0.290 0.600
- * blue 0.150 0.060
- * red 0.640 0.330
- * white (D65) 0.3127 0.3290
+ * Use full range, BT.601 transfer and BT.601_625 standard.
*/
- HAL_DATASPACE_JFIF = 0x101,
+ HAL_DATASPACE_JFIF = 0x101, // deprecated, use HAL_DATASPACE_V0_JFIF
+
+ HAL_DATASPACE_V0_JFIF = HAL_DATASPACE_STANDARD_BT601_625 |
+ HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_FULL,
/*
* ITU-R Recommendation 601 (BT.601) - 625-line
*
* Standard-definition television, 625 Lines (PAL)
*
- * For 8-bit-depth formats:
- * Luma (Y) samples should range from 16 to 235, inclusive
- * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
- *
- * For 10-bit-depth formats:
- * Luma (Y) samples should range from 64 to 940, inclusive
- * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
- *
- * Transfer characteristic curve:
- * E = 1.099 * L ^ 0.45 - 0.099, 1.00 >= L >= 0.018
- * E = 4.500 L, 0.018 > L >= 0
- * L - luminance of image 0 <= L <= 1 for conventional colorimetry
- * E - corresponding electrical signal
- *
- * Primaries: x y
- * green 0.290 0.600
- * blue 0.150 0.060
- * red 0.640 0.330
- * white (D65) 0.3127 0.3290
+ * Use limited range, BT.601 transfer and BT.601_625 standard.
*/
- HAL_DATASPACE_BT601_625 = 0x102,
+ HAL_DATASPACE_BT601_625 = 0x102, // deprecated, use HAL_DATASPACE_V0_BT601_625
+
+ HAL_DATASPACE_V0_BT601_625 = HAL_DATASPACE_STANDARD_BT601_625 |
+ HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_LIMITED,
+
/*
* ITU-R Recommendation 601 (BT.601) - 525-line
*
* Standard-definition television, 525 Lines (NTSC)
*
- * For 8-bit-depth formats:
- * Luma (Y) samples should range from 16 to 235, inclusive
- * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
- *
- * For 10-bit-depth formats:
- * Luma (Y) samples should range from 64 to 940, inclusive
- * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
- *
- * Transfer characteristic curve:
- * E = 1.099 * L ^ 0.45 - 0.099, 1.00 >= L >= 0.018
- * E = 4.500 L, 0.018 > L >= 0
- * L - luminance of image 0 <= L <= 1 for conventional colorimetry
- * E - corresponding electrical signal
- *
- * Primaries: x y
- * green 0.310 0.595
- * blue 0.155 0.070
- * red 0.630 0.340
- * white (D65) 0.3127 0.3290
+ * Use limited range, BT.601 transfer and BT.601_525 standard.
*/
- HAL_DATASPACE_BT601_525 = 0x103,
+ HAL_DATASPACE_BT601_525 = 0x103, // deprecated, use HAL_DATASPACE_V0_BT601_525
+
+ HAL_DATASPACE_V0_BT601_525 = HAL_DATASPACE_STANDARD_BT601_525 |
+ HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_LIMITED,
/*
* ITU-R Recommendation 709 (BT.709)
*
* High-definition television
*
- * For 8-bit-depth formats:
- * Luma (Y) samples should range from 16 to 235, inclusive
- * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
- *
- * For 10-bit-depth formats:
- * Luma (Y) samples should range from 64 to 940, inclusive
- * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
- *
- * Primaries: x y
- * green 0.300 0.600
- * blue 0.150 0.060
- * red 0.640 0.330
- * white (D65) 0.3127 0.3290
+ * Use limited range, BT.709 transfer and BT.709 standard.
*/
- HAL_DATASPACE_BT709 = 0x104,
+ HAL_DATASPACE_BT709 = 0x104, // deprecated, use HAL_DATASPACE_V0_BT709
+
+ HAL_DATASPACE_V0_BT709 = HAL_DATASPACE_STANDARD_BT709 |
+ HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_LIMITED,
+
+ /*
+ * Data spaces for non-color formats
+ */
/*
* The buffer contains depth ranging measurements from a depth camera.
diff --git a/include/system/radio.h b/include/system/radio.h
index a088526..9e291c8 100644
--- a/include/system/radio.h
+++ b/include/system/radio.h
@@ -94,6 +94,7 @@
radio_rds_t rds; /* RDS variants supported */
bool ta; /* Traffic Announcement supported */
bool af; /* Alternate Frequency supported */
+ bool ea; /* Emergency announcements supported */
} radio_hal_fm_band_config_t;
/* Additional attributes for an AM band configuration */
@@ -184,6 +185,7 @@
RADIO_EVENT_METADATA = 4, /* New meta data received */
RADIO_EVENT_TA = 5, /* Traffic announcement start or stop */
RADIO_EVENT_AF_SWITCH = 6, /* Switch to Alternate Frequency */
+ RADIO_EVENT_EA = 7, /* Emergency announcement start or stop */
// begin framework only events
RADIO_EVENT_CONTROL = 100, /* loss/gain of tuner control */
RADIO_EVENT_SERVER_DIED = 101, /* radio service died */
@@ -195,7 +197,8 @@
radio_event_type_t type; /* event type */
int status; /* used by RADIO_EVENT_CONFIG, RADIO_EVENT_TUNED */
union {
- bool on; /* RADIO_EVENT_ANTENNA, RADIO_EVENT_TA */
+ /* RADIO_EVENT_ANTENNA, RADIO_EVENT_TA, RADIO_EVENT_EA */
+ bool on;
radio_hal_band_config_t config; /* RADIO_EVENT_CONFIG */
radio_program_info_t info; /* RADIO_EVENT_TUNED, RADIO_EVENT_AF_SWITCH */
radio_metadata_t *metadata; /* RADIO_EVENT_METADATA */
diff --git a/include/system/window.h b/include/system/window.h
index 508ce00..1ca093f 100644
--- a/include/system/window.h
+++ b/include/system/window.h
@@ -25,6 +25,7 @@
#include <sys/cdefs.h>
#include <system/graphics.h>
#include <unistd.h>
+#include <stdbool.h>
#ifndef __UNUSED
#define __UNUSED __attribute__((__unused__))
@@ -311,6 +312,8 @@
NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18,
NATIVE_WINDOW_SET_BUFFERS_DATASPACE = 19,
NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */
+ NATIVE_WINDOW_SET_SINGLE_BUFFER_MODE = 21,
+ NATIVE_WINDOW_SET_AUTO_REFRESH = 22,
};
/* parameter for NATIVE_WINDOW_[API_][DIS]CONNECT */
@@ -351,7 +354,8 @@
NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY = 0x08
};
-/* parameter for NATIVE_WINDOW_SET_SCALING_MODE */
+/* 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)
@@ -949,6 +953,29 @@
rects, numRects);
}
+/*
+ * native_window_set_single_buffer_mode(..., bool singleBufferMode)
+ * Enable/disable single buffer mode
+ */
+static inline int native_window_set_single_buffer_mode(
+ struct ANativeWindow* window,
+ bool singleBufferMode)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_SINGLE_BUFFER_MODE,
+ singleBufferMode);
+}
+
+/*
+ * native_window_set_auto_refresh(..., autoRefresh)
+ * Enable/disable auto refresh when in single 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);
+}
+
__END_DECLS
#endif /* SYSTEM_CORE_INCLUDE_ANDROID_WINDOW_H */
diff --git a/include/usbhost/usbhost.h b/include/usbhost/usbhost.h
index 4350ec1..88b5b44 100644
--- a/include/usbhost/usbhost.h
+++ b/include/usbhost/usbhost.h
@@ -219,6 +219,9 @@
int length,
unsigned int timeout);
+/** Reset USB bus for the device */
+int usb_device_reset(struct usb_device *device);
+
/* Creates a new usb_request. */
struct usb_request *usb_request_new(struct usb_device *dev,
const struct usb_endpoint_descriptor *ep_desc);
diff --git a/init/Android.mk b/init/Android.mk
index 66ce8a8..d8b574f 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -89,8 +89,8 @@
libsquashfs_utils \
liblogwrap \
libcutils \
- libbase \
libext4_utils_static \
+ libbase \
libutils \
libc \
libselinux \
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 35f1a9e..2e72832 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -501,16 +501,16 @@
property_set("vold.decrypt", "trigger_default_encryption");
} else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
property_set("ro.crypto.state", "unencrypted");
- /* If fs_mgr determined this is an unencrypted device, then trigger
- * that action.
- */
+ ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
+ } else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
+ property_set("ro.crypto.state", "unsupported");
ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
} else if (ret == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
/* Setup a wipe via recovery, and reboot into recovery */
ERROR("fs_mgr_mount_all suggested recovery, so wiping data via recovery.\n");
ret = wipe_data_via_recovery();
/* If reboot worked, there is no return. */
- } else if (ret == FS_MGR_MNTALL_DEV_DEFAULT_FILE_ENCRYPTED) {
+ } else if (ret == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
if (e4crypt_install_keyring()) {
return -1;
}
@@ -520,13 +520,6 @@
// Although encrypted, we have device key, so we do not need to
// do anything different from the nonencrypted case.
ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
- } else if (ret == FS_MGR_MNTALL_DEV_NON_DEFAULT_FILE_ENCRYPTED) {
- if (e4crypt_install_keyring()) {
- return -1;
- }
- property_set("ro.crypto.state", "encrypted");
- property_set("ro.crypto.type", "file");
- property_set("vold.decrypt", "trigger_restart_min_framework");
} else if (ret > 0) {
ERROR("fs_mgr_mount_all returned unexpected error %d\n", ret);
}
@@ -884,11 +877,8 @@
do_installkeys_ensure_dir_exists);
}
-static int do_setusercryptopolicies(const std::vector<std::string>& args) {
- if (!is_file_crypto()) {
- return 0;
- }
- return e4crypt_set_user_crypto_policies(args[1].c_str());
+static int do_init_user0(const std::vector<std::string>& args) {
+ return e4crypt_do_init_user0();
}
BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
@@ -907,6 +897,7 @@
{"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}},
@@ -923,7 +914,6 @@
{"rmdir", {1, 1, do_rmdir}},
{"setprop", {2, 2, do_setprop}},
{"setrlimit", {3, 3, do_setrlimit}},
- {"setusercryptopolicies", {1, 1, do_setusercryptopolicies}},
{"start", {1, 1, do_start}},
{"stop", {1, 1, do_stop}},
{"swapon_all", {1, 1, do_swapon_all}},
diff --git a/libcutils/fs.c b/libcutils/fs.c
index 45c7add..5e2ef0b 100644
--- a/libcutils/fs.c
+++ b/libcutils/fs.c
@@ -37,7 +37,8 @@
#define ALL_PERMS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
#define BUF_SIZE 64
-int fs_prepare_dir(const char* path, mode_t mode, uid_t uid, gid_t gid) {
+static int fs_prepare_dir_impl(const char* path, mode_t mode, uid_t uid, gid_t gid,
+ int allow_fixup) {
// Check if path needs to be created
struct stat sb;
if (TEMP_FAILURE_RETRY(lstat(path, &sb)) == -1) {
@@ -54,10 +55,22 @@
ALOGE("Not a directory: %s", path);
return -1;
}
- if (((sb.st_mode & ALL_PERMS) == mode) && (sb.st_uid == uid) && (sb.st_gid == gid)) {
+ int owner_match = ((sb.st_uid == uid) && (sb.st_gid == gid));
+ int mode_match = ((sb.st_mode & ALL_PERMS) == mode);
+ if (owner_match && mode_match) {
return 0;
- } else {
+ } else if (allow_fixup) {
goto fixup;
+ } else {
+ if (!owner_match) {
+ ALOGE("Expected path %s with owner %d:%d but found %d:%d",
+ path, uid, gid, sb.st_uid, sb.st_gid);
+ return -1;
+ } else {
+ ALOGW("Expected path %s with mode %o but found %o",
+ path, mode, (sb.st_mode & ALL_PERMS));
+ return 0;
+ }
}
create:
@@ -81,6 +94,14 @@
return 0;
}
+int fs_prepare_dir(const char* path, mode_t mode, uid_t uid, gid_t gid) {
+ return fs_prepare_dir_impl(path, mode, uid, gid, 1);
+}
+
+int fs_prepare_dir_strict(const char* path, mode_t mode, uid_t uid, gid_t gid) {
+ return fs_prepare_dir_impl(path, mode, uid, gid, 0);
+}
+
int fs_read_atomic_int(const char* path, int* out_value) {
int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY));
if (fd == -1) {
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 6d50adc..0abfcbf 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -79,6 +79,7 @@
{ 00500, AID_ROOT, AID_ROOT, 0, "config" },
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" },
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private" },
+ { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-ephemeral" },
{ 00771, AID_ROOT, AID_ROOT, 0, "data/dalvik-cache" },
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/data" },
{ 00771, AID_SHELL, AID_SHELL, 0, "data/local/tmp" },
@@ -117,7 +118,6 @@
{ 00440, AID_ROOT, AID_SHELL, 0, "system/etc/init.goldfish.rc" },
{ 00550, AID_ROOT, AID_SHELL, 0, "system/etc/init.goldfish.sh" },
{ 00550, AID_ROOT, AID_SHELL, 0, "system/etc/init.ril" },
- { 00550, AID_DHCP, AID_SHELL, 0, "system/etc/dhcpcd/dhcpcd-run-hooks" },
{ 00555, AID_ROOT, AID_ROOT, 0, "system/etc/ppp/*" },
{ 00555, AID_ROOT, AID_ROOT, 0, "system/etc/rc.*" },
{ 00440, AID_ROOT, AID_ROOT, 0, "system/etc/recovery.img" },
@@ -126,6 +126,7 @@
{ 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app/*" },
{ 00644, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/*" },
{ 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private/*" },
+ { 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app-ephemeral/*" },
{ 00644, AID_APP, AID_APP, 0, "data/data/*" },
{ 00640, AID_ROOT, AID_SHELL, 0, "data/nativetest/tests.txt" },
{ 00640, AID_ROOT, AID_SHELL, 0, "data/nativetest64/tests.txt" },
diff --git a/libcutils/multiuser.c b/libcutils/multiuser.c
index 7c74bb8..0f4427b 100644
--- a/libcutils/multiuser.c
+++ b/libcutils/multiuser.c
@@ -27,3 +27,9 @@
uid_t multiuser_get_uid(userid_t userId, appid_t appId) {
return userId * MULTIUSER_APP_PER_USER_RANGE + (appId % MULTIUSER_APP_PER_USER_RANGE);
}
+
+appid_t multiuser_get_shared_app_gid(uid_t id) {
+ return MULTIUSER_FIRST_SHARED_APPLICATION_GID + (id % MULTIUSER_APP_PER_USER_RANGE)
+ - MULTIUSER_FIRST_APPLICATION_UID;
+
+}
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index 6bba3a7..1a26695 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -62,8 +62,10 @@
#ifdef USE_CPUSETS
// File descriptors open to /dev/cpuset/../tasks, setup by initialize, or -1 on error
+static int system_bg_cpuset_fd = -1;
static int bg_cpuset_fd = -1;
static int fg_cpuset_fd = -1;
+static int ta_cpuset_fd = -1; // special cpuset for top app
static int bg_schedboost_fd = -1;
static int fg_schedboost_fd = -1;
#endif
@@ -130,15 +132,19 @@
fg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
filename = "/dev/cpuset/background/tasks";
bg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
+ filename = "/dev/cpuset/system-background/tasks";
+ system_bg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
+ filename = "/dev/cpuset/top-app/tasks";
+ ta_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
+
#ifdef USE_SCHEDBOOST
- filename = "/sys/fs/cgroup/stune/foreground/tasks";
+ filename = "/dev/stune/foreground/tasks";
fg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
- filename = "/sys/fs/cgroup/stune/tasks";
+ filename = "/dev/stune/tasks";
bg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
#endif
}
#endif
-
}
/*
@@ -260,8 +266,8 @@
policy = _policy(policy);
pthread_once(&the_once, __initialize);
- int fd;
- int boost_fd;
+ int fd = -1;
+ int boost_fd = -1;
switch (policy) {
case SP_BACKGROUND:
fd = bg_cpuset_fd;
@@ -273,6 +279,14 @@
fd = fg_cpuset_fd;
boost_fd = fg_schedboost_fd;
break;
+ case SP_TOP_APP :
+ fd = ta_cpuset_fd;
+ boost_fd = fg_schedboost_fd;
+ break;
+ case SP_SYSTEM:
+ fd = system_bg_cpuset_fd;
+ boost_fd = bg_schedboost_fd;
+ break;
default:
boost_fd = fd = -1;
break;
@@ -330,6 +344,7 @@
case SP_FOREGROUND:
case SP_AUDIO_APP:
case SP_AUDIO_SYS:
+ case SP_TOP_APP:
SLOGD("^^^ tid %d (%s)", tid, thread_name);
break;
case SP_SYSTEM:
@@ -350,6 +365,7 @@
case SP_FOREGROUND:
case SP_AUDIO_APP:
case SP_AUDIO_SYS:
+ case SP_TOP_APP:
fd = fg_cgroup_fd;
break;
default:
@@ -404,6 +420,7 @@
[SP_SYSTEM] = " ",
[SP_AUDIO_APP] = "aa",
[SP_AUDIO_SYS] = "as",
+ [SP_TOP_APP] = "ta",
};
if ((policy < SP_CNT) && (strings[policy] != NULL))
return strings[policy];
diff --git a/libmemunreachable/Allocator.cpp b/libmemunreachable/Allocator.cpp
index b75f1e5..68f654c 100644
--- a/libmemunreachable/Allocator.cpp
+++ b/libmemunreachable/Allocator.cpp
@@ -370,11 +370,11 @@
}
void* HeapImpl::AllocLocked(size_t size) {
- if (__predict_false(size > kMaxBucketAllocationSize)) {
+ if (size > kMaxBucketAllocationSize) {
return MapAlloc(size);
}
int bucket = size_to_bucket(size);
- if (__predict_false(free_chunks_[bucket].empty())) {
+ if (free_chunks_[bucket].empty()) {
Chunk *chunk = new Chunk(this, bucket);
free_chunks_[bucket].insert(chunk->node_);
}
diff --git a/libmemunreachable/Allocator.h b/libmemunreachable/Allocator.h
index b0a4d4c..a8f579e 100644
--- a/libmemunreachable/Allocator.h
+++ b/libmemunreachable/Allocator.h
@@ -24,6 +24,7 @@
#include <map>
#include <memory>
#include <set>
+#include <unordered_map>
#include <unordered_set>
#include <vector>
extern std::atomic<int> heap_count;
@@ -209,9 +210,12 @@
template<class T>
using list = std::list<T, Allocator<T>>;
-template<class T, class Key, class Compare = std::less<Key>>
+template<class Key, class T, class Compare = std::less<Key>>
using map = std::map<Key, T, Compare, Allocator<std::pair<const Key, T>>>;
+template<class Key, class T, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>>
+using unordered_map = std::unordered_map<Key, T, Hash, KeyEqual, Allocator<std::pair<const Key, T>>>;
+
template<class Key, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>>
using unordered_set = std::unordered_set<Key, Hash, KeyEqual, Allocator<Key>>;
diff --git a/libmemunreachable/Android.mk b/libmemunreachable/Android.mk
index 0df26a8..7b66d44 100644
--- a/libmemunreachable/Android.mk
+++ b/libmemunreachable/Android.mk
@@ -3,6 +3,7 @@
memunreachable_srcs := \
Allocator.cpp \
HeapWalker.cpp \
+ LeakFolding.cpp \
LeakPipe.cpp \
LineBuffer.cpp \
MemUnreachable.cpp \
@@ -12,7 +13,9 @@
memunreachable_test_srcs := \
tests/Allocator_test.cpp \
+ tests/DisableMalloc_test.cpp \
tests/HeapWalker_test.cpp \
+ tests/LeakFolding_test.cpp \
tests/MemUnreachable_test.cpp \
tests/ThreadCapture_test.cpp \
@@ -41,3 +44,22 @@
LOCAL_SHARED_LIBRARIES := libmemunreachable libbase liblog
include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := memunreachable_test
+LOCAL_SRC_FILES := \
+ Allocator.cpp \
+ HeapWalker.cpp \
+ LeakFolding.cpp \
+ tests/Allocator_test.cpp \
+ tests/HeapWalker_test.cpp \
+ tests/HostMallocStub.cpp \
+ tests/LeakFolding_test.cpp \
+
+LOCAL_CFLAGS := -std=c++14 -Wall -Wextra -Werror
+LOCAL_CLANG := true
+LOCAL_SHARED_LIBRARIES := libbase liblog
+LOCAL_MODULE_HOST_OS := linux
+
+include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libmemunreachable/HeapWalker.cpp b/libmemunreachable/HeapWalker.cpp
index 1a0c33d..19393ec 100644
--- a/libmemunreachable/HeapWalker.cpp
+++ b/libmemunreachable/HeapWalker.cpp
@@ -21,17 +21,19 @@
#include "Allocator.h"
#include "HeapWalker.h"
+#include "LeakFolding.h"
#include "log.h"
bool HeapWalker::Allocation(uintptr_t begin, uintptr_t end) {
if (end == begin) {
end = begin + 1;
}
- auto inserted = allocations_.insert(std::pair<Range, RangeInfo>(Range{begin, end}, RangeInfo{false, false}));
+ Range range{begin, end};
+ auto inserted = allocations_.insert(std::pair<Range, AllocationInfo>(range, AllocationInfo{}));
if (inserted.second) {
valid_allocations_range_.begin = std::min(valid_allocations_range_.begin, begin);
valid_allocations_range_.end = std::max(valid_allocations_range_.end, end);
- allocation_bytes_ += end - begin;
+ allocation_bytes_ += range.size();
return true;
} else {
Range overlap = inserted.first->first;
@@ -44,27 +46,30 @@
}
}
-void HeapWalker::Walk(const Range& range, bool RangeInfo::*flag) {
- allocator::vector<Range> to_do(1, range, allocator_);
+bool HeapWalker::IsAllocationPtr(uintptr_t ptr, Range* range, AllocationInfo** info) {
+ if (ptr >= valid_allocations_range_.begin && ptr < valid_allocations_range_.end) {
+ AllocationMap::iterator it = allocations_.find(Range{ptr, ptr + 1});
+ if (it != allocations_.end()) {
+ *range = it->first;
+ *info = &it->second;
+ return true;
+ }
+ }
+ return false;
+}
+
+void HeapWalker::RecurseRoot(const Range& root) {
+ allocator::vector<Range> to_do(1, root, allocator_);
while (!to_do.empty()) {
Range range = to_do.back();
to_do.pop_back();
- uintptr_t begin = (range.begin + (sizeof(uintptr_t) - 1)) & ~(sizeof(uintptr_t) - 1);
- // TODO(ccross): we might need to consider a pointer to the end of a buffer
- // to be inside the buffer, which means the common case of a pointer to the
- // beginning of a buffer may keep two ranges live.
- for (uintptr_t i = begin; i < range.end; i += sizeof(uintptr_t)) {
- uintptr_t val = *reinterpret_cast<uintptr_t*>(i);
- if (val >= valid_allocations_range_.begin && val < valid_allocations_range_.end) {
- RangeMap::iterator it = allocations_.find(Range{val, val + 1});
- if (it != allocations_.end()) {
- if (!(it->second.*flag)) {
- to_do.push_back(it->first);
- it->second.*flag = true;
- }
- }
+
+ ForEachPtrInRange(range, [&](Range& ref_range, AllocationInfo* ref_info) {
+ if (!ref_info->referenced_from_root) {
+ ref_info->referenced_from_root = true;
+ to_do.push_back(ref_range);
}
- }
+ });
}
}
@@ -85,27 +90,22 @@
}
bool HeapWalker::DetectLeaks() {
+ // Recursively walk pointers from roots to mark referenced allocations
for (auto it = roots_.begin(); it != roots_.end(); it++) {
- Walk(*it, &RangeInfo::referenced_from_root);
+ RecurseRoot(*it);
}
Range vals;
vals.begin = reinterpret_cast<uintptr_t>(root_vals_.data());
vals.end = vals.begin + root_vals_.size() * sizeof(uintptr_t);
- Walk(vals, &RangeInfo::referenced_from_root);
- for (auto it = allocations_.begin(); it != allocations_.end(); it++) {
- if (!it->second.referenced_from_root) {
- Walk(it->first, &RangeInfo::referenced_from_leak);
- }
- }
+ RecurseRoot(vals);
return true;
}
bool HeapWalker::Leaked(allocator::vector<Range>& leaked, size_t limit,
size_t* num_leaks_out, size_t* leak_bytes_out) {
- DetectLeaks();
leaked.clear();
size_t num_leaks = 0;
@@ -120,7 +120,7 @@
size_t n = 0;
for (auto it = allocations_.begin(); it != allocations_.end(); it++) {
if (!it->second.referenced_from_root) {
- if (n++ <= limit) {
+ if (n++ < limit) {
leaked.push_back(it->first);
}
}
diff --git a/libmemunreachable/HeapWalker.h b/libmemunreachable/HeapWalker.h
index 4be1934..7b851c4 100644
--- a/libmemunreachable/HeapWalker.h
+++ b/libmemunreachable/HeapWalker.h
@@ -20,11 +20,14 @@
#include "android-base/macros.h"
#include "Allocator.h"
+#include "Tarjan.h"
// A range [begin, end)
struct Range {
uintptr_t begin;
uintptr_t end;
+
+ size_t size() const { return end - begin; };
};
// Comparator for Ranges that returns equivalence for overlapping ranges
@@ -34,7 +37,6 @@
}
};
-
class HeapWalker {
public:
HeapWalker(Allocator<HeapWalker> allocator) : allocator_(allocator),
@@ -55,16 +57,25 @@
size_t Allocations();
size_t AllocationBytes();
- private:
- struct RangeInfo {
+ template<class F>
+ void ForEachPtrInRange(const Range& range, F&& f);
+
+ template<class F>
+ void ForEachAllocation(F&& f);
+
+ struct AllocationInfo {
bool referenced_from_root;
- bool referenced_from_leak;
};
- void Walk(const Range& range, bool RangeInfo::* flag);
+
+ private:
+
+ void RecurseRoot(const Range& root);
+ bool IsAllocationPtr(uintptr_t ptr, Range* range, AllocationInfo** info);
+
DISALLOW_COPY_AND_ASSIGN(HeapWalker);
Allocator<HeapWalker> allocator_;
- using RangeMap = allocator::map<RangeInfo, Range, compare_range>;
- RangeMap allocations_;
+ using AllocationMap = allocator::map<Range, AllocationInfo, compare_range>;
+ AllocationMap allocations_;
size_t allocation_bytes_;
Range valid_allocations_range_;
@@ -72,4 +83,28 @@
allocator::vector<uintptr_t> root_vals_;
};
+template<class F>
+inline void HeapWalker::ForEachPtrInRange(const Range& range, F&& f) {
+ uintptr_t begin = (range.begin + (sizeof(uintptr_t) - 1)) & ~(sizeof(uintptr_t) - 1);
+ // TODO(ccross): we might need to consider a pointer to the end of a buffer
+ // to be inside the buffer, which means the common case of a pointer to the
+ // beginning of a buffer may keep two ranges live.
+ for (uintptr_t i = begin; i < range.end; i += sizeof(uintptr_t)) {
+ Range ref_range;
+ AllocationInfo* ref_info;
+ if (IsAllocationPtr(*reinterpret_cast<uintptr_t*>(i), &ref_range, &ref_info)) {
+ f(ref_range, ref_info);
+ }
+ }
+}
+
+template<class F>
+inline void HeapWalker::ForEachAllocation(F&& f) {
+ for (auto& it : allocations_) {
+ const Range& range = it.first;
+ HeapWalker::AllocationInfo& allocation = it.second;
+ f(range, allocation);
+ }
+}
+
#endif
diff --git a/libmemunreachable/Leak.h b/libmemunreachable/Leak.h
new file mode 100644
index 0000000..eaeeea7
--- /dev/null
+++ b/libmemunreachable/Leak.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LIBMEMUNREACHABLE_LEAK_H_
+#define LIBMEMUNREACHABLE_LEAK_H_
+
+#include <functional>
+#include <vector>
+
+#include "memunreachable/memunreachable.h"
+
+// Custom std::hash specialization so that Leak::Backtrace can be used
+// as a key in std::unordered_map.
+namespace std {
+
+template<>
+struct hash<Leak::Backtrace> {
+ std::size_t operator()(const Leak::Backtrace& key) const {
+ std::size_t seed = 0;
+
+ hash_combine(seed, key.num_frames);
+ for (size_t i = 0; i < key.num_frames; i++) {
+ hash_combine(seed, key.frames[i]);
+ }
+
+ return seed;
+ }
+
+ private:
+ template<typename T>
+ inline void hash_combine(std::size_t& seed, const T& v) const {
+ std::hash<T> hasher;
+ seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
+ }
+};
+
+} // namespace std
+
+static bool operator==(const Leak::Backtrace& lhs, const Leak::Backtrace& rhs) {
+ return (lhs.num_frames == rhs.num_frames) &&
+ memcmp(lhs.frames, rhs.frames, lhs.num_frames * sizeof(lhs.frames[0])) == 0;
+}
+
+#endif
diff --git a/libmemunreachable/LeakFolding.cpp b/libmemunreachable/LeakFolding.cpp
new file mode 100644
index 0000000..be4d20c
--- /dev/null
+++ b/libmemunreachable/LeakFolding.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+
+#include "Allocator.h"
+#include "HeapWalker.h"
+#include "LeakFolding.h"
+#include "Tarjan.h"
+#include "log.h"
+
+// Converts possibly cyclic graph of leaks to a DAG by combining
+// strongly-connected components into a object, stored in the scc pointer
+// of each node in the component.
+void LeakFolding::ComputeDAG() {
+ SCCList<LeakInfo> scc_list{allocator_};
+ Tarjan(leak_graph_, scc_list);
+
+ Allocator<SCCInfo> scc_allocator = allocator_;
+
+ for (auto& scc_nodes: scc_list) {
+ Allocator<SCCInfo>::unique_ptr leak_scc;
+ leak_scc = scc_allocator.make_unique(scc_allocator);
+
+ for (auto& node: scc_nodes) {
+ node->ptr->scc = leak_scc.get();
+ leak_scc->count++;
+ leak_scc->size += node->ptr->range.size();
+ }
+
+ leak_scc_.emplace_back(std::move(leak_scc));
+ }
+
+ for (auto& it : leak_map_) {
+ LeakInfo& leak = it.second;
+ for (auto& ref: leak.node.references_out) {
+ if (leak.scc != ref->ptr->scc) {
+ leak.scc->node.Edge(&ref->ptr->scc->node);
+ }
+ }
+ }
+}
+
+void LeakFolding::AccumulateLeaks(SCCInfo* dominator) {
+ std::function<void(SCCInfo*)> walk(std::allocator_arg, allocator_,
+ [&](SCCInfo* scc) {
+ if (scc->accumulator != dominator) {
+ scc->accumulator = dominator;
+ dominator->cuumulative_size += scc->size;
+ dominator->cuumulative_count += scc->count;
+ scc->node.Foreach([&](SCCInfo* ref) {
+ walk(ref);
+ });
+ }
+ });
+ walk(dominator);
+}
+
+bool LeakFolding::FoldLeaks() {
+ Allocator<LeakInfo> leak_allocator = allocator_;
+
+ // Find all leaked allocations insert them into leak_map_ and leak_graph_
+ heap_walker_.ForEachAllocation(
+ [&](const Range& range, HeapWalker::AllocationInfo& allocation) {
+ if (!allocation.referenced_from_root) {
+ auto it = leak_map_.emplace(std::piecewise_construct,
+ std::forward_as_tuple(range),
+ std::forward_as_tuple(range, allocator_));
+ LeakInfo& leak = it.first->second;
+ leak_graph_.push_back(&leak.node);
+ }
+ });
+
+ // Find references between leaked allocations and connect them in leak_graph_
+ for (auto& it : leak_map_) {
+ LeakInfo& leak = it.second;
+ heap_walker_.ForEachPtrInRange(leak.range,
+ [&](Range& ptr_range, HeapWalker::AllocationInfo* ptr_info) {
+ if (!ptr_info->referenced_from_root) {
+ LeakInfo* ptr_leak = &leak_map_.at(ptr_range);
+ leak.node.Edge(&ptr_leak->node);
+ }
+ });
+ }
+
+ // Convert the cyclic graph to a DAG by grouping strongly connected components
+ ComputeDAG();
+
+ // Compute dominators and cuumulative sizes
+ for (auto& scc : leak_scc_) {
+ if (scc->node.references_in.size() == 0) {
+ scc->dominator = true;
+ AccumulateLeaks(scc.get());
+ }
+ }
+
+ return true;
+}
+
+bool LeakFolding::Leaked(allocator::vector<LeakFolding::Leak>& leaked,
+ size_t* num_leaks_out, size_t* leak_bytes_out) {
+ size_t num_leaks = 0;
+ size_t leak_bytes = 0;
+ for (auto& it : leak_map_) {
+ const LeakInfo& leak = it.second;
+ num_leaks++;
+ leak_bytes += leak.range.size();
+ }
+
+ for (auto& it : leak_map_) {
+ const LeakInfo& leak = it.second;
+ if (leak.scc->dominator) {
+ leaked.emplace_back(Leak{leak.range,
+ leak.scc->cuumulative_count - 1,
+ leak.scc->cuumulative_size - leak.range.size()});
+ }
+ }
+
+ if (num_leaks_out) {
+ *num_leaks_out = num_leaks;
+ }
+ if (leak_bytes_out) {
+ *leak_bytes_out = leak_bytes;
+ }
+
+ return true;
+}
diff --git a/libmemunreachable/LeakFolding.h b/libmemunreachable/LeakFolding.h
new file mode 100644
index 0000000..732d3f2
--- /dev/null
+++ b/libmemunreachable/LeakFolding.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LIBMEMUNREACHABLE_LEAK_FOLDING_H_
+#define LIBMEMUNREACHABLE_LEAK_FOLDING_H_
+
+#include "HeapWalker.h"
+
+class LeakFolding {
+ public:
+ LeakFolding(Allocator<void> allocator, HeapWalker& heap_walker)
+ : allocator_(allocator), heap_walker_(heap_walker),
+ leak_map_(allocator), leak_graph_(allocator), leak_scc_(allocator) {}
+
+ bool FoldLeaks();
+
+ struct Leak {
+ const Range range;
+ size_t referenced_count;
+ size_t referenced_size;
+ };
+
+ bool Leaked(allocator::vector<Leak>& leaked,
+ size_t* num_leaks_out, size_t* leak_bytes_out);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LeakFolding);
+ Allocator<void> allocator_;
+ HeapWalker& heap_walker_;
+
+ struct SCCInfo {
+ public:
+ Node<SCCInfo> node;
+
+ size_t count;
+ size_t size;
+
+ size_t cuumulative_count;
+ size_t cuumulative_size;
+
+ bool dominator;
+ SCCInfo* accumulator;
+
+ SCCInfo(Allocator<SCCInfo> allocator) : node(this, allocator),
+ count(0), size(0), cuumulative_count(0), cuumulative_size(0),
+ dominator(false), accumulator(nullptr) {}
+ private:
+ SCCInfo(SCCInfo&&) = delete;
+ DISALLOW_COPY_AND_ASSIGN(SCCInfo);
+ };
+
+ struct LeakInfo {
+ public:
+ Node<LeakInfo> node;
+
+ const Range range;
+
+ SCCInfo* scc;
+
+ LeakInfo(const Range& range, Allocator<LeakInfo> allocator)
+ : node(this, allocator), range(range),
+ scc(nullptr) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LeakInfo);
+ };
+
+ void ComputeDAG();
+ void AccumulateLeaks(SCCInfo* dominator);
+
+ allocator::map<Range, LeakInfo, compare_range> leak_map_;
+ Graph<LeakInfo> leak_graph_;
+ allocator::vector<Allocator<SCCInfo>::unique_ptr> leak_scc_;
+};
+
+#endif // LIBMEMUNREACHABLE_LEAK_FOLDING_H_
diff --git a/libmemunreachable/MemUnreachable.cpp b/libmemunreachable/MemUnreachable.cpp
index eca26eb..ac19a66 100644
--- a/libmemunreachable/MemUnreachable.cpp
+++ b/libmemunreachable/MemUnreachable.cpp
@@ -21,12 +21,15 @@
#include <mutex>
#include <string>
#include <sstream>
+#include <unordered_map>
#include <backtrace.h>
#include <android-base/macros.h>
#include "Allocator.h"
#include "HeapWalker.h"
+#include "Leak.h"
+#include "LeakFolding.h"
#include "LeakPipe.h"
#include "ProcessMappings.h"
#include "PtracerThread.h"
@@ -117,32 +120,84 @@
return true;
}
-bool MemUnreachable::GetUnreachableMemory(allocator::vector<Leak>& leaks, size_t limit,
- size_t* num_leaks, size_t* leak_bytes) {
+bool MemUnreachable::GetUnreachableMemory(allocator::vector<Leak>& leaks,
+ size_t limit, size_t* num_leaks, size_t* leak_bytes) {
ALOGI("sweeping process %d for unreachable memory", pid_);
leaks.clear();
- allocator::vector<Range> leaked{allocator_};
- if (!heap_walker_.Leaked(leaked, limit, num_leaks, leak_bytes)) {
+ if (!heap_walker_.DetectLeaks()) {
return false;
}
- for (auto it = leaked.begin(); it != leaked.end(); it++) {
- Leak leak{};
- leak.begin = it->begin;
- leak.size = it->end - it->begin;;
- memcpy(leak.contents, reinterpret_cast<void*>(it->begin),
- std::min(leak.size, Leak::contents_length));
- ssize_t num_backtrace_frames = malloc_backtrace(reinterpret_cast<void*>(it->begin),
- leak.backtrace_frames, leak.backtrace_length);
- if (num_backtrace_frames > 0) {
- leak.num_backtrace_frames = num_backtrace_frames;
- }
- leaks.emplace_back(leak);
- }
+
+ allocator::vector<Range> leaked1{allocator_};
+ heap_walker_.Leaked(leaked1, 0, num_leaks, leak_bytes);
ALOGI("sweeping done");
+ ALOGI("folding related leaks");
+
+ LeakFolding folding(allocator_, heap_walker_);
+ if (!folding.FoldLeaks()) {
+ return false;
+ }
+
+ allocator::vector<LeakFolding::Leak> leaked{allocator_};
+
+ if (!folding.Leaked(leaked, num_leaks, leak_bytes)) {
+ return false;
+ }
+
+ allocator::unordered_map<Leak::Backtrace, Leak*> backtrace_map{allocator_};
+
+ // Prevent reallocations of backing memory so we can store pointers into it
+ // in backtrace_map.
+ leaks.reserve(leaked.size());
+
+ for (auto& it: leaked) {
+ leaks.emplace_back();
+ Leak* leak = &leaks.back();
+
+ ssize_t num_backtrace_frames = malloc_backtrace(reinterpret_cast<void*>(it.range.begin),
+ leak->backtrace.frames, leak->backtrace.max_frames);
+ if (num_backtrace_frames > 0) {
+ leak->backtrace.num_frames = num_backtrace_frames;
+
+ auto inserted = backtrace_map.emplace(leak->backtrace, leak);
+ if (!inserted.second) {
+ // Leak with same backtrace already exists, drop this one and
+ // increment similar counts on the existing one.
+ leaks.pop_back();
+ Leak* similar_leak = inserted.first->second;
+ similar_leak->similar_count++;
+ similar_leak->similar_size += it.range.size();
+ similar_leak->similar_referenced_count += it.referenced_count;
+ similar_leak->similar_referenced_size += it.referenced_size;
+ similar_leak->total_size += it.range.size();
+ similar_leak->total_size += it.referenced_size;
+ continue;
+ }
+ }
+
+ leak->begin = it.range.begin;
+ leak->size = it.range.size();
+ leak->referenced_count = it.referenced_count;
+ leak->referenced_size = it.referenced_size;
+ leak->total_size = leak->size + leak->referenced_size;
+ memcpy(leak->contents, reinterpret_cast<void*>(it.range.begin),
+ std::min(leak->size, Leak::contents_length));
+ }
+
+ ALOGI("folding done");
+
+ std::sort(leaks.begin(), leaks.end(), [](const Leak& a, const Leak& b) {
+ return a.total_size > b.total_size;
+ });
+
+ if (leaks.size() > limit) {
+ leaks.resize(limit);
+ }
+
return true;
}
@@ -203,6 +258,11 @@
return true;
}
+template<typename T>
+static inline const char* plural(T val) {
+ return (val == 1) ? "" : "s";
+}
+
bool GetUnreachableMemory(UnreachableMemoryInfo& info, size_t limit) {
int parent_pid = getpid();
int parent_tid = gettid();
@@ -339,9 +399,8 @@
ALOGI("unreachable memory detection done");
ALOGE("%zu bytes in %zu allocation%s unreachable out of %zu bytes in %zu allocation%s",
- info.leak_bytes, info.num_leaks, info.num_leaks == 1 ? "" : "s",
- info.allocation_bytes, info.num_allocations, info.num_allocations == 1 ? "" : "s");
-
+ info.leak_bytes, info.num_leaks, plural(info.num_leaks),
+ info.allocation_bytes, info.num_allocations, plural(info.num_allocations));
return true;
}
@@ -353,6 +412,23 @@
oss << " bytes unreachable at ";
oss << std::hex << begin;
oss << std::endl;
+ if (referenced_count > 0) {
+ oss << std::dec;
+ oss << " referencing " << referenced_size << " unreachable bytes";
+ oss << " in " << referenced_count << " allocation" << plural(referenced_count);
+ oss << std::endl;
+ }
+ if (similar_count > 0) {
+ oss << std::dec;
+ oss << " and " << similar_size << " similar unreachable bytes";
+ oss << " in " << similar_count << " allocation" << plural(similar_count);
+ oss << std::endl;
+ if (similar_referenced_count > 0) {
+ oss << " referencing " << similar_referenced_size << " unreachable bytes";
+ oss << " in " << similar_referenced_count << " allocation" << plural(similar_referenced_count);
+ oss << std::endl;
+ }
+ }
if (log_contents) {
const int bytes_per_line = 16;
@@ -361,7 +437,7 @@
if (bytes == size) {
oss << " contents:" << std::endl;
} else {
- oss << " first " << bytes << " bytes of contents:" << std::endl;
+ oss << " first " << bytes << " bytes of contents:" << std::endl;
}
for (size_t i = 0; i < bytes; i += bytes_per_line) {
@@ -385,21 +461,41 @@
oss << std::endl;
}
}
- if (num_backtrace_frames > 0) {
- oss << backtrace_string(backtrace_frames, num_backtrace_frames);
+ if (backtrace.num_frames > 0) {
+ oss << backtrace_string(backtrace.frames, backtrace.num_frames);
}
return oss.str();
}
+// Figure out the abi based on defined macros.
+#if defined(__arm__)
+#define ABI_STRING "arm"
+#elif defined(__aarch64__)
+#define ABI_STRING "arm64"
+#elif defined(__mips__) && !defined(__LP64__)
+#define ABI_STRING "mips"
+#elif defined(__mips__) && defined(__LP64__)
+#define ABI_STRING "mips64"
+#elif defined(__i386__)
+#define ABI_STRING "x86"
+#elif defined(__x86_64__)
+#define ABI_STRING "x86_64"
+#else
+#error "Unsupported ABI"
+#endif
+
std::string UnreachableMemoryInfo::ToString(bool log_contents) const {
std::ostringstream oss;
oss << " " << leak_bytes << " bytes in ";
- oss << num_leaks << " unreachable allocation" << (num_leaks == 1 ? "" : "s");
+ oss << num_leaks << " unreachable allocation" << plural(num_leaks);
+ oss << std::endl;
+ oss << " ABI: '" ABI_STRING "'" << std::endl;
oss << std::endl;
for (auto it = leaks.begin(); it != leaks.end(); it++) {
oss << it->ToString(log_contents);
+ oss << std::endl;
}
return oss.str();
diff --git a/libmemunreachable/ScopedAlarm.h b/libmemunreachable/ScopedAlarm.h
index 019deea..287f479 100644
--- a/libmemunreachable/ScopedAlarm.h
+++ b/libmemunreachable/ScopedAlarm.h
@@ -18,6 +18,7 @@
#define LIBMEMUNREACHABLE_SCOPED_ALARM_H_
#include <signal.h>
+#include <sys/time.h>
#include <chrono>
#include <functional>
diff --git a/libmemunreachable/Tarjan.h b/libmemunreachable/Tarjan.h
new file mode 100644
index 0000000..d7ecdb9
--- /dev/null
+++ b/libmemunreachable/Tarjan.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Based on system/update_engine/payload_generator/tarjan.cc
+
+#ifndef LIBMEMUNREACHABLE_TARJAN_H_
+#define LIBMEMUNREACHABLE_TARJAN_H_
+
+#include <algorithm>
+
+#include "Allocator.h"
+
+template<class T>
+class Node {
+ public:
+ allocator::set<Node<T>*> references_in;
+ allocator::set<Node<T>*> references_out;
+ size_t index;
+ size_t lowlink;
+
+ T* ptr;
+
+ Node(T* ptr, Allocator<Node> allocator) : references_in(allocator), references_out(allocator),
+ ptr(ptr) {};
+ Node(Node&& rhs) = default;
+ void Edge(Node<T>* ref) {
+ references_out.emplace(ref);
+ ref->references_in.emplace(this);
+ }
+ template<class F>
+ void Foreach(F&& f) {
+ for (auto& node: references_out) {
+ f(node->ptr);
+ }
+ }
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Node<T>);
+};
+
+template<class T>
+using Graph = allocator::vector<Node<T>*>;
+
+template<class T>
+using SCC = allocator::vector<Node<T>*>;
+
+template<class T>
+using SCCList = allocator::vector<SCC<T>>;
+
+template<class T>
+class TarjanAlgorithm {
+ public:
+ TarjanAlgorithm(Allocator<void> allocator) : index_(0),
+ stack_(allocator), components_(allocator) {}
+
+ void Execute(Graph<T>& graph, SCCList<T>& out);
+ private:
+ static constexpr size_t UNDEFINED_INDEX = static_cast<size_t>(-1);
+ void Tarjan(Node<T>* vertex, Graph<T>& graph);
+
+ size_t index_;
+ allocator::vector<Node<T>*> stack_;
+ SCCList<T> components_;
+};
+
+template<class T>
+void TarjanAlgorithm<T>::Execute(Graph<T>& graph, SCCList<T>& out) {
+ stack_.clear();
+ components_.clear();
+ index_ = 0;
+ for (auto& it: graph) {
+ it->index = UNDEFINED_INDEX;
+ it->lowlink = UNDEFINED_INDEX;
+ }
+
+ for (auto& it: graph) {
+ if (it->index == UNDEFINED_INDEX) {
+ Tarjan(it, graph);
+ }
+ }
+ out.swap(components_);
+}
+
+template<class T>
+void TarjanAlgorithm<T>::Tarjan(Node<T>* vertex, Graph<T>& graph) {
+ assert(vertex->index == UNDEFINED_INDEX);
+ vertex->index = index_;
+ vertex->lowlink = index_;
+ index_++;
+ stack_.push_back(vertex);
+ for (auto& it: vertex->references_out) {
+ Node<T>* vertex_next = it;
+ if (vertex_next->index == UNDEFINED_INDEX) {
+ Tarjan(vertex_next, graph);
+ vertex->lowlink = std::min(vertex->lowlink, vertex_next->lowlink);
+ } else if (std::find(stack_.begin(), stack_.end(), vertex_next) != stack_.end()) {
+ vertex->lowlink = std::min(vertex->lowlink, vertex_next->index);
+ }
+ }
+ if (vertex->lowlink == vertex->index) {
+ SCC<T> component{components_.get_allocator()};
+ Node<T>* other_vertex;
+ do {
+ other_vertex = stack_.back();
+ stack_.pop_back();
+ component.push_back(other_vertex);
+ } while (other_vertex != vertex && !stack_.empty());
+
+ components_.emplace_back(component);
+ }
+}
+
+template<class T>
+void Tarjan(Graph<T>& graph, SCCList<T>& out) {
+ TarjanAlgorithm<T> tarjan{graph.get_allocator()};
+ tarjan.Execute(graph, out);
+}
+
+#endif // LIBMEMUNREACHABLE_TARJAN_H_
diff --git a/libmemunreachable/ThreadCapture.cpp b/libmemunreachable/ThreadCapture.cpp
index 6357840..e8a8392 100644
--- a/libmemunreachable/ThreadCapture.cpp
+++ b/libmemunreachable/ThreadCapture.cpp
@@ -86,7 +86,7 @@
void PtraceDetach(pid_t tid, unsigned int signal);
bool PtraceThreadInfo(pid_t tid, ThreadInfo& thread_info);
- allocator::map<unsigned int, pid_t> captured_threads_;
+ allocator::map<pid_t, unsigned int> captured_threads_;
Allocator<ThreadCaptureImpl> allocator_;
pid_t pid_;
std::function<void(pid_t)> inject_test_func_;
diff --git a/libmemunreachable/bionic.h b/libmemunreachable/bionic.h
index 92de24a..83d07a8 100644
--- a/libmemunreachable/bionic.h
+++ b/libmemunreachable/bionic.h
@@ -18,6 +18,8 @@
#define LIBMEMUNREACHABLE_BIONIC_H_
#include <sys/cdefs.h>
+#include <stdint.h>
+#include <stdlib.h>
__BEGIN_DECLS
diff --git a/libmemunreachable/include/memunreachable/memunreachable.h b/libmemunreachable/include/memunreachable/memunreachable.h
index f4f01ce..9b227fd 100644
--- a/libmemunreachable/include/memunreachable/memunreachable.h
+++ b/libmemunreachable/include/memunreachable/memunreachable.h
@@ -27,11 +27,26 @@
struct Leak {
uintptr_t begin;
size_t size;
- size_t num_backtrace_frames;
+
+ size_t referenced_count;
+ size_t referenced_size;
+
+ size_t similar_count;
+ size_t similar_size;
+ size_t similar_referenced_count;
+ size_t similar_referenced_size;
+
+ size_t total_size;
+
static const size_t contents_length = 32;
char contents[contents_length];
- static const size_t backtrace_length = 16;
- uintptr_t backtrace_frames[backtrace_length];
+
+ struct Backtrace {
+ size_t num_frames;
+
+ static const size_t max_frames = 16;
+ uintptr_t frames[max_frames];
+ } backtrace;
std::string ToString(bool log_contents) const;
};
diff --git a/libmemunreachable/tests/Allocator_test.cpp b/libmemunreachable/tests/Allocator_test.cpp
index d8e473e..fa76ae0 100644
--- a/libmemunreachable/tests/Allocator_test.cpp
+++ b/libmemunreachable/tests/Allocator_test.cpp
@@ -15,12 +15,6 @@
*/
#include <Allocator.h>
-#include <sys/time.h>
-
-#include <chrono>
-#include <functional>
-#include <list>
-#include <vector>
#include <gtest/gtest.h>
#include <ScopedDisableMalloc.h>
@@ -28,8 +22,6 @@
std::function<void()> ScopedAlarm::func_;
-using namespace std::chrono_literals;
-
class AllocatorTest : public testing::Test {
protected:
AllocatorTest() : heap(), disable_malloc_() {}
@@ -180,94 +172,3 @@
ASSERT_NE(ptr, nullptr);
}
-
-class DisableMallocTest : public ::testing::Test {
- protected:
- void alarm(std::chrono::microseconds us) {
- std::chrono::seconds s = std::chrono::duration_cast<std::chrono::seconds>(us);
- itimerval t = itimerval();
- t.it_value.tv_sec = s.count();
- t.it_value.tv_usec = (us - s).count();
- setitimer(ITIMER_REAL, &t, NULL);
- }
-};
-
-TEST_F(DisableMallocTest, reenable) {
- ASSERT_EXIT({
- alarm(100ms);
- void *ptr1 = malloc(128);
- ASSERT_NE(ptr1, nullptr);
- free(ptr1);
- {
- ScopedDisableMalloc disable_malloc;
- }
- void *ptr2 = malloc(128);
- ASSERT_NE(ptr2, nullptr);
- free(ptr2);
- _exit(1);
- }, ::testing::ExitedWithCode(1), "");
-}
-
-TEST_F(DisableMallocTest, deadlock_allocate) {
- ASSERT_DEATH({
- void *ptr = malloc(128);
- ASSERT_NE(ptr, nullptr);
- free(ptr);
- {
- alarm(100ms);
- ScopedDisableMalloc disable_malloc;
- void* ptr = malloc(128);
- ASSERT_NE(ptr, nullptr);
- free(ptr);
- }
- }, "");
-}
-
-TEST_F(DisableMallocTest, deadlock_new) {
- ASSERT_DEATH({
- char* ptr = new(char);
- ASSERT_NE(ptr, nullptr);
- delete(ptr);
- {
- alarm(100ms);
- ScopedDisableMalloc disable_malloc;
- char* ptr = new(char);
- ASSERT_NE(ptr, nullptr);
- delete(ptr);
- }
- }, "");
-}
-
-TEST_F(DisableMallocTest, deadlock_delete) {
- ASSERT_DEATH({
- char* ptr = new(char);
- ASSERT_NE(ptr, nullptr);
- {
- alarm(250ms);
- ScopedDisableMalloc disable_malloc;
- delete(ptr);
- }
- }, "");
-}
-
-TEST_F(DisableMallocTest, deadlock_free) {
- ASSERT_DEATH({
- void *ptr = malloc(128);
- ASSERT_NE(ptr, nullptr);
- {
- alarm(100ms);
- ScopedDisableMalloc disable_malloc;
- free(ptr);
- }
- }, "");
-}
-
-TEST_F(DisableMallocTest, deadlock_fork) {
- ASSERT_DEATH({
- {
- alarm(100ms);
- ScopedDisableMalloc disable_malloc;
- fork();
- }
- }, "");
-}
diff --git a/libmemunreachable/tests/DisableMalloc_test.cpp b/libmemunreachable/tests/DisableMalloc_test.cpp
new file mode 100644
index 0000000..ea5c22c
--- /dev/null
+++ b/libmemunreachable/tests/DisableMalloc_test.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/time.h>
+
+#include <chrono>
+#include <functional>
+
+#include <gtest/gtest.h>
+#include <ScopedDisableMalloc.h>
+
+using namespace std::chrono_literals;
+
+class DisableMallocTest : public ::testing::Test {
+ protected:
+ void alarm(std::chrono::microseconds us) {
+ std::chrono::seconds s = std::chrono::duration_cast<std::chrono::seconds>(us);
+ itimerval t = itimerval();
+ t.it_value.tv_sec = s.count();
+ t.it_value.tv_usec = (us - s).count();
+ setitimer(ITIMER_REAL, &t, NULL);
+ }
+};
+
+TEST_F(DisableMallocTest, reenable) {
+ ASSERT_EXIT({
+ alarm(100ms);
+ void *ptr1 = malloc(128);
+ ASSERT_NE(ptr1, nullptr);
+ free(ptr1);
+ {
+ ScopedDisableMalloc disable_malloc;
+ }
+ void *ptr2 = malloc(128);
+ ASSERT_NE(ptr2, nullptr);
+ free(ptr2);
+ _exit(1);
+ }, ::testing::ExitedWithCode(1), "");
+}
+
+TEST_F(DisableMallocTest, deadlock_allocate) {
+ ASSERT_DEATH({
+ void *ptr = malloc(128);
+ ASSERT_NE(ptr, nullptr);
+ free(ptr);
+ {
+ alarm(100ms);
+ ScopedDisableMalloc disable_malloc;
+ void* ptr = malloc(128);
+ ASSERT_NE(ptr, nullptr);
+ free(ptr);
+ }
+ }, "");
+}
+
+TEST_F(DisableMallocTest, deadlock_new) {
+ ASSERT_DEATH({
+ char* ptr = new(char);
+ ASSERT_NE(ptr, nullptr);
+ delete(ptr);
+ {
+ alarm(100ms);
+ ScopedDisableMalloc disable_malloc;
+ char* ptr = new(char);
+ ASSERT_NE(ptr, nullptr);
+ delete(ptr);
+ }
+ }, "");
+}
+
+TEST_F(DisableMallocTest, deadlock_delete) {
+ ASSERT_DEATH({
+ char* ptr = new(char);
+ ASSERT_NE(ptr, nullptr);
+ {
+ alarm(250ms);
+ ScopedDisableMalloc disable_malloc;
+ delete(ptr);
+ }
+ }, "");
+}
+
+TEST_F(DisableMallocTest, deadlock_free) {
+ ASSERT_DEATH({
+ void *ptr = malloc(128);
+ ASSERT_NE(ptr, nullptr);
+ {
+ alarm(100ms);
+ ScopedDisableMalloc disable_malloc;
+ free(ptr);
+ }
+ }, "");
+}
+
+TEST_F(DisableMallocTest, deadlock_fork) {
+ ASSERT_DEATH({
+ {
+ alarm(100ms);
+ ScopedDisableMalloc disable_malloc;
+ fork();
+ }
+ }, "");
+}
diff --git a/libmemunreachable/tests/HeapWalker_test.cpp b/libmemunreachable/tests/HeapWalker_test.cpp
index 9921eb6..c3e1c4d 100644
--- a/libmemunreachable/tests/HeapWalker_test.cpp
+++ b/libmemunreachable/tests/HeapWalker_test.cpp
@@ -80,6 +80,8 @@
HeapWalker heap_walker(heap_);
heap_walker.Allocation(buffer_begin(buffer2), buffer_end(buffer2));
+ ASSERT_EQ(true, heap_walker.DetectLeaks());
+
allocator::vector<Range> leaked(heap_);
size_t num_leaks = 0;
size_t leaked_bytes = 0;
@@ -106,9 +108,11 @@
heap_walker.Allocation(buffer_begin(buffer2), buffer_end(buffer2));
heap_walker.Root(buffer_begin(buffer1), buffer_end(buffer1));
+ ASSERT_EQ(true, heap_walker.DetectLeaks());
+
allocator::vector<Range> leaked(heap_);
- size_t num_leaks = SIZE_T_MAX;
- size_t leaked_bytes = SIZE_T_MAX;
+ size_t num_leaks = SIZE_MAX;
+ size_t leaked_bytes = SIZE_MAX;
ASSERT_EQ(true, heap_walker.Leaked(leaked, 100, &num_leaks, &leaked_bytes));
EXPECT_EQ(0U, num_leaks);
@@ -132,9 +136,11 @@
heap_walker.Allocation(buffer_begin(buffer2), buffer_end(buffer2));
heap_walker.Root(buffer_begin(buffer1) + i, buffer_end(buffer1) - j);
+ ASSERT_EQ(true, heap_walker.DetectLeaks());
+
allocator::vector<Range> leaked(heap_);
- size_t num_leaks = SIZE_T_MAX;
- size_t leaked_bytes = SIZE_T_MAX;
+ size_t num_leaks = SIZE_MAX;
+ size_t leaked_bytes = SIZE_MAX;
ASSERT_EQ(true, heap_walker.Leaked(leaked, 100, &num_leaks, &leaked_bytes));
EXPECT_EQ(0U, num_leaks);
@@ -143,3 +149,26 @@
}
}
}
+
+TEST_F(HeapWalkerTest, cycle) {
+ void* buffer1;
+ void* buffer2;
+
+ buffer1 = &buffer2;
+ buffer2 = &buffer1;
+
+ HeapWalker heap_walker(heap_);
+ heap_walker.Allocation(buffer_begin(buffer1), buffer_end(buffer1));
+ heap_walker.Allocation(buffer_begin(buffer2), buffer_end(buffer2));
+
+ ASSERT_EQ(true, heap_walker.DetectLeaks());
+
+ allocator::vector<Range> leaked(heap_);
+ size_t num_leaks = 0;
+ size_t leaked_bytes = 0;
+ ASSERT_EQ(true, heap_walker.Leaked(leaked, 100, &num_leaks, &leaked_bytes));
+
+ EXPECT_EQ(2U, num_leaks);
+ EXPECT_EQ(2*sizeof(uintptr_t), leaked_bytes);
+ ASSERT_EQ(2U, leaked.size());
+}
diff --git a/libmemunreachable/tests/HostMallocStub.cpp b/libmemunreachable/tests/HostMallocStub.cpp
new file mode 100644
index 0000000..a7e3f07
--- /dev/null
+++ b/libmemunreachable/tests/HostMallocStub.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bionic.h"
+
+void malloc_disable() {
+}
+
+void malloc_enable() {
+}
diff --git a/libmemunreachable/tests/LeakFolding_test.cpp b/libmemunreachable/tests/LeakFolding_test.cpp
new file mode 100644
index 0000000..879a3a0
--- /dev/null
+++ b/libmemunreachable/tests/LeakFolding_test.cpp
@@ -0,0 +1,427 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "HeapWalker.h"
+#include "LeakFolding.h"
+
+#include <gtest/gtest.h>
+#include <ScopedDisableMalloc.h>
+#include "Allocator.h"
+
+class LeakFoldingTest : public ::testing::Test {
+ public:
+ LeakFoldingTest() : disable_malloc_(), heap_() {}
+
+ void TearDown() {
+ ASSERT_TRUE(heap_.empty());
+ if (!HasFailure()) {
+ ASSERT_FALSE(disable_malloc_.timed_out());
+ }
+ }
+
+ protected:
+ ScopedDisableMallocTimeout disable_malloc_;
+ Heap heap_;
+};
+
+#define buffer_begin(buffer) reinterpret_cast<uintptr_t>(&buffer[0])
+#define buffer_end(buffer) (reinterpret_cast<uintptr_t>(&buffer[0]) + sizeof(buffer))
+#define ALLOCATION(heap_walker, buffer) \
+ ASSERT_EQ(true, heap_walker.Allocation(buffer_begin(buffer), buffer_end(buffer)))
+
+TEST_F(LeakFoldingTest, one) {
+ void* buffer1[1] = {nullptr};
+
+ HeapWalker heap_walker(heap_);
+
+ ALLOCATION(heap_walker, buffer1);
+
+ LeakFolding folding(heap_, heap_walker);
+
+ ASSERT_TRUE(folding.FoldLeaks());
+
+ allocator::vector<LeakFolding::Leak> leaked(heap_);
+ size_t num_leaks = 0;
+ size_t leaked_bytes = 0;
+ ASSERT_EQ(true, folding.Leaked(leaked, &num_leaks, &leaked_bytes));
+
+ EXPECT_EQ(1U, num_leaks);
+ EXPECT_EQ(sizeof(uintptr_t), leaked_bytes);
+ ASSERT_EQ(1U, leaked.size());
+ EXPECT_EQ(0U, leaked[0].referenced_count);
+ EXPECT_EQ(0U, leaked[0].referenced_size);
+}
+
+TEST_F(LeakFoldingTest, two) {
+ void* buffer1[1] = {nullptr};
+ void* buffer2[1] = {nullptr};
+
+ HeapWalker heap_walker(heap_);
+
+ ALLOCATION(heap_walker, buffer1);
+ ALLOCATION(heap_walker, buffer2);
+
+ LeakFolding folding(heap_, heap_walker);
+
+ ASSERT_TRUE(folding.FoldLeaks());
+
+ allocator::vector<LeakFolding::Leak> leaked(heap_);
+ size_t num_leaks = 0;
+ size_t leaked_bytes = 0;
+ ASSERT_EQ(true, folding.Leaked(leaked, &num_leaks, &leaked_bytes));
+
+ EXPECT_EQ(2U, num_leaks);
+ EXPECT_EQ(2*sizeof(uintptr_t), leaked_bytes);
+ ASSERT_EQ(2U, leaked.size());
+ EXPECT_EQ(0U, leaked[0].referenced_count);
+ EXPECT_EQ(0U, leaked[0].referenced_size);
+ EXPECT_EQ(0U, leaked[1].referenced_count);
+ EXPECT_EQ(0U, leaked[1].referenced_size);
+}
+
+TEST_F(LeakFoldingTest, dominator) {
+ void* buffer1[1];
+ void* buffer2[1] = {nullptr};
+
+ buffer1[0] = buffer2;
+
+ HeapWalker heap_walker(heap_);
+
+ ALLOCATION(heap_walker, buffer1);
+ ALLOCATION(heap_walker, buffer2);
+
+ LeakFolding folding(heap_, heap_walker);
+
+ ASSERT_TRUE(folding.FoldLeaks());
+
+ allocator::vector<LeakFolding::Leak> leaked(heap_);
+ size_t num_leaks = 0;
+ size_t leaked_bytes = 0;
+ ASSERT_EQ(true, folding.Leaked(leaked, &num_leaks, &leaked_bytes));
+
+ EXPECT_EQ(2U, num_leaks);
+ EXPECT_EQ(2*sizeof(uintptr_t), leaked_bytes);
+ ASSERT_EQ(1U, leaked.size());
+ EXPECT_EQ(1U, leaked[0].referenced_count);
+ EXPECT_EQ(sizeof(uintptr_t), leaked[0].referenced_size);
+}
+
+TEST_F(LeakFoldingTest, cycle) {
+ void* buffer1[1];
+ void* buffer2[1];
+ void* buffer3[1];
+
+ buffer1[0] = buffer2;
+ buffer2[0] = buffer3;
+ buffer3[0] = buffer2;
+
+ HeapWalker heap_walker(heap_);
+
+ ALLOCATION(heap_walker, buffer1);
+ ALLOCATION(heap_walker, buffer2);
+ ALLOCATION(heap_walker, buffer3);
+
+ LeakFolding folding(heap_, heap_walker);
+
+ ASSERT_TRUE(folding.FoldLeaks());
+
+ allocator::vector<LeakFolding::Leak> leaked(heap_);
+ size_t num_leaks = 0;
+ size_t leaked_bytes = 0;
+ ASSERT_EQ(true, folding.Leaked(leaked, &num_leaks, &leaked_bytes));
+
+ EXPECT_EQ(3U, num_leaks);
+ EXPECT_EQ(3*sizeof(uintptr_t), leaked_bytes);
+ ASSERT_EQ(1U, leaked.size());
+ EXPECT_EQ(2U, leaked[0].referenced_count);
+ EXPECT_EQ(2*sizeof(uintptr_t), leaked[0].referenced_size);
+}
+
+TEST_F(LeakFoldingTest, dominator_cycle) {
+ void* buffer1[2] = {nullptr, nullptr};
+ void* buffer2[2];
+ void* buffer3[1] = {nullptr};
+
+ buffer1[0] = &buffer2;
+ buffer2[0] = &buffer1;
+ buffer2[1] = &buffer3;
+
+ HeapWalker heap_walker(heap_);
+
+ ALLOCATION(heap_walker, buffer1);
+ ALLOCATION(heap_walker, buffer2);
+ ALLOCATION(heap_walker, buffer3);
+
+ LeakFolding folding(heap_, heap_walker);
+
+ ASSERT_TRUE(folding.FoldLeaks());
+
+ allocator::vector<LeakFolding::Leak> leaked(heap_);
+ size_t num_leaks = 0;
+ size_t leaked_bytes = 0;
+ ASSERT_EQ(true, folding.Leaked(leaked, &num_leaks, &leaked_bytes));
+
+ EXPECT_EQ(3U, num_leaks);
+ EXPECT_EQ(5*sizeof(uintptr_t), leaked_bytes);
+ ASSERT_EQ(2U, leaked.size());
+
+ EXPECT_EQ(2U, leaked[0].referenced_count);
+ EXPECT_EQ(3*sizeof(uintptr_t), leaked[0].referenced_size);
+ EXPECT_EQ(2U, leaked[1].referenced_count);
+ EXPECT_EQ(3*sizeof(uintptr_t), leaked[1].referenced_size);
+}
+
+TEST_F(LeakFoldingTest, two_cycles) {
+ void* buffer1[1];
+ void* buffer2[1];
+ void* buffer3[1];
+ void* buffer4[1];
+ void* buffer5[1];
+ void* buffer6[1];
+
+ buffer1[0] = buffer3;
+ buffer2[0] = buffer5;
+ buffer3[0] = buffer4;
+ buffer4[0] = buffer3;
+ buffer5[0] = buffer6;
+ buffer6[0] = buffer5;
+
+ HeapWalker heap_walker(heap_);
+
+ ALLOCATION(heap_walker, buffer1);
+ ALLOCATION(heap_walker, buffer2);
+ ALLOCATION(heap_walker, buffer3);
+ ALLOCATION(heap_walker, buffer4);
+ ALLOCATION(heap_walker, buffer5);
+ ALLOCATION(heap_walker, buffer6);
+
+ LeakFolding folding(heap_, heap_walker);
+
+ ASSERT_TRUE(folding.FoldLeaks());
+
+ allocator::vector<LeakFolding::Leak> leaked(heap_);
+ size_t num_leaks = 0;
+ size_t leaked_bytes = 0;
+ ASSERT_EQ(true, folding.Leaked(leaked, &num_leaks, &leaked_bytes));
+
+ EXPECT_EQ(6U, num_leaks);
+ EXPECT_EQ(6*sizeof(uintptr_t), leaked_bytes);
+ ASSERT_EQ(2U, leaked.size());
+ EXPECT_EQ(2U, leaked[0].referenced_count);
+ EXPECT_EQ(2*sizeof(uintptr_t), leaked[0].referenced_size);
+ EXPECT_EQ(2U, leaked[1].referenced_count);
+ EXPECT_EQ(2*sizeof(uintptr_t), leaked[1].referenced_size);
+}
+
+TEST_F(LeakFoldingTest, two_dominator_cycles) {
+ void* buffer1[1];
+ void* buffer2[1];
+ void* buffer3[1];
+ void* buffer4[1];
+
+ buffer1[0] = buffer2;
+ buffer2[0] = buffer1;
+ buffer3[0] = buffer4;
+ buffer4[0] = buffer3;
+
+ HeapWalker heap_walker(heap_);
+
+ ALLOCATION(heap_walker, buffer1);
+ ALLOCATION(heap_walker, buffer2);
+ ALLOCATION(heap_walker, buffer3);
+ ALLOCATION(heap_walker, buffer4);
+
+ LeakFolding folding(heap_, heap_walker);
+
+ ASSERT_TRUE(folding.FoldLeaks());
+
+ allocator::vector<LeakFolding::Leak> leaked(heap_);
+ size_t num_leaks = 0;
+ size_t leaked_bytes = 0;
+ ASSERT_EQ(true, folding.Leaked(leaked, &num_leaks, &leaked_bytes));
+
+ EXPECT_EQ(4U, num_leaks);
+ EXPECT_EQ(4*sizeof(uintptr_t), leaked_bytes);
+ ASSERT_EQ(4U, leaked.size());
+ EXPECT_EQ(1U, leaked[0].referenced_count);
+ EXPECT_EQ(sizeof(uintptr_t), leaked[0].referenced_size);
+ EXPECT_EQ(1U, leaked[1].referenced_count);
+ EXPECT_EQ(sizeof(uintptr_t), leaked[1].referenced_size);
+ EXPECT_EQ(1U, leaked[2].referenced_count);
+ EXPECT_EQ(sizeof(uintptr_t), leaked[2].referenced_size);
+ EXPECT_EQ(1U, leaked[3].referenced_count);
+ EXPECT_EQ(sizeof(uintptr_t), leaked[3].referenced_size);
+}
+
+TEST_F(LeakFoldingTest, giant_dominator_cycle) {
+ const size_t n = 1000;
+ void* buffer[n];
+
+ HeapWalker heap_walker(heap_);
+
+ for (size_t i = 0; i < n; i ++) {
+ ASSERT_TRUE(heap_walker.Allocation(reinterpret_cast<uintptr_t>(&buffer[i]),
+ reinterpret_cast<uintptr_t>(&buffer[i+1])));
+ }
+
+ for (size_t i = 0; i < n - 1; i++) {
+ buffer[i] = &buffer[i+1];
+ }
+ buffer[n - 1] = &buffer[0];
+
+ LeakFolding folding(heap_, heap_walker);
+
+ ASSERT_TRUE(folding.FoldLeaks());
+
+ allocator::vector<LeakFolding::Leak> leaked(heap_);
+ size_t num_leaks = 0;
+ size_t leaked_bytes = 0;
+ ASSERT_EQ(true, folding.Leaked(leaked, &num_leaks, &leaked_bytes));
+
+ EXPECT_EQ(n, num_leaks);
+ EXPECT_EQ(n * sizeof(uintptr_t), leaked_bytes);
+ ASSERT_EQ(1000U, leaked.size());
+ EXPECT_EQ(n - 1, leaked[0].referenced_count);
+ EXPECT_EQ((n - 1) * sizeof(uintptr_t), leaked[0].referenced_size);
+}
+
+TEST_F(LeakFoldingTest, giant_cycle) {
+ const size_t n = 1000;
+ void* buffer[n];
+ void* buffer1[1];
+
+ HeapWalker heap_walker(heap_);
+
+ for (size_t i = 0; i < n - 1; i++) {
+ buffer[i] = &buffer[i+1];
+ }
+ buffer[n - 1] = &buffer[0];
+
+ buffer1[0] = &buffer[0];
+
+ for (size_t i = 0; i < n; i ++) {
+ ASSERT_TRUE(heap_walker.Allocation(reinterpret_cast<uintptr_t>(&buffer[i]),
+ reinterpret_cast<uintptr_t>(&buffer[i+1])));
+ }
+
+ ALLOCATION(heap_walker, buffer1);
+
+ LeakFolding folding(heap_, heap_walker);
+
+ ASSERT_TRUE(folding.FoldLeaks());
+
+ allocator::vector<LeakFolding::Leak> leaked(heap_);
+ size_t num_leaks = 0;
+ size_t leaked_bytes = 0;
+ ASSERT_EQ(true, folding.Leaked(leaked, &num_leaks, &leaked_bytes));
+
+ EXPECT_EQ(n + 1, num_leaks);
+ EXPECT_EQ((n + 1) * sizeof(uintptr_t), leaked_bytes);
+ ASSERT_EQ(1U, leaked.size());
+ EXPECT_EQ(n, leaked[0].referenced_count);
+ EXPECT_EQ(n * sizeof(uintptr_t), leaked[0].referenced_size);
+}
+
+TEST_F(LeakFoldingTest, multipath) {
+ void* buffer1[2];
+ void* buffer2[1];
+ void* buffer3[1];
+ void* buffer4[1] = {nullptr};
+
+ // 1
+ // / \
+ // v v
+ // 2 3
+ // \ /
+ // v
+ // 4
+
+ buffer1[0] = &buffer2;
+ buffer1[1] = &buffer3;
+ buffer2[0] = &buffer4;
+ buffer3[0] = &buffer4;
+
+ HeapWalker heap_walker(heap_);
+
+ ALLOCATION(heap_walker, buffer1);
+ ALLOCATION(heap_walker, buffer2);
+ ALLOCATION(heap_walker, buffer3);
+ ALLOCATION(heap_walker, buffer4);
+
+ LeakFolding folding(heap_, heap_walker);
+
+ ASSERT_TRUE(folding.FoldLeaks());
+
+ allocator::vector<LeakFolding::Leak> leaked(heap_);
+ size_t num_leaks = 0;
+ size_t leaked_bytes = 0;
+ ASSERT_EQ(true, folding.Leaked(leaked, &num_leaks, &leaked_bytes));
+
+ EXPECT_EQ(4U, num_leaks);
+ EXPECT_EQ(5 * sizeof(uintptr_t), leaked_bytes);
+ ASSERT_EQ(1U, leaked.size());
+ EXPECT_EQ(3U, leaked[0].referenced_count);
+ EXPECT_EQ(3 * sizeof(uintptr_t), leaked[0].referenced_size);
+}
+
+TEST_F(LeakFoldingTest, multicycle) {
+ void* buffer1[2]{};
+ void* buffer2[2]{};
+ void* buffer3[2]{};
+ void* buffer4[2]{};
+
+ // 1
+ // / ^
+ // v \
+ // 2 -> 3
+ // \ ^
+ // v /
+ // 4
+
+ buffer1[0] = &buffer2;
+ buffer2[0] = &buffer3;
+ buffer2[1] = &buffer4;
+ buffer3[0] = &buffer1;
+ buffer4[0] = &buffer3;
+
+ HeapWalker heap_walker(heap_);
+
+ ALLOCATION(heap_walker, buffer1);
+ ALLOCATION(heap_walker, buffer2);
+ ALLOCATION(heap_walker, buffer3);
+ ALLOCATION(heap_walker, buffer4);
+
+ LeakFolding folding(heap_, heap_walker);
+
+ ASSERT_TRUE(folding.FoldLeaks());
+
+ allocator::vector<LeakFolding::Leak> leaked(heap_);
+ size_t num_leaks = 0;
+ size_t leaked_bytes = 0;
+ ASSERT_EQ(true, folding.Leaked(leaked, &num_leaks, &leaked_bytes));
+
+ EXPECT_EQ(4U, num_leaks);
+ EXPECT_EQ(8 * sizeof(uintptr_t), leaked_bytes);
+ ASSERT_EQ(4U, leaked.size());
+ EXPECT_EQ(3U, leaked[0].referenced_count);
+ EXPECT_EQ(6 * sizeof(uintptr_t), leaked[0].referenced_size);
+ EXPECT_EQ(3U, leaked[1].referenced_count);
+ EXPECT_EQ(6 * sizeof(uintptr_t), leaked[1].referenced_size);
+ EXPECT_EQ(3U, leaked[2].referenced_count);
+ EXPECT_EQ(6 * sizeof(uintptr_t), leaked[2].referenced_size);
+ EXPECT_EQ(3U, leaked[3].referenced_count);
+ EXPECT_EQ(6 * sizeof(uintptr_t), leaked[3].referenced_size);
+}
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 86d9d77..3e4b15a 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -38,6 +38,7 @@
// TODO(dimitry): move this to system properties.
static const char* kPublicNativeLibraries = "libandroid.so:"
"libc.so:"
+ "libcamera2ndk.so:"
"libdl.so:"
"libEGL.so:"
"libGLESv1_CM.so:"
@@ -53,6 +54,7 @@
"libOpenSLES.so:"
"libRS.so:"
"libstdc++.so:"
+ "libvulkan.so:"
"libwebviewchromium_plat_support.so:"
"libz.so";
@@ -64,7 +66,8 @@
jobject class_loader,
bool is_shared,
jstring java_library_path,
- jstring java_permitted_path) {
+ jstring java_permitted_path,
+ int32_t target_sdk_version) {
ScopedUtfChars library_path(env, java_library_path);
std::string permitted_path;
@@ -73,7 +76,7 @@
permitted_path = path.c_str();
}
- if (!initialized_ && !InitPublicNamespace(library_path.c_str())) {
+ if (!initialized_ && !InitPublicNamespace(library_path.c_str(), target_sdk_version)) {
return nullptr;
}
@@ -119,10 +122,24 @@
}
private:
- bool InitPublicNamespace(const char* library_path) {
+ bool InitPublicNamespace(const char* library_path, int32_t target_sdk_version) {
// Some apps call dlopen from generated code unknown to linker in which
// case linker uses anonymous namespace. See b/25844435 for details.
- initialized_ = android_init_namespaces(kPublicNativeLibraries, library_path);
+ std::string publicNativeLibraries = kPublicNativeLibraries;
+
+ // TODO (dimitry): This is a workaround for http://b/26436837
+ // will be removed before the release.
+ if (target_sdk_version <= 23) {
+ // check if libart.so is loaded.
+ void* handle = dlopen("libart.so", RTLD_NOW | RTLD_NOLOAD);
+ if (handle != nullptr) {
+ publicNativeLibraries += ":libart.so";
+ dlclose(handle);
+ }
+ }
+ // END OF WORKAROUND
+
+ initialized_ = android_init_namespaces(publicNativeLibraries.c_str(), library_path);
return initialized_;
}
@@ -165,7 +182,8 @@
class_loader,
is_shared,
library_path,
- permitted_path);
+ permitted_path,
+ target_sdk_version);
if (ns == nullptr) {
return env->NewStringUTF(dlerror());
}
@@ -192,7 +210,7 @@
if (ns == nullptr) {
// This is the case where the classloader was not created by ApplicationLoaders
// In this case we create an isolated not-shared namespace for it.
- ns = g_namespaces->Create(env, class_loader, false, library_path, nullptr);
+ ns = g_namespaces->Create(env, class_loader, false, library_path, nullptr, target_sdk_version);
if (ns == nullptr) {
return nullptr;
}
diff --git a/libnetutils/Android.mk b/libnetutils/Android.mk
index 281b6c8..ce7c3ba 100644
--- a/libnetutils/Android.mk
+++ b/libnetutils/Android.mk
@@ -4,7 +4,6 @@
LOCAL_SRC_FILES := \
dhcpclient.c \
dhcpmsg.c \
- dhcp_utils.c \
ifc_utils.c \
packet.c
diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c
deleted file mode 100644
index c6b9fe4..0000000
--- a/libnetutils/dhcp_utils.c
+++ /dev/null
@@ -1,372 +0,0 @@
-/*
- * Copyright 2008, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* Utilities for managing the dhcpcd DHCP client daemon */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-
-#include <cutils/properties.h>
-
-static const char DAEMON_NAME[] = "dhcpcd";
-static const char DAEMON_PROP_NAME[] = "init.svc.dhcpcd";
-static const char HOSTNAME_PROP_NAME[] = "net.hostname";
-static const char DHCP_PROP_NAME_PREFIX[] = "dhcp";
-static const char DHCP_CONFIG_PATH[] = "/system/etc/dhcpcd/dhcpcd.conf";
-static const int NAP_TIME = 200; /* wait for 200ms at a time */
- /* when polling for property values */
-static const char DAEMON_NAME_RENEW[] = "iprenew";
-static char errmsg[100] = "\0";
-/* interface length for dhcpcd daemon start (dhcpcd_<interface> as defined in init.rc file)
- * or for filling up system properties dhcpcd.<interface>.ipaddress, dhcpcd.<interface>.dns1
- * and other properties on a successful bind
- */
-#define MAX_INTERFACE_LENGTH 25
-
-/*
- * P2p interface names increase sequentially p2p-p2p0-1, p2p-p2p0-2.. after
- * group formation. This does not work well with system properties which can quickly
- * exhaust or for specifiying a dhcp start target in init which requires
- * interface to be pre-defined in init.rc file.
- *
- * This function returns a common string p2p for all p2p interfaces.
- */
-void get_p2p_interface_replacement(const char *interface, char *p2p_interface) {
- /* Use p2p for any interface starting with p2p. */
- if (strncmp(interface, "p2p",3) == 0) {
- strncpy(p2p_interface, "p2p", MAX_INTERFACE_LENGTH);
- } else {
- strncpy(p2p_interface, interface, MAX_INTERFACE_LENGTH);
- }
-}
-
-/*
- * Wait for a system property to be assigned a specified value.
- * If desired_value is NULL, then just wait for the property to
- * be created with any value. maxwait is the maximum amount of
- * time in seconds to wait before giving up.
- */
-static int wait_for_property(const char *name, const char *desired_value, int maxwait)
-{
- char value[PROPERTY_VALUE_MAX] = {'\0'};
- int maxnaps = (maxwait * 1000) / NAP_TIME;
-
- if (maxnaps < 1) {
- maxnaps = 1;
- }
-
- while (maxnaps-- >= 0) {
- if (property_get(name, value, NULL)) {
- if (desired_value == NULL ||
- strcmp(value, desired_value) == 0) {
- return 0;
- }
- }
- if (maxnaps >= 0) {
- usleep(NAP_TIME * 1000);
- }
- }
- return -1; /* failure */
-}
-
-static int fill_ip_info(const char *interface,
- char *ipaddr,
- char *gateway,
- uint32_t *prefixLength,
- char *dns[],
- char *server,
- uint32_t *lease,
- char *vendorInfo,
- char *domain,
- char *mtu)
-{
- char prop_name[PROPERTY_KEY_MAX];
- char prop_value[PROPERTY_VALUE_MAX];
- /* Interface name after converting p2p0-p2p0-X to p2p to reuse system properties */
- char p2p_interface[MAX_INTERFACE_LENGTH];
- int x;
-
- get_p2p_interface_replacement(interface, p2p_interface);
-
- snprintf(prop_name, sizeof(prop_name), "%s.%s.ipaddress", DHCP_PROP_NAME_PREFIX, p2p_interface);
- property_get(prop_name, ipaddr, NULL);
-
- snprintf(prop_name, sizeof(prop_name), "%s.%s.gateway", DHCP_PROP_NAME_PREFIX, p2p_interface);
- property_get(prop_name, gateway, NULL);
-
- snprintf(prop_name, sizeof(prop_name), "%s.%s.server", DHCP_PROP_NAME_PREFIX, p2p_interface);
- property_get(prop_name, server, NULL);
-
- //TODO: Handle IPv6 when we change system property usage
- if (gateway[0] == '\0' || strncmp(gateway, "0.0.0.0", 7) == 0) {
- //DHCP server is our best bet as gateway
- strncpy(gateway, server, PROPERTY_VALUE_MAX);
- }
-
- snprintf(prop_name, sizeof(prop_name), "%s.%s.mask", DHCP_PROP_NAME_PREFIX, p2p_interface);
- if (property_get(prop_name, prop_value, NULL)) {
- int p;
- // this conversion is v4 only, but this dhcp client is v4 only anyway
- in_addr_t mask = ntohl(inet_addr(prop_value));
- // Check netmask is a valid IP address. ntohl gives NONE response (all 1's) for
- // non 255.255.255.255 inputs. if we get that value check if it is legit..
- if (mask == INADDR_NONE && strcmp(prop_value, "255.255.255.255") != 0) {
- snprintf(errmsg, sizeof(errmsg), "DHCP gave invalid net mask %s", prop_value);
- return -1;
- }
- for (p = 0; p < 32; p++) {
- if (mask == 0) break;
- // check for non-contiguous netmask, e.g., 255.254.255.0
- if ((mask & 0x80000000) == 0) {
- snprintf(errmsg, sizeof(errmsg), "DHCP gave invalid net mask %s", prop_value);
- return -1;
- }
- mask = mask << 1;
- }
- *prefixLength = p;
- }
-
- for (x=0; dns[x] != NULL; x++) {
- snprintf(prop_name, sizeof(prop_name), "%s.%s.dns%d", DHCP_PROP_NAME_PREFIX, p2p_interface, x+1);
- property_get(prop_name, dns[x], NULL);
- }
-
- snprintf(prop_name, sizeof(prop_name), "%s.%s.leasetime", DHCP_PROP_NAME_PREFIX, p2p_interface);
- if (property_get(prop_name, prop_value, NULL)) {
- *lease = atol(prop_value);
- }
-
- snprintf(prop_name, sizeof(prop_name), "%s.%s.vendorInfo", DHCP_PROP_NAME_PREFIX,
- p2p_interface);
- property_get(prop_name, vendorInfo, NULL);
-
- snprintf(prop_name, sizeof(prop_name), "%s.%s.domain", DHCP_PROP_NAME_PREFIX,
- p2p_interface);
- property_get(prop_name, domain, NULL);
-
- snprintf(prop_name, sizeof(prop_name), "%s.%s.mtu", DHCP_PROP_NAME_PREFIX,
- p2p_interface);
- property_get(prop_name, mtu, NULL);
-
- return 0;
-}
-
-/*
- * Get any available DHCP results.
- */
-int dhcp_get_results(const char *interface,
- char *ipaddr,
- char *gateway,
- uint32_t *prefixLength,
- char *dns[],
- char *server,
- uint32_t *lease,
- char *vendorInfo,
- char *domain,
- char *mtu)
-{
- char result_prop_name[PROPERTY_KEY_MAX];
- char prop_value[PROPERTY_VALUE_MAX];
-
- /* Interface name after converting p2p0-p2p0-X to p2p to reuse system properties */
- char p2p_interface[MAX_INTERFACE_LENGTH];
- get_p2p_interface_replacement(interface, p2p_interface);
- snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
- DHCP_PROP_NAME_PREFIX,
- p2p_interface);
-
- memset(prop_value, '\0', PROPERTY_VALUE_MAX);
- if (!property_get(result_prop_name, prop_value, NULL)) {
- snprintf(errmsg, sizeof(errmsg), "%s", "DHCP result property was not set");
- return -1;
- }
- if (strcmp(prop_value, "ok") == 0) {
- if (fill_ip_info(interface, ipaddr, gateway, prefixLength, dns,
- server, lease, vendorInfo, domain, mtu) == -1) {
- return -1;
- }
- return 0;
- } else {
- snprintf(errmsg, sizeof(errmsg), "DHCP result was %s", prop_value);
- return -1;
- }
-}
-
-/*
- * Start the dhcp client daemon, and wait for it to finish
- * configuring the interface.
- *
- * The device init.rc file needs a corresponding entry for this work.
- *
- * Example:
- * service dhcpcd_<interface> /system/bin/dhcpcd -ABKL -f dhcpcd.conf
- */
-int dhcp_start(const char *interface)
-{
- char result_prop_name[PROPERTY_KEY_MAX];
- char daemon_prop_name[PROPERTY_KEY_MAX];
- char prop_value[PROPERTY_VALUE_MAX] = {'\0'};
- char daemon_cmd[PROPERTY_VALUE_MAX * 2 + sizeof(DHCP_CONFIG_PATH)];
- const char *ctrl_prop = "ctl.start";
- const char *desired_status = "running";
- /* Interface name after converting p2p0-p2p0-X to p2p to reuse system properties */
- char p2p_interface[MAX_INTERFACE_LENGTH];
-
- get_p2p_interface_replacement(interface, p2p_interface);
-
- snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
- DHCP_PROP_NAME_PREFIX,
- p2p_interface);
-
- snprintf(daemon_prop_name, sizeof(daemon_prop_name), "%s_%s",
- DAEMON_PROP_NAME,
- p2p_interface);
-
- /* Erase any previous setting of the dhcp result property */
- property_set(result_prop_name, "");
-
- /* Start the daemon and wait until it's ready */
- if (property_get(HOSTNAME_PROP_NAME, prop_value, NULL) && (prop_value[0] != '\0'))
- snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:-f %s -h %s %s", DAEMON_NAME,
- p2p_interface, DHCP_CONFIG_PATH, prop_value, interface);
- else
- snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:-f %s %s", DAEMON_NAME,
- p2p_interface, DHCP_CONFIG_PATH, interface);
- memset(prop_value, '\0', PROPERTY_VALUE_MAX);
- property_set(ctrl_prop, daemon_cmd);
- if (wait_for_property(daemon_prop_name, desired_status, 10) < 0) {
- snprintf(errmsg, sizeof(errmsg), "%s", "Timed out waiting for dhcpcd to start");
- return -1;
- }
-
- /* Wait for the daemon to return a result */
- if (wait_for_property(result_prop_name, NULL, 30) < 0) {
- snprintf(errmsg, sizeof(errmsg), "%s", "Timed out waiting for DHCP to finish");
- return -1;
- }
-
- return 0;
-}
-
-/**
- * Stop the DHCP client daemon.
- */
-int dhcp_stop(const char *interface)
-{
- char result_prop_name[PROPERTY_KEY_MAX];
- char daemon_prop_name[PROPERTY_KEY_MAX];
- char daemon_cmd[PROPERTY_VALUE_MAX * 2];
- const char *ctrl_prop = "ctl.stop";
- const char *desired_status = "stopped";
-
- char p2p_interface[MAX_INTERFACE_LENGTH];
-
- get_p2p_interface_replacement(interface, p2p_interface);
-
- snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
- DHCP_PROP_NAME_PREFIX,
- p2p_interface);
-
- snprintf(daemon_prop_name, sizeof(daemon_prop_name), "%s_%s",
- DAEMON_PROP_NAME,
- p2p_interface);
-
- snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s", DAEMON_NAME, p2p_interface);
-
- /* Stop the daemon and wait until it's reported to be stopped */
- property_set(ctrl_prop, daemon_cmd);
- if (wait_for_property(daemon_prop_name, desired_status, 5) < 0) {
- return -1;
- }
- property_set(result_prop_name, "failed");
- return 0;
-}
-
-/**
- * Release the current DHCP client lease.
- */
-int dhcp_release_lease(const char *interface)
-{
- char daemon_prop_name[PROPERTY_KEY_MAX];
- char daemon_cmd[PROPERTY_VALUE_MAX * 2];
- const char *ctrl_prop = "ctl.stop";
- const char *desired_status = "stopped";
-
- char p2p_interface[MAX_INTERFACE_LENGTH];
-
- get_p2p_interface_replacement(interface, p2p_interface);
-
- snprintf(daemon_prop_name, sizeof(daemon_prop_name), "%s_%s",
- DAEMON_PROP_NAME,
- p2p_interface);
-
- snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s", DAEMON_NAME, p2p_interface);
-
- /* Stop the daemon and wait until it's reported to be stopped */
- property_set(ctrl_prop, daemon_cmd);
- if (wait_for_property(daemon_prop_name, desired_status, 5) < 0) {
- return -1;
- }
- return 0;
-}
-
-char *dhcp_get_errmsg() {
- return errmsg;
-}
-
-/**
- * The device init.rc file needs a corresponding entry.
- *
- * Example:
- * service iprenew_<interface> /system/bin/dhcpcd -n
- *
- */
-int dhcp_start_renew(const char *interface)
-{
- char result_prop_name[PROPERTY_KEY_MAX];
- char prop_value[PROPERTY_VALUE_MAX] = {'\0'};
- char daemon_cmd[PROPERTY_VALUE_MAX * 2];
- const char *ctrl_prop = "ctl.start";
-
- char p2p_interface[MAX_INTERFACE_LENGTH];
-
- get_p2p_interface_replacement(interface, p2p_interface);
-
- snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
- DHCP_PROP_NAME_PREFIX,
- p2p_interface);
-
- /* Erase any previous setting of the dhcp result property */
- property_set(result_prop_name, "");
-
- /* Start the renew daemon and wait until it's ready */
- snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:%s", DAEMON_NAME_RENEW,
- p2p_interface, interface);
- memset(prop_value, '\0', PROPERTY_VALUE_MAX);
- property_set(ctrl_prop, daemon_cmd);
-
- /* Wait for the daemon to return a result */
- if (wait_for_property(result_prop_name, NULL, 30) < 0) {
- snprintf(errmsg, sizeof(errmsg), "%s", "Timed out waiting for DHCP Renew to finish");
- return -1;
- }
-
- return 0;
-}
diff --git a/libnetutils/dhcptool.c b/libnetutils/dhcptool.c
index 352ac5e..a2d3869 100644
--- a/libnetutils/dhcptool.c
+++ b/libnetutils/dhcptool.c
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <err.h>
#include <errno.h>
#include <error.h>
#include <stdbool.h>
@@ -29,12 +30,14 @@
char* interface = argv[1];
if (ifc_init()) {
- error(EXIT_FAILURE, errno, "dhcptool %s: ifc_init failed", interface);
+ err(errno, "dhcptool %s: ifc_init failed", interface);
+ ifc_close();
+ return EXIT_FAILURE;
}
int rc = do_dhcp(interface);
if (rc) {
- error(0, errno, "dhcptool %s: do_dhcp failed", interface);
+ err(errno, "dhcptool %s: do_dhcp failed", interface);
}
ifc_close();
diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c
index e0a9f7f..85ff070 100644
--- a/libnetutils/ifc_utils.c
+++ b/libnetutils/ifc_utils.c
@@ -19,6 +19,7 @@
#include <unistd.h>
#include <string.h>
#include <errno.h>
+#include <pthread.h>
#include <sys/socket.h>
#include <sys/select.h>
@@ -57,6 +58,8 @@
static int ifc_ctl_sock = -1;
static int ifc_ctl_sock6 = -1;
+static pthread_mutex_t ifc_sock_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+static pthread_mutex_t ifc_sock6_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
void printerr(char *fmt, ...);
#define DBG 0
@@ -122,6 +125,8 @@
int ifc_init(void)
{
int ret;
+
+ pthread_mutex_lock(&ifc_sock_mutex);
if (ifc_ctl_sock == -1) {
ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (ifc_ctl_sock < 0) {
@@ -136,6 +141,7 @@
int ifc_init6(void)
{
+ pthread_mutex_lock(&ifc_sock6_mutex);
if (ifc_ctl_sock6 == -1) {
ifc_ctl_sock6 = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (ifc_ctl_sock6 < 0) {
@@ -152,6 +158,7 @@
(void)close(ifc_ctl_sock);
ifc_ctl_sock = -1;
}
+ pthread_mutex_unlock(&ifc_sock_mutex);
}
void ifc_close6(void)
@@ -160,6 +167,7 @@
(void)close(ifc_ctl_sock6);
ifc_ctl_sock6 = -1;
}
+ pthread_mutex_unlock(&ifc_sock6_mutex);
}
static void ifc_init_ifr(const char *name, struct ifreq *ifr)
@@ -541,6 +549,7 @@
ifc_init();
if (ifc_ctl_sock < 0) {
+ ifc_close();
return -errno;
}
diff --git a/libprocessgroup/Android.mk b/libprocessgroup/Android.mk
index ee6ba58..1885fa5 100644
--- a/libprocessgroup/Android.mk
+++ b/libprocessgroup/Android.mk
@@ -7,14 +7,4 @@
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_CFLAGS := -Wall -Werror
-LOCAL_REQUIRED_MODULE := processgroup_cleanup
include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := cleanup.cpp
-LOCAL_MODULE := processgroup_cleanup
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_CFLAGS := -Wall -Werror
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_STATIC_LIBRARIES := libc libcutils
-include $(BUILD_EXECUTABLE)
diff --git a/libprocessgroup/cleanup.cpp b/libprocessgroup/cleanup.cpp
deleted file mode 100644
index cca8dc4..0000000
--- a/libprocessgroup/cleanup.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2014 Google, Inc
- *
- * 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 <string.h>
-#include <unistd.h>
-#include <sys/syslimits.h>
-
-#include "processgroup_priv.h"
-
-int main(int argc, char **argv)
-{
- char buf[PATH_MAX];
- if (argc != 2)
- return -1;
-
- memcpy(buf, PROCESSGROUP_CGROUP_PATH, sizeof(PROCESSGROUP_CGROUP_PATH));
- strlcat(buf, argv[1], sizeof(buf));
- return rmdir(buf);
-}
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 00a0357..ba97f32 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -22,6 +22,7 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
+#include <mutex>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@@ -36,7 +37,27 @@
#include <utils/SystemClock.h>
#include <processgroup/processgroup.h>
-#include "processgroup_priv.h"
+
+#define MEM_CGROUP_PATH "/dev/memcg/apps"
+#define MEM_CGROUP_TASKS "/dev/memcg/apps/tasks"
+#define ACCT_CGROUP_PATH "/acct"
+
+#define PROCESSGROUP_UID_PREFIX "uid_"
+#define PROCESSGROUP_PID_PREFIX "pid_"
+#define PROCESSGROUP_CGROUP_PROCS_FILE "/cgroup.procs"
+#define PROCESSGROUP_MAX_UID_LEN 11
+#define PROCESSGROUP_MAX_PID_LEN 11
+#define PROCESSGROUP_MAX_PATH_LEN \
+ ((sizeof(MEM_CGROUP_PATH) > sizeof(ACCT_CGROUP_PATH) ? \
+ sizeof(MEM_CGROUP_PATH) : sizeof(ACCT_CGROUP_PATH)) + \
+ sizeof(PROCESSGROUP_UID_PREFIX) + 1 + \
+ PROCESSGROUP_MAX_UID_LEN + \
+ sizeof(PROCESSGROUP_PID_PREFIX) + 1 + \
+ PROCESSGROUP_MAX_PID_LEN + \
+ sizeof(PROCESSGROUP_CGROUP_PROCS_FILE) + \
+ 1)
+
+std::once_flag init_path_flag;
struct ctx {
bool initialized;
@@ -46,10 +67,21 @@
size_t buf_len;
};
+static const char* getCgroupRootPath() {
+ static const char* cgroup_root_path = NULL;
+ std::call_once(init_path_flag, [&]() {
+ // Check if mem cgroup is mounted, only then check for write-access to avoid
+ // SELinux denials
+ cgroup_root_path = access(MEM_CGROUP_TASKS, F_OK) || access(MEM_CGROUP_PATH, W_OK) ?
+ ACCT_CGROUP_PATH : MEM_CGROUP_PATH;
+ });
+ return cgroup_root_path;
+}
+
static int convertUidToPath(char *path, size_t size, uid_t uid)
{
return snprintf(path, size, "%s/%s%d",
- PROCESSGROUP_CGROUP_PATH,
+ getCgroupRootPath(),
PROCESSGROUP_UID_PREFIX,
uid);
}
@@ -57,7 +89,7 @@
static int convertUidPidToPath(char *path, size_t size, uid_t uid, int pid)
{
return snprintf(path, size, "%s/%s%d/%s%d",
- PROCESSGROUP_CGROUP_PATH,
+ getCgroupRootPath(),
PROCESSGROUP_UID_PREFIX,
uid,
PROCESSGROUP_PID_PREFIX,
@@ -188,9 +220,10 @@
void removeAllProcessGroups()
{
SLOGV("removeAllProcessGroups()");
- std::unique_ptr<DIR, decltype(&closedir)> root(opendir(PROCESSGROUP_CGROUP_PATH), closedir);
+ const char *cgroup_root_path = getCgroupRootPath();
+ std::unique_ptr<DIR, decltype(&closedir)> root(opendir(cgroup_root_path), closedir);
if (root == NULL) {
- SLOGE("failed to open %s: %s", PROCESSGROUP_CGROUP_PATH, strerror(errno));
+ SLOGE("failed to open %s: %s", cgroup_root_path, strerror(errno));
} else {
struct dirent cur;
struct dirent *dir;
@@ -204,7 +237,7 @@
continue;
}
- snprintf(path, sizeof(path), "%s/%s", PROCESSGROUP_CGROUP_PATH, dir->d_name);
+ snprintf(path, sizeof(path), "%s/%s", cgroup_root_path, dir->d_name);
removeUidProcessGroups(path);
SLOGV("removing %s\n", path);
rmdir(path);
diff --git a/libprocessgroup/processgroup_priv.h b/libprocessgroup/processgroup_priv.h
deleted file mode 100644
index 1895bf9..0000000
--- a/libprocessgroup/processgroup_priv.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2014 Google, Inc
- *
- * 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 _PROCESSGROUP_PRIV_H_
-#define _PROCESSGROUP_PRIV_H_
-
-#define PROCESSGROUP_CGROUP_PATH "/acct"
-#define PROCESSGROUP_UID_PREFIX "uid_"
-#define PROCESSGROUP_PID_PREFIX "pid_"
-#define PROCESSGROUP_CGROUP_PROCS_FILE "/cgroup.procs"
-#define PROCESSGROUP_MAX_UID_LEN 11
-#define PROCESSGROUP_MAX_PID_LEN 11
-#define PROCESSGROUP_MAX_PATH_LEN \
- (sizeof(PROCESSGROUP_CGROUP_PATH) + \
- sizeof(PROCESSGROUP_UID_PREFIX) + 1 + \
- PROCESSGROUP_MAX_UID_LEN + \
- sizeof(PROCESSGROUP_PID_PREFIX) + 1 + \
- PROCESSGROUP_MAX_PID_LEN + \
- sizeof(PROCESSGROUP_CGROUP_PROCS_FILE) + \
- 1)
-
-#endif
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 23dcd62..739fad7 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -159,7 +159,7 @@
struct ifaddrmsg *ifaddr = (struct ifaddrmsg *) NLMSG_DATA(nh);
struct ifa_cacheinfo *cacheinfo = NULL;
char addrstr[INET6_ADDRSTRLEN] = "";
- char ifname[IFNAMSIZ];
+ char ifname[IFNAMSIZ] = "";
if (!checkRtNetlinkLength(nh, sizeof(*ifaddr)))
return false;
@@ -207,8 +207,7 @@
// Find the interface name.
if (!if_indextoname(ifaddr->ifa_index, ifname)) {
- SLOGE("Unknown ifindex %d in %s", ifaddr->ifa_index, msgtype);
- return false;
+ SLOGD("Unknown ifindex %d in %s", ifaddr->ifa_index, msgtype);
}
} else if (rta->rta_type == IFA_CACHEINFO) {
@@ -235,8 +234,7 @@
mAction = (type == RTM_NEWADDR) ? Action::kAddressUpdated :
Action::kAddressRemoved;
mSubsystem = strdup("net");
- asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr,
- ifaddr->ifa_prefixlen);
+ asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr, ifaddr->ifa_prefixlen);
asprintf(&mParams[1], "INTERFACE=%s", ifname);
asprintf(&mParams[2], "FLAGS=%u", ifaddr->ifa_flags);
asprintf(&mParams[3], "SCOPE=%u", ifaddr->ifa_scope);
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index b8e3215..299fdc4 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -617,6 +617,11 @@
return ioctl(device->fd, USBDEVFS_BULK, &ctrl);
}
+int usb_device_reset(struct usb_device *device)
+{
+ return ioctl(device->fd, USBDEVFS_RESET);
+}
+
struct usb_request *usb_request_new(struct usb_device *dev,
const struct usb_endpoint_descriptor *ep_desc)
{
diff --git a/libutils/Android.mk b/libutils/Android.mk
index 6f88a6d..84bac32 100644
--- a/libutils/Android.mk
+++ b/libutils/Android.mk
@@ -106,19 +106,16 @@
LOCAL_SANITIZE := integer
include $(BUILD_SHARED_LIBRARY)
-# Include subdirectory makefiles
-# ============================================================
-
include $(CLEAR_VARS)
LOCAL_MODULE := SharedBufferTest
-LOCAL_STATIC_LIBRARIES := libutils libcutils
+LOCAL_STATIC_LIBRARIES := libutils
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SRC_FILES := SharedBufferTest.cpp
include $(BUILD_NATIVE_TEST)
include $(CLEAR_VARS)
LOCAL_MODULE := SharedBufferTest
-LOCAL_STATIC_LIBRARIES := libutils libcutils
+LOCAL_STATIC_LIBRARIES := libutils
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SRC_FILES := SharedBufferTest.cpp
include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libutils/SharedBuffer.cpp b/libutils/SharedBuffer.cpp
index c7dd1ab..34d75ee 100644
--- a/libutils/SharedBuffer.cpp
+++ b/libutils/SharedBuffer.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define __STDC_LIMIT_MACROS
-#include <stdint.h>
#include <stdlib.h>
#include <string.h>
diff --git a/libutils/SharedBufferTest.cpp b/libutils/SharedBufferTest.cpp
index a0484ff..33a4e0c 100644
--- a/libutils/SharedBufferTest.cpp
+++ b/libutils/SharedBufferTest.cpp
@@ -31,10 +31,10 @@
// Check that null is returned, as we are asking for the whole address space.
android::SharedBuffer* buf =
android::SharedBuffer::alloc(SIZE_MAX - sizeof(android::SharedBuffer) - 1);
- ASSERT_TRUE(NULL == buf);
+ ASSERT_EQ(nullptr, buf);
buf = android::SharedBuffer::alloc(0);
- ASSERT_FALSE(NULL == buf);
+ ASSERT_NE(nullptr, buf);
ASSERT_EQ(0U, buf->size());
buf->release();
}
@@ -49,7 +49,7 @@
// Make sure we don't die here.
// Check that null is returned, as we are asking for the whole address space.
buf = buf->editResize(SIZE_MAX - sizeof(android::SharedBuffer) - 1);
- ASSERT_TRUE(NULL == buf);
+ ASSERT_EQ(nullptr, buf);
buf = android::SharedBuffer::alloc(10);
buf = buf->editResize(0);
diff --git a/libutils/tests/String8_test.cpp b/libutils/tests/String8_test.cpp
index c42c68d..01e64f6 100644
--- a/libutils/tests/String8_test.cpp
+++ b/libutils/tests/String8_test.cpp
@@ -72,4 +72,9 @@
EXPECT_STREQ(src3, " Verify me.");
}
+TEST_F(String8Test, SetToSizeMaxReturnsNoMemory) {
+ const char *in = "some string";
+ EXPECT_EQ(NO_MEMORY, String8("").setTo(in, SIZE_MAX));
+}
+
}
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index aa3db8a..afc81ed 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -39,7 +39,7 @@
#endif
#define MEMCG_SYSFS_PATH "/dev/memcg/"
-#define MEMPRESSURE_WATCH_LEVEL "medium"
+#define MEMPRESSURE_WATCH_LEVEL "low"
#define ZONEINFO_PATH "/proc/zoneinfo"
#define LINE_MAX 128
@@ -77,12 +77,7 @@
static int epollfd;
static int maxevents;
-#define OOM_DISABLE (-17)
-/* inclusive */
-#define OOM_ADJUST_MIN (-16)
-#define OOM_ADJUST_MAX 15
-
-/* kernel OOM score values */
+/* OOM score values used by both kernel and framework */
#define OOM_SCORE_ADJ_MIN (-1000)
#define OOM_SCORE_ADJ_MAX 1000
@@ -114,8 +109,8 @@
static struct proc *pidhash[PIDHASH_SZ];
#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
-#define ADJTOSLOT(adj) (adj + -OOM_ADJUST_MIN)
-static struct adjslot_list procadjslot_list[ADJTOSLOT(OOM_ADJUST_MAX) + 1];
+#define ADJTOSLOT(adj) (adj + -OOM_SCORE_ADJ_MIN)
+static struct adjslot_list procadjslot_list[ADJTOSLOT(OOM_SCORE_ADJ_MAX) + 1];
/*
* Wait 1-2 seconds for the death report of a killed process prior to
@@ -148,14 +143,6 @@
return ret;
}
-static int lowmem_oom_adj_to_oom_score_adj(int oom_adj)
-{
- if (oom_adj == OOM_ADJUST_MAX)
- return OOM_SCORE_ADJ_MAX;
- else
- return (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE;
-}
-
static struct proc *pid_lookup(int pid) {
struct proc *procp;
@@ -254,13 +241,13 @@
char path[80];
char val[20];
- if (oomadj < OOM_DISABLE || oomadj > OOM_ADJUST_MAX) {
+ if (oomadj < OOM_SCORE_ADJ_MIN || oomadj > OOM_SCORE_ADJ_MAX) {
ALOGE("Invalid PROCPRIO oomadj argument %d", oomadj);
return;
}
snprintf(path, sizeof(path), "/proc/%d/oom_score_adj", pid);
- snprintf(val, sizeof(val), "%d", lowmem_oom_adj_to_oom_score_adj(oomadj));
+ snprintf(val, sizeof(val), "%d", oomadj);
writefilestring(path, val);
if (use_inkernel_interface)
@@ -608,7 +595,7 @@
static int find_and_kill_process(int other_free, int other_file, bool first)
{
int i;
- int min_score_adj = OOM_ADJUST_MAX + 1;
+ int min_score_adj = OOM_SCORE_ADJ_MAX + 1;
int minfree = 0;
int killed_size = 0;
@@ -620,10 +607,10 @@
}
}
- if (min_score_adj == OOM_ADJUST_MAX + 1)
+ if (min_score_adj == OOM_SCORE_ADJ_MAX + 1)
return 0;
- for (i = OOM_ADJUST_MAX; i >= min_score_adj; i--) {
+ for (i = OOM_SCORE_ADJ_MAX; i >= min_score_adj; i--) {
struct proc *procp;
retry:
@@ -784,7 +771,7 @@
ALOGE("Kernel does not support memory pressure events or in-kernel low memory killer");
}
- for (i = 0; i <= ADJTOSLOT(OOM_ADJUST_MAX); i++) {
+ for (i = 0; i <= ADJTOSLOT(OOM_SCORE_ADJ_MAX); i++) {
procadjslot_list[i].next = &procadjslot_list[i];
procadjslot_list[i].prev = &procadjslot_list[i];
}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 6d5023e..194b41b 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -46,29 +46,16 @@
mount cgroup none /acct cpuacct
mkdir /acct/uid
- # Create cgroup mount point for memory
- mount tmpfs none /sys/fs/cgroup mode=0750,uid=0,gid=1000
- mkdir /sys/fs/cgroup/memory 0750 root system
- mount cgroup none /sys/fs/cgroup/memory memory
- write /sys/fs/cgroup/memory/memory.move_charge_at_immigrate 1
- chown root system /sys/fs/cgroup/memory/tasks
- chmod 0660 /sys/fs/cgroup/memory/tasks
- mkdir /sys/fs/cgroup/memory/sw 0750 root system
- write /sys/fs/cgroup/memory/sw/memory.swappiness 100
- write /sys/fs/cgroup/memory/sw/memory.move_charge_at_immigrate 1
- chown root system /sys/fs/cgroup/memory/sw/tasks
- chmod 0660 /sys/fs/cgroup/memory/sw/tasks
-
# Create energy-aware scheduler tuning nodes
- mkdir /sys/fs/cgroup/stune
- mount cgroup none /sys/fs/cgroup/stune schedtune
- mkdir /sys/fs/cgroup/stune/foreground
- chown system system /sys/fs/cgroup/stune
- chown system system /sys/fs/cgroup/stune/foreground
- chown system system /sys/fs/cgroup/stune/tasks
- chown system system /sys/fs/cgroup/stune/foreground/tasks
- chmod 0664 /sys/fs/cgroup/stune/tasks
- chmod 0664 /sys/fs/cgroup/stune/foreground/tasks
+ mkdir /dev/stune
+ mount cgroup none /dev/stune schedtune
+ mkdir /dev/stune/foreground
+ chown system system /dev/stune
+ chown system system /dev/stune/foreground
+ chown system system /dev/stune/tasks
+ chown system system /dev/stune/foreground/tasks
+ chmod 0664 /dev/stune/tasks
+ chmod 0664 /dev/stune/foreground/tasks
# Mount staging areas for devices managed by vold
# See storage config details at http://source.android.com/tech/storage/
@@ -83,6 +70,7 @@
mkdir /mnt/user 0755 root root
mkdir /mnt/user/0 0755 root root
mkdir /mnt/expand 0771 system system
+ mkdir /mnt/appfuse 0711 root root
# Storage views to support runtime permissions
mkdir /mnt/runtime 0700 root root
@@ -97,9 +85,11 @@
symlink /storage/self/primary /sdcard
symlink /mnt/user/0/primary /mnt/runtime/default/self/primary
- # memory control cgroup
+ # root memory control cgroup, used by lmkd
mkdir /dev/memcg 0700 root system
mount cgroup none /dev/memcg memory
+ # app mem cgroups, used by activity manager, lmkd and zygote
+ mkdir /dev/memcg/apps/ 0755 system system
write /proc/sys/kernel/panic_on_oops 1
write /proc/sys/kernel/hung_task_timeout_secs 0
@@ -175,21 +165,32 @@
write /dev/cpuset/system-background/cpus 0
write /dev/cpuset/system-background/mems 0
+ mkdir /dev/cpuset/top-app
+ write /dev/cpuset/top-app/cpus 0
+ write /dev/cpuset/top-app/mems 0
+
# change permissions for all cpusets we'll touch at runtime
chown system system /dev/cpuset
chown system system /dev/cpuset/foreground
chown system system /dev/cpuset/foreground/boost
chown system system /dev/cpuset/background
chown system system /dev/cpuset/system-background
+ chown system system /dev/cpuset/top-app
chown system system /dev/cpuset/tasks
chown system system /dev/cpuset/foreground/tasks
chown system system /dev/cpuset/foreground/boost/tasks
chown system system /dev/cpuset/background/tasks
chown system system /dev/cpuset/system-background/tasks
+ chown system system /dev/cpuset/top-app/tasks
+
+ # set system-background to 0775 so SurfaceFlinger can touch it
+ chmod 0775 /dev/cpuset/system-background
+
chmod 0664 /dev/cpuset/foreground/tasks
chmod 0664 /dev/cpuset/foreground/boost/tasks
chmod 0664 /dev/cpuset/background/tasks
chmod 0664 /dev/cpuset/system-background/tasks
+ chmod 0664 /dev/cpuset/top-app/tasks
chmod 0664 /dev/cpuset/tasks
@@ -285,6 +286,10 @@
# permissions if created by the recovery system.
mkdir /cache/recovery 0770 system cache
+ # Backup/restore mechanism uses the cache partition
+ mkdir /cache/backup_stage 0700 system system
+ mkdir /cache/backup 0700 system system
+
#change permissions on vmallocinfo so we can grab it from bugreports
chown root log /proc/vmallocinfo
chmod 0440 /proc/vmallocinfo
@@ -321,8 +326,6 @@
start vold
installkey /data
- # Emulated internal storage area
- mkdir /data/media 0770 media_rw media_rw
# Start bootcharting as soon as possible after the data partition is
# mounted to collect more data.
mkdir /data/bootchart 0755 shell shell
@@ -359,16 +362,23 @@
chmod 0660 /data/misc/wifi/wpa_supplicant.conf
mkdir /data/local 0751 root root
mkdir /data/misc/media 0700 media media
+ mkdir /data/misc/audioserver 0700 audioserver audioserver
+ mkdir /data/misc/cameraserver 0700 cameraserver cameraserver
mkdir /data/misc/vold 0700 root root
mkdir /data/misc/boottrace 0771 system shell
mkdir /data/misc/update_engine 0700 root root
mkdir /data/misc/trace 0700 root root
+ # profile file layout
+ mkdir /data/misc/profiles 0771 system system
+ mkdir /data/misc/profiles/cur 0771 system system
+ mkdir /data/misc/profiles/ref 0771 system system
# For security reasons, /data/local/tmp should always be empty.
# Do not place files or directories in /data/local/tmp
mkdir /data/local/tmp 0771 shell shell
mkdir /data/data 0771 system system
mkdir /data/app-private 0771 system system
+ mkdir /data/app-ephemeral 0771 system system
mkdir /data/app-asec 0700 root root
mkdir /data/app-lib 0771 system system
mkdir /data/app 0771 system system
@@ -377,6 +387,8 @@
# create dalvik-cache, so as to enforce our permissions
mkdir /data/dalvik-cache 0771 root root
+ # create the A/B OTA directory, so as to enforce our permissions
+ mkdir /data/ota 0771 root root
# create resource-cache and double-check the perms
mkdir /data/resource-cache 0771 system system
@@ -397,7 +409,8 @@
mkdir /data/anr 0775 system system
# symlink to bugreport storage location
- symlink /data/data/com.android.shell/files/bugreports /data/bugreports
+ rm /data/bugreports
+ symlink /data/user_de/0/com.android.shell/files/bugreports /data/bugreports
# Separate location for storing security policy files on data
mkdir /data/security 0711 system system
@@ -405,13 +418,25 @@
# Create all remaining /data root dirs so that they are made through init
# and get proper encryption policy installed
mkdir /data/backup 0700 system system
- mkdir /data/media 0770 media_rw media_rw
mkdir /data/ss 0700 system system
+
mkdir /data/system 0775 system system
mkdir /data/system/heapdump 0700 system system
- mkdir /data/user 0711 system system
- setusercryptopolicies /data/user
+ mkdir /data/system_de 0770 system system
+ mkdir /data/system_ce 0770 system system
+
+ mkdir /data/misc_de 01771 system misc
+ mkdir /data/misc_ce 01771 system misc
+
+ mkdir /data/user 0711 system system
+ mkdir /data/user_de 0711 system system
+ symlink /data/data /data/user/0
+
+ mkdir /data/media 0770 media_rw media_rw
+ mkdir /data/media/obb 0770 media_rw media_rw
+
+ init_user0
# Reload policy from /data/security if present.
setprop selinux.reload_policy 1
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index 0ca38b9..22b9d6b 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -3,6 +3,8 @@
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
+ onrestart restart audioserver
+ onrestart restart cameraserver
onrestart restart media
onrestart restart netd
- writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
+ writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index 1646c0f..555eda4 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -3,6 +3,8 @@
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
+ onrestart restart audioserver
+ onrestart restart cameraserver
onrestart restart media
onrestart restart netd
writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
@@ -11,4 +13,4 @@
class main
socket zygote_secondary stream 660 root system
onrestart restart zygote
- writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
+ writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index b477c8e..297468c 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -3,6 +3,8 @@
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
+ onrestart restart audioserver
+ onrestart restart cameraserver
onrestart restart media
onrestart restart netd
- writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
+ writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 633a981..46f9f02 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -3,6 +3,8 @@
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
+ onrestart restart audioserver
+ onrestart restart cameraserver
onrestart restart media
onrestart restart netd
writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
@@ -11,4 +13,4 @@
class main
socket zygote_secondary stream 660 root system
onrestart restart zygote
- writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
+ writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index f862561..45efe36 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -1214,13 +1214,7 @@
}
out.fh = ptr_to_id(h);
out.open_flags = 0;
-
-#ifdef FUSE_STACKED_IO
- out.lower_fd = h->fd;
-#else
out.padding = 0;
-#endif
-
fuse_reply(fuse, hdr->unique, &out, sizeof(out));
return NO_STATUS;
}
@@ -1384,13 +1378,7 @@
}
out.fh = ptr_to_id(h);
out.open_flags = 0;
-
-#ifdef FUSE_STACKED_IO
- out.lower_fd = -1;
-#else
out.padding = 0;
-#endif
-
fuse_reply(fuse, hdr->unique, &out, sizeof(out));
return NO_STATUS;
}
@@ -1472,11 +1460,6 @@
out.major = FUSE_KERNEL_VERSION;
out.max_readahead = req->max_readahead;
out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
-
-#ifdef FUSE_STACKED_IO
- out.flags |= FUSE_STACKED_IO;
-#endif
-
out.max_background = 32;
out.congestion_threshold = 32;
out.max_write = MAX_WRITE;
diff --git a/trusty/gatekeeper/Android.mk b/trusty/gatekeeper/Android.mk
new file mode 100644
index 0000000..13e9a09
--- /dev/null
+++ b/trusty/gatekeeper/Android.mk
@@ -0,0 +1,50 @@
+#
+# Copyright (C) 2015 The Android Open-Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# WARNING: Everything listed here will be built on ALL platforms,
+# including x86, the emulator, and the SDK. Modules must be uniquely
+# named (liblights.panda), and must build everywhere, or limit themselves
+# to only building on ARM if they include assembly. Individual makefiles
+# are responsible for having their own logic, for fine-grained control.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := gatekeeper.trusty
+
+LOCAL_MODULE_RELATIVE_PATH := hw
+
+LOCAL_SRC_FILES := \
+ module.cpp \
+ trusty_gatekeeper_ipc.c \
+ trusty_gatekeeper.cpp
+
+LOCAL_CLFAGS = -fvisibility=hidden -Wall -Werror
+
+LOCAL_SHARED_LIBRARIES := \
+ libgatekeeper \
+ liblog \
+ libcutils \
+ libtrusty
+
+LOCAL_MODULE_TAGS := optional
+
+# Symlink gatekeeper.trusty.so -> gatekeeper.<device>.so so libhardware can find it.
+LOCAL_POST_INSTALL_CMD = \
+ $(hide) ln -sf $(notdir $(LOCAL_INSTALLED_MODULE)) $(dir $(LOCAL_INSTALLED_MODULE))gatekeeper.$(TARGET_DEVICE).so
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/trusty/gatekeeper/gatekeeper_ipc.h b/trusty/gatekeeper/gatekeeper_ipc.h
new file mode 100644
index 0000000..b05dcd8
--- /dev/null
+++ b/trusty/gatekeeper/gatekeeper_ipc.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#define GATEKEEPER_PORT "com.android.trusty.gatekeeper"
+#define GATEKEEPER_MAX_BUFFER_LENGTH 1024
+
+enum gatekeeper_command {
+ GK_REQ_SHIFT = 1,
+ GK_RESP_BIT = 1,
+
+ GK_ENROLL = (0 << GK_REQ_SHIFT),
+ GK_VERIFY = (1 << GK_REQ_SHIFT),
+};
+
+/**
+ * gatekeeper_message - Serial header for communicating with GK server
+ * @cmd: the command, one of ENROLL, VERIFY. Payload must be a serialized
+ * buffer of the corresponding request object.
+ * @payload: start of the serialized command specific payload
+ */
+struct gatekeeper_message {
+ uint32_t cmd;
+ uint8_t payload[0];
+};
+
diff --git a/trusty/gatekeeper/module.cpp b/trusty/gatekeeper/module.cpp
new file mode 100644
index 0000000..0ee3c2f
--- /dev/null
+++ b/trusty/gatekeeper/module.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <hardware/hardware.h>
+
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "trusty_gatekeeper.h"
+
+using gatekeeper::TrustyGateKeeperDevice;
+
+static int trusty_gatekeeper_open(const hw_module_t *module, const char *name,
+ hw_device_t **device) {
+
+ if (strcmp(name, HARDWARE_GATEKEEPER) != 0) {
+ return -EINVAL;
+ }
+
+ TrustyGateKeeperDevice *gatekeeper = new TrustyGateKeeperDevice(module);
+ if (gatekeeper == NULL) return -ENOMEM;
+ *device = gatekeeper->hw_device();
+
+ return 0;
+}
+
+static struct hw_module_methods_t gatekeeper_module_methods = {
+ .open = trusty_gatekeeper_open,
+};
+
+struct gatekeeper_module HAL_MODULE_INFO_SYM __attribute__((visibility("default"))) = {
+ .common = {
+ .tag = HARDWARE_MODULE_TAG,
+ .module_api_version = GATEKEEPER_MODULE_API_VERSION_0_1,
+ .hal_api_version = HARDWARE_HAL_API_VERSION,
+ .id = GATEKEEPER_HARDWARE_MODULE_ID,
+ .name = "Trusty GateKeeper HAL",
+ .author = "The Android Open Source Project",
+ .methods = &gatekeeper_module_methods,
+ .dso = 0,
+ .reserved = {}
+ },
+};
diff --git a/trusty/gatekeeper/trusty_gatekeeper.cpp b/trusty/gatekeeper/trusty_gatekeeper.cpp
new file mode 100644
index 0000000..d24f44f
--- /dev/null
+++ b/trusty/gatekeeper/trusty_gatekeeper.cpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <assert.h>
+#include <type_traits>
+
+#include "trusty_gatekeeper.h"
+#include "trusty_gatekeeper_ipc.h"
+#include "gatekeeper_ipc.h"
+
+#define LOG_TAG "TrustyGateKeeper"
+#include <cutils/log.h>
+
+namespace gatekeeper {
+
+const uint32_t SEND_BUF_SIZE = 8192;
+const uint32_t RECV_BUF_SIZE = 8192;
+
+TrustyGateKeeperDevice::TrustyGateKeeperDevice(const hw_module_t *module) {
+#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
+ static_assert(std::is_standard_layout<TrustyGateKeeperDevice>::value,
+ "TrustyGateKeeperDevice must be standard layout");
+ static_assert(offsetof(TrustyGateKeeperDevice, device_) == 0,
+ "device_ must be the first member of TrustyGateKeeperDevice");
+ static_assert(offsetof(TrustyGateKeeperDevice, device_.common) == 0,
+ "common must be the first member of gatekeeper_device");
+#else
+ assert(reinterpret_cast<gatekeeper_device_t *>(this) == &device_);
+ assert(reinterpret_cast<hw_device_t *>(this) == &(device_.common));
+#endif
+
+ memset(&device_, 0, sizeof(device_));
+ device_.common.tag = HARDWARE_DEVICE_TAG;
+ device_.common.version = 1;
+ device_.common.module = const_cast<hw_module_t *>(module);
+ device_.common.close = close_device;
+
+ device_.enroll = enroll;
+ device_.verify = verify;
+ device_.delete_user = nullptr;
+ device_.delete_all_users = nullptr;
+
+ int rc = trusty_gatekeeper_connect();
+ if (rc < 0) {
+ ALOGE("Error initializing trusty session: %d", rc);
+ }
+
+ error_ = rc;
+
+}
+
+hw_device_t* TrustyGateKeeperDevice::hw_device() {
+ return &device_.common;
+}
+
+int TrustyGateKeeperDevice::close_device(hw_device_t* dev) {
+ delete reinterpret_cast<TrustyGateKeeperDevice *>(dev);
+ return 0;
+}
+
+TrustyGateKeeperDevice::~TrustyGateKeeperDevice() {
+ trusty_gatekeeper_disconnect();
+}
+
+int TrustyGateKeeperDevice::Enroll(uint32_t uid, const uint8_t *current_password_handle,
+ uint32_t current_password_handle_length, const uint8_t *current_password,
+ uint32_t current_password_length, const uint8_t *desired_password,
+ uint32_t desired_password_length, uint8_t **enrolled_password_handle,
+ uint32_t *enrolled_password_handle_length) {
+
+ if (error_ != 0) {
+ return error_;
+ }
+
+ SizedBuffer desired_password_buffer(desired_password_length);
+ memcpy(desired_password_buffer.buffer.get(), desired_password, desired_password_length);
+
+ SizedBuffer current_password_handle_buffer(current_password_handle_length);
+ if (current_password_handle) {
+ memcpy(current_password_handle_buffer.buffer.get(), current_password_handle,
+ current_password_handle_length);
+ }
+
+ SizedBuffer current_password_buffer(current_password_length);
+ if (current_password) {
+ memcpy(current_password_buffer.buffer.get(), current_password, current_password_length);
+ }
+
+ EnrollRequest request(uid, ¤t_password_handle_buffer, &desired_password_buffer,
+ ¤t_password_buffer);
+ EnrollResponse response;
+
+ gatekeeper_error_t error = Send(request, &response);
+
+ if (error == ERROR_RETRY) {
+ return response.retry_timeout;
+ } else if (error != ERROR_NONE) {
+ return -EINVAL;
+ }
+
+ *enrolled_password_handle = response.enrolled_password_handle.buffer.release();
+ *enrolled_password_handle_length = response.enrolled_password_handle.length;
+
+
+ return 0;
+}
+
+int TrustyGateKeeperDevice::Verify(uint32_t uid, uint64_t challenge,
+ const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length,
+ const uint8_t *provided_password, uint32_t provided_password_length,
+ uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll) {
+ if (error_ != 0) {
+ return error_;
+ }
+
+ SizedBuffer password_handle_buffer(enrolled_password_handle_length);
+ memcpy(password_handle_buffer.buffer.get(), enrolled_password_handle,
+ enrolled_password_handle_length);
+ SizedBuffer provided_password_buffer(provided_password_length);
+ memcpy(provided_password_buffer.buffer.get(), provided_password, provided_password_length);
+
+ VerifyRequest request(uid, challenge, &password_handle_buffer, &provided_password_buffer);
+ VerifyResponse response;
+
+ gatekeeper_error_t error = Send(request, &response);
+
+ if (error == ERROR_RETRY) {
+ return response.retry_timeout;
+ } else if (error != ERROR_NONE) {
+ return -EINVAL;
+ }
+
+ if (auth_token != NULL && auth_token_length != NULL) {
+ *auth_token = response.auth_token.buffer.release();
+ *auth_token_length = response.auth_token.length;
+ }
+
+ if (request_reenroll != NULL) {
+ *request_reenroll = response.request_reenroll;
+ }
+
+ return 0;
+}
+
+gatekeeper_error_t TrustyGateKeeperDevice::Send(uint32_t command, const GateKeeperMessage& request,
+ GateKeeperMessage *response) {
+ uint32_t request_size = request.GetSerializedSize();
+ if (request_size > SEND_BUF_SIZE)
+ return ERROR_INVALID;
+ uint8_t send_buf[SEND_BUF_SIZE];
+ request.Serialize(send_buf, send_buf + request_size);
+
+ // Send it
+ uint8_t recv_buf[RECV_BUF_SIZE];
+ uint32_t response_size = RECV_BUF_SIZE;
+ int rc = trusty_gatekeeper_call(command, send_buf, request_size, recv_buf, &response_size);
+ if (rc < 0) {
+ ALOGE("error (%d) calling gatekeeper TA", rc);
+ return ERROR_INVALID;
+ }
+
+ const gatekeeper_message *msg = reinterpret_cast<gatekeeper_message *>(recv_buf);
+ const uint8_t *payload = msg->payload;
+
+ return response->Deserialize(payload, payload + response_size);
+}
+
+static inline TrustyGateKeeperDevice *convert_device(const gatekeeper_device *dev) {
+ return reinterpret_cast<TrustyGateKeeperDevice *>(const_cast<gatekeeper_device *>(dev));
+}
+
+/* static */
+int TrustyGateKeeperDevice::enroll(const struct gatekeeper_device *dev, uint32_t uid,
+ const uint8_t *current_password_handle, uint32_t current_password_handle_length,
+ const uint8_t *current_password, uint32_t current_password_length,
+ const uint8_t *desired_password, uint32_t desired_password_length,
+ uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length) {
+
+ if (dev == NULL ||
+ enrolled_password_handle == NULL || enrolled_password_handle_length == NULL ||
+ desired_password == NULL || desired_password_length == 0)
+ return -EINVAL;
+
+ // Current password and current password handle go together
+ if (current_password_handle == NULL || current_password_handle_length == 0 ||
+ current_password == NULL || current_password_length == 0) {
+ current_password_handle = NULL;
+ current_password_handle_length = 0;
+ current_password = NULL;
+ current_password_length = 0;
+ }
+
+ return convert_device(dev)->Enroll(uid, current_password_handle, current_password_handle_length,
+ current_password, current_password_length, desired_password, desired_password_length,
+ enrolled_password_handle, enrolled_password_handle_length);
+
+}
+
+/* static */
+int TrustyGateKeeperDevice::verify(const struct gatekeeper_device *dev, uint32_t uid,
+ uint64_t challenge, const uint8_t *enrolled_password_handle,
+ uint32_t enrolled_password_handle_length, const uint8_t *provided_password,
+ uint32_t provided_password_length, uint8_t **auth_token, uint32_t *auth_token_length,
+ bool *request_reenroll) {
+
+ if (dev == NULL || enrolled_password_handle == NULL ||
+ provided_password == NULL) {
+ return -EINVAL;
+ }
+
+ return convert_device(dev)->Verify(uid, challenge, enrolled_password_handle,
+ enrolled_password_handle_length, provided_password, provided_password_length,
+ auth_token, auth_token_length, request_reenroll);
+}
+};
diff --git a/trusty/gatekeeper/trusty_gatekeeper.h b/trusty/gatekeeper/trusty_gatekeeper.h
new file mode 100644
index 0000000..82108dc
--- /dev/null
+++ b/trusty/gatekeeper/trusty_gatekeeper.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2014 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 TRUSTY_GATEKEEPER_H
+#define TRUSTY_GATEKEEPER_H
+
+#include <hardware/gatekeeper.h>
+#include <gatekeeper/gatekeeper_messages.h>
+
+#include "gatekeeper_ipc.h"
+
+namespace gatekeeper {
+
+class TrustyGateKeeperDevice {
+ public:
+
+ TrustyGateKeeperDevice(const hw_module_t* module);
+ ~TrustyGateKeeperDevice();
+
+ hw_device_t* hw_device();
+
+ /**
+ * Enrolls password_payload, which should be derived from a user selected pin or password,
+ * with the authentication factor private key used only for enrolling authentication
+ * factor data.
+ *
+ * Returns: 0 on success or an error code less than 0 on error.
+ * On error, enrolled_password will not be allocated.
+ */
+ int Enroll(uint32_t uid, const uint8_t *current_password_handle,
+ uint32_t current_password_handle_length, const uint8_t *current_password,
+ uint32_t current_password_length, const uint8_t *desired_password,
+ uint32_t desired_password_length, uint8_t **enrolled_password_handle,
+ uint32_t *enrolled_password_handle_length);
+
+ /**
+ * Verifies provided_password matches expected_password after enrolling
+ * with the authentication factor private key.
+ *
+ * Implementations of this module may retain the result of this call
+ * to attest to the recency of authentication.
+ *
+ * On success, writes the address of a verification token to verification_token,
+ *
+ * Returns: 0 on success or an error code less than 0 on error
+ * On error, verification token will not be allocated
+ */
+ int Verify(uint32_t uid, uint64_t challenge, const uint8_t *enrolled_password_handle,
+ uint32_t enrolled_password_handle_length, const uint8_t *provided_password,
+ uint32_t provided_password_length, uint8_t **auth_token, uint32_t *auth_token_length,
+ bool *request_reenroll);
+
+ private:
+
+ gatekeeper_error_t Send(uint32_t command, const GateKeeperMessage& request,
+ GateKeeperMessage* response);
+
+ gatekeeper_error_t Send(const EnrollRequest& request, EnrollResponse *response) {
+ return Send(GK_ENROLL, request, response);
+ }
+
+ gatekeeper_error_t Send(const VerifyRequest& request, VerifyResponse *response) {
+ return Send(GK_VERIFY, request, response);
+ }
+
+ // Static methods interfacing the HAL API with the TrustyGateKeeper device
+
+ /**
+ * Enrolls desired_password, which should be derived from a user selected pin or password,
+ * with the authentication factor private key used only for enrolling authentication
+ * factor data.
+ *
+ * If there was already a password enrolled, it should be provided in
+ * current_password_handle, along with the current password in current_password
+ * that should validate against current_password_handle.
+ *
+ * Returns: 0 on success or an error code less than 0 on error.
+ * On error, enrolled_password_handle will not be allocated.
+ */
+ static int enroll(const struct gatekeeper_device *dev, uint32_t uid,
+ const uint8_t *current_password_handle, uint32_t current_password_handle_length,
+ const uint8_t *current_password, uint32_t current_password_length,
+ const uint8_t *desired_password, uint32_t desired_password_length,
+ uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length);
+
+ /**
+ * Verifies provided_password matches enrolled_password_handle.
+ *
+ * Implementations of this module may retain the result of this call
+ * to attest to the recency of authentication.
+ *
+ * On success, writes the address of a verification token to auth_token,
+ * usable to attest password verification to other trusted services. Clients
+ * may pass NULL for this value.
+ *
+ * Returns: 0 on success or an error code less than 0 on error
+ * On error, verification token will not be allocated
+ */
+ static int verify(const struct gatekeeper_device *dev, uint32_t uid, uint64_t challenge,
+ const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length,
+ const uint8_t *provided_password, uint32_t provided_password_length,
+ uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll);
+
+ static int close_device(hw_device_t* dev);
+
+ gatekeeper_device device_;
+ int error_;
+
+};
+}
+
+#endif
+
diff --git a/trusty/gatekeeper/trusty_gatekeeper_ipc.c b/trusty/gatekeeper/trusty_gatekeeper_ipc.c
new file mode 100644
index 0000000..a1c319e
--- /dev/null
+++ b/trusty/gatekeeper/trusty_gatekeeper_ipc.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LOG_TAG "TrustyGateKeeper"
+#include <cutils/log.h>
+#include <trusty/tipc.h>
+
+#include "trusty_gatekeeper_ipc.h"
+#include "gatekeeper_ipc.h"
+
+#define TRUSTY_DEVICE_NAME "/dev/trusty-ipc-dev0"
+
+static int handle_ = 0;
+
+int trusty_gatekeeper_connect() {
+ int rc = tipc_connect(TRUSTY_DEVICE_NAME, GATEKEEPER_PORT);
+ if (rc < 0) {
+ return rc;
+ }
+
+ handle_ = rc;
+ return 0;
+}
+
+int trusty_gatekeeper_call(uint32_t cmd, void *in, uint32_t in_size, uint8_t *out,
+ uint32_t *out_size) {
+ if (handle_ == 0) {
+ ALOGE("not connected\n");
+ return -EINVAL;
+ }
+
+ size_t msg_size = in_size + sizeof(struct gatekeeper_message);
+ struct gatekeeper_message *msg = malloc(msg_size);
+ msg->cmd = cmd;
+ memcpy(msg->payload, in, in_size);
+
+ ssize_t rc = write(handle_, msg, msg_size);
+ free(msg);
+
+ if (rc < 0) {
+ ALOGE("failed to send cmd (%d) to %s: %s\n", cmd,
+ GATEKEEPER_PORT, strerror(errno));
+ return -errno;
+ }
+
+ rc = read(handle_, out, *out_size);
+ if (rc < 0) {
+ ALOGE("failed to retrieve response for cmd (%d) to %s: %s\n",
+ cmd, GATEKEEPER_PORT, strerror(errno));
+ return -errno;
+ }
+
+ if ((size_t) rc < sizeof(struct gatekeeper_message)) {
+ ALOGE("invalid response size (%d)\n", (int) rc);
+ return -EINVAL;
+ }
+
+ msg = (struct gatekeeper_message *) out;
+
+ if ((cmd | GK_RESP_BIT) != msg->cmd) {
+ ALOGE("invalid command (%d)\n", msg->cmd);
+ return -EINVAL;
+ }
+
+ *out_size = ((size_t) rc) - sizeof(struct gatekeeper_message);
+ return rc;
+}
+
+void trusty_gatekeeper_disconnect() {
+ if (handle_ != 0) {
+ tipc_close(handle_);
+ }
+}
+
diff --git a/trusty/gatekeeper/trusty_gatekeeper_ipc.h b/trusty/gatekeeper/trusty_gatekeeper_ipc.h
new file mode 100644
index 0000000..f8de7f8
--- /dev/null
+++ b/trusty/gatekeeper/trusty_gatekeeper_ipc.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+__BEGIN_DECLS
+
+int trusty_gatekeeper_connect();
+int trusty_gatekeeper_call(uint32_t cmd, void *in, uint32_t in_size, uint8_t *out,
+ uint32_t *out_size);
+void trusty_gatekeeper_disconnect();
+
+__END_DECLS