Merge "fs_mgr: add verify_dev flag to fs_mgr_setup_verity()" am: abc26ed753 am: 7da0c3db16 am: 70bcce4deb
am: 82f542f5a1
Change-Id: I427f830f6021a0abde66e9db200a9ce6ba8ddcea
diff --git a/fingerprintd/Android.mk b/fingerprintd/Android.mk
index 48b9525..55803cf 100644
--- a/fingerprintd/Android.mk
+++ b/fingerprintd/Android.mk
@@ -26,8 +26,11 @@
LOCAL_MODULE := fingerprintd
LOCAL_SHARED_LIBRARIES := \
libbinder \
+ libhidlbase \
+ libhidltransport \
liblog \
libhardware \
libutils \
- libkeystore_binder
+ libkeystore_binder \
+ android.hardware.biometrics.fingerprint@2.1
include $(BUILD_EXECUTABLE)
diff --git a/fingerprintd/FingerprintDaemonProxy.cpp b/fingerprintd/FingerprintDaemonProxy.cpp
index 1c7da30..73748f2 100644
--- a/fingerprintd/FingerprintDaemonProxy.cpp
+++ b/fingerprintd/FingerprintDaemonProxy.cpp
@@ -16,10 +16,10 @@
#define LOG_TAG "fingerprintd"
+#include <android/hardware/biometrics/fingerprint/2.1/types.h>
+#include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprint.h>
+#include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprintClientCallback.h>
#include <binder/IServiceManager.h>
-#include <hardware/hardware.h>
-#include <hardware/fingerprint.h>
-#include <hardware/hw_auth_token.h>
#include <keystore/IKeystoreService.h>
#include <keystore/keystore.h> // for error codes
#include <utils/Log.h>
@@ -28,12 +28,45 @@
namespace android {
-FingerprintDaemonProxy* FingerprintDaemonProxy::sInstance = NULL;
+using hardware::hidl_string;
+using hardware::Return;
+using hardware::biometrics::fingerprint::V2_1::FingerprintMsg;
+using hardware::biometrics::fingerprint::V2_1::RequestStatus;
+using hardware::biometrics::fingerprint::V2_1::FingerprintError;
+using hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprintClientCallback;
+using Type = hardware::biometrics::fingerprint::V2_1::FingerprintMsgType;
+using IBiometricsFingerprint = hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprint;
-// Supported fingerprint HAL version
-static const uint16_t kVersion = HARDWARE_MODULE_API_VERSION(2, 0);
+FingerprintDaemonProxy* FingerprintDaemonProxy::sInstance = nullptr;
+static sp<IBiometricsFingerprint> gBFP = nullptr;
+static sp<IBiometricsFingerprintClientCallback> gClientCallback = nullptr;
-FingerprintDaemonProxy::FingerprintDaemonProxy() : mModule(NULL), mDevice(NULL), mCallback(NULL) {
+template <typename E>
+constexpr typename std::underlying_type<E>::type to_native(E e) {
+ return static_cast<typename std::underlying_type<E>::type>(e);
+}
+
+const ssize_t hw_auth_token_size = 69;
+
+namespace hardware {
+
+class BiometricsFingerprintClientCallback : public IBiometricsFingerprintClientCallback {
+ public:
+ BiometricsFingerprintClientCallback() {};
+ virtual ~BiometricsFingerprintClientCallback() = default;
+ Return<void> notify(const FingerprintMsg& msg) {
+ FingerprintDaemonProxy::hal_notify_callback(msg);
+ return Void();
+ }
+};
+
+IBiometricsFingerprintClientCallback* HIDL_FETCH_IBiometricsFingerprintClientCallback(const char* /* name */) {
+ return new BiometricsFingerprintClientCallback();
+}
+
+} // namespace hardware
+
+FingerprintDaemonProxy::FingerprintDaemonProxy() : mCallback(nullptr) {
}
@@ -41,76 +74,75 @@
closeHal();
}
-void FingerprintDaemonProxy::hal_notify_callback(const fingerprint_msg_t *msg) {
+void FingerprintDaemonProxy::hal_notify_callback(const hardware::biometrics::fingerprint::V2_1::FingerprintMsg &msg) {
FingerprintDaemonProxy* instance = FingerprintDaemonProxy::getInstance();
const sp<IFingerprintDaemonCallback> callback = instance->mCallback;
- if (callback == NULL) {
+ if (callback == nullptr) {
ALOGE("Invalid callback object");
return;
}
- const int64_t device = (int64_t) instance->mDevice;
- switch (msg->type) {
- case FINGERPRINT_ERROR:
- ALOGD("onError(%d)", msg->data.error);
- callback->onError(device, msg->data.error);
+ switch (msg.type) {
+ case Type::ERROR:
+ ALOGD("onError(%d)", msg.data.error);
+ callback->onError(0, to_native(msg.data.error));
break;
- case FINGERPRINT_ACQUIRED:
- ALOGD("onAcquired(%d)", msg->data.acquired.acquired_info);
- callback->onAcquired(device, msg->data.acquired.acquired_info);
+ case Type::ACQUIRED:
+ ALOGD("onAcquired(%d)", msg.data.acquired.acquiredInfo);
+ callback->onAcquired(0, to_native(msg.data.acquired.acquiredInfo));
break;
- case FINGERPRINT_AUTHENTICATED:
+ case Type::AUTHENTICATED:
ALOGD("onAuthenticated(fid=%d, gid=%d)",
- 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));
+ 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);
+ callback->onAuthenticated(0,
+ msg.data.authenticated.finger.fid,
+ msg.data.authenticated.finger.gid);
break;
- case FINGERPRINT_TEMPLATE_ENROLLING:
+ case Type::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);
- 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.samplesRemaining);
+ callback->onEnrollResult(0,
+ msg.data.enroll.finger.fid,
+ msg.data.enroll.finger.gid,
+ msg.data.enroll.samplesRemaining);
break;
- case FINGERPRINT_TEMPLATE_REMOVED:
+ case Type::TEMPLATE_REMOVED:
ALOGD("onRemove(fid=%d, gid=%d)",
- 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);
+ callback->onRemoved(0,
+ msg.data.removed.finger.fid,
+ msg.data.removed.finger.gid);
break;
- case FINGERPRINT_TEMPLATE_ENUMERATING:
+ case Type::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);
+ msg.data.enumerated.finger.fid,
+ msg.data.enumerated.finger.gid,
+ msg.data.enumerated.remainingTemplates);
+ callback->onEnumerate(0,
+ msg.data.enumerated.finger.fid,
+ msg.data.enumerated.finger.gid,
+ msg.data.enumerated.remainingTemplates);
break;
default:
- ALOGE("invalid msg type: %d", msg->type);
+ ALOGE("invalid msg type: %d", msg.type);
return;
}
}
void FingerprintDaemonProxy::notifyKeystore(const uint8_t *auth_token, const size_t auth_token_length) {
- if (auth_token != NULL && auth_token_length > 0) {
+ if (auth_token != nullptr && auth_token_length > 0) {
// TODO: cache service?
sp < IServiceManager > sm = defaultServiceManager();
sp < IBinder > binder = sm->getService(String16("android.security.keystore"));
sp < IKeystoreService > service = interface_cast < IKeystoreService > (binder);
- if (service != NULL) {
+ if (service != nullptr) {
status_t ret = service->addAuthToken(auth_token, auth_token_length);
if (ret != ResponseCode::NO_ERROR) {
ALOGE("Falure sending auth token to KeyStore: %d", ret);
@@ -122,7 +154,7 @@
}
void FingerprintDaemonProxy::init(const sp<IFingerprintDaemonCallback>& callback) {
- if (mCallback != NULL && IInterface::asBinder(callback) != IInterface::asBinder(mCallback)) {
+ if (mCallback != nullptr && IInterface::asBinder(callback) != IInterface::asBinder(mCallback)) {
IInterface::asBinder(mCallback)->unlinkToDeath(this);
}
IInterface::asBinder(callback)->linkToDeath(this);
@@ -132,49 +164,99 @@
int32_t FingerprintDaemonProxy::enroll(const uint8_t* token, ssize_t tokenSize, int32_t groupId,
int32_t timeout) {
ALOG(LOG_VERBOSE, LOG_TAG, "enroll(gid=%d, timeout=%d)\n", groupId, timeout);
- if (tokenSize != sizeof(hw_auth_token_t) ) {
- ALOG(LOG_VERBOSE, LOG_TAG, "enroll() : invalid token size %zu\n", tokenSize);
+ if (tokenSize != hw_auth_token_size) {
+ ALOG(LOG_VERBOSE, LOG_TAG, "enroll() : invalid token size %zd, expected %zd\n", tokenSize, hw_auth_token_size);
return -1;
}
- const hw_auth_token_t* authToken = reinterpret_cast<const hw_auth_token_t*>(token);
- return mDevice->enroll(mDevice, authToken, groupId, timeout);
+
+ hardware::hidl_array<uint8_t, hw_auth_token_size> hat(token);
+ Return<RequestStatus> ret = gBFP->enroll(hat, groupId, timeout);
+ if (!ret.isOk()) {
+ ALOGE("Unknown transport error");
+ return -1;
+ }
+
+ RequestStatus status = ret;
+ return to_native(status);
}
uint64_t FingerprintDaemonProxy::preEnroll() {
- return mDevice->pre_enroll(mDevice);
+ return gBFP->preEnroll();
}
int32_t FingerprintDaemonProxy::postEnroll() {
- return mDevice->post_enroll(mDevice);
+ Return<RequestStatus> ret = gBFP->postEnroll();
+ if (!ret.isOk()) {
+ ALOGE("Unknown transport error");
+ return -1;
+ }
+
+ RequestStatus status = ret;
+ return to_native(status);
}
int32_t FingerprintDaemonProxy::stopEnrollment() {
ALOG(LOG_VERBOSE, LOG_TAG, "stopEnrollment()\n");
- return mDevice->cancel(mDevice);
+ Return<RequestStatus> ret = gBFP->cancel();
+ if (!ret.isOk()) {
+ ALOGE("Unknown transport error");
+ return -1;
+ }
+
+ RequestStatus status = ret;
+ return to_native(status);
}
int32_t FingerprintDaemonProxy::authenticate(uint64_t sessionId, uint32_t groupId) {
ALOG(LOG_VERBOSE, LOG_TAG, "authenticate(sid=%" PRId64 ", gid=%d)\n", sessionId, groupId);
- return mDevice->authenticate(mDevice, sessionId, groupId);
+ Return<RequestStatus> ret = gBFP->authenticate(sessionId, groupId);
+ if (!ret.isOk()) {
+ ALOGE("Unknown transport error");
+ return -1;
+ }
+
+ RequestStatus status = ret;
+ return to_native(status);
}
int32_t FingerprintDaemonProxy::stopAuthentication() {
ALOG(LOG_VERBOSE, LOG_TAG, "stopAuthentication()\n");
- return mDevice->cancel(mDevice);
+ Return<RequestStatus> ret = gBFP->cancel();
+ if (!ret.isOk()) {
+ ALOGE("Unknown transport error");
+ return -1;
+ }
+
+ RequestStatus status = ret;
+ return to_native(status);
}
int32_t FingerprintDaemonProxy::remove(int32_t fingerId, int32_t groupId) {
ALOG(LOG_VERBOSE, LOG_TAG, "remove(fid=%d, gid=%d)\n", fingerId, groupId);
- return mDevice->remove(mDevice, groupId, fingerId);
+ Return<RequestStatus> ret = gBFP->remove(groupId, fingerId);
+ if (!ret.isOk()) {
+ ALOGE("Unknown transport error");
+ return -1;
+ }
+
+ RequestStatus status = ret;
+ return to_native(status);
}
int32_t FingerprintDaemonProxy::enumerate() {
ALOG(LOG_VERBOSE, LOG_TAG, "enumerate()\n");
- return mDevice->enumerate(mDevice);
+ Return<RequestStatus> ret = gBFP->enumerate();
+ if (!ret.isOk()) {
+ ALOGE("Unknown transport error");
+ return -1;
+ }
+
+ RequestStatus status = ret;
+ return to_native(status);
}
uint64_t FingerprintDaemonProxy::getAuthenticatorId() {
- return mDevice->get_authenticator_id(mDevice);
+ return gBFP->getAuthenticatorId();
}
int32_t FingerprintDaemonProxy::setActiveGroup(int32_t groupId, const uint8_t* path,
@@ -183,74 +265,35 @@
ALOGE("Bad path length: %zd", pathlen);
return -1;
}
- // Convert to null-terminated string
- char path_name[PATH_MAX];
- memcpy(path_name, path, pathlen);
- 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);
+ hidl_string pathname;
+ pathname.setToExternal(reinterpret_cast<const char*>(path), pathlen);
+ ALOG(LOG_VERBOSE, LOG_TAG, "setActiveGroup(%d, %s, %zu)", groupId, pathname.c_str(), pathlen);
+ Return<RequestStatus> ret = gBFP->setActiveGroup(groupId, pathname);
+ if (!ret.isOk()) {
+ ALOGE("Unknown transport error");
+ return -1;
+ }
+
+ RequestStatus status = ret;
+ return to_native(status);
}
int64_t FingerprintDaemonProxy::openHal() {
- ALOG(LOG_VERBOSE, LOG_TAG, "nativeOpenHal()\n");
- int err;
- const hw_module_t *hw_module = NULL;
- if (0 != (err = hw_get_module(FINGERPRINT_HARDWARE_MODULE_ID, &hw_module))) {
- ALOGE("Can't open fingerprint HW Module, error: %d", err);
- return 0;
+ if (gBFP == nullptr) {
+ // TODO(b/31632518)
+ gBFP = IBiometricsFingerprint::getService("fingerprint");
+ if(gBFP == nullptr) {
+ ALOGE("Can't get service fingerprint");
+ return 0;
+ }
}
- if (NULL == hw_module) {
- ALOGE("No valid fingerprint module");
- return 0;
- }
-
- mModule = reinterpret_cast<const fingerprint_module_t*>(hw_module);
-
- if (mModule->common.methods->open == NULL) {
- ALOGE("No valid open method");
- return 0;
- }
-
- hw_device_t *device = NULL;
-
- if (0 != (err = mModule->common.methods->open(hw_module, NULL, &device))) {
- ALOGE("Can't open fingerprint methods, error: %d", err);
- return 0;
- }
-
- if (kVersion != device->version) {
- ALOGE("Wrong fp version. Expected %d, got %d", kVersion, device->version);
- // return 0; // FIXME
- }
-
- mDevice = reinterpret_cast<fingerprint_device_t*>(device);
- err = mDevice->set_notify(mDevice, hal_notify_callback);
- if (err < 0) {
- ALOGE("Failed in call to set_notify(), err=%d", err);
- return 0;
- }
-
- // Sanity check - remove
- if (mDevice->notify != hal_notify_callback) {
- ALOGE("NOTIFY not set properly: %p != %p", mDevice->notify, hal_notify_callback);
- }
-
- ALOG(LOG_VERBOSE, LOG_TAG, "fingerprint HAL successfully initialized");
- return reinterpret_cast<int64_t>(mDevice); // This is just a handle
+ gClientCallback = hardware::HIDL_FETCH_IBiometricsFingerprintClientCallback(nullptr);
+ gBFP->setNotify(gClientCallback);
+ return reinterpret_cast<int64_t>(gBFP.get());
}
int32_t FingerprintDaemonProxy::closeHal() {
- ALOG(LOG_VERBOSE, LOG_TAG, "nativeCloseHal()\n");
- if (mDevice == NULL) {
- ALOGE("No valid device");
- return -ENOSYS;
- }
- int err;
- if (0 != (err = mDevice->common.close(reinterpret_cast<hw_device_t*>(mDevice)))) {
- ALOGE("Can't close fingerprint module, error: %d", err);
- return err;
- }
- mDevice = NULL;
+ // Obsolete, return 0 for compatibility reasons.
return 0;
}
@@ -261,8 +304,8 @@
ALOGE("Can't close fingerprint device, error: %d", err);
}
if (IInterface::asBinder(mCallback) == who) {
- mCallback = NULL;
+ mCallback = nullptr;
}
}
-}
+} // namespace android
diff --git a/fingerprintd/FingerprintDaemonProxy.h b/fingerprintd/FingerprintDaemonProxy.h
index 145b4c9..715344c 100644
--- a/fingerprintd/FingerprintDaemonProxy.h
+++ b/fingerprintd/FingerprintDaemonProxy.h
@@ -22,6 +22,8 @@
namespace android {
+using hardware::biometrics::fingerprint::V2_1::RequestStatus;
+
class FingerprintDaemonProxy : public BnFingerprintDaemon {
public:
static FingerprintDaemonProxy* getInstance() {
@@ -45,17 +47,16 @@
virtual int32_t setActiveGroup(int32_t groupId, const uint8_t* path, ssize_t pathLen);
virtual int64_t openHal();
virtual int32_t closeHal();
+ static void hal_notify_callback(const hardware::biometrics::fingerprint::V2_1::FingerprintMsg &msg);
private:
FingerprintDaemonProxy();
virtual ~FingerprintDaemonProxy();
void binderDied(const wp<IBinder>& who);
void notifyKeystore(const uint8_t *auth_token, const size_t auth_token_length);
- static void hal_notify_callback(const fingerprint_msg_t *msg);
+ int32_t HandleTransportError(const RequestStatus error);
static FingerprintDaemonProxy* sInstance;
- fingerprint_module_t const* mModule;
- fingerprint_device_t* mDevice;
sp<IFingerprintDaemonCallback> mCallback;
};
diff --git a/fingerprintd/IFingerprintDaemon.h b/fingerprintd/IFingerprintDaemon.h
index 23c36ff..c5cdbfe 100644
--- a/fingerprintd/IFingerprintDaemon.h
+++ b/fingerprintd/IFingerprintDaemon.h
@@ -17,6 +17,8 @@
#ifndef IFINGERPRINT_DAEMON_H_
#define IFINGERPRINT_DAEMON_H_
+#include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprint.h>
+#include <android/hardware/biometrics/fingerprint/2.1/types.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>
@@ -69,7 +71,7 @@
// DECLARE_META_INTERFACE - C++ client interface not needed
static const android::String16 descriptor;
- static void hal_notify_callback(const fingerprint_msg_t *msg);
+ static void hal_notify_callback(const hardware::biometrics::fingerprint::V2_1::FingerprintMsg &msg);
};
// ----------------------------------------------------------------------------
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 863c12c..99778a4 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -405,7 +405,7 @@
return ret;
}
-static int fs_match(char *in1, char *in2)
+static int fs_match(const char *in1, const char *in2)
{
char *n1;
char *n2;
@@ -824,7 +824,7 @@
* If multiple fstab entries are to be mounted on "n_name", it will try to mount each one
* in turn, and stop on 1st success, or no more match.
*/
-int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
+int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
char *tmp_mount_point)
{
int i = 0;
diff --git a/fs_mgr/fs_mgr_main.c b/fs_mgr/fs_mgr_main.c
index 33a7496..4bfe202 100644
--- a/fs_mgr/fs_mgr_main.c
+++ b/fs_mgr/fs_mgr_main.c
@@ -14,12 +14,17 @@
* limitations under the License.
*/
+#define _GNU_SOURCE
+
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
-#include <libgen.h>
#include "fs_mgr_priv.h"
+#ifdef _LIBGEN_H
+#warning "libgen.h must not be included"
+#endif
+
char *me = "";
static void usage(void)
@@ -32,10 +37,10 @@
* and exit the program, do not return to the caller.
* Return the number of argv[] entries consumed.
*/
-static void parse_options(int argc, char *argv[], int *a_flag, int *u_flag, int *n_flag,
- char **n_name, char **n_blk_dev)
+static void parse_options(int argc, char * const argv[], int *a_flag, int *u_flag, int *n_flag,
+ const char **n_name, const char **n_blk_dev)
{
- me = basename(strdup(argv[0]));
+ me = basename(argv[0]);
if (argc <= 1) {
usage();
@@ -75,14 +80,14 @@
return;
}
-int main(int argc, char *argv[])
+int main(int argc, char * const argv[])
{
int a_flag=0;
int u_flag=0;
int n_flag=0;
- char *n_name=NULL;
- char *n_blk_dev=NULL;
- char *fstab_file=NULL;
+ const char *n_name=NULL;
+ const char *n_blk_dev=NULL;
+ const char *fstab_file=NULL;
struct fstab *fstab=NULL;
klog_set_level(6);
@@ -97,7 +102,7 @@
if (a_flag) {
return fs_mgr_mount_all(fstab, MOUNT_MODE_DEFAULT);
} else if (n_flag) {
- return fs_mgr_do_mount(fstab, n_name, n_blk_dev, 0);
+ return fs_mgr_do_mount(fstab, n_name, (char *)n_blk_dev, 0);
} else if (u_flag) {
return fs_mgr_unmount_all(fstab);
} else {
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index e7a0a1d..ef7fdd3 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -99,7 +99,7 @@
#define FS_MGR_DOMNT_FAILED (-1)
#define FS_MGR_DOMNT_BUSY (-2)
-int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
+int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
char *tmp_mount_point);
int fs_mgr_do_tmpfs_mount(char *n_name);
int fs_mgr_unmount_all(struct fstab *fstab);
diff --git a/gatekeeperd/Android.mk b/gatekeeperd/Android.mk
index 3f78955..0dfd9d8 100644
--- a/gatekeeperd/Android.mk
+++ b/gatekeeperd/Android.mk
@@ -33,7 +33,12 @@
libbase \
libutils \
libcrypto \
- libkeystore_binder
+ libkeystore_binder \
+ libhidlbase \
+ libhidltransport \
+ libhwbinder \
+ android.hardware.gatekeeper@1.0 \
+
LOCAL_STATIC_LIBRARIES := libscrypt_static
LOCAL_C_INCLUDES := external/scrypt/lib/crypto
LOCAL_INIT_RC := gatekeeperd.rc
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp
index 49a8841..bea7ee7 100644
--- a/gatekeeperd/gatekeeperd.cpp
+++ b/gatekeeperd/gatekeeperd.cpp
@@ -39,6 +39,15 @@
#include "SoftGateKeeperDevice.h"
#include "IUserManager.h"
+#include <hidl/HidlSupport.h>
+#include <android/hardware/gatekeeper/1.0/IGatekeeper.h>
+
+using android::sp;
+using android::hardware::gatekeeper::V1_0::IGatekeeper;
+using android::hardware::gatekeeper::V1_0::GatekeeperStatusCode;
+using android::hardware::gatekeeper::V1_0::GatekeeperResponse;
+using android::hardware::Return;
+
namespace android {
static const String16 KEYGUARD_PERMISSION("android.permission.ACCESS_KEYGUARD_SECURE_STORAGE");
@@ -47,28 +56,22 @@
class GateKeeperProxy : public BnGateKeeperService {
public:
GateKeeperProxy() {
- int ret = hw_get_module_by_class(GATEKEEPER_HARDWARE_MODULE_ID, NULL, &module);
- device = NULL;
+ hw_device = IGatekeeper::getService("gatekeeper");
- if (ret < 0) {
+ if (hw_device == nullptr) {
ALOGW("falling back to software GateKeeper");
soft_device.reset(new SoftGateKeeperDevice());
- } else {
- ret = gatekeeper_open(module, &device);
- 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);
+ if (hw_device != nullptr) {
+ hw_device->deleteAllUsers([](const GatekeeperResponse &){});
}
}
}
virtual ~GateKeeperProxy() {
- if (device) gatekeeper_close(device);
}
void store_sid(uint32_t uid, uint64_t sid) {
@@ -141,7 +144,7 @@
if (desired_password_length == 0) return -EINVAL;
int ret;
- if (device) {
+ if (hw_device != nullptr) {
const gatekeeper::password_handle_t *handle =
reinterpret_cast<const gatekeeper::password_handle_t *>(current_password_handle);
@@ -154,10 +157,37 @@
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);
+ android::hardware::hidl_vec<uint8_t> curPwdHandle;
+ curPwdHandle.setToExternal(const_cast<uint8_t*>(current_password_handle),
+ current_password_handle_length);
+ android::hardware::hidl_vec<uint8_t> curPwd;
+ curPwd.setToExternal(const_cast<uint8_t*>(current_password),
+ current_password_length);
+ android::hardware::hidl_vec<uint8_t> newPwd;
+ newPwd.setToExternal(const_cast<uint8_t*>(desired_password),
+ desired_password_length);
+
+ Return<void> hwRes = hw_device->enroll(uid, curPwdHandle, curPwd, newPwd,
+ [&ret, enrolled_password_handle, enrolled_password_handle_length]
+ (const GatekeeperResponse &rsp) {
+ ret = static_cast<int>(rsp.code); // propagate errors
+ if (rsp.code >= GatekeeperStatusCode::STATUS_OK) {
+ if (enrolled_password_handle != nullptr &&
+ enrolled_password_handle_length != nullptr) {
+ *enrolled_password_handle = new uint8_t[rsp.data.size()];
+ *enrolled_password_handle_length = rsp.data.size();
+ memcpy(*enrolled_password_handle, rsp.data.data(),
+ *enrolled_password_handle_length);
+ }
+ ret = 0; // all success states are reported as 0
+ } else if (rsp.code == GatekeeperStatusCode::ERROR_RETRY_TIMEOUT && rsp.timeout > 0) {
+ ret = rsp.timeout;
+ }
+ });
+ if (!hwRes.isOk()) {
+ ALOGE("enroll transaction failed\n");
+ ret = -1;
+ }
} else {
ret = soft_device->enroll(uid,
current_password_handle, current_password_handle_length,
@@ -214,16 +244,40 @@
return -EINVAL;
int ret;
- if (device) {
+ if (hw_device != nullptr) {
const gatekeeper::password_handle_t *handle =
reinterpret_cast<const gatekeeper::password_handle_t *>(enrolled_password_handle);
// handle version 0 does not have hardware backed flag, and thus cannot be upgraded to
// a HAL if there was none before
if (handle->version == 0 || 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);
+ android::hardware::hidl_vec<uint8_t> curPwdHandle;
+ curPwdHandle.setToExternal(const_cast<uint8_t*>(enrolled_password_handle),
+ enrolled_password_handle_length);
+ android::hardware::hidl_vec<uint8_t> enteredPwd;
+ enteredPwd.setToExternal(const_cast<uint8_t*>(provided_password),
+ provided_password_length);
+ Return<void> hwRes = hw_device->verify(uid, challenge, curPwdHandle, enteredPwd,
+ [&ret, request_reenroll, auth_token, auth_token_length]
+ (const GatekeeperResponse &rsp) {
+ ret = static_cast<int>(rsp.code); // propagate errors
+ if (auth_token != nullptr && auth_token_length != nullptr &&
+ rsp.code >= GatekeeperStatusCode::STATUS_OK) {
+ *auth_token = new uint8_t[rsp.data.size()];
+ *auth_token_length = rsp.data.size();
+ memcpy(*auth_token, rsp.data.data(), *auth_token_length);
+ if (request_reenroll != nullptr) {
+ *request_reenroll = (rsp.code == GatekeeperStatusCode::STATUS_REENROLL);
+ }
+ ret = 0; // all success states are reported as 0
+ } else if (rsp.code == GatekeeperStatusCode::ERROR_RETRY_TIMEOUT &&
+ rsp.timeout > 0) {
+ ret = rsp.timeout;
+ }
+ });
+ if (!hwRes.isOk()) {
+ ALOGE("verify transaction failed\n");
+ ret = -1;
+ }
} else {
// upgrade scenario, a HAL has been added to this device where there was none before
SoftGateKeeperDevice soft_dev;
@@ -295,8 +349,8 @@
}
clear_sid(uid);
- if (device != NULL && device->delete_user != NULL) {
- device->delete_user(device, uid);
+ if (hw_device != nullptr) {
+ hw_device->deleteUser(uid, [] (const GatekeeperResponse &){});
}
}
@@ -308,7 +362,7 @@
return PERMISSION_DENIED;
}
- if (device == NULL) {
+ if (hw_device == NULL) {
const char *result = "Device not available";
write(fd, result, strlen(result) + 1);
} else {
@@ -320,9 +374,8 @@
}
private:
- gatekeeper_device_t *device;
+ sp<IGatekeeper> hw_device;
UniquePtr<SoftGateKeeperDevice> soft_device;
- const hw_module_t *module;
};
}// namespace android
diff --git a/healthd/Android.mk b/healthd/Android.mk
index b292725..8b59964 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -3,16 +3,6 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := healthd_board_default.cpp
-LOCAL_MODULE := libhealthd.default
-LOCAL_CFLAGS := -Werror
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_STATIC_LIBRARIES := libbinder
-LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := libbinder
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
LOCAL_SRC_FILES := BatteryMonitor.cpp
LOCAL_MODULE := libbatterymonitor
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
@@ -21,26 +11,47 @@
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
-ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
-LOCAL_CFLAGS += -DCHARGER_ENABLE_SUSPEND
-LOCAL_SHARED_LIBRARIES += libsuspend
-endif
LOCAL_SRC_FILES := \
healthd_mode_android.cpp \
- healthd_mode_charger.cpp \
- AnimationParser.cpp \
- BatteryPropertiesRegistrar.cpp \
+ BatteryPropertiesRegistrar.cpp
-LOCAL_MODULE := libhealthd_internal
-LOCAL_C_INCLUDES := bootable/recovery
+LOCAL_MODULE := libhealthd_android
LOCAL_EXPORT_C_INCLUDE_DIRS := \
$(LOCAL_PATH) \
- $(LOCAL_PATH)/include \
+ $(LOCAL_PATH)/include
LOCAL_STATIC_LIBRARIES := \
libbatterymonitor \
libbatteryservice \
- libbinder \
+ libutils \
+ libbase \
+ libcutils \
+ liblog \
+ libc \
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_CFLAGS := -Werror
+ifeq ($(strip $(BOARD_CHARGER_DISABLE_INIT_BLANK)),true)
+LOCAL_CFLAGS += -DCHARGER_DISABLE_INIT_BLANK
+endif
+ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
+LOCAL_CFLAGS += -DCHARGER_ENABLE_SUSPEND
+endif
+
+LOCAL_SRC_FILES := \
+ healthd_mode_charger.cpp \
+ AnimationParser.cpp
+
+LOCAL_MODULE := libhealthd_charger
+LOCAL_C_INCLUDES := bootable/recovery $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+ $(LOCAL_PATH) \
+ $(LOCAL_PATH)/include
+
+LOCAL_STATIC_LIBRARIES := \
libminui \
libpng \
libz \
@@ -51,11 +62,14 @@
libm \
libc \
+ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
+LOCAL_STATIC_LIBRARIES += libsuspend
+endif
+
include $(BUILD_STATIC_LIBRARY)
-
+### charger ###
include $(CLEAR_VARS)
-
ifeq ($(strip $(BOARD_CHARGER_NO_UI)),true)
LOCAL_CHARGER_NO_UI := true
endif
@@ -64,80 +78,57 @@
endif
LOCAL_SRC_FILES := \
- healthd.cpp \
- healthd_mode_android.cpp \
- BatteryPropertiesRegistrar.cpp \
+ healthd_common.cpp \
+ charger.cpp \
-ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
-LOCAL_SRC_FILES += healthd_mode_charger.cpp
-endif
-
-LOCAL_MODULE := healthd
+LOCAL_MODULE := charger
LOCAL_MODULE_TAGS := optional
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_CFLAGS := -D__STDC_LIMIT_MACROS -Werror
-
-ifeq ($(strip $(BOARD_CHARGER_DISABLE_INIT_BLANK)),true)
-LOCAL_CFLAGS += -DCHARGER_DISABLE_INIT_BLANK
-endif
-
-ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
-LOCAL_CFLAGS += -DCHARGER_ENABLE_SUSPEND
-endif
-
+LOCAL_CFLAGS := -Werror
ifeq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
LOCAL_CFLAGS += -DCHARGER_NO_UI
endif
-
-LOCAL_C_INCLUDES := bootable/recovery $(LOCAL_PATH)/include
-
ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_FAST),)
LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_FAST=$(BOARD_PERIODIC_CHORES_INTERVAL_FAST)
endif
-
ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_SLOW),)
LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_SLOW=$(BOARD_PERIODIC_CHORES_INTERVAL_SLOW)
endif
LOCAL_STATIC_LIBRARIES := \
- libhealthd_internal \
+ libhealthd_charger \
libbatterymonitor \
- libbatteryservice \
- libbinder \
libbase \
-
-ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
-LOCAL_STATIC_LIBRARIES += \
- libminui \
- libpng \
- libz \
-
-endif
-
-
-LOCAL_STATIC_LIBRARIES += \
libutils \
libcutils \
liblog \
libm \
libc \
+ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
+LOCAL_STATIC_LIBRARIES += \
+ libminui \
+ libpng \
+ libz \
+
+endif
+
ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
LOCAL_STATIC_LIBRARIES += libsuspend
endif
LOCAL_HAL_STATIC_LIBRARIES := libhealthd
-# Symlink /charger to /sbin/healthd
+# Symlink /charger to /sbin/charger
LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT) \
- && ln -sf /sbin/healthd $(TARGET_ROOT_OUT)/charger
+ && ln -sf /sbin/charger $(TARGET_ROOT_OUT)/charger
include $(BUILD_EXECUTABLE)
-
ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
define _add-charger-image
include $$(CLEAR_VARS)
@@ -165,3 +156,41 @@
_add-charger-image :=
_img_modules :=
endif # LOCAL_CHARGER_NO_UI
+
+### healthd ###
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ healthd_common.cpp \
+ healthd.cpp \
+
+LOCAL_MODULE := healthd
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+
+ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_FAST),)
+LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_FAST=$(BOARD_PERIODIC_CHORES_INTERVAL_FAST)
+endif
+ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_SLOW),)
+LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_SLOW=$(BOARD_PERIODIC_CHORES_INTERVAL_SLOW)
+endif
+
+LOCAL_STATIC_LIBRARIES := \
+ libhealthd_android \
+ libbatterymonitor \
+ libbatteryservice \
+ android.hardware.health@1.0-convert \
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ libbase \
+ libutils \
+ libcutils \
+ liblog \
+ libm \
+ libc \
+ libhidlbase \
+ libhidltransport \
+ android.hardware.health@1.0 \
+
+include $(BUILD_EXECUTABLE)
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 0c90a54..369a022 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -141,6 +141,7 @@
struct sysfsStringEnumMap supplyTypeMap[] = {
{ "Unknown", ANDROID_POWER_SUPPLY_TYPE_UNKNOWN },
{ "Battery", ANDROID_POWER_SUPPLY_TYPE_BATTERY },
+ { "BMS", ANDROID_POWER_SUPPLY_TYPE_BATTERY },
{ "UPS", ANDROID_POWER_SUPPLY_TYPE_AC },
{ "Mains", ANDROID_POWER_SUPPLY_TYPE_AC },
{ "USB", ANDROID_POWER_SUPPLY_TYPE_USB },
diff --git a/healthd/charger.cpp b/healthd/charger.cpp
new file mode 100644
index 0000000..5a8fe1a
--- /dev/null
+++ b/healthd/charger.cpp
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "charger"
+#define KLOG_LEVEL 6
+
+#include <healthd/healthd.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <cutils/klog.h>
+
+using namespace android;
+
+// main healthd loop
+extern int healthd_main(void);
+
+// Charger mode
+
+extern void healthd_mode_charger_init(struct healthd_config *config);
+extern int healthd_mode_charger_preparetowait(void);
+extern void healthd_mode_charger_heartbeat(void);
+extern void healthd_mode_charger_battery_update(
+ struct android::BatteryProperties *props);
+
+// NOPs for modes that need no special action
+
+static void healthd_mode_nop_init(struct healthd_config *config);
+static int healthd_mode_nop_preparetowait(void);
+static void healthd_mode_nop_heartbeat(void);
+static void healthd_mode_nop_battery_update(
+ struct android::BatteryProperties *props);
+
+static struct healthd_mode_ops healthd_nops = {
+ .init = healthd_mode_nop_init,
+ .preparetowait = healthd_mode_nop_preparetowait,
+ .heartbeat = healthd_mode_nop_heartbeat,
+ .battery_update = healthd_mode_nop_battery_update,
+};
+
+#ifdef CHARGER_NO_UI
+static struct healthd_mode_ops charger_ops = healthd_nops;
+#else
+static struct healthd_mode_ops charger_ops = {
+ .init = healthd_mode_charger_init,
+ .preparetowait = healthd_mode_charger_preparetowait,
+ .heartbeat = healthd_mode_charger_heartbeat,
+ .battery_update = healthd_mode_charger_battery_update,
+};
+#endif
+
+static void healthd_mode_nop_init(struct healthd_config* /*config*/) {
+}
+
+static int healthd_mode_nop_preparetowait(void) {
+ return -1;
+}
+
+static void healthd_mode_nop_heartbeat(void) {
+}
+
+static void healthd_mode_nop_battery_update(
+ struct android::BatteryProperties* /*props*/) {
+}
+
+int main(int argc, char **argv) {
+ int ch;
+
+ healthd_mode_ops = &charger_ops;
+
+ while ((ch = getopt(argc, argv, "cr")) != -1) {
+ switch (ch) {
+ case 'c':
+ // -c is now a noop
+ break;
+ case 'r':
+ // force nops for recovery
+ healthd_mode_ops = &healthd_nops;
+ break;
+ case '?':
+ default:
+ KLOG_ERROR(LOG_TAG, "Unrecognized charger option: %c\n",
+ optopt);
+ exit(1);
+ }
+ }
+
+ return healthd_main();
+}
diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp
index aa6735d..cae6c4c 100644
--- a/healthd/healthd.cpp
+++ b/healthd/healthd.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * 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.
@@ -18,369 +18,106 @@
#define KLOG_LEVEL 6
#include <healthd/healthd.h>
-#include <healthd/BatteryMonitor.h>
-#include <errno.h>
-#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include <unistd.h>
-#include <batteryservice/BatteryService.h>
#include <cutils/klog.h>
-#include <cutils/uevent.h>
-#include <sys/epoll.h>
-#include <sys/timerfd.h>
-#include <utils/Errors.h>
+
+#include <android/hardware/health/1.0/IHealth.h>
+#include <android/hardware/health/1.0/types.h>
+#include <hal_conversion.h>
using namespace android;
-#ifndef BOARD_PERIODIC_CHORES_INTERVAL_FAST
- // Periodic chores fast interval in seconds
- #define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1)
-#else
- #define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (BOARD_PERIODIC_CHORES_INTERVAL_FAST)
-#endif
+using IHealth = ::android::hardware::health::V1_0::IHealth;
+using Result = ::android::hardware::health::V1_0::Result;
+using HealthConfig = ::android::hardware::health::V1_0::HealthConfig;
+using HealthInfo = ::android::hardware::health::V1_0::HealthInfo;
-#ifndef BOARD_PERIODIC_CHORES_INTERVAL_SLOW
- // Periodic chores fast interval in seconds
- #define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10)
-#else
- #define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (BOARD_PERIODIC_CHORES_INTERVAL_SLOW)
-#endif
+using ::android::hardware::health::V1_0::hal_conversion::convertToHealthConfig;
+using ::android::hardware::health::V1_0::hal_conversion::convertFromHealthConfig;
+using ::android::hardware::health::V1_0::hal_conversion::convertToHealthInfo;
+using ::android::hardware::health::V1_0::hal_conversion::convertFromHealthInfo;
-static struct healthd_config healthd_config = {
- .periodic_chores_interval_fast = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST,
- .periodic_chores_interval_slow = DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW,
- .batteryStatusPath = String8(String8::kEmptyString),
- .batteryHealthPath = String8(String8::kEmptyString),
- .batteryPresentPath = String8(String8::kEmptyString),
- .batteryCapacityPath = String8(String8::kEmptyString),
- .batteryVoltagePath = String8(String8::kEmptyString),
- .batteryTemperaturePath = String8(String8::kEmptyString),
- .batteryTechnologyPath = String8(String8::kEmptyString),
- .batteryCurrentNowPath = String8(String8::kEmptyString),
- .batteryCurrentAvgPath = String8(String8::kEmptyString),
- .batteryChargeCounterPath = String8(String8::kEmptyString),
- .batteryFullChargePath = String8(String8::kEmptyString),
- .batteryCycleCountPath = String8(String8::kEmptyString),
- .energyCounter = NULL,
- .boot_min_cap = 0,
- .screen_on = NULL,
-};
+// device specific hal interface;
+static sp<IHealth> gHealth;
-static int eventct;
-static int epollfd;
-
-#define POWER_SUPPLY_SUBSYSTEM "power_supply"
-
-// epoll_create() parameter is actually unused
-#define MAX_EPOLL_EVENTS 40
-static int uevent_fd;
-static int wakealarm_fd;
-
-// -1 for no epoll timeout
-static int awake_poll_interval = -1;
-
-static int wakealarm_wake_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST;
-
-static BatteryMonitor* gBatteryMonitor;
-
-struct healthd_mode_ops *healthd_mode_ops;
+// main healthd loop
+extern int healthd_main(void);
// Android mode
-
extern void healthd_mode_android_init(struct healthd_config *config);
extern int healthd_mode_android_preparetowait(void);
+extern void healthd_mode_android_heartbeat(void);
extern void healthd_mode_android_battery_update(
struct android::BatteryProperties *props);
-// Charger mode
-
-extern void healthd_mode_charger_init(struct healthd_config *config);
-extern int healthd_mode_charger_preparetowait(void);
-extern void healthd_mode_charger_heartbeat(void);
-extern void healthd_mode_charger_battery_update(
- struct android::BatteryProperties *props);
-
-// NOPs for modes that need no special action
-
-static void healthd_mode_nop_init(struct healthd_config *config);
-static int healthd_mode_nop_preparetowait(void);
-static void healthd_mode_nop_heartbeat(void);
-static void healthd_mode_nop_battery_update(
- struct android::BatteryProperties *props);
-
static struct healthd_mode_ops android_ops = {
.init = healthd_mode_android_init,
.preparetowait = healthd_mode_android_preparetowait,
- .heartbeat = healthd_mode_nop_heartbeat,
+ .heartbeat = healthd_mode_android_heartbeat,
.battery_update = healthd_mode_android_battery_update,
};
-static struct healthd_mode_ops charger_ops = {
-#ifdef CHARGER_NO_UI
- .init = healthd_mode_nop_init,
- .preparetowait = healthd_mode_nop_preparetowait,
- .heartbeat = healthd_mode_nop_heartbeat,
- .battery_update = healthd_mode_nop_battery_update,
-#else
- .init = healthd_mode_charger_init,
- .preparetowait = healthd_mode_charger_preparetowait,
- .heartbeat = healthd_mode_charger_heartbeat,
- .battery_update = healthd_mode_charger_battery_update,
-#endif
-};
+// default energy counter property redirect to talk to device
+// HAL
+static int healthd_board_get_energy_counter(int64_t *energy) {
-static struct healthd_mode_ops recovery_ops = {
- .init = healthd_mode_nop_init,
- .preparetowait = healthd_mode_nop_preparetowait,
- .heartbeat = healthd_mode_nop_heartbeat,
- .battery_update = healthd_mode_nop_battery_update,
-};
-
-static void healthd_mode_nop_init(struct healthd_config* /*config*/) {
-}
-
-static int healthd_mode_nop_preparetowait(void) {
- return -1;
-}
-
-static void healthd_mode_nop_heartbeat(void) {
-}
-
-static void healthd_mode_nop_battery_update(
- struct android::BatteryProperties* /*props*/) {
-}
-
-int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup) {
- struct epoll_event ev;
-
- ev.events = EPOLLIN;
-
- if (wakeup == EVENT_WAKEUP_FD)
- ev.events |= EPOLLWAKEUP;
-
- ev.data.ptr = (void *)handler;
- if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
- KLOG_ERROR(LOG_TAG,
- "epoll_ctl failed; errno=%d\n", errno);
- return -1;
+ if (gHealth == nullptr) {
+ return NAME_NOT_FOUND;
}
- eventct++;
- return 0;
+ Result result = Result::NOT_SUPPORTED;
+ gHealth->energyCounter([=, &result] (Result ret, int64_t energyOut) {
+ result = ret;
+ *energy = energyOut;
+ });
+
+ return result == Result::SUCCESS ? OK : NAME_NOT_FOUND;
}
-static void wakealarm_set_interval(int interval) {
- struct itimerspec itval;
+void healthd_board_init(struct healthd_config *config) {
- if (wakealarm_fd == -1)
- return;
+ // Initialize the board HAL - Equivalent of healthd_board_init(config)
+ // in charger/recovery mode.
- wakealarm_wake_interval = interval;
-
- if (interval == -1)
- interval = 0;
-
- itval.it_interval.tv_sec = interval;
- itval.it_interval.tv_nsec = 0;
- itval.it_value.tv_sec = interval;
- itval.it_value.tv_nsec = 0;
-
- if (timerfd_settime(wakealarm_fd, 0, &itval, NULL) == -1)
- KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
-}
-
-status_t healthd_get_property(int id, struct BatteryProperty *val) {
- return gBatteryMonitor->getProperty(id, val);
-}
-
-void healthd_battery_update(void) {
- // Fast wake interval when on charger (watch for overheat);
- // slow wake interval when on battery (watch for drained battery).
-
- int new_wake_interval = gBatteryMonitor->update() ?
- healthd_config.periodic_chores_interval_fast :
- healthd_config.periodic_chores_interval_slow;
-
- if (new_wake_interval != wakealarm_wake_interval)
- wakealarm_set_interval(new_wake_interval);
-
- // During awake periods poll at fast rate. If wake alarm is set at fast
- // rate then just use the alarm; if wake alarm is set at slow rate then
- // poll at fast rate while awake and let alarm wake up at slow rate when
- // asleep.
-
- if (healthd_config.periodic_chores_interval_fast == -1)
- awake_poll_interval = -1;
- else
- awake_poll_interval =
- new_wake_interval == healthd_config.periodic_chores_interval_fast ?
- -1 : healthd_config.periodic_chores_interval_fast * 1000;
-}
-
-void healthd_dump_battery_state(int fd) {
- gBatteryMonitor->dumpState(fd);
- fsync(fd);
-}
-
-static void periodic_chores() {
- healthd_battery_update();
-}
-
-#define UEVENT_MSG_LEN 2048
-static void uevent_event(uint32_t /*epevents*/) {
- char msg[UEVENT_MSG_LEN+2];
- char *cp;
- int n;
-
- n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);
- if (n <= 0)
- return;
- if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
- return;
-
- msg[n] = '\0';
- msg[n+1] = '\0';
- cp = msg;
-
- while (*cp) {
- if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
- healthd_battery_update();
- break;
- }
-
- /* advance to after the next \0 */
- while (*cp++)
- ;
- }
-}
-
-static void uevent_init(void) {
- uevent_fd = uevent_open_socket(64*1024, true);
-
- if (uevent_fd < 0) {
- KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
+ gHealth = IHealth::getService("health");
+ if (gHealth == nullptr) {
+ KLOG_WARNING(LOG_TAG, "unable to get HAL interface, using defaults\n");
return;
}
- fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
- if (healthd_register_event(uevent_fd, uevent_event, EVENT_WAKEUP_FD))
- KLOG_ERROR(LOG_TAG,
- "register for uevent events failed\n");
+ HealthConfig halConfig;
+ convertToHealthConfig(config, halConfig);
+ gHealth->init(halConfig, [=] (const auto &halConfigOut) {
+ convertFromHealthConfig(halConfigOut, config);
+ // always redirect energy counter queries
+ config->energyCounter = healthd_board_get_energy_counter;
+ });
}
-static void wakealarm_event(uint32_t /*epevents*/) {
- unsigned long long wakeups;
+int healthd_board_battery_update(struct android::BatteryProperties *props) {
+ int logthis = 0;
- if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) {
- KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n");
- return;
+ if (gHealth == nullptr) {
+ return logthis;
}
- periodic_chores();
+ HealthInfo info;
+ convertToHealthInfo(props, info);
+ gHealth->update(info,
+ [=, &logthis] (int32_t ret, const auto &infoOut) {
+ logthis = ret;
+ convertFromHealthInfo(infoOut, props);
+ });
+
+ return logthis;
}
-static void wakealarm_init(void) {
- wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);
- if (wakealarm_fd == -1) {
- KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");
- return;
- }
+int main(int /*argc*/, char ** /*argv*/) {
- if (healthd_register_event(wakealarm_fd, wakealarm_event, EVENT_WAKEUP_FD))
- KLOG_ERROR(LOG_TAG,
- "Registration of wakealarm event failed\n");
-
- wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
-}
-
-static void healthd_mainloop(void) {
- int nevents = 0;
- while (1) {
- struct epoll_event events[eventct];
- int timeout = awake_poll_interval;
- int mode_timeout;
-
- /* Don't wait for first timer timeout to run periodic chores */
- if (!nevents)
- periodic_chores();
-
- healthd_mode_ops->heartbeat();
-
- mode_timeout = healthd_mode_ops->preparetowait();
- if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout))
- timeout = mode_timeout;
- nevents = epoll_wait(epollfd, events, eventct, timeout);
- if (nevents == -1) {
- if (errno == EINTR)
- continue;
- KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
- break;
- }
-
- for (int n = 0; n < nevents; ++n) {
- if (events[n].data.ptr)
- (*(void (*)(int))events[n].data.ptr)(events[n].events);
- }
- }
-
- return;
-}
-
-static int healthd_init() {
- epollfd = epoll_create(MAX_EPOLL_EVENTS);
- if (epollfd == -1) {
- KLOG_ERROR(LOG_TAG,
- "epoll_create failed; errno=%d\n",
- errno);
- return -1;
- }
-
- healthd_board_init(&healthd_config);
- healthd_mode_ops->init(&healthd_config);
- wakealarm_init();
- uevent_init();
- gBatteryMonitor = new BatteryMonitor();
- gBatteryMonitor->init(&healthd_config);
- return 0;
-}
-
-int main(int argc, char **argv) {
- int ch;
- int ret;
-
- klog_set_level(KLOG_LEVEL);
healthd_mode_ops = &android_ops;
- if (!strcmp(basename(argv[0]), "charger")) {
- healthd_mode_ops = &charger_ops;
- } else {
- while ((ch = getopt(argc, argv, "cr")) != -1) {
- switch (ch) {
- case 'c':
- healthd_mode_ops = &charger_ops;
- break;
- case 'r':
- healthd_mode_ops = &recovery_ops;
- break;
- case '?':
- default:
- KLOG_ERROR(LOG_TAG, "Unrecognized healthd option: %c\n",
- optopt);
- exit(1);
- }
- }
- }
-
- ret = healthd_init();
- if (ret) {
- KLOG_ERROR("Initialization failed, exiting\n");
- exit(2);
- }
-
- healthd_mainloop();
- KLOG_ERROR("Main loop terminated, exiting\n");
- return 3;
+ return healthd_main();
}
diff --git a/healthd/healthd_board_default.cpp b/healthd/healthd_board_default.cpp
deleted file mode 100644
index eb55773..0000000
--- a/healthd/healthd_board_default.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2013 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 <healthd/healthd.h>
-
-void healthd_board_init(struct healthd_config*)
-{
- // use defaults
-}
-
-
-int healthd_board_battery_update(struct android::BatteryProperties*)
-{
- // return 0 to log periodic polled battery status to kernel log
- return 0;
-}
diff --git a/healthd/healthd_common.cpp b/healthd/healthd_common.cpp
new file mode 100644
index 0000000..6599919
--- /dev/null
+++ b/healthd/healthd_common.cpp
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "healthd-common"
+#define KLOG_LEVEL 6
+
+#include <healthd/healthd.h>
+#include <healthd/BatteryMonitor.h>
+
+#include <errno.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <batteryservice/BatteryService.h>
+#include <cutils/klog.h>
+#include <cutils/uevent.h>
+#include <sys/epoll.h>
+#include <sys/timerfd.h>
+#include <utils/Errors.h>
+
+using namespace android;
+
+#ifndef BOARD_PERIODIC_CHORES_INTERVAL_FAST
+ // Periodic chores fast interval in seconds
+ #define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1)
+#else
+ #define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (BOARD_PERIODIC_CHORES_INTERVAL_FAST)
+#endif
+
+#ifndef BOARD_PERIODIC_CHORES_INTERVAL_SLOW
+ // Periodic chores fast interval in seconds
+ #define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10)
+#else
+ #define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (BOARD_PERIODIC_CHORES_INTERVAL_SLOW)
+#endif
+
+static struct healthd_config healthd_config = {
+ .periodic_chores_interval_fast = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST,
+ .periodic_chores_interval_slow = DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW,
+ .batteryStatusPath = String8(String8::kEmptyString),
+ .batteryHealthPath = String8(String8::kEmptyString),
+ .batteryPresentPath = String8(String8::kEmptyString),
+ .batteryCapacityPath = String8(String8::kEmptyString),
+ .batteryVoltagePath = String8(String8::kEmptyString),
+ .batteryTemperaturePath = String8(String8::kEmptyString),
+ .batteryTechnologyPath = String8(String8::kEmptyString),
+ .batteryCurrentNowPath = String8(String8::kEmptyString),
+ .batteryCurrentAvgPath = String8(String8::kEmptyString),
+ .batteryChargeCounterPath = String8(String8::kEmptyString),
+ .batteryFullChargePath = String8(String8::kEmptyString),
+ .batteryCycleCountPath = String8(String8::kEmptyString),
+ .energyCounter = NULL,
+ .boot_min_cap = 0,
+ .screen_on = NULL,
+};
+
+static int eventct;
+static int epollfd;
+
+#define POWER_SUPPLY_SUBSYSTEM "power_supply"
+
+// epoll_create() parameter is actually unused
+#define MAX_EPOLL_EVENTS 40
+static int uevent_fd;
+static int wakealarm_fd;
+
+// -1 for no epoll timeout
+static int awake_poll_interval = -1;
+
+static int wakealarm_wake_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST;
+
+static BatteryMonitor* gBatteryMonitor;
+
+struct healthd_mode_ops *healthd_mode_ops;
+
+int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup) {
+ struct epoll_event ev;
+
+ ev.events = EPOLLIN;
+
+ if (wakeup == EVENT_WAKEUP_FD)
+ ev.events |= EPOLLWAKEUP;
+
+ ev.data.ptr = (void *)handler;
+ if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
+ KLOG_ERROR(LOG_TAG,
+ "epoll_ctl failed; errno=%d\n", errno);
+ return -1;
+ }
+
+ eventct++;
+ return 0;
+}
+
+static void wakealarm_set_interval(int interval) {
+ struct itimerspec itval;
+
+ if (wakealarm_fd == -1)
+ return;
+
+ wakealarm_wake_interval = interval;
+
+ if (interval == -1)
+ interval = 0;
+
+ itval.it_interval.tv_sec = interval;
+ itval.it_interval.tv_nsec = 0;
+ itval.it_value.tv_sec = interval;
+ itval.it_value.tv_nsec = 0;
+
+ if (timerfd_settime(wakealarm_fd, 0, &itval, NULL) == -1)
+ KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
+}
+
+status_t healthd_get_property(int id, struct BatteryProperty *val) {
+ return gBatteryMonitor->getProperty(id, val);
+}
+
+void healthd_battery_update(void) {
+ // Fast wake interval when on charger (watch for overheat);
+ // slow wake interval when on battery (watch for drained battery).
+
+ int new_wake_interval = gBatteryMonitor->update() ?
+ healthd_config.periodic_chores_interval_fast :
+ healthd_config.periodic_chores_interval_slow;
+
+ if (new_wake_interval != wakealarm_wake_interval)
+ wakealarm_set_interval(new_wake_interval);
+
+ // During awake periods poll at fast rate. If wake alarm is set at fast
+ // rate then just use the alarm; if wake alarm is set at slow rate then
+ // poll at fast rate while awake and let alarm wake up at slow rate when
+ // asleep.
+
+ if (healthd_config.periodic_chores_interval_fast == -1)
+ awake_poll_interval = -1;
+ else
+ awake_poll_interval =
+ new_wake_interval == healthd_config.periodic_chores_interval_fast ?
+ -1 : healthd_config.periodic_chores_interval_fast * 1000;
+}
+
+void healthd_dump_battery_state(int fd) {
+ gBatteryMonitor->dumpState(fd);
+ fsync(fd);
+}
+
+static void periodic_chores() {
+ healthd_battery_update();
+}
+
+#define UEVENT_MSG_LEN 2048
+static void uevent_event(uint32_t /*epevents*/) {
+ char msg[UEVENT_MSG_LEN+2];
+ char *cp;
+ int n;
+
+ n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);
+ if (n <= 0)
+ return;
+ if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
+ return;
+
+ msg[n] = '\0';
+ msg[n+1] = '\0';
+ cp = msg;
+
+ while (*cp) {
+ if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
+ healthd_battery_update();
+ break;
+ }
+
+ /* advance to after the next \0 */
+ while (*cp++)
+ ;
+ }
+}
+
+static void uevent_init(void) {
+ uevent_fd = uevent_open_socket(64*1024, true);
+
+ if (uevent_fd < 0) {
+ KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
+ return;
+ }
+
+ fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
+ if (healthd_register_event(uevent_fd, uevent_event, EVENT_WAKEUP_FD))
+ KLOG_ERROR(LOG_TAG,
+ "register for uevent events failed\n");
+}
+
+static void wakealarm_event(uint32_t /*epevents*/) {
+ unsigned long long wakeups;
+
+ if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) {
+ KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n");
+ return;
+ }
+
+ periodic_chores();
+}
+
+static void wakealarm_init(void) {
+ wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);
+ if (wakealarm_fd == -1) {
+ KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");
+ return;
+ }
+
+ if (healthd_register_event(wakealarm_fd, wakealarm_event, EVENT_WAKEUP_FD))
+ KLOG_ERROR(LOG_TAG,
+ "Registration of wakealarm event failed\n");
+
+ wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
+}
+
+static void healthd_mainloop(void) {
+ int nevents = 0;
+ while (1) {
+ struct epoll_event events[eventct];
+ int timeout = awake_poll_interval;
+ int mode_timeout;
+
+ /* Don't wait for first timer timeout to run periodic chores */
+ if (!nevents)
+ periodic_chores();
+
+ healthd_mode_ops->heartbeat();
+
+ mode_timeout = healthd_mode_ops->preparetowait();
+ if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout))
+ timeout = mode_timeout;
+ nevents = epoll_wait(epollfd, events, eventct, timeout);
+ if (nevents == -1) {
+ if (errno == EINTR)
+ continue;
+ KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
+ break;
+ }
+
+ for (int n = 0; n < nevents; ++n) {
+ if (events[n].data.ptr)
+ (*(void (*)(int))events[n].data.ptr)(events[n].events);
+ }
+ }
+
+ return;
+}
+
+static int healthd_init() {
+ epollfd = epoll_create(MAX_EPOLL_EVENTS);
+ if (epollfd == -1) {
+ KLOG_ERROR(LOG_TAG,
+ "epoll_create failed; errno=%d\n",
+ errno);
+ return -1;
+ }
+
+ healthd_board_init(&healthd_config);
+ healthd_mode_ops->init(&healthd_config);
+ wakealarm_init();
+ uevent_init();
+ gBatteryMonitor = new BatteryMonitor();
+ gBatteryMonitor->init(&healthd_config);
+ return 0;
+}
+
+int healthd_main() {
+ int ret;
+
+ klog_set_level(KLOG_LEVEL);
+
+ if (!healthd_mode_ops) {
+ KLOG_ERROR("healthd ops not set, exiting\n");
+ exit(1);
+ }
+
+ ret = healthd_init();
+ if (ret) {
+ KLOG_ERROR("Initialization failed, exiting\n");
+ exit(2);
+ }
+
+ healthd_mainloop();
+ KLOG_ERROR("Main loop terminated, exiting\n");
+ return 3;
+}
diff --git a/healthd/healthd_mode_android.cpp b/healthd/healthd_mode_android.cpp
index 323ef52..c612313 100644
--- a/healthd/healthd_mode_android.cpp
+++ b/healthd/healthd_mode_android.cpp
@@ -42,6 +42,9 @@
return -1;
}
+void healthd_mode_android_heartbeat(void) {
+}
+
static void binder_event(uint32_t /*epevents*/) {
IPCThreadState::self()->handlePolledCommands();
}
diff --git a/include/system/graphics-base.h b/include/system/graphics-base.h
new file mode 100644
index 0000000..346a318
--- /dev/null
+++ b/include/system/graphics-base.h
@@ -0,0 +1,134 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+// Source: android.hardware.graphics.common@1.0
+
+#ifndef HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_0_EXPORTED_CONSTANTS_H_
+#define HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_0_EXPORTED_CONSTANTS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ HAL_PIXEL_FORMAT_RGBA_8888 = 1,
+ HAL_PIXEL_FORMAT_RGBX_8888 = 2,
+ HAL_PIXEL_FORMAT_RGB_888 = 3,
+ HAL_PIXEL_FORMAT_RGB_565 = 4,
+ HAL_PIXEL_FORMAT_BGRA_8888 = 5,
+ HAL_PIXEL_FORMAT_RGBA_FP16 = 22, // 0x16
+ HAL_PIXEL_FORMAT_YV12 = 842094169, // 0x32315659
+ HAL_PIXEL_FORMAT_Y8 = 538982489, // 0x20203859
+ HAL_PIXEL_FORMAT_Y16 = 540422489, // 0x20363159
+ HAL_PIXEL_FORMAT_RAW16 = 32, // 0x20
+ HAL_PIXEL_FORMAT_RAW10 = 37, // 0x25
+ HAL_PIXEL_FORMAT_RAW12 = 38, // 0x26
+ HAL_PIXEL_FORMAT_RAW_OPAQUE = 36, // 0x24
+ HAL_PIXEL_FORMAT_BLOB = 33, // 0x21
+ HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 34, // 0x22
+ HAL_PIXEL_FORMAT_YCBCR_420_888 = 35, // 0x23
+ HAL_PIXEL_FORMAT_YCBCR_422_888 = 39, // 0x27
+ HAL_PIXEL_FORMAT_YCBCR_444_888 = 40, // 0x28
+ HAL_PIXEL_FORMAT_FLEX_RGB_888 = 41, // 0x29
+ HAL_PIXEL_FORMAT_FLEX_RGBA_8888 = 42, // 0x2A
+ HAL_PIXEL_FORMAT_YCBCR_422_SP = 16, // 0x10
+ HAL_PIXEL_FORMAT_YCRCB_420_SP = 17, // 0x11
+ HAL_PIXEL_FORMAT_YCBCR_422_I = 20, // 0x14
+ HAL_PIXEL_FORMAT_JPEG = 256, // 0x100
+} android_pixel_format_t;
+
+typedef enum {
+ HAL_TRANSFORM_FLIP_H = 1, // 0x01
+ HAL_TRANSFORM_FLIP_V = 2, // 0x02
+ HAL_TRANSFORM_ROT_90 = 4, // 0x04
+ HAL_TRANSFORM_ROT_180 = 3, // 0x03
+ HAL_TRANSFORM_ROT_270 = 7, // 0x07
+} android_transform_t;
+
+typedef enum {
+ HAL_DATASPACE_UNKNOWN = 0, // 0x0
+ HAL_DATASPACE_ARBITRARY = 1, // 0x1
+ HAL_DATASPACE_STANDARD_SHIFT = 16,
+ HAL_DATASPACE_STANDARD_MASK = 4128768, // (63 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_UNSPECIFIED = 0, // (0 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_BT709 = 65536, // (1 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_BT601_625 = 131072, // (2 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED = 196608, // (3 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_BT601_525 = 262144, // (4 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED = 327680, // (5 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_BT2020 = 393216, // (6 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE = 458752, // (7 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_BT470M = 524288, // (8 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_FILM = 589824, // (9 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_DCI_P3 = 655360, // (10 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_ADOBE_RGB = 720896, // (11 << STANDARD_SHIFT)
+ HAL_DATASPACE_TRANSFER_SHIFT = 22,
+ HAL_DATASPACE_TRANSFER_MASK = 130023424, // (31 << TRANSFER_SHIFT)
+ HAL_DATASPACE_TRANSFER_UNSPECIFIED = 0, // (0 << TRANSFER_SHIFT)
+ HAL_DATASPACE_TRANSFER_LINEAR = 4194304, // (1 << TRANSFER_SHIFT)
+ HAL_DATASPACE_TRANSFER_SRGB = 8388608, // (2 << TRANSFER_SHIFT)
+ HAL_DATASPACE_TRANSFER_SMPTE_170M = 12582912, // (3 << TRANSFER_SHIFT)
+ HAL_DATASPACE_TRANSFER_GAMMA2_2 = 16777216, // (4 << TRANSFER_SHIFT)
+ HAL_DATASPACE_TRANSFER_GAMMA2_6 = 20971520, // (5 << TRANSFER_SHIFT)
+ HAL_DATASPACE_TRANSFER_GAMMA2_8 = 25165824, // (6 << TRANSFER_SHIFT)
+ HAL_DATASPACE_TRANSFER_ST2084 = 29360128, // (7 << TRANSFER_SHIFT)
+ HAL_DATASPACE_TRANSFER_HLG = 33554432, // (8 << TRANSFER_SHIFT)
+ HAL_DATASPACE_RANGE_SHIFT = 27,
+ HAL_DATASPACE_RANGE_MASK = 939524096, // (7 << RANGE_SHIFT)
+ HAL_DATASPACE_RANGE_UNSPECIFIED = 0, // (0 << RANGE_SHIFT)
+ HAL_DATASPACE_RANGE_FULL = 134217728, // (1 << RANGE_SHIFT)
+ HAL_DATASPACE_RANGE_LIMITED = 268435456, // (2 << RANGE_SHIFT)
+ HAL_DATASPACE_RANGE_EXTENDED = 402653184, // (3 << RANGE_SHIFT)
+ HAL_DATASPACE_SRGB_LINEAR = 512, // 0x200
+ HAL_DATASPACE_V0_SRGB_LINEAR = 138477568, // ((STANDARD_BT709 | TRANSFER_LINEAR) | RANGE_FULL)
+ HAL_DATASPACE_V0_SCRGB_LINEAR = 406913024, // ((STANDARD_BT709 | TRANSFER_LINEAR) | RANGE_EXTENDED)
+ HAL_DATASPACE_SRGB = 513, // 0x201
+ HAL_DATASPACE_V0_SRGB = 142671872, // ((STANDARD_BT709 | TRANSFER_SRGB) | RANGE_FULL)
+ HAL_DATASPACE_V0_SCRGB = 411107328, // ((STANDARD_BT709 | TRANSFER_SRGB) | RANGE_EXTENDED)
+ HAL_DATASPACE_JFIF = 257, // 0x101
+ HAL_DATASPACE_V0_JFIF = 146931712, // ((STANDARD_BT601_625 | TRANSFER_SMPTE_170M) | RANGE_FULL)
+ HAL_DATASPACE_BT601_625 = 258, // 0x102
+ HAL_DATASPACE_V0_BT601_625 = 281149440, // ((STANDARD_BT601_625 | TRANSFER_SMPTE_170M) | RANGE_LIMITED)
+ HAL_DATASPACE_BT601_525 = 259, // 0x103
+ HAL_DATASPACE_V0_BT601_525 = 281280512, // ((STANDARD_BT601_525 | TRANSFER_SMPTE_170M) | RANGE_LIMITED)
+ HAL_DATASPACE_BT709 = 260, // 0x104
+ HAL_DATASPACE_V0_BT709 = 281083904, // ((STANDARD_BT709 | TRANSFER_SMPTE_170M) | RANGE_LIMITED)
+ HAL_DATASPACE_DCI_P3_LINEAR = 139067392, // ((STANDARD_DCI_P3 | TRANSFER_LINEAR) | RANGE_FULL)
+ HAL_DATASPACE_DCI_P3 = 155844608, // ((STANDARD_DCI_P3 | TRANSFER_GAMMA2_6) | RANGE_FULL)
+ HAL_DATASPACE_ADOBE_RGB = 151715840, // ((STANDARD_ADOBE_RGB | TRANSFER_GAMMA2_2) | RANGE_FULL)
+ HAL_DATASPACE_BT2020_LINEAR = 138805248, // ((STANDARD_BT2020 | TRANSFER_LINEAR) | RANGE_FULL)
+ HAL_DATASPACE_BT2020 = 147193856, // ((STANDARD_BT2020 | TRANSFER_SMPTE_170M) | RANGE_FULL)
+ HAL_DATASPACE_DEPTH = 4096, // 0x1000
+} android_dataspace_t;
+
+typedef enum {
+ HAL_COLOR_MODE_NATIVE = 0,
+ HAL_COLOR_MODE_STANDARD_BT601_625 = 1,
+ HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED = 2,
+ HAL_COLOR_MODE_STANDARD_BT601_525 = 3,
+ HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED = 4,
+ HAL_COLOR_MODE_STANDARD_BT709 = 5,
+ HAL_COLOR_MODE_DCI_P3 = 6,
+ HAL_COLOR_MODE_SRGB = 7,
+ HAL_COLOR_MODE_ADOBE_RGB = 8,
+} android_color_mode_t;
+
+typedef enum {
+ HAL_COLOR_TRANSFORM_IDENTITY = 0,
+ HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX = 1,
+ HAL_COLOR_TRANSFORM_VALUE_INVERSE = 2,
+ HAL_COLOR_TRANSFORM_GRAYSCALE = 3,
+ HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA = 4,
+ HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA = 5,
+ HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA = 6,
+} android_color_transform_t;
+
+typedef enum {
+ HAL_HDR_DOLBY_VISION = 1,
+ HAL_HDR_HDR10 = 2,
+ HAL_HDR_HLG = 3,
+} android_hdr_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_0_EXPORTED_CONSTANTS_H_
diff --git a/include/system/graphics.h b/include/system/graphics.h
index ae10fa0..449b8c7 100644
--- a/include/system/graphics.h
+++ b/include/system/graphics.h
@@ -20,10 +20,30 @@
#include <stddef.h>
#include <stdint.h>
+/*
+ * Some of the enums are now defined in HIDL in hardware/interfaces and are
+ * generated.
+ */
+#include "graphics-base.h"
+
#ifdef __cplusplus
extern "C" {
#endif
+/* for compatibility */
+#define HAL_PIXEL_FORMAT_YCbCr_420_888 HAL_PIXEL_FORMAT_YCBCR_420_888
+#define HAL_PIXEL_FORMAT_YCbCr_422_888 HAL_PIXEL_FORMAT_YCBCR_422_888
+#define HAL_PIXEL_FORMAT_YCbCr_444_888 HAL_PIXEL_FORMAT_YCBCR_444_888
+#define HAL_PIXEL_FORMAT_YCbCr_422_SP HAL_PIXEL_FORMAT_YCBCR_422_SP
+#define HAL_PIXEL_FORMAT_YCrCb_420_SP HAL_PIXEL_FORMAT_YCRCB_420_SP
+#define HAL_PIXEL_FORMAT_YCbCr_422_I HAL_PIXEL_FORMAT_YCBCR_422_I
+typedef android_pixel_format_t android_pixel_format;
+typedef android_transform_t android_transform;
+typedef android_dataspace_t android_dataspace;
+typedef android_color_mode_t android_color_mode;
+typedef android_color_transform_t android_color_transform;
+typedef android_hdr_t android_hdr;
+
/*
* If the HAL needs to create service threads to handle graphics related
* tasks, these threads need to run at HAL_PRIORITY_URGENT_DISPLAY priority
@@ -38,411 +58,6 @@
#define HAL_PRIORITY_URGENT_DISPLAY (-8)
-/**
- * pixel format definitions
- */
-
-typedef enum android_pixel_format {
- /*
- * "linear" color pixel formats:
- *
- * When used with ANativeWindow, the dataSpace field describes the color
- * space of the buffer.
- *
- * The color space determines, for example, if the formats are linear or
- * gamma-corrected; or whether any special operations are performed when
- * reading or writing into a buffer in one of these formats.
- */
- HAL_PIXEL_FORMAT_RGBA_8888 = 1,
- HAL_PIXEL_FORMAT_RGBX_8888 = 2,
- HAL_PIXEL_FORMAT_RGB_888 = 3,
- HAL_PIXEL_FORMAT_RGB_565 = 4,
- HAL_PIXEL_FORMAT_BGRA_8888 = 5,
-
- /*
- * 0x100 - 0x1FF
- *
- * This range is reserved for pixel formats that are specific to the HAL
- * implementation. Implementations can use any value in this range to
- * communicate video pixel formats between their HAL modules. These formats
- * must not have an alpha channel. Additionally, an EGLimage created from a
- * gralloc buffer of one of these formats must be supported for use with the
- * GL_OES_EGL_image_external OpenGL ES extension.
- */
-
- /*
- * Android YUV format:
- *
- * This format is exposed outside of the HAL to software decoders and
- * applications. EGLImageKHR must support it in conjunction with the
- * OES_EGL_image_external extension.
- *
- * YV12 is a 4:2:0 YCrCb planar format comprised of a WxH Y plane followed
- * by (W/2) x (H/2) Cr and Cb planes.
- *
- * This format assumes
- * - an even width
- * - an even height
- * - a horizontal stride multiple of 16 pixels
- * - a vertical stride equal to the height
- *
- * y_size = stride * height
- * c_stride = ALIGN(stride/2, 16)
- * c_size = c_stride * height/2
- * size = y_size + c_size * 2
- * cr_offset = y_size
- * cb_offset = y_size + c_size
- *
- * When used with ANativeWindow, the dataSpace field describes the color
- * space of the buffer.
- */
- HAL_PIXEL_FORMAT_YV12 = 0x32315659, // YCrCb 4:2:0 Planar
-
-
- /*
- * Android Y8 format:
- *
- * This format is exposed outside of the HAL to the framework.
- * The expected gralloc usage flags are SW_* and HW_CAMERA_*,
- * and no other HW_ flags will be used.
- *
- * Y8 is a YUV planar format comprised of a WxH Y plane,
- * with each pixel being represented by 8 bits.
- *
- * It is equivalent to just the Y plane from YV12.
- *
- * This format assumes
- * - an even width
- * - an even height
- * - a horizontal stride multiple of 16 pixels
- * - a vertical stride equal to the height
- *
- * size = stride * height
- *
- * When used with ANativeWindow, the dataSpace field describes the color
- * space of the buffer.
- */
- HAL_PIXEL_FORMAT_Y8 = 0x20203859,
-
- /*
- * Android Y16 format:
- *
- * This format is exposed outside of the HAL to the framework.
- * The expected gralloc usage flags are SW_* and HW_CAMERA_*,
- * and no other HW_ flags will be used.
- *
- * Y16 is a YUV planar format comprised of a WxH Y plane,
- * with each pixel being represented by 16 bits.
- *
- * It is just like Y8, but has double the bits per pixel (little endian).
- *
- * This format assumes
- * - an even width
- * - an even height
- * - a horizontal stride multiple of 16 pixels
- * - a vertical stride equal to the height
- * - strides are specified in pixels, not in bytes
- *
- * size = stride * height * 2
- *
- * When used with ANativeWindow, the dataSpace field describes the color
- * space of the buffer, except that dataSpace field
- * HAL_DATASPACE_DEPTH indicates that this buffer contains a depth
- * image where each sample is a distance value measured by a depth camera,
- * plus an associated confidence value.
- */
- HAL_PIXEL_FORMAT_Y16 = 0x20363159,
-
- /*
- * Android RAW sensor format:
- *
- * This format is exposed outside of the camera HAL to applications.
- *
- * RAW16 is a single-channel, 16-bit, little endian format, typically
- * representing raw Bayer-pattern images from an image sensor, with minimal
- * processing.
- *
- * The exact pixel layout of the data in the buffer is sensor-dependent, and
- * needs to be queried from the camera device.
- *
- * Generally, not all 16 bits are used; more common values are 10 or 12
- * bits. If not all bits are used, the lower-order bits are filled first.
- * All parameters to interpret the raw data (black and white points,
- * color space, etc) must be queried from the camera device.
- *
- * This format assumes
- * - an even width
- * - an even height
- * - a horizontal stride multiple of 16 pixels
- * - a vertical stride equal to the height
- * - strides are specified in pixels, not in bytes
- *
- * size = stride * height * 2
- *
- * This format must be accepted by the gralloc module when used with the
- * following usage flags:
- * - GRALLOC_USAGE_HW_CAMERA_*
- * - GRALLOC_USAGE_SW_*
- * - GRALLOC_USAGE_RENDERSCRIPT
- *
- * When used with ANativeWindow, the dataSpace should be
- * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
- * extra metadata to define.
- */
- HAL_PIXEL_FORMAT_RAW16 = 0x20,
-
- /*
- * Android RAW10 format:
- *
- * This format is exposed outside of the camera HAL to applications.
- *
- * RAW10 is a single-channel, 10-bit per pixel, densely packed in each row,
- * unprocessed format, usually representing raw Bayer-pattern images coming from
- * an image sensor.
- *
- * In an image buffer with this format, starting from the first pixel of each
- * row, each 4 consecutive pixels are packed into 5 bytes (40 bits). Each one
- * of the first 4 bytes contains the top 8 bits of each pixel, The fifth byte
- * contains the 2 least significant bits of the 4 pixels, the exact layout data
- * for each 4 consecutive pixels is illustrated below (Pi[j] stands for the jth
- * bit of the ith pixel):
- *
- * bit 7 bit 0
- * =====|=====|=====|=====|=====|=====|=====|=====|
- * Byte 0: |P0[9]|P0[8]|P0[7]|P0[6]|P0[5]|P0[4]|P0[3]|P0[2]|
- * |-----|-----|-----|-----|-----|-----|-----|-----|
- * Byte 1: |P1[9]|P1[8]|P1[7]|P1[6]|P1[5]|P1[4]|P1[3]|P1[2]|
- * |-----|-----|-----|-----|-----|-----|-----|-----|
- * Byte 2: |P2[9]|P2[8]|P2[7]|P2[6]|P2[5]|P2[4]|P2[3]|P2[2]|
- * |-----|-----|-----|-----|-----|-----|-----|-----|
- * Byte 3: |P3[9]|P3[8]|P3[7]|P3[6]|P3[5]|P3[4]|P3[3]|P3[2]|
- * |-----|-----|-----|-----|-----|-----|-----|-----|
- * Byte 4: |P3[1]|P3[0]|P2[1]|P2[0]|P1[1]|P1[0]|P0[1]|P0[0]|
- * ===============================================
- *
- * This format assumes
- * - a width multiple of 4 pixels
- * - an even height
- * - a vertical stride equal to the height
- * - strides are specified in bytes, not in pixels
- *
- * size = stride * height
- *
- * When stride is equal to width * (10 / 8), there will be no padding bytes at
- * the end of each row, the entire image data is densely packed. When stride is
- * larger than width * (10 / 8), padding bytes will be present at the end of each
- * row (including the last row).
- *
- * This format must be accepted by the gralloc module when used with the
- * following usage flags:
- * - GRALLOC_USAGE_HW_CAMERA_*
- * - GRALLOC_USAGE_SW_*
- * - GRALLOC_USAGE_RENDERSCRIPT
- *
- * When used with ANativeWindow, the dataSpace field should be
- * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
- * extra metadata to define.
- */
- HAL_PIXEL_FORMAT_RAW10 = 0x25,
-
- /*
- * Android RAW12 format:
- *
- * This format is exposed outside of camera HAL to applications.
- *
- * RAW12 is a single-channel, 12-bit per pixel, densely packed in each row,
- * unprocessed format, usually representing raw Bayer-pattern images coming from
- * an image sensor.
- *
- * In an image buffer with this format, starting from the first pixel of each
- * row, each two consecutive pixels are packed into 3 bytes (24 bits). The first
- * and second byte contains the top 8 bits of first and second pixel. The third
- * byte contains the 4 least significant bits of the two pixels, the exact layout
- * data for each two consecutive pixels is illustrated below (Pi[j] stands for
- * the jth bit of the ith pixel):
- *
- * bit 7 bit 0
- * ======|======|======|======|======|======|======|======|
- * Byte 0: |P0[11]|P0[10]|P0[ 9]|P0[ 8]|P0[ 7]|P0[ 6]|P0[ 5]|P0[ 4]|
- * |------|------|------|------|------|------|------|------|
- * Byte 1: |P1[11]|P1[10]|P1[ 9]|P1[ 8]|P1[ 7]|P1[ 6]|P1[ 5]|P1[ 4]|
- * |------|------|------|------|------|------|------|------|
- * Byte 2: |P1[ 3]|P1[ 2]|P1[ 1]|P1[ 0]|P0[ 3]|P0[ 2]|P0[ 1]|P0[ 0]|
- * =======================================================
- *
- * This format assumes:
- * - a width multiple of 4 pixels
- * - an even height
- * - a vertical stride equal to the height
- * - strides are specified in bytes, not in pixels
- *
- * size = stride * height
- *
- * When stride is equal to width * (12 / 8), there will be no padding bytes at
- * the end of each row, the entire image data is densely packed. When stride is
- * larger than width * (12 / 8), padding bytes will be present at the end of
- * each row (including the last row).
- *
- * This format must be accepted by the gralloc module when used with the
- * following usage flags:
- * - GRALLOC_USAGE_HW_CAMERA_*
- * - GRALLOC_USAGE_SW_*
- * - GRALLOC_USAGE_RENDERSCRIPT
- *
- * When used with ANativeWindow, the dataSpace field should be
- * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
- * extra metadata to define.
- */
- HAL_PIXEL_FORMAT_RAW12 = 0x26,
-
- /*
- * Android opaque RAW format:
- *
- * This format is exposed outside of the camera HAL to applications.
- *
- * RAW_OPAQUE is a format for unprocessed raw image buffers coming from an
- * image sensor. The actual structure of buffers of this format is
- * implementation-dependent.
- *
- * This format must be accepted by the gralloc module when used with the
- * following usage flags:
- * - GRALLOC_USAGE_HW_CAMERA_*
- * - GRALLOC_USAGE_SW_*
- * - GRALLOC_USAGE_RENDERSCRIPT
- *
- * When used with ANativeWindow, the dataSpace field should be
- * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
- * extra metadata to define.
- */
- HAL_PIXEL_FORMAT_RAW_OPAQUE = 0x24,
-
- /*
- * Android binary blob graphics buffer format:
- *
- * This format is used to carry task-specific data which does not have a
- * standard image structure. The details of the format are left to the two
- * endpoints.
- *
- * A typical use case is for transporting JPEG-compressed images from the
- * Camera HAL to the framework or to applications.
- *
- * Buffers of this format must have a height of 1, and width equal to their
- * size in bytes.
- *
- * When used with ANativeWindow, the mapping of the dataSpace field to
- * buffer contents for BLOB is as follows:
- *
- * dataSpace value | Buffer contents
- * -------------------------------+-----------------------------------------
- * HAL_DATASPACE_JFIF | An encoded JPEG image
- * HAL_DATASPACE_DEPTH | An android_depth_points buffer
- * Other | Unsupported
- *
- */
- HAL_PIXEL_FORMAT_BLOB = 0x21,
-
- /*
- * Android format indicating that the choice of format is entirely up to the
- * device-specific Gralloc implementation.
- *
- * The Gralloc implementation should examine the usage bits passed in when
- * allocating a buffer with this format, and it should derive the pixel
- * format from those usage flags. This format will never be used with any
- * of the GRALLOC_USAGE_SW_* usage flags.
- *
- * If a buffer of this format is to be used as an OpenGL ES texture, the
- * framework will assume that sampling the texture will always return an
- * alpha value of 1.0 (i.e. the buffer contains only opaque pixel values).
- *
- * When used with ANativeWindow, the dataSpace field describes the color
- * space of the buffer.
- */
- HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22,
-
- /*
- * Android flexible YCbCr 4:2:0 formats
- *
- * This format allows platforms to use an efficient YCbCr/YCrCb 4:2:0
- * buffer layout, while still describing the general format in a
- * layout-independent manner. While called YCbCr, it can be
- * used to describe formats with either chromatic ordering, as well as
- * whole planar or semiplanar layouts.
- *
- * struct android_ycbcr (below) is the the struct used to describe it.
- *
- * This format must be accepted by the gralloc module when
- * USAGE_SW_WRITE_* or USAGE_SW_READ_* are set.
- *
- * This format is locked for use by gralloc's (*lock_ycbcr) method, and
- * locking with the (*lock) method will return an error.
- *
- * When used with ANativeWindow, the dataSpace field describes the color
- * space of the buffer.
- */
- HAL_PIXEL_FORMAT_YCbCr_420_888 = 0x23,
-
- /*
- * Android flexible YCbCr 4:2:2 formats
- *
- * This format allows platforms to use an efficient YCbCr/YCrCb 4:2:2
- * buffer layout, while still describing the general format in a
- * layout-independent manner. While called YCbCr, it can be
- * used to describe formats with either chromatic ordering, as well as
- * whole planar or semiplanar layouts.
- *
- * This format is currently only used by SW readable buffers
- * produced by MediaCodecs, so the gralloc module can ignore this format.
- */
- HAL_PIXEL_FORMAT_YCbCr_422_888 = 0x27,
-
- /*
- * Android flexible YCbCr 4:4:4 formats
- *
- * This format allows platforms to use an efficient YCbCr/YCrCb 4:4:4
- * buffer layout, while still describing the general format in a
- * layout-independent manner. While called YCbCr, it can be
- * used to describe formats with either chromatic ordering, as well as
- * whole planar or semiplanar layouts.
- *
- * This format is currently only used by SW readable buffers
- * produced by MediaCodecs, so the gralloc module can ignore this format.
- */
- HAL_PIXEL_FORMAT_YCbCr_444_888 = 0x28,
-
- /*
- * Android flexible RGB 888 formats
- *
- * This format allows platforms to use an efficient RGB/BGR/RGBX/BGRX
- * buffer layout, while still describing the general format in a
- * layout-independent manner. While called RGB, it can be
- * used to describe formats with either color ordering and optional
- * padding, as well as whole planar layout.
- *
- * This format is currently only used by SW readable buffers
- * produced by MediaCodecs, so the gralloc module can ignore this format.
- */
- HAL_PIXEL_FORMAT_FLEX_RGB_888 = 0x29,
-
- /*
- * Android flexible RGBA 8888 formats
- *
- * This format allows platforms to use an efficient RGBA/BGRA/ARGB/ABGR
- * buffer layout, while still describing the general format in a
- * layout-independent manner. While called RGBA, it can be
- * used to describe formats with any of the component orderings, as
- * well as whole planar layout.
- *
- * This format is currently only used by SW readable buffers
- * produced by MediaCodecs, so the gralloc module can ignore this format.
- */
- HAL_PIXEL_FORMAT_FLEX_RGBA_8888 = 0x2A,
-
- /* Legacy formats (deprecated), used by ImageFormat.java */
- HAL_PIXEL_FORMAT_YCbCr_422_SP = 0x10, // NV16
- HAL_PIXEL_FORMAT_YCrCb_420_SP = 0x11, // NV21
- HAL_PIXEL_FORMAT_YCbCr_422_I = 0x14, // YUY2
-} android_pixel_format_t;
-
/*
* Structure for describing YCbCr formats for consumption by applications.
* This is used with HAL_PIXEL_FORMAT_YCbCr_*_888.
@@ -622,797 +237,6 @@
#endif
};
-/**
- * Transformation definitions
- *
- * IMPORTANT NOTE:
- * HAL_TRANSFORM_ROT_90 is applied CLOCKWISE and AFTER HAL_TRANSFORM_FLIP_{H|V}.
- *
- */
-
-typedef enum android_transform {
- /* flip source image horizontally (around the vertical axis) */
- HAL_TRANSFORM_FLIP_H = 0x01,
- /* flip source image vertically (around the horizontal axis)*/
- HAL_TRANSFORM_FLIP_V = 0x02,
- /* rotate source image 90 degrees clockwise */
- HAL_TRANSFORM_ROT_90 = 0x04,
- /* rotate source image 180 degrees */
- HAL_TRANSFORM_ROT_180 = 0x03,
- /* rotate source image 270 degrees clockwise */
- HAL_TRANSFORM_ROT_270 = 0x07,
- /* don't use. see system/window.h */
- HAL_TRANSFORM_RESERVED = 0x08,
-} android_transform_t;
-
-/**
- * Dataspace Definitions
- * ======================
- *
- * Dataspace is the definition of how pixel values should be interpreted.
- *
- * For many formats, this is the colorspace of the image data, which includes
- * primaries (including white point) and the transfer characteristic function,
- * which describes both gamma curve and numeric range (within the bit depth).
- *
- * Other dataspaces include depth measurement data from a depth camera.
- *
- * A dataspace is comprised of a number of fields.
- *
- * Version
- * --------
- * The top 2 bits represent the revision of the field specification. This is
- * currently always 0.
- *
- *
- * bits 31-30 29 - 0
- * +-----+----------------------------------------------------+
- * fields | Rev | Revision specific fields |
- * +-----+----------------------------------------------------+
- *
- * Field layout for version = 0:
- * ----------------------------
- *
- * A dataspace is comprised of the following fields:
- * Standard
- * Transfer function
- * Range
- *
- * bits 31-30 29-27 26 - 22 21 - 16 15 - 0
- * +-----+-----+--------+--------+----------------------------+
- * fields | 0 |Range|Transfer|Standard| Legacy and custom |
- * +-----+-----+--------+--------+----------------------------+
- * VV RRR TTTTT SSSSSS LLLLLLLL LLLLLLLL
- *
- * If range, transfer and standard fields are all 0 (e.g. top 16 bits are
- * all zeroes), the bottom 16 bits contain either a legacy dataspace value,
- * or a custom value.
- */
-
-typedef enum android_dataspace {
- /*
- * Default-assumption data space, when not explicitly specified.
- *
- * It is safest to assume the buffer is an image with sRGB primaries and
- * encoding ranges, but the consumer and/or the producer of the data may
- * simply be using defaults. No automatic gamma transform should be
- * expected, except for a possible display gamma transform when drawn to a
- * screen.
- */
- HAL_DATASPACE_UNKNOWN = 0x0,
-
- /*
- * Arbitrary dataspace with manually defined characteristics. Definition
- * for colorspaces or other meaning must be communicated separately.
- *
- * This is used when specifying primaries, transfer characteristics,
- * etc. separately.
- *
- * A typical use case is in video encoding parameters (e.g. for H.264),
- * where a colorspace can have separately defined primaries, transfer
- * characteristics, etc.
- */
- HAL_DATASPACE_ARBITRARY = 0x1,
-
- /*
- * Color-description aspects
- *
- * The following aspects define various characteristics of the color
- * specification. These represent bitfields, so that a data space value
- * can specify each of them independently.
- */
-
- HAL_DATASPACE_STANDARD_SHIFT = 16,
-
- /*
- * Standard aspect
- *
- * Defines the chromaticity coordinates of the source primaries in terms of
- * the CIE 1931 definition of x and y specified in ISO 11664-1.
- */
- HAL_DATASPACE_STANDARD_MASK = 63 << HAL_DATASPACE_STANDARD_SHIFT, // 0x3F
-
- /*
- * Chromacity coordinates are unknown or are determined by the application.
- * Implementations shall use the following suggested standards:
- *
- * All YCbCr formats: BT709 if size is 720p or larger (since most video
- * content is letterboxed this corresponds to width is
- * 1280 or greater, or height is 720 or greater).
- * BT601_625 if size is smaller than 720p or is JPEG.
- * All RGB formats: BT709.
- *
- * For all other formats standard is undefined, and implementations should use
- * an appropriate standard for the data represented.
- */
- HAL_DATASPACE_STANDARD_UNSPECIFIED = 0 << HAL_DATASPACE_STANDARD_SHIFT,
-
- /*
- * Primaries: x y
- * green 0.300 0.600
- * blue 0.150 0.060
- * red 0.640 0.330
- * white (D65) 0.3127 0.3290
- *
- * Use the unadjusted KR = 0.2126, KB = 0.0722 luminance interpretation
- * for RGB conversion.
- */
- HAL_DATASPACE_STANDARD_BT709 = 1 << HAL_DATASPACE_STANDARD_SHIFT,
-
- /*
- * Primaries: x y
- * green 0.290 0.600
- * blue 0.150 0.060
- * red 0.640 0.330
- * white (D65) 0.3127 0.3290
- *
- * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
- * for RGB conversion from the one purely determined by the primaries
- * to minimize the color shift into RGB space that uses BT.709
- * primaries.
- */
- HAL_DATASPACE_STANDARD_BT601_625 = 2 << HAL_DATASPACE_STANDARD_SHIFT,
-
- /*
- * Primaries: x y
- * green 0.290 0.600
- * blue 0.150 0.060
- * red 0.640 0.330
- * white (D65) 0.3127 0.3290
- *
- * Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation
- * for RGB conversion.
- */
- HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED = 3 << HAL_DATASPACE_STANDARD_SHIFT,
-
- /*
- * Primaries: x y
- * green 0.310 0.595
- * blue 0.155 0.070
- * red 0.630 0.340
- * white (D65) 0.3127 0.3290
- *
- * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
- * for RGB conversion from the one purely determined by the primaries
- * to minimize the color shift into RGB space that uses BT.709
- * primaries.
- */
- HAL_DATASPACE_STANDARD_BT601_525 = 4 << HAL_DATASPACE_STANDARD_SHIFT,
-
- /*
- * Primaries: x y
- * green 0.310 0.595
- * blue 0.155 0.070
- * red 0.630 0.340
- * white (D65) 0.3127 0.3290
- *
- * Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation
- * for RGB conversion (as in SMPTE 240M).
- */
- HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED = 5 << HAL_DATASPACE_STANDARD_SHIFT,
-
- /*
- * Primaries: x y
- * green 0.170 0.797
- * blue 0.131 0.046
- * red 0.708 0.292
- * white (D65) 0.3127 0.3290
- *
- * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
- * for RGB conversion.
- */
- HAL_DATASPACE_STANDARD_BT2020 = 6 << HAL_DATASPACE_STANDARD_SHIFT,
-
- /*
- * Primaries: x y
- * green 0.170 0.797
- * blue 0.131 0.046
- * red 0.708 0.292
- * white (D65) 0.3127 0.3290
- *
- * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
- * for RGB conversion using the linear domain.
- */
- HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE = 7 << HAL_DATASPACE_STANDARD_SHIFT,
-
- /*
- * Primaries: x y
- * green 0.21 0.71
- * blue 0.14 0.08
- * red 0.67 0.33
- * white (C) 0.310 0.316
- *
- * Use the unadjusted KR = 0.30, KB = 0.11 luminance interpretation
- * for RGB conversion.
- */
- HAL_DATASPACE_STANDARD_BT470M = 8 << HAL_DATASPACE_STANDARD_SHIFT,
-
- /*
- * Primaries: x y
- * green 0.243 0.692
- * blue 0.145 0.049
- * red 0.681 0.319
- * white (C) 0.310 0.316
- *
- * Use the unadjusted KR = 0.254, KB = 0.068 luminance interpretation
- * for RGB conversion.
- */
- HAL_DATASPACE_STANDARD_FILM = 9 << HAL_DATASPACE_STANDARD_SHIFT,
-
- HAL_DATASPACE_TRANSFER_SHIFT = 22,
-
- /*
- * Transfer aspect
- *
- * Transfer characteristics are the opto-electronic transfer characteristic
- * at the source as a function of linear optical intensity (luminance).
- *
- * For digital signals, E corresponds to the recorded value. Normally, the
- * transfer function is applied in RGB space to each of the R, G and B
- * components independently. This may result in color shift that can be
- * minized by applying the transfer function in Lab space only for the L
- * component. Implementation may apply the transfer function in RGB space
- * for all pixel formats if desired.
- */
-
- HAL_DATASPACE_TRANSFER_MASK = 31 << HAL_DATASPACE_TRANSFER_SHIFT, // 0x1F
-
- /*
- * Transfer characteristics are unknown or are determined by the
- * application.
- *
- * Implementations should use the following transfer functions:
- *
- * For YCbCr formats: use HAL_DATASPACE_TRANSFER_SMPTE_170M
- * For RGB formats: use HAL_DATASPACE_TRANSFER_SRGB
- *
- * For all other formats transfer function is undefined, and implementations
- * should use an appropriate standard for the data represented.
- */
- HAL_DATASPACE_TRANSFER_UNSPECIFIED = 0 << HAL_DATASPACE_TRANSFER_SHIFT,
-
- /*
- * Transfer characteristic curve:
- * E = L
- * L - luminance of image 0 <= L <= 1 for conventional colorimetry
- * E - corresponding electrical signal
- */
- HAL_DATASPACE_TRANSFER_LINEAR = 1 << HAL_DATASPACE_TRANSFER_SHIFT,
-
- /*
- * Transfer characteristic curve:
- *
- * E = 1.055 * L^(1/2.4) - 0.055 for 0.0031308 <= L <= 1
- * = 12.92 * L for 0 <= L < 0.0031308
- * L - luminance of image 0 <= L <= 1 for conventional colorimetry
- * E - corresponding electrical signal
- */
- HAL_DATASPACE_TRANSFER_SRGB = 2 << HAL_DATASPACE_TRANSFER_SHIFT,
-
- /*
- * BT.601 525, BT.601 625, BT.709, BT.2020
- *
- * Transfer characteristic curve:
- * E = 1.099 * L ^ 0.45 - 0.099 for 0.018 <= L <= 1
- * = 4.500 * L for 0 <= L < 0.018
- * L - luminance of image 0 <= L <= 1 for conventional colorimetry
- * E - corresponding electrical signal
- */
- HAL_DATASPACE_TRANSFER_SMPTE_170M = 3 << HAL_DATASPACE_TRANSFER_SHIFT,
-
- /*
- * Assumed display gamma 2.2.
- *
- * Transfer characteristic curve:
- * E = L ^ (1/2.2)
- * L - luminance of image 0 <= L <= 1 for conventional colorimetry
- * E - corresponding electrical signal
- */
- HAL_DATASPACE_TRANSFER_GAMMA2_2 = 4 << HAL_DATASPACE_TRANSFER_SHIFT,
-
- /*
- * display gamma 2.8.
- *
- * Transfer characteristic curve:
- * E = L ^ (1/2.8)
- * L - luminance of image 0 <= L <= 1 for conventional colorimetry
- * E - corresponding electrical signal
- */
- HAL_DATASPACE_TRANSFER_GAMMA2_8 = 5 << HAL_DATASPACE_TRANSFER_SHIFT,
-
- /*
- * SMPTE ST 2084
- *
- * Transfer characteristic curve:
- * E = ((c1 + c2 * L^n) / (1 + c3 * L^n)) ^ m
- * c1 = c3 - c2 + 1 = 3424 / 4096 = 0.8359375
- * c2 = 32 * 2413 / 4096 = 18.8515625
- * c3 = 32 * 2392 / 4096 = 18.6875
- * m = 128 * 2523 / 4096 = 78.84375
- * n = 0.25 * 2610 / 4096 = 0.1593017578125
- * L - luminance of image 0 <= L <= 1 for HDR colorimetry.
- * L = 1 corresponds to 10000 cd/m2
- * E - corresponding electrical signal
- */
- HAL_DATASPACE_TRANSFER_ST2084 = 6 << HAL_DATASPACE_TRANSFER_SHIFT,
-
- /*
- * ARIB STD-B67 Hybrid Log Gamma
- *
- * Transfer characteristic curve:
- * E = r * L^0.5 for 0 <= L <= 1
- * = a * ln(L - b) + c for 1 < L
- * a = 0.17883277
- * b = 0.28466892
- * c = 0.55991073
- * r = 0.5
- * L - luminance of image 0 <= L for HDR colorimetry. L = 1 corresponds
- * to reference white level of 100 cd/m2
- * E - corresponding electrical signal
- */
- HAL_DATASPACE_TRANSFER_HLG = 7 << HAL_DATASPACE_TRANSFER_SHIFT,
-
- HAL_DATASPACE_RANGE_SHIFT = 27,
-
- /*
- * Range aspect
- *
- * Defines the range of values corresponding to the unit range of 0-1.
- * This is defined for YCbCr only, but can be expanded to RGB space.
- */
- HAL_DATASPACE_RANGE_MASK = 7 << HAL_DATASPACE_RANGE_SHIFT, // 0x7
-
- /*
- * Range is unknown or are determined by the application. Implementations
- * shall use the following suggested ranges:
- *
- * All YCbCr formats: limited range.
- * All RGB or RGBA formats (including RAW and Bayer): full range.
- * All Y formats: full range
- *
- * For all other formats range is undefined, and implementations should use
- * an appropriate range for the data represented.
- */
- HAL_DATASPACE_RANGE_UNSPECIFIED = 0 << HAL_DATASPACE_RANGE_SHIFT,
-
- /*
- * Full range uses all values for Y, Cb and Cr from
- * 0 to 2^b-1, where b is the bit depth of the color format.
- */
- HAL_DATASPACE_RANGE_FULL = 1 << HAL_DATASPACE_RANGE_SHIFT,
-
- /*
- * Limited range uses values 16/256*2^b to 235/256*2^b for Y, and
- * 1/16*2^b to 15/16*2^b for Cb, Cr, R, G and B, where b is the bit depth of
- * the color format.
- *
- * E.g. For 8-bit-depth formats:
- * Luma (Y) samples should range from 16 to 235, inclusive
- * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
- *
- * For 10-bit-depth formats:
- * Luma (Y) samples should range from 64 to 940, inclusive
- * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
- */
- HAL_DATASPACE_RANGE_LIMITED = 2 << HAL_DATASPACE_RANGE_SHIFT,
-
- /*
- * Legacy dataspaces
- */
-
- /*
- * sRGB linear encoding:
- *
- * The red, green, and blue components are stored in sRGB space, but
- * are linear, not gamma-encoded.
- * The RGB primaries and the white point are the same as BT.709.
- *
- * The values are encoded using the full range ([0,255] for 8-bit) for all
- * components.
- */
- HAL_DATASPACE_SRGB_LINEAR = 0x200, // deprecated, use HAL_DATASPACE_V0_SRGB_LINEAR
-
- HAL_DATASPACE_V0_SRGB_LINEAR = HAL_DATASPACE_STANDARD_BT709 |
- HAL_DATASPACE_TRANSFER_LINEAR | HAL_DATASPACE_RANGE_FULL,
-
-
- /*
- * sRGB gamma encoding:
- *
- * The red, green and blue components are stored in sRGB space, and
- * converted to linear space when read, using the SRGB transfer function
- * for each of the R, G and B components. When written, the inverse
- * transformation is performed.
- *
- * The alpha component, if present, is always stored in linear space and
- * is left unmodified when read or written.
- *
- * Use full range and BT.709 standard.
- */
- HAL_DATASPACE_SRGB = 0x201, // deprecated, use HAL_DATASPACE_V0_SRGB
-
- HAL_DATASPACE_V0_SRGB = HAL_DATASPACE_STANDARD_BT709 |
- HAL_DATASPACE_TRANSFER_SRGB | HAL_DATASPACE_RANGE_FULL,
-
-
- /*
- * YCbCr Colorspaces
- * -----------------
- *
- * Primaries are given using (x,y) coordinates in the CIE 1931 definition
- * of x and y specified by ISO 11664-1.
- *
- * Transfer characteristics are the opto-electronic transfer characteristic
- * at the source as a function of linear optical intensity (luminance).
- */
-
- /*
- * JPEG File Interchange Format (JFIF)
- *
- * Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255
- *
- * Use full range, BT.601 transfer and BT.601_625 standard.
- */
- HAL_DATASPACE_JFIF = 0x101, // deprecated, use HAL_DATASPACE_V0_JFIF
-
- HAL_DATASPACE_V0_JFIF = HAL_DATASPACE_STANDARD_BT601_625 |
- HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_FULL,
-
- /*
- * ITU-R Recommendation 601 (BT.601) - 625-line
- *
- * Standard-definition television, 625 Lines (PAL)
- *
- * Use limited range, BT.601 transfer and BT.601_625 standard.
- */
- HAL_DATASPACE_BT601_625 = 0x102, // deprecated, use HAL_DATASPACE_V0_BT601_625
-
- HAL_DATASPACE_V0_BT601_625 = HAL_DATASPACE_STANDARD_BT601_625 |
- HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_LIMITED,
-
-
- /*
- * ITU-R Recommendation 601 (BT.601) - 525-line
- *
- * Standard-definition television, 525 Lines (NTSC)
- *
- * Use limited range, BT.601 transfer and BT.601_525 standard.
- */
- HAL_DATASPACE_BT601_525 = 0x103, // deprecated, use HAL_DATASPACE_V0_BT601_525
-
- HAL_DATASPACE_V0_BT601_525 = HAL_DATASPACE_STANDARD_BT601_525 |
- HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_LIMITED,
-
- /*
- * ITU-R Recommendation 709 (BT.709)
- *
- * High-definition television
- *
- * Use limited range, BT.709 transfer and BT.709 standard.
- */
- HAL_DATASPACE_BT709 = 0x104, // deprecated, use HAL_DATASPACE_V0_BT709
-
- HAL_DATASPACE_V0_BT709 = HAL_DATASPACE_STANDARD_BT709 |
- HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_LIMITED,
-
- /*
- * Data spaces for non-color formats
- */
-
- /*
- * The buffer contains depth ranging measurements from a depth camera.
- * This value is valid with formats:
- * HAL_PIXEL_FORMAT_Y16: 16-bit samples, consisting of a depth measurement
- * and an associated confidence value. The 3 MSBs of the sample make
- * up the confidence value, and the low 13 LSBs of the sample make up
- * the depth measurement.
- * For the confidence section, 0 means 100% confidence, 1 means 0%
- * confidence. The mapping to a linear float confidence value between
- * 0.f and 1.f can be obtained with
- * float confidence = (((depthSample >> 13) - 1) & 0x7) / 7.0f;
- * The depth measurement can be extracted simply with
- * uint16_t range = (depthSample & 0x1FFF);
- * HAL_PIXEL_FORMAT_BLOB: A depth point cloud, as
- * a variable-length float (x,y,z, confidence) coordinate point list.
- * The point cloud will be represented with the android_depth_points
- * structure.
- */
- HAL_DATASPACE_DEPTH = 0x1000
-
-} android_dataspace_t;
-
-/*
- * Color modes that may be supported by a display.
- *
- * Definitions:
- * Rendering intent generally defines the goal in mapping a source (input)
- * color to a destination device color for a given color mode.
- *
- * It is important to keep in mind three cases where mapping may be applied:
- * 1. The source gamut is much smaller than the destination (display) gamut
- * 2. The source gamut is much larger than the destination gamut (this will
- * ordinarily be handled using colorimetric rendering, below)
- * 3. The source and destination gamuts are roughly equal, although not
- * completely overlapping
- * Also, a common requirement for mappings is that skin tones should be
- * preserved, or at least remain natural in appearance.
- *
- * Colorimetric Rendering Intent (All cases):
- * Colorimetric indicates that colors should be preserved. In the case
- * that the source gamut lies wholly within the destination gamut or is
- * about the same (#1, #3), this will simply mean that no manipulations
- * (no saturation boost, for example) are applied. In the case where some
- * source colors lie outside the destination gamut (#2, #3), those will
- * need to be mapped to colors that are within the destination gamut,
- * while the already in-gamut colors remain unchanged.
- *
- * Non-colorimetric transforms can take many forms. There are no hard
- * rules and it's left to the implementation to define.
- * Two common intents are described below.
- *
- * Stretched-Gamut Enhancement Intent (Source < Destination):
- * When the destination gamut is much larger than the source gamut (#1), the
- * source primaries may be redefined to reflect the full extent of the
- * destination space, or to reflect an intermediate gamut.
- * Skin-tone preservation would likely be applied. An example might be sRGB
- * input displayed on a DCI-P3 capable device, with skin-tone preservation.
- *
- * Within-Gamut Enhancement Intent (Source >= Destination):
- * When the device (destination) gamut is not larger than the source gamut
- * (#2 or #3), but the appearance of a larger gamut is desired, techniques
- * such as saturation boost may be applied to the source colors. Skin-tone
- * preservation may be applied. There is no unique method for within-gamut
- * enhancement; it would be defined within a flexible color mode.
- *
- */
-typedef enum android_color_mode {
-
- /*
- * HAL_COLOR_MODE_DEFAULT is the "native" gamut of the display.
- * White Point: Vendor/OEM defined
- * Panel Gamma: Vendor/OEM defined (typically 2.2)
- * Rendering Intent: Vendor/OEM defined (typically 'enhanced')
- */
- HAL_COLOR_MODE_NATIVE = 0,
-
- /*
- * HAL_COLOR_MODE_STANDARD_BT601_625 corresponds with display
- * settings that implement the ITU-R Recommendation BT.601
- * or Rec 601. Using 625 line version
- * Rendering Intent: Colorimetric
- * Primaries:
- * x y
- * green 0.290 0.600
- * blue 0.150 0.060
- * red 0.640 0.330
- * white (D65) 0.3127 0.3290
- *
- * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
- * for RGB conversion from the one purely determined by the primaries
- * to minimize the color shift into RGB space that uses BT.709
- * primaries.
- *
- * Gamma Correction (GC):
- *
- * if Vlinear < 0.018
- * Vnonlinear = 4.500 * Vlinear
- * else
- * Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
- */
- HAL_COLOR_MODE_STANDARD_BT601_625 = 1,
-
- /*
- * Primaries:
- * x y
- * green 0.290 0.600
- * blue 0.150 0.060
- * red 0.640 0.330
- * white (D65) 0.3127 0.3290
- *
- * Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation
- * for RGB conversion.
- *
- * Gamma Correction (GC):
- *
- * if Vlinear < 0.018
- * Vnonlinear = 4.500 * Vlinear
- * else
- * Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
- */
- HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED = 2,
-
- /*
- * Primaries:
- * x y
- * green 0.310 0.595
- * blue 0.155 0.070
- * red 0.630 0.340
- * white (D65) 0.3127 0.3290
- *
- * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
- * for RGB conversion from the one purely determined by the primaries
- * to minimize the color shift into RGB space that uses BT.709
- * primaries.
- *
- * Gamma Correction (GC):
- *
- * if Vlinear < 0.018
- * Vnonlinear = 4.500 * Vlinear
- * else
- * Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
- */
- HAL_COLOR_MODE_STANDARD_BT601_525 = 3,
-
- /*
- * Primaries:
- * x y
- * green 0.310 0.595
- * blue 0.155 0.070
- * red 0.630 0.340
- * white (D65) 0.3127 0.3290
- *
- * Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation
- * for RGB conversion (as in SMPTE 240M).
- *
- * Gamma Correction (GC):
- *
- * if Vlinear < 0.018
- * Vnonlinear = 4.500 * Vlinear
- * else
- * Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
- */
- HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED = 4,
-
- /*
- * HAL_COLOR_MODE_REC709 corresponds with display settings that implement
- * the ITU-R Recommendation BT.709 / Rec. 709 for high-definition television.
- * Rendering Intent: Colorimetric
- * Primaries:
- * x y
- * green 0.300 0.600
- * blue 0.150 0.060
- * red 0.640 0.330
- * white (D65) 0.3127 0.3290
- *
- * HDTV REC709 Inverse Gamma Correction (IGC): V represents normalized
- * (with [0 to 1] range) value of R, G, or B.
- *
- * if Vnonlinear < 0.081
- * Vlinear = Vnonlinear / 4.5
- * else
- * Vlinear = ((Vnonlinear + 0.099) / 1.099) ^ (1/0.45)
- *
- * HDTV REC709 Gamma Correction (GC):
- *
- * if Vlinear < 0.018
- * Vnonlinear = 4.5 * Vlinear
- * else
- * Vnonlinear = 1.099 * (Vlinear) ^ 0.45 – 0.099
- */
- HAL_COLOR_MODE_STANDARD_BT709 = 5,
-
- /*
- * HAL_COLOR_MODE_DCI_P3 corresponds with display settings that implement
- * SMPTE EG 432-1 and SMPTE RP 431-2
- * Rendering Intent: Colorimetric
- * Primaries:
- * x y
- * green 0.265 0.690
- * blue 0.150 0.060
- * red 0.680 0.320
- * white (D65) 0.3127 0.3290
- *
- * Gamma: 2.2
- */
- HAL_COLOR_MODE_DCI_P3 = 6,
-
- /*
- * HAL_COLOR_MODE_SRGB corresponds with display settings that implement
- * the sRGB color space. Uses the same primaries as ITU-R Recommendation
- * BT.709
- * Rendering Intent: Colorimetric
- * Primaries:
- * x y
- * green 0.300 0.600
- * blue 0.150 0.060
- * red 0.640 0.330
- * white (D65) 0.3127 0.3290
- *
- * PC/Internet (sRGB) Inverse Gamma Correction (IGC):
- *
- * if Vnonlinear ≤ 0.03928
- * Vlinear = Vnonlinear / 12.92
- * else
- * Vlinear = ((Vnonlinear + 0.055)/1.055) ^ 2.4
- *
- * PC/Internet (sRGB) Gamma Correction (GC):
- *
- * if Vlinear ≤ 0.0031308
- * Vnonlinear = 12.92 * Vlinear
- * else
- * Vnonlinear = 1.055 * (Vlinear)^(1/2.4) – 0.055
- */
- HAL_COLOR_MODE_SRGB = 7,
-
- /*
- * HAL_COLOR_MODE_ADOBE_RGB corresponds with the RGB color space developed
- * by Adobe Systems, Inc. in 1998.
- * Rendering Intent: Colorimetric
- * Primaries:
- * x y
- * green 0.210 0.710
- * blue 0.150 0.060
- * red 0.640 0.330
- * white (D65) 0.3127 0.3290
- *
- * Gamma: 2.2
- */
- HAL_COLOR_MODE_ADOBE_RGB = 8
-
-} android_color_mode_t;
-
-/*
- * Color transforms that may be applied by hardware composer to the whole
- * display.
- */
-typedef enum android_color_transform {
- /* Applies no transform to the output color */
- HAL_COLOR_TRANSFORM_IDENTITY = 0,
-
- /* Applies an arbitrary transform defined by a 4x4 affine matrix */
- HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX = 1,
-
- /* Applies a transform that inverts the value or luminance of the color, but
- * does not modify hue or saturation */
- HAL_COLOR_TRANSFORM_VALUE_INVERSE = 2,
-
- /* Applies a transform that maps all colors to shades of gray */
- HAL_COLOR_TRANSFORM_GRAYSCALE = 3,
-
- /* Applies a transform which corrects for protanopic color blindness */
- HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA = 4,
-
- /* Applies a transform which corrects for deuteranopic color blindness */
- HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA = 5,
-
- /* Applies a transform which corrects for tritanopic color blindness */
- HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA = 6
-} android_color_transform_t;
-
-/*
- * Supported HDR formats. Must be kept in sync with equivalents in Display.java.
- */
-typedef enum android_hdr {
- /* Device supports Dolby Vision HDR */
- HAL_HDR_DOLBY_VISION = 1,
-
- /* Device supports HDR10 */
- HAL_HDR_HDR10 = 2,
-
- /* Device supports hybrid log-gamma HDR */
- HAL_HDR_HLG = 3
-} android_hdr_t;
-
#ifdef __cplusplus
}
#endif
diff --git a/include/system/radio.h b/include/system/radio.h
index 36e2188..ea77bdd 100644
--- a/include/system/radio.h
+++ b/include/system/radio.h
@@ -81,7 +81,7 @@
} radio_direction_t;
/* unique handle allocated to a radio module */
-typedef unsigned int radio_handle_t;
+typedef uint32_t radio_handle_t;
/* Opaque meta data structure used by radio meta data API (see system/radio_metadata.h) */
typedef struct radio_medtadata radio_metadata_t;
@@ -109,10 +109,10 @@
typedef struct radio_hal_band_config {
radio_band_t type;
bool antenna_connected;
- unsigned int lower_limit;
- unsigned int upper_limit;
- unsigned int num_spacings;
- unsigned int spacings[RADIO_NUM_SPACINGS_MAX];
+ uint32_t lower_limit;
+ uint32_t upper_limit;
+ uint32_t num_spacings;
+ uint32_t spacings[RADIO_NUM_SPACINGS_MAX];
union {
radio_hal_fm_band_config_t fm;
radio_hal_am_band_config_t am;
@@ -137,10 +137,10 @@
char product[RADIO_STRING_LEN_MAX]; /* product name */
char version[RADIO_STRING_LEN_MAX]; /* product version */
char serial[RADIO_STRING_LEN_MAX]; /* serial number (for subscription services) */
- unsigned int num_tuners; /* number of tuners controllable independently */
- unsigned int num_audio_sources; /* number of audio sources driven simultaneously */
+ uint32_t num_tuners; /* number of tuners controllable independently */
+ uint32_t num_audio_sources; /* number of audio sources driven simultaneously */
bool supports_capture; /* the hardware supports capture of audio source audio HAL */
- unsigned int num_bands; /* number of band descriptors */
+ uint32_t num_bands; /* number of band descriptors */
radio_hal_band_config_t bands[RADIO_NUM_BANDS_MAX]; /* band descriptors */
} radio_hal_properties_t;
@@ -153,10 +153,10 @@
char product[RADIO_STRING_LEN_MAX];
char version[RADIO_STRING_LEN_MAX];
char serial[RADIO_STRING_LEN_MAX];
- unsigned int num_tuners;
- unsigned int num_audio_sources;
+ uint32_t num_tuners;
+ uint32_t num_audio_sources;
bool supports_capture;
- unsigned int num_bands;
+ uint32_t num_bands;
radio_band_config_t bands[RADIO_NUM_BANDS_MAX];
} radio_properties_t;
@@ -164,12 +164,12 @@
* Contains information on currently tuned channel.
*/
typedef struct radio_program_info {
- unsigned int channel; /* current channel. (e.g kHz for band type RADIO_BAND_FM) */
- unsigned int sub_channel; /* current sub channel. (used for RADIO_BAND_FM_HD) */
+ uint32_t channel; /* current channel. (e.g kHz for band type RADIO_BAND_FM) */
+ uint32_t sub_channel; /* current sub channel. (used for RADIO_BAND_FM_HD) */
bool tuned; /* tuned to a program or not */
bool stereo; /* program is stereo or not */
bool digital; /* digital program or not (e.g HD Radio program) */
- unsigned int signal_strength; /* signal strength from 0 to 100 */
+ uint32_t signal_strength; /* signal strength from 0 to 100 */
/* meta data (e.g PTY, song title ...), must not be NULL */
__attribute__((aligned(8))) radio_metadata_t *metadata;
} radio_program_info_t;
@@ -196,7 +196,7 @@
/* Event passed to the framework by the HAL callback */
typedef struct radio_hal_event {
radio_event_type_t type; /* event type */
- int status; /* used by RADIO_EVENT_CONFIG, RADIO_EVENT_TUNED */
+ int32_t status; /* used by RADIO_EVENT_CONFIG, RADIO_EVENT_TUNED */
union {
/* RADIO_EVENT_ANTENNA, RADIO_EVENT_TA, RADIO_EVENT_EA */
bool on;
@@ -209,12 +209,13 @@
/* Used internally by the framework. Same information as in struct radio_hal_event */
typedef struct radio_event {
radio_event_type_t type;
- int status;
+ int32_t status;
union {
bool on;
radio_band_config_t config;
radio_program_info_t info;
- radio_metadata_t *metadata; /* offset from start of struct when in shared memory */
+ /* meta data (e.g PTY, song title ...), must not be NULL */
+ __attribute__((aligned(8))) radio_metadata_t *metadata;
};
} radio_event_t;
diff --git a/include/system/window.h b/include/system/window.h
index f439705..abd3282 100644
--- a/include/system/window.h
+++ b/include/system/window.h
@@ -121,8 +121,9 @@
int stride;
int format;
int usage;
+ uintptr_t layerCount;
- void* reserved[2];
+ void* reserved[1];
buffer_handle_t handle;
@@ -297,6 +298,25 @@
* Returns the duration of the last queueBuffer call in microseconds
*/
NATIVE_WINDOW_LAST_QUEUE_DURATION = 15,
+
+ /*
+ * Returns the number of image layers that the ANativeWindow buffer
+ * contains. By default this is 1, unless a buffer is explicitly allocated
+ * to contain multiple layers.
+ */
+ NATIVE_WINDOW_LAYER_COUNT = 16,
+
+ /*
+ * Returns 1 if NATIVE_WINDOW_GET_FRAME_TIMESTAMPS will return display
+ * present info, 0 if it won't.
+ */
+ NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT = 17,
+
+ /*
+ * Returns 1 if NATIVE_WINDOW_GET_FRAME_TIMESTAMPS will return display
+ * retire info, 0 if it won't.
+ */
+ NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_RETIRE = 18,
};
/* Valid operations for the (*perform)() hook.
@@ -333,7 +353,8 @@
NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */
NATIVE_WINDOW_SET_SHARED_BUFFER_MODE = 21,
NATIVE_WINDOW_SET_AUTO_REFRESH = 22,
- NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 23,
+ NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS = 23,
+ NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 24,
};
/* parameter for NATIVE_WINDOW_[API_][DIS]CONNECT */
@@ -996,15 +1017,24 @@
return window->perform(window, NATIVE_WINDOW_SET_AUTO_REFRESH, autoRefresh);
}
+static inline int native_window_enable_frame_timestamps(
+ struct ANativeWindow* window, bool enable)
+{
+ return window->perform(window, NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS,
+ enable);
+}
+
static inline int native_window_get_frame_timestamps(
struct ANativeWindow* window, uint32_t framesAgo,
- int64_t* outPostedTime, int64_t* outAcquireTime,
+ int64_t* outRequestedPresentTime, int64_t* outAcquireTime,
int64_t* outRefreshStartTime, int64_t* outGlCompositionDoneTime,
- int64_t* outDisplayRetireTime, int64_t* outReleaseTime)
+ int64_t* outDisplayPresentTime, int64_t* outDisplayRetireTime,
+ int64_t* outReleaseTime)
{
return window->perform(window, NATIVE_WINDOW_GET_FRAME_TIMESTAMPS,
- framesAgo, outPostedTime, outAcquireTime, outRefreshStartTime,
- outGlCompositionDoneTime, outDisplayRetireTime, outReleaseTime);
+ framesAgo, outRequestedPresentTime, outAcquireTime,
+ outRefreshStartTime, outGlCompositionDoneTime,
+ outDisplayPresentTime, outDisplayRetireTime, outReleaseTime);
}
diff --git a/include/utils/SortedVector.h b/include/utils/SortedVector.h
index 86f3496..d57465d 100644
--- a/include/utils/SortedVector.h
+++ b/include/utils/SortedVector.h
@@ -37,18 +37,18 @@
public:
typedef TYPE value_type;
-
- /*!
+
+ /*!
* Constructors and destructors
*/
-
+
SortedVector();
SortedVector(const SortedVector<TYPE>& rhs);
virtual ~SortedVector();
/*! copy operator */
- const SortedVector<TYPE>& operator = (const SortedVector<TYPE>& rhs) const;
- SortedVector<TYPE>& operator = (const SortedVector<TYPE>& rhs);
+ const SortedVector<TYPE>& operator = (const SortedVector<TYPE>& rhs) const;
+ SortedVector<TYPE>& operator = (const SortedVector<TYPE>& rhs);
/*
* empty the vector
@@ -56,7 +56,7 @@
inline void clear() { VectorImpl::clear(); }
- /*!
+ /*!
* vector stats
*/
@@ -69,11 +69,11 @@
//! sets the capacity. capacity can never be reduced less than size()
inline ssize_t setCapacity(size_t size) { return VectorImpl::setCapacity(size); }
- /*!
+ /*!
* C-style array access
*/
-
- //! read-only C-style access
+
+ //! read-only C-style access
inline const TYPE* array() const;
//! read-write C-style access. BE VERY CAREFUL when modifying the array
@@ -82,12 +82,12 @@
//! finds the index of an item
ssize_t indexOf(const TYPE& item) const;
-
+
//! finds where this item should be inserted
size_t orderOf(const TYPE& item) const;
-
-
- /*!
+
+
+ /*!
* accessors
*/
@@ -104,7 +104,7 @@
//! add an item in the right place (and replace the one that is there)
ssize_t add(const TYPE& item);
-
+
//! editItemAt() MUST NOT change the order of this item
TYPE& editItemAt(size_t index) {
return *( static_cast<TYPE *>(VectorImpl::editItemLocation(index)) );
@@ -113,7 +113,7 @@
//! merges a vector into this one
ssize_t merge(const Vector<TYPE>& vector);
ssize_t merge(const SortedVector<TYPE>& vector);
-
+
//! removes an item
ssize_t remove(const TYPE&);
@@ -121,7 +121,24 @@
inline ssize_t removeItemsAt(size_t index, size_t count = 1);
//! remove one item
inline ssize_t removeAt(size_t index) { return removeItemsAt(index); }
-
+
+ /*
+ * these inlines add some level of compatibility with STL.
+ */
+ typedef TYPE* iterator;
+ typedef TYPE const* const_iterator;
+
+ inline iterator begin() { return editArray(); }
+ inline iterator end() { return editArray() + size(); }
+ inline const_iterator begin() const { return array(); }
+ inline const_iterator end() const { return array() + size(); }
+ inline void reserve(size_t n) { setCapacity(n); }
+ inline bool empty() const{ return isEmpty(); }
+ inline iterator erase(iterator pos) {
+ ssize_t index = removeItemsAt(pos-array());
+ return begin() + index;
+ }
+
protected:
virtual void do_construct(void* storage, size_t num) const;
virtual void do_destroy(void* storage, size_t num) const;
@@ -159,13 +176,13 @@
template<class TYPE> inline
SortedVector<TYPE>& SortedVector<TYPE>::operator = (const SortedVector<TYPE>& rhs) {
SortedVectorImpl::operator = (rhs);
- return *this;
+ return *this;
}
template<class TYPE> inline
const SortedVector<TYPE>& SortedVector<TYPE>::operator = (const SortedVector<TYPE>& rhs) const {
SortedVectorImpl::operator = (rhs);
- return *this;
+ return *this;
}
template<class TYPE> inline
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 6155d16..dddb289 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -149,9 +149,14 @@
"system/bin/run-as" },
{ 00700, AID_SYSTEM, AID_SHELL, CAP_MASK_LONG(CAP_BLOCK_SUSPEND),
"system/bin/inputflinger" },
+ { 00750, AID_SYSTEM, AID_SHELL, CAP_MASK_LONG(CAP_SETUID) |
+ CAP_MASK_LONG(CAP_SETGID) |
+ CAP_MASK_LONG(CAP_SYS_PTRACE),
+ "system/bin/storaged" },
/* Support FIFO scheduling mode in SurfaceFlinger. */
- { 00755, AID_SYSTEM, AID_GRAPHICS, CAP_MASK_LONG(CAP_SYS_NICE), "system/bin/surfaceflinger" },
+ { 00755, AID_SYSTEM, AID_GRAPHICS, CAP_MASK_LONG(CAP_SYS_NICE),
+ "system/bin/surfaceflinger" },
/* Support hostapd administering a network interface. */
{ 00755, AID_WIFI, AID_WIFI, CAP_MASK_LONG(CAP_NET_ADMIN) |
diff --git a/libmemtrack/Android.bp b/libmemtrack/Android.bp
index 98413dd..68c580a 100644
--- a/libmemtrack/Android.bp
+++ b/libmemtrack/Android.bp
@@ -2,13 +2,19 @@
cc_library_shared {
name: "libmemtrack",
- srcs: ["memtrack.c"],
+ srcs: ["memtrack.cpp"],
export_include_dirs: ["include"],
local_include_dirs: ["include"],
include_dirs: ["hardware/libhardware/include"],
shared_libs: [
"libhardware",
"liblog",
+ "libbase",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hardware.memtrack@1.0",
],
cflags: [
"-Wall",
diff --git a/libmemtrack/include/memtrack/memtrack.h b/libmemtrack/include/memtrack/memtrack.h
index 8c0ab89..2134a6f 100644
--- a/libmemtrack/include/memtrack/memtrack.h
+++ b/libmemtrack/include/memtrack/memtrack.h
@@ -35,16 +35,6 @@
struct memtrack_proc;
/**
- * memtrack_init
- *
- * Must be called once before calling any other functions. After this function
- * is called, everything else is thread-safe.
- *
- * Returns 0 on success, -errno on error.
- */
-int memtrack_init(void);
-
-/**
* memtrack_proc_new
*
* Return a new handle to hold process memory stats.
diff --git a/libmemtrack/memtrack.c b/libmemtrack/memtrack.c
deleted file mode 100644
index 29cc92c..0000000
--- a/libmemtrack/memtrack.c
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "memtrack"
-
-#include <memtrack/memtrack.h>
-
-#include <errno.h>
-#include <malloc.h>
-#include <string.h>
-
-#include <android/log.h>
-#include <hardware/memtrack.h>
-
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
-
-static const memtrack_module_t *module;
-
-struct memtrack_proc {
- pid_t pid;
- struct memtrack_proc_type {
- enum memtrack_type type;
- size_t num_records;
- size_t allocated_records;
- struct memtrack_record *records;
- } types[MEMTRACK_NUM_TYPES];
-};
-
-int memtrack_init(void)
-{
- int err;
-
- if (module) {
- return 0;
- }
-
- err = hw_get_module(MEMTRACK_HARDWARE_MODULE_ID,
- (hw_module_t const**)&module);
- if (err) {
- ALOGE("Couldn't load %s module (%s)", MEMTRACK_HARDWARE_MODULE_ID,
- strerror(-err));
- return err;
- }
-
- return module->init(module);
-}
-
-struct memtrack_proc *memtrack_proc_new(void)
-{
- if (!module) {
- return NULL;
- }
-
- return calloc(sizeof(struct memtrack_proc), 1);
-}
-
-void memtrack_proc_destroy(struct memtrack_proc *p)
-{
- enum memtrack_type i;
-
- if (p) {
- for (i = 0; i < MEMTRACK_NUM_TYPES; i++) {
- free(p->types[i].records);
- }
- }
- free(p);
-}
-
-static int memtrack_proc_get_type(struct memtrack_proc_type *t,
- pid_t pid, enum memtrack_type type)
-{
- size_t num_records = t->num_records;
- int ret;
-
-retry:
- ret = module->getMemory(module, pid, type, t->records, &num_records);
- if (ret) {
- t->num_records = 0;
- return ret;
- }
- if (num_records > t->allocated_records) {
- /* Need more records than allocated */
- free(t->records);
- t->records = calloc(sizeof(*t->records), num_records);
- if (!t->records) {
- return -ENOMEM;
- }
- t->allocated_records = num_records;
- goto retry;
- }
- t->num_records = num_records;
-
- return 0;
-}
-
-/* TODO: sanity checks on return values from HALs:
- * make sure no records have invalid flags set
- * - unknown flags
- * - too many flags of a single category
- * - missing ACCOUNTED/UNACCOUNTED
- * make sure there are not overlapping SHARED and SHARED_PSS records
- */
-static int memtrack_proc_sanity_check(struct memtrack_proc *p)
-{
- (void)p;
- return 0;
-}
-
-int memtrack_proc_get(struct memtrack_proc *p, pid_t pid)
-{
- enum memtrack_type i;
-
- if (!module) {
- return -EINVAL;
- }
-
- if (!p) {
- return -EINVAL;
- }
-
- p->pid = pid;
- for (i = 0; i < MEMTRACK_NUM_TYPES; i++) {
- memtrack_proc_get_type(&p->types[i], pid, i);
- }
-
- return memtrack_proc_sanity_check(p);
-}
-
-static ssize_t memtrack_proc_sum(struct memtrack_proc *p,
- enum memtrack_type types[], size_t num_types,
- unsigned int flags)
-{
- ssize_t sum = 0;
- size_t i;
- size_t j;
-
- for (i = 0; i < num_types; i++) {
- enum memtrack_type type = types[i];
- for (j = 0; j < p->types[type].num_records; j++) {
- if ((p->types[type].records[j].flags & flags) == flags) {
- sum += p->types[type].records[j].size_in_bytes;
- }
- }
- }
-
- return sum;
-}
-
-ssize_t memtrack_proc_graphics_total(struct memtrack_proc *p)
-{
- enum memtrack_type types[] = { MEMTRACK_TYPE_GRAPHICS };
- return memtrack_proc_sum(p, types, ARRAY_SIZE(types), 0);
-}
-
-ssize_t memtrack_proc_graphics_pss(struct memtrack_proc *p)
-{
- enum memtrack_type types[] = { MEMTRACK_TYPE_GRAPHICS };
- return memtrack_proc_sum(p, types, ARRAY_SIZE(types),
- MEMTRACK_FLAG_SMAPS_UNACCOUNTED);
-}
-
-ssize_t memtrack_proc_gl_total(struct memtrack_proc *p)
-{
- enum memtrack_type types[] = { MEMTRACK_TYPE_GL };
- return memtrack_proc_sum(p, types, ARRAY_SIZE(types), 0);
-}
-
-ssize_t memtrack_proc_gl_pss(struct memtrack_proc *p)
-{
- enum memtrack_type types[] = { MEMTRACK_TYPE_GL };
- return memtrack_proc_sum(p, types, ARRAY_SIZE(types),
- MEMTRACK_FLAG_SMAPS_UNACCOUNTED);
-}
-
-ssize_t memtrack_proc_other_total(struct memtrack_proc *p)
-{
- enum memtrack_type types[] = { MEMTRACK_TYPE_MULTIMEDIA,
- MEMTRACK_TYPE_CAMERA,
- MEMTRACK_TYPE_OTHER };
- return memtrack_proc_sum(p, types, ARRAY_SIZE(types), 0);
-}
-
-ssize_t memtrack_proc_other_pss(struct memtrack_proc *p)
-{
- enum memtrack_type types[] = { MEMTRACK_TYPE_MULTIMEDIA,
- MEMTRACK_TYPE_CAMERA,
- MEMTRACK_TYPE_OTHER };
- return memtrack_proc_sum(p, types, ARRAY_SIZE(types),
- MEMTRACK_FLAG_SMAPS_UNACCOUNTED);
-}
diff --git a/libmemtrack/memtrack.cpp b/libmemtrack/memtrack.cpp
new file mode 100644
index 0000000..1b38925
--- /dev/null
+++ b/libmemtrack/memtrack.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "memtrack"
+#include <android/hardware/memtrack/1.0/IMemtrack.h>
+#include <memtrack/memtrack.h>
+
+#include <errno.h>
+#include <malloc.h>
+#include <vector>
+#include <string.h>
+#include <mutex>
+
+#include <android/log.h>
+
+using android::hardware::memtrack::V1_0::IMemtrack;
+using android::hardware::memtrack::V1_0::MemtrackType;
+using android::hardware::memtrack::V1_0::MemtrackRecord;
+using android::hardware::memtrack::V1_0::MemtrackFlag;
+using android::hardware::memtrack::V1_0::MemtrackStatus;
+using android::hardware::hidl_vec;
+
+struct memtrack_proc_type {
+ MemtrackType type;
+ std::vector<MemtrackRecord> records;
+};
+
+struct memtrack_proc {
+ pid_t pid;
+ memtrack_proc_type types[static_cast<int>(MemtrackType::NUM_TYPES)];
+};
+
+//TODO(b/31632518)
+static android::sp<IMemtrack> get_instance() {
+ static android::sp<IMemtrack> module = IMemtrack::getService("memtrack");
+ if (module == nullptr) {
+ ALOGE("Couldn't load memtrack module");
+ }
+ return module;
+}
+
+memtrack_proc *memtrack_proc_new(void)
+{
+ return new memtrack_proc();
+}
+
+void memtrack_proc_destroy(memtrack_proc *p)
+{
+ delete(p);
+}
+
+static int memtrack_proc_get_type(memtrack_proc_type *t,
+ pid_t pid, MemtrackType type)
+{
+ int err = 0;
+ android::sp<IMemtrack> memtrack = get_instance();
+ if (memtrack == nullptr)
+ return -1;
+
+ memtrack->getMemory(pid, type,
+ [&t, &err](MemtrackStatus status, hidl_vec<MemtrackRecord> records) {
+ if (status != MemtrackStatus::SUCCESS) {
+ err = -1;
+ t->records.resize(0);
+ }
+ t->records.resize(records.size());
+ for (size_t i = 0; i < records.size(); i++) {
+ t->records[i].sizeInBytes = records[i].sizeInBytes;
+ t->records[i].flags = records[i].flags;
+ }
+ });
+ return err;
+}
+
+/* TODO: sanity checks on return values from HALs:
+ * make sure no records have invalid flags set
+ * - unknown flags
+ * - too many flags of a single category
+ * - missing ACCOUNTED/UNACCOUNTED
+ * make sure there are not overlapping SHARED and SHARED_PSS records
+ */
+static int memtrack_proc_sanity_check(memtrack_proc* /*p*/)
+{
+ return 0;
+}
+
+int memtrack_proc_get(memtrack_proc *p, pid_t pid)
+{
+ if (!p) {
+ return -EINVAL;
+ }
+
+ p->pid = pid;
+ for (uint32_t i = 0; i < (uint32_t)MemtrackType::NUM_TYPES; i++) {
+ int ret = memtrack_proc_get_type(&p->types[i], pid, (MemtrackType)i);
+ if (ret != 0)
+ return ret;
+ }
+
+ return memtrack_proc_sanity_check(p);
+}
+
+static ssize_t memtrack_proc_sum(memtrack_proc *p,
+ const std::vector<MemtrackType>& types, uint32_t flags)
+{
+ ssize_t sum = 0;
+
+ for (size_t i = 0; i < types.size(); i++) {
+ memtrack_proc_type type = p->types[static_cast<int>(types[i])];
+ std::vector<MemtrackRecord> records = type.records;
+ for (size_t j = 0; j < records.size(); j++) {
+ if ((records[j].flags & flags) == flags) {
+ sum += records[j].sizeInBytes;
+ }
+ }
+ }
+
+ return sum;
+}
+
+ssize_t memtrack_proc_graphics_total(memtrack_proc *p)
+{
+ std::vector<MemtrackType> types = {MemtrackType::GRAPHICS};
+ return memtrack_proc_sum(p, types, 0);
+}
+
+ssize_t memtrack_proc_graphics_pss(memtrack_proc *p)
+{
+ std::vector<MemtrackType> types = { MemtrackType::GRAPHICS };
+ return memtrack_proc_sum(p, types,
+ (uint32_t)MemtrackFlag::SMAPS_UNACCOUNTED);
+}
+
+ssize_t memtrack_proc_gl_total(memtrack_proc *p)
+{
+ std::vector<MemtrackType> types = { MemtrackType::GL };
+ return memtrack_proc_sum(p, types, 0);
+}
+
+ssize_t memtrack_proc_gl_pss(memtrack_proc *p)
+{
+ std::vector<MemtrackType> types = { MemtrackType::GL };
+ return memtrack_proc_sum(p, types,
+ (uint32_t)MemtrackFlag::SMAPS_UNACCOUNTED);
+}
+
+ssize_t memtrack_proc_other_total(memtrack_proc *p)
+{
+ std::vector<MemtrackType> types = { MemtrackType::MULTIMEDIA,
+ MemtrackType::CAMERA, MemtrackType::OTHER };
+ return memtrack_proc_sum(p, types, 0);
+}
+
+ssize_t memtrack_proc_other_pss(memtrack_proc *p)
+{
+ std::vector<MemtrackType> types = { MemtrackType::MULTIMEDIA,
+ MemtrackType::CAMERA, MemtrackType::OTHER };
+ return memtrack_proc_sum(p, types,
+ (uint32_t)MemtrackFlag::SMAPS_UNACCOUNTED);
+}
diff --git a/libmemtrack/memtrack_test.c b/libmemtrack/memtrack_test.c
index eaadfa7..77c935e 100644
--- a/libmemtrack/memtrack_test.c
+++ b/libmemtrack/memtrack_test.c
@@ -82,12 +82,6 @@
(void)argc;
(void)argv;
- ret = memtrack_init();
- if (ret < 0) {
- fprintf(stderr, "failed to initialize HAL: %s (%d)\n", strerror(-ret), ret);
- exit(EXIT_FAILURE);
- }
-
ret = pm_kernel_create(&ker);
if (ret) {
fprintf(stderr, "Error creating kernel interface -- "
diff --git a/libsparse/simg_dump.py b/libsparse/simg_dump.py
index c70d45f..82a03ad 100755
--- a/libsparse/simg_dump.py
+++ b/libsparse/simg_dump.py
@@ -15,43 +15,64 @@
# limitations under the License.
from __future__ import print_function
-import getopt, posixpath, signal, struct, sys
+import csv
+import getopt
+import hashlib
+import posixpath
+import signal
+import struct
+import sys
+
def usage(argv0):
print("""
-Usage: %s [-v] sparse_image_file ...
+Usage: %s [-v] [-s] [-c <filename>] sparse_image_file ...
-v verbose output
-""" % ( argv0 ))
+ -s show sha1sum of data blocks
+ -c <filename> save .csv file of blocks
+""" % (argv0))
sys.exit(2)
-def main():
+def main():
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
me = posixpath.basename(sys.argv[0])
# Parse the command line
- verbose = 0 # -v
+ verbose = 0 # -v
+ showhash = 0 # -s
+ csvfilename = None # -c
try:
opts, args = getopt.getopt(sys.argv[1:],
- "v",
- ["verbose"])
+ "vsc:",
+ ["verbose", "showhash", "csvfile"])
except getopt.GetoptError, e:
print(e)
usage(me)
for o, a in opts:
if o in ("-v", "--verbose"):
verbose += 1
+ elif o in ("-s", "--showhash"):
+ showhash = True
+ elif o in ("-c", "--csvfile"):
+ csvfilename = a
else:
print("Unrecognized option \"%s\"" % (o))
usage(me)
- if len(args) == 0:
+ if not args:
print("No sparse_image_file specified")
usage(me)
+ if csvfilename:
+ csvfile = open(csvfilename, "wb")
+ csvwriter = csv.writer(csvfile)
+
+ output = verbose or csvfilename or showhash
+
for path in args:
- FH = open(path, 'rb')
+ FH = open(path, "rb")
header_bin = FH.read(28)
header = struct.unpack("<I4H4I", header_bin)
@@ -88,71 +109,99 @@
if image_checksum != 0:
print("checksum=0x%08X" % (image_checksum))
- if not verbose:
+ if not output:
continue
- print(" input_bytes output_blocks")
- print("chunk offset number offset number")
+
+ if verbose > 0:
+ print(" input_bytes output_blocks")
+ print("chunk offset number offset number")
+
+ if csvfilename:
+ csvwriter.writerow(["chunk", "input offset", "input bytes",
+ "output offset", "output blocks", "type", "hash"])
+
offset = 0
- for i in xrange(1,total_chunks+1):
+ for i in xrange(1, total_chunks + 1):
header_bin = FH.read(12)
header = struct.unpack("<2H2I", header_bin)
chunk_type = header[0]
- reserved1 = header[1]
chunk_sz = header[2]
total_sz = header[3]
data_sz = total_sz - 12
+ curhash = ""
+ curtype = ""
+ curpos = FH.tell()
- print("%4u %10u %10u %7u %7u" % (i, FH.tell(), data_sz, offset, chunk_sz),
- end=" ")
+ if verbose > 0:
+ print("%4u %10u %10u %7u %7u" % (i, curpos, data_sz, offset, chunk_sz),
+ end=" ")
if chunk_type == 0xCAC1:
if data_sz != (chunk_sz * blk_sz):
print("Raw chunk input size (%u) does not match output size (%u)"
% (data_sz, chunk_sz * blk_sz))
- break;
+ break
else:
- print("Raw data", end="")
- FH.read(data_sz)
+ curtype = "Raw data"
+ data = FH.read(data_sz)
+ if showhash:
+ h = hashlib.sha1()
+ h.update(data)
+ curhash = h.hexdigest()
elif chunk_type == 0xCAC2:
if data_sz != 4:
print("Fill chunk should have 4 bytes of fill, but this has %u"
- % (data_sz), end="")
- break;
+ % (data_sz))
+ break
else:
fill_bin = FH.read(4)
fill = struct.unpack("<I", fill_bin)
- print("Fill with 0x%08X" % (fill))
+ curtype = format("Fill with 0x%08X" % (fill))
+ if showhash:
+ h = hashlib.sha1()
+ data = fill_bin * (blk_sz / 4);
+ for block in xrange(chunk_sz):
+ h.update(data)
+ curhash = h.hexdigest()
elif chunk_type == 0xCAC3:
if data_sz != 0:
print("Don't care chunk input size is non-zero (%u)" % (data_sz))
- break;
+ break
else:
- print("Don't care", end="")
+ curtype = "Don't care"
elif chunk_type == 0xCAC4:
if data_sz != 4:
print("CRC32 chunk should have 4 bytes of CRC, but this has %u"
- % (data_sz), end="")
- break;
+ % (data_sz))
+ break
else:
crc_bin = FH.read(4)
crc = struct.unpack("<I", crc_bin)
- print("Unverified CRC32 0x%08X" % (crc))
+ curtype = format("Unverified CRC32 0x%08X" % (crc))
else:
- print("Unknown chunk type 0x%04X" % (chunk_type), end="")
- break;
+ print("Unknown chunk type 0x%04X" % (chunk_type))
+ break
- if verbose > 1:
- header = struct.unpack("<12B", header_bin)
- print(" (%02X%02X %02X%02X %02X%02X%02X%02X %02X%02X%02X%02X)"
- % (header[0], header[1], header[2], header[3],
- header[4], header[5], header[6], header[7],
- header[8], header[9], header[10], header[11]))
- else:
- print()
+ if verbose > 0:
+ print("%-18s" % (curtype), end=" ")
+
+ if verbose > 1:
+ header = struct.unpack("<12B", header_bin)
+ print(" (%02X%02X %02X%02X %02X%02X%02X%02X %02X%02X%02X%02X)"
+ % (header[0], header[1], header[2], header[3],
+ header[4], header[5], header[6], header[7],
+ header[8], header[9], header[10], header[11]), end=" ")
+
+ print(curhash)
+
+ if csvfilename:
+ csvwriter.writerow([i, curpos, data_sz, offset, chunk_sz, curtype,
+ curhash])
offset += chunk_sz
- print(" %10u %7u End" % (FH.tell(), offset))
+ if verbose > 0:
+ print(" %10u %7u End" % (FH.tell(), offset))
if total_blks != offset:
print("The header said we should have %u output blocks, but we saw %u"
@@ -163,6 +212,9 @@
print("There were %u bytes of extra data at the end of the file."
% (junk_len))
+ if csvfilename:
+ csvfile.close()
+
sys.exit(0)
if __name__ == "__main__":
diff --git a/libsuspend/Android.bp b/libsuspend/Android.bp
index d27ceea..d442c94 100644
--- a/libsuspend/Android.bp
+++ b/libsuspend/Android.bp
@@ -4,8 +4,6 @@
name: "libsuspend",
srcs: [
"autosuspend.c",
- "autosuspend_autosleep.c",
- "autosuspend_earlysuspend.c",
"autosuspend_wakeup_count.c",
],
export_include_dirs: ["include"],
diff --git a/libsuspend/autosuspend.c b/libsuspend/autosuspend.c
index 64d1bfc..2e1983a 100644
--- a/libsuspend/autosuspend.c
+++ b/libsuspend/autosuspend.c
@@ -34,19 +34,6 @@
return 0;
}
- autosuspend_ops = autosuspend_earlysuspend_init();
- if (autosuspend_ops) {
- goto out;
- }
-
-/* Remove autosleep so userspace can manager suspend/resume and keep stats */
-#if 0
- autosuspend_ops = autosuspend_autosleep_init();
- if (autosuspend_ops) {
- goto out;
- }
-#endif
-
autosuspend_ops = autosuspend_wakeup_count_init();
if (autosuspend_ops) {
goto out;
diff --git a/libsuspend/autosuspend_autosleep.c b/libsuspend/autosuspend_autosleep.c
deleted file mode 100644
index 97109ac..0000000
--- a/libsuspend/autosuspend_autosleep.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "libsuspend"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stddef.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <android/log.h>
-
-#include "autosuspend_ops.h"
-
-#define SYS_POWER_AUTOSLEEP "/sys/power/autosleep"
-
-static int autosleep_fd;
-static const char *sleep_state = "mem";
-static const char *on_state = "off";
-
-static int autosuspend_autosleep_enable(void)
-{
- char buf[80];
- int ret;
-
- ALOGV("autosuspend_autosleep_enable\n");
-
- ret = TEMP_FAILURE_RETRY(write(autosleep_fd, sleep_state, strlen(sleep_state)));
- if (ret < 0) {
- strerror_r(errno, buf, sizeof(buf));
- ALOGE("Error writing to %s: %s\n", SYS_POWER_AUTOSLEEP, buf);
- goto err;
- }
-
- ALOGV("autosuspend_autosleep_enable done\n");
-
- return 0;
-
-err:
- return ret;
-}
-
-static int autosuspend_autosleep_disable(void)
-{
- char buf[80];
- int ret;
-
- ALOGV("autosuspend_autosleep_disable\n");
-
- ret = TEMP_FAILURE_RETRY(write(autosleep_fd, on_state, strlen(on_state)));
- if (ret < 0) {
- strerror_r(errno, buf, sizeof(buf));
- ALOGE("Error writing to %s: %s\n", SYS_POWER_AUTOSLEEP, buf);
- goto err;
- }
-
- ALOGV("autosuspend_autosleep_disable done\n");
-
- return 0;
-
-err:
- return ret;
-}
-
-struct autosuspend_ops autosuspend_autosleep_ops = {
- .enable = autosuspend_autosleep_enable,
- .disable = autosuspend_autosleep_disable,
-};
-
-struct autosuspend_ops *autosuspend_autosleep_init(void)
-{
- char buf[80];
-
- autosleep_fd = TEMP_FAILURE_RETRY(open(SYS_POWER_AUTOSLEEP, O_WRONLY));
- if (autosleep_fd < 0) {
- strerror_r(errno, buf, sizeof(buf));
- ALOGE("Error opening %s: %s\n", SYS_POWER_AUTOSLEEP, buf);
- return NULL;
- }
-
- ALOGI("Selected autosleep\n");
-
- autosuspend_autosleep_disable();
-
- return &autosuspend_autosleep_ops;
-}
diff --git a/libsuspend/autosuspend_earlysuspend.c b/libsuspend/autosuspend_earlysuspend.c
deleted file mode 100644
index 9519e51..0000000
--- a/libsuspend/autosuspend_earlysuspend.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "libsuspend"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <android/log.h>
-
-#include "autosuspend_ops.h"
-
-#define EARLYSUSPEND_SYS_POWER_STATE "/sys/power/state"
-#define EARLYSUSPEND_WAIT_FOR_FB_SLEEP "/sys/power/wait_for_fb_sleep"
-#define EARLYSUSPEND_WAIT_FOR_FB_WAKE "/sys/power/wait_for_fb_wake"
-
-static int sPowerStatefd;
-static const char *pwr_state_mem = "mem";
-static const char *pwr_state_on = "on";
-static pthread_t earlysuspend_thread;
-static pthread_mutex_t earlysuspend_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t earlysuspend_cond = PTHREAD_COND_INITIALIZER;
-static bool wait_for_earlysuspend;
-static enum {
- EARLYSUSPEND_ON,
- EARLYSUSPEND_MEM,
-} earlysuspend_state = EARLYSUSPEND_ON;
-
-int wait_for_fb_wake(void)
-{
- int err = 0;
- char buf;
- int fd = TEMP_FAILURE_RETRY(open(EARLYSUSPEND_WAIT_FOR_FB_WAKE, O_RDONLY, 0));
- // if the file doesn't exist, the error will be caught in read() below
- err = TEMP_FAILURE_RETRY(read(fd, &buf, 1));
- ALOGE_IF(err < 0,
- "*** ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno));
- close(fd);
- return err < 0 ? err : 0;
-}
-
-static int wait_for_fb_sleep(void)
-{
- int err = 0;
- char buf;
- int fd = TEMP_FAILURE_RETRY(open(EARLYSUSPEND_WAIT_FOR_FB_SLEEP, O_RDONLY, 0));
- // if the file doesn't exist, the error will be caught in read() below
- err = TEMP_FAILURE_RETRY(read(fd, &buf, 1));
- ALOGE_IF(err < 0,
- "*** ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno));
- close(fd);
- return err < 0 ? err : 0;
-}
-
-static void *earlysuspend_thread_func(void __unused *arg)
-{
- while (1) {
- if (wait_for_fb_sleep()) {
- ALOGE("Failed reading wait_for_fb_sleep, exiting earlysuspend thread\n");
- return NULL;
- }
- pthread_mutex_lock(&earlysuspend_mutex);
- earlysuspend_state = EARLYSUSPEND_MEM;
- pthread_cond_signal(&earlysuspend_cond);
- pthread_mutex_unlock(&earlysuspend_mutex);
-
- if (wait_for_fb_wake()) {
- ALOGE("Failed reading wait_for_fb_wake, exiting earlysuspend thread\n");
- return NULL;
- }
- pthread_mutex_lock(&earlysuspend_mutex);
- earlysuspend_state = EARLYSUSPEND_ON;
- pthread_cond_signal(&earlysuspend_cond);
- pthread_mutex_unlock(&earlysuspend_mutex);
- }
-}
-static int autosuspend_earlysuspend_enable(void)
-{
- char buf[80];
- int ret;
-
- ALOGV("autosuspend_earlysuspend_enable\n");
-
- ret = write(sPowerStatefd, pwr_state_mem, strlen(pwr_state_mem));
- if (ret < 0) {
- strerror_r(errno, buf, sizeof(buf));
- ALOGE("Error writing to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
- goto err;
- }
-
- if (wait_for_earlysuspend) {
- pthread_mutex_lock(&earlysuspend_mutex);
- while (earlysuspend_state != EARLYSUSPEND_MEM) {
- pthread_cond_wait(&earlysuspend_cond, &earlysuspend_mutex);
- }
- pthread_mutex_unlock(&earlysuspend_mutex);
- }
-
- ALOGV("autosuspend_earlysuspend_enable done\n");
-
- return 0;
-
-err:
- return ret;
-}
-
-static int autosuspend_earlysuspend_disable(void)
-{
- char buf[80];
- int ret;
-
- ALOGV("autosuspend_earlysuspend_disable\n");
-
- ret = TEMP_FAILURE_RETRY(write(sPowerStatefd, pwr_state_on, strlen(pwr_state_on)));
- if (ret < 0) {
- strerror_r(errno, buf, sizeof(buf));
- ALOGE("Error writing to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
- goto err;
- }
-
- if (wait_for_earlysuspend) {
- pthread_mutex_lock(&earlysuspend_mutex);
- while (earlysuspend_state != EARLYSUSPEND_ON) {
- pthread_cond_wait(&earlysuspend_cond, &earlysuspend_mutex);
- }
- pthread_mutex_unlock(&earlysuspend_mutex);
- }
-
- ALOGV("autosuspend_earlysuspend_disable done\n");
-
- return 0;
-
-err:
- return ret;
-}
-
-struct autosuspend_ops autosuspend_earlysuspend_ops = {
- .enable = autosuspend_earlysuspend_enable,
- .disable = autosuspend_earlysuspend_disable,
-};
-
-void start_earlysuspend_thread(void)
-{
- char buf[80];
- int ret;
-
- ret = access(EARLYSUSPEND_WAIT_FOR_FB_SLEEP, F_OK);
- if (ret < 0) {
- return;
- }
-
- ret = access(EARLYSUSPEND_WAIT_FOR_FB_WAKE, F_OK);
- if (ret < 0) {
- return;
- }
-
- wait_for_fb_wake();
-
- ALOGI("Starting early suspend unblocker thread\n");
- ret = pthread_create(&earlysuspend_thread, NULL, earlysuspend_thread_func, NULL);
- if (ret) {
- strerror_r(errno, buf, sizeof(buf));
- ALOGE("Error creating thread: %s\n", buf);
- return;
- }
-
- wait_for_earlysuspend = true;
-}
-
-struct autosuspend_ops *autosuspend_earlysuspend_init(void)
-{
- char buf[80];
- int ret;
-
- sPowerStatefd = TEMP_FAILURE_RETRY(open(EARLYSUSPEND_SYS_POWER_STATE, O_RDWR));
-
- if (sPowerStatefd < 0) {
- strerror_r(errno, buf, sizeof(buf));
- ALOGW("Error opening %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
- return NULL;
- }
-
- ret = TEMP_FAILURE_RETRY(write(sPowerStatefd, "on", 2));
- if (ret < 0) {
- strerror_r(errno, buf, sizeof(buf));
- ALOGW("Error writing 'on' to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
- goto err_write;
- }
-
- ALOGI("Selected early suspend\n");
-
- start_earlysuspend_thread();
-
- return &autosuspend_earlysuspend_ops;
-
-err_write:
- close(sPowerStatefd);
- return NULL;
-}
diff --git a/libusbhost/include/usbhost/usbhost.h b/libusbhost/include/usbhost/usbhost.h
index 84594c8..a8dd673 100644
--- a/libusbhost/include/usbhost/usbhost.h
+++ b/libusbhost/include/usbhost/usbhost.h
@@ -144,17 +144,17 @@
* usb_device_get_product_name and usb_device_get_serial.
* Call free() to free the result when you are done with it.
*/
-char* usb_device_get_string(struct usb_device *device, int id);
+char* usb_device_get_string(struct usb_device *device, int id, int timeout);
/* Returns the manufacturer name for the USB device.
* Call free() to free the result when you are done with it.
*/
-char* usb_device_get_manufacturer_name(struct usb_device *device);
+char* usb_device_get_manufacturer_name(struct usb_device *device, int timeout);
/* Returns the product name for the USB device.
* Call free() to free the result when you are done with it.
*/
-char* usb_device_get_product_name(struct usb_device *device);
+char* usb_device_get_product_name(struct usb_device *device, int timeout);
/* Returns the version number for the USB device.
*/
@@ -163,7 +163,7 @@
/* Returns the USB serial number for the USB device.
* Call free() to free the result when you are done with it.
*/
-char* usb_device_get_serial(struct usb_device *device);
+char* usb_device_get_serial(struct usb_device *device, int timeout);
/* Returns true if we have write access to the USB device,
* and false if we only have access to the USB device configuration.
@@ -232,10 +232,11 @@
/* Submits a read or write request on the specified device */
int usb_request_queue(struct usb_request *req);
- /* Waits for the results of a previous usb_request_queue operation.
+ /* Waits for the results of a previous usb_request_queue operation. timeoutMillis == -1 requests
+ * to wait forever.
* Returns a usb_request, or NULL for error.
*/
-struct usb_request *usb_request_wait(struct usb_device *dev);
+struct usb_request *usb_request_wait(struct usb_device *dev, int timeoutMillis);
/* Cancels a pending usb_request_queue() operation. */
int usb_request_cancel(struct usb_request *req);
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index 68aca17..7adb4f2 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
// #define DEBUG 1
#if DEBUG
@@ -43,6 +47,7 @@
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
+#include <poll.h>
#include <pthread.h>
#include <linux/usbdevice_fs.h>
@@ -449,7 +454,7 @@
return (struct usb_device_descriptor*)device->desc;
}
-char* usb_device_get_string(struct usb_device *device, int id)
+char* usb_device_get_string(struct usb_device *device, int id, int timeout)
{
char string[256];
__u16 buffer[MAX_STRING_DESCRIPTOR_LENGTH / sizeof(__u16)];
@@ -465,7 +470,8 @@
// read list of supported languages
result = usb_device_control_transfer(device,
USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE, USB_REQ_GET_DESCRIPTOR,
- (USB_DT_STRING << 8) | 0, 0, languages, sizeof(languages), 0);
+ (USB_DT_STRING << 8) | 0, 0, languages, sizeof(languages),
+ timeout);
if (result > 0)
languageCount = (result - 2) / 2;
@@ -474,7 +480,8 @@
result = usb_device_control_transfer(device,
USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE, USB_REQ_GET_DESCRIPTOR,
- (USB_DT_STRING << 8) | id, languages[i], buffer, sizeof(buffer), 0);
+ (USB_DT_STRING << 8) | id, languages[i], buffer, sizeof(buffer),
+ timeout);
if (result > 0) {
int i;
// skip first word, and copy the rest to the string, changing shorts to bytes.
@@ -489,16 +496,16 @@
return NULL;
}
-char* usb_device_get_manufacturer_name(struct usb_device *device)
+char* usb_device_get_manufacturer_name(struct usb_device *device, int timeout)
{
struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
- return usb_device_get_string(device, desc->iManufacturer);
+ return usb_device_get_string(device, desc->iManufacturer, timeout);
}
-char* usb_device_get_product_name(struct usb_device *device)
+char* usb_device_get_product_name(struct usb_device *device, int timeout)
{
struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
- return usb_device_get_string(device, desc->iProduct);
+ return usb_device_get_string(device, desc->iProduct, timeout);
}
int usb_device_get_version(struct usb_device *device)
@@ -507,10 +514,10 @@
return desc->bcdUSB;
}
-char* usb_device_get_serial(struct usb_device *device)
+char* usb_device_get_serial(struct usb_device *device, int timeout)
{
struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
- return usb_device_get_string(device, desc->iSerialNumber);
+ return usb_device_get_string(device, desc->iSerialNumber, timeout);
}
int usb_device_is_writeable(struct usb_device *device)
@@ -681,29 +688,38 @@
return res;
}
-struct usb_request *usb_request_wait(struct usb_device *dev)
+struct usb_request *usb_request_wait(struct usb_device *dev, int timeoutMillis)
{
- struct usbdevfs_urb *urb = NULL;
- struct usb_request *req = NULL;
+ // Poll until a request becomes available if there is a timeout
+ if (timeoutMillis > 0) {
+ struct pollfd p = {.fd = dev->fd, .events = POLLOUT, .revents = 0};
- while (1) {
- int res = ioctl(dev->fd, USBDEVFS_REAPURB, &urb);
- D("USBDEVFS_REAPURB returned %d\n", res);
- if (res < 0) {
- if(errno == EINTR) {
- continue;
- }
- D("[ reap urb - error ]\n");
+ int res = poll(&p, 1, timeoutMillis);
+
+ if (res != 1 || p.revents != POLLOUT) {
+ D("[ poll - event %d, error %d]\n", p.revents, errno);
return NULL;
- } else {
- D("[ urb @%p status = %d, actual = %d ]\n",
- urb, urb->status, urb->actual_length);
- req = (struct usb_request*)urb->usercontext;
- req->actual_length = urb->actual_length;
}
- break;
}
- return req;
+
+ // Read the request. This should usually succeed as we polled before, but it can fail e.g. when
+ // two threads are reading usb requests at the same time and only a single request is available.
+ struct usbdevfs_urb *urb = NULL;
+ int res = TEMP_FAILURE_RETRY(ioctl(dev->fd, timeoutMillis == -1 ? USBDEVFS_REAPURB :
+ USBDEVFS_REAPURBNDELAY, &urb));
+ D("%s returned %d\n", timeoutMillis == -1 ? "USBDEVFS_REAPURB" : "USBDEVFS_REAPURBNDELAY", res);
+
+ if (res < 0) {
+ D("[ reap urb - error %d]\n", errno);
+ return NULL;
+ } else {
+ D("[ urb @%p status = %d, actual = %d ]\n", urb, urb->status, urb->actual_length);
+
+ struct usb_request *req = (struct usb_request*)urb->usercontext;
+ req->actual_length = urb->actual_length;
+
+ return req;
+ }
}
int usb_request_cancel(struct usb_request *req)
@@ -711,4 +727,3 @@
struct usbdevfs_urb *urb = ((struct usbdevfs_urb*)req->private_data);
return ioctl(req->dev->fd, USBDEVFS_DISCARDURB, urb);
}
-
diff --git a/libutils/Looper.cpp b/libutils/Looper.cpp
index 26e27cf..3edc536 100644
--- a/libutils/Looper.cpp
+++ b/libutils/Looper.cpp
@@ -83,6 +83,7 @@
Looper::~Looper() {
close(mWakeEventFd);
+ mWakeEventFd = -1;
if (mEpollFd >= 0) {
close(mEpollFd);
}
@@ -412,7 +413,8 @@
ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
if (nWrite != sizeof(uint64_t)) {
if (errno != EAGAIN) {
- ALOGW("Could not write wake signal: %s", strerror(errno));
+ LOG_ALWAYS_FATAL("Could not write wake signal to fd %d: %s",
+ mWakeEventFd, strerror(errno));
}
}
}
diff --git a/libutils/SharedBuffer.cpp b/libutils/SharedBuffer.cpp
index 269326a..229e3f2 100644
--- a/libutils/SharedBuffer.cpp
+++ b/libutils/SharedBuffer.cpp
@@ -113,16 +113,26 @@
int32_t SharedBuffer::release(uint32_t flags) const
{
- int32_t prev = 1;
- if (onlyOwner()
- || (((prev = mRefs.fetch_sub(1, std::memory_order_release)) == 1)
- && (atomic_thread_fence(std::memory_order_acquire), true))) {
+ const bool useDealloc = ((flags & eKeepStorage) == 0);
+ if (onlyOwner()) {
+ // Since we're the only owner, our reference count goes to zero.
mRefs.store(0, std::memory_order_relaxed);
- if ((flags & eKeepStorage) == 0) {
- free(const_cast<SharedBuffer*>(this));
+ if (useDealloc) {
+ dealloc(this);
+ }
+ // As the only owner, our previous reference count was 1.
+ return 1;
+ }
+ // There's multiple owners, we need to use an atomic decrement.
+ int32_t prevRefCount = mRefs.fetch_sub(1, std::memory_order_release);
+ if (prevRefCount == 1) {
+ // We're the last reference, we need the acquire fence.
+ atomic_thread_fence(std::memory_order_acquire);
+ if (useDealloc) {
+ dealloc(this);
}
}
- return prev;
+ return prevRefCount;
}
diff --git a/libziparchive/testdata/bad_filename.zip b/libziparchive/testdata/bad_filename.zip
new file mode 100644
index 0000000..294eaf5
--- /dev/null
+++ b/libziparchive/testdata/bad_filename.zip
Binary files differ
diff --git a/libziparchive/testdata/crash.apk b/libziparchive/testdata/crash.apk
new file mode 100644
index 0000000..d6dd52d
--- /dev/null
+++ b/libziparchive/testdata/crash.apk
Binary files differ
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 0ac6f2c..c2055b7 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -373,6 +373,11 @@
archive->hash_table_size = RoundUpPower2(1 + (num_entries * 4) / 3);
archive->hash_table = reinterpret_cast<ZipString*>(calloc(archive->hash_table_size,
sizeof(ZipString)));
+ if (archive->hash_table == nullptr) {
+ ALOGW("Zip: unable to allocate the %u-entry hash_table, entry size: %zu",
+ archive->hash_table_size, sizeof(ZipString));
+ return -1;
+ }
/*
* Walk through the central directory, adding entries to the hash
@@ -405,6 +410,11 @@
const uint16_t comment_length = cdr->comment_length;
const uint8_t* file_name = ptr + sizeof(CentralDirectoryRecord);
+ if (file_name + file_name_length > cd_end) {
+ ALOGW("Zip: file name boundary exceeds the central directory range, file_name_length: "
+ "%" PRIx16 ", cd_length: %zu", file_name_length, cd_length);
+ return -1;
+ }
/* check that file name is valid UTF-8 and doesn't contain NUL (U+0000) characters */
if (!IsValidEntryName(file_name, file_name_length)) {
return -1;
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 9dd6cc0..493a0ce 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -38,6 +38,8 @@
static const std::string kValidZip = "valid.zip";
static const std::string kLargeZip = "large.zip";
static const std::string kBadCrcZip = "bad_crc.zip";
+static const std::string kCrashApk = "crash.apk";
+static const std::string kBadFilenameZip = "bad_filename.zip";
static const std::string kUpdateZip = "dummy-update.zip";
static const std::vector<uint8_t> kATxtContents {
@@ -83,7 +85,15 @@
TEST(ziparchive, Open) {
ZipArchiveHandle handle;
ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
+ CloseArchive(handle);
+ ASSERT_EQ(-1, OpenArchiveWrapper(kBadFilenameZip, &handle));
+ CloseArchive(handle);
+}
+
+TEST(ziparchive, OutOfBound) {
+ ZipArchiveHandle handle;
+ ASSERT_EQ(-8, OpenArchiveWrapper(kCrashApk, &handle));
CloseArchive(handle);
}
diff --git a/rootdir/etc/public.libraries.android.txt b/rootdir/etc/public.libraries.android.txt
index e6c94ff..2fe90d9 100644
--- a/rootdir/etc/public.libraries.android.txt
+++ b/rootdir/etc/public.libraries.android.txt
@@ -12,6 +12,7 @@
liblog.so
libmediandk.so
libm.so
+liboboe.so
libOpenMAXAL.so
libOpenSLES.so
libRS.so
diff --git a/rootdir/etc/public.libraries.wear.txt b/rootdir/etc/public.libraries.wear.txt
index 292730a..b35d463 100644
--- a/rootdir/etc/public.libraries.wear.txt
+++ b/rootdir/etc/public.libraries.wear.txt
@@ -12,6 +12,7 @@
liblog.so
libmediandk.so
libm.so
+liboboe.so
libOpenMAXAL.so
libOpenSLES.so
libRS.so
diff --git a/rootdir/init.rc b/rootdir/init.rc
index c0a0fce..ccbad4b 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -307,7 +307,8 @@
# Mount shared so changes propagate into child namespaces
mount rootfs rootfs / shared rec
# Mount default storage into root namespace
- mount none /mnt/runtime/default /storage slave bind rec
+ mount none /mnt/runtime/default /storage bind rec
+ mount none none /storage slave rec
# Make sure /sys/kernel/debug (if present) is labeled properly
# Note that tracefs may be mounted under debug, so we need to cross filesystems
@@ -650,10 +651,9 @@
critical
seclabel u:r:ueventd:s0
-service healthd /sbin/healthd
+service healthd /system/bin/healthd
class core
critical
- seclabel u:r:healthd:s0
group root system wakelock
service console /system/bin/sh
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 66e7750..7084355 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -13,7 +13,7 @@
onrestart restart wificond
writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
-service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
+service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
class main
priority -20
user root
diff --git a/sdcard/fuse.cpp b/sdcard/fuse.cpp
index 3f0f95f..95559d7 100644
--- a/sdcard/fuse.cpp
+++ b/sdcard/fuse.cpp
@@ -997,7 +997,7 @@
{
struct node* node;
char path[PATH_MAX];
- struct fuse_open_out out;
+ struct fuse_open_out out = {};
struct handle *h;
pthread_mutex_lock(&fuse->global->lock);
@@ -1026,13 +1026,6 @@
}
out.fh = ptr_to_id(h);
out.open_flags = 0;
-
-#ifdef FUSE_SHORTCIRCUIT
- out.lower_fd = h->fd;
-#else
- out.padding = 0;
-#endif
-
fuse_reply(fuse, hdr->unique, &out, sizeof(out));
return NO_STATUS;
}
@@ -1169,7 +1162,7 @@
{
struct node* node;
char path[PATH_MAX];
- struct fuse_open_out out;
+ struct fuse_open_out out = {};
struct dirhandle *h;
pthread_mutex_lock(&fuse->global->lock);
@@ -1196,13 +1189,6 @@
}
out.fh = ptr_to_id(h);
out.open_flags = 0;
-
-#ifdef FUSE_SHORTCIRCUIT
- out.lower_fd = -1;
-#else
- out.padding = 0;
-#endif
-
fuse_reply(fuse, hdr->unique, &out, sizeof(out));
return NO_STATUS;
}
@@ -1282,11 +1268,6 @@
out.major = FUSE_KERNEL_VERSION;
out.max_readahead = req->max_readahead;
out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
-
-#ifdef FUSE_SHORTCIRCUIT
- out.flags |= FUSE_SHORTCIRCUIT;
-#endif
-
out.max_background = 32;
out.congestion_threshold = 32;
out.max_write = MAX_WRITE;
diff --git a/storaged/Android.mk b/storaged/Android.mk
new file mode 100644
index 0000000..db97040
--- /dev/null
+++ b/storaged/Android.mk
@@ -0,0 +1,34 @@
+# Copyright 2016 The Android Open Source Project
+
+LOCAL_PATH := $(call my-dir)
+
+LIBSTORAGED_SHARED_LIBRARIES := libbinder libbase libutils libcutils liblog libsysutils libcap
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := storaged.cpp \
+ storaged_service.cpp \
+ storaged_utils.cpp \
+ EventLogTags.logtags
+LOCAL_MODULE := libstoraged
+LOCAL_CFLAGS := -Werror
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include external/googletest/googletest/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_SHARED_LIBRARIES := $(LIBSTORAGED_SHARED_LIBRARIES)
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := storaged
+LOCAL_INIT_RC := storaged.rc
+LOCAL_SRC_FILES := main.cpp
+# libstoraged is an internal static library, only main.cpp and storaged_test.cpp should be using it
+LOCAL_STATIC_LIBRARIES := libstoraged
+LOCAL_SHARED_LIBRARIES := $(LIBSTORAGED_SHARED_LIBRARIES)
+LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter
+LOCAL_C_INCLUDES := external/googletest/googletest/include
+
+include $(BUILD_EXECUTABLE)
+
+include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/storaged/EventLogTags.logtags b/storaged/EventLogTags.logtags
new file mode 100644
index 0000000..ee92dd1
--- /dev/null
+++ b/storaged/EventLogTags.logtags
@@ -0,0 +1,39 @@
+# The entries in this file map a sparse set of log tag numbers to tag names.
+# This is installed on the device, in /system/etc, and parsed by logcat.
+#
+# Tag numbers are decimal integers, from 0 to 2^31. (Let's leave the
+# negative values alone for now.)
+#
+# Tag names are one or more ASCII letters and numbers or underscores, i.e.
+# "[A-Z][a-z][0-9]_". Do not include spaces or punctuation (the former
+# impacts log readability, the latter makes regex searches more annoying).
+#
+# Tag numbers and names are separated by whitespace. Blank lines and lines
+# starting with '#' are ignored.
+#
+# Optionally, after the tag names can be put a description for the value(s)
+# of the tag. Description are in the format
+# (<name>|data type[|data unit])
+# Multiple values are separated by commas.
+#
+# The data type is a number from the following values:
+# 1: int
+# 2: long
+# 3: string
+# 4: list
+# 5: float
+#
+# The data unit is a number taken from the following list:
+# 1: Number of objects
+# 2: Number of bytes
+# 3: Number of milliseconds
+# 4: Number of allocations
+# 5: Id
+# 6: Percent
+# Default value for data of type int/long is 2 (bytes).
+#
+# TODO: generate ".java" and ".h" files with integer constants from this file.
+
+2732 storaged_disk_stats (type|3),(start_time|2|3),(end_time|2|3),(read_ios|2|1),(read_merges|2|1),(read_sectors|2|1),(read_ticks|2|3),(write_ios|2|1),(write_merges|2|1),(write_sectors|2|1),(write_ticks|2|3),(o_in_flight|2|1),(io_ticks|2|3),(io_in_queue|2|1)
+
+2733 storaged_emmc_info (mmc_ver|3),(eol|1),(lifetime_a|1),(lifetime_b|1)
diff --git a/storaged/include/storaged.h b/storaged/include/storaged.h
new file mode 100644
index 0000000..eb827cf
--- /dev/null
+++ b/storaged/include/storaged.h
@@ -0,0 +1,340 @@
+/*
+ * 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 _STORAGED_H_
+#define _STORAGED_H_
+
+#define DEBUG
+
+#include <queue>
+#include <semaphore.h>
+#include <stdint.h>
+#include <string>
+#include <syslog.h>
+#include <unordered_map>
+#include <vector>
+
+#define FRIEND_TEST(test_case_name, test_name) \
+friend class test_case_name##_##test_name##_Test
+
+/* For debug */
+#ifdef DEBUG
+#define debuginfo(fmt, ...) \
+ do {printf("%s():\t" fmt "\t[%s:%d]\n", __FUNCTION__, ##__VA_ARGS__, __FILE__, __LINE__);} \
+ while(0)
+#else
+#define debuginfo(...)
+#endif
+
+#define KMSG_PRIORITY(PRI) \
+ '<', \
+ '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) / 10, \
+ '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) % 10, \
+ '>'
+
+static char kmsg_error_prefix[] = { KMSG_PRIORITY(LOG_ERR),
+ 's', 't', 'o', 'r', 'a', 'g', 'e', 'd', ':', '\0' };
+
+static char kmsg_info_prefix[] = { KMSG_PRIORITY(LOG_INFO),
+ 's', 't', 'o', 'r', 'a', 'g', 'e', 'd', ':', '\0' };
+
+static char kmsg_warning_prefix[] = { KMSG_PRIORITY(LOG_WARNING),
+ 's', 't', 'o', 'r', 'a', 'g', 'e', 'd', ':', '\0' };
+
+// number of attributes diskstats has
+#define DISK_STATS_SIZE ( 11 )
+// maximum size limit of a stats file
+#define DISK_STATS_FILE_MAX_SIZE ( 256 )
+#define DISK_STATS_IO_IN_FLIGHT_IDX ( 8 )
+struct disk_stats {
+ /* It will be extremely unlikely for any of the following entries to overflow.
+ * For read_bytes(which will be greater than any of the following entries), it
+ * will take 27 years to overflow uint64_t at the reading rate of 20GB/s, which
+ * is the peak memory transfer rate for current memory.
+ * The diskstats entries (first 11) need to be at top in this structure _after_
+ * compiler's optimization.
+ */
+ uint64_t read_ios; // number of read I/Os processed
+ uint64_t read_merges; // number of read I/Os merged with in-queue I/Os
+ uint64_t read_sectors; // number of sectors read
+ uint64_t read_ticks; // total wait time for read requests
+ uint64_t write_ios; // number of write I/Os processed
+ uint64_t write_merges; // number of write I/Os merged with in-queue I/Os
+ uint64_t write_sectors; // number of sectors written
+ uint64_t write_ticks; // total wait time for write requests
+ uint64_t io_in_flight; // number of I/Os currently in flight
+ uint64_t io_ticks; // total time this block device has been active
+ uint64_t io_in_queue; // total wait time for all requests
+
+ uint64_t start_time; // monotonic time accounting starts
+ uint64_t end_time; // monotonic time accounting ends
+ uint32_t counter; // private counter for accumulate calculations
+ double io_avg; // average io_in_flight for accumulate calculations
+};
+
+#define MMC_VER_STR_LEN ( 8 ) // maximum length of the MMC version string
+// minimum size of a ext_csd file
+#define EXT_CSD_FILE_MIN_SIZE ( 1024 )
+struct emmc_info {
+ int eol; // pre-eol (end of life) information
+ int lifetime_a; // device life time estimation (type A)
+ int lifetime_b; // device life time estimation (type B)
+ char mmc_ver[MMC_VER_STR_LEN]; // device version string
+};
+
+struct disk_perf {
+ uint32_t read_perf; // read speed (kbytes/s)
+ uint32_t read_ios; // read I/Os per second
+ uint32_t write_perf; // write speed (kbytes/s)
+ uint32_t write_ios; // write I/Os per second
+ uint32_t queue; // I/Os in queue
+};
+
+#define CMD_MAX_LEN ( 64 )
+struct task_info {
+ uint32_t pid; // task id
+ uint64_t rchar; // characters read
+ uint64_t wchar; // characters written
+ uint64_t syscr; // read syscalls
+ uint64_t syscw; // write syscalls
+ uint64_t read_bytes; // bytes read (from storage layer)
+ uint64_t write_bytes; // bytes written (to storage layer)
+ uint64_t cancelled_write_bytes; // cancelled write byte by truncate
+
+ uint64_t starttime; // start time of task
+
+ char cmd[CMD_MAX_LEN]; // filename of the executable
+};
+
+class lock_t {
+ sem_t* mSem;
+public:
+ lock_t(sem_t* sem) {
+ mSem = sem;
+ sem_wait(mSem);
+ }
+ ~lock_t() {
+ sem_post(mSem);
+ }
+};
+
+class tasks_t {
+private:
+ FRIEND_TEST(storaged_test, tasks_t);
+ sem_t mSem;
+ // hashmap for all running tasks w/ pid as key
+ std::unordered_map<uint32_t, struct task_info> mRunning;
+ // hashmap for all tasks that have been killed (categorized by cmd) w/ cmd as key
+ std::unordered_map<std::string, struct task_info> mOld;
+ std::unordered_map<std::uint32_t, struct task_info> get_running_tasks();
+public:
+ tasks_t() {
+ sem_init(&mSem, 0, 1); // TODO: constructor don't have a return value, what if sem_init fails
+ }
+
+ ~tasks_t() {
+ sem_destroy(&mSem);
+ }
+
+ void update_running_tasks(void);
+ std::vector<struct task_info> get_tasks(void);
+};
+
+class stream_stats {
+private:
+ double mSum;
+ double mSquareSum;
+ uint32_t mCnt;
+public:
+ stream_stats() : mSum(0), mSquareSum(0), mCnt(0) {};
+ ~stream_stats() {};
+ double get_mean() {
+ return mSum / mCnt;
+ }
+ double get_std() {
+ return sqrt(mSquareSum / mCnt - mSum * mSum / (mCnt * mCnt));
+ }
+ void add(uint32_t num) {
+ mSum += (double)num;
+ mSquareSum += (double)num * (double)num;
+ mCnt++;
+ }
+ void evict(uint32_t num) {
+ if (mSum < num || mSquareSum < (double)num * (double)num) return;
+ mSum -= (double)num;
+ mSquareSum -= (double)num * (double)num;
+ mCnt--;
+ }
+};
+
+#define MMC_DISK_STATS_PATH "/sys/block/mmcblk0/stat"
+#define SDA_DISK_STATS_PATH "/sys/block/sda/stat"
+#define EMMC_ECSD_PATH "/d/mmc0/mmc0:0001/ext_csd"
+class disk_stats_monitor {
+private:
+ FRIEND_TEST(storaged_test, disk_stats_monitor);
+ const char* DISK_STATS_PATH;
+ struct disk_stats mPrevious;
+ struct disk_stats mAccumulate;
+ bool mStall;
+ std::queue<struct disk_perf> mBuffer;
+ struct {
+ stream_stats read_perf; // read speed (bytes/s)
+ stream_stats read_ios; // read I/Os per second
+ stream_stats write_perf; // write speed (bytes/s)
+ stream_stats write_ios; // write I/O per second
+ stream_stats queue; // I/Os in queue
+ } mStats;
+ bool mValid;
+ const uint32_t mWindow;
+ const double mSigma;
+ struct disk_perf mMean;
+ struct disk_perf mStd;
+
+ void update_mean();
+ void update_std();
+ void add(struct disk_perf* perf);
+ void evict(struct disk_perf* perf);
+ bool detect(struct disk_perf* perf);
+
+ void update(struct disk_stats* stats);
+
+public:
+ disk_stats_monitor(uint32_t window_size = 5, double sigma = 1.0) :
+ mStall(false),
+ mValid(false),
+ mWindow(window_size),
+ mSigma(sigma) {
+ memset(&mPrevious, 0, sizeof(mPrevious));
+ memset(&mMean, 0, sizeof(mMean));
+ memset(&mStd, 0, sizeof(mStd));
+
+ if (access(MMC_DISK_STATS_PATH, R_OK) >= 0) {
+ DISK_STATS_PATH = MMC_DISK_STATS_PATH;
+ } else {
+ DISK_STATS_PATH = SDA_DISK_STATS_PATH;
+ }
+ }
+ void update(void);
+};
+
+class disk_stats_publisher {
+private:
+ FRIEND_TEST(storaged_test, disk_stats_publisher);
+ const char* DISK_STATS_PATH;
+ struct disk_stats mAccumulate;
+ struct disk_stats mPrevious;
+public:
+ disk_stats_publisher(void) {
+ memset(&mAccumulate, 0, sizeof(struct disk_stats));
+ memset(&mPrevious, 0, sizeof(struct disk_stats));
+
+ if (access(MMC_DISK_STATS_PATH, R_OK) >= 0) {
+ DISK_STATS_PATH = MMC_DISK_STATS_PATH;
+ } else {
+ DISK_STATS_PATH = SDA_DISK_STATS_PATH;
+ }
+ }
+
+ ~disk_stats_publisher(void) {}
+ void publish(void);
+ void update(void);
+};
+
+class emmc_info_t {
+private:
+ struct emmc_info mInfo;
+ bool mValid;
+ int mFdEmmc;
+public:
+ emmc_info_t(void) :
+ mValid(false),
+ mFdEmmc(-1) {
+ memset(&mInfo, 0, sizeof(struct emmc_info));
+ }
+ ~emmc_info_t(void) {}
+
+ void publish(void);
+ void update(void);
+ void set_emmc_fd(int fd) {
+ mFdEmmc = fd;
+ }
+};
+
+// Periodic chores intervals in seconds
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT ( 20 )
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH ( 60 )
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_EMMC_INFO_PUBLISH ( 60 * 2 )
+
+struct storaged_config {
+ int periodic_chores_interval_unit;
+ int periodic_chores_interval_disk_stats_publish;
+ int periodic_chores_interval_emmc_info_publish;
+ bool proc_taskio_readable; // are /proc/[pid]/{io, comm, cmdline, stat} all readable
+ bool emmc_available; // whether eMMC est_csd file is readable
+ bool diskstats_available; // whether diskstats is accessible
+};
+
+class storaged_t {
+private:
+ time_t mTimer;
+ storaged_config mConfig;
+ disk_stats_publisher mDiskStats;
+ disk_stats_monitor mDsm;
+ emmc_info_t mEmmcInfo;
+ tasks_t mTasks;
+ time_t mStarttime;
+public:
+ storaged_t(void);
+ ~storaged_t() {}
+ void event(void);
+ void pause(void) {
+ sleep(mConfig.periodic_chores_interval_unit);
+ }
+ void set_unit_interval(int unit) {
+ mConfig.periodic_chores_interval_unit = unit;
+ }
+ void set_diskstats_interval(int disk_stats) {
+ mConfig.periodic_chores_interval_disk_stats_publish = disk_stats;
+ }
+ void set_emmc_interval(int emmc_info) {
+ mConfig.periodic_chores_interval_emmc_info_publish = emmc_info;
+ }
+ std::vector<struct task_info> get_tasks(void) {
+ // There could be a race when get_tasks() and the main thread is updating at the same time
+ // While update_running_tasks() is updating the critical sections at the end of the function
+ // all together atomically, the final state of task_t can only be either the main thread's
+ // update or this update. Since the race can only occur when both threads are updating
+ // "simultaneously", either final state is acceptable.
+ mTasks.update_running_tasks();
+ return mTasks.get_tasks();
+ }
+
+ void set_privileged_fds(int fd_emmc) {
+ mEmmcInfo.set_emmc_fd(fd_emmc);
+ }
+
+ time_t get_starttime(void) {
+ return mStarttime;
+ }
+};
+
+// Eventlog tag
+// The content must match the definition in EventLogTags.logtags
+#define EVENTLOGTAG_DISKSTATS ( 2732 )
+#define EVENTLOGTAG_EMMCINFO ( 2733 )
+
+#endif /* _STORAGED_H_ */
diff --git a/storaged/include/storaged_service.h b/storaged/include/storaged_service.h
new file mode 100644
index 0000000..64a9c81
--- /dev/null
+++ b/storaged/include/storaged_service.h
@@ -0,0 +1,59 @@
+/*
+ * 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 _STORAGED_SERVICE_H_
+#define _STORAGED_SERVICE_H_
+
+#include <vector>
+
+#include <binder/IInterface.h>
+#include <binder/IBinder.h>
+
+#include "storaged.h"
+
+using namespace android;
+
+// Interface
+class IStoraged : public IInterface {
+public:
+ enum {
+ DUMPTASKS = IBinder::FIRST_CALL_TRANSACTION,
+ };
+ // Request the service to run the test function
+ virtual std::vector<struct task_info> dump_tasks(const char* option) = 0;
+
+ DECLARE_META_INTERFACE(Storaged);
+};
+
+// Client
+class BpStoraged : public BpInterface<IStoraged> {
+public:
+ BpStoraged(const sp<IBinder>& impl) : BpInterface<IStoraged>(impl){};
+ virtual std::vector<struct task_info> dump_tasks(const char* option);
+};
+
+// Server
+class BnStoraged : public BnInterface<IStoraged> {
+ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
+};
+
+class Storaged : public BnStoraged {
+ virtual std::vector<struct task_info> dump_tasks(const char* option);
+};
+
+sp<IStoraged> get_storaged_service();
+
+#endif /* _STORAGED_SERVICE_H_ */
\ No newline at end of file
diff --git a/storaged/include/storaged_utils.h b/storaged/include/storaged_utils.h
new file mode 100644
index 0000000..b0e5146
--- /dev/null
+++ b/storaged/include/storaged_utils.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _STORAGED_UTILS_H_
+#define _STORAGED_UTILS_H_
+
+#include <stdint.h>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "storaged.h"
+
+// Diskstats
+bool parse_disk_stats(const char* disk_stats_path, struct disk_stats* stats);
+struct disk_perf get_disk_perf(struct disk_stats* stats);
+struct disk_stats get_inc_disk_stats(struct disk_stats* prev, struct disk_stats* curr);
+void add_disk_stats(struct disk_stats* src, struct disk_stats* dst);
+bool parse_emmc_ecsd(int ext_csd_fd, struct emmc_info* info);
+
+// Task I/O
+bool parse_task_info(uint32_t pid, struct task_info* info);
+void sort_running_tasks_info(std::vector<struct task_info> &tasks);
+
+// Logging
+void log_console_running_tasks_info(std::vector<struct task_info> tasks);
+void log_kernel_disk_stats(struct disk_stats* stats, const char* type);
+void log_kernel_disk_perf(struct disk_perf* perf, const char* type);
+void log_kernel_emmc_info(struct emmc_info* info);
+
+void log_event_disk_stats(struct disk_stats* stats, const char* type);
+void log_event_emmc_info(struct emmc_info* info_);
+#endif /* _STORAGED_UTILS_H_ */
\ No newline at end of file
diff --git a/storaged/main.cpp b/storaged/main.cpp
new file mode 100644
index 0000000..31ada68
--- /dev/null
+++ b/storaged/main.cpp
@@ -0,0 +1,297 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "storaged"
+#define KLOG_LEVEL 6
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <sys/capability.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <vector>
+
+#include <android-base/macros.h>
+#include <android-base/stringprintf.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+#include <cutils/android_get_control_file.h>
+#include <cutils/klog.h>
+#include <cutils/sched_policy.h>
+#include <private/android_filesystem_config.h>
+
+#include <storaged.h>
+#include <storaged_service.h>
+#include <storaged_utils.h>
+
+storaged_t storaged;
+
+static int drop_privs() {
+ // privilege setting
+ struct sched_param param;
+ memset(¶m, 0, sizeof(param));
+
+ if (set_sched_policy(0, SP_BACKGROUND) < 0) return -1;
+
+ if (sched_setscheduler((pid_t) 0, SCHED_BATCH, ¶m) < 0) return -1;
+
+ if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) return -1;
+
+ if (prctl(PR_SET_KEEPCAPS, 1) < 0) return -1;
+
+ std::unique_ptr<struct _cap_struct, int(*)(void *)> caps(cap_init(), cap_free);
+ if (cap_clear(caps.get()) < 0) return -1;
+ cap_value_t cap_value[] = {
+ CAP_SETGID,
+ CAP_SETUID,
+ CAP_SYS_PTRACE // allow access to proc/<pid>/io as non-root user
+ };
+ if (cap_set_flag(caps.get(), CAP_PERMITTED,
+ arraysize(cap_value), cap_value,
+ CAP_SET) < 0) return -1;
+ if (cap_set_flag(caps.get(), CAP_EFFECTIVE,
+ arraysize(cap_value), cap_value,
+ CAP_SET) < 0) return -1;
+ if (cap_set_proc(caps.get()) < 0)
+ return -1;
+
+ gid_t groups[] = { AID_READPROC };
+
+ if (setgroups(sizeof(groups) / sizeof(groups[0]), groups) == -1) return -1;
+
+ if (setgid(AID_SYSTEM) != 0) return -1;
+
+ if (setuid(AID_SYSTEM) != 0) return -1;
+
+ if (cap_set_flag(caps.get(), CAP_PERMITTED, 2, cap_value, CAP_CLEAR) < 0) return -1;
+ if (cap_set_flag(caps.get(), CAP_EFFECTIVE, 2, cap_value, CAP_CLEAR) < 0) return -1;
+ if (cap_set_proc(caps.get()) < 0)
+ return -1;
+
+ return 0;
+}
+
+// Function of storaged's main thread
+extern int fd_dmesg;
+void* storaged_main(void* s) {
+ storaged_t* storaged = (storaged_t*)s;
+
+ if (fd_dmesg >= 0) {
+ static const char start_message[] = {KMSG_PRIORITY(LOG_INFO),
+ 's', 't', 'o', 'r', 'a', 'g', 'e', 'd', ':', ' ', 'S', 't', 'a', 'r', 't', '\n'};
+ write(fd_dmesg, start_message, sizeof(start_message));
+ }
+
+ for (;;) {
+ storaged->event();
+ storaged->pause();
+ }
+ return NULL;
+}
+
+static void help_message(void) {
+ printf("usage: storaged [OPTION]\n");
+ printf(" -d --dump Dump task I/O usage to stdout\n");
+ printf(" -s --start Start storaged (default)\n");
+ printf(" --emmc=INTERVAL Set publish interval of emmc lifetime information (in days)\n");
+ printf(" --diskstats=INTERVAL Set publish interval of diskstats (in hours)\n");
+ printf(" --unit=INTERVAL Set storaged's refresh interval (in seconds)\n");
+ fflush(stdout);
+}
+
+#define HOUR_TO_SEC ( 3600 )
+#define DAY_TO_SEC ( 3600 * 24 )
+
+int main(int argc, char** argv) {
+ klog_set_level(KLOG_LEVEL);
+ int flag_main_service = 0;
+ int flag_dump_task = 0;
+ int flag_config = 0;
+ int unit_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT;
+ int diskstats_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH;
+ int emmc_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_EMMC_INFO_PUBLISH;
+ int fd_emmc = -1;
+ int opt;
+
+ for (;;) {
+ int opt_idx = 0;
+ static struct option long_options[] = {
+ {"start", no_argument, 0, 's'},
+ {"kill", no_argument, 0, 'k'},
+ {"dump", no_argument, 0, 'd'},
+ {"help", no_argument, 0, 'h'},
+ {"unit", required_argument, 0, 0 },
+ {"diskstats", required_argument, 0, 0 },
+ {"emmc", required_argument, 0, 0 }
+ };
+ opt = getopt_long(argc, argv, ":skdh0", long_options, &opt_idx);
+ if (opt == -1) {
+ break;
+ }
+
+ switch (opt) {
+ case 0:
+ printf("option %s", long_options[opt_idx].name);
+ if (optarg) {
+ printf(" with arg %s", optarg);
+ if (strcmp(long_options[opt_idx].name, "unit") == 0) {
+ unit_interval = atoi(optarg);
+ if (unit_interval == 0) {
+ fprintf(stderr, "Invalid argument. Option %s requires an integer argument greater than 0.\n",
+ long_options[opt_idx].name);
+ help_message();
+ return -1;
+ }
+ } else if (strcmp(long_options[opt_idx].name, "diskstats") == 0) {
+ diskstats_interval = atoi(optarg) * HOUR_TO_SEC;
+ if (diskstats_interval == 0) {
+ fprintf(stderr, "Invalid argument. Option %s requires an integer argument greater than 0.\n",
+ long_options[opt_idx].name);
+ help_message();
+ return -1;
+ }
+
+ } else if (strcmp(long_options[opt_idx].name, "emmc") == 0) {
+ emmc_interval = atoi(optarg) * DAY_TO_SEC;
+ if (diskstats_interval == 0) {
+ fprintf(stderr, "Invalid argument. Option %s requires an integer argument greater than 0.\n",
+ long_options[opt_idx].name);
+ help_message();
+ return -1;
+ }
+ }
+ flag_config = 1;
+ } else {
+ fprintf(stderr, "Invalid argument. Option %s requires an argument.\n",
+ long_options[opt_idx].name);
+ help_message();
+ return -1;
+ }
+ printf("\n");
+ break;
+ case 's':
+ flag_main_service = 1;
+ break;
+ case 'd':
+ flag_dump_task = 1;
+ break;
+ case 'h':
+ help_message();
+ return 0;
+ case '?':
+ default:
+ fprintf(stderr, "no supported option\n");
+ help_message();
+ return -1;
+ }
+ }
+
+ if (argc == 1) {
+ flag_main_service = 1;
+ }
+
+ if (flag_main_service && flag_dump_task) {
+ fprintf(stderr, "Invalid arguments. Option \"start\" and \"dump\" cannot be used together.\n");
+ help_message();
+ return -1;
+ }
+
+ if (flag_config && flag_dump_task) {
+ fprintf(stderr, "Invalid arguments. Cannot set configs in \'dump\' option.\n");
+ help_message();
+ return -1;
+ }
+
+ if (flag_main_service) { // start main thread
+ static const char dev_kmsg[] = "/dev/kmsg";
+ fd_dmesg = android_get_control_file(dev_kmsg);
+ if (fd_dmesg < 0)
+ fd_dmesg = TEMP_FAILURE_RETRY(open(dev_kmsg, O_WRONLY));
+
+ static const char mmc0_ext_csd[] = "/d/mmc0/mmc0:0001/ext_csd";
+ fd_emmc = android_get_control_file(mmc0_ext_csd);
+ if (fd_emmc < 0)
+ fd_emmc = TEMP_FAILURE_RETRY(open(mmc0_ext_csd, O_RDONLY));
+
+ if (drop_privs() != 0) {
+ return -1;
+ }
+
+ storaged.set_privileged_fds(fd_emmc);
+
+ if (flag_config) {
+ storaged.set_unit_interval(unit_interval);
+ storaged.set_diskstats_interval(diskstats_interval);
+ storaged.set_emmc_interval(emmc_interval);
+ }
+
+ // Start the main thread of storaged
+ pthread_t storaged_main_thread;
+ if (pthread_create(&storaged_main_thread, NULL, storaged_main, &storaged)) {
+ if (fd_dmesg >= 0) {
+ std::string error_message = android::base::StringPrintf(
+ "%s Failed to create main thread\n", kmsg_error_prefix);
+ write(fd_dmesg, error_message.c_str(), error_message.length());
+ }
+ return -1;
+ }
+
+ defaultServiceManager()->addService(String16("storaged"), new Storaged());
+ android::ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+ pthread_join(storaged_main_thread, NULL);
+
+ close(fd_dmesg);
+ close(fd_emmc);
+
+ return 0;
+ }
+
+ if (flag_dump_task) {
+ sp<IStoraged> storaged_service = get_storaged_service();
+ if (storaged_service == NULL) {
+ fprintf(stderr, "Cannot find storaged service.\nMaybe run storaged --start first?\n");
+ return -1;
+ }
+ std::vector<struct task_info> res = storaged_service->dump_tasks(NULL);
+
+ if (res.size() == 0) {
+ fprintf(stderr, "Task I/O is not readable in this version of kernel.\n");
+ return 0;
+ }
+
+ time_t starttime = storaged.get_starttime();
+
+ if (starttime == (time_t)-1) {
+ fprintf(stderr, "Unknown start time\n");
+ } else {
+ char* time_str = ctime(&starttime);
+ printf("Application I/O was collected by storaged since %s", time_str);
+ }
+
+ sort_running_tasks_info(res);
+ log_console_running_tasks_info(res);
+
+ return 0;
+ }
+
+ return 0;
+}
diff --git a/storaged/storaged.cpp b/storaged/storaged.cpp
new file mode 100644
index 0000000..7b0c3ad
--- /dev/null
+++ b/storaged/storaged.cpp
@@ -0,0 +1,210 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "storaged"
+
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <android-base/logging.h>
+
+#include <storaged.h>
+#include <storaged_utils.h>
+
+/* disk_stats_publisher */
+void disk_stats_publisher::publish(void) {
+ // Logging
+ log_kernel_disk_stats(&mAccumulate, "regular");
+ struct disk_perf perf = get_disk_perf(&mAccumulate);
+ log_kernel_disk_perf(&perf, "regular");
+ log_event_disk_stats(&mAccumulate, "regular");
+ // Reset global structures
+ memset(&mAccumulate, 0, sizeof(struct disk_stats));
+}
+
+void disk_stats_publisher::update(void) {
+ struct disk_stats curr;
+ if (parse_disk_stats(DISK_STATS_PATH, &curr)) {
+ struct disk_stats inc = get_inc_disk_stats(&mPrevious, &curr);
+ add_disk_stats(&inc, &mAccumulate);
+#ifdef DEBUG
+// log_kernel_disk_stats(&mPrevious, "prev stats");
+// log_kernel_disk_stats(&curr, "curr stats");
+// log_kernel_disk_stats(&inc, "inc stats");
+// log_kernel_disk_stats(&mAccumulate, "accumulated stats");
+#endif
+ mPrevious = curr;
+ }
+}
+
+/* disk_stats_monitor */
+void disk_stats_monitor::update_mean() {
+ CHECK(mValid);
+ mMean.read_perf = (uint32_t)mStats.read_perf.get_mean();
+ mMean.read_ios = (uint32_t)mStats.read_ios.get_mean();
+ mMean.write_perf = (uint32_t)mStats.write_perf.get_mean();
+ mMean.write_ios = (uint32_t)mStats.write_ios.get_mean();
+ mMean.queue = (uint32_t)mStats.queue.get_mean();
+}
+
+void disk_stats_monitor::update_std() {
+ CHECK(mValid);
+ mStd.read_perf = (uint32_t)mStats.read_perf.get_std();
+ mStd.read_ios = (uint32_t)mStats.read_ios.get_std();
+ mStd.write_perf = (uint32_t)mStats.write_perf.get_std();
+ mStd.write_ios = (uint32_t)mStats.write_ios.get_std();
+ mStd.queue = (uint32_t)mStats.queue.get_std();
+}
+
+void disk_stats_monitor::add(struct disk_perf* perf) {
+ mStats.read_perf.add(perf->read_perf);
+ mStats.read_ios.add(perf->read_ios);
+ mStats.write_perf.add(perf->write_perf);
+ mStats.write_ios.add(perf->write_ios);
+ mStats.queue.add(perf->queue);
+}
+
+void disk_stats_monitor::evict(struct disk_perf* perf) {
+ mStats.read_perf.evict(perf->read_perf);
+ mStats.read_ios.evict(perf->read_ios);
+ mStats.write_perf.evict(perf->write_perf);
+ mStats.write_ios.evict(perf->write_ios);
+ mStats.queue.evict(perf->queue);
+}
+
+bool disk_stats_monitor::detect(struct disk_perf* perf) {
+ return ((double)perf->queue >= (double)mMean.queue + mSigma * (double)mStd.queue) &&
+ ((double)perf->read_perf < (double)mMean.read_perf - mSigma * (double)mStd.read_perf) &&
+ ((double)perf->write_perf < (double)mMean.write_perf - mSigma * (double)mStd.write_perf);
+}
+
+void disk_stats_monitor::update(struct disk_stats* stats) {
+ struct disk_stats inc = get_inc_disk_stats(&mPrevious, stats);
+ struct disk_perf perf = get_disk_perf(&inc);
+ // Update internal data structures
+ if (LIKELY(mValid)) {
+ CHECK_EQ(mBuffer.size(), mWindow);
+
+ if (UNLIKELY(detect(&perf))) {
+ mStall = true;
+ add_disk_stats(&inc, &mAccumulate);
+#ifdef DEBUG
+ log_kernel_disk_perf(&mMean, "stalled_mean");
+ log_kernel_disk_perf(&mStd, "stalled_std");
+#endif
+ } else {
+ if (mStall) {
+ log_kernel_disk_stats(&mAccumulate, "stalled");
+ struct disk_perf acc_perf = get_disk_perf(&mAccumulate);
+ log_kernel_disk_perf(&acc_perf, "stalled");
+
+ log_event_disk_stats(&mAccumulate, "stalled");
+ mStall = false;
+ memset(&mAccumulate, 0, sizeof(mAccumulate));
+ }
+ }
+
+ evict(&mBuffer.front());
+ mBuffer.pop();
+ add(&perf);
+ mBuffer.push(perf);
+
+ update_mean();
+ update_std();
+
+ } else { /* mValid == false */
+ CHECK_LT(mBuffer.size(), mWindow);
+ add(&perf);
+ mBuffer.push(perf);
+ if (mBuffer.size() == mWindow) {
+ mValid = true;
+ update_mean();
+ update_std();
+ }
+ }
+
+ mPrevious = *stats;
+}
+
+void disk_stats_monitor::update(void) {
+ struct disk_stats curr;
+ if (LIKELY(parse_disk_stats(DISK_STATS_PATH, &curr))) {
+ update(&curr);
+ }
+}
+
+/* emmc_info_t */
+void emmc_info_t::publish(void) {
+ if (mValid) {
+ log_kernel_emmc_info(&mInfo);
+ log_event_emmc_info(&mInfo);
+ }
+}
+
+void emmc_info_t::update(void) {
+ if (mFdEmmc >= 0) {
+ mValid = parse_emmc_ecsd(mFdEmmc, &mInfo);
+ }
+}
+
+/* storaged_t */
+storaged_t::storaged_t(void) {
+ mConfig.emmc_available = (access(EMMC_ECSD_PATH, R_OK) >= 0);
+
+ if (access(MMC_DISK_STATS_PATH, R_OK) < 0 && access(SDA_DISK_STATS_PATH, R_OK) < 0) {
+ mConfig.diskstats_available = false;
+ } else {
+ mConfig.diskstats_available = true;
+ }
+
+ mConfig.proc_taskio_readable = true;
+ const char* test_paths[] = {"/proc/1/io", "/proc/1/comm", "/proc/1/cmdline", "/proc/1/stat"};
+ for (uint i = 0; i < sizeof(test_paths) / sizeof(const char*); ++i) {
+ if (access(test_paths[i], R_OK) < 0) {
+ mConfig.proc_taskio_readable = false;
+ break;
+ }
+ }
+
+ mConfig.periodic_chores_interval_unit = DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT;
+ mConfig.periodic_chores_interval_disk_stats_publish = DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH;
+ mConfig.periodic_chores_interval_emmc_info_publish = DEFAULT_PERIODIC_CHORES_INTERVAL_EMMC_INFO_PUBLISH;
+
+ mStarttime = time(NULL);
+}
+
+void storaged_t::event(void) {
+ if (mConfig.diskstats_available) {
+ mDiskStats.update();
+ mDsm.update();
+ if (mTimer && (mTimer % mConfig.periodic_chores_interval_disk_stats_publish) == 0) {
+ mDiskStats.publish();
+ }
+ }
+
+ if (mConfig.proc_taskio_readable) {
+ mTasks.update_running_tasks();
+ }
+
+ if (mConfig.emmc_available && mTimer &&
+ (mTimer % mConfig.periodic_chores_interval_emmc_info_publish) == 0) {
+ mEmmcInfo.update();
+ mEmmcInfo.publish();
+ }
+
+ mTimer += mConfig.periodic_chores_interval_unit;
+}
diff --git a/storaged/storaged.rc b/storaged/storaged.rc
new file mode 100644
index 0000000..f72521c
--- /dev/null
+++ b/storaged/storaged.rc
@@ -0,0 +1,5 @@
+service storaged /system/bin/storaged
+ class main
+ file /d/mmc0/mmc0:0001/ext_csd r
+ file /dev/kmsg w
+ group root readproc
diff --git a/storaged/storaged_service.cpp b/storaged/storaged_service.cpp
new file mode 100644
index 0000000..aa38ceb
--- /dev/null
+++ b/storaged/storaged_service.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vector>
+
+#include <binder/IBinder.h>
+#include <binder/IInterface.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+
+#include <storaged.h>
+#include <storaged_service.h>
+
+extern storaged_t storaged;
+
+std::vector<struct task_info> BpStoraged::dump_tasks(const char* /*option*/) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IStoraged::getInterfaceDescriptor());
+
+ remote()->transact(DUMPTASKS, data, &reply);
+
+ uint32_t res_size = reply.readInt32();
+ std::vector<struct task_info> res(res_size);
+ for (auto&& task : res) {
+ reply.read(&task, sizeof(task));
+ }
+ return res;
+}
+
+IMPLEMENT_META_INTERFACE(Storaged, "Storaged");
+
+status_t BnStoraged::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+ data.checkInterface(this);
+
+ switch(code) {
+ case DUMPTASKS: {
+ std::vector<struct task_info> res = dump_tasks(NULL);
+
+ reply->writeInt32(res.size());
+ for (auto task : res) {
+ reply->write(&task, sizeof(task));
+ }
+ return NO_ERROR;
+ }
+ break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+std::vector<struct task_info> Storaged::dump_tasks(const char* /* option */) {
+ return storaged.get_tasks();
+}
+
+sp<IStoraged> get_storaged_service() {
+ sp<IServiceManager> sm = defaultServiceManager();
+ if (sm == NULL) return NULL;
+
+ sp<IBinder> binder = sm->getService(String16("storaged"));
+ if (binder == NULL) return NULL;
+
+ sp<IStoraged> storaged = interface_cast<IStoraged>(binder);
+
+ return storaged;
+}
\ No newline at end of file
diff --git a/storaged/storaged_utils.cpp b/storaged/storaged_utils.cpp
new file mode 100644
index 0000000..5e04888
--- /dev/null
+++ b/storaged/storaged_utils.cpp
@@ -0,0 +1,580 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "storaged"
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <linux/time.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <sstream>
+#include <string>
+#include <unordered_map>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <cutils/klog.h>
+#include <log/log.h>
+#include <log/log_event_list.h>
+
+#include <storaged.h>
+#include <storaged_utils.h>
+
+#define SECTOR_SIZE ( 512 )
+#define SEC_TO_MSEC ( 1000 )
+#define MSEC_TO_USEC ( 1000 )
+#define USEC_TO_NSEC ( 1000 )
+
+int fd_dmesg = -1;
+
+bool parse_disk_stats(const char* disk_stats_path, struct disk_stats* stats) {
+ // Get time
+ struct timespec ts;
+ // Use monotonic to exclude suspend time so that we measure IO bytes/sec
+ // when system is running.
+ int ret = clock_gettime(CLOCK_MONOTONIC, &ts);
+ if (ret < 0) {
+ if (fd_dmesg >= 0) {
+ std::string error_message = android::base::StringPrintf(
+ "%s clock_gettime() failed with errno %d\n",
+ kmsg_error_prefix, ret);
+ write(fd_dmesg, error_message.c_str(), error_message.length());
+ }
+ return false;
+ }
+
+ std::string buffer;
+ if (!android::base::ReadFileToString(disk_stats_path, &buffer)) {
+ if (fd_dmesg >= 0) {
+ std::string error_message = android::base::StringPrintf(
+ "%s %s: ReadFileToString failed.\n", kmsg_error_prefix, disk_stats_path);
+ write(fd_dmesg, error_message.c_str(), error_message.length());
+ }
+ return false;
+ }
+
+ // Regular diskstats entries
+ std::stringstream ss(buffer);
+ for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
+ ss >> *((uint64_t*)stats + i);
+ }
+ // Other entries
+ stats->start_time = 0;
+ stats->end_time = (uint64_t)ts.tv_sec * SEC_TO_MSEC +
+ ts.tv_nsec / (MSEC_TO_USEC * USEC_TO_NSEC);
+ stats->counter = 1;
+ stats->io_avg = (double)stats->io_in_flight;
+ return true;
+}
+
+struct disk_perf get_disk_perf(struct disk_stats* stats) {
+ struct disk_perf perf;
+ memset(&perf, 0, sizeof(struct disk_perf)); // initialize
+
+ if (stats->io_ticks) {
+ if (stats->read_ticks) {
+ unsigned long long divisor = stats->read_ticks * stats->io_ticks;
+ perf.read_perf = ((unsigned long long)SECTOR_SIZE *
+ stats->read_sectors *
+ stats->io_in_queue +
+ (divisor >> 1)) /
+ divisor;
+ perf.read_ios = ((unsigned long long)SEC_TO_MSEC *
+ stats->read_ios *
+ stats->io_in_queue +
+ (divisor >> 1)) /
+ divisor;
+ }
+ if (stats->write_ticks) {
+ unsigned long long divisor = stats->write_ticks * stats->io_ticks;
+ perf.write_perf = ((unsigned long long)SECTOR_SIZE *
+ stats->write_sectors *
+ stats->io_in_queue +
+ (divisor >> 1)) /
+ divisor;
+ perf.write_ios = ((unsigned long long)SEC_TO_MSEC *
+ stats->write_ios *
+ stats->io_in_queue +
+ (divisor >> 1)) /
+ divisor;
+ }
+ perf.queue = (stats->io_in_queue + (stats->io_ticks >> 1)) /
+ stats->io_ticks;
+ }
+ return perf;
+}
+
+struct disk_stats get_inc_disk_stats(struct disk_stats* prev, struct disk_stats* curr) {
+ struct disk_stats inc;
+ for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
+ if (i == DISK_STATS_IO_IN_FLIGHT_IDX) {
+ continue;
+ }
+
+ *((uint64_t*)&inc + i) =
+ *((uint64_t*)curr + i) - *((uint64_t*)prev + i);
+ }
+ // io_in_flight is exception
+ inc.io_in_flight = curr->io_in_flight;
+
+ inc.start_time = prev->end_time;
+ inc.end_time = curr->end_time;
+ inc.io_avg = curr->io_avg;
+ inc.counter = 1;
+
+ return inc;
+}
+
+// Add src to dst
+void add_disk_stats(struct disk_stats* src, struct disk_stats* dst) {
+ if (dst->end_time != 0 && dst->end_time != src->start_time && fd_dmesg >= 0) {
+ std::string warning_message = android::base::StringPrintf(
+ "%s Two dis-continuous periods of diskstats are added. "
+ "dst end with %jd, src start with %jd\n",
+ kmsg_warning_prefix, dst->end_time, src->start_time);
+
+ write(fd_dmesg, warning_message.c_str(), warning_message.length());
+ }
+
+ for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
+ if (i == DISK_STATS_IO_IN_FLIGHT_IDX) {
+ continue;
+ }
+
+ *((uint64_t*)dst + i) += *((uint64_t*)src + i);
+ }
+
+ dst->io_in_flight = src->io_in_flight;
+ if (dst->counter + src->counter) {
+ dst->io_avg = ((dst->io_avg * dst->counter) + (src->io_avg * src->counter)) /
+ (dst->counter + src->counter);
+ }
+ dst->counter += src->counter;
+ dst->end_time = src->end_time;
+ if (dst->start_time == 0) {
+ dst->start_time = src->start_time;
+ }
+}
+
+bool parse_emmc_ecsd(int ext_csd_fd, struct emmc_info* info) {
+ CHECK(ext_csd_fd >= 0);
+ struct hex {
+ char str[2];
+ };
+ // List of interesting offsets
+ static const size_t EXT_CSD_REV_IDX = 192 * sizeof(hex);
+ static const size_t EXT_PRE_EOL_INFO_IDX = 267 * sizeof(hex);
+ static const size_t EXT_DEVICE_LIFE_TIME_EST_A_IDX = 268 * sizeof(hex);
+ static const size_t EXT_DEVICE_LIFE_TIME_EST_B_IDX = 269 * sizeof(hex);
+
+ // Read file
+ CHECK(lseek(ext_csd_fd, 0, SEEK_SET) == 0);
+ std::string buffer;
+ if (!android::base::ReadFdToString(ext_csd_fd, &buffer)) {
+ if (fd_dmesg >= 0) {
+ std::string error_message = android::base::StringPrintf(
+ "%s ReadFdToString failed.\n", kmsg_error_prefix);
+ write(fd_dmesg, error_message.c_str(), error_message.length());
+ }
+ return false;
+ }
+
+ if (buffer.length() < EXT_CSD_FILE_MIN_SIZE) {
+ if (fd_dmesg >= 0) {
+ std::string error_message = android::base::StringPrintf(
+ "%s EMMC ext csd file has truncated content. File length: %d\n",
+ kmsg_error_prefix, (int)buffer.length());
+ write(fd_dmesg, error_message.c_str(), error_message.length());
+ }
+ return false;
+ }
+
+ std::string sub;
+ std::stringstream ss;
+ // Parse EXT_CSD_REV
+ int ext_csd_rev = -1;
+ sub = buffer.substr(EXT_CSD_REV_IDX, sizeof(hex));
+ ss << sub;
+ ss >> std::hex >> ext_csd_rev;
+ if (ext_csd_rev < 0) {
+ if (fd_dmesg >= 0) {
+ std::string error_message = android::base::StringPrintf(
+ "%s Failure on parsing EXT_CSD_REV.\n", kmsg_error_prefix);
+ write(fd_dmesg, error_message.c_str(), error_message.length());
+ }
+ return false;
+ }
+ ss.clear();
+
+ static const char* ver_str[] = {
+ "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0"
+ };
+
+ strncpy(info->mmc_ver,
+ (ext_csd_rev < (int)(sizeof(ver_str) / sizeof(ver_str[0]))) ?
+ ver_str[ext_csd_rev] :
+ "Unknown",
+ MMC_VER_STR_LEN);
+
+ if (ext_csd_rev < 7) {
+ return 0;
+ }
+
+ // Parse EXT_PRE_EOL_INFO
+ info->eol = -1;
+ sub = buffer.substr(EXT_PRE_EOL_INFO_IDX, sizeof(hex));
+ ss << sub;
+ ss >> std::hex >> info->eol;
+ if (info->eol < 0) {
+ if (fd_dmesg >= 0) {
+ std::string error_message = android::base::StringPrintf(
+ "%s Failure on parsing EXT_PRE_EOL_INFO.\n", kmsg_error_prefix);
+ write(fd_dmesg, error_message.c_str(), error_message.length());
+ }
+ return false;
+ }
+ ss.clear();
+
+ // Parse DEVICE_LIFE_TIME_EST
+ info->lifetime_a = -1;
+ sub = buffer.substr(EXT_DEVICE_LIFE_TIME_EST_A_IDX, sizeof(hex));
+ ss << sub;
+ ss >> std::hex >> info->lifetime_a;
+ if (info->lifetime_a < 0) {
+ if (fd_dmesg >= 0) {
+ std::string error_message = android::base::StringPrintf(
+ "%s Failure on parsing EXT_DEVICE_LIFE_TIME_EST_TYP_A.\n", kmsg_error_prefix);
+ write(fd_dmesg, error_message.c_str(), error_message.length());
+ }
+ return false;
+ }
+ ss.clear();
+
+ info->lifetime_b = -1;
+ sub = buffer.substr(EXT_DEVICE_LIFE_TIME_EST_B_IDX, sizeof(hex));
+ ss << sub;
+ ss >> std::hex >> info->lifetime_b;
+ if (info->lifetime_b < 0) {
+ if (fd_dmesg >= 0) {
+ std::string error_message = android::base::StringPrintf(
+ "%s Failure on parsing EXT_DEVICE_LIFE_TIME_EST_TYP_B.\n", kmsg_error_prefix);
+ write(fd_dmesg, error_message.c_str(), error_message.length());
+ }
+ return false;
+ }
+ ss.clear();
+
+ return true;
+}
+
+#define PROC_DIR "/proc/"
+#define PROC_STAT_STARTTIME_IDX ( 22 ) // This index is 1 based according to the linux proc man page
+bool parse_task_info(uint32_t pid, struct task_info* info) {
+ std::string buffer;
+ std::string pid_str = std::to_string(pid);
+ info->pid = pid;
+
+ // Get task I/O
+ std::string task_io_path = android::base::StringPrintf(PROC_DIR "%s/io", pid_str.c_str());
+ if (!android::base::ReadFileToString(task_io_path, &buffer)) return false;
+
+ std::stringstream ss(buffer);
+ std::string title;
+
+ ss >> title >> info->rchar
+ >> title >> info->wchar
+ >> title >> info->syscr
+ >> title >> info->syscw
+ >> title >> info->read_bytes
+ >> title >> info->write_bytes
+ >> title >> info->cancelled_write_bytes;
+ ss.clear();
+
+ // Get cmd string
+ std::string task_cmdline_path = android::base::StringPrintf(PROC_DIR "%u/cmdline", pid);
+ if (!android::base::ReadFileToString(task_cmdline_path, &buffer)) return false;
+ strcpy(info->cmd, android::base::Trim(buffer).c_str());
+
+ if (info->cmd[0] == '\0') {
+ std::string task_comm_path = android::base::StringPrintf(PROC_DIR "%u/comm", pid);
+ if (!android::base::ReadFileToString(task_comm_path, &buffer)) return false;
+ strcpy(info->cmd, android::base::Trim(buffer).c_str());
+ }
+
+ // Get task start time
+ std::string task_stat_path = android::base::StringPrintf(PROC_DIR "%u/stat", pid);
+ if (!android::base::ReadFileToString(task_stat_path, &buffer)) return false;
+
+ std::vector<std::string> stat_parts = android::base::Split(buffer, " ");
+ info->starttime = atoll(stat_parts[PROC_STAT_STARTTIME_IDX - 1].c_str());
+
+ return true;
+}
+
+static bool is_pid(char* d_name) {
+ if (!d_name || d_name[0] == '\0') return false;
+ char* c = d_name;
+ while (*c) {
+ if (!isdigit(*c)) return false;
+ ++c;
+ }
+ return true;
+}
+
+static bool cmp_task_info(struct task_info i, struct task_info j) {
+ if (i.write_bytes + i.read_bytes != j.write_bytes + j.read_bytes) {
+ return i.write_bytes + i.read_bytes > j.write_bytes + j.read_bytes;
+ }
+ if (i.wchar + i.rchar != j.wchar + j.rchar) {
+ return i.wchar + i.rchar > j.wchar + j.rchar;
+ }
+ if (i.syscw + i.syscr != j.syscw + j.syscr) {
+ return i.syscw + i.syscr > j.syscw + j.syscr;
+ }
+
+ return strcmp(i.cmd, j.cmd) < 0;
+}
+
+std::unordered_map<uint32_t, struct task_info> tasks_t::get_running_tasks() {
+ std::unordered_map<uint32_t, struct task_info> retval;
+ std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(PROC_DIR), closedir);
+ CHECK(dir != NULL);
+ struct dirent* dp;
+
+ for (;;) {
+ if ((dp = readdir(dir.get())) == NULL) break;
+ if (!is_pid(dp->d_name)) continue;
+
+ uint32_t pid = atol(dp->d_name);
+ struct task_info info;
+ if (parse_task_info(pid, &info)) {
+ retval[pid] = info;
+ }
+ }
+ return retval;
+}
+
+static void add_task_info(struct task_info* src, struct task_info* dst) {
+ CHECK(strcmp(src->cmd, dst->cmd) == 0);
+
+ dst->pid = 0;
+ dst->rchar += src->rchar;
+ dst->wchar += src->wchar;
+ dst->syscr += src->syscr;
+ dst->syscw += src->syscw;
+ dst->read_bytes += src->read_bytes;
+ dst->write_bytes += src->write_bytes;
+ dst->cancelled_write_bytes += src->cancelled_write_bytes;
+ dst->starttime = 0;
+}
+
+void tasks_t::update_running_tasks(void) {
+ std::unordered_map<uint32_t, struct task_info> tasks_latest = get_running_tasks();
+ std::unordered_map<std::string, struct task_info> tasks_old = mOld;
+
+ for (auto t : mRunning) {
+ uint32_t pid = t.first;
+ // old task on mRunning still exist on tasks_latest
+ if (tasks_latest.find(pid) != tasks_latest.end() &&
+ tasks_latest[pid].starttime == t.second.starttime) {
+ continue;
+ } else {
+ // This branch will handle 2 cases:
+ // - Task get killed between the 2 samplings
+ // - Task get killed and its pid is reused
+ std::string cmd = t.second.cmd;
+ struct task_info info = t.second;
+
+ if (tasks_old.find(cmd) == tasks_old.end()) {
+ tasks_old[cmd] = info;
+ } else {
+ add_task_info(&info, &tasks_old[cmd]);
+ }
+ }
+ }
+ { // update critical area
+ // this is really fast!
+ std::unique_ptr<lock_t> lock(new lock_t(&mSem));
+ mRunning = tasks_latest;
+ mOld = tasks_old;
+ }
+
+}
+
+std::vector<struct task_info> tasks_t::get_tasks(void) {
+ std::unique_ptr<lock_t> lock(new lock_t(&mSem));
+ std::unordered_map<std::string, struct task_info> tasks_map = mOld;
+
+ for (auto i : mRunning) {
+ std::string cmd = i.second.cmd;
+ if (tasks_map.find(cmd) == tasks_map.end()) {
+ tasks_map[cmd] = i.second;
+ } else {
+ add_task_info(&i.second, &tasks_map[cmd]);
+ }
+ }
+
+ std::vector<struct task_info> retval(tasks_map.size());
+ int idx = 0;
+ for (auto i : tasks_map) {
+ retval[idx++] = i.second;
+ }
+
+ return retval;
+}
+
+void sort_running_tasks_info(std::vector<struct task_info> &tasks) {
+ std::sort(tasks.begin(), tasks.end(), cmp_task_info);
+}
+
+/* Logging functions */
+void log_console_running_tasks_info(std::vector<struct task_info> tasks) {
+// Sample Output:
+// Application Read Write Read Write Read Write Cancelled
+// Name Characters Characters Syscalls Syscalls Bytes Bytes Writebytes
+// ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
+// zygote64 37688308 3388467 7607 4363 314519552 5373952 8192
+// system_server 95874193 2216913 74613 52257 213078016 7237632 16384
+// zygote 506279 1726194 921 263 128114688 1765376 0
+// /vendor/bin/qcks 75415632 75154382 21672 25036 63627264 29974528 10485760
+// /init 86658523 5107871 82113 8633 91015168 1245184 0
+
+ // Title
+ printf(" Application Read Write Read Write Read Write Cancelled\n"
+ " Name Characters Characters Syscalls Syscalls Bytes Bytes Writebytes\n"
+ " ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------\n");
+
+ for (struct task_info task : tasks) {
+ printf("%50s%15ju%15ju%15ju%15ju%15ju%15ju%15ju\n",
+ task.cmd, task.rchar, task.wchar, task.syscr, task.syscw,
+ task.read_bytes, task.write_bytes, task.cancelled_write_bytes);
+ }
+ fflush(stdout);
+}
+
+void log_kernel_disk_stats(struct disk_stats* stats, const char* type) {
+ // skip if the input structure are all zeros
+ if (stats == NULL) return;
+ struct disk_stats zero_cmp;
+ memset(&zero_cmp, 0, sizeof(zero_cmp));
+ if (memcmp(&zero_cmp, stats, sizeof(struct disk_stats)) == 0) return;
+
+ if (fd_dmesg >= 0) {
+ std::string info_message = android::base::StringPrintf(
+ "%s diskstats %s: %ju %ju %ju %ju %ju %ju %ju %ju %ju %ju %.1f %ju %ju\n",
+ kmsg_info_prefix, type, stats->start_time, stats->end_time,
+ stats->read_ios, stats->read_merges,
+ stats->read_sectors, stats->read_ticks,
+ stats->write_ios, stats->write_merges,
+ stats->write_sectors, stats->write_ticks,
+ stats->io_avg, stats->io_ticks,
+ stats->io_in_queue);
+
+ write(fd_dmesg, info_message.c_str(), info_message.length());
+ }
+}
+
+void log_kernel_disk_perf(struct disk_perf* perf, const char* type) {
+ // skip if the input structure are all zeros
+ if (perf == NULL) return;
+ struct disk_perf zero_cmp;
+ memset(&zero_cmp, 0, sizeof(zero_cmp));
+ if (memcmp(&zero_cmp, perf, sizeof(struct disk_perf)) == 0) return;
+
+ if (fd_dmesg >= 0) {
+ std::string info_message = android::base::StringPrintf(
+ "%s perf(ios) %s rd:%luKB/s(%lu/s) wr:%luKB/s(%lu/s) q:%lu\n",
+ kmsg_info_prefix, type,
+ (unsigned long)perf->read_perf, (unsigned long)perf->read_ios,
+ (unsigned long)perf->write_perf, (unsigned long)perf->write_ios,
+ (unsigned long)perf->queue);
+
+ write(fd_dmesg, info_message.c_str(), info_message.length());
+ }
+}
+
+void log_kernel_emmc_info(struct emmc_info* info) {
+ // skip if the input structure are all zeros
+ if (info == NULL) return;
+ struct emmc_info zero_cmp;
+ memset(&zero_cmp, 0, sizeof(zero_cmp));
+ if (memcmp(&zero_cmp, info, sizeof(struct emmc_info)) == 0) return;
+
+ if (fd_dmesg >= 0) {
+ std::string info_message = android::base::StringPrintf(
+ "%s MMC %s eol:%d, lifetime typA:%d, typB:%d\n",
+ kmsg_info_prefix, info->mmc_ver, info->eol, info->lifetime_a, info->lifetime_b);
+
+ write(fd_dmesg, info_message.c_str(), info_message.length());
+ }
+}
+
+void log_event_disk_stats(struct disk_stats* stats, const char* type) {
+ // skip if the input structure are all zeros
+ if (stats == NULL) return;
+ struct disk_stats zero_cmp;
+ memset(&zero_cmp, 0, sizeof(zero_cmp));
+ // skip event logging diskstats when it is zero increment (all first 11 entries are zero)
+ if (memcmp(&zero_cmp, stats, sizeof(uint64_t) * DISK_STATS_SIZE) == 0) return;
+
+ // Construct eventlog list
+ android_log_context ctx = create_android_logger(EVENTLOGTAG_DISKSTATS);
+
+ android_log_write_string8(ctx, type);
+ android_log_write_int64(ctx, stats->start_time);
+ android_log_write_int64(ctx, stats->end_time);
+ android_log_write_int64(ctx, stats->read_ios);
+ android_log_write_int64(ctx, stats->read_merges);
+ android_log_write_int64(ctx, stats->read_sectors);
+ android_log_write_int64(ctx, stats->read_ticks);
+ android_log_write_int64(ctx, stats->write_ios);
+ android_log_write_int64(ctx, stats->write_merges);
+ android_log_write_int64(ctx, stats->write_sectors);
+ android_log_write_int64(ctx, stats->write_ticks);
+ android_log_write_int64(ctx, (uint64_t)stats->io_avg);
+ android_log_write_int64(ctx, stats->io_ticks);
+ android_log_write_int64(ctx, stats->io_in_queue);
+
+ android_log_write_list(ctx, LOG_ID_EVENTS);
+ android_log_destroy(&ctx);
+}
+
+void log_event_emmc_info(struct emmc_info* info) {
+ // skip if the input structure are all zeros
+ if (info == NULL) return;
+ struct emmc_info zero_cmp;
+ memset(&zero_cmp, 0, sizeof(zero_cmp));
+ if (memcmp(&zero_cmp, info, sizeof(struct emmc_info)) == 0) return;
+
+ android_log_context ctx = create_android_logger(EVENTLOGTAG_EMMCINFO);
+
+ android_log_write_string8(ctx, info->mmc_ver);
+ android_log_write_int32(ctx, info->eol);
+ android_log_write_int32(ctx, info->lifetime_a);
+ android_log_write_int32(ctx, info->lifetime_b);
+
+ android_log_write_list(ctx, LOG_ID_EVENTS);
+ android_log_destroy(&ctx);
+}
diff --git a/storaged/tests/Android.mk b/storaged/tests/Android.mk
new file mode 100644
index 0000000..4a0e45c
--- /dev/null
+++ b/storaged/tests/Android.mk
@@ -0,0 +1,45 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+test_module_prefix := storaged-
+test_tags := tests
+
+# -----------------------------------------------------------------------------
+# Unit tests.
+# -----------------------------------------------------------------------------
+
+test_c_flags := \
+ -fstack-protector-all \
+ -g \
+ -Wall -Wextra \
+ -Werror \
+ -fno-builtin \
+
+test_src_files := \
+ storaged_test.cpp \
+
+# Build tests for the logger. Run with:
+# adb shell /data/nativetest/storaged-unit-tests/storaged-unit-tests
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(test_module_prefix)unit-tests
+LOCAL_MODULE_TAGS := $(test_tags)
+LOCAL_CFLAGS += $(test_c_flags)
+LOCAL_STATIC_LIBRARIES := libstoraged
+LOCAL_SHARED_LIBRARIES := libbase libcutils liblog
+LOCAL_SRC_FILES := $(test_src_files)
+include $(BUILD_NATIVE_TEST)
diff --git a/storaged/tests/storaged_test.cpp b/storaged/tests/storaged_test.cpp
new file mode 100644
index 0000000..99b21ac
--- /dev/null
+++ b/storaged/tests/storaged_test.cpp
@@ -0,0 +1,586 @@
+/*
+ * 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 <deque>
+#include <fcntl.h>
+#include <random>
+#include <string.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+
+#include <storaged.h> // data structures
+#include <storaged_utils.h> // functions to test
+
+#define MMC_DISK_STATS_PATH "/sys/block/mmcblk0/stat"
+#define SDA_DISK_STATS_PATH "/sys/block/sda/stat"
+#define EMMC_EXT_CSD_PATH "/d/mmc0/mmc0:0001/ext_csd"
+#define INIT_TASK_IO_PATH "/proc/1/io"
+
+static void pause(uint32_t sec) {
+ const char* path = "/cache/test";
+ int fd = open(path, O_WRONLY | O_CREAT);
+ ASSERT_LT(-1, fd);
+ char buffer[2048];
+ memset(buffer, 1, sizeof(buffer));
+ int loop_size = 100;
+ for (int i = 0; i < loop_size; ++i) {
+ ASSERT_EQ(2048, write(fd, buffer, sizeof(buffer)));
+ }
+ fsync(fd);
+ close(fd);
+
+ fd = open(path, O_RDONLY);
+ ASSERT_LT(-1, fd);
+ for (int i = 0; i < loop_size; ++i) {
+ ASSERT_EQ(2048, read(fd, buffer, sizeof(buffer)));
+ }
+ close(fd);
+
+ sleep(sec);
+}
+
+// the return values of the tested functions should be the expected ones
+const char* DISK_STATS_PATH;
+TEST(storaged_test, retvals) {
+ struct disk_stats stats;
+ struct emmc_info info;
+ memset(&stats, 0, sizeof(struct disk_stats));
+ memset(&info, 0, sizeof(struct emmc_info));
+
+ int emmc_fd = open(EMMC_EXT_CSD_PATH, O_RDONLY);
+ if (emmc_fd >= 0) {
+ EXPECT_TRUE(parse_emmc_ecsd(emmc_fd, &info));
+ }
+
+ if (access(MMC_DISK_STATS_PATH, R_OK) >= 0) {
+ DISK_STATS_PATH = MMC_DISK_STATS_PATH;
+ } else if (access(SDA_DISK_STATS_PATH, R_OK) >= 0) {
+ DISK_STATS_PATH = SDA_DISK_STATS_PATH;
+ } else {
+ return;
+ }
+
+ EXPECT_TRUE(parse_disk_stats(DISK_STATS_PATH, &stats));
+
+ struct disk_stats old_stats;
+ memset(&old_stats, 0, sizeof(struct disk_stats));
+ old_stats = stats;
+
+ const char wrong_path[] = "/this/is/wrong";
+ EXPECT_FALSE(parse_disk_stats(wrong_path, &stats));
+
+ // reading a wrong path should not damage the output structure
+ EXPECT_EQ(0, memcmp(&stats, &old_stats, sizeof(disk_stats)));
+}
+
+TEST(storaged_test, disk_stats) {
+ struct disk_stats stats;
+ memset(&stats, 0, sizeof(struct disk_stats));
+
+ ASSERT_TRUE(parse_disk_stats(DISK_STATS_PATH, &stats));
+
+ // every entry of stats (except io_in_flight) should all be greater than 0
+ for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
+ if (i == 8) continue; // skip io_in_flight which can be 0
+ EXPECT_LT((uint64_t)0, *((uint64_t*)&stats + i));
+ }
+
+ // accumulation of the increments should be the same with the overall increment
+ struct disk_stats base, tmp, curr, acc, inc[5];
+ memset(&base, 0, sizeof(struct disk_stats));
+ memset(&tmp, 0, sizeof(struct disk_stats));
+ memset(&acc, 0, sizeof(struct disk_stats));
+
+ for (uint i = 0; i < 5; ++i) {
+ ASSERT_TRUE(parse_disk_stats(DISK_STATS_PATH, &curr));
+ if (i == 0) {
+ base = curr;
+ tmp = curr;
+ sleep(5);
+ continue;
+ }
+ inc[i] = get_inc_disk_stats(&tmp, &curr);
+ add_disk_stats(&inc[i], &acc);
+ tmp = curr;
+ pause(5);
+ }
+ struct disk_stats overall_inc;
+ memset(&overall_inc, 0, sizeof(disk_stats));
+ overall_inc= get_inc_disk_stats(&base, &curr);
+
+ for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
+ if (i == 8) continue; // skip io_in_flight which can be 0
+ EXPECT_EQ(*((uint64_t*)&overall_inc + i), *((uint64_t*)&acc + i));
+ }
+}
+
+TEST(storaged_test, emmc_info) {
+ struct emmc_info info, void_info;
+ memset(&info, 0, sizeof(struct emmc_info));
+ memset(&void_info, 0, sizeof(struct emmc_info));
+
+ if (access(EMMC_EXT_CSD_PATH, R_OK) >= 0) {
+ int emmc_fd = open(EMMC_EXT_CSD_PATH, O_RDONLY);
+ ASSERT_GE(emmc_fd, 0);
+ ASSERT_TRUE(parse_emmc_ecsd(emmc_fd, &info));
+ // parse_emmc_ecsd() should put something in info.
+ EXPECT_NE(0, memcmp(&void_info, &info, sizeof(struct emmc_info)));
+ }
+}
+
+TEST(storaged_test, task_info) {
+ // parse_task_info should read something other than 0 from /proc/1/*
+ struct task_info task_info;
+ memset(&task_info, 0, sizeof(task_info));
+
+ if (!parse_task_info(1, &task_info)) return;
+
+ EXPECT_EQ((uint32_t)1, task_info.pid);
+ EXPECT_LT((uint64_t)0, task_info.rchar);
+ EXPECT_LT((uint64_t)0, task_info.wchar);
+ EXPECT_LT((uint64_t)0, task_info.syscr);
+ EXPECT_LT((uint64_t)0, task_info.syscw);
+ EXPECT_LT((uint64_t)0, task_info.read_bytes);
+ EXPECT_LT((uint64_t)0, task_info.write_bytes);
+ // cancelled_write_bytes of init could be 0, there is no need to test
+ EXPECT_LE((uint64_t)0, task_info.starttime);
+ EXPECT_NE((char*)NULL, strstr(task_info.cmd, "init"));
+
+ // Entries in /proc/1/io should be increasing through time
+ struct task_info task_old, task_new;
+ memset(&task_old, 0, sizeof(task_old));
+ memset(&task_new, 0, sizeof(task_new));
+
+ // parse_task_info should succeed at this point
+ ASSERT_TRUE(parse_task_info(1, &task_old));
+ sleep(1);
+ ASSERT_TRUE(parse_task_info(1, &task_new));
+
+ EXPECT_EQ(task_old.pid, task_new.pid);
+ EXPECT_LE(task_old.rchar, task_new.rchar);
+ EXPECT_LE(task_old.wchar, task_new.wchar);
+ EXPECT_LE(task_old.syscr, task_new.syscr);
+ EXPECT_LE(task_old.syscw, task_new.syscw);
+ EXPECT_LE(task_old.read_bytes, task_new.read_bytes);
+ EXPECT_LE(task_old.write_bytes, task_new.write_bytes);
+ EXPECT_LE(task_old.cancelled_write_bytes, task_new.cancelled_write_bytes);
+ EXPECT_EQ(task_old.starttime, task_new.starttime);
+ EXPECT_EQ(0, strcmp(task_old.cmd, task_new.cmd));
+}
+
+static double mean(std::deque<uint32_t> nums) {
+ double sum = 0.0;
+ for (uint32_t i : nums) {
+ sum += i;
+ }
+ return sum / nums.size();
+}
+
+static double standard_deviation(std::deque<uint32_t> nums) {
+ double sum = 0.0;
+ double avg = mean(nums);
+ for (uint32_t i : nums) {
+ sum += ((double)i - avg) * ((double)i - avg);
+ }
+ return sqrt(sum / nums.size());
+}
+
+TEST(storaged_test, stream_stats) {
+ // 100 random numbers
+ std::vector<uint32_t> data = {8147,9058,1270,9134,6324,975,2785,5469,9575,9649,1576,9706,9572,4854,8003,1419,4218,9157,7922,9595,6557,357,8491,9340,6787,7577,7431,3922,6555,1712,7060,318,2769,462,971,8235,6948,3171,9502,344,4387,3816,7655,7952,1869,4898,4456,6463,7094,7547,2760,6797,6551,1626,1190,4984,9597,3404,5853,2238,7513,2551,5060,6991,8909,9593,5472,1386,1493,2575,8407,2543,8143,2435,9293,3500,1966,2511,6160,4733,3517,8308,5853,5497,9172,2858,7572,7537,3804,5678,759,540,5308,7792,9340,1299,5688,4694,119,3371};
+ std::deque<uint32_t> test_data;
+ stream_stats sstats;
+ for (uint32_t i : data) {
+ test_data.push_back(i);
+ sstats.add(i);
+
+ EXPECT_EQ((int)standard_deviation(test_data), (int)sstats.get_std());
+ EXPECT_EQ((int)mean(test_data), (int)sstats.get_mean());
+ }
+
+ for (uint32_t i : data) {
+ test_data.pop_front();
+ sstats.evict(i);
+
+ EXPECT_EQ((int)standard_deviation(test_data), (int)sstats.get_std());
+ EXPECT_EQ((int)mean(test_data), (int)sstats.get_mean());
+ }
+
+ // some real data
+ std::vector<uint32_t> another_data = {113875,81620,103145,28327,86855,207414,96526,52567,28553,250311};
+ test_data.clear();
+ uint32_t window_size = 2;
+ uint32_t idx;
+ stream_stats sstats1;
+ for (idx = 0; idx < window_size; ++idx) {
+ test_data.push_back(another_data[idx]);
+ sstats1.add(another_data[idx]);
+ }
+ EXPECT_EQ((int)standard_deviation(test_data), (int)sstats1.get_std());
+ EXPECT_EQ((int)mean(test_data), (int)sstats1.get_mean());
+ for (;idx < another_data.size(); ++idx) {
+ test_data.pop_front();
+ sstats1.evict(another_data[idx - window_size]);
+ test_data.push_back(another_data[idx]);
+ sstats1.add(another_data[idx]);
+ EXPECT_EQ((int)standard_deviation(test_data), (int)sstats1.get_std());
+ EXPECT_EQ((int)mean(test_data), (int)sstats1.get_mean());
+ }
+}
+
+static void expect_increasing(struct task_info told, struct task_info tnew) {
+ ASSERT_EQ(told.pid, tnew.pid);
+ ASSERT_EQ(told.starttime, tnew.starttime);
+ ASSERT_EQ(strcmp(told.cmd, tnew.cmd), 0);
+
+ EXPECT_LE(told.rchar, tnew.rchar);
+ EXPECT_LE(told.wchar, tnew.wchar);
+ EXPECT_LE(told.syscr, tnew.syscr);
+ EXPECT_LE(told.syscw, tnew.syscw);
+ EXPECT_LE(told.read_bytes, tnew.read_bytes);
+ EXPECT_LE(told.write_bytes, tnew.write_bytes);
+ EXPECT_LE(told.cancelled_write_bytes, tnew.cancelled_write_bytes);
+}
+
+static void expect_equal(struct task_info told, struct task_info tnew) {
+ ASSERT_EQ(told.pid, tnew.pid);
+ ASSERT_EQ(told.starttime, tnew.starttime);
+ ASSERT_EQ(strcmp(told.cmd, tnew.cmd), 0);
+
+ EXPECT_EQ(told.rchar, tnew.rchar);
+ EXPECT_EQ(told.wchar, tnew.wchar);
+ EXPECT_EQ(told.syscr, tnew.syscr);
+ EXPECT_EQ(told.syscw, tnew.syscw);
+ EXPECT_EQ(told.read_bytes, tnew.read_bytes);
+ EXPECT_EQ(told.write_bytes, tnew.write_bytes);
+ EXPECT_EQ(told.cancelled_write_bytes, tnew.cancelled_write_bytes);
+}
+
+static std::set<uint32_t> find_overlap(std::unordered_map<uint32_t, struct task_info> t1,
+ std::unordered_map<uint32_t, struct task_info> t2) {
+ std::set<uint32_t> retval;
+ for (auto i : t1) {
+ if (t2.find(i.first) != t2.end()) {
+ retval.insert(i.first);
+ }
+ }
+
+ return retval;
+}
+
+static std::set<std::string> find_overlap(std::unordered_map<std::string, struct task_info> t1,
+ std::unordered_map<std::string, struct task_info> t2) {
+ std::set<std::string> retval;
+ for (auto i : t1) {
+ if (t2.find(i.first) != t2.end()) {
+ retval.insert(i.first);
+ }
+ }
+
+ return retval;
+}
+
+static bool cmp_app_name(struct task_info i, struct task_info j) {
+ return strcmp(i.cmd, j.cmd) > 0;
+}
+
+static void expect_match(std::vector<struct task_info> v1, std::vector<struct task_info> v2) {
+ ASSERT_EQ(v1.size(), v2.size());
+ std::sort(v1.begin(), v1.end(), cmp_app_name);
+ std::sort(v2.begin(), v2.end(), cmp_app_name);
+
+ for (uint i = 0; i < v1.size(); ++i) {
+ expect_equal(v1[i], v2[i]);
+ }
+}
+
+static void add_task_info(struct task_info* src, struct task_info* dst) {
+ ASSERT_EQ(0, strcmp(src->cmd, dst->cmd));
+
+ dst->pid = 0;
+ dst->rchar += src->rchar;
+ dst->wchar += src->wchar;
+ dst->syscr += src->syscr;
+ dst->syscw += src->syscw;
+ dst->read_bytes += src->read_bytes;
+ dst->write_bytes += src->write_bytes;
+ dst->cancelled_write_bytes += src->cancelled_write_bytes;
+ dst->starttime = 0;
+}
+
+static std::vector<struct task_info>
+categorize_tasks(std::unordered_map<uint32_t, struct task_info> tasks) {
+ std::unordered_map<std::string, struct task_info> tasks_cmd;
+ for (auto i : tasks) {
+ std::string cmd = i.second.cmd;
+ if (tasks_cmd.find(cmd) == tasks_cmd.end()) {
+ tasks_cmd[cmd] = i.second;
+ } else {
+ add_task_info(&i.second, &tasks_cmd[cmd]);
+ }
+ }
+
+ std::vector<struct task_info> retval(tasks_cmd.size());
+ int cnt = 0;
+ for (auto i : tasks_cmd) {
+ retval[cnt++] = i.second;
+ }
+
+ return retval;
+}
+
+#define TEST_LOOPS 20
+TEST(storaged_test, tasks_t) {
+ // pass this test if /proc/[pid]/io is not readable
+ const char* test_paths[] = {"/proc/1/io", "/proc/1/comm", "/proc/1/cmdline", "/proc/1/stat"};
+ for (uint i = 0; i < sizeof(test_paths) / sizeof(const char*); ++i) {
+ if (access(test_paths[i], R_OK) < 0) return;
+ }
+
+ tasks_t tasks;
+ EXPECT_EQ((uint32_t)0, tasks.mRunning.size());
+ EXPECT_EQ((uint32_t)0, tasks.mOld.size());
+
+ tasks.update_running_tasks();
+
+ std::unordered_map<uint32_t, struct task_info> prev_running = tasks.mRunning;
+ std::unordered_map<std::string, struct task_info> prev_old = tasks.mOld;
+
+ // hashmap maintaining
+ std::unordered_map<uint32_t, struct task_info> tasks_pid = tasks.mRunning;
+
+ // get_running_tasks() should return something other than a null map
+ std::unordered_map<uint32_t, struct task_info> test = tasks.get_running_tasks();
+ EXPECT_LE((uint32_t)1, test.size());
+
+ for (int i = 0; i < TEST_LOOPS; ++i) {
+ tasks.update_running_tasks();
+
+ std::set<uint32_t> overlap_running = find_overlap(prev_running, tasks.mRunning);
+ std::set<std::string> overlap_old = find_overlap(prev_old, tasks.mOld);
+
+ // overlap_running should capture init(pid == 1), since init never get killed
+ EXPECT_LE((uint32_t)1, overlap_running.size());
+ EXPECT_NE(overlap_running.find((uint32_t)1), overlap_running.end());
+ // overlap_old should never capture init, since init never get killed
+ EXPECT_EQ(overlap_old.find("init"), overlap_old.end());
+
+ // overlapping entries in previous and current running-tasks map should have increasing contents
+ for (uint32_t i : overlap_running) {
+ expect_increasing(prev_running[i], tasks.mRunning[i]);
+ }
+
+ // overlapping entries in previous and current killed-tasks map should have increasing contents
+ // and the map size should also be increasing
+ for (std::string i : overlap_old) {
+ expect_increasing(prev_old[i], tasks.mOld[i]);
+ }
+ EXPECT_LE(prev_old.size(), tasks.mRunning.size());
+
+ // update app name & tasks_pid
+ for (auto i : tasks.mRunning) {
+ // test will fail if the pid got wrapped
+ if (tasks_pid.find(i.first) != tasks_pid.end()) {
+ expect_increasing(tasks_pid[i.first], i.second);
+ tasks_pid[i.first] = i.second;
+ } else {
+ tasks_pid[i.first] = i.second;
+ }
+ }
+
+ // get maintained tasks
+ std::vector<struct task_info> test_tasks = categorize_tasks(tasks_pid);
+ std::vector<struct task_info> real_tasks = tasks.get_tasks();
+
+ expect_match(test_tasks, real_tasks);
+
+ prev_running = tasks.mRunning;
+ prev_old = tasks.mOld;
+
+ pause(5);
+ }
+}
+
+static struct disk_perf disk_perf_multiply(struct disk_perf perf, double mul) {
+ struct disk_perf retval;
+ retval.read_perf = (double)perf.read_perf * mul;
+ retval.read_ios = (double)perf.read_ios * mul;
+ retval.write_perf = (double)perf.write_perf * mul;
+ retval.write_ios = (double)perf.write_ios * mul;
+ retval.queue = (double)perf.queue * mul;
+
+ return retval;
+}
+
+static struct disk_stats disk_stats_add(struct disk_stats stats1, struct disk_stats stats2) {
+ struct disk_stats retval;
+ retval.read_ios = stats1.read_ios + stats2.read_ios;
+ retval.read_merges = stats1.read_merges + stats2.read_merges;
+ retval.read_sectors = stats1.read_sectors + stats2.read_sectors;
+ retval.read_ticks = stats1.read_ticks + stats2.read_ticks;
+ retval.write_ios = stats1.write_ios + stats2.write_ios;
+ retval.write_merges = stats1.write_merges + stats2.write_merges;
+ retval.write_sectors = stats1.write_sectors + stats2.write_sectors;
+ retval.write_ticks = stats1.write_ticks + stats2.write_ticks;
+ retval.io_in_flight = stats1.io_in_flight + stats2.io_in_flight;
+ retval.io_ticks = stats1.io_ticks + stats2.io_ticks;
+ retval.io_in_queue = stats1.io_in_queue + stats2.io_in_queue;
+ retval.end_time = stats1.end_time + stats2.end_time;
+
+ return retval;
+}
+
+TEST(storaged_test, disk_stats_monitor) {
+ // asserting that there is one file for diskstats
+ ASSERT_TRUE(access(MMC_DISK_STATS_PATH, R_OK) >= 0 || access(SDA_DISK_STATS_PATH, R_OK) >= 0);
+ // testing if detect() will return the right value
+ disk_stats_monitor dsm_detect;
+ // feed monitor with constant perf data for io perf baseline
+ // using constant perf is reasonable since the functionality of stream_stats
+ // has already been tested
+ struct disk_perf norm_perf = {
+ .read_perf = 10 * 1024,
+ .read_ios = 50,
+ .write_perf = 5 * 1024,
+ .write_ios = 25,
+ .queue = 5
+ };
+
+ std::random_device rd;
+ std::mt19937 gen(rd());
+ std::uniform_real_distribution<> rand(0.8, 1.2);
+
+ for (uint i = 0; i < dsm_detect.mWindow; ++i) {
+ struct disk_perf perf = disk_perf_multiply(norm_perf, rand(gen));
+
+ dsm_detect.add(&perf);
+ dsm_detect.mBuffer.push(perf);
+ EXPECT_EQ(dsm_detect.mBuffer.size(), (uint64_t)i + 1);
+ }
+
+ dsm_detect.mValid = true;
+ dsm_detect.update_mean();
+ dsm_detect.update_std();
+
+ for (double i = 0; i < 2 * dsm_detect.mSigma; i += 0.5) {
+ struct disk_perf test_perf;
+ struct disk_perf test_mean = dsm_detect.mMean;
+ struct disk_perf test_std = dsm_detect.mStd;
+
+ test_perf.read_perf = (double)test_mean.read_perf - i * test_std.read_perf;
+ test_perf.read_ios = (double)test_mean.read_ios - i * test_std.read_ios;
+ test_perf.write_perf = (double)test_mean.write_perf - i * test_std.write_perf;
+ test_perf.write_ios = (double)test_mean.write_ios - i * test_std.write_ios;
+ test_perf.queue = (double)test_mean.queue + i * test_std.queue;
+
+ EXPECT_EQ((i > dsm_detect.mSigma), dsm_detect.detect(&test_perf));
+ }
+
+ // testing if stalled disk_stats can be correctly accumulated in the monitor
+ disk_stats_monitor dsm_acc;
+ struct disk_stats norm_inc = {
+ .read_ios = 200,
+ .read_merges = 0,
+ .read_sectors = 200,
+ .read_ticks = 200,
+ .write_ios = 100,
+ .write_merges = 0,
+ .write_sectors = 100,
+ .write_ticks = 100,
+ .io_in_flight = 0,
+ .io_ticks = 600,
+ .io_in_queue = 300,
+ .start_time = 0,
+ .end_time = 100,
+ .counter = 0,
+ .io_avg = 0
+ };
+
+ struct disk_stats stall_inc = {
+ .read_ios = 200,
+ .read_merges = 0,
+ .read_sectors = 20,
+ .read_ticks = 200,
+ .write_ios = 100,
+ .write_merges = 0,
+ .write_sectors = 10,
+ .write_ticks = 100,
+ .io_in_flight = 0,
+ .io_ticks = 600,
+ .io_in_queue = 1200,
+ .start_time = 0,
+ .end_time = 100,
+ .counter = 0,
+ .io_avg = 0
+ };
+
+ struct disk_stats stats_base;
+ memset(&stats_base, 0, sizeof(stats_base));
+
+ int loop_size = 100;
+ for (int i = 0; i < loop_size; ++i) {
+ stats_base = disk_stats_add(stats_base, norm_inc);
+ dsm_acc.update(&stats_base);
+ EXPECT_EQ(dsm_acc.mValid, (uint32_t)(i + 1) >= dsm_acc.mWindow);
+ EXPECT_FALSE(dsm_acc.mStall);
+ }
+
+ stats_base = disk_stats_add(stats_base, stall_inc);
+ dsm_acc.update(&stats_base);
+ EXPECT_TRUE(dsm_acc.mValid);
+ EXPECT_TRUE(dsm_acc.mStall);
+
+ for (int i = 0; i < 10; ++i) {
+ stats_base = disk_stats_add(stats_base, norm_inc);
+ dsm_acc.update(&stats_base);
+ EXPECT_TRUE(dsm_acc.mValid);
+ EXPECT_FALSE(dsm_acc.mStall);
+ }
+}
+
+static void expect_increasing(struct disk_stats stats1, struct disk_stats stats2) {
+ EXPECT_LE(stats1.read_ios, stats2.read_ios);
+ EXPECT_LE(stats1.read_merges, stats2.read_merges);
+ EXPECT_LE(stats1.read_sectors, stats2.read_sectors);
+ EXPECT_LE(stats1.read_ticks, stats2.read_ticks);
+
+ EXPECT_LE(stats1.write_ios, stats2.write_ios);
+ EXPECT_LE(stats1.write_merges, stats2.write_merges);
+ EXPECT_LE(stats1.write_sectors, stats2.write_sectors);
+ EXPECT_LE(stats1.write_ticks, stats2.write_ticks);
+
+ EXPECT_LE(stats1.io_ticks, stats2.io_ticks);
+ EXPECT_LE(stats1.io_in_queue, stats2.io_in_queue);
+}
+
+TEST(storaged_test, disk_stats_publisher) {
+ // asserting that there is one file for diskstats
+ ASSERT_TRUE(access(MMC_DISK_STATS_PATH, R_OK) >= 0 || access(SDA_DISK_STATS_PATH, R_OK) >= 0);
+ disk_stats_publisher dsp;
+ struct disk_stats prev;
+ memset(&prev, 0, sizeof(prev));
+
+ for (int i = 0; i < TEST_LOOPS; ++i) {
+ dsp.update();
+ expect_increasing(prev, dsp.mPrevious);
+ prev = dsp.mPrevious;
+ pause(10);
+ }
+}
+