Merge "Add missing include. Clang build fix." into mnc-dev
diff --git a/adb/Android.mk b/adb/Android.mk
index 1613a88..425bf9b 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -232,12 +232,11 @@
-D_GNU_SOURCE \
-Wno-deprecated-declarations \
-ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
-LOCAL_CFLAGS += -DALLOW_ADBD_ROOT=1
-endif
+LOCAL_CFLAGS += -DALLOW_ADBD_NO_AUTH=$(if $(filter userdebug eng,$(TARGET_BUILD_VARIANT)),1,0)
ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1
+LOCAL_CFLAGS += -DALLOW_ADBD_ROOT=1
endif
LOCAL_MODULE := adbd
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 8a7b9c9..f64b19f 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -421,9 +421,9 @@
parse_banner(reinterpret_cast<const char*>(p->data), t);
- if (HOST || !auth_enabled) {
+ if (HOST || !auth_required) {
handle_online(t);
- if(!HOST) send_connect(t);
+ if (!HOST) send_connect(t);
} else {
send_auth_request(t);
}
diff --git a/adb/adb_auth.cpp b/adb/adb_auth.cpp
index dc01825..cff26d6 100644
--- a/adb/adb_auth.cpp
+++ b/adb/adb_auth.cpp
@@ -28,7 +28,7 @@
#include "adb.h"
#include "transport.h"
-int auth_enabled = 0;
+bool auth_required = true;
void send_auth_request(atransport *t)
{
diff --git a/adb/adb_auth.h b/adb/adb_auth.h
index 1e1978d..a13604a 100644
--- a/adb/adb_auth.h
+++ b/adb/adb_auth.h
@@ -19,7 +19,7 @@
#include "adb.h"
-extern int auth_enabled;
+extern bool auth_required;
int adb_auth_keygen(const char* filename);
void adb_auth_verified(atransport *t);
diff --git a/adb/adb_auth_host.cpp b/adb/adb_auth_host.cpp
index 510dcc2..61a3777 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/adb_auth_host.cpp
@@ -173,7 +173,7 @@
return 0;
}
- outfile = fopen(path, "we");
+ outfile = fopen(path, "w");
if (!outfile) {
D("Failed to open '%s'\n", path);
return 0;
@@ -239,7 +239,7 @@
old_mask = umask(077);
- f = fopen(file, "we");
+ f = fopen(file, "w");
if (!f) {
D("Failed to open '%s'\n", file);
umask(old_mask);
@@ -273,7 +273,7 @@
{
D("read_key '%s'\n", file);
- FILE* fp = fopen(file, "re");
+ FILE* fp = fopen(file, "r");
if (!fp) {
D("Failed to open '%s': %s\n", file, strerror(errno));
return 0;
diff --git a/adb/adb_main.cpp b/adb/adb_main.cpp
index 3f88d13..45a2158 100644
--- a/adb/adb_main.cpp
+++ b/adb/adb_main.cpp
@@ -239,10 +239,11 @@
// descriptor will always be open.
adbd_cloexec_auth_socket();
- property_get("ro.adb.secure", value, "0");
- auth_enabled = !strcmp(value, "1");
- if (auth_enabled)
- adbd_auth_init();
+ if (ALLOW_ADBD_NO_AUTH && property_get_bool("ro.adb.secure", 0) == 0) {
+ auth_required = false;
+ }
+
+ adbd_auth_init();
// Our external storage path may be different than apps, since
// we aren't able to bind mount after dropping root.
diff --git a/fingerprintd/FingerprintDaemonProxy.cpp b/fingerprintd/FingerprintDaemonProxy.cpp
index a8a4024..4c8e478 100644
--- a/fingerprintd/FingerprintDaemonProxy.cpp
+++ b/fingerprintd/FingerprintDaemonProxy.cpp
@@ -41,7 +41,7 @@
closeHal();
}
-void FingerprintDaemonProxy::hal_notify_callback(fingerprint_msg_t msg) {
+void FingerprintDaemonProxy::hal_notify_callback(const fingerprint_msg_t *msg) {
FingerprintDaemonProxy* instance = FingerprintDaemonProxy::getInstance();
const sp<IFingerprintDaemonCallback> callback = instance->mCallback;
if (callback == NULL) {
@@ -49,52 +49,52 @@
return;
}
const int64_t device = (int64_t) instance->mDevice;
- switch (msg.type) {
+ switch (msg->type) {
case FINGERPRINT_ERROR:
- ALOGD("onError(%d)", msg.data.error);
- callback->onError(device, msg.data.error);
+ ALOGD("onError(%d)", msg->data.error);
+ callback->onError(device, msg->data.error);
break;
case FINGERPRINT_ACQUIRED:
- ALOGD("onAcquired(%d)", msg.data.acquired.acquired_info);
- callback->onAcquired(device, msg.data.acquired.acquired_info);
+ ALOGD("onAcquired(%d)", msg->data.acquired.acquired_info);
+ callback->onAcquired(device, msg->data.acquired.acquired_info);
break;
case FINGERPRINT_AUTHENTICATED:
ALOGD("onAuthenticated(fid=%d, gid=%d)",
- msg.data.authenticated.finger.fid,
- msg.data.authenticated.finger.gid);
- if (msg.data.authenticated.finger.fid != 0) {
- uint8_t* hat = reinterpret_cast<uint8_t *>(&msg.data.authenticated.hat);
- instance->notifyKeystore(hat, sizeof(msg.data.authenticated.hat));
+ msg->data.authenticated.finger.fid,
+ msg->data.authenticated.finger.gid);
+ if (msg->data.authenticated.finger.fid != 0) {
+ const uint8_t* hat = reinterpret_cast<const uint8_t *>(&msg->data.authenticated.hat);
+ instance->notifyKeystore(hat, sizeof(msg->data.authenticated.hat));
}
callback->onAuthenticated(device,
- msg.data.authenticated.finger.fid,
- msg.data.authenticated.finger.gid);
+ msg->data.authenticated.finger.fid,
+ msg->data.authenticated.finger.gid);
break;
case FINGERPRINT_TEMPLATE_ENROLLING:
ALOGD("onEnrollResult(fid=%d, gid=%d, rem=%d)",
- msg.data.enroll.finger.fid,
- msg.data.enroll.finger.gid,
- msg.data.enroll.samples_remaining);
+ msg->data.enroll.finger.fid,
+ msg->data.enroll.finger.gid,
+ msg->data.enroll.samples_remaining);
callback->onEnrollResult(device,
- msg.data.enroll.finger.fid,
- msg.data.enroll.finger.gid,
- msg.data.enroll.samples_remaining);
+ msg->data.enroll.finger.fid,
+ msg->data.enroll.finger.gid,
+ msg->data.enroll.samples_remaining);
break;
case FINGERPRINT_TEMPLATE_REMOVED:
ALOGD("onRemove(fid=%d, gid=%d)",
- msg.data.removed.finger.fid,
- msg.data.removed.finger.gid);
+ msg->data.removed.finger.fid,
+ msg->data.removed.finger.gid);
callback->onRemoved(device,
- msg.data.removed.finger.fid,
- msg.data.removed.finger.gid);
+ msg->data.removed.finger.fid,
+ msg->data.removed.finger.gid);
break;
default:
- ALOGE("invalid msg: %d", msg.type);
+ ALOGE("invalid msg type: %d", msg->type);
return;
}
}
-void FingerprintDaemonProxy::notifyKeystore(uint8_t *auth_token, size_t auth_token_length) {
+void FingerprintDaemonProxy::notifyKeystore(const uint8_t *auth_token, const size_t auth_token_length) {
if (auth_token != NULL && auth_token_length > 0) {
// TODO: cache service?
sp < IServiceManager > sm = defaultServiceManager();
@@ -151,10 +151,7 @@
int32_t FingerprintDaemonProxy::remove(int32_t fingerId, int32_t groupId) {
ALOG(LOG_VERBOSE, LOG_TAG, "remove(fid=%d, gid=%d)\n", fingerId, groupId);
- fingerprint_finger_id_t finger;
- finger.fid = fingerId;
- finger.gid = groupId;
- return mDevice->remove(mDevice, finger);
+ return mDevice->remove(mDevice, groupId, fingerId);
}
uint64_t FingerprintDaemonProxy::getAuthenticatorId() {
@@ -163,8 +160,8 @@
int32_t FingerprintDaemonProxy::setActiveGroup(int32_t groupId, const uint8_t* path,
ssize_t pathlen) {
- if (pathlen >= PATH_MAX) {
- ALOGE("Path name is too long\n");
+ if (pathlen >= PATH_MAX || pathlen <= 0) {
+ ALOGE("Bad path length: %zd", pathlen);
return -1;
}
// Convert to null-terminated string
@@ -173,7 +170,6 @@
path_name[pathlen] = '\0';
ALOG(LOG_VERBOSE, LOG_TAG, "setActiveGroup(%d, %s, %zu)", groupId, path_name, pathlen);
return mDevice->set_active_group(mDevice, groupId, path_name);
- return -1;
}
int64_t FingerprintDaemonProxy::openHal() {
diff --git a/fingerprintd/FingerprintDaemonProxy.h b/fingerprintd/FingerprintDaemonProxy.h
index 95c926b..50d30ef 100644
--- a/fingerprintd/FingerprintDaemonProxy.h
+++ b/fingerprintd/FingerprintDaemonProxy.h
@@ -48,8 +48,8 @@
FingerprintDaemonProxy();
virtual ~FingerprintDaemonProxy();
void binderDied(const wp<IBinder>& who);
- void notifyKeystore(uint8_t *auth_token, size_t auth_token_length);
- static void hal_notify_callback(fingerprint_msg_t msg);
+ void notifyKeystore(const uint8_t *auth_token, const size_t auth_token_length);
+ static void hal_notify_callback(const fingerprint_msg_t *msg);
static FingerprintDaemonProxy* sInstance;
fingerprint_module_t const* mModule;
diff --git a/fingerprintd/IFingerprintDaemon.h b/fingerprintd/IFingerprintDaemon.h
index fe3f64b..08cb008 100644
--- a/fingerprintd/IFingerprintDaemon.h
+++ b/fingerprintd/IFingerprintDaemon.h
@@ -65,7 +65,7 @@
// DECLARE_META_INTERFACE - C++ client interface not needed
static const android::String16 descriptor;
- static void hal_notify_callback(fingerprint_msg_t msg);
+ static void hal_notify_callback(const fingerprint_msg_t *msg);
};
// ----------------------------------------------------------------------------
diff --git a/gatekeeperd/SoftGateKeeper.h b/gatekeeperd/SoftGateKeeper.h
index e554411..75fe11d 100644
--- a/gatekeeperd/SoftGateKeeper.h
+++ b/gatekeeperd/SoftGateKeeper.h
@@ -20,6 +20,8 @@
extern "C" {
#include <openssl/rand.h>
+#include <openssl/sha.h>
+
#include <crypto_scrypt.h>
}
@@ -30,6 +32,10 @@
namespace gatekeeper {
+struct fast_hash_t {
+ uint64_t salt;
+ uint8_t digest[SHA256_DIGEST_LENGTH];
+};
class SoftGateKeeper : public GateKeeper {
public:
@@ -125,9 +131,48 @@
return true;
}
+ fast_hash_t ComputeFastHash(const SizedBuffer &password, uint64_t salt) {
+ fast_hash_t fast_hash;
+ size_t digest_size = password.length + sizeof(salt);
+ std::unique_ptr<uint8_t[]> digest(new uint8_t[digest_size]);
+ memcpy(digest.get(), &salt, sizeof(salt));
+ memcpy(digest.get() + sizeof(salt), password.buffer.get(), password.length);
+
+ SHA256(digest.get(), digest_size, (uint8_t *) &fast_hash.digest);
+
+ fast_hash.salt = salt;
+ return fast_hash;
+ }
+
+ bool VerifyFast(const fast_hash_t &fast_hash, const SizedBuffer &password) {
+ fast_hash_t computed = ComputeFastHash(password, fast_hash.salt);
+ return memcmp(computed.digest, fast_hash.digest, SHA256_DIGEST_LENGTH) == 0;
+ }
+
+ bool DoVerify(const password_handle_t *expected_handle, const SizedBuffer &password) {
+ FastHashMap::const_iterator it = fast_hash_map_.find(expected_handle->user_id);
+ if (it != fast_hash_map_.end() && VerifyFast(it->second, password)) {
+ return true;
+ } else {
+ if (GateKeeper::DoVerify(expected_handle, password)) {
+ uint64_t salt;
+ GetRandom(&salt, sizeof(salt));
+ fast_hash_map_[expected_handle->user_id] = ComputeFastHash(password, salt);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
private:
+
+ typedef std::unordered_map<uint32_t, failure_record_t> FailureRecordMap;
+ typedef std::unordered_map<uint64_t, fast_hash_t> FastHashMap;
+
UniquePtr<uint8_t[]> key_;
- std::unordered_map<uint32_t, failure_record_t> failure_map_;
+ FailureRecordMap failure_map_;
+ FastHashMap fast_hash_map_;
};
}
diff --git a/gatekeeperd/SoftGateKeeperDevice.h b/gatekeeperd/SoftGateKeeperDevice.h
index 51a8511..3463c29 100644
--- a/gatekeeperd/SoftGateKeeperDevice.h
+++ b/gatekeeperd/SoftGateKeeperDevice.h
@@ -68,7 +68,7 @@
const uint8_t *provided_password, uint32_t provided_password_length,
uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll);
private:
- UniquePtr<GateKeeper> impl_;
+ UniquePtr<SoftGateKeeper> impl_;
};
} // namespace gatekeeper
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp
index c0f2279..f4f2cbf 100644
--- a/gatekeeperd/gatekeeperd.cpp
+++ b/gatekeeperd/gatekeeperd.cpp
@@ -31,6 +31,7 @@
#include <binder/IServiceManager.h>
#include <binder/PermissionCache.h>
#include <utils/String16.h>
+#include <utils/Log.h>
#include <keystore/IKeystoreService.h>
#include <keystore/keystore.h> // For error code
@@ -57,6 +58,13 @@
if (ret < 0)
LOG_ALWAYS_FATAL_IF(ret < 0, "Unable to open GateKeeper HAL");
}
+
+ if (mark_cold_boot()) {
+ ALOGI("cold boot: clearing state");
+ if (device != NULL && device->delete_all_users != NULL) {
+ device->delete_all_users(device);
+ }
+ }
}
virtual ~GateKeeperProxy() {
@@ -75,6 +83,20 @@
close(fd);
}
+ bool mark_cold_boot() {
+ const char *filename = ".coldboot";
+ if (access(filename, F_OK) == -1) {
+ int fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
+ if (fd < 0) {
+ ALOGE("could not open file: %s : %s", filename, strerror(errno));
+ return false;
+ }
+ close(fd);
+ return true;
+ }
+ return false;
+ }
+
void maybe_store_sid(uint32_t uid, uint64_t sid) {
char filename[21];
sprintf(filename, "%u", uid);
@@ -119,8 +141,19 @@
int ret;
if (device) {
- ret = device->enroll(device, uid,
- current_password_handle, current_password_handle_length,
+ const gatekeeper::password_handle_t *handle =
+ reinterpret_cast<const gatekeeper::password_handle_t *>(current_password_handle);
+
+ if (handle != NULL && !handle->hardware_backed) {
+ // handle is being re-enrolled from a software version. HAL probably won't accept
+ // the handle as valid, so we nullify it and enroll from scratch
+ current_password_handle = NULL;
+ current_password_handle_length = 0;
+ current_password = NULL;
+ current_password_length = 0;
+ }
+
+ ret = device->enroll(device, 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);
@@ -174,10 +207,26 @@
int ret;
if (device) {
- ret = device->verify(device, uid, challenge,
- enrolled_password_handle, enrolled_password_handle_length,
- provided_password, provided_password_length, auth_token, auth_token_length,
- request_reenroll);
+ const gatekeeper::password_handle_t *handle =
+ reinterpret_cast<const gatekeeper::password_handle_t *>(enrolled_password_handle);
+ if (handle->hardware_backed) {
+ ret = device->verify(device, uid, challenge,
+ enrolled_password_handle, enrolled_password_handle_length,
+ provided_password, provided_password_length, auth_token, auth_token_length,
+ request_reenroll);
+ } else {
+ // upgrade scenario, a HAL has been added to this device where there was none before
+ SoftGateKeeperDevice soft_dev;
+ ret = soft_dev.verify(uid, challenge,
+ enrolled_password_handle, enrolled_password_handle_length,
+ provided_password, provided_password_length, auth_token, auth_token_length,
+ request_reenroll);
+
+ if (ret == 0) {
+ // success! re-enroll with HAL
+ *request_reenroll = true;
+ }
+ }
} else {
ret = soft_device->verify(uid, challenge,
enrolled_password_handle, enrolled_password_handle_length,
@@ -221,6 +270,10 @@
return;
}
clear_sid(uid);
+
+ if (device != NULL && device->delete_user != NULL) {
+ device->delete_user(device, uid);
+ }
}
virtual status_t dump(int fd, const Vector<String16> &) {
diff --git a/include/cutils/sched_policy.h b/include/cutils/sched_policy.h
index ba84ce3..6a8d570 100644
--- a/include/cutils/sched_policy.h
+++ b/include/cutils/sched_policy.h
@@ -34,6 +34,8 @@
SP_SYSTEM_DEFAULT = SP_FOREGROUND,
} SchedPolicy;
+extern int set_cpuset_policy(int tid, SchedPolicy policy);
+
/* Assign thread tid to the cgroup associated with the specified policy.
* If the thread is a thread group leader, that is it's gettid() == getpid(),
* then the other threads in the same thread group are _not_ affected.
diff --git a/init/init.cpp b/init/init.cpp
index 85d7909..93fe944 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -290,6 +290,16 @@
freecon(scon);
scon = NULL;
+ if (svc->writepid_files_) {
+ std::string pid_str = android::base::StringPrintf("%d", pid);
+ for (auto& file : *svc->writepid_files_) {
+ if (!android::base::WriteStringToFile(pid_str, file)) {
+ ERROR("couldn't write %s to %s: %s\n",
+ pid_str.c_str(), file.c_str(), strerror(errno));
+ }
+ }
+ }
+
if (svc->ioprio_class != IoSchedClass_NONE) {
if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) {
ERROR("Failed to set pid %d ioprio = %d,%d: %s\n",
diff --git a/init/init.h b/init/init.h
index 1cabb14..c166969 100644
--- a/init/init.h
+++ b/init/init.h
@@ -19,6 +19,9 @@
#include <sys/types.h>
+#include <string>
+#include <vector>
+
#include <cutils/list.h>
#include <cutils/iosched_policy.h>
@@ -116,6 +119,8 @@
struct action onrestart; /* Actions to execute on restart. */
+ std::vector<std::string>* writepid_files_;
+
/* keycodes for triggering this service via /dev/keychord */
int *keycodes;
int nkeycodes;
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index 385b37b..666a86e 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -206,6 +206,7 @@
break;
case 'w':
if (!strcmp(s, "rite")) return K_write;
+ if (!strcmp(s, "ritepid")) return K_writepid;
if (!strcmp(s, "ait")) return K_wait;
break;
}
@@ -926,6 +927,16 @@
svc->seclabel = args[1];
}
break;
+ case K_writepid:
+ if (nargs < 2) {
+ parse_error(state, "writepid option requires at least one filename\n");
+ break;
+ }
+ svc->writepid_files_ = new std::vector<std::string>;
+ for (int i = 1; i < nargs; ++i) {
+ svc->writepid_files_->push_back(args[i]);
+ }
+ break;
default:
parse_error(state, "invalid option '%s'\n", args[0]);
diff --git a/init/keywords.h b/init/keywords.h
index 37f01b8..e637d7d 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -43,11 +43,15 @@
enum {
K_UNKNOWN,
#endif
+ KEYWORD(bootchart_init, COMMAND, 0, do_bootchart_init)
+ KEYWORD(chmod, COMMAND, 2, do_chmod)
+ KEYWORD(chown, COMMAND, 2, do_chown)
KEYWORD(class, OPTION, 0, 0)
+ KEYWORD(class_reset, COMMAND, 1, do_class_reset)
KEYWORD(class_start, COMMAND, 1, do_class_start)
KEYWORD(class_stop, COMMAND, 1, do_class_stop)
- KEYWORD(class_reset, COMMAND, 1, do_class_reset)
KEYWORD(console, OPTION, 0, 0)
+ KEYWORD(copy, COMMAND, 2, do_copy)
KEYWORD(critical, OPTION, 0, 0)
KEYWORD(disabled, OPTION, 0, 0)
KEYWORD(domainname, COMMAND, 1, do_domainname)
@@ -57,16 +61,20 @@
KEYWORD(group, OPTION, 0, 0)
KEYWORD(hostname, COMMAND, 1, do_hostname)
KEYWORD(ifup, COMMAND, 1, do_ifup)
+ KEYWORD(import, SECTION, 1, 0)
KEYWORD(insmod, COMMAND, 1, do_insmod)
KEYWORD(installkey, COMMAND, 1, do_installkey)
- KEYWORD(import, SECTION, 1, 0)
+ KEYWORD(ioprio, OPTION, 0, 0)
KEYWORD(keycodes, OPTION, 0, 0)
+ KEYWORD(load_all_props, COMMAND, 0, do_load_all_props)
+ KEYWORD(load_persist_props, COMMAND, 0, do_load_persist_props)
+ KEYWORD(loglevel, COMMAND, 1, do_loglevel)
KEYWORD(mkdir, COMMAND, 1, do_mkdir)
KEYWORD(mount_all, COMMAND, 1, do_mount_all)
KEYWORD(mount, COMMAND, 3, do_mount)
- KEYWORD(on, SECTION, 0, 0)
KEYWORD(oneshot, OPTION, 0, 0)
KEYWORD(onrestart, OPTION, 0, 0)
+ KEYWORD(on, SECTION, 0, 0)
KEYWORD(powerctl, COMMAND, 1, do_powerctl)
KEYWORD(restart, COMMAND, 1, do_restart)
KEYWORD(restorecon, COMMAND, 1, do_restorecon)
@@ -82,22 +90,15 @@
KEYWORD(start, COMMAND, 1, do_start)
KEYWORD(stop, COMMAND, 1, do_stop)
KEYWORD(swapon_all, COMMAND, 1, do_swapon_all)
- KEYWORD(trigger, COMMAND, 1, do_trigger)
KEYWORD(symlink, COMMAND, 1, do_symlink)
KEYWORD(sysclktz, COMMAND, 1, do_sysclktz)
+ KEYWORD(trigger, COMMAND, 1, do_trigger)
KEYWORD(user, OPTION, 0, 0)
KEYWORD(verity_load_state, COMMAND, 0, do_verity_load_state)
KEYWORD(verity_update_state, COMMAND, 0, do_verity_update_state)
KEYWORD(wait, COMMAND, 1, do_wait)
KEYWORD(write, COMMAND, 2, do_write)
- KEYWORD(copy, COMMAND, 2, do_copy)
- KEYWORD(chown, COMMAND, 2, do_chown)
- KEYWORD(chmod, COMMAND, 2, do_chmod)
- KEYWORD(loglevel, COMMAND, 1, do_loglevel)
- KEYWORD(load_persist_props, COMMAND, 0, do_load_persist_props)
- KEYWORD(load_all_props, COMMAND, 0, do_load_all_props)
- KEYWORD(ioprio, OPTION, 0, 0)
- KEYWORD(bootchart_init, COMMAND, 0, do_bootchart_init)
+ KEYWORD(writepid, OPTION, 0, 0)
#ifdef __MAKE_KEYWORD_ENUM__
KEYWORD_COUNT,
};
diff --git a/init/readme.txt b/init/readme.txt
index c213041..9e3394e 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -60,36 +60,36 @@
runs the service.
critical
- This is a device-critical service. If it exits more than four times in
- four minutes, the device will reboot into recovery mode.
+ This is a device-critical service. If it exits more than four times in
+ four minutes, the device will reboot into recovery mode.
disabled
- This service will not automatically start with its class.
- It must be explicitly started by name.
+ This service will not automatically start with its class.
+ It must be explicitly started by name.
setenv <name> <value>
- Set the environment variable <name> to <value> in the launched process.
+ Set the environment variable <name> to <value> in the launched process.
socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]
- Create a unix domain socket named /dev/socket/<name> and pass
- its fd to the launched process. <type> must be "dgram", "stream" or "seqpacket".
- User and group default to 0.
- 'seclabel' is the SELinux security context for the socket.
- It defaults to the service security context, as specified by seclabel or
- computed based on the service executable file security context.
+ Create a unix domain socket named /dev/socket/<name> and pass
+ its fd to the launched process. <type> must be "dgram", "stream" or "seqpacket".
+ User and group default to 0.
+ 'seclabel' is the SELinux security context for the socket.
+ It defaults to the service security context, as specified by seclabel or
+ computed based on the service executable file security context.
user <username>
- Change to username before exec'ing this service.
- Currently defaults to root. (??? probably should default to nobody)
- Currently, if your process requires linux capabilities then you cannot use
- this command. You must instead request the capabilities in-process while
- still root, and then drop to your desired uid.
+ Change to username before exec'ing this service.
+ Currently defaults to root. (??? probably should default to nobody)
+ Currently, if your process requires linux capabilities then you cannot use
+ this command. You must instead request the capabilities in-process while
+ still root, and then drop to your desired uid.
group <groupname> [ <groupname> ]*
- Change to groupname before exec'ing this service. Additional
- groupnames beyond the (required) first one are used to set the
- supplemental groups of the process (via setgroups()).
- Currently defaults to root. (??? probably should default to nobody)
+ Change to groupname before exec'ing this service. Additional
+ groupnames beyond the (required) first one are used to set the
+ supplemental groups of the process (via setgroups()).
+ Currently defaults to root. (??? probably should default to nobody)
seclabel <seclabel>
Change to 'seclabel' before exec'ing this service.
@@ -99,22 +99,26 @@
If not specified and no transition is defined in policy, defaults to the init context.
oneshot
- Do not restart the service when it exits.
+ Do not restart the service when it exits.
class <name>
- Specify a class name for the service. All services in a
- named class may be started or stopped together. A service
- is in the class "default" if one is not specified via the
- class option.
+ Specify a class name for the service. All services in a
+ named class may be started or stopped together. A service
+ is in the class "default" if one is not specified via the
+ class option.
onrestart
- Execute a Command (see below) when service restarts.
+ Execute a Command (see below) when service restarts.
+
+writepid <file...>
+ Write the child's pid to the given files when it forks. Meant for
+ cgroup/cpuset usage.
Triggers
--------
- Triggers are strings which can be used to match certain kinds
- of events and used to cause an action to occur.
+Triggers are strings which can be used to match certain kinds
+of events and used to cause an action to occur.
boot
This is the first trigger that will occur when init starts
diff --git a/libbacktrace/BacktracePtrace.cpp b/libbacktrace/BacktracePtrace.cpp
index e10cce1..fd8b713 100644
--- a/libbacktrace/BacktracePtrace.cpp
+++ b/libbacktrace/BacktracePtrace.cpp
@@ -37,8 +37,6 @@
errno = 0;
*out_value = ptrace(PTRACE_PEEKTEXT, tid, reinterpret_cast<void*>(addr), nullptr);
if (*out_value == static_cast<word_t>(-1) && errno) {
- BACK_LOGW("invalid pointer %p reading from tid %d, ptrace() strerror(errno)=%s",
- reinterpret_cast<void*>(addr), tid, strerror(errno));
return false;
}
return true;
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 9dc15d1..0963076 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -125,6 +125,9 @@
LOCAL_C_INCLUDES := $(libcutils_c_includes)
LOCAL_STATIC_LIBRARIES := liblog
+ifneq ($(ENABLE_CPUSETS),)
+LOCAL_CFLAGS += -DUSE_CPUSETS
+endif
LOCAL_CFLAGS += -Werror -std=gnu90
include $(BUILD_STATIC_LIBRARY)
@@ -134,6 +137,9 @@
# liblog symbols present in libcutils.
LOCAL_WHOLE_STATIC_LIBRARIES := libcutils liblog
LOCAL_SHARED_LIBRARIES := liblog
+ifneq ($(ENABLE_CPUSETS),)
+LOCAL_CFLAGS += -DUSE_CPUSETS
+endif
LOCAL_CFLAGS += -Werror
LOCAL_C_INCLUDES := $(libcutils_c_includes)
include $(BUILD_SHARED_LIBRARY)
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index dfc8777..cf50ba7 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -1,16 +1,16 @@
/*
** Copyright 2007, 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
+** 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
+** 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
+** 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.
*/
@@ -59,27 +59,16 @@
static int bg_cgroup_fd = -1;
static int fg_cgroup_fd = -1;
+// File descriptors open to /dev/cpuset/../tasks, setup by initialize, or -1 on error
+static int bg_cpuset_fd = -1;
+static int fg_cpuset_fd = -1;
+
/* Add tid to the scheduling group defined by the policy */
-static int add_tid_to_cgroup(int tid, SchedPolicy policy)
+static int add_tid_to_cgroup(int tid, int fd)
{
- int fd;
-
- switch (policy) {
- case SP_BACKGROUND:
- fd = bg_cgroup_fd;
- break;
- case SP_FOREGROUND:
- case SP_AUDIO_APP:
- case SP_AUDIO_SYS:
- fd = fg_cgroup_fd;
- break;
- default:
- fd = -1;
- break;
- }
-
if (fd < 0) {
- SLOGE("add_tid_to_cgroup failed; policy=%d\n", policy);
+ SLOGE("add_tid_to_cgroup failed; fd=%d\n", fd);
+ errno = EINVAL;
return -1;
}
@@ -100,8 +89,9 @@
*/
if (errno == ESRCH)
return 0;
- SLOGW("add_tid_to_cgroup failed to write '%s' (%s); policy=%d\n",
- ptr, strerror(errno), policy);
+ SLOGW("add_tid_to_cgroup failed to write '%s' (%s); fd=%d\n",
+ ptr, strerror(errno), fd);
+ errno = EINVAL;
return -1;
}
@@ -127,6 +117,17 @@
} else {
__sys_supports_schedgroups = 0;
}
+
+#ifdef USE_CPUSETS
+ if (!access("/dev/cpuset/tasks", F_OK)) {
+
+ filename = "/dev/cpuset/foreground/tasks";
+ fg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
+ filename = "/dev/cpuset/background/tasks";
+ bg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
+ }
+#endif
+
}
/*
@@ -236,6 +237,42 @@
return 0;
}
+int set_cpuset_policy(int tid, SchedPolicy policy)
+{
+ // in the absence of cpusets, use the old sched policy
+#ifndef USE_CPUSETS
+ return set_sched_policy(tid, policy);
+#else
+ if (tid == 0) {
+ tid = gettid();
+ }
+ policy = _policy(policy);
+ pthread_once(&the_once, __initialize);
+
+ int fd;
+ switch (policy) {
+ case SP_BACKGROUND:
+ fd = bg_cpuset_fd;
+ break;
+ case SP_FOREGROUND:
+ case SP_AUDIO_APP:
+ case SP_AUDIO_SYS:
+ fd = fg_cpuset_fd;
+ break;
+ default:
+ fd = -1;
+ break;
+ }
+
+ if (add_tid_to_cgroup(tid, fd) != 0) {
+ if (errno != ESRCH && errno != ENOENT)
+ return -errno;
+ }
+
+ return 0;
+#endif
+}
+
int set_sched_policy(int tid, SchedPolicy policy)
{
if (tid == 0) {
@@ -286,7 +323,23 @@
#endif
if (__sys_supports_schedgroups) {
- if (add_tid_to_cgroup(tid, policy)) {
+ int fd;
+ switch (policy) {
+ case SP_BACKGROUND:
+ fd = bg_cgroup_fd;
+ break;
+ case SP_FOREGROUND:
+ case SP_AUDIO_APP:
+ case SP_AUDIO_SYS:
+ fd = fg_cgroup_fd;
+ break;
+ default:
+ fd = -1;
+ break;
+ }
+
+
+ if (add_tid_to_cgroup(tid, fd) != 0) {
if (errno != ESRCH && errno != ENOENT)
return -errno;
}
@@ -296,7 +349,7 @@
param.sched_priority = 0;
sched_setscheduler(tid,
(policy == SP_BACKGROUND) ?
- SCHED_BATCH : SCHED_NORMAL,
+ SCHED_BATCH : SCHED_NORMAL,
¶m);
}
@@ -337,4 +390,3 @@
else
return "error";
}
-
diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c
index 2e09192..7a8e33f 100644
--- a/liblog/log_is_loggable.c
+++ b/liblog/log_is_loggable.c
@@ -15,41 +15,158 @@
*/
#include <ctype.h>
+#include <pthread.h>
+#include <stdlib.h>
#include <string.h>
-#include <sys/system_properties.h>
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
#include <android/log.h>
-static int __android_log_level(const char *tag, int def)
+struct cache {
+ const prop_info *pinfo;
+ uint32_t serial;
+ char c;
+};
+
+static void refresh_cache(struct cache *cache, const char *key)
{
+ uint32_t serial;
char buf[PROP_VALUE_MAX];
- if (!tag || !*tag) {
- return def;
+ if (!cache->pinfo) {
+ cache->pinfo = __system_property_find(key);
+ if (!cache->pinfo) {
+ return;
+ }
}
- {
- static const char log_namespace[] = "persist.log.tag.";
- char key[sizeof(log_namespace) + strlen(tag)];
+ serial = __system_property_serial(cache->pinfo);
+ if (serial == cache->serial) {
+ return;
+ }
+ cache->serial = serial;
+ __system_property_read(cache->pinfo, 0, buf);
+ cache->c = buf[0];
+}
- strcpy(key, log_namespace);
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+static int __android_log_level(const char *tag, int def)
+{
+ /* sizeof() is used on this array below */
+ static const char log_namespace[] = "persist.log.tag.";
+ static const size_t base_offset = 8; /* skip "persist." */
+ /* calculate the size of our key temporary buffer */
+ const size_t taglen = (tag && *tag) ? strlen(tag) : 0;
+ /* sizeof(log_namespace) = strlen(log_namespace) + 1 */
+ char key[sizeof(log_namespace) + taglen];
+ char *kp;
+ size_t i;
+ char c = 0;
+ /*
+ * Single layer cache of four properties. Priorities are:
+ * log.tag.<tag>
+ * persist.log.tag.<tag>
+ * log.tag
+ * persist.log.tag
+ * Where the missing tag matches all tags and becomes the
+ * system global default. We do not support ro.log.tag* .
+ */
+ static char *last_tag;
+ static uint32_t global_serial;
+ uint32_t current_global_serial;
+ static struct cache tag_cache[2] = {
+ { NULL, -1, 0 },
+ { NULL, -1, 0 }
+ };
+ static struct cache global_cache[2] = {
+ { NULL, -1, 0 },
+ { NULL, -1, 0 }
+ };
+
+ strcpy(key, log_namespace);
+
+ pthread_mutex_lock(&lock);
+
+ current_global_serial = __system_property_area_serial();
+
+ if (taglen) {
+ uint32_t current_local_serial = current_global_serial;
+
+ if (!last_tag || strcmp(last_tag, tag)) {
+ /* invalidate log.tag.<tag> cache */
+ for(i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
+ tag_cache[i].pinfo = NULL;
+ tag_cache[i].serial = -1;
+ tag_cache[i].c = '\0';
+ }
+ free(last_tag);
+ last_tag = NULL;
+ current_global_serial = -1;
+ }
+ if (!last_tag) {
+ last_tag = strdup(tag);
+ }
strcpy(key + sizeof(log_namespace) - 1, tag);
- if (__system_property_get(key + 8, buf) <= 0) {
- buf[0] = '\0';
- }
- if (!buf[0] && __system_property_get(key, buf) <= 0) {
- buf[0] = '\0';
+ kp = key;
+ for(i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
+ if (current_local_serial != global_serial) {
+ refresh_cache(&tag_cache[i], kp);
+ }
+
+ if (tag_cache[i].c) {
+ c = tag_cache[i].c;
+ break;
+ }
+
+ kp = key + base_offset;
}
}
- switch (toupper(buf[0])) {
- case 'V': return ANDROID_LOG_VERBOSE;
- case 'D': return ANDROID_LOG_DEBUG;
- case 'I': return ANDROID_LOG_INFO;
- case 'W': return ANDROID_LOG_WARN;
- case 'E': return ANDROID_LOG_ERROR;
- case 'F': /* FALLTHRU */ /* Not officially supported */
- case 'A': return ANDROID_LOG_FATAL;
- case 'S': return -1; /* ANDROID_LOG_SUPPRESS */
+
+ switch (toupper(c)) { /* if invalid, resort to global */
+ case 'V':
+ case 'D':
+ case 'I':
+ case 'W':
+ case 'E':
+ case 'F': /* Not officially supported */
+ case 'A':
+ case 'S':
+ break;
+ default:
+ /* clear '.' after log.tag */
+ key[sizeof(log_namespace) - 2] = '\0';
+
+ kp = key;
+ for(i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) {
+ if (current_global_serial != global_serial) {
+ refresh_cache(&global_cache[i], kp);
+ }
+
+ if (global_cache[i].c) {
+ c = global_cache[i].c;
+ break;
+ }
+
+ kp = key + base_offset;
+ }
+ break;
+ }
+
+ global_serial = current_global_serial;
+
+ pthread_mutex_unlock(&lock);
+
+ switch (toupper(c)) {
+ case 'V': return ANDROID_LOG_VERBOSE;
+ case 'D': return ANDROID_LOG_DEBUG;
+ case 'I': return ANDROID_LOG_INFO;
+ case 'W': return ANDROID_LOG_WARN;
+ case 'E': return ANDROID_LOG_ERROR;
+ case 'F': /* FALLTHRU */ /* Not officially supported */
+ case 'A': return ANDROID_LOG_FATAL;
+ case 'S': return -1; /* ANDROID_LOG_SUPPRESS */
}
return def;
}
diff --git a/liblog/tests/Android.mk b/liblog/tests/Android.mk
index d75bbc9..a407c50 100644
--- a/liblog/tests/Android.mk
+++ b/liblog/tests/Android.mk
@@ -77,6 +77,6 @@
LOCAL_MODULE := $(test_module_prefix)unit-tests
LOCAL_MODULE_TAGS := $(test_tags)
LOCAL_CFLAGS += $(test_c_flags)
-LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SHARED_LIBRARIES := liblog libcutils
LOCAL_SRC_FILES := $(test_src_files)
include $(BUILD_NATIVE_TEST)
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 33f6481..abe0239 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -17,6 +17,8 @@
#include <fcntl.h>
#include <inttypes.h>
#include <signal.h>
+
+#include <cutils/properties.h>
#include <gtest/gtest.h>
#include <log/log.h>
#include <log/logger.h>
@@ -439,6 +441,7 @@
LOG_FAILURE_RETRY(__android_log_buf_write(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
tag, max_payload_buf));
+ sleep(2);
struct logger_list *logger_list;
@@ -603,10 +606,14 @@
if (id != android_name_to_log_id(name)) {
continue;
}
+ fprintf(stderr, "log buffer %s\r", name);
struct logger * logger;
EXPECT_TRUE(NULL != (logger = android_logger_open(logger_list, id)));
EXPECT_EQ(id, android_logger_get_id(logger));
- EXPECT_LT(0, android_logger_get_log_size(logger));
+ /* crash buffer is allowed to be empty, that is actually healthy! */
+ if (android_logger_get_log_size(logger) || strcmp("crash", name)) {
+ EXPECT_LT(0, android_logger_get_log_size(logger));
+ }
EXPECT_LT(0, android_logger_get_log_readable_size(logger));
EXPECT_LT(0, android_logger_get_log_version(logger));
}
@@ -682,3 +689,190 @@
android_log_format_free(p_format);
}
+
+TEST(liblog, is_loggable) {
+ static const char tag[] = "is_loggable";
+ static const char log_namespace[] = "persist.log.tag.";
+ static const size_t base_offset = 8; /* skip "persist." */
+ // sizeof("string") = strlen("string") + 1
+ char key[sizeof(log_namespace) + sizeof(tag) - 1];
+ char hold[4][PROP_VALUE_MAX];
+ static const struct {
+ int level;
+ char type;
+ } levels[] = {
+ { ANDROID_LOG_VERBOSE, 'v' },
+ { ANDROID_LOG_DEBUG , 'd' },
+ { ANDROID_LOG_INFO , 'i' },
+ { ANDROID_LOG_WARN , 'w' },
+ { ANDROID_LOG_ERROR , 'e' },
+ { ANDROID_LOG_FATAL , 'a' },
+ { -1 , 's' },
+ { -2 , 'g' }, // Illegal value, resort to default
+ };
+
+ // Set up initial test condition
+ memset(hold, 0, sizeof(hold));
+ snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
+ property_get(key, hold[0], "");
+ property_set(key, "");
+ property_get(key + base_offset, hold[1], "");
+ property_set(key + base_offset, "");
+ strcpy(key, log_namespace);
+ key[sizeof(log_namespace) - 2] = '\0';
+ property_get(key, hold[2], "");
+ property_set(key, "");
+ property_get(key, hold[3], "");
+ property_set(key + base_offset, "");
+
+ // All combinations of level and defaults
+ for(size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
+ if (levels[i].level == -2) {
+ continue;
+ }
+ for(size_t j = 0; j < (sizeof(levels) / sizeof(levels[0])); ++j) {
+ if (levels[j].level == -2) {
+ continue;
+ }
+ fprintf(stderr, "i=%zu j=%zu\r", i, j);
+ if ((levels[i].level < levels[j].level)
+ || (levels[j].level == -1)) {
+ EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
+ levels[j].level));
+ } else {
+ EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
+ levels[j].level));
+ }
+ }
+ }
+
+ // All combinations of level and tag and global properties
+ for(size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
+ if (levels[i].level == -2) {
+ continue;
+ }
+ for(size_t j = 0; j < (sizeof(levels) / sizeof(levels[0])); ++j) {
+ char buf[2];
+ buf[0] = levels[j].type;
+ buf[1] = '\0';
+
+ snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
+ fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
+ i, j, key, buf);
+ property_set(key, buf);
+ if ((levels[i].level < levels[j].level)
+ || (levels[j].level == -1)
+ || ((levels[i].level < ANDROID_LOG_DEBUG)
+ && (levels[j].level == -2))) {
+ EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
+ ANDROID_LOG_DEBUG));
+ } else {
+ EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
+ ANDROID_LOG_DEBUG));
+ }
+ property_set(key, "");
+
+ fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
+ i, j, key + base_offset, buf);
+ property_set(key + base_offset, buf);
+ if ((levels[i].level < levels[j].level)
+ || (levels[j].level == -1)
+ || ((levels[i].level < ANDROID_LOG_DEBUG)
+ && (levels[j].level == -2))) {
+ EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
+ ANDROID_LOG_DEBUG));
+ } else {
+ EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
+ ANDROID_LOG_DEBUG));
+ }
+ property_set(key + base_offset, "");
+
+ strcpy(key, log_namespace);
+ key[sizeof(log_namespace) - 2] = '\0';
+ fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
+ i, j, key, buf);
+ property_set(key, buf);
+ if ((levels[i].level < levels[j].level)
+ || (levels[j].level == -1)
+ || ((levels[i].level < ANDROID_LOG_DEBUG)
+ && (levels[j].level == -2))) {
+ EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
+ ANDROID_LOG_DEBUG));
+ } else {
+ EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
+ ANDROID_LOG_DEBUG));
+ }
+ property_set(key, "");
+
+ fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
+ i, j, key + base_offset, buf);
+ property_set(key + base_offset, buf);
+ if ((levels[i].level < levels[j].level)
+ || (levels[j].level == -1)
+ || ((levels[i].level < ANDROID_LOG_DEBUG)
+ && (levels[j].level == -2))) {
+ EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
+ ANDROID_LOG_DEBUG));
+ } else {
+ EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
+ ANDROID_LOG_DEBUG));
+ }
+ property_set(key + base_offset, "");
+ }
+ }
+
+ // All combinations of level and tag properties, but with global set to INFO
+ strcpy(key, log_namespace);
+ key[sizeof(log_namespace) - 2] = '\0';
+ property_set(key, "I");
+ snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
+ for(size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
+ if (levels[i].level == -2) {
+ continue;
+ }
+ for(size_t j = 0; j < (sizeof(levels) / sizeof(levels[0])); ++j) {
+ char buf[2];
+ buf[0] = levels[j].type;
+ buf[1] = '\0';
+
+ fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
+ i, j, key, buf);
+ property_set(key, buf);
+ if ((levels[i].level < levels[j].level)
+ || (levels[j].level == -1)
+ || ((levels[i].level < ANDROID_LOG_INFO) // Yes INFO
+ && (levels[j].level == -2))) {
+ EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
+ ANDROID_LOG_DEBUG));
+ } else {
+ EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
+ ANDROID_LOG_DEBUG));
+ }
+ property_set(key, "");
+
+ fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
+ i, j, key + base_offset, buf);
+ property_set(key + base_offset, buf);
+ if ((levels[i].level < levels[j].level)
+ || (levels[j].level == -1)
+ || ((levels[i].level < ANDROID_LOG_INFO) // Yes INFO
+ && (levels[j].level == -2))) {
+ EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
+ ANDROID_LOG_DEBUG));
+ } else {
+ EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
+ ANDROID_LOG_DEBUG));
+ }
+ property_set(key + base_offset, "");
+ }
+ }
+
+ // reset parms
+ snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
+ property_set(key, hold[0]);
+ property_set(key + base_offset, hold[1]);
+ strcpy(key, log_namespace);
+ key[sizeof(log_namespace) - 2] = '\0';
+ property_set(key, hold[2]);
+ property_set(key + base_offset, hold[3]);
+}
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index a80965f..ad0500d 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -252,14 +252,15 @@
int killProcessGroup(uid_t uid, int initialPid, int signal)
{
int processes;
- int sleep_us = 100;
+ const int sleep_us = 5 * 1000; // 5ms
int64_t startTime = android::uptimeMillis();
+ int retry = 40;
while ((processes = killProcessGroupOnce(uid, initialPid, signal)) > 0) {
SLOGV("killed %d processes for processgroup %d\n", processes, initialPid);
- if (sleep_us < 128000) {
+ if (retry > 0) {
usleep(sleep_us);
- sleep_us *= 2;
+ --retry;
} else {
SLOGE("failed to kill %d processes for processgroup %d\n",
processes, initialPid);
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index ef30017..2347028 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -455,18 +455,20 @@
SLOGE("Invalid optlen %d for RDNSS option\n", optlen);
return false;
}
- int numaddrs = (optlen - 1) / 2;
+ const int numaddrs = (optlen - 1) / 2;
// Find the lifetime.
struct nd_opt_rdnss *rndss_opt = (struct nd_opt_rdnss *) opthdr;
- uint32_t lifetime = ntohl(rndss_opt->nd_opt_rdnss_lifetime);
+ const uint32_t lifetime = ntohl(rndss_opt->nd_opt_rdnss_lifetime);
// Construct "SERVERS=<comma-separated string of DNS addresses>".
- // Reserve (INET6_ADDRSTRLEN + 1) chars for each address: all but the
- // the last address are followed by ','; the last is followed by '\0'.
static const char kServerTag[] = "SERVERS=";
- static const int kTagLength = sizeof(kServerTag) - 1;
- int bufsize = kTagLength + numaddrs * (INET6_ADDRSTRLEN + 1);
+ static const int kTagLength = strlen(kServerTag);
+ // Reserve sufficient space for an IPv6 link-local address: all but the
+ // last address are followed by ','; the last is followed by '\0'.
+ static const int kMaxSingleAddressLength =
+ INET6_ADDRSTRLEN + strlen("%") + IFNAMSIZ + strlen(",");
+ const int bufsize = kTagLength + numaddrs * (INET6_ADDRSTRLEN + 1);
char *buf = (char *) malloc(bufsize);
if (!buf) {
SLOGE("RDNSS option: out of memory\n");
@@ -482,6 +484,10 @@
}
inet_ntop(AF_INET6, addrs + i, buf + pos, bufsize - pos);
pos += strlen(buf + pos);
+ if (IN6_IS_ADDR_LINKLOCAL(addrs + i)) {
+ buf[pos++] = '%';
+ pos += strlcpy(buf + pos, ifname, bufsize - pos);
+ }
}
buf[pos] = '\0';
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index 40b8b9f..b8e3215 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -56,6 +56,9 @@
#define USB_FS_ID_SCANNER USB_FS_DIR "/%d/%d"
#define USB_FS_ID_FORMAT USB_FS_DIR "/%03d/%03d"
+// Some devices fail to send string descriptors if we attempt reading > 255 bytes
+#define MAX_STRING_DESCRIPTOR_LENGTH 255
+
// From drivers/usb/core/devio.c
// I don't know why this isn't in a kernel header
#define MAX_USBFS_BUFFER_SIZE 16384
@@ -449,8 +452,8 @@
char* usb_device_get_string(struct usb_device *device, int id)
{
char string[256];
- __u16 buffer[128];
- __u16 languages[128];
+ __u16 buffer[MAX_STRING_DESCRIPTOR_LENGTH / sizeof(__u16)];
+ __u16 languages[MAX_STRING_DESCRIPTOR_LENGTH / sizeof(__u16)];
int i, result;
int languageCount = 0;
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 4373e2a..0f5071b 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -140,8 +140,26 @@
if ((log_id >= LOG_ID_MAX) || (log_id < 0)) {
return -EINVAL;
}
+
LogBufferElement *elem = new LogBufferElement(log_id, realtime,
uid, pid, tid, msg, len);
+ int prio = ANDROID_LOG_INFO;
+ const char *tag = NULL;
+ if (log_id == LOG_ID_EVENTS) {
+ tag = android::tagToName(elem->getTag());
+ } else {
+ prio = *msg;
+ tag = msg + 1;
+ }
+ if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
+ // Log traffic received to total
+ pthread_mutex_lock(&mLogElementsLock);
+ stats.add(elem);
+ stats.subtract(elem);
+ pthread_mutex_unlock(&mLogElementsLock);
+ delete elem;
+ return -EACCES;
+ }
pthread_mutex_lock(&mLogElementsLock);
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 8238a52..3f5fdce 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -30,7 +30,7 @@
#include "LogReader.h"
const uint64_t LogBufferElement::FLUSH_ERROR(0);
-atomic_int_fast64_t LogBufferElement::sequence;
+atomic_int_fast64_t LogBufferElement::sequence(1);
LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime,
uid_t uid, pid_t pid, pid_t tid,
@@ -105,8 +105,12 @@
size_t LogBufferElement::populateDroppedMessage(char *&buffer,
LogBuffer *parent) {
static const char tag[] = "chatty";
- static const char format_uid[] = "uid=%u%s%s expire %u line%s";
+ if (!__android_log_is_loggable(ANDROID_LOG_INFO, tag, ANDROID_LOG_VERBOSE)) {
+ return 0;
+ }
+
+ static const char format_uid[] = "uid=%u%s%s expire %u line%s";
char *name = parent->uidToName(mUid);
char *commName = android::tidToName(mTid);
if (!commName && (mTid != mPid)) {
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index 7d14648..d578c04 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -45,8 +45,8 @@
}
char c;
while ((c = *s++)) {
- if (!isdigit(c) && (c == '>')) {
- return s;
+ if (!isdigit(c)) {
+ return (c == '>') ? s : NULL;
}
}
return NULL;
@@ -65,17 +65,15 @@
while ((c = *s++)) {
if ((c == '.') && first_period) {
first_period = false;
- continue;
- }
- if (!isdigit(c) && (c == ']')) {
- return s;
+ } else if (!isdigit(c)) {
+ return ((c == ']') && !first_period && (*s == ' ')) ? s : NULL;
}
}
return NULL;
}
// Like strtok_r with "\r\n" except that we look for log signatures (regex)
-// \(\(<[0-9]+>\)\([[] *[0-9]+[]]\)\{0,1\}\|[[] *[0-9]+[]]\)
+// \(\(<[0-9]+>\)\([[] *[0-9]+[.][0-9]+[]] \)\{0,1\}\|[[] *[0-9]+[.][0-9]+[]] \)
// and split if we see a second one without a newline.
#define SIGNATURE_MASK 0xF0
@@ -547,10 +545,21 @@
}
}
size_t l = etag - tag;
+ // skip leading space
while (isspace(*buf)) {
++buf;
}
- size_t n = 1 + l + 1 + strlen(buf) + 1;
+ // truncate trailing space
+ size_t b = strlen(buf);
+ while (b && isspace(buf[b-1])) {
+ --b;
+ }
+ // trick ... allow tag with empty content to be logged. log() drops empty
+ if (!b && l) {
+ buf = " ";
+ b = 1;
+ }
+ size_t n = 1 + l + 1 + b + 1;
// Allocate a buffer to hold the interpreted log message
int rc = n;
@@ -572,7 +581,8 @@
++np;
// Copy main message to the remainder
- strcpy(np, buf);
+ strncpy(np, buf, b);
+ np[b] = '\0';
// Log message
rc = logbuf->log(LOG_ID_KERNEL, now, uid, pid, tid, newstr,
diff --git a/logd/main.cpp b/logd/main.cpp
index a876c99..9b88983 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -33,6 +33,8 @@
#include <syslog.h>
#include <unistd.h>
+#include <memory>
+
#include <cutils/properties.h>
#include <cutils/sched_policy.h>
#include <cutils/sockets.h>
@@ -275,6 +277,45 @@
&& !property_get_bool("ro.config.low_ram", false));
}
+static void readDmesg(LogAudit *al, LogKlog *kl) {
+ if (!al && !kl) {
+ return;
+ }
+
+ int len = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
+ if (len <= 0) {
+ return;
+ }
+
+ len += 1024; // Margin for additional input race or trailing nul
+ std::unique_ptr<char []> buf(new char[len]);
+
+ int rc = klogctl(KLOG_READ_ALL, buf.get(), len);
+ if (rc <= 0) {
+ return;
+ }
+
+ if (rc < len) {
+ len = rc + 1;
+ }
+ buf[len - 1] = '\0';
+
+ if (kl) {
+ kl->synchronize(buf.get());
+ }
+
+ for (char *ptr = NULL, *tok = buf.get();
+ (rc >= 0) && ((tok = log_strtok_r(tok, &ptr)));
+ tok = NULL) {
+ if (al) {
+ rc = al->log(tok);
+ }
+ if (kl) {
+ rc = kl->log(tok);
+ }
+ }
+}
+
// Foreground waits for exit of the main persistent threads
// that are started here. The threads are created to manage
// UNIX domain client sockets for writing, reading and
@@ -410,41 +451,16 @@
kl = new LogKlog(logBuf, reader, fdDmesg, fdPmesg, al != NULL);
}
- if (al || kl) {
- int len = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
- if (len > 0) {
- len++;
- char buf[len];
+ readDmesg(al, kl);
- int rc = klogctl(KLOG_READ_ALL, buf, len);
+ // failure is an option ... messages are in dmesg (required by standard)
- buf[len - 1] = '\0';
+ if (kl && kl->startListener()) {
+ delete kl;
+ }
- if ((rc >= 0) && kl) {
- kl->synchronize(buf);
- }
-
- for (char *ptr = NULL, *tok = buf;
- (rc >= 0) && ((tok = log_strtok_r(tok, &ptr)));
- tok = NULL) {
- if (al) {
- rc = al->log(tok);
- }
- if (kl) {
- rc = kl->log(tok);
- }
- }
- }
-
- // failure is an option ... messages are in dmesg (required by standard)
-
- if (kl && kl->startListener()) {
- delete kl;
- }
-
- if (al && al->startListener()) {
- delete al;
- }
+ if (al && al->startListener()) {
+ delete al;
}
TEMP_FAILURE_RETRY(pause());
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 2fbac23..17e2153 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -125,6 +125,28 @@
write /dev/cpuctl/bg_non_interactive/cpu.rt_runtime_us 700000
write /dev/cpuctl/bg_non_interactive/cpu.rt_period_us 1000000
+ # sets up initial cpusets for ActivityManager
+ mkdir /dev/cpuset
+ mount cpuset none /dev/cpuset
+ mkdir /dev/cpuset/foreground
+ mkdir /dev/cpuset/background
+ # this ensures that the cpusets are present and usable, but the device's
+ # init.rc must actually set the correct cpus
+ write /dev/cpuset/foreground/cpus 0
+ write /dev/cpuset/background/cpus 0
+ write /dev/cpuset/foreground/mems 0
+ write /dev/cpuset/background/mems 0
+ chown system system /dev/cpuset
+ chown system system /dev/cpuset/foreground
+ chown system system /dev/cpuset/background
+ chown system system /dev/cpuset/tasks
+ chown system system /dev/cpuset/foreground/tasks
+ chown system system /dev/cpuset/background/tasks
+ chmod 0644 /dev/cpuset/foreground/tasks
+ chmod 0644 /dev/cpuset/background/tasks
+ chmod 0644 /dev/cpuset/tasks
+
+
# qtaguid will limit access to specific data based on group memberships.
# net_bw_acct grants impersonation of socket owners.
# net_bw_stats grants access to other apps' detailed tagged-socket stats.
@@ -248,7 +270,10 @@
# create basic filesystem structure
mkdir /data/misc 01771 system misc
mkdir /data/misc/adb 02750 system shell
- mkdir /data/misc/bluedroid 0770 bluetooth net_bt_stack
+ mkdir /data/misc/bluedroid 02770 bluetooth net_bt_stack
+ # Fix the access permissions and group ownership for 'bt_config.conf'
+ chmod 0660 /data/misc/bluedroid/bt_config.conf
+ chown bluetooth net_bt_stack /data/misc/bluedroid/bt_config.conf
mkdir /data/misc/bluetooth 0770 system system
mkdir /data/misc/keystore 0700 keystore keystore
mkdir /data/misc/gatekeeper 0700 system system
diff --git a/run-as/package.c b/run-as/package.c
index 9e1f5bb..aea89e5 100644
--- a/run-as/package.c
+++ b/run-as/package.c
@@ -16,6 +16,7 @@
*/
#include <errno.h>
#include <fcntl.h>
+#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
@@ -421,7 +422,7 @@
* If the package database is corrupted, return -1 and set errno to EINVAL
*/
int
-get_package_info(const char* pkgName, PackageInfo *info)
+get_package_info(const char* pkgName, uid_t userId, PackageInfo *info)
{
char* buffer;
size_t buffer_len;
@@ -506,7 +507,20 @@
if (q == p)
goto BAD_FORMAT;
- p = string_copy(info->dataDir, sizeof info->dataDir, p, q - p);
+ /* If userId == 0 (i.e. user is device owner) we can use dataDir value
+ * from packages.list, otherwise compose data directory as
+ * /data/user/$uid/$packageId
+ */
+ if (userId == 0) {
+ p = string_copy(info->dataDir, sizeof info->dataDir, p, q - p);
+ } else {
+ snprintf(info->dataDir,
+ sizeof info->dataDir,
+ "/data/user/%d/%s",
+ userId,
+ pkgName);
+ p = q;
+ }
/* skip spaces */
if (parse_spaces(&p, end) < 0)
diff --git a/run-as/package.h b/run-as/package.h
index 34603c0..eeb5913 100644
--- a/run-as/package.h
+++ b/run-as/package.h
@@ -33,9 +33,11 @@
char seinfo[PATH_MAX];
} PackageInfo;
-/* see documentation in package.c for these functiosn */
+/* see documentation in package.c for these functions */
-extern int get_package_info(const char* packageName, PackageInfo* info);
+extern int get_package_info(const char* packageName,
+ uid_t userId,
+ PackageInfo* info);
extern int check_data_path(const char* dataDir, uid_t uid);
diff --git a/run-as/run-as.c b/run-as/run-as.c
index 368b8f1..3f32e7d 100644
--- a/run-as/run-as.c
+++ b/run-as/run-as.c
@@ -102,13 +102,14 @@
static void
usage(void)
{
- panic("Usage:\n " PROGNAME " <package-name> <command> [<args>]\n");
+ panic("Usage:\n " PROGNAME " <package-name> [--user <uid>] <command> [<args>]\n");
}
int main(int argc, char **argv)
{
const char* pkgname;
- int myuid, uid, gid;
+ uid_t myuid, uid, gid, userAppId = 0;
+ int commandArgvOfs = 2, userId = 0;
PackageInfo info;
struct __user_cap_header_struct capheader;
struct __user_cap_data_struct capdata[2];
@@ -136,14 +137,31 @@
panic("Could not set capabilities: %s\n", strerror(errno));
}
- /* retrieve package information from system (does setegid) */
pkgname = argv[1];
- if (get_package_info(pkgname, &info) < 0) {
+
+ /* get user_id from command line if provided */
+ if ((argc >= 4) && !strcmp(argv[2], "--user")) {
+ userId = atoi(argv[3]);
+ if (userId < 0)
+ panic("Negative user id %d is provided\n", userId);
+ commandArgvOfs += 2;
+ }
+
+ /* retrieve package information from system (does setegid) */
+ if (get_package_info(pkgname, userId, &info) < 0) {
panic("Package '%s' is unknown\n", pkgname);
}
+ /* verify that user id is not too big. */
+ if ((UID_MAX - info.uid) / AID_USER < (uid_t)userId) {
+ panic("User id %d is too big\n", userId);
+ }
+
+ /* calculate user app ID. */
+ userAppId = (AID_USER * userId) + info.uid;
+
/* reject system packages */
- if (info.uid < AID_APP) {
+ if (userAppId < AID_APP) {
panic("Package '%s' is not an application\n", pkgname);
}
@@ -153,14 +171,14 @@
}
/* check that the data directory path is valid */
- if (check_data_path(info.dataDir, info.uid) < 0) {
+ if (check_data_path(info.dataDir, userAppId) < 0) {
panic("Package '%s' has corrupt installation\n", pkgname);
}
/* Ensure that we change all real/effective/saved IDs at the
* same time to avoid nasty surprises.
*/
- uid = gid = info.uid;
+ uid = gid = userAppId;
if(setresgid(gid,gid,gid) || setresuid(uid,uid,uid)) {
panic("Permission denied\n");
}
@@ -181,8 +199,9 @@
}
/* User specified command for exec. */
- if ((argc >= 3) && (execvp(argv[2], argv+2) < 0)) {
- panic("exec failed for %s: %s\n", argv[2], strerror(errno));
+ if ((argc >= commandArgvOfs + 1) &&
+ (execvp(argv[commandArgvOfs], argv+commandArgvOfs) < 0)) {
+ panic("exec failed for %s: %s\n", argv[commandArgvOfs], strerror(errno));
}
/* Default exec shell. */