diff options
68 files changed, 3729 insertions, 3227 deletions
diff --git a/fingerprintd/Android.mk b/fingerprintd/Android.mk deleted file mode 100644 index 48b95258a..000000000 --- a/fingerprintd/Android.mk +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright (C) 2015 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_CFLAGS := -Wall -Wextra -Werror -Wunused -LOCAL_SRC_FILES := \ - FingerprintDaemonProxy.cpp \ - IFingerprintDaemon.cpp \ - IFingerprintDaemonCallback.cpp \ - fingerprintd.cpp -LOCAL_MODULE := fingerprintd -LOCAL_SHARED_LIBRARIES := \ - libbinder \ - liblog \ - libhardware \ - libutils \ - libkeystore_binder -include $(BUILD_EXECUTABLE) diff --git a/fingerprintd/FingerprintDaemonProxy.cpp b/fingerprintd/FingerprintDaemonProxy.cpp deleted file mode 100644 index b3c0cd7d4..000000000 --- a/fingerprintd/FingerprintDaemonProxy.cpp +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "fingerprintd" - -#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> - -#include "FingerprintDaemonProxy.h" - -namespace android { - -FingerprintDaemonProxy* FingerprintDaemonProxy::sInstance = NULL; - -// Supported fingerprint HAL version -static const uint16_t kVersion = HARDWARE_MODULE_API_VERSION(2, 1); - -FingerprintDaemonProxy::FingerprintDaemonProxy() : mModule(NULL), mDevice(NULL), mCallback(NULL) { - -} - -FingerprintDaemonProxy::~FingerprintDaemonProxy() { - closeHal(); -} - -void FingerprintDaemonProxy::hal_notify_callback(const fingerprint_msg_t *msg) { - FingerprintDaemonProxy* instance = FingerprintDaemonProxy::getInstance(); - const sp<IFingerprintDaemonCallback> callback = instance->mCallback; - if (callback == NULL) { - 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); - break; - case FINGERPRINT_ACQUIRED: - ALOGD("onAcquired(%d)", msg->data.acquired.acquired_info); - callback->onAcquired(device, msg->data.acquired.acquired_info); - break; - case FINGERPRINT_AUTHENTICATED: - ALOGD("onAuthenticated(fid=%d, gid=%d)", - msg->data.authenticated.finger.fid, - msg->data.authenticated.finger.gid); - if (msg->data.authenticated.finger.fid != 0) { - 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); - break; - case FINGERPRINT_TEMPLATE_ENROLLING: - ALOGD("onEnrollResult(fid=%d, gid=%d, rem=%d)", - msg->data.enroll.finger.fid, - msg->data.enroll.finger.gid, - msg->data.enroll.samples_remaining); - callback->onEnrollResult(device, - msg->data.enroll.finger.fid, - msg->data.enroll.finger.gid, - msg->data.enroll.samples_remaining); - break; - case FINGERPRINT_TEMPLATE_REMOVED: - ALOGD("onRemove(fid=%d, gid=%d)", - msg->data.removed.finger.fid, - msg->data.removed.finger.gid); - callback->onRemoved(device, - msg->data.removed.finger.fid, - msg->data.removed.finger.gid); - break; - case FINGERPRINT_TEMPLATE_ENUMERATING: - ALOGD("onEnumerate(fid=%d, gid=%d, rem=%d)", - msg->data.enumerated.finger.fid, - msg->data.enumerated.finger.gid, - msg->data.enumerated.remaining_templates); - callback->onEnumerate(device, - msg->data.enumerated.finger.fid, - msg->data.enumerated.finger.gid, - msg->data.enumerated.remaining_templates); - break; - default: - ALOGE("invalid msg type: %d", msg->type); - return; - } -} - -void FingerprintDaemonProxy::notifyKeystore(const uint8_t *auth_token, const size_t auth_token_length) { - if (auth_token != NULL && auth_token_length > 0) { - // TODO: cache service? - sp < IServiceManager > sm = defaultServiceManager(); - sp < IBinder > binder = sm->getService(String16("android.security.keystore")); - sp < IKeystoreService > service = interface_cast < IKeystoreService > (binder); - if (service != NULL) { - status_t ret = service->addAuthToken(auth_token, auth_token_length); - if (ret != ResponseCode::NO_ERROR) { - ALOGE("Falure sending auth token to KeyStore: %d", ret); - } - } else { - ALOGE("Unable to communicate with KeyStore"); - } - } -} - -void FingerprintDaemonProxy::init(const sp<IFingerprintDaemonCallback>& callback) { - if (mCallback != NULL && IInterface::asBinder(callback) != IInterface::asBinder(mCallback)) { - IInterface::asBinder(mCallback)->unlinkToDeath(this); - } - IInterface::asBinder(callback)->linkToDeath(this); - mCallback = callback; -} - -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); - return -1; - } - const hw_auth_token_t* authToken = reinterpret_cast<const hw_auth_token_t*>(token); - return mDevice->enroll(mDevice, authToken, groupId, timeout); -} - -uint64_t FingerprintDaemonProxy::preEnroll() { - return mDevice->pre_enroll(mDevice); -} - -int32_t FingerprintDaemonProxy::postEnroll() { - return mDevice->post_enroll(mDevice); -} - -int32_t FingerprintDaemonProxy::stopEnrollment() { - ALOG(LOG_VERBOSE, LOG_TAG, "stopEnrollment()\n"); - return mDevice->cancel(mDevice); -} - -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); -} - -int32_t FingerprintDaemonProxy::stopAuthentication() { - ALOG(LOG_VERBOSE, LOG_TAG, "stopAuthentication()\n"); - return mDevice->cancel(mDevice); -} - -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); -} - -int32_t FingerprintDaemonProxy::enumerate() { - ALOG(LOG_VERBOSE, LOG_TAG, "enumerate()\n"); - return mDevice->enumerate(mDevice); -} - -uint64_t FingerprintDaemonProxy::getAuthenticatorId() { - return mDevice->get_authenticator_id(mDevice); -} - -int32_t FingerprintDaemonProxy::setActiveGroup(int32_t groupId, const uint8_t* path, - ssize_t pathlen) { - if (pathlen >= PATH_MAX || pathlen <= 0) { - 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); -} - -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 (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 -} - -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; - return 0; -} - -void FingerprintDaemonProxy::binderDied(const wp<IBinder>& who) { - ALOGD("binder died"); - int err; - if (0 != (err = closeHal())) { - ALOGE("Can't close fingerprint device, error: %d", err); - } - if (IInterface::asBinder(mCallback) == who) { - mCallback = NULL; - } -} - -} diff --git a/fingerprintd/FingerprintDaemonProxy.h b/fingerprintd/FingerprintDaemonProxy.h deleted file mode 100644 index 145b4c936..000000000 --- a/fingerprintd/FingerprintDaemonProxy.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef FINGERPRINT_DAEMON_PROXY_H_ -#define FINGERPRINT_DAEMON_PROXY_H_ - -#include "IFingerprintDaemon.h" -#include "IFingerprintDaemonCallback.h" - -namespace android { - -class FingerprintDaemonProxy : public BnFingerprintDaemon { - public: - static FingerprintDaemonProxy* getInstance() { - if (sInstance == NULL) { - sInstance = new FingerprintDaemonProxy(); - } - return sInstance; - } - - // These reflect binder methods. - virtual void init(const sp<IFingerprintDaemonCallback>& callback); - virtual int32_t enroll(const uint8_t* token, ssize_t tokenLength, int32_t groupId, int32_t timeout); - virtual uint64_t preEnroll(); - virtual int32_t postEnroll(); - virtual int32_t stopEnrollment(); - virtual int32_t authenticate(uint64_t sessionId, uint32_t groupId); - virtual int32_t stopAuthentication(); - virtual int32_t remove(int32_t fingerId, int32_t groupId); - virtual int32_t enumerate(); - virtual uint64_t getAuthenticatorId(); - virtual int32_t setActiveGroup(int32_t groupId, const uint8_t* path, ssize_t pathLen); - virtual int64_t openHal(); - virtual int32_t closeHal(); - - 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); - - static FingerprintDaemonProxy* sInstance; - fingerprint_module_t const* mModule; - fingerprint_device_t* mDevice; - sp<IFingerprintDaemonCallback> mCallback; -}; - -} // namespace android - -#endif // FINGERPRINT_DAEMON_PROXY_H_ diff --git a/fingerprintd/IFingerprintDaemon.cpp b/fingerprintd/IFingerprintDaemon.cpp deleted file mode 100644 index bc4af5685..000000000 --- a/fingerprintd/IFingerprintDaemon.cpp +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2015, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -#include <inttypes.h> - -#include <binder/IPCThreadState.h> -#include <binder/IServiceManager.h> -#include <binder/PermissionCache.h> -#include <utils/String16.h> -#include <utils/Looper.h> -#include <keystore/IKeystoreService.h> -#include <keystore/keystore.h> // for error code -#include <hardware/hardware.h> -#include <hardware/fingerprint.h> -#include <hardware/hw_auth_token.h> -#include "IFingerprintDaemon.h" -#include "IFingerprintDaemonCallback.h" - -namespace android { - -static const String16 USE_FINGERPRINT_PERMISSION("android.permission.USE_FINGERPRINT"); -static const String16 MANAGE_FINGERPRINT_PERMISSION("android.permission.MANAGE_FINGERPRINT"); -static const String16 HAL_FINGERPRINT_PERMISSION("android.permission.MANAGE_FINGERPRINT"); // TODO -static const String16 DUMP_PERMISSION("android.permission.DUMP"); - -const android::String16 -IFingerprintDaemon::descriptor("android.hardware.fingerprint.IFingerprintDaemon"); - -const android::String16& -IFingerprintDaemon::getInterfaceDescriptor() const { - return IFingerprintDaemon::descriptor; -} - -status_t BnFingerprintDaemon::onTransact(uint32_t code, const Parcel& data, Parcel* reply, - uint32_t flags) { - switch(code) { - case AUTHENTICATE: { - CHECK_INTERFACE(IFingerprintDaemon, data, reply); - if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) { - return PERMISSION_DENIED; - } - const uint64_t sessionId = data.readInt64(); - const uint32_t groupId = data.readInt32(); - const int32_t ret = authenticate(sessionId, groupId); - reply->writeNoException(); - reply->writeInt32(ret); - return NO_ERROR; - }; - case CANCEL_AUTHENTICATION: { - CHECK_INTERFACE(IFingerprintDaemon, data, reply); - if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) { - return PERMISSION_DENIED; - } - const int32_t ret = stopAuthentication(); - reply->writeNoException(); - reply->writeInt32(ret); - return NO_ERROR; - } - case ENROLL: { - CHECK_INTERFACE(IFingerprintDaemon, data, reply); - if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) { - return PERMISSION_DENIED; - } - const ssize_t tokenSize = data.readInt32(); - const uint8_t* token = static_cast<const uint8_t *>(data.readInplace(tokenSize)); - const int32_t groupId = data.readInt32(); - const int32_t timeout = data.readInt32(); - const int32_t ret = enroll(token, tokenSize, groupId, timeout); - reply->writeNoException(); - reply->writeInt32(ret); - return NO_ERROR; - } - case CANCEL_ENROLLMENT: { - CHECK_INTERFACE(IFingerprintDaemon, data, reply); - if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) { - return PERMISSION_DENIED; - } - const int32_t ret = stopEnrollment(); - reply->writeNoException(); - reply->writeInt32(ret); - return NO_ERROR; - } - case PRE_ENROLL: { - CHECK_INTERFACE(IFingerprintDaemon, data, reply); - if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) { - return PERMISSION_DENIED; - } - const uint64_t ret = preEnroll(); - reply->writeNoException(); - reply->writeInt64(ret); - return NO_ERROR; - } - case POST_ENROLL: { - CHECK_INTERFACE(IFingerprintDaemon, data, reply); - if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) { - return PERMISSION_DENIED; - } - const int32_t ret = postEnroll(); - reply->writeNoException(); - reply->writeInt32(ret); - return NO_ERROR; - } - case REMOVE: { - CHECK_INTERFACE(IFingerprintDaemon, data, reply); - if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) { - return PERMISSION_DENIED; - } - const int32_t fingerId = data.readInt32(); - const int32_t groupId = data.readInt32(); - const int32_t ret = remove(fingerId, groupId); - reply->writeNoException(); - reply->writeInt32(ret); - return NO_ERROR; - } - case ENUMERATE: { - CHECK_INTERFACE(IFingerprintDaemon, data, reply); - if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) { - return PERMISSION_DENIED; - } - const int32_t ret = enumerate(); - reply->writeNoException(); - reply->writeInt32(ret); - return NO_ERROR; - } - case GET_AUTHENTICATOR_ID: { - CHECK_INTERFACE(IFingerprintDaemon, data, reply); - if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) { - return PERMISSION_DENIED; - } - const uint64_t ret = getAuthenticatorId(); - reply->writeNoException(); - reply->writeInt64(ret); - return NO_ERROR; - } - case SET_ACTIVE_GROUP: { - CHECK_INTERFACE(IFingerprintDaemon, data, reply); - if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) { - return PERMISSION_DENIED; - } - const int32_t group = data.readInt32(); - const ssize_t pathSize = data.readInt32(); - const uint8_t* path = static_cast<const uint8_t *>(data.readInplace(pathSize)); - const int32_t ret = setActiveGroup(group, path, pathSize); - reply->writeNoException(); - reply->writeInt32(ret); - return NO_ERROR; - } - case OPEN_HAL: { - CHECK_INTERFACE(IFingerprintDaemon, data, reply); - if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) { - return PERMISSION_DENIED; - } - const int64_t ret = openHal(); - reply->writeNoException(); - reply->writeInt64(ret); - return NO_ERROR; - } - case CLOSE_HAL: { - CHECK_INTERFACE(IFingerprintDaemon, data, reply); - if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) { - return PERMISSION_DENIED; - } - const int32_t ret = closeHal(); - reply->writeNoException(); - reply->writeInt32(ret); - return NO_ERROR; - } - case INIT: { - CHECK_INTERFACE(IFingerprintDaemon, data, reply); - if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) { - return PERMISSION_DENIED; - } - sp<IFingerprintDaemonCallback> callback = - interface_cast<IFingerprintDaemonCallback>(data.readStrongBinder()); - init(callback); - reply->writeNoException(); - return NO_ERROR; - } - default: - return BBinder::onTransact(code, data, reply, flags); - } -}; - -bool BnFingerprintDaemon::checkPermission(const String16& permission) { - const IPCThreadState* ipc = IPCThreadState::self(); - const int calling_pid = ipc->getCallingPid(); - const int calling_uid = ipc->getCallingUid(); - return PermissionCache::checkPermission(permission, calling_pid, calling_uid); -} - - -}; // namespace android diff --git a/fingerprintd/IFingerprintDaemon.h b/fingerprintd/IFingerprintDaemon.h deleted file mode 100644 index 23c36ff87..000000000 --- a/fingerprintd/IFingerprintDaemon.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef IFINGERPRINT_DAEMON_H_ -#define IFINGERPRINT_DAEMON_H_ - -#include <binder/IInterface.h> -#include <binder/Parcel.h> - -namespace android { - -class IFingerprintDaemonCallback; - -/* -* Abstract base class for native implementation of FingerprintService. -* -* Note: This must be kept manually in sync with IFingerprintDaemon.aidl -*/ -class IFingerprintDaemon : public IInterface, public IBinder::DeathRecipient { - public: - enum { - AUTHENTICATE = IBinder::FIRST_CALL_TRANSACTION + 0, - CANCEL_AUTHENTICATION = IBinder::FIRST_CALL_TRANSACTION + 1, - ENROLL = IBinder::FIRST_CALL_TRANSACTION + 2, - CANCEL_ENROLLMENT = IBinder::FIRST_CALL_TRANSACTION + 3, - PRE_ENROLL = IBinder::FIRST_CALL_TRANSACTION + 4, - REMOVE = IBinder::FIRST_CALL_TRANSACTION + 5, - GET_AUTHENTICATOR_ID = IBinder::FIRST_CALL_TRANSACTION + 6, - SET_ACTIVE_GROUP = IBinder::FIRST_CALL_TRANSACTION + 7, - OPEN_HAL = IBinder::FIRST_CALL_TRANSACTION + 8, - CLOSE_HAL = IBinder::FIRST_CALL_TRANSACTION + 9, - INIT = IBinder::FIRST_CALL_TRANSACTION + 10, - POST_ENROLL = IBinder::FIRST_CALL_TRANSACTION + 11, - ENUMERATE = IBinder::FIRST_CALL_TRANSACTION + 12, - }; - - IFingerprintDaemon() { } - virtual ~IFingerprintDaemon() { } - virtual const android::String16& getInterfaceDescriptor() const; - - // Binder interface methods - virtual void init(const sp<IFingerprintDaemonCallback>& callback) = 0; - virtual int32_t enroll(const uint8_t* token, ssize_t tokenLength, int32_t groupId, - int32_t timeout) = 0; - virtual uint64_t preEnroll() = 0; - virtual int32_t postEnroll() = 0; - virtual int32_t stopEnrollment() = 0; - virtual int32_t authenticate(uint64_t sessionId, uint32_t groupId) = 0; - virtual int32_t stopAuthentication() = 0; - virtual int32_t remove(int32_t fingerId, int32_t groupId) = 0; - virtual int32_t enumerate() = 0; - virtual uint64_t getAuthenticatorId() = 0; - virtual int32_t setActiveGroup(int32_t groupId, const uint8_t* path, ssize_t pathLen) = 0; - virtual int64_t openHal() = 0; - virtual int32_t closeHal() = 0; - - // DECLARE_META_INTERFACE - C++ client interface not needed - static const android::String16 descriptor; - static void hal_notify_callback(const fingerprint_msg_t *msg); -}; - -// ---------------------------------------------------------------------------- - -class BnFingerprintDaemon: public BnInterface<IFingerprintDaemon> { - public: - virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, - uint32_t flags = 0); - private: - bool checkPermission(const String16& permission); -}; - -} // namespace android - -#endif // IFINGERPRINT_DAEMON_H_ - diff --git a/fingerprintd/IFingerprintDaemonCallback.cpp b/fingerprintd/IFingerprintDaemonCallback.cpp deleted file mode 100644 index 1d75aa7fc..000000000 --- a/fingerprintd/IFingerprintDaemonCallback.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "IFingerprintDaemonCallback" -#include <stdint.h> -#include <sys/types.h> -#include <utils/Log.h> -#include <binder/Parcel.h> - -#include "IFingerprintDaemonCallback.h" - -namespace android { - -class BpFingerprintDaemonCallback : public BpInterface<IFingerprintDaemonCallback> -{ -public: - explicit BpFingerprintDaemonCallback(const sp<IBinder>& impl) : - BpInterface<IFingerprintDaemonCallback>(impl) { - } - virtual status_t onEnrollResult(int64_t devId, int32_t fpId, int32_t gpId, int32_t rem) { - Parcel data, reply; - data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor()); - data.writeInt64(devId); - data.writeInt32(fpId); - data.writeInt32(gpId); - data.writeInt32(rem); - return remote()->transact(ON_ENROLL_RESULT, data, &reply, IBinder::FLAG_ONEWAY); - } - - virtual status_t onAcquired(int64_t devId, int32_t acquiredInfo) { - Parcel data, reply; - data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor()); - data.writeInt64(devId); - data.writeInt32(acquiredInfo); - return remote()->transact(ON_ACQUIRED, data, &reply, IBinder::FLAG_ONEWAY); - } - - virtual status_t onAuthenticated(int64_t devId, int32_t fpId, int32_t gpId) { - Parcel data, reply; - data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor()); - data.writeInt64(devId); - data.writeInt32(fpId); - data.writeInt32(gpId); - return remote()->transact(ON_AUTHENTICATED, data, &reply, IBinder::FLAG_ONEWAY); - } - - virtual status_t onError(int64_t devId, int32_t error) { - Parcel data, reply; - data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor()); - data.writeInt64(devId); - data.writeInt32(error); - return remote()->transact(ON_ERROR, data, &reply, IBinder::FLAG_ONEWAY); - } - - virtual status_t onRemoved(int64_t devId, int32_t fpId, int32_t gpId) { - Parcel data, reply; - data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor()); - data.writeInt64(devId); - data.writeInt32(fpId); - data.writeInt32(gpId); - return remote()->transact(ON_REMOVED, data, &reply, IBinder::FLAG_ONEWAY); - } - - virtual status_t onEnumerate(int64_t devId, int32_t fpId, int32_t gpId, int32_t rem) { - Parcel data, reply; - data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor()); - data.writeInt64(devId); - data.writeInt32(fpId); - data.writeInt32(gpId); - data.writeInt32(rem); - return remote()->transact(ON_ENUMERATE, data, &reply, IBinder::FLAG_ONEWAY); - } -}; - -IMPLEMENT_META_INTERFACE(FingerprintDaemonCallback, - "android.hardware.fingerprint.IFingerprintDaemonCallback"); - -}; // namespace android diff --git a/fingerprintd/IFingerprintDaemonCallback.h b/fingerprintd/IFingerprintDaemonCallback.h deleted file mode 100644 index e343cb4f6..000000000 --- a/fingerprintd/IFingerprintDaemonCallback.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef IFINGERPRINT_DAEMON_CALLBACK_H_ -#define IFINGERPRINT_DAEMON_CALLBACK_H_ - -#include <inttypes.h> -#include <utils/Errors.h> -#include <binder/IInterface.h> -#include <binder/Parcel.h> - -namespace android { - -/* -* Communication channel back to FingerprintService.java -*/ -class IFingerprintDaemonCallback : public IInterface { - public: - // must be kept in sync with IFingerprintService.aidl - enum { - ON_ENROLL_RESULT = IBinder::FIRST_CALL_TRANSACTION + 0, - ON_ACQUIRED = IBinder::FIRST_CALL_TRANSACTION + 1, - ON_AUTHENTICATED = IBinder::FIRST_CALL_TRANSACTION + 2, - ON_ERROR = IBinder::FIRST_CALL_TRANSACTION + 3, - ON_REMOVED = IBinder::FIRST_CALL_TRANSACTION + 4, - ON_ENUMERATE = IBinder::FIRST_CALL_TRANSACTION + 5, - }; - - virtual status_t onEnrollResult(int64_t devId, int32_t fpId, int32_t gpId, int32_t rem) = 0; - virtual status_t onAcquired(int64_t devId, int32_t acquiredInfo) = 0; - virtual status_t onAuthenticated(int64_t devId, int32_t fingerId, int32_t groupId) = 0; - virtual status_t onError(int64_t devId, int32_t error) = 0; - virtual status_t onRemoved(int64_t devId, int32_t fingerId, int32_t groupId) = 0; - virtual status_t onEnumerate(int64_t devId, int32_t fingerId, int32_t groupId, int32_t rem) = 0; - - DECLARE_META_INTERFACE(FingerprintDaemonCallback); -}; - -}; // namespace android - -#endif // IFINGERPRINT_DAEMON_CALLBACK_H_ diff --git a/fingerprintd/fingerprintd.cpp b/fingerprintd/fingerprintd.cpp deleted file mode 100644 index 2fc2d0aec..000000000 --- a/fingerprintd/fingerprintd.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "fingerprintd" - -#include <binder/IPCThreadState.h> -#include <binder/IServiceManager.h> -#include <binder/PermissionCache.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 <log/log.h> -#include <utils/Log.h> -#include <utils/String16.h> - -#include "FingerprintDaemonProxy.h" - -int main() { - ALOGI("Starting " LOG_TAG); - android::sp<android::IServiceManager> serviceManager = android::defaultServiceManager(); - android::sp<android::FingerprintDaemonProxy> proxy = - android::FingerprintDaemonProxy::getInstance(); - android::status_t ret = serviceManager->addService( - android::FingerprintDaemonProxy::descriptor, proxy); - if (ret != android::OK) { - ALOGE("Couldn't register " LOG_TAG " binder service!"); - return -1; - } - - /* - * We're the only thread in existence, so we're just going to process - * Binder transaction as a single-threaded program. - */ - android::IPCThreadState::self()->joinThreadPool(); - ALOGI("Done"); - return 0; -} diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp index 48ddf29e8..44789cc90 100644 --- a/fs_mgr/fs_mgr_fstab.cpp +++ b/fs_mgr/fs_mgr_fstab.cpp @@ -34,7 +34,8 @@ struct fs_mgr_flag_values { int max_comp_streams; unsigned int zram_size; uint64_t reserved_size; - unsigned int file_encryption_mode; + unsigned int file_contents_mode; + unsigned int file_names_mode; unsigned int erase_blk_size; unsigned int logical_blk_size; }; @@ -94,15 +95,51 @@ static struct flag_list fs_mgr_flags[] = { { 0, 0 }, }; -#define EM_SOFTWARE 1 -#define EM_ICE 2 +#define EM_AES_256_XTS 1 +#define EM_ICE 2 +#define EM_AES_256_CTS 3 +#define EM_AES_256_HEH 4 -static struct flag_list encryption_modes[] = { - {"software", EM_SOFTWARE}, - {"ice", EM_ICE}, - {0, 0} +static const struct flag_list file_contents_encryption_modes[] = { + {"aes-256-xts", EM_AES_256_XTS}, + {"software", EM_AES_256_XTS}, /* alias for backwards compatibility */ + {"ice", EM_ICE}, /* hardware-specific inline cryptographic engine */ + {0, 0}, }; +static const struct flag_list file_names_encryption_modes[] = { + {"aes-256-cts", EM_AES_256_CTS}, + {"aes-256-heh", EM_AES_256_HEH}, + {0, 0}, +}; + +static unsigned int encryption_mode_to_flag(const struct flag_list *list, + const char *mode, const char *type) +{ + const struct flag_list *j; + + for (j = list; j->name; ++j) { + if (!strcmp(mode, j->name)) { + return j->flag; + } + } + LERROR << "Unknown " << type << " encryption mode: " << mode; + return 0; +} + +static const char *flag_to_encryption_mode(const struct flag_list *list, + unsigned int flag) +{ + const struct flag_list *j; + + for (j = list; j->name; ++j) { + if (flag == j->flag) { + return j->name; + } + } + return nullptr; +} + static uint64_t calculate_zram_size(unsigned int percentage) { uint64_t total; @@ -183,20 +220,28 @@ static int parse_flags(char *flags, struct flag_list *fl, * location of the keys. Get it and return it. */ flag_vals->key_loc = strdup(strchr(p, '=') + 1); - flag_vals->file_encryption_mode = EM_SOFTWARE; + flag_vals->file_contents_mode = EM_AES_256_XTS; + flag_vals->file_names_mode = EM_AES_256_CTS; } else if ((fl[i].flag == MF_FILEENCRYPTION) && flag_vals) { - /* The fileencryption flag is followed by an = and the - * type of the encryption. Get it and return it. + /* The fileencryption flag is followed by an = and + * the mode of contents encryption, then optionally a + * : and the mode of filenames encryption (defaults + * to aes-256-cts). Get it and return it. */ - const struct flag_list *j; - const char *mode = strchr(p, '=') + 1; - for (j = encryption_modes; j->name; ++j) { - if (!strcmp(mode, j->name)) { - flag_vals->file_encryption_mode = j->flag; - } + char *mode = strchr(p, '=') + 1; + char *colon = strchr(mode, ':'); + if (colon) { + *colon = '\0'; } - if (flag_vals->file_encryption_mode == 0) { - LERROR << "Unknown file encryption mode: " << mode; + flag_vals->file_contents_mode = + encryption_mode_to_flag(file_contents_encryption_modes, + mode, "file contents"); + if (colon) { + flag_vals->file_names_mode = + encryption_mode_to_flag(file_names_encryption_modes, + colon + 1, "file names"); + } else { + flag_vals->file_names_mode = EM_AES_256_CTS; } } else if ((fl[i].flag == MF_LENGTH) && flag_vals) { /* The length flag is followed by an = and the @@ -406,7 +451,8 @@ struct fstab *fs_mgr_read_fstab_file(FILE *fstab_file) fstab->recs[cnt].max_comp_streams = flag_vals.max_comp_streams; fstab->recs[cnt].zram_size = flag_vals.zram_size; fstab->recs[cnt].reserved_size = flag_vals.reserved_size; - fstab->recs[cnt].file_encryption_mode = flag_vals.file_encryption_mode; + fstab->recs[cnt].file_contents_mode = flag_vals.file_contents_mode; + fstab->recs[cnt].file_names_mode = flag_vals.file_names_mode; fstab->recs[cnt].erase_blk_size = flag_vals.erase_blk_size; fstab->recs[cnt].logical_blk_size = flag_vals.logical_blk_size; cnt++; @@ -567,15 +613,14 @@ int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab) return fstab->fs_mgr_flags & MF_FILEENCRYPTION; } -const char* fs_mgr_get_file_encryption_mode(const struct fstab_rec *fstab) +void fs_mgr_get_file_encryption_modes(const struct fstab_rec *fstab, + const char **contents_mode_ret, + const char **filenames_mode_ret) { - const struct flag_list *j; - for (j = encryption_modes; j->name; ++j) { - if (fstab->file_encryption_mode == j->flag) { - return j->name; - } - } - return NULL; + *contents_mode_ret = flag_to_encryption_mode(file_contents_encryption_modes, + fstab->file_contents_mode); + *filenames_mode_ret = flag_to_encryption_mode(file_names_encryption_modes, + fstab->file_names_mode); } int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab) diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h index a9deed948..597651448 100644 --- a/fs_mgr/include/fs_mgr.h +++ b/fs_mgr/include/fs_mgr.h @@ -76,7 +76,8 @@ struct fstab_rec { int max_comp_streams; unsigned int zram_size; uint64_t reserved_size; - unsigned int file_encryption_mode; + unsigned int file_contents_mode; + unsigned int file_names_mode; unsigned int erase_blk_size; unsigned int logical_blk_size; }; @@ -118,7 +119,9 @@ int fs_mgr_is_nonremovable(const struct fstab_rec *fstab); int fs_mgr_is_verified(const struct fstab_rec *fstab); int fs_mgr_is_encryptable(const struct fstab_rec *fstab); int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab); -const char* fs_mgr_get_file_encryption_mode(const struct fstab_rec *fstab); +void fs_mgr_get_file_encryption_modes(const struct fstab_rec *fstab, + const char **contents_mode_ret, + const char **filenames_mode_ret); int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab); int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab); int fs_mgr_is_notrim(struct fstab_rec *fstab); diff --git a/gatekeeperd/Android.mk b/gatekeeperd/Android.mk index 3f7895554..0dfd9d8a9 100644 --- a/gatekeeperd/Android.mk +++ b/gatekeeperd/Android.mk @@ -33,7 +33,12 @@ LOCAL_SHARED_LIBRARIES := \ 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 96bda07a5..86b6287c4 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 @@ static const String16 DUMP_PERMISSION("android.permission.DUMP"); 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 @@ public: 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 @@ public: 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 @@ public: 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; @@ -250,9 +304,9 @@ public: sp<IBinder> binder = sm->getService(String16("android.security.keystore")); sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder); if (service != NULL) { - status_t ret = service->addAuthToken(*auth_token, *auth_token_length); - if (ret != ResponseCode::NO_ERROR) { - ALOGE("Falure sending auth token to KeyStore: %d", ret); + auto ret = service->addAuthToken(*auth_token, *auth_token_length); + if (!ret.isOk()) { + ALOGE("Failure sending auth token to KeyStore: %" PRId32, int32_t(ret)); } } else { ALOGE("Unable to communicate with KeyStore"); @@ -295,8 +349,8 @@ public: } 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 @@ public: 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 @@ public: } 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 b292725b9..8b5996442 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 @@ LOCAL_STATIC_LIBRARIES := libutils libbase libbinder include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) +LOCAL_SRC_FILES := \ + healthd_mode_android.cpp \ + BatteryPropertiesRegistrar.cpp + +LOCAL_MODULE := libhealthd_android +LOCAL_EXPORT_C_INCLUDE_DIRS := \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/include + +LOCAL_STATIC_LIBRARIES := \ + libbatterymonitor \ + libbatteryservice \ + 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 -LOCAL_SHARED_LIBRARIES += libsuspend endif + LOCAL_SRC_FILES := \ - healthd_mode_android.cpp \ healthd_mode_charger.cpp \ - AnimationParser.cpp \ - BatteryPropertiesRegistrar.cpp \ + AnimationParser.cpp -LOCAL_MODULE := libhealthd_internal -LOCAL_C_INCLUDES := bootable/recovery +LOCAL_MODULE := libhealthd_charger +LOCAL_C_INCLUDES := bootable/recovery $(LOCAL_PATH)/include LOCAL_EXPORT_C_INCLUDE_DIRS := \ $(LOCAL_PATH) \ - $(LOCAL_PATH)/include \ + $(LOCAL_PATH)/include LOCAL_STATIC_LIBRARIES := \ - libbatterymonitor \ - libbatteryservice \ - libbinder \ libminui \ libpng \ libz \ @@ -51,11 +62,14 @@ LOCAL_STATIC_LIBRARIES := \ libm \ libc \ -include $(BUILD_STATIC_LIBRARY) +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 @@ LOCAL_CHARGER_NO_UI := true 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 @@ include $(BUILD_PHONY_PACKAGE) _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 0c90a5456..4007203b2 100644 --- a/healthd/BatteryMonitor.cpp +++ b/healthd/BatteryMonitor.cpp @@ -141,6 +141,7 @@ BatteryMonitor::PowerSupplyType BatteryMonitor::readPowerSupplyType(const String 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 }, @@ -347,6 +348,7 @@ int BatteryMonitor::getChargeStatus() { status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) { status_t ret = BAD_VALUE; + std::string buf; val->valueInt64 = LONG_MIN; @@ -399,6 +401,15 @@ status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) { } break; + case BATTERY_PROP_BATTERY_STATUS: + if (mAlwaysPluggedDevice) { + val->valueInt64 = BATTERY_STATUS_CHARGING; + } else { + val->valueInt64 = getChargeStatus(); + } + ret = NO_ERROR; + break; + default: break; } diff --git a/healthd/charger.cpp b/healthd/charger.cpp new file mode 100644 index 000000000..5a8fe1a8b --- /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 aa6735d71..cae6c4c3c 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> -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, -}; +#include <android/hardware/health/1.0/IHealth.h> +#include <android/hardware/health/1.0/types.h> +#include <hal_conversion.h> -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; +using namespace android; -// -1 for no epoll timeout -static int awake_poll_interval = -1; +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; -static int wakealarm_wake_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST; +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 BatteryMonitor* gBatteryMonitor; +// device specific hal interface; +static sp<IHealth> gHealth; -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 -}; - -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*/) { -} +// default energy counter property redirect to talk to device +// HAL +static int healthd_board_get_energy_counter(int64_t *energy) { -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; + }); -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"); + return result == Result::SUCCESS ? OK : NAME_NOT_FOUND; } -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); +void healthd_board_init(struct healthd_config *config) { - // 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. + // Initialize the board HAL - Equivalent of healthd_board_init(config) + // in charger/recovery mode. - 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"); + gHealth = IHealth::getService("health"); + if (gHealth == nullptr) { + KLOG_WARNING(LOG_TAG, "unable to get HAL interface, using defaults\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); + 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 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(); +int healthd_board_battery_update(struct android::BatteryProperties *props) { + int logthis = 0; - 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); - } + if (gHealth == nullptr) { + return logthis; } - 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; - } + HealthInfo info; + convertToHealthInfo(props, info); + gHealth->update(info, + [=, &logthis] (int32_t ret, const auto &infoOut) { + logthis = ret; + convertFromHealthInfo(infoOut, props); + }); - healthd_board_init(&healthd_config); - healthd_mode_ops->init(&healthd_config); - wakealarm_init(); - uevent_init(); - gBatteryMonitor = new BatteryMonitor(); - gBatteryMonitor->init(&healthd_config); - return 0; + return logthis; } -int main(int argc, char **argv) { - int ch; - int ret; +int main(int /*argc*/, char ** /*argv*/) { - 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 eb55773de..000000000 --- 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 000000000..659991918 --- /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 323ef52fd..c6123137a 100644 --- a/healthd/healthd_mode_android.cpp +++ b/healthd/healthd_mode_android.cpp @@ -42,6 +42,9 @@ int healthd_mode_android_preparetowait(void) { return -1; } +void healthd_mode_android_heartbeat(void) { +} + static void binder_event(uint32_t /*epevents*/) { IPCThreadState::self()->handlePolledCommands(); } diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp index 91774c6bc..49a534c32 100644 --- a/healthd/healthd_mode_charger.cpp +++ b/healthd/healthd_mode_charger.cpp @@ -39,12 +39,12 @@ #include <linux/netlink.h> #include <batteryservice/BatteryService.h> -#include <cutils/android_reboot.h> #include <cutils/klog.h> #include <cutils/misc.h> #include <cutils/uevent.h> #include <cutils/properties.h> #include <minui/minui.h> +#include <sys/reboot.h> #ifdef CHARGER_ENABLE_SUSPEND #include <suspend/autosuspend.h> @@ -636,7 +636,7 @@ static void process_key(struct charger *charger, int code, int64_t now) } else { if (charger->batt_anim->cur_level >= charger->boot_min_cap) { LOGW("[%" PRId64 "] rebooting\n", now); - android_reboot(ANDROID_RB_RESTART, 0, 0); + reboot(RB_AUTOBOOT); } else { LOGV("[%" PRId64 "] ignore power-button press, battery level " "less than minimum\n", now); @@ -691,7 +691,7 @@ static void handle_power_supply_state(struct charger *charger, int64_t now) now, (int64_t)UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check); } else if (now >= charger->next_pwr_check) { LOGW("[%" PRId64 "] shutting down\n", now); - android_reboot(ANDROID_RB_POWEROFF, 0, 0); + reboot(RB_POWER_OFF); } else { /* otherwise we already have a shutdown timer scheduled */ } diff --git a/include/system/graphics-base.h b/include/system/graphics-base.h new file mode 100644 index 000000000..2aac2d87c --- /dev/null +++ b/include/system/graphics-base.h @@ -0,0 +1,139 @@ +// 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_1010102 = 43, // 0x2B + 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_DISPLAY_P3_LINEAR = 139067392, // ((STANDARD_DCI_P3 | TRANSFER_LINEAR) | RANGE_FULL) + HAL_DATASPACE_DISPLAY_P3 = 143261696, // ((STANDARD_DCI_P3 | TRANSFER_SRGB) | 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 + HAL_DATASPACE_SENSOR = 4097, // 0x1001 +} 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, + HAL_COLOR_MODE_DISPLAY_P3 = 9, +} 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 ae10fa095..1a9918797 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 @@ extern "C" { #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. @@ -623,795 +238,24 @@ struct android_depth_points { }; /** - * 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, + * These structures are used to define the reference display's + * capabilities for HDR content. Display engine can use this + * to better tone map content to user's display. + * Color is defined in CIE XYZ coordinates + */ +struct android_xy_color { + float x; + float y; +}; - /* Device supports hybrid log-gamma HDR */ - HAL_HDR_HLG = 3 -} android_hdr_t; +struct android_smpte2086_metadata { + struct android_xy_color displayPrimaryRed; + struct android_xy_color displayPrimaryGreen; + struct android_xy_color displayPrimaryBlue; + struct android_xy_color whitePoint; + float maxLuminance; + float minLuminance; +}; #ifdef __cplusplus } diff --git a/include/system/radio.h b/include/system/radio.h index 03b252e30..acf3ea787 100644 --- a/include/system/radio.h +++ b/include/system/radio.h @@ -81,7 +81,7 @@ typedef enum { } 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_metadata radio_metadata_t; @@ -109,10 +109,10 @@ typedef struct radio_hal_am_band_config { 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 @@ typedef struct radio_hal_properties { 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 @@ typedef struct radio_properties { 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 @@ typedef struct radio_properties { * 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 @@ typedef unsigned int radio_event_type_t; /* 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 @@ typedef struct radio_hal_event { /* 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 f43970549..c3407731b 100644 --- a/include/system/window.h +++ b/include/system/window.h @@ -121,8 +121,9 @@ typedef struct ANativeWindowBuffer int stride; int format; int usage; + uintptr_t layerCount; - void* reserved[2]; + void* reserved[1]; buffer_handle_t handle; @@ -297,6 +298,25 @@ enum { * 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,11 @@ enum { 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_GET_REFRESH_CYCLE_DURATION= 23, + NATIVE_WINDOW_GET_NEXT_FRAME_ID = 24, + NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS = 25, + NATIVE_WINDOW_GET_COMPOSITOR_TIMING = 26, + NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27, }; /* parameter for NATIVE_WINDOW_[API_][DIS]CONNECT */ @@ -996,15 +1020,49 @@ static inline int native_window_set_auto_refresh( return window->perform(window, NATIVE_WINDOW_SET_AUTO_REFRESH, autoRefresh); } +static inline int native_window_get_refresh_cycle_duration( + struct ANativeWindow* window, + int64_t* outRefreshDuration) +{ + return window->perform(window, NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION, + outRefreshDuration); +} + +static inline int native_window_get_next_frame_id( + struct ANativeWindow* window, uint64_t* frameId) +{ + return window->perform(window, NATIVE_WINDOW_GET_NEXT_FRAME_ID, frameId); +} + +static inline int native_window_enable_frame_timestamps( + struct ANativeWindow* window, bool enable) +{ + return window->perform(window, NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS, + enable); +} + +static inline int native_window_get_compositor_timing( + struct ANativeWindow* window, + int64_t* compositeDeadline, int64_t* compositeInterval, + int64_t* compositeToPresentLatency) +{ + return window->perform(window, NATIVE_WINDOW_GET_COMPOSITOR_TIMING, + compositeDeadline, compositeInterval, compositeToPresentLatency); +} + static inline int native_window_get_frame_timestamps( - struct ANativeWindow* window, uint32_t framesAgo, - int64_t* outPostedTime, int64_t* outAcquireTime, - int64_t* outRefreshStartTime, int64_t* outGlCompositionDoneTime, - int64_t* outDisplayRetireTime, int64_t* outReleaseTime) + struct ANativeWindow* window, uint64_t frameId, + int64_t* outRequestedPresentTime, int64_t* outAcquireTime, + int64_t* outLatchTime, int64_t* outFirstRefreshStartTime, + int64_t* outLastRefreshStartTime, int64_t* outGpuCompositionDoneTime, + int64_t* outDisplayPresentTime, int64_t* outDisplayRetireTime, + int64_t* outDequeueReadyTime, int64_t* outReleaseTime) { return window->perform(window, NATIVE_WINDOW_GET_FRAME_TIMESTAMPS, - framesAgo, outPostedTime, outAcquireTime, outRefreshStartTime, - outGlCompositionDoneTime, outDisplayRetireTime, outReleaseTime); + frameId, outRequestedPresentTime, outAcquireTime, outLatchTime, + outFirstRefreshStartTime, outLastRefreshStartTime, + outGpuCompositionDoneTime, outDisplayPresentTime, + outDisplayRetireTime, outDequeueReadyTime, outReleaseTime); } diff --git a/init/builtins.cpp b/init/builtins.cpp index 2388edcf7..8ab5e3008 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -704,6 +704,9 @@ static int do_powerctl(const std::vector<std::string>& args) { } else if (strncmp(command, "reboot", 6) == 0) { cmd = ANDROID_RB_RESTART2; len = 6; + } else if (strncmp(command, "thermal-shutdown", 16) == 0) { + cmd = ANDROID_RB_THERMOFF; + len = 16; } else { LOG(ERROR) << "powerctl: unrecognized command '" << command << "'"; return -EINVAL; diff --git a/libcutils/android_reboot.c b/libcutils/android_reboot.c index 159a9d427..06026d125 100644 --- a/libcutils/android_reboot.c +++ b/libcutils/android_reboot.c @@ -189,11 +189,56 @@ out: free_entries(&ro_entries); } +static void save_reboot_reason(int cmd, const char *arg) +{ + FILE *fp; + const char *reason = NULL; + + fp = fopen(LAST_REBOOT_REASON_FILE, "w"); + if (fp == NULL) { + KLOG_WARNING(TAG, "Error creating " LAST_REBOOT_REASON_FILE + ": %s\n", strerror(errno)); + return; + } + switch (cmd) { + case ANDROID_RB_RESTART: + reason = "restart"; + break; + + case ANDROID_RB_POWEROFF: + reason = "power-off"; + break; + + case ANDROID_RB_RESTART2: + reason = arg && strlen(arg) ? arg : "restart"; + break; + + case ANDROID_RB_THERMOFF: + reason = "thermal-shutdown"; + break; + + default: + fprintf(fp,"0x%08X\n", cmd); + break; + } + + if (reason) { + if (fprintf(fp, "%s\n", reason) < 0) { + KLOG_WARNING(TAG, "Error writing " LAST_REBOOT_REASON_FILE + ": %s\n", strerror(errno)); + } + } + + fclose(fp); +} + int android_reboot_with_callback( int cmd, int flags __unused, const char *arg, void (*cb_on_remount)(const struct mntent*)) { int ret; + + save_reboot_reason(cmd, arg); remount_ro(cb_on_remount); switch (cmd) { case ANDROID_RB_RESTART: @@ -209,6 +254,10 @@ int android_reboot_with_callback( LINUX_REBOOT_CMD_RESTART2, arg); break; + case ANDROID_RB_THERMOFF: + ret = reboot(RB_POWER_OFF); + break; + default: ret = -1; } diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c index 7e27c3e67..394a89703 100644 --- a/libcutils/fs_config.c +++ b/libcutils/fs_config.c @@ -149,9 +149,14 @@ static const struct fs_path_config android_files[] = { "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/libcutils/include/cutils/android_reboot.h b/libcutils/include/cutils/android_reboot.h index a3861a02d..2e3b42986 100644 --- a/libcutils/include/cutils/android_reboot.h +++ b/libcutils/include/cutils/android_reboot.h @@ -25,10 +25,14 @@ __BEGIN_DECLS #define ANDROID_RB_RESTART 0xDEAD0001 #define ANDROID_RB_POWEROFF 0xDEAD0002 #define ANDROID_RB_RESTART2 0xDEAD0003 +#define ANDROID_RB_THERMOFF 0xDEAD0004 /* Properties */ #define ANDROID_RB_PROPERTY "sys.powerctl" +/* Android reboot reason stored in this file */ +#define LAST_REBOOT_REASON_FILE "/data/misc/reboot/last_reboot_reason" + int android_reboot(int cmd, int flags, const char *arg); int android_reboot_with_callback( int cmd, int flags, const char *arg, diff --git a/libmemtrack/Android.bp b/libmemtrack/Android.bp index 98413ddcc..68c580a45 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 8c0ab891c..2134a6ffe 100644 --- a/libmemtrack/include/memtrack/memtrack.h +++ b/libmemtrack/include/memtrack/memtrack.h @@ -35,16 +35,6 @@ extern "C" { 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 9ed945147..000000000 --- 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 <hardware/memtrack.h> -#include <log/log.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 000000000..e83f18189 --- /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 <log/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(); + 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 eaadfa705..77c935e4a 100644 --- a/libmemtrack/memtrack_test.c +++ b/libmemtrack/memtrack_test.c @@ -82,12 +82,6 @@ int main(int argc, char *argv[]) (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 c70d45fe3..82a03ad95 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 @@ def main(): 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)) - else: - print("Unknown chunk type 0x%04X" % (chunk_type), end="") - 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])) + curtype = format("Unverified CRC32 0x%08X" % (crc)) else: - print() + print("Unknown chunk type 0x%04X" % (chunk_type)) + break + + 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 @@ def main(): 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 d27ceea68..d442c9433 100644 --- a/libsuspend/Android.bp +++ b/libsuspend/Android.bp @@ -4,8 +4,6 @@ cc_library { 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 54730c293..96e1c10d0 100644 --- a/libsuspend/autosuspend.c +++ b/libsuspend/autosuspend.c @@ -34,19 +34,6 @@ static int autosuspend_init(void) 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 77d8db0a6..000000000 --- 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 <log/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 809ee825e..000000000 --- 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 <log/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 84594c818..a8dd6737c 100644 --- a/libusbhost/include/usbhost/usbhost.h +++ b/libusbhost/include/usbhost/usbhost.h @@ -144,17 +144,17 @@ const struct usb_device_descriptor* usb_device_get_device_descriptor(struct usb_ * 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 @@ int usb_device_get_version(struct usb_device *device); /* 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 @@ void usb_request_free(struct usb_request *req); /* 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 68aca1774..7adb4f2f7 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 @@ const struct usb_device_descriptor* usb_device_get_device_descriptor(struct usb_ 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 @@ char* usb_device_get_string(struct usb_device *device, int id) // 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 @@ char* usb_device_get_string(struct usb_device *device, int id) 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 @@ char* usb_device_get_string(struct usb_device *device, int id) 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 @@ int usb_device_get_version(struct usb_device *device) 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 @@ int usb_request_queue(struct usb_request *req) 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; - - 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"); + // Poll until a request becomes available if there is a timeout + if (timeoutMillis > 0) { + struct pollfd p = {.fd = dev->fd, .events = POLLOUT, .revents = 0}; + + 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 @@ int usb_request_cancel(struct usb_request *req) 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 77e69e4b3..84bc028f8 100644 --- a/libutils/Looper.cpp +++ b/libutils/Looper.cpp @@ -83,6 +83,7 @@ Looper::Looper(bool allowNonCallbacks) : Looper::~Looper() { close(mWakeEventFd); + mWakeEventFd = -1; if (mEpollFd >= 0) { close(mEpollFd); } @@ -412,7 +413,8 @@ void Looper::wake() { 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 957aedb8f..1fa1d7a54 100644 --- a/libutils/SharedBuffer.cpp +++ b/libutils/SharedBuffer.cpp @@ -113,16 +113,26 @@ void SharedBuffer::acquire() const { 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/libutils/include/utils/SortedVector.h b/libutils/include/utils/SortedVector.h index 86f349645..d57465d33 100644 --- a/libutils/include/utils/SortedVector.h +++ b/libutils/include/utils/SortedVector.h @@ -37,18 +37,18 @@ class SortedVector : private SortedVectorImpl 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 @@ public: inline void clear() { VectorImpl::clear(); } - /*! + /*! * vector stats */ @@ -69,11 +69,11 @@ public: //! 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 @@ public: //! 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 @@ public: //! 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 @@ public: //! 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 @@ public: 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 @@ SortedVector<TYPE>::~SortedVector() { 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/libziparchive/testdata/bad_filename.zip b/libziparchive/testdata/bad_filename.zip Binary files differnew file mode 100644 index 000000000..294eaf562 --- /dev/null +++ b/libziparchive/testdata/bad_filename.zip diff --git a/libziparchive/testdata/crash.apk b/libziparchive/testdata/crash.apk Binary files differnew file mode 100644 index 000000000..d6dd52dd7 --- /dev/null +++ b/libziparchive/testdata/crash.apk diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc index 0ac6f2c0c..c2055b7f5 100644 --- a/libziparchive/zip_archive.cc +++ b/libziparchive/zip_archive.cc @@ -373,6 +373,11 @@ static int32_t ParseZipArchive(ZipArchive* archive) { 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 @@ static int32_t ParseZipArchive(ZipArchive* archive) { 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 9dd6cc0df..493a0ce86 100644 --- a/libziparchive/zip_archive_test.cc +++ b/libziparchive/zip_archive_test.cc @@ -38,6 +38,8 @@ static const std::string kMissingZip = "missing.zip"; 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 @@ static void SetZipString(ZipString* zip_str, const std::string& str) { 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/logd/LogBuffer.cpp b/logd/LogBuffer.cpp index 7613c1e98..e03731b70 100644 --- a/logd/LogBuffer.cpp +++ b/logd/LogBuffer.cpp @@ -183,7 +183,8 @@ static enum match_type identical(LogBufferElement* elem, LogBufferElement* last) lenr -= avcr - msgr; if (lenl != lenr) return DIFFERENT; if (fastcmp<memcmp>(avcl + strlen(avc), - avcr + strlen(avc), lenl)) return DIFFERENT; + avcr + strlen(avc), + lenl - strlen(avc))) return DIFFERENT; return SAME; } diff --git a/rootdir/etc/public.libraries.android.txt b/rootdir/etc/public.libraries.android.txt index e6c94ffe8..40819828c 100644 --- a/rootdir/etc/public.libraries.android.txt +++ b/rootdir/etc/public.libraries.android.txt @@ -1,4 +1,5 @@ libandroid.so +libaaudio.so libc.so libcamera2ndk.so libdl.so diff --git a/rootdir/etc/public.libraries.wear.txt b/rootdir/etc/public.libraries.wear.txt index 292730a10..9f0cde1d2 100644 --- a/rootdir/etc/public.libraries.wear.txt +++ b/rootdir/etc/public.libraries.wear.txt @@ -1,4 +1,5 @@ libandroid.so +libaaudio.so libc.so libcamera2ndk.so libdl.so diff --git a/rootdir/init.rc b/rootdir/init.rc index 1e5fa504f..fe7e3d030 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -306,7 +306,8 @@ on post-fs # 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 @@ -647,10 +648,9 @@ service ueventd /sbin/ueventd 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 36bb4430a..09db7b03d 100644 --- a/rootdir/init.zygote64_32.rc +++ b/rootdir/init.zygote64_32.rc @@ -13,7 +13,7 @@ service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-s onrestart restart wificond writepid /dev/cpuset/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 3f0f95fe2..95559d7ff 100644 --- a/sdcard/fuse.cpp +++ b/sdcard/fuse.cpp @@ -997,7 +997,7 @@ static int handle_open(struct fuse* fuse, struct fuse_handler* handler, { 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 @@ static int handle_open(struct fuse* fuse, struct fuse_handler* handler, } 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 @@ static int handle_opendir(struct fuse* fuse, struct fuse_handler* handler, { 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 @@ static int handle_opendir(struct fuse* fuse, struct fuse_handler* handler, } 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 @@ static int handle_init(struct fuse* fuse, struct fuse_handler* handler, 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 000000000..2adb14daa --- /dev/null +++ b/storaged/Android.mk @@ -0,0 +1,44 @@ +# Copyright 2016 The Android Open Source Project + +LOCAL_PATH := $(call my-dir) + +LIBSTORAGED_SHARED_LIBRARIES := \ + libbinder \ + libbase \ + libutils \ + libcutils \ + liblog \ + libsysutils \ + libpackagelistparser \ + libbatteryservice \ + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + storaged.cpp \ + storaged_service.cpp \ + storaged_utils.cpp \ + storaged_uid_monitor.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 000000000..2e25d4a29 --- /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)
\ No newline at end of file diff --git a/storaged/README.properties b/storaged/README.properties new file mode 100644 index 000000000..70e6026f0 --- /dev/null +++ b/storaged/README.properties @@ -0,0 +1,6 @@ +ro.storaged.event.interval # interval storaged scans for IO stats, in seconds +ro.storaged.event.perf_check # check for time spent in event loop, in microseconds +ro.storaged.disk_stats_pub # interval storaged publish disk stats, in seconds +ro.storaged.emmc_info_pub # interval storaged publish emmc info, in seconds +ro.storaged.uid_io.interval # interval storaged checks Per UID IO usage, in seconds +ro.storaged.uid_io.threshold # Per UID IO usage limit, in bytes diff --git a/storaged/include/storaged.h b/storaged/include/storaged.h new file mode 100644 index 000000000..591719e74 --- /dev/null +++ b/storaged/include/storaged.h @@ -0,0 +1,324 @@ +/* + * 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_ + +#include <semaphore.h> +#include <stdint.h> +#include <time.h> + +#include <queue> +#include <string> +#include <unordered_map> +#include <vector> + +#include <batteryservice/IBatteryPropertiesListener.h> + +#include "storaged_uid_monitor.h" + +using namespace android; + +#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 SECTOR_SIZE ( 512 ) +#define SEC_TO_MSEC ( 1000 ) +#define MSEC_TO_USEC ( 1000 ) +#define USEC_TO_NSEC ( 1000 ) +#define SEC_TO_USEC ( 1000000 ) +#define HOUR_TO_SEC ( 3600 ) +#define DAY_TO_SEC ( 3600 * 24 ) + +// 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 ( 9 ) // maximum length of the MMC version string, including NULL terminator +// 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 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" +#define UID_IO_STATS_PATH "/proc/uid_io/stats" + +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 ( 60 ) +#define DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH ( 3600 ) +#define DEFAULT_PERIODIC_CHORES_INTERVAL_EMMC_INFO_PUBLISH ( 86400 ) +#define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO ( 3600 ) +#define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO_LIMIT (300) + +// UID IO threshold in bytes +#define DEFAULT_PERIODIC_CHORES_UID_IO_THRESHOLD ( 1024 * 1024 * 1024ULL ) + +struct storaged_config { + int periodic_chores_interval_unit; + int periodic_chores_interval_disk_stats_publish; + int periodic_chores_interval_emmc_info_publish; + int periodic_chores_interval_uid_io; + bool proc_uid_io_available; // whether uid_io is accessible + bool emmc_available; // whether eMMC est_csd file is readable + bool diskstats_available; // whether diskstats is accessible + int event_time_check_usec; // check how much cputime spent in event loop +}; + +class storaged_t : public BnBatteryPropertiesListener { +private: + time_t mTimer; + storaged_config mConfig; + disk_stats_publisher mDiskStats; + disk_stats_monitor mDsm; + emmc_info_t mEmmcInfo; + uid_monitor mUidm; + time_t mStarttime; +public: + storaged_t(void); + ~storaged_t() {} + void event(void); + void event_checked(void); + void pause(void) { + sleep(mConfig.periodic_chores_interval_unit); + } + void set_privileged_fds(int fd_emmc) { + mEmmcInfo.set_emmc_fd(fd_emmc); + } + + time_t get_starttime(void) { + return mStarttime; + } + + std::unordered_map<uint32_t, struct uid_info> get_uids(void) { + return mUidm.get_uid_io_stats(); + } + std::map<uint64_t, std::vector<struct uid_record>> get_uid_records( + double hours, uint64_t threshold, bool force_report) { + return mUidm.dump(hours, threshold, force_report); + } + void update_uid_io_interval(int interval) { + if (interval >= DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO_LIMIT) { + mConfig.periodic_chores_interval_uid_io = interval; + } + } + + void init_battery_service(); + virtual void batteryPropertiesChanged(struct BatteryProperties props); +}; + +// Eventlog tag +// The content must match the definition in EventLogTags.logtags +#define EVENTLOGTAG_DISKSTATS ( 2732 ) +#define EVENTLOGTAG_EMMCINFO ( 2733 ) +#define EVENTLOGTAG_UID_IO_ALERT ( 2734 ) + +#endif /* _STORAGED_H_ */ diff --git a/storaged/include/storaged_service.h b/storaged/include/storaged_service.h new file mode 100644 index 000000000..a8ddf4c32 --- /dev/null +++ b/storaged/include/storaged_service.h @@ -0,0 +1,60 @@ +/* + * 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 { + DUMPUIDS = IBinder::FIRST_CALL_TRANSACTION, + }; + // Request the service to run the test function + virtual std::vector<struct uid_info> dump_uids(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 uid_info> dump_uids(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 uid_info> dump_uids(const char* option); + virtual status_t dump(int fd, const Vector<String16>& args); +}; + +sp<IStoraged> get_storaged_service(); + +#endif /* _STORAGED_SERVICE_H_ */
\ No newline at end of file diff --git a/storaged/include/storaged_uid_monitor.h b/storaged/include/storaged_uid_monitor.h new file mode 100644 index 000000000..031b7c4ee --- /dev/null +++ b/storaged/include/storaged_uid_monitor.h @@ -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. + */ + +#ifndef _STORAGED_UID_MONITOR_H_ +#define _STORAGED_UID_MONITOR_H_ + +#include <stdint.h> + +#include <string> +#include <unordered_map> +#include <vector> + +enum uid_stat_t { + FOREGROUND = 0, + BACKGROUND = 1, + UID_STATS = 2 +}; + +enum charger_stat_t { + CHARGER_OFF = 0, + CHARGER_ON = 1, + CHARGER_STATS = 2 +}; + +enum io_type_t { + READ = 0, + WRITE = 1, + IO_TYPES = 2 +}; + +struct uid_io_stats { + uint64_t rchar; // characters read + uint64_t wchar; // characters written + uint64_t read_bytes; // bytes read (from storage layer) + uint64_t write_bytes; // bytes written (to storage layer) +}; + +struct uid_info { + uint32_t uid; // user id + std::string name; // package name + struct uid_io_stats io[UID_STATS]; // [0]:foreground [1]:background +}; + +struct uid_io_usage { + uint64_t bytes[IO_TYPES][UID_STATS][CHARGER_STATS]; +}; + +struct uid_record { + std::string name; + struct uid_io_usage ios; +}; + +class uid_monitor { +private: + // last dump from /proc/uid_io/stats, uid -> uid_info + std::unordered_map<uint32_t, struct uid_info> last_uid_io_stats; + // current io usage for next report, app name -> uid_io_usage + std::unordered_map<std::string, struct uid_io_usage> curr_io_stats; + // io usage records, timestamp -> vector of events + std::map<uint64_t, std::vector<struct uid_record>> records; + // charger ON/OFF + charger_stat_t charger_stat; + // protects curr_io_stats, last_uid_io_stats, records and charger_stat + sem_t um_lock; + + // reads from /proc/uid_io/stats + std::unordered_map<uint32_t, struct uid_info> get_uid_io_stats_locked(); + // flushes curr_io_stats to records + void add_records_locked(uint64_t curr_ts); + // updates curr_io_stats and set last_uid_io_stats + void update_curr_io_stats_locked(); + +public: + uid_monitor(); + ~uid_monitor(); + // called by storaged main thread + void init(charger_stat_t stat); + // called by storaged -u + std::unordered_map<uint32_t, struct uid_info> get_uid_io_stats(); + // called by dumpsys + std::map<uint64_t, std::vector<struct uid_record>> dump( + double hours, uint64_t threshold, bool force_report); + // called by battery properties listener + void set_charger_state(charger_stat_t stat); + // called by storaged periodic_chore or dump with force_report + void report(); +}; + +#endif /* _STORAGED_UID_MONITOR_H_ */ diff --git a/storaged/include/storaged_utils.h b/storaged/include/storaged_utils.h new file mode 100644 index 000000000..2161c4008 --- /dev/null +++ b/storaged/include/storaged_utils.h @@ -0,0 +1,44 @@ +/* + * 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); + +// UID I/O +void sort_running_uids_info(std::vector<struct uid_info> &uids); + +// Logging +void log_console_running_uids_info(std::vector<struct uid_info> uids); + +void log_debug_disk_perf(struct disk_perf* perf, const char* type); + +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_ */ diff --git a/storaged/main.cpp b/storaged/main.cpp new file mode 100644 index 000000000..f5a8f3901 --- /dev/null +++ b/storaged/main.cpp @@ -0,0 +1,180 @@ +/* + * 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/logging.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/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; + + return 0; +} + +// Function of storaged's main thread +void* storaged_main(void* s) { + storaged_t* storaged = (storaged_t*)s; + + storaged->init_battery_service(); + + LOG_TO(SYSTEM, INFO) << "storaged: Start"; + + for (;;) { + storaged->event_checked(); + storaged->pause(); + } + return NULL; +} + +static void help_message(void) { + printf("usage: storaged [OPTION]\n"); + printf(" -u --uid Dump uid I/O usage to stdout\n"); + printf(" -s --start Start storaged (default)\n"); + fflush(stdout); +} + +int main(int argc, char** argv) { + int flag_main_service = 0; + int flag_dump_uid = 0; + 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'}, + {"uid", no_argument, 0, 'u'}, + {"help", no_argument, 0, 'h'} + }; + opt = getopt_long(argc, argv, ":skdhu0", long_options, &opt_idx); + if (opt == -1) { + break; + } + + switch (opt) { + case 's': + flag_main_service = 1; + break; + case 'u': + flag_dump_uid = 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_uid) { + fprintf(stderr, "Invalid arguments. Option \"start\" and \"dump\" cannot be used together.\n"); + help_message(); + return -1; + } + + if (flag_main_service) { // start main thread + 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); + + // Start the main thread of storaged + pthread_t storaged_main_thread; + errno = pthread_create(&storaged_main_thread, NULL, storaged_main, &storaged); + if (errno != 0) { + PLOG_TO(SYSTEM, ERROR) << "Failed to create main thread"; + return -1; + } + + defaultServiceManager()->addService(String16("storaged"), new Storaged()); + android::ProcessState::self()->startThreadPool(); + IPCThreadState::self()->joinThreadPool(); + pthread_join(storaged_main_thread, NULL); + + close(fd_emmc); + + return 0; + } + + if (flag_dump_uid) { + 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 uid_info> res = storaged_service->dump_uids(NULL); + + if (res.size() == 0) { + fprintf(stderr, "UID I/O is not readable in this version of kernel.\n"); + return 0; + } + + sort_running_uids_info(res); + log_console_running_uids_info(res); + + return 0; + } + + return 0; +} diff --git a/storaged/storaged.cpp b/storaged/storaged.cpp new file mode 100644 index 000000000..2f020742a --- /dev/null +++ b/storaged/storaged.cpp @@ -0,0 +1,284 @@ +/* + * 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 <batteryservice/BatteryServiceConstants.h> +#include <batteryservice/IBatteryPropertiesRegistrar.h> +#include <binder/IServiceManager.h> +#include <cutils/properties.h> +#include <log/log.h> + +#include <storaged.h> +#include <storaged_utils.h> + +/* disk_stats_publisher */ +void disk_stats_publisher::publish(void) { + // Logging + struct disk_perf perf = get_disk_perf(&mAccumulate); + log_debug_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); + log_debug_disk_perf(&mMean, "stalled_mean"); + log_debug_disk_perf(&mStd, "stalled_std"); + } else { + if (mStall) { + struct disk_perf acc_perf = get_disk_perf(&mAccumulate); + log_debug_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_event_emmc_info(&mInfo); + } +} + +void emmc_info_t::update(void) { + if (mFdEmmc >= 0) { + mValid = parse_emmc_ecsd(mFdEmmc, &mInfo); + } +} + +static sp<IBatteryPropertiesRegistrar> get_battery_properties_service() { + sp<IServiceManager> sm = defaultServiceManager(); + if (sm == NULL) return NULL; + + sp<IBinder> binder = sm->getService(String16("batteryproperties")); + if (binder == NULL) return NULL; + + sp<IBatteryPropertiesRegistrar> battery_properties = + interface_cast<IBatteryPropertiesRegistrar>(binder); + + return battery_properties; +} + +static inline charger_stat_t is_charger_on(int64_t prop) { + return (prop == BATTERY_STATUS_CHARGING || prop == BATTERY_STATUS_FULL) ? + CHARGER_ON : CHARGER_OFF; +} + +void storaged_t::batteryPropertiesChanged(struct BatteryProperties props) { + mUidm.set_charger_state(is_charger_on(props.batteryStatus)); +} + +void storaged_t::init_battery_service() { + sp<IBatteryPropertiesRegistrar> battery_properties = get_battery_properties_service(); + if (battery_properties == NULL) { + LOG_TO(SYSTEM, WARNING) << "failed to find batteryproperties service"; + return; + } + + struct BatteryProperty val; + battery_properties->getProperty(BATTERY_PROP_BATTERY_STATUS, &val); + mUidm.init(is_charger_on(val.valueInt64)); + + // register listener after init uid_monitor + battery_properties->registerListener(this); +} + +/* 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_uid_io_available = (access(UID_IO_STATS_PATH, R_OK) == 0); + + mConfig.periodic_chores_interval_unit = + property_get_int32("ro.storaged.event.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT); + + mConfig.event_time_check_usec = + property_get_int32("ro.storaged.event.perf_check", 0); + + mConfig.periodic_chores_interval_disk_stats_publish = + property_get_int32("ro.storaged.disk_stats_pub", DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH); + + mConfig.periodic_chores_interval_emmc_info_publish = + property_get_int32("ro.storaged.emmc_info_pub", DEFAULT_PERIODIC_CHORES_INTERVAL_EMMC_INFO_PUBLISH); + + mConfig.periodic_chores_interval_uid_io = + property_get_int32("ro.storaged.uid_io.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO); + + 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.emmc_available && mTimer && + (mTimer % mConfig.periodic_chores_interval_emmc_info_publish) == 0) { + mEmmcInfo.update(); + mEmmcInfo.publish(); + } + + if (mConfig.proc_uid_io_available && mTimer && + (mTimer % mConfig.periodic_chores_interval_uid_io) == 0) { + mUidm.report(); + } + + mTimer += mConfig.periodic_chores_interval_unit; +} + +void storaged_t::event_checked(void) { + struct timespec start_ts, end_ts; + bool check_time = true; + + if (mConfig.event_time_check_usec && + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_ts) < 0) { + check_time = false; + static time_t state_a; + IF_ALOG_RATELIMIT_LOCAL(300, &state_a) { + PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed"; + } + } + + event(); + + if (mConfig.event_time_check_usec && check_time) { + if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_ts) < 0) { + static time_t state_b; + IF_ALOG_RATELIMIT_LOCAL(300, &state_b) { + PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed"; + } + return; + } + int64_t cost = (end_ts.tv_sec - start_ts.tv_sec) * SEC_TO_USEC + + (end_ts.tv_nsec - start_ts.tv_nsec) / USEC_TO_NSEC; + if (cost > mConfig.event_time_check_usec) { + LOG_TO(SYSTEM, ERROR) + << "event loop spent " << cost << " usec, threshold " + << mConfig.event_time_check_usec << " usec"; + } + } +} diff --git a/storaged/storaged.rc b/storaged/storaged.rc new file mode 100644 index 000000000..bb7c623fd --- /dev/null +++ b/storaged/storaged.rc @@ -0,0 +1,6 @@ +service storaged /system/bin/storaged + class main + file /d/mmc0/mmc0:0001/ext_csd r + writepid /dev/cpuset/system-background/tasks + user root + group system package_info
\ No newline at end of file diff --git a/storaged/storaged_service.cpp b/storaged/storaged_service.cpp new file mode 100644 index 000000000..9c8cbf0e8 --- /dev/null +++ b/storaged/storaged_service.cpp @@ -0,0 +1,156 @@ +/* + * 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 <stdint.h> + +#include <vector> + +#include <binder/IBinder.h> +#include <binder/IInterface.h> + +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <binder/PermissionCache.h> +#include <private/android_filesystem_config.h> + +#include <storaged.h> +#include <storaged_service.h> + +extern storaged_t storaged; + +std::vector<struct uid_info> BpStoraged::dump_uids(const char* /*option*/) { + Parcel data, reply; + data.writeInterfaceToken(IStoraged::getInterfaceDescriptor()); + + remote()->transact(DUMPUIDS, data, &reply); + + uint32_t res_size = reply.readInt32(); + std::vector<struct uid_info> res(res_size); + for (auto&& uid : res) { + uid.uid = reply.readInt32(); + uid.name = reply.readCString(); + reply.read(&uid.io, sizeof(uid.io)); + } + return res; +} +IMPLEMENT_META_INTERFACE(Storaged, "Storaged"); + +status_t BnStoraged::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { + switch(code) { + case DUMPUIDS: { + if (!data.checkInterface(this)) + return BAD_TYPE; + std::vector<struct uid_info> res = dump_uids(NULL); + reply->writeInt32(res.size()); + for (auto uid : res) { + reply->writeInt32(uid.uid); + reply->writeCString(uid.name.c_str()); + reply->write(&uid.io, sizeof(uid.io)); + } + return NO_ERROR; + } + break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +std::vector<struct uid_info> Storaged::dump_uids(const char* /* option */) { + std::vector<struct uid_info> uids_v; + std::unordered_map<uint32_t, struct uid_info> uids_m = storaged.get_uids(); + + for (const auto& it : uids_m) { + uids_v.push_back(it.second); + } + return uids_v; +} + +status_t Storaged::dump(int fd, const Vector<String16>& args) { + IPCThreadState* self = IPCThreadState::self(); + const int pid = self->getCallingPid(); + const int uid = self->getCallingUid(); + if ((uid != AID_SHELL) && + !PermissionCache::checkPermission( + String16("android.permission.DUMP"), pid, uid)) { + return PERMISSION_DENIED; + } + + double hours = 0; + int time_window = 0; + uint64_t threshold = 0; + bool force_report = false; + for (size_t i = 0; i < args.size(); i++) { + const auto& arg = args[i]; + if (arg == String16("--hours")) { + if (++i >= args.size()) + break; + hours = stod(String16::std_string(args[i])); + continue; + } + if (arg == String16("--time_window")) { + if (++i >= args.size()) + break; + time_window = stoi(String16::std_string(args[i])); + continue; + } + if (arg == String16("--threshold")) { + if (++i >= args.size()) + break; + threshold = stoll(String16::std_string(args[i])); + continue; + } + if (arg == String16("--force")) { + force_report = true; + continue; + } + } + + const std::map<uint64_t, std::vector<struct uid_record>>& records = + storaged.get_uid_records(hours, threshold, force_report); + for (const auto& it : records) { + dprintf(fd, "%llu\n", (unsigned long long)it.first); + for (const auto& record : it.second) { + dprintf(fd, "%s %llu %llu %llu %llu %llu %llu %llu %llu\n", + record.name.c_str(), + (unsigned long long)record.ios.bytes[READ][FOREGROUND][CHARGER_OFF], + (unsigned long long)record.ios.bytes[WRITE][FOREGROUND][CHARGER_OFF], + (unsigned long long)record.ios.bytes[READ][BACKGROUND][CHARGER_OFF], + (unsigned long long)record.ios.bytes[WRITE][BACKGROUND][CHARGER_OFF], + (unsigned long long)record.ios.bytes[READ][FOREGROUND][CHARGER_ON], + (unsigned long long)record.ios.bytes[WRITE][FOREGROUND][CHARGER_ON], + (unsigned long long)record.ios.bytes[READ][BACKGROUND][CHARGER_ON], + (unsigned long long)record.ios.bytes[WRITE][BACKGROUND][CHARGER_ON]); + } + } + + if (time_window) { + storaged.update_uid_io_interval(time_window); + } + + return NO_ERROR; +} + +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; +} diff --git a/storaged/storaged_uid_monitor.cpp b/storaged/storaged_uid_monitor.cpp new file mode 100644 index 000000000..49d0d4861 --- /dev/null +++ b/storaged/storaged_uid_monitor.cpp @@ -0,0 +1,263 @@ +/* + * 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 <stdint.h> +#include <time.h> + +#include <string> +#include <sstream> +#include <unordered_map> + +#include <android-base/file.h> +#include <android-base/logging.h> +#include <android-base/macros.h> +#include <android-base/stringprintf.h> +#include <log/log_event_list.h> +#include <packagelistparser/packagelistparser.h> + +#include "storaged.h" +#include "storaged_uid_monitor.h" + +using namespace android; +using namespace android::base; + +static bool packagelist_parse_cb(pkg_info* info, void* userdata) +{ + std::unordered_map<uint32_t, struct uid_info>* uids = + reinterpret_cast<std::unordered_map<uint32_t, struct uid_info>*>(userdata); + + if (uids->find(info->uid) != uids->end()) { + (*uids)[info->uid].name = info->name; + } + + packagelist_free(info); + return true; +} + +std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats() +{ + std::unique_ptr<lock_t> lock(new lock_t(&um_lock)); + return get_uid_io_stats_locked(); +}; + +std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats_locked() +{ + std::unordered_map<uint32_t, struct uid_info> uid_io_stats; + std::string buffer; + if (!android::base::ReadFileToString(UID_IO_STATS_PATH, &buffer)) { + PLOG_TO(SYSTEM, ERROR) << UID_IO_STATS_PATH << ": ReadFileToString failed"; + return uid_io_stats; + } + + std::stringstream ss(buffer); + struct uid_info u; + bool refresh_uid = false; + + while (ss >> u.uid) { + ss >> u.io[FOREGROUND].rchar >> u.io[FOREGROUND].wchar + >> u.io[FOREGROUND].read_bytes >> u.io[FOREGROUND].write_bytes + >> u.io[BACKGROUND].rchar >> u.io[BACKGROUND].wchar + >> u.io[BACKGROUND].read_bytes >> u.io[BACKGROUND].write_bytes; + + if (!ss.good()) { + ss.clear(std::ios_base::badbit); + break; + } + + if (last_uid_io_stats.find(u.uid) == last_uid_io_stats.end()) { + refresh_uid = true; + u.name = std::to_string(u.uid); + } else { + u.name = last_uid_io_stats[u.uid].name; + } + uid_io_stats[u.uid] = u; + } + + if (!ss.eof() || ss.bad()) { + uid_io_stats.clear(); + LOG_TO(SYSTEM, ERROR) << "read UID IO stats failed"; + } + + if (refresh_uid) { + packagelist_parse(packagelist_parse_cb, &uid_io_stats); + } + + return uid_io_stats; +} + +static const int MAX_UID_RECORDS_SIZE = 1000 * 48; // 1000 uids in 48 hours + +static inline int records_size( + const std::map<uint64_t, std::vector<struct uid_record>>& records) +{ + int count = 0; + for (auto const& it : records) { + count += it.second.size(); + } + return count; +} + +static struct uid_io_usage zero_io_usage; + +void uid_monitor::add_records_locked(uint64_t curr_ts) +{ + // remove records more than 5 days old + if (curr_ts > 5 * DAY_TO_SEC) { + auto it = records.lower_bound(curr_ts - 5 * DAY_TO_SEC); + records.erase(records.begin(), it); + } + + std::vector<struct uid_record> new_records; + for (const auto& p : curr_io_stats) { + struct uid_record record = {}; + record.name = p.first; + record.ios = p.second; + if (memcmp(&record.ios, &zero_io_usage, sizeof(struct uid_io_usage))) { + new_records.push_back(record); + } + } + + curr_io_stats.clear(); + + if (new_records.empty()) + return; + + // make some room for new records + int overflow = records_size(records) + + new_records.size() - MAX_UID_RECORDS_SIZE; + while (overflow > 0 && records.size() > 0) { + overflow -= records[0].size(); + records.erase(records.begin()); + } + + records[curr_ts].insert(records[curr_ts].end(), + new_records.begin(), new_records.end()); +} + +std::map<uint64_t, std::vector<struct uid_record>> uid_monitor::dump( + double hours, uint64_t threshold, bool force_report) +{ + if (force_report) { + report(); + } + + std::unique_ptr<lock_t> lock(new lock_t(&um_lock)); + + std::map<uint64_t, std::vector<struct uid_record>> dump_records; + uint64_t first_ts = 0; + + if (hours != 0) { + first_ts = time(NULL) - hours * HOUR_TO_SEC; + } + + for (auto it = records.lower_bound(first_ts); it != records.end(); ++it) { + const std::vector<struct uid_record>& recs = it->second; + std::vector<struct uid_record> filtered; + + for (const auto& rec : recs) { + if (rec.ios.bytes[READ][FOREGROUND][CHARGER_ON] + + rec.ios.bytes[READ][FOREGROUND][CHARGER_OFF] + + rec.ios.bytes[READ][BACKGROUND][CHARGER_ON] + + rec.ios.bytes[READ][BACKGROUND][CHARGER_OFF] + + rec.ios.bytes[WRITE][FOREGROUND][CHARGER_ON] + + rec.ios.bytes[WRITE][FOREGROUND][CHARGER_OFF] + + rec.ios.bytes[WRITE][BACKGROUND][CHARGER_ON] + + rec.ios.bytes[WRITE][BACKGROUND][CHARGER_OFF] > threshold) { + filtered.push_back(rec); + } + } + dump_records.insert( + std::pair<uint64_t, std::vector<struct uid_record>>(it->first, filtered)); + } + + return dump_records; +} + +void uid_monitor::update_curr_io_stats_locked() +{ + std::unordered_map<uint32_t, struct uid_info> uid_io_stats = + get_uid_io_stats_locked(); + if (uid_io_stats.empty()) { + return; + } + + for (const auto& it : uid_io_stats) { + const struct uid_info& uid = it.second; + + if (curr_io_stats.find(uid.name) == curr_io_stats.end()) { + curr_io_stats[uid.name] = {}; + } + + struct uid_io_usage& usage = curr_io_stats[uid.name]; + int64_t fg_rd_delta = uid.io[FOREGROUND].read_bytes - + last_uid_io_stats[uid.uid].io[FOREGROUND].read_bytes; + int64_t bg_rd_delta = uid.io[BACKGROUND].read_bytes - + last_uid_io_stats[uid.uid].io[BACKGROUND].read_bytes; + int64_t fg_wr_delta = uid.io[FOREGROUND].write_bytes - + last_uid_io_stats[uid.uid].io[FOREGROUND].write_bytes; + int64_t bg_wr_delta = uid.io[BACKGROUND].write_bytes - + last_uid_io_stats[uid.uid].io[BACKGROUND].write_bytes; + + usage.bytes[READ][FOREGROUND][charger_stat] += + (fg_rd_delta < 0) ? uid.io[FOREGROUND].read_bytes : fg_rd_delta; + usage.bytes[READ][BACKGROUND][charger_stat] += + (bg_rd_delta < 0) ? uid.io[BACKGROUND].read_bytes : bg_rd_delta; + usage.bytes[WRITE][FOREGROUND][charger_stat] += + (fg_wr_delta < 0) ? uid.io[FOREGROUND].write_bytes : fg_wr_delta; + usage.bytes[WRITE][BACKGROUND][charger_stat] += + (bg_wr_delta < 0) ? uid.io[BACKGROUND].write_bytes : bg_wr_delta; + } + + last_uid_io_stats = uid_io_stats; +} + +void uid_monitor::report() +{ + std::unique_ptr<lock_t> lock(new lock_t(&um_lock)); + + update_curr_io_stats_locked(); + add_records_locked(time(NULL)); +} + +void uid_monitor::set_charger_state(charger_stat_t stat) +{ + std::unique_ptr<lock_t> lock(new lock_t(&um_lock)); + + if (charger_stat == stat) { + return; + } + + update_curr_io_stats_locked(); + charger_stat = stat; +} + +void uid_monitor::init(charger_stat_t stat) +{ + charger_stat = stat; + last_uid_io_stats = get_uid_io_stats(); +} + +uid_monitor::uid_monitor() +{ + sem_init(&um_lock, 0, 1); +} + +uid_monitor::~uid_monitor() +{ + sem_destroy(&um_lock); +} diff --git a/storaged/storaged_utils.cpp b/storaged/storaged_utils.cpp new file mode 100644 index 000000000..1ef89af68 --- /dev/null +++ b/storaged/storaged_utils.cpp @@ -0,0 +1,341 @@ +/* + * 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 <iomanip> +#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 <log/log_event_list.h> + +#include <storaged.h> +#include <storaged_utils.h> + +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) { + PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed"; + return false; + } + + std::string buffer; + if (!android::base::ReadFileToString(disk_stats_path, &buffer)) { + PLOG_TO(SYSTEM, ERROR) << disk_stats_path << ": ReadFileToString failed."; + 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) { + LOG_TO(SYSTEM, WARNING) << "Two dis-continuous periods of diskstats" + << " are added. dst end with " << dst->end_time + << ", src start with " << src->start_time; + } + + 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)) { + PLOG_TO(SYSTEM, ERROR) << "ReadFdToString failed."; + return false; + } + + if (buffer.length() < EXT_CSD_FILE_MIN_SIZE) { + LOG_TO(SYSTEM, ERROR) << "EMMC ext csd file has truncated content. " + << "File length: " << buffer.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) { + LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_CSD_REV."; + return false; + } + ss.clear(); + + static const char* ver_str[] = { + "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0" + }; + + strlcpy(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) { + LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_PRE_EOL_INFO."; + 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) { + LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_DEVICE_LIFE_TIME_EST_TYP_A."; + 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) { + LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_DEVICE_LIFE_TIME_EST_TYP_B."; + return false; + } + ss.clear(); + + return true; +} + +static bool cmp_uid_info(struct uid_info l, struct uid_info r) { + // Compare background I/O first. + for (int i = UID_STATS - 1; i >= 0; i--) { + uint64_t l_bytes = l.io[i].read_bytes + l.io[i].write_bytes; + uint64_t r_bytes = r.io[i].read_bytes + r.io[i].write_bytes; + uint64_t l_chars = l.io[i].rchar + l.io[i].wchar; + uint64_t r_chars = r.io[i].rchar + r.io[i].wchar; + + if (l_bytes != r_bytes) { + return l_bytes > r_bytes; + } + if (l_chars != r_chars) { + return l_chars > r_chars; + } + } + + return l.name < r.name; +} + +void sort_running_uids_info(std::vector<struct uid_info> &uids) { + std::sort(uids.begin(), uids.end(), cmp_uid_info); +} + +// Logging functions +void log_console_running_uids_info(std::vector<struct uid_info> uids) { +// Sample Output: +// Application FG Read FG Write FG Read FG Write BG Read BG Write BG Read BG Write +// NAME/UID Characters Characters Bytes Bytes Characters Characters Bytes Bytes +// ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- +// com.google.android.gsf.login 0 0 0 0 57195097 5137089 176386048 6512640 +// com.google.android.googlequicksearchbox 0 0 0 0 4196821 12123468 34295808 13225984 +// 1037 4572 537 0 0 131352 5145643 34263040 5144576 +// com.google.android.youtube 2182 70 0 0 63969383 482939 38731776 466944 + + // Title + printf("Per-UID I/O stats\n"); + printf(" Application FG Read FG Write FG Read FG Write BG Read BG Write BG Read BG Write\n" + " NAME/UID Characters Characters Bytes Bytes Characters Characters Bytes Bytes\n" + " ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------\n"); + + for (const auto& uid : uids) { + printf("%50s%15ju%15ju%15ju%15ju%15ju%15ju%15ju%15ju\n", uid.name.c_str(), + uid.io[0].rchar, uid.io[0].wchar, uid.io[0].read_bytes, uid.io[0].write_bytes, + uid.io[1].rchar, uid.io[1].wchar, uid.io[1].read_bytes, uid.io[1].write_bytes); + } + fflush(stdout); +} + +#if DEBUG +void log_debug_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; + + LOG_TO(SYSTEM, INFO) << "perf(ios) " << type + << " rd:" << perf->read_perf << "KB/s(" << perf->read_ios << "/s)" + << " wr:" << perf->write_perf << "KB/s(" << perf->write_ios << "/s)" + << " q:" << perf->queue; +} +#else +void log_debug_disk_perf(struct disk_perf* /* perf */, const char* /* type */) {} +#endif + +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; + + android_log_event_list(EVENTLOGTAG_DISKSTATS) + << 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 + << (uint64_t)stats->io_avg << stats->io_ticks << stats->io_in_queue + << LOG_ID_EVENTS; +} + +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_event_list(EVENTLOGTAG_EMMCINFO) + << info->mmc_ver << info->eol << info->lifetime_a << info->lifetime_b + << LOG_ID_EVENTS; +} diff --git a/storaged/tests/Android.mk b/storaged/tests/Android.mk new file mode 100644 index 000000000..26d04b162 --- /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 libpackagelistparser +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 000000000..9e03c5018 --- /dev/null +++ b/storaged/tests/storaged_test.cpp @@ -0,0 +1,373 @@ +/* + * 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" + +static void pause(uint32_t sec) { + const char* path = "/cache/test"; + int fd = open(path, O_WRONLY | O_CREAT, 0600); + 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))); + } +} + +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 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); +} + +#define TEST_LOOPS 20 +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); + } +} + |
