diff options
137 files changed, 7371 insertions, 6521 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 8f5d3ad2c..41a58683e 100644 --- a/fs_mgr/fs_mgr_fstab.cpp +++ b/fs_mgr/fs_mgr_fstab.cpp @@ -41,7 +41,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; }; @@ -101,15 +102,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; @@ -208,20 +245,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 @@ -540,7 +585,8 @@ static 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++; @@ -808,15 +854,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_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h index 17e1fb176..8a18ec030 100644 --- a/fs_mgr/include_fstab/fstab/fstab.h +++ b/fs_mgr/include_fstab/fstab/fstab.h @@ -57,7 +57,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; }; @@ -77,7 +78,8 @@ int fs_mgr_is_verifyatboot(const struct fstab_rec* fstab); int fs_mgr_is_avb(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(const 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..e6eb3bc25 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(); - 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 4e3b885ce..676ee4151 100644 --- a/healthd/BatteryMonitor.cpp +++ b/healthd/BatteryMonitor.cpp @@ -351,6 +351,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; @@ -403,6 +404,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..ed1971a97 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(); + 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_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 d7d14544d..c76762d37 100644 --- a/healthd/healthd_mode_charger.cpp +++ b/healthd/healthd_mode_charger.cpp @@ -40,12 +40,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> @@ -642,7 +642,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); @@ -697,7 +697,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/init/selinux.cpp b/init/selinux.cpp index b9305ed47..32bb3dc6d 100644 --- a/init/selinux.cpp +++ b/init/selinux.cpp @@ -227,6 +227,18 @@ bool FindPrecompiledSplitPolicy(std::string* file) { return true; } +bool GetVendorMappingVersion(std::string* plat_vers) { + if (!ReadFirstLine("/vendor/etc/selinux/plat_sepolicy_vers.txt", plat_vers)) { + PLOG(ERROR) << "Failed to read /vendor/etc/selinux/plat_sepolicy_vers.txt"; + return false; + } + if (plat_vers->empty()) { + LOG(ERROR) << "No version present in plat_sepolicy_vers.txt"; + return false; + } + return true; +} + constexpr const char plat_policy_cil_file[] = "/system/etc/selinux/plat_sepolicy.cil"; bool IsSplitPolicyDevice() { @@ -277,14 +289,20 @@ bool LoadSplitPolicy() { return false; } + // Determine which mapping file to include + std::string vend_plat_vers; + if (!GetVendorMappingVersion(&vend_plat_vers)) { + return false; + } + std::string mapping_file("/system/etc/selinux/mapping/" + vend_plat_vers + ".cil"); // clang-format off const char* compile_args[] = { "/system/bin/secilc", plat_policy_cil_file, - "-M", "true", + "-M", "true", "-G", "-N", // Target the highest policy language version supported by the kernel "-c", std::to_string(max_policy_version).c_str(), - "/system/etc/selinux/mapping_sepolicy.cil", + mapping_file.c_str(), "/vendor/etc/selinux/nonplat_sepolicy.cil", "-o", compiled_sepolicy, // We don't care about file_contexts output by the compiler @@ -362,8 +380,21 @@ void SelinuxRestoreContext() { selinux_android_restorecon("/dev/random", 0); selinux_android_restorecon("/dev/urandom", 0); selinux_android_restorecon("/dev/__properties__", 0); + + selinux_android_restorecon("/file_contexts.bin", 0); + selinux_android_restorecon("/plat_file_contexts", 0); + selinux_android_restorecon("/nonplat_file_contexts", 0); selinux_android_restorecon("/plat_property_contexts", 0); selinux_android_restorecon("/nonplat_property_contexts", 0); + selinux_android_restorecon("/plat_seapp_contexts", 0); + selinux_android_restorecon("/nonplat_seapp_contexts", 0); + selinux_android_restorecon("/plat_service_contexts", 0); + selinux_android_restorecon("/nonplat_service_contexts", 0); + selinux_android_restorecon("/plat_hwservice_contexts", 0); + selinux_android_restorecon("/nonplat_hwservice_contexts", 0); + selinux_android_restorecon("/sepolicy", 0); + selinux_android_restorecon("/vndservice_contexts", 0); + selinux_android_restorecon("/dev/block", SELINUX_ANDROID_RESTORECON_RECURSE); selinux_android_restorecon("/dev/device-mapper", 0); diff --git a/libappfuse/Android.bp b/libappfuse/Android.bp index bfe5aaf97..29ffe3244 100644 --- a/libappfuse/Android.bp +++ b/libappfuse/Android.bp @@ -18,6 +18,7 @@ cc_library_shared { "FuseAppLoop.cc", "FuseBuffer.cc", "FuseBridgeLoop.cc", + "EpollController.cc", ] } diff --git a/libappfuse/EpollController.cc b/libappfuse/EpollController.cc new file mode 100644 index 000000000..9daeab8f4 --- /dev/null +++ b/libappfuse/EpollController.cc @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specic language governing permissions and + * limitations under the License. + */ + +#include <android-base/logging.h> + +#include "libappfuse/EpollController.h" + +namespace android { +namespace fuse { + +EpollController::EpollController(base::unique_fd&& poll_fd) : poll_fd_(std::move(poll_fd)) { +} + +bool EpollController::Wait(size_t event_count) { + events_.resize(event_count); + const int result = TEMP_FAILURE_RETRY(epoll_wait(poll_fd_, events_.data(), event_count, -1)); + if (result == -1) { + PLOG(ERROR) << "Failed to wait for epoll"; + return false; + } + events_.resize(result); + return true; +} + +bool EpollController::AddFd(int fd, int events, void* data) { + return InvokeControl(EPOLL_CTL_ADD, fd, events, data); +} + +bool EpollController::UpdateFd(int fd, int events, void* data) { + return InvokeControl(EPOLL_CTL_MOD, fd, events, data); +} + +bool EpollController::RemoveFd(int fd) { + return InvokeControl(EPOLL_CTL_DEL, fd, /* events */ 0, nullptr); +} + +const std::vector<epoll_event>& EpollController::events() const { + return events_; +} + +bool EpollController::InvokeControl(int op, int fd, int events, void* data) const { + epoll_event event; + memset(&event, 0, sizeof(event)); + event.events = events; + event.data.ptr = data; + if (epoll_ctl(poll_fd_, op, fd, &event) == -1) { + PLOG(ERROR) << "epoll_ctl() error op=" << op; + return false; + } + return true; +} +} +} diff --git a/libappfuse/FuseAppLoop.cc b/libappfuse/FuseAppLoop.cc index a31880e41..b6bc191b7 100644 --- a/libappfuse/FuseAppLoop.cc +++ b/libappfuse/FuseAppLoop.cc @@ -16,205 +16,232 @@ #include "libappfuse/FuseAppLoop.h" +#include <sys/eventfd.h> #include <sys/stat.h> #include <android-base/logging.h> #include <android-base/unique_fd.h> +#include "libappfuse/EpollController.h" + namespace android { namespace fuse { namespace { -void HandleLookUp(FuseBuffer* buffer, FuseAppLoopCallback* callback) { - // AppFuse does not support directory structure now. - // It can lookup only files under the mount point. - if (buffer->request.header.nodeid != FUSE_ROOT_ID) { - LOG(ERROR) << "Nodeid is not FUSE_ROOT_ID."; - buffer->response.Reset(0, -ENOENT, buffer->request.header.unique); - return; - } - - // Ensure that the filename ends with 0. - const size_t filename_length = - buffer->request.header.len - sizeof(fuse_in_header); - if (buffer->request.lookup_name[filename_length - 1] != 0) { - LOG(ERROR) << "File name does not end with 0."; - buffer->response.Reset(0, -ENOENT, buffer->request.header.unique); - return; - } - - const uint64_t inode = - static_cast<uint64_t>(atol(buffer->request.lookup_name)); - if (inode == 0 || inode == LONG_MAX) { - LOG(ERROR) << "Invalid filename"; - buffer->response.Reset(0, -ENOENT, buffer->request.header.unique); - return; - } - - const int64_t size = callback->OnGetSize(inode); - if (size < 0) { - buffer->response.Reset(0, size, buffer->request.header.unique); - return; - } - - buffer->response.Reset(sizeof(fuse_entry_out), 0, - buffer->request.header.unique); - buffer->response.entry_out.nodeid = inode; - buffer->response.entry_out.attr_valid = 10; - buffer->response.entry_out.entry_valid = 10; - buffer->response.entry_out.attr.ino = inode; - buffer->response.entry_out.attr.mode = S_IFREG | 0777; - buffer->response.entry_out.attr.size = size; -} +bool HandleLookUp(FuseAppLoop* loop, FuseBuffer* buffer, FuseAppLoopCallback* callback) { + // AppFuse does not support directory structure now. + // It can lookup only files under the mount point. + if (buffer->request.header.nodeid != FUSE_ROOT_ID) { + LOG(ERROR) << "Nodeid is not FUSE_ROOT_ID."; + return loop->ReplySimple(buffer->request.header.unique, -ENOENT); + } -void HandleGetAttr(FuseBuffer* buffer, FuseAppLoopCallback* callback) { - const uint64_t nodeid = buffer->request.header.nodeid; - int64_t size; - uint32_t mode; - if (nodeid == FUSE_ROOT_ID) { - size = 0; - mode = S_IFDIR | 0777; - } else { - size = callback->OnGetSize(buffer->request.header.nodeid); - if (size < 0) { - buffer->response.Reset(0, size, buffer->request.header.unique); - return; + // Ensure that the filename ends with 0. + const size_t filename_length = buffer->request.header.len - sizeof(fuse_in_header); + if (buffer->request.lookup_name[filename_length - 1] != 0) { + LOG(ERROR) << "File name does not end with 0."; + return loop->ReplySimple(buffer->request.header.unique, -ENOENT); + } + + const uint64_t inode = static_cast<uint64_t>(atol(buffer->request.lookup_name)); + if (inode == 0 || inode == LONG_MAX) { + LOG(ERROR) << "Invalid filename"; + return loop->ReplySimple(buffer->request.header.unique, -ENOENT); } - mode = S_IFREG | 0777; - } - - buffer->response.Reset(sizeof(fuse_attr_out), 0, - buffer->request.header.unique); - buffer->response.attr_out.attr_valid = 10; - buffer->response.attr_out.attr.ino = nodeid; - buffer->response.attr_out.attr.mode = mode; - buffer->response.attr_out.attr.size = size; -} -void HandleOpen(FuseBuffer* buffer, FuseAppLoopCallback* callback) { - const int32_t file_handle = callback->OnOpen(buffer->request.header.nodeid); - if (file_handle < 0) { - buffer->response.Reset(0, file_handle, buffer->request.header.unique); - return; - } - buffer->response.Reset(sizeof(fuse_open_out), kFuseSuccess, - buffer->request.header.unique); - buffer->response.open_out.fh = file_handle; + callback->OnLookup(buffer->request.header.unique, inode); + return true; } -void HandleFsync(FuseBuffer* buffer, FuseAppLoopCallback* callback) { - buffer->response.Reset(0, callback->OnFsync(buffer->request.header.nodeid), - buffer->request.header.unique); +bool HandleGetAttr(FuseAppLoop* loop, FuseBuffer* buffer, FuseAppLoopCallback* callback) { + if (buffer->request.header.nodeid == FUSE_ROOT_ID) { + return loop->ReplyGetAttr(buffer->request.header.unique, buffer->request.header.nodeid, 0, + S_IFDIR | 0777); + } else { + callback->OnGetAttr(buffer->request.header.unique, buffer->request.header.nodeid); + return true; + } } -void HandleRelease(FuseBuffer* buffer, FuseAppLoopCallback* callback) { - buffer->response.Reset(0, callback->OnRelease(buffer->request.header.nodeid), - buffer->request.header.unique); +bool HandleRead(FuseAppLoop* loop, FuseBuffer* buffer, FuseAppLoopCallback* callback) { + if (buffer->request.read_in.size > kFuseMaxRead) { + return loop->ReplySimple(buffer->request.header.unique, -EINVAL); + } + + callback->OnRead(buffer->request.header.unique, buffer->request.header.nodeid, + buffer->request.read_in.offset, buffer->request.read_in.size); + return true; } -void HandleRead(FuseBuffer* buffer, FuseAppLoopCallback* callback) { - const uint64_t unique = buffer->request.header.unique; - const uint64_t nodeid = buffer->request.header.nodeid; - const uint64_t offset = buffer->request.read_in.offset; - const uint32_t size = buffer->request.read_in.size; - - if (size > kFuseMaxRead) { - buffer->response.Reset(0, -EINVAL, buffer->request.header.unique); - return; - } - - const int32_t read_size = callback->OnRead(nodeid, offset, size, - buffer->response.read_data); - if (read_size < 0) { - buffer->response.Reset(0, read_size, buffer->request.header.unique); - return; - } - - buffer->response.ResetHeader(read_size, kFuseSuccess, unique); +bool HandleWrite(FuseAppLoop* loop, FuseBuffer* buffer, FuseAppLoopCallback* callback) { + if (buffer->request.write_in.size > kFuseMaxWrite) { + return loop->ReplySimple(buffer->request.header.unique, -EINVAL); + } + + callback->OnWrite(buffer->request.header.unique, buffer->request.header.nodeid, + buffer->request.write_in.offset, buffer->request.write_in.size, + buffer->request.write_data); + return true; } -void HandleWrite(FuseBuffer* buffer, FuseAppLoopCallback* callback) { - const uint64_t unique = buffer->request.header.unique; - const uint64_t nodeid = buffer->request.header.nodeid; - const uint64_t offset = buffer->request.write_in.offset; - const uint32_t size = buffer->request.write_in.size; - - if (size > kFuseMaxWrite) { - buffer->response.Reset(0, -EINVAL, buffer->request.header.unique); - return; - } - - const int32_t write_size = callback->OnWrite(nodeid, offset, size, - buffer->request.write_data); - if (write_size < 0) { - buffer->response.Reset(0, write_size, buffer->request.header.unique); - return; - } - - buffer->response.Reset(sizeof(fuse_write_out), kFuseSuccess, unique); - buffer->response.write_out.size = write_size; +bool HandleMessage(FuseAppLoop* loop, FuseBuffer* buffer, int fd, FuseAppLoopCallback* callback) { + if (!buffer->request.Read(fd)) { + return false; + } + + const uint32_t opcode = buffer->request.header.opcode; + LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode; + switch (opcode) { + case FUSE_FORGET: + // Do not reply to FUSE_FORGET. + return true; + + case FUSE_LOOKUP: + return HandleLookUp(loop, buffer, callback); + + case FUSE_GETATTR: + return HandleGetAttr(loop, buffer, callback); + + case FUSE_OPEN: + callback->OnOpen(buffer->request.header.unique, buffer->request.header.nodeid); + return true; + + case FUSE_READ: + return HandleRead(loop, buffer, callback); + + case FUSE_WRITE: + return HandleWrite(loop, buffer, callback); + + case FUSE_RELEASE: + callback->OnRelease(buffer->request.header.unique, buffer->request.header.nodeid); + return true; + + case FUSE_FSYNC: + callback->OnFsync(buffer->request.header.unique, buffer->request.header.nodeid); + return true; + + default: + buffer->HandleNotImpl(); + return buffer->response.Write(fd); + } } } // namespace -bool StartFuseAppLoop(int raw_fd, FuseAppLoopCallback* callback) { - base::unique_fd fd(raw_fd); - FuseBuffer buffer; +FuseAppLoopCallback::~FuseAppLoopCallback() = default; + +FuseAppLoop::FuseAppLoop(base::unique_fd&& fd) : fd_(std::move(fd)) {} - LOG(DEBUG) << "Start fuse loop."; - while (callback->IsActive()) { - if (!buffer.request.Read(fd)) { - return false; +void FuseAppLoop::Break() { + const int64_t value = 1; + if (write(break_fd_, &value, sizeof(value)) == -1) { + PLOG(ERROR) << "Failed to send a break event"; } +} - const uint32_t opcode = buffer.request.header.opcode; - LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode; - switch (opcode) { - case FUSE_FORGET: - // Do not reply to FUSE_FORGET. - continue; +bool FuseAppLoop::ReplySimple(uint64_t unique, int32_t result) { + if (result == -ENOSYS) { + // We should not return -ENOSYS because the kernel stops delivering FUSE + // command after receiving -ENOSYS as a result for the command. + result = -EBADF; + } + FuseSimpleResponse response; + response.Reset(0, result, unique); + return response.Write(fd_); +} - case FUSE_LOOKUP: - HandleLookUp(&buffer, callback); - break; +bool FuseAppLoop::ReplyLookup(uint64_t unique, uint64_t inode, int64_t size) { + FuseSimpleResponse response; + response.Reset(sizeof(fuse_entry_out), 0, unique); + response.entry_out.nodeid = inode; + response.entry_out.attr_valid = 10; + response.entry_out.entry_valid = 10; + response.entry_out.attr.ino = inode; + response.entry_out.attr.mode = S_IFREG | 0777; + response.entry_out.attr.size = size; + return response.Write(fd_); +} - case FUSE_GETATTR: - HandleGetAttr(&buffer, callback); - break; +bool FuseAppLoop::ReplyGetAttr(uint64_t unique, uint64_t inode, int64_t size, int mode) { + CHECK(mode == (S_IFREG | 0777) || mode == (S_IFDIR | 0777)); + FuseSimpleResponse response; + response.Reset(sizeof(fuse_attr_out), 0, unique); + response.attr_out.attr_valid = 10; + response.attr_out.attr.ino = inode; + response.attr_out.attr.mode = mode; + response.attr_out.attr.size = size; + return response.Write(fd_); +} - case FUSE_OPEN: - HandleOpen(&buffer, callback); - break; +bool FuseAppLoop::ReplyOpen(uint64_t unique, uint64_t fh) { + FuseSimpleResponse response; + response.Reset(sizeof(fuse_open_out), kFuseSuccess, unique); + response.open_out.fh = fh; + return response.Write(fd_); +} - case FUSE_READ: - HandleRead(&buffer, callback); - break; +bool FuseAppLoop::ReplyWrite(uint64_t unique, uint32_t size) { + CHECK(size <= kFuseMaxWrite); + FuseSimpleResponse response; + response.Reset(sizeof(fuse_write_out), kFuseSuccess, unique); + response.write_out.size = size; + return response.Write(fd_); +} - case FUSE_WRITE: - HandleWrite(&buffer, callback); - break; +bool FuseAppLoop::ReplyRead(uint64_t unique, uint32_t size, const void* data) { + CHECK(size <= kFuseMaxRead); + FuseSimpleResponse response; + response.ResetHeader(size, kFuseSuccess, unique); + return response.WriteWithBody(fd_, sizeof(FuseResponse), data); +} - case FUSE_RELEASE: - HandleRelease(&buffer, callback); - break; +void FuseAppLoop::Start(FuseAppLoopCallback* callback) { + break_fd_.reset(eventfd(/* initval */ 0, EFD_CLOEXEC)); + if (break_fd_.get() == -1) { + PLOG(ERROR) << "Failed to open FD for break event"; + return; + } + + base::unique_fd epoll_fd(epoll_create1(EPOLL_CLOEXEC)); + if (epoll_fd.get() == -1) { + PLOG(ERROR) << "Failed to open FD for epoll"; + return; + } - case FUSE_FSYNC: - HandleFsync(&buffer, callback); - break; + int last_event; + int break_event; - default: - buffer.HandleNotImpl(); - break; + std::unique_ptr<EpollController> epoll_controller(new EpollController(std::move(epoll_fd))); + if (!epoll_controller->AddFd(fd_, EPOLLIN, &last_event)) { + return; + } + if (!epoll_controller->AddFd(break_fd_, EPOLLIN, &break_event)) { + return; } - if (!buffer.response.Write(fd)) { - LOG(ERROR) << "Failed to write a response to the device."; - return false; + last_event = 0; + break_event = 0; + + FuseBuffer buffer; + while (true) { + if (!epoll_controller->Wait(1)) { + break; + } + last_event = 0; + *reinterpret_cast<int*>(epoll_controller->events()[0].data.ptr) = + epoll_controller->events()[0].events; + + if (break_event != 0 || (last_event & ~EPOLLIN) != 0) { + break; + } + + if (!HandleMessage(this, &buffer, fd_, callback)) { + break; + } } - } - return true; + LOG(VERBOSE) << "FuseAppLoop exit"; } } // namespace fuse diff --git a/libappfuse/FuseBridgeLoop.cc b/libappfuse/FuseBridgeLoop.cc index 2386bf84b..3f47066a8 100644 --- a/libappfuse/FuseBridgeLoop.cc +++ b/libappfuse/FuseBridgeLoop.cc @@ -16,85 +16,355 @@ #include "libappfuse/FuseBridgeLoop.h" +#include <sys/epoll.h> +#include <sys/socket.h> + +#include <unordered_map> + #include <android-base/logging.h> #include <android-base/unique_fd.h> +#include "libappfuse/EpollController.h" + namespace android { namespace fuse { +namespace { + +enum class FuseBridgeState { kWaitToReadEither, kWaitToReadProxy, kWaitToWriteProxy, kClosing }; + +struct FuseBridgeEntryEvent { + FuseBridgeEntry* entry; + int events; +}; + +void GetObservedEvents(FuseBridgeState state, int* device_events, int* proxy_events) { + switch (state) { + case FuseBridgeState::kWaitToReadEither: + *device_events = EPOLLIN; + *proxy_events = EPOLLIN; + return; + case FuseBridgeState::kWaitToReadProxy: + *device_events = 0; + *proxy_events = EPOLLIN; + return; + case FuseBridgeState::kWaitToWriteProxy: + *device_events = 0; + *proxy_events = EPOLLOUT; + return; + case FuseBridgeState::kClosing: + *device_events = 0; + *proxy_events = 0; + return; + } +} +} + +class FuseBridgeEntry { + public: + FuseBridgeEntry(int mount_id, base::unique_fd&& dev_fd, base::unique_fd&& proxy_fd) + : mount_id_(mount_id), + device_fd_(std::move(dev_fd)), + proxy_fd_(std::move(proxy_fd)), + state_(FuseBridgeState::kWaitToReadEither), + last_state_(FuseBridgeState::kWaitToReadEither), + last_device_events_({this, 0}), + last_proxy_events_({this, 0}), + open_count_(0) {} + + // Transfer bytes depends on availability of FDs and the internal |state_|. + void Transfer(FuseBridgeLoopCallback* callback) { + constexpr int kUnexpectedEventMask = ~(EPOLLIN | EPOLLOUT); + const bool unexpected_event = (last_device_events_.events & kUnexpectedEventMask) || + (last_proxy_events_.events & kUnexpectedEventMask); + const bool device_read_ready = last_device_events_.events & EPOLLIN; + const bool proxy_read_ready = last_proxy_events_.events & EPOLLIN; + const bool proxy_write_ready = last_proxy_events_.events & EPOLLOUT; + + last_device_events_.events = 0; + last_proxy_events_.events = 0; + + LOG(VERBOSE) << "Transfer device_read_ready=" << device_read_ready + << " proxy_read_ready=" << proxy_read_ready + << " proxy_write_ready=" << proxy_write_ready; + + if (unexpected_event) { + LOG(ERROR) << "Invalid epoll event is observed"; + state_ = FuseBridgeState::kClosing; + return; + } + + switch (state_) { + case FuseBridgeState::kWaitToReadEither: + if (proxy_read_ready) { + state_ = ReadFromProxy(); + } else if (device_read_ready) { + state_ = ReadFromDevice(callback); + } + return; + + case FuseBridgeState::kWaitToReadProxy: + CHECK(proxy_read_ready); + state_ = ReadFromProxy(); + return; + + case FuseBridgeState::kWaitToWriteProxy: + CHECK(proxy_write_ready); + state_ = WriteToProxy(); + return; + + case FuseBridgeState::kClosing: + return; + } + } + + bool IsClosing() const { return state_ == FuseBridgeState::kClosing; } + + int mount_id() const { return mount_id_; } + + private: + friend class BridgeEpollController; + + FuseBridgeState ReadFromProxy() { + switch (buffer_.response.ReadOrAgain(proxy_fd_)) { + case ResultOrAgain::kSuccess: + break; + case ResultOrAgain::kFailure: + return FuseBridgeState::kClosing; + case ResultOrAgain::kAgain: + return FuseBridgeState::kWaitToReadProxy; + } + + if (!buffer_.response.Write(device_fd_)) { + return FuseBridgeState::kClosing; + } + + auto it = opcode_map_.find(buffer_.response.header.unique); + if (it != opcode_map_.end()) { + switch (it->second) { + case FUSE_OPEN: + if (buffer_.response.header.error == fuse::kFuseSuccess) { + open_count_++; + } + break; + + case FUSE_RELEASE: + if (open_count_ > 0) { + open_count_--; + } else { + LOG(WARNING) << "Unexpected FUSE_RELEASE before opening a file."; + break; + } + if (open_count_ == 0) { + return FuseBridgeState::kClosing; + } + break; + } + opcode_map_.erase(it); + } + + return FuseBridgeState::kWaitToReadEither; + } + + FuseBridgeState ReadFromDevice(FuseBridgeLoopCallback* callback) { + LOG(VERBOSE) << "ReadFromDevice"; + if (!buffer_.request.Read(device_fd_)) { + return FuseBridgeState::kClosing; + } + + const uint32_t opcode = buffer_.request.header.opcode; + LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode; + switch (opcode) { + case FUSE_FORGET: + // Do not reply to FUSE_FORGET. + return FuseBridgeState::kWaitToReadEither; + + case FUSE_LOOKUP: + case FUSE_GETATTR: + case FUSE_OPEN: + case FUSE_READ: + case FUSE_WRITE: + case FUSE_RELEASE: + case FUSE_FSYNC: + if (opcode == FUSE_OPEN || opcode == FUSE_RELEASE) { + opcode_map_.emplace(buffer_.request.header.unique, opcode); + } + return WriteToProxy(); + + case FUSE_INIT: + buffer_.HandleInit(); + break; + + default: + buffer_.HandleNotImpl(); + break; + } + + if (!buffer_.response.Write(device_fd_)) { + return FuseBridgeState::kClosing; + } + + if (opcode == FUSE_INIT) { + callback->OnMount(mount_id_); + } + + return FuseBridgeState::kWaitToReadEither; + } + + FuseBridgeState WriteToProxy() { + switch (buffer_.request.WriteOrAgain(proxy_fd_)) { + case ResultOrAgain::kSuccess: + return FuseBridgeState::kWaitToReadEither; + case ResultOrAgain::kFailure: + return FuseBridgeState::kClosing; + case ResultOrAgain::kAgain: + return FuseBridgeState::kWaitToWriteProxy; + } + } -bool StartFuseBridgeLoop( - int raw_dev_fd, int raw_proxy_fd, FuseBridgeLoopCallback* callback) { - base::unique_fd dev_fd(raw_dev_fd); - base::unique_fd proxy_fd(raw_proxy_fd); - FuseBuffer buffer; - size_t open_count = 0; - - LOG(DEBUG) << "Start fuse loop."; - while (true) { - if (!buffer.request.Read(dev_fd)) { - return false; + const int mount_id_; + base::unique_fd device_fd_; + base::unique_fd proxy_fd_; + FuseBuffer buffer_; + FuseBridgeState state_; + FuseBridgeState last_state_; + FuseBridgeEntryEvent last_device_events_; + FuseBridgeEntryEvent last_proxy_events_; + + // Remember map between unique and opcode in fuse_in_header so that we can + // refer the opcode later. + std::unordered_map<uint64_t, uint32_t> opcode_map_; + + int open_count_; + + DISALLOW_COPY_AND_ASSIGN(FuseBridgeEntry); +}; + +class BridgeEpollController : private EpollController { + public: + BridgeEpollController(base::unique_fd&& poll_fd) : EpollController(std::move(poll_fd)) {} + + bool AddBridgePoll(FuseBridgeEntry* bridge) const { + return InvokeControl(EPOLL_CTL_ADD, bridge); } - const uint32_t opcode = buffer.request.header.opcode; - LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode; - switch (opcode) { - case FUSE_FORGET: - // Do not reply to FUSE_FORGET. - continue; - - case FUSE_LOOKUP: - case FUSE_GETATTR: - case FUSE_OPEN: - case FUSE_READ: - case FUSE_WRITE: - case FUSE_RELEASE: - case FUSE_FSYNC: - if (!buffer.request.Write(proxy_fd)) { - LOG(ERROR) << "Failed to write a request to the proxy."; - return false; - } - if (!buffer.response.Read(proxy_fd)) { - LOG(ERROR) << "Failed to read a response from the proxy."; - return false; - } - break; - - case FUSE_INIT: - buffer.HandleInit(); - break; - - default: - buffer.HandleNotImpl(); - break; + bool UpdateOrDeleteBridgePoll(FuseBridgeEntry* bridge) const { + return InvokeControl( + bridge->state_ != FuseBridgeState::kClosing ? EPOLL_CTL_MOD : EPOLL_CTL_DEL, bridge); } - if (!buffer.response.Write(dev_fd)) { - LOG(ERROR) << "Failed to write a response to the device."; - return false; + bool Wait(size_t bridge_count, std::unordered_set<FuseBridgeEntry*>* entries_out) { + CHECK(entries_out); + const size_t event_count = std::max<size_t>(bridge_count * 2, 1); + if (!EpollController::Wait(event_count)) { + return false; + } + entries_out->clear(); + for (const auto& event : events()) { + FuseBridgeEntryEvent* const entry_event = + reinterpret_cast<FuseBridgeEntryEvent*>(event.data.ptr); + entry_event->events = event.events; + entries_out->insert(entry_event->entry); + } + return true; } - switch (opcode) { - case FUSE_INIT: - callback->OnMount(); - break; - case FUSE_OPEN: - if (buffer.response.header.error == fuse::kFuseSuccess) { - open_count++; - } - break; - case FUSE_RELEASE: - if (open_count != 0) { - open_count--; - } else { - LOG(WARNING) << "Unexpected FUSE_RELEASE before opening a file."; - break; - } - if (open_count == 0) { - return true; - } - break; + private: + bool InvokeControl(int op, FuseBridgeEntry* bridge) const { + LOG(VERBOSE) << "InvokeControl op=" << op << " bridge=" << bridge->mount_id_ + << " state=" << static_cast<int>(bridge->state_) + << " last_state=" << static_cast<int>(bridge->last_state_); + + int last_device_events; + int last_proxy_events; + int device_events; + int proxy_events; + GetObservedEvents(bridge->last_state_, &last_device_events, &last_proxy_events); + GetObservedEvents(bridge->state_, &device_events, &proxy_events); + bool result = true; + if (op != EPOLL_CTL_MOD || last_device_events != device_events) { + result &= EpollController::InvokeControl(op, bridge->device_fd_, device_events, + &bridge->last_device_events_); + } + if (op != EPOLL_CTL_MOD || last_proxy_events != proxy_events) { + result &= EpollController::InvokeControl(op, bridge->proxy_fd_, proxy_events, + &bridge->last_proxy_events_); + } + return result; + } +}; + +FuseBridgeLoop::FuseBridgeLoop() : opened_(true) { + base::unique_fd epoll_fd(epoll_create1(/* no flag */ 0)); + if (epoll_fd.get() == -1) { + PLOG(ERROR) << "Failed to open FD for epoll"; + opened_ = false; + return; + } + epoll_controller_.reset(new BridgeEpollController(std::move(epoll_fd))); +} + +FuseBridgeLoop::~FuseBridgeLoop() { CHECK(bridges_.empty()); } + +bool FuseBridgeLoop::AddBridge(int mount_id, base::unique_fd dev_fd, base::unique_fd proxy_fd) { + LOG(VERBOSE) << "Adding bridge " << mount_id; + + std::unique_ptr<FuseBridgeEntry> bridge( + new FuseBridgeEntry(mount_id, std::move(dev_fd), std::move(proxy_fd))); + std::lock_guard<std::mutex> lock(mutex_); + if (!opened_) { + LOG(ERROR) << "Tried to add a mount to a closed bridge"; + return false; + } + if (bridges_.count(mount_id)) { + LOG(ERROR) << "Tried to add a mount point that has already been added"; + return false; + } + if (!epoll_controller_->AddBridgePoll(bridge.get())) { + return false; + } + + bridges_.emplace(mount_id, std::move(bridge)); + return true; +} + +bool FuseBridgeLoop::ProcessEventLocked(const std::unordered_set<FuseBridgeEntry*>& entries, + FuseBridgeLoopCallback* callback) { + for (auto entry : entries) { + entry->Transfer(callback); + if (!epoll_controller_->UpdateOrDeleteBridgePoll(entry)) { + return false; + } + if (entry->IsClosing()) { + const int mount_id = entry->mount_id(); + callback->OnClosed(mount_id); + bridges_.erase(mount_id); + if (bridges_.size() == 0) { + // All bridges are now closed. + return false; + } + } + } + return true; +} + +void FuseBridgeLoop::Start(FuseBridgeLoopCallback* callback) { + LOG(DEBUG) << "Start fuse bridge loop"; + std::unordered_set<FuseBridgeEntry*> entries; + while (true) { + const bool wait_result = epoll_controller_->Wait(bridges_.size(), &entries); + LOG(VERBOSE) << "Receive epoll events"; + { + std::lock_guard<std::mutex> lock(mutex_); + if (!(wait_result && ProcessEventLocked(entries, callback))) { + for (auto it = bridges_.begin(); it != bridges_.end();) { + callback->OnClosed(it->second->mount_id()); + it = bridges_.erase(it); + } + opened_ = false; + return; + } + } } - } } } // namespace fuse diff --git a/libappfuse/FuseBuffer.cc b/libappfuse/FuseBuffer.cc index 8fb2dbcc5..653e96b28 100644 --- a/libappfuse/FuseBuffer.cc +++ b/libappfuse/FuseBuffer.cc @@ -23,81 +23,165 @@ #include <algorithm> #include <type_traits> +#include <sys/socket.h> +#include <sys/uio.h> + #include <android-base/file.h> #include <android-base/logging.h> #include <android-base/macros.h> namespace android { namespace fuse { +namespace { -static_assert( - std::is_standard_layout<FuseBuffer>::value, - "FuseBuffer must be standard layout union."); +constexpr useconds_t kRetrySleepForWriting = 1000; // 1 ms template <typename T> -bool FuseMessage<T>::CheckHeaderLength(const char* name) const { - const auto& header = static_cast<const T*>(this)->header; - if (header.len >= sizeof(header) && header.len <= sizeof(T)) { - return true; - } else { - LOG(ERROR) << "Invalid header length is found in " << name << ": " << - header.len; - return false; - } +bool CheckHeaderLength(const FuseMessage<T>* self, const char* name, size_t max_size) { + const auto& header = static_cast<const T*>(self)->header; + if (header.len >= sizeof(header) && header.len <= max_size) { + return true; + } else { + LOG(ERROR) << "Invalid header length is found in " << name << ": " << header.len; + return false; + } } template <typename T> -bool FuseMessage<T>::Read(int fd) { - char* const buf = reinterpret_cast<char*>(this); - const ssize_t result = TEMP_FAILURE_RETRY(::read(fd, buf, sizeof(T))); - if (result < 0) { - PLOG(ERROR) << "Failed to read a FUSE message"; - return false; - } +ResultOrAgain ReadInternal(FuseMessage<T>* self, int fd, int sockflag) { + char* const buf = reinterpret_cast<char*>(self); + const ssize_t result = sockflag ? TEMP_FAILURE_RETRY(recv(fd, buf, sizeof(T), sockflag)) + : TEMP_FAILURE_RETRY(read(fd, buf, sizeof(T))); - const auto& header = static_cast<const T*>(this)->header; - if (result < static_cast<ssize_t>(sizeof(header))) { - LOG(ERROR) << "Read bytes " << result << " are shorter than header size " << - sizeof(header); - return false; - } + switch (result) { + case 0: + // Expected EOF. + return ResultOrAgain::kFailure; + case -1: + if (errno == EAGAIN) { + return ResultOrAgain::kAgain; + } + PLOG(ERROR) << "Failed to read a FUSE message"; + return ResultOrAgain::kFailure; + } - if (!CheckHeaderLength("Read")) { - return false; - } + const auto& header = static_cast<const T*>(self)->header; + if (result < static_cast<ssize_t>(sizeof(header))) { + LOG(ERROR) << "Read bytes " << result << " are shorter than header size " << sizeof(header); + return ResultOrAgain::kFailure; + } - if (static_cast<uint32_t>(result) > header.len) { - LOG(ERROR) << "Read bytes " << result << " are longer than header.len " << - header.len; - return false; - } + if (!CheckHeaderLength<T>(self, "Read", sizeof(T))) { + return ResultOrAgain::kFailure; + } - if (!base::ReadFully(fd, buf + result, header.len - result)) { - PLOG(ERROR) << "ReadFully failed"; - return false; - } + if (static_cast<uint32_t>(result) != header.len) { + LOG(ERROR) << "Read bytes " << result << " are different from header.len " << header.len; + return ResultOrAgain::kFailure; + } - return true; + return ResultOrAgain::kSuccess; } template <typename T> -bool FuseMessage<T>::Write(int fd) const { - if (!CheckHeaderLength("Write")) { - return false; - } +ResultOrAgain WriteInternal(const FuseMessage<T>* self, int fd, int sockflag, const void* data, + size_t max_size) { + if (!CheckHeaderLength<T>(self, "Write", max_size)) { + return ResultOrAgain::kFailure; + } - const char* const buf = reinterpret_cast<const char*>(this); - const auto& header = static_cast<const T*>(this)->header; - if (!base::WriteFully(fd, buf, header.len)) { - PLOG(ERROR) << "WriteFully failed"; - return false; - } + const char* const buf = reinterpret_cast<const char*>(self); + const auto& header = static_cast<const T*>(self)->header; + + while (true) { + int result; + if (sockflag) { + CHECK(data == nullptr); + result = TEMP_FAILURE_RETRY(send(fd, buf, header.len, sockflag)); + } else if (data) { + const struct iovec vec[] = {{const_cast<char*>(buf), sizeof(header)}, + {const_cast<void*>(data), header.len - sizeof(header)}}; + result = TEMP_FAILURE_RETRY(writev(fd, vec, arraysize(vec))); + } else { + result = TEMP_FAILURE_RETRY(write(fd, buf, header.len)); + } + if (result == -1) { + switch (errno) { + case ENOBUFS: + // When returning ENOBUFS, epoll still reports the FD is writable. Just usleep + // and retry again. + usleep(kRetrySleepForWriting); + continue; + case EAGAIN: + return ResultOrAgain::kAgain; + default: + PLOG(ERROR) << "Failed to write a FUSE message"; + return ResultOrAgain::kFailure; + } + } - return true; + if (static_cast<unsigned int>(result) != header.len) { + LOG(ERROR) << "Written bytes " << result << " is different from length in header " + << header.len; + return ResultOrAgain::kFailure; + } + return ResultOrAgain::kSuccess; + } +} } -template class FuseMessage<FuseRequest>; -template class FuseMessage<FuseResponse>; +static_assert(std::is_standard_layout<FuseBuffer>::value, + "FuseBuffer must be standard layout union."); + +bool SetupMessageSockets(base::unique_fd (*result)[2]) { + base::unique_fd fds[2]; + { + int raw_fds[2]; + if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, raw_fds) == -1) { + PLOG(ERROR) << "Failed to create sockets for proxy"; + return false; + } + fds[0].reset(raw_fds[0]); + fds[1].reset(raw_fds[1]); + } + + constexpr int kMaxMessageSize = sizeof(FuseBuffer); + if (setsockopt(fds[0], SOL_SOCKET, SO_SNDBUFFORCE, &kMaxMessageSize, sizeof(int)) != 0 || + setsockopt(fds[1], SOL_SOCKET, SO_SNDBUFFORCE, &kMaxMessageSize, sizeof(int)) != 0) { + PLOG(ERROR) << "Failed to update buffer size for socket"; + return false; + } + + (*result)[0] = std::move(fds[0]); + (*result)[1] = std::move(fds[1]); + return true; +} + +template <typename T> +bool FuseMessage<T>::Read(int fd) { + return ReadInternal(this, fd, 0) == ResultOrAgain::kSuccess; +} + +template <typename T> +ResultOrAgain FuseMessage<T>::ReadOrAgain(int fd) { + return ReadInternal(this, fd, MSG_DONTWAIT); +} + +template <typename T> +bool FuseMessage<T>::Write(int fd) const { + return WriteInternal(this, fd, 0, nullptr, sizeof(T)) == ResultOrAgain::kSuccess; +} + +template <typename T> +bool FuseMessage<T>::WriteWithBody(int fd, size_t max_size, const void* data) const { + CHECK(data != nullptr); + return WriteInternal(this, fd, 0, data, max_size) == ResultOrAgain::kSuccess; +} + +template <typename T> +ResultOrAgain FuseMessage<T>::WriteOrAgain(int fd) const { + return WriteInternal(this, fd, MSG_DONTWAIT, nullptr, sizeof(T)); +} void FuseRequest::Reset( uint32_t data_length, uint32_t opcode, uint64_t unique) { @@ -107,17 +191,18 @@ void FuseRequest::Reset( header.unique = unique; } -void FuseResponse::ResetHeader( - uint32_t data_length, int32_t error, uint64_t unique) { - CHECK_LE(error, 0) << "error should be zero or negative."; - header.len = sizeof(fuse_out_header) + data_length; - header.error = error; - header.unique = unique; +template <size_t N> +void FuseResponseBase<N>::ResetHeader(uint32_t data_length, int32_t error, uint64_t unique) { + CHECK_LE(error, 0) << "error should be zero or negative."; + header.len = sizeof(fuse_out_header) + data_length; + header.error = error; + header.unique = unique; } -void FuseResponse::Reset(uint32_t data_length, int32_t error, uint64_t unique) { - memset(this, 0, sizeof(fuse_out_header) + data_length); - ResetHeader(data_length, error, unique); +template <size_t N> +void FuseResponseBase<N>::Reset(uint32_t data_length, int32_t error, uint64_t unique) { + memset(this, 0, sizeof(fuse_out_header) + data_length); + ResetHeader(data_length, error, unique); } void FuseBuffer::HandleInit() { @@ -167,5 +252,11 @@ void FuseBuffer::HandleNotImpl() { response.Reset(0, -ENOSYS, unique); } +template class FuseMessage<FuseRequest>; +template class FuseMessage<FuseResponse>; +template class FuseMessage<FuseSimpleResponse>; +template struct FuseResponseBase<0u>; +template struct FuseResponseBase<kFuseMaxRead>; + } // namespace fuse } // namespace android diff --git a/libappfuse/include/libappfuse/EpollController.h b/libappfuse/include/libappfuse/EpollController.h new file mode 100644 index 000000000..622bd2cc9 --- /dev/null +++ b/libappfuse/include/libappfuse/EpollController.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specic language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_LIBAPPFUSE_EPOLLCONTROLLER_H_ +#define ANDROID_LIBAPPFUSE_EPOLLCONTROLLER_H_ + +#include <sys/epoll.h> + +#include <vector> + +#include <android-base/macros.h> +#include <android-base/unique_fd.h> + +namespace android { +namespace fuse { + +class EpollController { + public: + explicit EpollController(base::unique_fd&& poll_fd); + bool Wait(size_t event_count); + bool AddFd(int fd, int events, void* data); + bool UpdateFd(int fd, int events, void* data); + bool RemoveFd(int fd); + + const std::vector<epoll_event>& events() const; + + protected: + bool InvokeControl(int op, int fd, int events, void* data) const; + + private: + base::unique_fd poll_fd_; + std::vector<epoll_event> events_; + + DISALLOW_COPY_AND_ASSIGN(EpollController); +}; +} +} + +#endif // ANDROID_LIBAPPFUSE_EPOLLCONTROLLER_H_ diff --git a/libappfuse/include/libappfuse/FuseAppLoop.h b/libappfuse/include/libappfuse/FuseAppLoop.h index c3edfcc32..f2ef2b5c5 100644 --- a/libappfuse/include/libappfuse/FuseAppLoop.h +++ b/libappfuse/include/libappfuse/FuseAppLoop.h @@ -17,23 +17,51 @@ #ifndef ANDROID_LIBAPPFUSE_FUSEAPPLOOP_H_ #define ANDROID_LIBAPPFUSE_FUSEAPPLOOP_H_ +#include <memory> +#include <mutex> + +#include <android-base/unique_fd.h> + #include "libappfuse/FuseBuffer.h" namespace android { namespace fuse { +class EpollController; + class FuseAppLoopCallback { public: - virtual bool IsActive() = 0; - virtual int64_t OnGetSize(uint64_t inode) = 0; - virtual int32_t OnFsync(uint64_t inode) = 0; - virtual int32_t OnWrite( - uint64_t inode, uint64_t offset, uint32_t size, const void* data) = 0; - virtual int32_t OnRead( - uint64_t inode, uint64_t offset, uint32_t size, void* data) = 0; - virtual int32_t OnOpen(uint64_t inode) = 0; - virtual int32_t OnRelease(uint64_t inode) = 0; - virtual ~FuseAppLoopCallback() = default; + virtual void OnLookup(uint64_t unique, uint64_t inode) = 0; + virtual void OnGetAttr(uint64_t unique, uint64_t inode) = 0; + virtual void OnFsync(uint64_t unique, uint64_t inode) = 0; + virtual void OnWrite(uint64_t unique, uint64_t inode, uint64_t offset, uint32_t size, + const void* data) = 0; + virtual void OnRead(uint64_t unique, uint64_t inode, uint64_t offset, uint32_t size) = 0; + virtual void OnOpen(uint64_t unique, uint64_t inode) = 0; + virtual void OnRelease(uint64_t unique, uint64_t inode) = 0; + virtual ~FuseAppLoopCallback(); +}; + +class FuseAppLoop final { + public: + FuseAppLoop(base::unique_fd&& fd); + + void Start(FuseAppLoopCallback* callback); + void Break(); + + bool ReplySimple(uint64_t unique, int32_t result); + bool ReplyLookup(uint64_t unique, uint64_t inode, int64_t size); + bool ReplyGetAttr(uint64_t unique, uint64_t inode, int64_t size, int mode); + bool ReplyOpen(uint64_t unique, uint64_t fh); + bool ReplyWrite(uint64_t unique, uint32_t size); + bool ReplyRead(uint64_t unique, uint32_t size, const void* data); + + private: + base::unique_fd fd_; + base::unique_fd break_fd_; + + // Lock for multi-threading. + std::mutex mutex_; }; bool StartFuseAppLoop(int fd, FuseAppLoopCallback* callback); diff --git a/libappfuse/include/libappfuse/FuseBridgeLoop.h b/libappfuse/include/libappfuse/FuseBridgeLoop.h index 1f71cf272..6bfda9819 100644 --- a/libappfuse/include/libappfuse/FuseBridgeLoop.h +++ b/libappfuse/include/libappfuse/FuseBridgeLoop.h @@ -17,6 +17,13 @@ #ifndef ANDROID_LIBAPPFUSE_FUSEBRIDGELOOP_H_ #define ANDROID_LIBAPPFUSE_FUSEBRIDGELOOP_H_ +#include <map> +#include <mutex> +#include <queue> +#include <unordered_set> + +#include <android-base/macros.h> + #include "libappfuse/FuseBuffer.h" namespace android { @@ -24,12 +31,41 @@ namespace fuse { class FuseBridgeLoopCallback { public: - virtual void OnMount() = 0; - virtual ~FuseBridgeLoopCallback() = default; + virtual void OnMount(int mount_id) = 0; + virtual void OnClosed(int mount_id) = 0; + virtual ~FuseBridgeLoopCallback() = default; }; -bool StartFuseBridgeLoop( - int dev_fd, int proxy_fd, FuseBridgeLoopCallback* callback); +class FuseBridgeEntry; +class BridgeEpollController; + +class FuseBridgeLoop final { + public: + FuseBridgeLoop(); + ~FuseBridgeLoop(); + + void Start(FuseBridgeLoopCallback* callback); + + // Add bridge to the loop. It's OK to invoke the method from a different + // thread from one which invokes |Start|. + bool AddBridge(int mount_id, base::unique_fd dev_fd, base::unique_fd proxy_fd); + + private: + bool ProcessEventLocked(const std::unordered_set<FuseBridgeEntry*>& entries, + FuseBridgeLoopCallback* callback); + + std::unique_ptr<BridgeEpollController> epoll_controller_; + + // Map between |mount_id| and bridge entry. + std::map<int, std::unique_ptr<FuseBridgeEntry>> bridges_; + + // Lock for multi-threading. + std::mutex mutex_; + + bool opened_; + + DISALLOW_COPY_AND_ASSIGN(FuseBridgeLoop); +}; } // namespace fuse } // namespace android diff --git a/libappfuse/include/libappfuse/FuseBuffer.h b/libappfuse/include/libappfuse/FuseBuffer.h index 959dde798..7a70bf3b4 100644 --- a/libappfuse/include/libappfuse/FuseBuffer.h +++ b/libappfuse/include/libappfuse/FuseBuffer.h @@ -17,6 +17,7 @@ #ifndef ANDROID_LIBAPPFUSE_FUSEBUFFER_H_ #define ANDROID_LIBAPPFUSE_FUSEBUFFER_H_ +#include <android-base/unique_fd.h> #include <linux/fuse.h> namespace android { @@ -28,13 +29,23 @@ constexpr size_t kFuseMaxWrite = 256 * 1024; constexpr size_t kFuseMaxRead = 128 * 1024; constexpr int32_t kFuseSuccess = 0; +// Setup sockets to transfer FuseMessage. +bool SetupMessageSockets(base::unique_fd (*sockets)[2]); + +enum class ResultOrAgain { + kSuccess, + kFailure, + kAgain, +}; + template<typename T> class FuseMessage { public: bool Read(int fd); bool Write(int fd) const; - private: - bool CheckHeaderLength(const char* name) const; + bool WriteWithBody(int fd, size_t max_size, const void* data) const; + ResultOrAgain ReadOrAgain(int fd); + ResultOrAgain WriteOrAgain(int fd) const; }; // FuseRequest represents file operation requests from /dev/fuse. It starts @@ -61,26 +72,30 @@ struct FuseRequest : public FuseMessage<FuseRequest> { // FuseResponse represents file operation responses to /dev/fuse. It starts // from fuse_out_header. The body layout depends on the operation code. -struct FuseResponse : public FuseMessage<FuseResponse> { - fuse_out_header header; - union { - // for FUSE_INIT - fuse_init_out init_out; - // for FUSE_LOOKUP - fuse_entry_out entry_out; - // for FUSE_GETATTR - fuse_attr_out attr_out; - // for FUSE_OPEN - fuse_open_out open_out; - // for FUSE_READ - char read_data[kFuseMaxRead]; - // for FUSE_WRITE - fuse_write_out write_out; - }; - void Reset(uint32_t data_length, int32_t error, uint64_t unique); - void ResetHeader(uint32_t data_length, int32_t error, uint64_t unique); +template <size_t N> +struct FuseResponseBase : public FuseMessage<FuseResponseBase<N>> { + fuse_out_header header; + union { + // for FUSE_INIT + fuse_init_out init_out; + // for FUSE_LOOKUP + fuse_entry_out entry_out; + // for FUSE_GETATTR + fuse_attr_out attr_out; + // for FUSE_OPEN + fuse_open_out open_out; + // for FUSE_READ + char read_data[N]; + // for FUSE_WRITE + fuse_write_out write_out; + }; + void Reset(uint32_t data_length, int32_t error, uint64_t unique); + void ResetHeader(uint32_t data_length, int32_t error, uint64_t unique); }; +using FuseResponse = FuseResponseBase<kFuseMaxRead>; +using FuseSimpleResponse = FuseResponseBase<0u>; + // To reduce memory usage, FuseBuffer shares the memory region for request and // response. union FuseBuffer final { diff --git a/libappfuse/tests/FuseAppLoopTest.cc b/libappfuse/tests/FuseAppLoopTest.cc index 25906cf1c..98e36652a 100644 --- a/libappfuse/tests/FuseAppLoopTest.cc +++ b/libappfuse/tests/FuseAppLoopTest.cc @@ -23,6 +23,9 @@ #include <gtest/gtest.h> #include <thread> +#include "libappfuse/EpollController.h" +#include "libappfuse/FuseBridgeLoop.h" + namespace android { namespace fuse { namespace { @@ -37,85 +40,61 @@ struct CallbackRequest { class Callback : public FuseAppLoopCallback { public: std::vector<CallbackRequest> requests; + FuseAppLoop* loop; - bool IsActive() override { - return true; + void OnGetAttr(uint64_t seq, uint64_t inode) override { + EXPECT_NE(FUSE_ROOT_ID, static_cast<int>(inode)); + EXPECT_TRUE(loop->ReplyGetAttr(seq, inode, kTestFileSize, S_IFREG | 0777)); } - int64_t OnGetSize(uint64_t inode) override { - if (inode == FUSE_ROOT_ID) { - return 0; - } else { - return kTestFileSize; - } + void OnLookup(uint64_t unique, uint64_t inode) override { + EXPECT_NE(FUSE_ROOT_ID, static_cast<int>(inode)); + EXPECT_TRUE(loop->ReplyLookup(unique, inode, kTestFileSize)); } - int32_t OnFsync(uint64_t inode) override { - requests.push_back({ - .code = FUSE_FSYNC, - .inode = inode - }); - return 0; + void OnFsync(uint64_t seq, uint64_t inode) override { + requests.push_back({.code = FUSE_FSYNC, .inode = inode}); + loop->ReplySimple(seq, 0); } - int32_t OnWrite(uint64_t inode, - uint64_t offset ATTRIBUTE_UNUSED, - uint32_t size ATTRIBUTE_UNUSED, - const void* data ATTRIBUTE_UNUSED) override { - requests.push_back({ - .code = FUSE_WRITE, - .inode = inode - }); - return 0; + void OnWrite(uint64_t seq, uint64_t inode, uint64_t offset ATTRIBUTE_UNUSED, + uint32_t size ATTRIBUTE_UNUSED, const void* data ATTRIBUTE_UNUSED) override { + requests.push_back({.code = FUSE_WRITE, .inode = inode}); + loop->ReplyWrite(seq, 0); } - int32_t OnRead(uint64_t inode, - uint64_t offset ATTRIBUTE_UNUSED, - uint32_t size ATTRIBUTE_UNUSED, - void* data ATTRIBUTE_UNUSED) override { - requests.push_back({ - .code = FUSE_READ, - .inode = inode - }); - return 0; + void OnRead(uint64_t seq, uint64_t inode, uint64_t offset ATTRIBUTE_UNUSED, + uint32_t size ATTRIBUTE_UNUSED) override { + requests.push_back({.code = FUSE_READ, .inode = inode}); + loop->ReplySimple(seq, 0); } - int32_t OnOpen(uint64_t inode) override { - requests.push_back({ - .code = FUSE_OPEN, - .inode = inode - }); - return 0; + void OnOpen(uint64_t seq, uint64_t inode) override { + requests.push_back({.code = FUSE_OPEN, .inode = inode}); + loop->ReplyOpen(seq, inode); } - int32_t OnRelease(uint64_t inode) override { - requests.push_back({ - .code = FUSE_RELEASE, - .inode = inode - }); - return 0; + void OnRelease(uint64_t seq, uint64_t inode) override { + requests.push_back({.code = FUSE_RELEASE, .inode = inode}); + loop->ReplySimple(seq, 0); } }; class FuseAppLoopTest : public ::testing::Test { - private: - std::thread thread_; - protected: - base::unique_fd sockets_[2]; - Callback callback_; - FuseRequest request_; - FuseResponse response_; - - void SetUp() override { - base::SetMinimumLogSeverity(base::VERBOSE); - int sockets[2]; - ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)); - sockets_[0].reset(sockets[0]); - sockets_[1].reset(sockets[1]); - thread_ = std::thread([this] { - StartFuseAppLoop(sockets_[1].release(), &callback_); - }); + std::thread thread_; + base::unique_fd sockets_[2]; + Callback callback_; + FuseRequest request_; + FuseResponse response_; + std::unique_ptr<FuseAppLoop> loop_; + + void SetUp() override { + base::SetMinimumLogSeverity(base::VERBOSE); + ASSERT_TRUE(SetupMessageSockets(&sockets_)); + loop_.reset(new FuseAppLoop(std::move(sockets_[1]))); + callback_.loop = loop_.get(); + thread_ = std::thread([this] { loop_->Start(&callback_); }); } void CheckCallback( @@ -303,5 +282,18 @@ TEST_F(FuseAppLoopTest, Write) { CheckCallback(sizeof(fuse_write_in), FUSE_WRITE, sizeof(fuse_write_out)); } +TEST_F(FuseAppLoopTest, Break) { + // Ensure that the loop started. + request_.Reset(sizeof(fuse_open_in), FUSE_OPEN, 1); + request_.header.nodeid = 10; + ASSERT_TRUE(request_.Write(sockets_[0])); + ASSERT_TRUE(response_.Read(sockets_[0])); + + loop_->Break(); + if (thread_.joinable()) { + thread_.join(); + } +} + } // namespace fuse } // namespace android diff --git a/libappfuse/tests/FuseBridgeLoopTest.cc b/libappfuse/tests/FuseBridgeLoopTest.cc index e74d9e700..51d605136 100644 --- a/libappfuse/tests/FuseBridgeLoopTest.cc +++ b/libappfuse/tests/FuseBridgeLoopTest.cc @@ -32,10 +32,12 @@ namespace { class Callback : public FuseBridgeLoopCallback { public: bool mounted; - Callback() : mounted(false) {} - void OnMount() override { - mounted = true; - } + bool closed; + Callback() : mounted(false), closed(false) {} + + void OnMount(int /*mount_id*/) override { mounted = true; } + + void OnClosed(int /* mount_id */) override { closed = true; } }; class FuseBridgeLoopTest : public ::testing::Test { @@ -50,18 +52,12 @@ class FuseBridgeLoopTest : public ::testing::Test { void SetUp() override { base::SetMinimumLogSeverity(base::VERBOSE); - int dev_sockets[2]; - int proxy_sockets[2]; - ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, dev_sockets)); - ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, proxy_sockets)); - dev_sockets_[0].reset(dev_sockets[0]); - dev_sockets_[1].reset(dev_sockets[1]); - proxy_sockets_[0].reset(proxy_sockets[0]); - proxy_sockets_[1].reset(proxy_sockets[1]); - + ASSERT_TRUE(SetupMessageSockets(&dev_sockets_)); + ASSERT_TRUE(SetupMessageSockets(&proxy_sockets_)); thread_ = std::thread([this] { - StartFuseBridgeLoop( - dev_sockets_[1].release(), proxy_sockets_[0].release(), &callback_); + FuseBridgeLoop loop; + loop.AddBridge(1, std::move(dev_sockets_[1]), std::move(proxy_sockets_[0])); + loop.Start(&callback_); }); } @@ -122,6 +118,7 @@ class FuseBridgeLoopTest : public ::testing::Test { if (thread_.joinable()) { thread_.join(); } + ASSERT_TRUE(callback_.closed); } void TearDown() override { diff --git a/libappfuse/tests/FuseBufferTest.cc b/libappfuse/tests/FuseBufferTest.cc index 1a1abd57e..ade34acc1 100644 --- a/libappfuse/tests/FuseBufferTest.cc +++ b/libappfuse/tests/FuseBufferTest.cc @@ -112,30 +112,6 @@ TEST(FuseMessageTest, Write_TooShort) { TestWriteInvalidLength(sizeof(fuse_in_header) - 1); } -TEST(FuseMessageTest, ShortWriteAndRead) { - int raw_fds[2]; - ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, raw_fds)); - - android::base::unique_fd fds[2]; - fds[0].reset(raw_fds[0]); - fds[1].reset(raw_fds[1]); - - const int send_buffer_size = 1024; - ASSERT_EQ(0, setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, &send_buffer_size, - sizeof(int))); - - bool succeed = false; - const int sender_fd = fds[0].get(); - std::thread thread([sender_fd, &succeed] { - FuseRequest request; - request.header.len = 1024 * 4; - succeed = request.Write(sender_fd); - }); - thread.detach(); - FuseRequest request; - ASSERT_TRUE(request.Read(fds[1])); -} - TEST(FuseResponseTest, Reset) { FuseResponse response; // Write 1 to the first ten bytes. @@ -211,5 +187,29 @@ TEST(FuseBufferTest, HandleNotImpl) { EXPECT_EQ(-ENOSYS, buffer.response.header.error); } +TEST(SetupMessageSocketsTest, Stress) { + constexpr int kCount = 1000; + + FuseRequest request; + request.header.len = sizeof(FuseRequest); + + base::unique_fd fds[2]; + SetupMessageSockets(&fds); + + std::thread thread([&fds] { + FuseRequest request; + for (int i = 0; i < kCount; ++i) { + ASSERT_TRUE(request.Read(fds[1])); + usleep(1000); + } + }); + + for (int i = 0; i < kCount; ++i) { + ASSERT_TRUE(request.Write(fds[0])); + } + + thread.join(); +} + } // namespace fuse } // namespace android diff --git a/libcrypto_utils/Android.bp b/libcrypto_utils/Android.bp index f2560e6a3..4a5f2a7ac 100644 --- a/libcrypto_utils/Android.bp +++ b/libcrypto_utils/Android.bp @@ -16,6 +16,7 @@ cc_library { name: "libcrypto_utils", + vendor_available: true, host_supported: true, srcs: [ "android_pubkey.c", diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp index 13c4abf98..a1dbd7881 100644 --- a/libcutils/fs_config.cpp +++ b/libcutils/fs_config.cpp @@ -186,7 +186,7 @@ static const struct fs_path_config android_files[] = { // Support hostapd administering a network interface. { 00755, AID_WIFI, AID_WIFI, CAP_MASK_LONG(CAP_NET_ADMIN) | CAP_MASK_LONG(CAP_NET_RAW), - "system/bin/hostapd" }, + "vendor/bin/hostapd" }, // Support Bluetooth legacy hal accessing /sys/class/rfkill // Support RT scheduling in Bluetooth diff --git a/libgrallocusage/Android.bp b/libgrallocusage/Android.bp new file mode 100644 index 000000000..54bfee5c4 --- /dev/null +++ b/libgrallocusage/Android.bp @@ -0,0 +1,29 @@ +// Copyright 2017 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +cc_library_static { + name: "libgrallocusage", + cppflags: [ + "-Weverything", + "-Werror", + "-Wno-c++98-compat-pedantic", + // Hide errors in headers we include + "-Wno-global-constructors", + "-Wno-exit-time-destructors", + "-Wno-padded", + ], + srcs: ["GrallocUsageConversion.cpp"], + export_include_dirs: ["include"], + shared_libs: ["android.hardware.graphics.allocator@2.0"], +} diff --git a/libgrallocusage/GrallocUsageConversion.cpp b/libgrallocusage/GrallocUsageConversion.cpp new file mode 100644 index 000000000..05c8ec44f --- /dev/null +++ b/libgrallocusage/GrallocUsageConversion.cpp @@ -0,0 +1,67 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <grallocusage/GrallocUsageConversion.h> + +#include <hardware/gralloc.h> +#include <hardware/gralloc1.h> + +void android_convertGralloc0To1Usage(int32_t usage, uint64_t* producerUsage, + uint64_t* consumerUsage) { + constexpr uint64_t PRODUCER_MASK = + GRALLOC1_PRODUCER_USAGE_CPU_READ | + /* GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN | */ + GRALLOC1_PRODUCER_USAGE_CPU_WRITE | + /* GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN | */ + GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET | GRALLOC1_PRODUCER_USAGE_PROTECTED | + GRALLOC1_PRODUCER_USAGE_CAMERA | GRALLOC1_PRODUCER_USAGE_VIDEO_DECODER | + GRALLOC1_PRODUCER_USAGE_SENSOR_DIRECT_DATA; + constexpr uint64_t CONSUMER_MASK = + GRALLOC1_CONSUMER_USAGE_CPU_READ | + /* GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN | */ + GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE | GRALLOC1_CONSUMER_USAGE_HWCOMPOSER | + GRALLOC1_CONSUMER_USAGE_CLIENT_TARGET | GRALLOC1_CONSUMER_USAGE_CURSOR | + GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER | GRALLOC1_CONSUMER_USAGE_CAMERA | + GRALLOC1_CONSUMER_USAGE_RENDERSCRIPT | GRALLOC1_CONSUMER_USAGE_GPU_DATA_BUFFER; + *producerUsage = static_cast<uint64_t>(usage) & PRODUCER_MASK; + *consumerUsage = static_cast<uint64_t>(usage) & CONSUMER_MASK; + if ((static_cast<uint32_t>(usage) & GRALLOC_USAGE_SW_READ_OFTEN) == GRALLOC_USAGE_SW_READ_OFTEN) { + *producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN; + *consumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN; + } + if ((static_cast<uint32_t>(usage) & GRALLOC_USAGE_SW_WRITE_OFTEN) == + GRALLOC_USAGE_SW_WRITE_OFTEN) { + *producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN; + } +} + +int32_t android_convertGralloc1To0Usage(uint64_t producerUsage, uint64_t consumerUsage) { + static_assert(uint64_t(GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN) == + uint64_t(GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN), + "expected ConsumerUsage and ProducerUsage CPU_READ_OFTEN bits to match"); + uint64_t merged = producerUsage | consumerUsage; + if ((merged & (GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN)) == + GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN) { + merged &= ~uint64_t(GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN); + merged |= GRALLOC_USAGE_SW_READ_OFTEN; + } + if ((merged & (GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN)) == + GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN) { + merged &= ~uint64_t(GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN); + merged |= GRALLOC_USAGE_SW_WRITE_OFTEN; + } + return static_cast<int32_t>(merged); +} diff --git a/libgrallocusage/MODULE_LICENSE_APACHE2 b/libgrallocusage/MODULE_LICENSE_APACHE2 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/libgrallocusage/MODULE_LICENSE_APACHE2 diff --git a/libgrallocusage/NOTICE b/libgrallocusage/NOTICE new file mode 100644 index 000000000..c5b1efa7a --- /dev/null +++ b/libgrallocusage/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-2008, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/libgrallocusage/include/grallocusage/GrallocUsageConversion.h b/libgrallocusage/include/grallocusage/GrallocUsageConversion.h new file mode 100644 index 000000000..5c94343c2 --- /dev/null +++ b/libgrallocusage/include/grallocusage/GrallocUsageConversion.h @@ -0,0 +1,47 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GRALLOCUSAGE_GRALLOC_USAGE_CONVERSION_H +#define ANDROID_GRALLOCUSAGE_GRALLOC_USAGE_CONVERSION_H 1 + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +// Conversion functions are out-of-line so that users don't have to be exposed to +// android/hardware/graphics/allocator/2.0/types.h and link against +// android.hardware.graphics.allocator@2.0 to get that in their search path. + +// Convert a 32-bit gralloc0 usage mask to a producer/consumer pair of 64-bit usage masks as used +// by android.hardware.graphics.allocator@2.0 (and gralloc1). This conversion properly handles the +// mismatch between a.h.g.allocator@2.0's CPU_{READ,WRITE}_OFTEN and gralloc0's +// SW_{READ,WRITE}_OFTEN. +void android_convertGralloc0To1Usage(int32_t usage, uint64_t* producerUsage, + uint64_t* consumerUsage); + +// Convert a producer/consumer pair of 64-bit usage masks as used by +// android.hardware.graphics.allocator@2.0 (and gralloc1) to a 32-bit gralloc0 usage mask. This +// conversion properly handles the mismatch between a.h.g.allocator@2.0's CPU_{READ,WRITE}_OFTEN +// and gralloc0's SW_{READ,WRITE}_OFTEN. +int32_t android_convertGralloc1To0Usage(uint64_t producerUsage, uint64_t consumerUsage); + +#ifdef __cplusplus +} +#endif + +#endif // ANDROID_GRALLOCUSAGE_GRALLOC_USAGE_CONVERSION_H diff --git a/liblog/Android.bp b/liblog/Android.bp index b98d18ff6..e74aa8283 100644 --- a/liblog/Android.bp +++ b/liblog/Android.bp @@ -42,24 +42,6 @@ liblog_target_sources = [ "logd_writer.c", ] -cc_library_headers { - name: "liblog_headers", - host_supported: true, - vendor_available: true, - export_include_dirs: ["include"], - target: { - windows: { - enabled: true, - }, - linux_bionic: { - enabled: true, - }, - vendor: { - export_include_dirs: ["include_vndk"], - }, - }, -} - // Shared and static library for host and device // ======================================================== cc_library { @@ -99,8 +81,7 @@ cc_library { }, }, - header_libs: ["liblog_headers"], - export_header_lib_headers: ["liblog_headers"], + export_include_dirs: ["include"], cflags: [ "-Werror", @@ -119,7 +100,7 @@ cc_library { } ndk_headers { - name: "liblog_ndk_headers", + name: "liblog_headers", from: "include/android", to: "android", srcs: ["include/android/log.h"], diff --git a/liblog/tests/AndroidTest.xml b/liblog/tests/AndroidTest.xml index b8d87e6c9..427f2b41c 100644 --- a/liblog/tests/AndroidTest.xml +++ b/liblog/tests/AndroidTest.xml @@ -14,6 +14,7 @@ limitations under the License. --> <configuration description="Config for CTS Logging Library test cases"> + <option name="config-descriptor:metadata" key="component" value="systems" /> <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher"> <option name="cleanup" value="true" /> <option name="push" value="CtsLiblogTestCases->/data/local/tmp/CtsLiblogTestCases" /> 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..c5e74c103 --- /dev/null +++ b/libmemtrack/memtrack.cpp @@ -0,0 +1,173 @@ +/* + * 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; +using android::hardware::Return; + +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; + + Return<void> ret = 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 ret.isOk() ? err : -1; +} + +/* 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 78831510a..130800ed8 100644 --- a/libsuspend/Android.bp +++ b/libsuspend/Android.bp @@ -6,8 +6,6 @@ cc_library { 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/libsync/Android.bp b/libsync/Android.bp index 4f71b9fd6..1646348a9 100644 --- a/libsync/Android.bp +++ b/libsync/Android.bp @@ -1,3 +1,17 @@ +ndk_headers { + name: "libsync_headers", + from: "include/ndk", + to: "android", + srcs: ["include/ndk/sync.h"], + license: "NOTICE", +} + +ndk_library { + name: "libsync", + symbol_file: "libsync.map.txt", + first_version: "26", +} + cc_defaults { name: "libsync_defaults", srcs: ["sync.c"], diff --git a/libsync/NOTICE b/libsync/NOTICE new file mode 100644 index 000000000..2c8db73b0 --- /dev/null +++ b/libsync/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2012-2017, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/libsync/include/android/sync.h b/libsync/include/android/sync.h new file mode 100644 index 000000000..68f74a0b2 --- /dev/null +++ b/libsync/include/android/sync.h @@ -0,0 +1,69 @@ +/* + * sync.h + * + * Copyright 2012 Google, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __SYS_CORE_SYNC_H +#define __SYS_CORE_SYNC_H + +/* This file contains the legacy sync interface used by Android platform and + * device code. The direct contents will be removed over time as code + * transitions to using the updated interface in ndk/sync.h. When this file is + * empty other than the ndk/sync.h include, that file will be renamed to + * replace this one. + * + * New code should continue to include this file (#include <android/sync.h>) + * instead of ndk/sync.h so the eventual rename is seamless, but should only + * use the things declared in ndk/sync.h. + * + * This file used to be called sync/sync.h, but we renamed to that both the + * platform and NDK call it android/sync.h. A symlink from the old name to this + * one exists temporarily to avoid having to change all sync clients + * simultaneously. It will be removed when they've been updated, and probably + * after this change has been delivered to AOSP so that integrations don't + * break builds. + */ + +#include "../ndk/sync.h" + +__BEGIN_DECLS + +struct sync_fence_info_data { + uint32_t len; + char name[32]; + int32_t status; + uint8_t pt_info[0]; +}; + +struct sync_pt_info { + uint32_t len; + char obj_name[32]; + char driver_name[32]; + int32_t status; + uint64_t timestamp_ns; + uint8_t driver_data[0]; +}; + +/* timeout in msecs */ +int sync_wait(int fd, int timeout); +struct sync_fence_info_data *sync_fence_info(int fd); +struct sync_pt_info *sync_pt_info(struct sync_fence_info_data *info, + struct sync_pt_info *itr); +void sync_fence_info_free(struct sync_fence_info_data *info); + +__END_DECLS + +#endif /* __SYS_CORE_SYNC_H */ diff --git a/libsync/include/ndk/sync.h b/libsync/include/ndk/sync.h new file mode 100644 index 000000000..3c5578313 --- /dev/null +++ b/libsync/include/ndk/sync.h @@ -0,0 +1,88 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_SYNC_H +#define ANDROID_SYNC_H + +#include <stdint.h> + +#include <linux/sync_file.h> + +__BEGIN_DECLS + +#if __ANDROID_API__ >= __ANDROID_API_O__ + +/* Fences indicate the status of an asynchronous task. They are initially + * in unsignaled state (0), and make a one-time transition to either signaled + * (1) or error (< 0) state. A sync file is a collection of one or more fences; + * the sync file's status is error if any of its fences are in error state, + * signaled if all of the child fences are signaled, or unsignaled otherwise. + * + * Sync files are created by various device APIs in response to submitting + * tasks to the device. Standard file descriptor lifetime syscalls like dup() + * and close() are used to manage sync file lifetime. + * + * The poll(), ppoll(), or select() syscalls can be used to wait for the sync + * file to change status, or (with a timeout of zero) to check its status. + * + * The functions below provide a few additional sync-specific operations. + */ + +/** + * Merge two sync files. + * + * This produces a new sync file with the given name which has the union of the + * two original sync file's fences; redundant fences may be removed. + * + * If one of the input sync files is signaled or invalid, then this function + * may behave like dup(): the new file descriptor refers to the valid/unsignaled + * sync file with its original name, rather than a new sync file. + * + * The original fences remain valid, and the caller is responsible for closing + * them. + */ +int32_t sync_merge(const char *name, int32_t fd1, int32_t fd2); + +/** + * Retrieve detailed information about a sync file and its fences. + * + * The returned sync_file_info must be freed by calling sync_file_info_free(). + */ +struct sync_file_info *sync_file_info(int32_t fd); + +/** + * Get the array of fence infos from the sync file's info. + * + * The returned array is owned by the parent sync file info, and has + * info->num_fences entries. + */ +static inline struct sync_fence_info* sync_get_fence_info(const struct sync_file_info* info) { +// This header should compile in C, but some C++ projects enable +// warnings-as-error for C-style casts. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wold-style-cast" + return (struct sync_fence_info *)(uintptr_t)(info->sync_fence_info); +#pragma GCC diagnostic pop +} + +/** Free a struct sync_file_info structure */ +void sync_file_info_free(struct sync_file_info *info); + +#endif // __ANDROID_API__ >= __ANDROID_API_O__ + +__END_DECLS + +#endif /* ANDROID_SYNC_H */ diff --git a/libsync/include/sync/sync.h b/libsync/include/sync/sync.h index 50ed0ac57..3b17e480a 100644..120000 --- a/libsync/include/sync/sync.h +++ b/libsync/include/sync/sync.h @@ -1,163 +1 @@ -/* - * sync.h - * - * Copyright 2012 Google, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __SYS_CORE_SYNC_H -#define __SYS_CORE_SYNC_H - -#include <sys/cdefs.h> -#include <stdint.h> - -#include <linux/types.h> - -__BEGIN_DECLS - -struct sync_legacy_merge_data { - int32_t fd2; - char name[32]; - int32_t fence; -}; - -struct sync_fence_info_data { - uint32_t len; - char name[32]; - int32_t status; - uint8_t pt_info[0]; -}; - -struct sync_pt_info { - uint32_t len; - char obj_name[32]; - char driver_name[32]; - int32_t status; - uint64_t timestamp_ns; - uint8_t driver_data[0]; -}; - -#define SYNC_IOC_MAGIC '>' - -/** - * DOC: SYNC_IOC_LEGACY_WAIT - wait for a fence to signal - * - * pass timeout in milliseconds. Waits indefinitely timeout < 0. - * - * This is the legacy version of the Sync API before the de-stage that happened - * on Linux kernel 4.7. - */ -#define SYNC_IOC_LEGACY_WAIT _IOW(SYNC_IOC_MAGIC, 0, __s32) - -/** - * DOC: SYNC_IOC_MERGE - merge two fences - * - * Takes a struct sync_merge_data. Creates a new fence containing copies of - * the sync_pts in both the calling fd and sync_merge_data.fd2. Returns the - * new fence's fd in sync_merge_data.fence - * - * This is the legacy version of the Sync API before the de-stage that happened - * on Linux kernel 4.7. - */ -#define SYNC_IOC_LEGACY_MERGE _IOWR(SYNC_IOC_MAGIC, 1, \ - struct sync_legacy_merge_data) - -/** - * DOC: SYNC_IOC_LEGACY_FENCE_INFO - get detailed information on a fence - * - * Takes a struct sync_fence_info_data with extra space allocated for pt_info. - * Caller should write the size of the buffer into len. On return, len is - * updated to reflect the total size of the sync_fence_info_data including - * pt_info. - * - * pt_info is a buffer containing sync_pt_infos for every sync_pt in the fence. - * To iterate over the sync_pt_infos, use the sync_pt_info.len field. - * - * This is the legacy version of the Sync API before the de-stage that happened - * on Linux kernel 4.7. - */ -#define SYNC_IOC_LEGACY_FENCE_INFO _IOWR(SYNC_IOC_MAGIC, 2,\ - struct sync_fence_info_data) - -struct sync_merge_data { - char name[32]; - int32_t fd2; - int32_t fence; - uint32_t flags; - uint32_t pad; -}; - -struct sync_file_info { - char name[32]; - int32_t status; - uint32_t flags; - uint32_t num_fences; - uint32_t pad; - - uint64_t sync_fence_info; -}; - -struct sync_fence_info { - char obj_name[32]; - char driver_name[32]; - int32_t status; - uint32_t flags; - uint64_t timestamp_ns; -}; - -/** - * Mainline API: - * - * Opcodes 0, 1 and 2 were burned during a API change to avoid users of the - * old API to get weird errors when trying to handling sync_files. The API - * change happened during the de-stage of the Sync Framework when there was - * no upstream users available. - */ - -/** - * DOC: SYNC_IOC_MERGE - merge two fences - * - * Takes a struct sync_merge_data. Creates a new fence containing copies of - * the sync_pts in both the calling fd and sync_merge_data.fd2. Returns the - * new fence's fd in sync_merge_data.fence - * - * This is the new version of the Sync API after the de-stage that happened - * on Linux kernel 4.7. - */ -#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 3, struct sync_merge_data) - -/** - * DOC: SYNC_IOC_FILE_INFO - get detailed information on a sync_file - * - * Takes a struct sync_file_info. If num_fences is 0, the field is updated - * with the actual number of fences. If num_fences is > 0, the system will - * use the pointer provided on sync_fence_info to return up to num_fences of - * struct sync_fence_info, with detailed fence information. - * - * This is the new version of the Sync API after the de-stage that happened - * on Linux kernel 4.7. - */ -#define SYNC_IOC_FILE_INFO _IOWR(SYNC_IOC_MAGIC, 4, struct sync_file_info) - -/* timeout in msecs */ -int sync_wait(int fd, int timeout); -int sync_merge(const char *name, int fd1, int fd2); -struct sync_fence_info_data *sync_fence_info(int fd); -struct sync_pt_info *sync_pt_info(struct sync_fence_info_data *info, - struct sync_pt_info *itr); -void sync_fence_info_free(struct sync_fence_info_data *info); - -__END_DECLS - -#endif /* __SYS_CORE_SYNC_H */ +../android/sync.h
\ No newline at end of file diff --git a/libsync/libsync.map.txt b/libsync/libsync.map.txt new file mode 100644 index 000000000..daa28ae92 --- /dev/null +++ b/libsync/libsync.map.txt @@ -0,0 +1,32 @@ +# +# Copyright 2017 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LIBSYNC { + global: + sync_merge; # introduced=26 + sync_get_fence_info; # introduced=26 + sync_free_fence_info; # introduced=26 + local: + *; +}; + +LIBSYNC_PLATFORM { + global: + sync_wait; + sync_fence_info; + sync_pt_info; + sync_fence_info_free; +} LIBSYNC_PLATFORM; diff --git a/libsync/sync.c b/libsync/sync.c index 9ed03dba8..baeccda47 100644 --- a/libsync/sync.c +++ b/libsync/sync.c @@ -16,19 +16,59 @@ * limitations under the License. */ +#include <errno.h> #include <fcntl.h> #include <malloc.h> +#include <poll.h> +#include <stdatomic.h> #include <stdint.h> #include <string.h> -#include <errno.h> -#include <poll.h> #include <sys/ioctl.h> #include <sys/stat.h> #include <sys/types.h> -#include <sync/sync.h> +#include <android/sync.h> +/* Legacy Sync API */ + +struct sync_legacy_merge_data { + int32_t fd2; + char name[32]; + int32_t fence; +}; + +/** + * DOC: SYNC_IOC_MERGE - merge two fences + * + * Takes a struct sync_merge_data. Creates a new fence containing copies of + * the sync_pts in both the calling fd and sync_merge_data.fd2. Returns the + * new fence's fd in sync_merge_data.fence + * + * This is the legacy version of the Sync API before the de-stage that happened + * on Linux kernel 4.7. + */ +#define SYNC_IOC_LEGACY_MERGE _IOWR(SYNC_IOC_MAGIC, 1, \ + struct sync_legacy_merge_data) + +/** + * DOC: SYNC_IOC_LEGACY_FENCE_INFO - get detailed information on a fence + * + * Takes a struct sync_fence_info_data with extra space allocated for pt_info. + * Caller should write the size of the buffer into len. On return, len is + * updated to reflect the total size of the sync_fence_info_data including + * pt_info. + * + * pt_info is a buffer containing sync_pt_infos for every sync_pt in the fence. + * To iterate over the sync_pt_infos, use the sync_pt_info.len field. + * + * This is the legacy version of the Sync API before the de-stage that happened + * on Linux kernel 4.7. + */ +#define SYNC_IOC_LEGACY_FENCE_INFO _IOWR(SYNC_IOC_MAGIC, 2,\ + struct sync_fence_info_data) + +/* SW Sync API */ struct sw_sync_create_fence_data { __u32 value; @@ -40,6 +80,24 @@ struct sw_sync_create_fence_data { #define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0, struct sw_sync_create_fence_data) #define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32) +// --------------------------------------------------------------------------- +// Support for caching the sync uapi version. +// +// This library supports both legacy (android/staging) uapi and modern +// (mainline) sync uapi. Library calls first try one uapi, and if that fails, +// try the other. Since any given kernel only supports one uapi version, after +// the first successful syscall we know what the kernel supports and can skip +// trying the other. + +enum uapi_version { + UAPI_UNKNOWN, + UAPI_MODERN, + UAPI_LEGACY +}; +static atomic_int g_uapi_version = ATOMIC_VAR_INIT(UAPI_UNKNOWN); + +// --------------------------------------------------------------------------- + int sync_wait(int fd, int timeout) { struct pollfd fds; @@ -70,9 +128,21 @@ int sync_wait(int fd, int timeout) return ret; } -int sync_merge(const char *name, int fd1, int fd2) +static int legacy_sync_merge(const char *name, int fd1, int fd2) +{ + struct sync_legacy_merge_data data; + int ret; + + data.fd2 = fd2; + strlcpy(data.name, name, sizeof(data.name)); + ret = ioctl(fd1, SYNC_IOC_LEGACY_MERGE, &data); + if (ret < 0) + return ret; + return data.fence; +} + +static int modern_sync_merge(const char *name, int fd1, int fd2) { - struct sync_legacy_merge_data legacy_data; struct sync_merge_data data; int ret; @@ -82,29 +152,42 @@ int sync_merge(const char *name, int fd1, int fd2) data.pad = 0; ret = ioctl(fd1, SYNC_IOC_MERGE, &data); - if (ret < 0 && errno == ENOTTY) { - legacy_data.fd2 = fd2; - strlcpy(legacy_data.name, name, sizeof(legacy_data.name)); + if (ret < 0) + return ret; + return data.fence; +} - ret = ioctl(fd1, SYNC_IOC_LEGACY_MERGE, &legacy_data); - if (ret < 0) - return ret; +int sync_merge(const char *name, int fd1, int fd2) +{ + int uapi; + int ret; - return legacy_data.fence; - } else if (ret < 0) { - return ret; + uapi = atomic_load_explicit(&g_uapi_version, memory_order_acquire); + + if (uapi == UAPI_MODERN || uapi == UAPI_UNKNOWN) { + ret = modern_sync_merge(name, fd1, fd2); + if (ret >= 0 || errno != ENOTTY) { + if (ret >= 0 && uapi == UAPI_UNKNOWN) { + atomic_store_explicit(&g_uapi_version, UAPI_MODERN, + memory_order_release); + } + return ret; + } } - return data.fence; + ret = legacy_sync_merge(name, fd1, fd2); + if (ret >= 0 && uapi == UAPI_UNKNOWN) { + atomic_store_explicit(&g_uapi_version, UAPI_LEGACY, + memory_order_release); + } + return ret; } -struct sync_fence_info_data *sync_fence_info(int fd) +static struct sync_fence_info_data *legacy_sync_fence_info(int fd) { struct sync_fence_info_data *legacy_info; struct sync_pt_info *legacy_pt_info; - struct sync_file_info *info; - struct sync_fence_info *fence_info; - int err, num_fences, i; + int err; legacy_info = malloc(4096); if (legacy_info == NULL) @@ -112,46 +195,57 @@ struct sync_fence_info_data *sync_fence_info(int fd) legacy_info->len = 4096; err = ioctl(fd, SYNC_IOC_LEGACY_FENCE_INFO, legacy_info); - if (err < 0 && errno != ENOTTY) { + if (err < 0) { free(legacy_info); return NULL; - } else if (err == 0) { - return legacy_info; } + return legacy_info; +} - info = calloc(1, sizeof(*info)); - if (info == NULL) - goto free; +static struct sync_file_info *modern_sync_file_info(int fd) +{ + struct sync_file_info local_info; + struct sync_file_info *info; + int err; - err = ioctl(fd, SYNC_IOC_FILE_INFO, info); + memset(&local_info, 0, sizeof(local_info)); + err = ioctl(fd, SYNC_IOC_FILE_INFO, &local_info); if (err < 0) - goto free; - - num_fences = info->num_fences; - - if (num_fences) { - info->flags = 0; - info->num_fences = num_fences; - info->sync_fence_info = (uint64_t) calloc(num_fences, - sizeof(struct sync_fence_info)); - if ((void *)info->sync_fence_info == NULL) - goto free; - - err = ioctl(fd, SYNC_IOC_FILE_INFO, info); - if (err < 0) { - free((void *)info->sync_fence_info); - goto free; - } + return NULL; + + info = calloc(1, sizeof(struct sync_file_info) + + local_info.num_fences * sizeof(struct sync_fence_info)); + if (!info) + return NULL; + info->sync_fence_info = (__u64)(uintptr_t)(info + 1); + + err = ioctl(fd, SYNC_IOC_FILE_INFO, info); + if (err < 0) { + free(info); + return NULL; } + return info; +} + +static struct sync_fence_info_data *sync_file_info_to_legacy_fence_info( + const struct sync_file_info *info) +{ + struct sync_fence_info_data *legacy_info; + struct sync_pt_info *legacy_pt_info; + const struct sync_fence_info *fence_info = sync_get_fence_info(info); + const uint32_t num_fences = info->num_fences; + + legacy_info = malloc(4096); + if (legacy_info == NULL) + return NULL; legacy_info->len = sizeof(*legacy_info) + - num_fences * sizeof(struct sync_fence_info); + num_fences * sizeof(struct sync_pt_info); strlcpy(legacy_info->name, info->name, sizeof(legacy_info->name)); legacy_info->status = info->status; legacy_pt_info = (struct sync_pt_info *)legacy_info->pt_info; - fence_info = (struct sync_fence_info *)info->sync_fence_info; - for (i = 0 ; i < num_fences ; i++) { + for (uint32_t i = 0; i < num_fences; i++) { legacy_pt_info[i].len = sizeof(*legacy_pt_info); strlcpy(legacy_pt_info[i].obj_name, fence_info[i].obj_name, sizeof(legacy_pt_info->obj_name)); @@ -161,14 +255,109 @@ struct sync_fence_info_data *sync_fence_info(int fd) legacy_pt_info[i].timestamp_ns = fence_info[i].timestamp_ns; } - free((void *)info->sync_fence_info); - free(info); return legacy_info; +} -free: - free(legacy_info); - free(info); - return NULL; +static struct sync_file_info* legacy_fence_info_to_sync_file_info( + struct sync_fence_info_data *legacy_info) +{ + struct sync_file_info *info; + struct sync_pt_info *pt; + struct sync_fence_info *fence; + size_t num_fences; + int err; + + pt = NULL; + num_fences = 0; + while ((pt = sync_pt_info(legacy_info, pt)) != NULL) + num_fences++; + + info = calloc(1, sizeof(struct sync_file_info) + + num_fences * sizeof(struct sync_fence_info)); + if (!info) { + free(legacy_info); + return NULL; + } + info->sync_fence_info = (__u64)(uintptr_t)(info + 1); + + strlcpy(info->name, legacy_info->name, sizeof(info->name)); + info->status = legacy_info->status; + info->num_fences = num_fences; + + pt = NULL; + fence = sync_get_fence_info(info); + while ((pt = sync_pt_info(legacy_info, pt)) != NULL) { + strlcpy(fence->obj_name, pt->obj_name, sizeof(fence->obj_name)); + strlcpy(fence->driver_name, pt->driver_name, + sizeof(fence->driver_name)); + fence->status = pt->status; + fence->timestamp_ns = pt->timestamp_ns; + fence++; + } + + return info; +} + +struct sync_fence_info_data *sync_fence_info(int fd) +{ + struct sync_fence_info_data *legacy_info; + int uapi; + + uapi = atomic_load_explicit(&g_uapi_version, memory_order_acquire); + + if (uapi == UAPI_LEGACY || uapi == UAPI_UNKNOWN) { + legacy_info = legacy_sync_fence_info(fd); + if (legacy_info || errno != ENOTTY) { + if (legacy_info && uapi == UAPI_UNKNOWN) { + atomic_store_explicit(&g_uapi_version, UAPI_LEGACY, + memory_order_release); + } + return legacy_info; + } + } + + struct sync_file_info* file_info; + file_info = modern_sync_file_info(fd); + if (!file_info) + return NULL; + if (uapi == UAPI_UNKNOWN) { + atomic_store_explicit(&g_uapi_version, UAPI_MODERN, + memory_order_release); + } + legacy_info = sync_file_info_to_legacy_fence_info(file_info); + sync_file_info_free(file_info); + return legacy_info; +} + +struct sync_file_info* sync_file_info(int32_t fd) +{ + struct sync_file_info *info; + int uapi; + + uapi = atomic_load_explicit(&g_uapi_version, memory_order_acquire); + + if (uapi == UAPI_MODERN || uapi == UAPI_UNKNOWN) { + info = modern_sync_file_info(fd); + if (info || errno != ENOTTY) { + if (info && uapi == UAPI_UNKNOWN) { + atomic_store_explicit(&g_uapi_version, UAPI_MODERN, + memory_order_release); + } + return info; + } + } + + struct sync_fence_info_data *legacy_info; + legacy_info = legacy_sync_fence_info(fd); + if (!legacy_info) + return NULL; + if (uapi == UAPI_UNKNOWN) { + atomic_store_explicit(&g_uapi_version, UAPI_LEGACY, + memory_order_release); + } + info = legacy_fence_info_to_sync_file_info(legacy_info); + sync_fence_info_free(legacy_info); + return info; } struct sync_pt_info *sync_pt_info(struct sync_fence_info_data *info, @@ -190,6 +379,11 @@ void sync_fence_info_free(struct sync_fence_info_data *info) free(info); } +void sync_file_info_free(struct sync_file_info *info) +{ + free(info); +} + int sw_sync_timeline_create(void) { diff --git a/libsync/sync_test.c b/libsync/sync_test.c index 9a5f7d858..f1ffdcf9e 100644 --- a/libsync/sync_test.c +++ b/libsync/sync_test.c @@ -22,7 +22,7 @@ #include <string.h> #include <unistd.h> -#include <sync/sync.h> +#include <android/sync.h> #include "sw_sync.h" pthread_mutex_t printf_mutex = PTHREAD_MUTEX_INITIALIZER; diff --git a/libsync/tests/sync_test.cpp b/libsync/tests/sync_test.cpp index 401aaeee5..f08e97e2c 100644 --- a/libsync/tests/sync_test.cpp +++ b/libsync/tests/sync_test.cpp @@ -1,5 +1,5 @@ #include <gtest/gtest.h> -#include <sync/sync.h> +#include <android/sync.h> #include <sw_sync.h> #include <fcntl.h> #include <vector> @@ -172,20 +172,20 @@ public: return sync_wait(m_fd, timeout); } vector<SyncPointInfo> getInfo() const { - struct sync_pt_info *pointInfo = nullptr; vector<SyncPointInfo> fenceInfo; - sync_fence_info_data *info = sync_fence_info(getFd()); + struct sync_file_info *info = sync_file_info(getFd()); if (!info) { return fenceInfo; } - while ((pointInfo = sync_pt_info(info, pointInfo))) { + const auto fences = sync_get_fence_info(info); + for (uint32_t i = 0; i < info->num_fences; i++) { fenceInfo.push_back(SyncPointInfo{ - pointInfo->driver_name, - pointInfo->obj_name, - pointInfo->timestamp_ns, - pointInfo->status}); + fences[i].driver_name, + fences[i].obj_name, + fences[i].timestamp_ns, + fences[i].status}); } - sync_fence_info_free(info); + sync_file_info_free(info); return fenceInfo; } int getSize() const { @@ -212,6 +212,32 @@ private: } }; +static void CheckModernLegacyInfoMatch(const SyncFence& f) { + struct sync_file_info* modern = sync_file_info(f.getFd()); + struct sync_fence_info_data* legacy = sync_fence_info(f.getFd()); + + ASSERT_TRUE(modern != NULL); + ASSERT_TRUE(legacy != NULL); + + EXPECT_STREQ(modern->name, legacy->name); + EXPECT_EQ(modern->status, legacy->status); + + uint32_t fenceIdx = 0; + struct sync_pt_info* pt = sync_pt_info(legacy, NULL); + const struct sync_fence_info* fences = sync_get_fence_info(modern); + while (fenceIdx < modern->num_fences && pt != NULL) { + EXPECT_STREQ(fences[fenceIdx].obj_name, pt->obj_name); + EXPECT_STREQ(fences[fenceIdx].driver_name, pt->driver_name); + EXPECT_EQ(fences[fenceIdx].status, pt->status); + EXPECT_EQ(fences[fenceIdx].timestamp_ns, pt->timestamp_ns); + + fenceIdx++; + pt = sync_pt_info(legacy, pt); + } + EXPECT_EQ(fenceIdx, modern->num_fences); + EXPECT_EQ(NULL, pt); +} + int SyncFence::s_fenceCount = 0; TEST(AllocTest, Timeline) { @@ -225,6 +251,7 @@ TEST(AllocTest, Fence) { SyncFence fence(timeline, 1); ASSERT_TRUE(fence.isValid()); + CheckModernLegacyInfoMatch(fence); } TEST(AllocTest, FenceNegative) { @@ -321,15 +348,21 @@ TEST(FenceTest, OneTimelineMerge) { timeline.inc(1); ASSERT_EQ(a.getSignaledCount(), 1); ASSERT_EQ(d.getActiveCount(), 1); + CheckModernLegacyInfoMatch(a); + CheckModernLegacyInfoMatch(d); timeline.inc(1); ASSERT_EQ(b.getSignaledCount(), 1); ASSERT_EQ(d.getActiveCount(), 1); + CheckModernLegacyInfoMatch(b); + CheckModernLegacyInfoMatch(d); timeline.inc(1); ASSERT_EQ(c.getSignaledCount(), 1); ASSERT_EQ(d.getActiveCount(), 0); ASSERT_EQ(d.getSignaledCount(), 1); + CheckModernLegacyInfoMatch(c); + CheckModernLegacyInfoMatch(d); } TEST(FenceTest, MergeSameFence) { @@ -343,9 +376,11 @@ TEST(FenceTest, MergeSameFence) { ASSERT_TRUE(selfMergeFence.isValid()); ASSERT_EQ(selfMergeFence.getSignaledCount(), 0); + CheckModernLegacyInfoMatch(selfMergeFence); timeline.inc(5); ASSERT_EQ(selfMergeFence.getSignaledCount(), 1); + CheckModernLegacyInfoMatch(selfMergeFence); } TEST(FenceTest, PollOnDestroyedTimeline) { @@ -397,14 +432,17 @@ TEST(FenceTest, MultiTimelineWait) { timelineA.inc(5); ASSERT_EQ(mergedFence.getActiveCount(), 2); ASSERT_EQ(mergedFence.getSignaledCount(), 1); + CheckModernLegacyInfoMatch(mergedFence); timelineB.inc(5); ASSERT_EQ(mergedFence.getActiveCount(), 1); ASSERT_EQ(mergedFence.getSignaledCount(), 2); + CheckModernLegacyInfoMatch(mergedFence); timelineC.inc(5); ASSERT_EQ(mergedFence.getActiveCount(), 0); ASSERT_EQ(mergedFence.getSignaledCount(), 3); + CheckModernLegacyInfoMatch(mergedFence); // confirm you can successfully wait. ASSERT_EQ(mergedFence.wait(100), 0); @@ -560,6 +598,7 @@ TEST_P(MergeStressTest, RandomMerge) { // Merge. fence = SyncFence(fence, SyncFence(timeline, syncPoint)); ASSERT_TRUE(fence.isValid()); + CheckModernLegacyInfoMatch(fence); } // Confirm our map matches the fence. diff --git a/libsystem/include/system/graphics-base.h b/libsystem/include/system/graphics-base.h new file mode 100644 index 000000000..2a44fafdf --- /dev/null +++ b/libsystem/include/system/graphics-base.h @@ -0,0 +1,141 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. +// Source: android.hardware.graphics.common@1.0 +// Root: android.hardware:hardware/interfaces + +#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_BT2020_PQ = 163971072, // ((STANDARD_BT2020 | TRANSFER_ST2084) | 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/libsystem/include/system/graphics.h b/libsystem/include/system/graphics.h index ae10fa095..1a9918797 100644 --- a/libsystem/include/system/graphics.h +++ b/libsystem/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/libsystem/include/system/radio.h b/libsystem/include/system/radio.h index 03b252e30..acf3ea787 100644 --- a/libsystem/include/system/radio.h +++ b/libsystem/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/libsystem/include/system/window-deprecated.h b/libsystem/include/system/window-deprecated.h new file mode 100644 index 000000000..e836aea94 --- /dev/null +++ b/libsystem/include/system/window-deprecated.h @@ -0,0 +1,1114 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/************************************************************************************************** + ************************************************************************************************** + **** **** + **** DEPRECATED **** + **** **** + **** THIS FILE EXISTS ONLY FOR BACKWARD SOURCE COMPATIBILITY. **** + **** **** + **** DO NOT ADD TO THIS FILE. **** + **** **** + **** Driver implementors (vendors) should use vndk/window.h **** + **** (frameworks/native/libs/nativewindow/include/vndk/window.h) **** + **** **** + **** Internal definition can be found here: **** + **** frameworks/native/libs/nativewindow/include/system/window.h **** + **** **** + ************************************************************************************************** + **************************************************************************************************/ + +#pragma once + +#include <cutils/native_handle.h> +#include <errno.h> +#include <limits.h> +#include <stdint.h> +#include <string.h> +#include <sys/cdefs.h> +#include <system/graphics.h> +#include <unistd.h> +#include <stdbool.h> + +#ifndef __UNUSED +#define __UNUSED __attribute__((__unused__)) +#endif +#ifndef __deprecated +#define __deprecated __attribute__((__deprecated__)) +#endif + +__BEGIN_DECLS + +/*****************************************************************************/ + +#ifdef __cplusplus +#define ANDROID_NATIVE_UNSIGNED_CAST(x) static_cast<unsigned int>(x) +#else +#define ANDROID_NATIVE_UNSIGNED_CAST(x) ((unsigned int)(x)) +#endif + +#define ANDROID_NATIVE_MAKE_CONSTANT(a,b,c,d) \ + ((ANDROID_NATIVE_UNSIGNED_CAST(a) << 24) | \ + (ANDROID_NATIVE_UNSIGNED_CAST(b) << 16) | \ + (ANDROID_NATIVE_UNSIGNED_CAST(c) << 8) | \ + (ANDROID_NATIVE_UNSIGNED_CAST(d))) + +#define ANDROID_NATIVE_WINDOW_MAGIC \ + ANDROID_NATIVE_MAKE_CONSTANT('_','w','n','d') + +#define ANDROID_NATIVE_BUFFER_MAGIC \ + ANDROID_NATIVE_MAKE_CONSTANT('_','b','f','r') + +// --------------------------------------------------------------------------- + +// This #define may be used to conditionally compile device-specific code to +// support either the prior ANativeWindow interface, which did not pass libsync +// fences around, or the new interface that does. This #define is only present +// when the ANativeWindow interface does include libsync support. +#define ANDROID_NATIVE_WINDOW_HAS_SYNC 1 + +// --------------------------------------------------------------------------- + +typedef const native_handle_t* buffer_handle_t; + +// --------------------------------------------------------------------------- + +typedef struct android_native_rect_t +{ + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; +} android_native_rect_t; + +// --------------------------------------------------------------------------- + +typedef struct android_native_base_t +{ + /* a magic value defined by the actual EGL native type */ + int magic; + + /* the sizeof() of the actual EGL native type */ + int version; + + void* reserved[4]; + + /* reference-counting interface */ + void (*incRef)(struct android_native_base_t* base); + void (*decRef)(struct android_native_base_t* base); +} android_native_base_t; + +typedef struct ANativeWindowBuffer +{ +#ifdef __cplusplus + ANativeWindowBuffer() { + common.magic = ANDROID_NATIVE_BUFFER_MAGIC; + common.version = sizeof(ANativeWindowBuffer); + memset(common.reserved, 0, sizeof(common.reserved)); + } + + // Implement the methods that sp<ANativeWindowBuffer> expects so that it + // can be used to automatically refcount ANativeWindowBuffer's. + void incStrong(const void* /*id*/) const { + common.incRef(const_cast<android_native_base_t*>(&common)); + } + void decStrong(const void* /*id*/) const { + common.decRef(const_cast<android_native_base_t*>(&common)); + } +#endif + + struct android_native_base_t common; + + int width; + int height; + int stride; + int format; + int usage; + uintptr_t layerCount; + + void* reserved[1]; + + buffer_handle_t handle; + + void* reserved_proc[8]; +} ANativeWindowBuffer_t; + +// Old typedef for backwards compatibility. +typedef ANativeWindowBuffer_t android_native_buffer_t; + +// --------------------------------------------------------------------------- + +/* attributes queriable with query() */ +enum { + NATIVE_WINDOW_WIDTH = 0, + NATIVE_WINDOW_HEIGHT = 1, + NATIVE_WINDOW_FORMAT = 2, + + /* The minimum number of buffers that must remain un-dequeued after a buffer + * has been queued. This value applies only if set_buffer_count was used to + * override the number of buffers and if a buffer has since been queued. + * Users of the set_buffer_count ANativeWindow method should query this + * value before calling set_buffer_count. If it is necessary to have N + * buffers simultaneously dequeued as part of the steady-state operation, + * and this query returns M then N+M buffers should be requested via + * native_window_set_buffer_count. + * + * Note that this value does NOT apply until a single buffer has been + * queued. In particular this means that it is possible to: + * + * 1. Query M = min undequeued buffers + * 2. Set the buffer count to N + M + * 3. Dequeue all N + M buffers + * 4. Cancel M buffers + * 5. Queue, dequeue, queue, dequeue, ad infinitum + */ + NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS = 3, + + /* Check whether queueBuffer operations on the ANativeWindow send the buffer + * to the window compositor. The query sets the returned 'value' argument + * to 1 if the ANativeWindow DOES send queued buffers directly to the window + * compositor and 0 if the buffers do not go directly to the window + * compositor. + * + * This can be used to determine whether protected buffer content should be + * sent to the ANativeWindow. Note, however, that a result of 1 does NOT + * indicate that queued buffers will be protected from applications or users + * capturing their contents. If that behavior is desired then some other + * mechanism (e.g. the GRALLOC_USAGE_PROTECTED flag) should be used in + * conjunction with this query. + */ + NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER = 4, + + /* Get the concrete type of a ANativeWindow. See below for the list of + * possible return values. + * + * This query should not be used outside the Android framework and will + * likely be removed in the near future. + */ + NATIVE_WINDOW_CONCRETE_TYPE = 5, + + + /* + * Default width and height of ANativeWindow buffers, these are the + * dimensions of the window buffers irrespective of the + * NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS call and match the native window + * size unless overridden by NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS. + */ + NATIVE_WINDOW_DEFAULT_WIDTH = 6, + NATIVE_WINDOW_DEFAULT_HEIGHT = 7, + + /* + * transformation that will most-likely be applied to buffers. This is only + * a hint, the actual transformation applied might be different. + * + * INTENDED USE: + * + * The transform hint can be used by a producer, for instance the GLES + * driver, to pre-rotate the rendering such that the final transformation + * in the composer is identity. This can be very useful when used in + * conjunction with the h/w composer HAL, in situations where it + * cannot handle arbitrary rotations. + * + * 1. Before dequeuing a buffer, the GL driver (or any other ANW client) + * queries the ANW for NATIVE_WINDOW_TRANSFORM_HINT. + * + * 2. The GL driver overrides the width and height of the ANW to + * account for NATIVE_WINDOW_TRANSFORM_HINT. This is done by querying + * NATIVE_WINDOW_DEFAULT_{WIDTH | HEIGHT}, swapping the dimensions + * according to NATIVE_WINDOW_TRANSFORM_HINT and calling + * native_window_set_buffers_dimensions(). + * + * 3. The GL driver dequeues a buffer of the new pre-rotated size. + * + * 4. The GL driver renders to the buffer such that the image is + * already transformed, that is applying NATIVE_WINDOW_TRANSFORM_HINT + * to the rendering. + * + * 5. The GL driver calls native_window_set_transform to apply + * inverse transformation to the buffer it just rendered. + * In order to do this, the GL driver needs + * to calculate the inverse of NATIVE_WINDOW_TRANSFORM_HINT, this is + * done easily: + * + * int hintTransform, inverseTransform; + * query(..., NATIVE_WINDOW_TRANSFORM_HINT, &hintTransform); + * inverseTransform = hintTransform; + * if (hintTransform & HAL_TRANSFORM_ROT_90) + * inverseTransform ^= HAL_TRANSFORM_ROT_180; + * + * + * 6. The GL driver queues the pre-transformed buffer. + * + * 7. The composer combines the buffer transform with the display + * transform. If the buffer transform happens to cancel out the + * display transform then no rotation is needed. + * + */ + NATIVE_WINDOW_TRANSFORM_HINT = 8, + + /* + * Boolean that indicates whether the consumer is running more than + * one buffer behind the producer. + */ + NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND = 9, + + /* + * The consumer gralloc usage bits currently set by the consumer. + * The values are defined in hardware/libhardware/include/gralloc.h. + */ + NATIVE_WINDOW_CONSUMER_USAGE_BITS = 10, + + /** + * Transformation that will by applied to buffers by the hwcomposer. + * This must not be set or checked by producer endpoints, and will + * disable the transform hint set in SurfaceFlinger (see + * NATIVE_WINDOW_TRANSFORM_HINT). + * + * INTENDED USE: + * Temporary - Please do not use this. This is intended only to be used + * by the camera's LEGACY mode. + * + * In situations where a SurfaceFlinger client wishes to set a transform + * that is not visible to the producer, and will always be applied in the + * hardware composer, the client can set this flag with + * native_window_set_buffers_sticky_transform. This can be used to rotate + * and flip buffers consumed by hardware composer without actually changing + * the aspect ratio of the buffers produced. + */ + NATIVE_WINDOW_STICKY_TRANSFORM = 11, + + /** + * The default data space for the buffers as set by the consumer. + * The values are defined in graphics.h. + */ + NATIVE_WINDOW_DEFAULT_DATASPACE = 12, + + /* + * Returns the age of the contents of the most recently dequeued buffer as + * the number of frames that have elapsed since it was last queued. For + * example, if the window is double-buffered, the age of any given buffer in + * steady state will be 2. If the dequeued buffer has never been queued, its + * age will be 0. + */ + NATIVE_WINDOW_BUFFER_AGE = 13, + + /* + * Returns the duration of the last dequeueBuffer call in microseconds + */ + NATIVE_WINDOW_LAST_DEQUEUE_DURATION = 14, + + /* + * Returns the duration of the last queueBuffer call in microseconds + */ + NATIVE_WINDOW_LAST_QUEUE_DURATION = 15, + + /* + * Returns the number of image layers that the ANativeWindow buffer + * contains. By default this is 1, unless a buffer is explicitly allocated + * to contain multiple layers. + */ + NATIVE_WINDOW_LAYER_COUNT = 16, + + /* + * Returns 1 if the native window is valid, 0 otherwise. native window is valid + * if it is safe (i.e. no crash will occur) to call any method on it. + */ + NATIVE_WINDOW_IS_VALID = 17, + + /* + * Returns 1 if NATIVE_WINDOW_GET_FRAME_TIMESTAMPS will return display + * present info, 0 if it won't. + */ + NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT = 18, + + /* + * The consumer end is capable of handling protected buffers, i.e. buffer + * with GRALLOC_USAGE_PROTECTED usage bits on. + */ + NATIVE_WINDOW_CONSUMER_IS_PROTECTED = 19, +}; + +/* Valid operations for the (*perform)() hook. + * + * Values marked as 'deprecated' are supported, but have been superceded by + * other functionality. + * + * Values marked as 'private' should be considered private to the framework. + * HAL implementation code with access to an ANativeWindow should not use these, + * as it may not interact properly with the framework's use of the + * ANativeWindow. + */ +enum { +// clang-format off + NATIVE_WINDOW_SET_USAGE = 0, + NATIVE_WINDOW_CONNECT = 1, /* deprecated */ + NATIVE_WINDOW_DISCONNECT = 2, /* deprecated */ + NATIVE_WINDOW_SET_CROP = 3, /* private */ + NATIVE_WINDOW_SET_BUFFER_COUNT = 4, + NATIVE_WINDOW_SET_BUFFERS_GEOMETRY = 5, /* deprecated */ + NATIVE_WINDOW_SET_BUFFERS_TRANSFORM = 6, + NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP = 7, + NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS = 8, + NATIVE_WINDOW_SET_BUFFERS_FORMAT = 9, + NATIVE_WINDOW_SET_SCALING_MODE = 10, /* private */ + NATIVE_WINDOW_LOCK = 11, /* private */ + NATIVE_WINDOW_UNLOCK_AND_POST = 12, /* private */ + NATIVE_WINDOW_API_CONNECT = 13, /* private */ + NATIVE_WINDOW_API_DISCONNECT = 14, /* private */ + NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */ + NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* private */ + NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17,/* private */ + NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18, + NATIVE_WINDOW_SET_BUFFERS_DATASPACE = 19, + NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */ + NATIVE_WINDOW_SET_SHARED_BUFFER_MODE = 21, + NATIVE_WINDOW_SET_AUTO_REFRESH = 22, + NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION= 23, + NATIVE_WINDOW_GET_NEXT_FRAME_ID = 24, + NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS = 25, + NATIVE_WINDOW_GET_COMPOSITOR_TIMING = 26, + NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27, + NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28, + NATIVE_WINDOW_GET_HDR_SUPPORT = 29, +// clang-format on +}; + +/* parameter for NATIVE_WINDOW_[API_][DIS]CONNECT */ +enum { + /* Buffers will be queued by EGL via eglSwapBuffers after being filled using + * OpenGL ES. + */ + NATIVE_WINDOW_API_EGL = 1, + + /* Buffers will be queued after being filled using the CPU + */ + NATIVE_WINDOW_API_CPU = 2, + + /* Buffers will be queued by Stagefright after being filled by a video + * decoder. The video decoder can either be a software or hardware decoder. + */ + NATIVE_WINDOW_API_MEDIA = 3, + + /* Buffers will be queued by the the camera HAL. + */ + NATIVE_WINDOW_API_CAMERA = 4, +}; + +/* parameter for NATIVE_WINDOW_SET_BUFFERS_TRANSFORM */ +enum { + /* flip source image horizontally */ + NATIVE_WINDOW_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H , + /* flip source image vertically */ + NATIVE_WINDOW_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V, + /* rotate source image 90 degrees clock-wise, and is applied after TRANSFORM_FLIP_{H|V} */ + NATIVE_WINDOW_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90, + /* rotate source image 180 degrees */ + NATIVE_WINDOW_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180, + /* rotate source image 270 degrees clock-wise */ + NATIVE_WINDOW_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270, + /* transforms source by the inverse transform of the screen it is displayed onto. This + * transform is applied last */ + NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY = 0x08 +}; + +/* parameter for NATIVE_WINDOW_SET_SCALING_MODE + * keep in sync with Surface.java in frameworks/base */ +enum { + /* the window content is not updated (frozen) until a buffer of + * the window size is received (enqueued) + */ + NATIVE_WINDOW_SCALING_MODE_FREEZE = 0, + /* the buffer is scaled in both dimensions to match the window size */ + NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW = 1, + /* the buffer is scaled uniformly such that the smaller dimension + * of the buffer matches the window size (cropping in the process) + */ + NATIVE_WINDOW_SCALING_MODE_SCALE_CROP = 2, + /* the window is clipped to the size of the buffer's crop rectangle; pixels + * outside the crop rectangle are treated as if they are completely + * transparent. + */ + NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP = 3, +}; + +/* values returned by the NATIVE_WINDOW_CONCRETE_TYPE query */ +enum { + NATIVE_WINDOW_FRAMEBUFFER = 0, /* FramebufferNativeWindow */ + NATIVE_WINDOW_SURFACE = 1, /* Surface */ +}; + +/* parameter for NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP + * + * Special timestamp value to indicate that timestamps should be auto-generated + * by the native window when queueBuffer is called. This is equal to INT64_MIN, + * defined directly to avoid problems with C99/C++ inclusion of stdint.h. + */ +static const int64_t NATIVE_WINDOW_TIMESTAMP_AUTO = (-9223372036854775807LL-1); + +/* parameter for NATIVE_WINDOW_GET_FRAME_TIMESTAMPS + * + * Special timestamp value to indicate the timestamps aren't yet known or + * that they are invalid. + */ +static const int64_t NATIVE_WINDOW_TIMESTAMP_PENDING = -2; +static const int64_t NATIVE_WINDOW_TIMESTAMP_INVALID = -1; + +struct ANativeWindow +{ +#ifdef __cplusplus + ANativeWindow() + : flags(0), minSwapInterval(0), maxSwapInterval(0), xdpi(0), ydpi(0) + { + common.magic = ANDROID_NATIVE_WINDOW_MAGIC; + common.version = sizeof(ANativeWindow); + memset(common.reserved, 0, sizeof(common.reserved)); + } + + /* Implement the methods that sp<ANativeWindow> expects so that it + can be used to automatically refcount ANativeWindow's. */ + void incStrong(const void* /*id*/) const { + common.incRef(const_cast<android_native_base_t*>(&common)); + } + void decStrong(const void* /*id*/) const { + common.decRef(const_cast<android_native_base_t*>(&common)); + } +#endif + + struct android_native_base_t common; + + /* flags describing some attributes of this surface or its updater */ + const uint32_t flags; + + /* min swap interval supported by this updated */ + const int minSwapInterval; + + /* max swap interval supported by this updated */ + const int maxSwapInterval; + + /* horizontal and vertical resolution in DPI */ + const float xdpi; + const float ydpi; + + /* Some storage reserved for the OEM's driver. */ + intptr_t oem[4]; + + /* + * Set the swap interval for this surface. + * + * Returns 0 on success or -errno on error. + */ + int (*setSwapInterval)(struct ANativeWindow* window, + int interval); + + /* + * Hook called by EGL to acquire a buffer. After this call, the buffer + * is not locked, so its content cannot be modified. This call may block if + * no buffers are available. + * + * The window holds a reference to the buffer between dequeueBuffer and + * either queueBuffer or cancelBuffer, so clients only need their own + * reference if they might use the buffer after queueing or canceling it. + * Holding a reference to a buffer after queueing or canceling it is only + * allowed if a specific buffer count has been set. + * + * Returns 0 on success or -errno on error. + * + * XXX: This function is deprecated. It will continue to work for some + * time for binary compatibility, but the new dequeueBuffer function that + * outputs a fence file descriptor should be used in its place. + */ + int (*dequeueBuffer_DEPRECATED)(struct ANativeWindow* window, + struct ANativeWindowBuffer** buffer); + + /* + * hook called by EGL to lock a buffer. This MUST be called before modifying + * the content of a buffer. The buffer must have been acquired with + * dequeueBuffer first. + * + * Returns 0 on success or -errno on error. + * + * XXX: This function is deprecated. It will continue to work for some + * time for binary compatibility, but it is essentially a no-op, and calls + * to it should be removed. + */ + int (*lockBuffer_DEPRECATED)(struct ANativeWindow* window, + struct ANativeWindowBuffer* buffer); + + /* + * Hook called by EGL when modifications to the render buffer are done. + * This unlocks and post the buffer. + * + * The window holds a reference to the buffer between dequeueBuffer and + * either queueBuffer or cancelBuffer, so clients only need their own + * reference if they might use the buffer after queueing or canceling it. + * Holding a reference to a buffer after queueing or canceling it is only + * allowed if a specific buffer count has been set. + * + * Buffers MUST be queued in the same order than they were dequeued. + * + * Returns 0 on success or -errno on error. + * + * XXX: This function is deprecated. It will continue to work for some + * time for binary compatibility, but the new queueBuffer function that + * takes a fence file descriptor should be used in its place (pass a value + * of -1 for the fence file descriptor if there is no valid one to pass). + */ + int (*queueBuffer_DEPRECATED)(struct ANativeWindow* window, + struct ANativeWindowBuffer* buffer); + + /* + * hook used to retrieve information about the native window. + * + * Returns 0 on success or -errno on error. + */ + int (*query)(const struct ANativeWindow* window, + int what, int* value); + + /* + * hook used to perform various operations on the surface. + * (*perform)() is a generic mechanism to add functionality to + * ANativeWindow while keeping backward binary compatibility. + * + * DO NOT CALL THIS HOOK DIRECTLY. Instead, use the helper functions + * defined below. + * + * (*perform)() returns -ENOENT if the 'what' parameter is not supported + * by the surface's implementation. + * + * See above for a list of valid operations, such as + * NATIVE_WINDOW_SET_USAGE or NATIVE_WINDOW_CONNECT + */ + int (*perform)(struct ANativeWindow* window, + int operation, ... ); + + /* + * Hook used to cancel a buffer that has been dequeued. + * No synchronization is performed between dequeue() and cancel(), so + * either external synchronization is needed, or these functions must be + * called from the same thread. + * + * The window holds a reference to the buffer between dequeueBuffer and + * either queueBuffer or cancelBuffer, so clients only need their own + * reference if they might use the buffer after queueing or canceling it. + * Holding a reference to a buffer after queueing or canceling it is only + * allowed if a specific buffer count has been set. + * + * XXX: This function is deprecated. It will continue to work for some + * time for binary compatibility, but the new cancelBuffer function that + * takes a fence file descriptor should be used in its place (pass a value + * of -1 for the fence file descriptor if there is no valid one to pass). + */ + int (*cancelBuffer_DEPRECATED)(struct ANativeWindow* window, + struct ANativeWindowBuffer* buffer); + + /* + * Hook called by EGL to acquire a buffer. This call may block if no + * buffers are available. + * + * The window holds a reference to the buffer between dequeueBuffer and + * either queueBuffer or cancelBuffer, so clients only need their own + * reference if they might use the buffer after queueing or canceling it. + * Holding a reference to a buffer after queueing or canceling it is only + * allowed if a specific buffer count has been set. + * + * The libsync fence file descriptor returned in the int pointed to by the + * fenceFd argument will refer to the fence that must signal before the + * dequeued buffer may be written to. A value of -1 indicates that the + * caller may access the buffer immediately without waiting on a fence. If + * a valid file descriptor is returned (i.e. any value except -1) then the + * caller is responsible for closing the file descriptor. + * + * Returns 0 on success or -errno on error. + */ + int (*dequeueBuffer)(struct ANativeWindow* window, + struct ANativeWindowBuffer** buffer, int* fenceFd); + + /* + * Hook called by EGL when modifications to the render buffer are done. + * This unlocks and post the buffer. + * + * The window holds a reference to the buffer between dequeueBuffer and + * either queueBuffer or cancelBuffer, so clients only need their own + * reference if they might use the buffer after queueing or canceling it. + * Holding a reference to a buffer after queueing or canceling it is only + * allowed if a specific buffer count has been set. + * + * The fenceFd argument specifies a libsync fence file descriptor for a + * fence that must signal before the buffer can be accessed. If the buffer + * can be accessed immediately then a value of -1 should be used. The + * caller must not use the file descriptor after it is passed to + * queueBuffer, and the ANativeWindow implementation is responsible for + * closing it. + * + * Returns 0 on success or -errno on error. + */ + int (*queueBuffer)(struct ANativeWindow* window, + struct ANativeWindowBuffer* buffer, int fenceFd); + + /* + * Hook used to cancel a buffer that has been dequeued. + * No synchronization is performed between dequeue() and cancel(), so + * either external synchronization is needed, or these functions must be + * called from the same thread. + * + * The window holds a reference to the buffer between dequeueBuffer and + * either queueBuffer or cancelBuffer, so clients only need their own + * reference if they might use the buffer after queueing or canceling it. + * Holding a reference to a buffer after queueing or canceling it is only + * allowed if a specific buffer count has been set. + * + * The fenceFd argument specifies a libsync fence file decsriptor for a + * fence that must signal before the buffer can be accessed. If the buffer + * can be accessed immediately then a value of -1 should be used. + * + * Note that if the client has not waited on the fence that was returned + * from dequeueBuffer, that same fence should be passed to cancelBuffer to + * ensure that future uses of the buffer are preceded by a wait on that + * fence. The caller must not use the file descriptor after it is passed + * to cancelBuffer, and the ANativeWindow implementation is responsible for + * closing it. + * + * Returns 0 on success or -errno on error. + */ + int (*cancelBuffer)(struct ANativeWindow* window, + struct ANativeWindowBuffer* buffer, int fenceFd); +}; + + /* Backwards compatibility: use ANativeWindow (struct ANativeWindow in C). + * android_native_window_t is deprecated. + */ +typedef struct ANativeWindow ANativeWindow; +typedef struct ANativeWindow android_native_window_t __deprecated; + +/* + * native_window_set_usage(..., usage) + * Sets the intended usage flags for the next buffers + * acquired with (*lockBuffer)() and on. + * By default (if this function is never called), a usage of + * GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE + * is assumed. + * Calling this function will usually cause following buffers to be + * reallocated. + */ + +static inline int native_window_set_usage( + struct ANativeWindow* window, int usage) +{ + return window->perform(window, NATIVE_WINDOW_SET_USAGE, usage); +} + +/* deprecated. Always returns 0. Don't call. */ +static inline int native_window_connect( + struct ANativeWindow* window __UNUSED, int api __UNUSED) __deprecated; + +static inline int native_window_connect( + struct ANativeWindow* window __UNUSED, int api __UNUSED) { + return 0; +} + +/* deprecated. Always returns 0. Don't call. */ +static inline int native_window_disconnect( + struct ANativeWindow* window __UNUSED, int api __UNUSED) __deprecated; + +static inline int native_window_disconnect( + struct ANativeWindow* window __UNUSED, int api __UNUSED) { + return 0; +} + +/* + * native_window_set_crop(..., crop) + * Sets which region of the next queued buffers needs to be considered. + * Depending on the scaling mode, a buffer's crop region is scaled and/or + * cropped to match the surface's size. This function sets the crop in + * pre-transformed buffer pixel coordinates. + * + * The specified crop region applies to all buffers queued after it is called. + * + * If 'crop' is NULL, subsequently queued buffers won't be cropped. + * + * An error is returned if for instance the crop region is invalid, out of the + * buffer's bound or if the window is invalid. + */ +static inline int native_window_set_crop( + struct ANativeWindow* window, + android_native_rect_t const * crop) +{ + return window->perform(window, NATIVE_WINDOW_SET_CROP, crop); +} + +/* + * native_window_set_post_transform_crop(..., crop) + * Sets which region of the next queued buffers needs to be considered. + * Depending on the scaling mode, a buffer's crop region is scaled and/or + * cropped to match the surface's size. This function sets the crop in + * post-transformed pixel coordinates. + * + * The specified crop region applies to all buffers queued after it is called. + * + * If 'crop' is NULL, subsequently queued buffers won't be cropped. + * + * An error is returned if for instance the crop region is invalid, out of the + * buffer's bound or if the window is invalid. + */ +static inline int native_window_set_post_transform_crop( + struct ANativeWindow* window, + android_native_rect_t const * crop) +{ + return window->perform(window, NATIVE_WINDOW_SET_POST_TRANSFORM_CROP, crop); +} + +/* + * native_window_set_active_rect(..., active_rect) + * + * This function is deprecated and will be removed soon. For now it simply + * sets the post-transform crop for compatibility while multi-project commits + * get checked. + */ +static inline int native_window_set_active_rect( + struct ANativeWindow* window, + android_native_rect_t const * active_rect) __deprecated; + +static inline int native_window_set_active_rect( + struct ANativeWindow* window, + android_native_rect_t const * active_rect) +{ + return native_window_set_post_transform_crop(window, active_rect); +} + +/* + * native_window_set_buffer_count(..., count) + * Sets the number of buffers associated with this native window. + */ +static inline int native_window_set_buffer_count( + struct ANativeWindow* window, + size_t bufferCount) +{ + return window->perform(window, NATIVE_WINDOW_SET_BUFFER_COUNT, bufferCount); +} + +/* + * native_window_set_buffers_geometry(..., int w, int h, int format) + * All buffers dequeued after this call will have the dimensions and format + * specified. A successful call to this function has the same effect as calling + * native_window_set_buffers_size and native_window_set_buffers_format. + * + * XXX: This function is deprecated. The native_window_set_buffers_dimensions + * and native_window_set_buffers_format functions should be used instead. + */ +static inline int native_window_set_buffers_geometry( + struct ANativeWindow* window, + int w, int h, int format) __deprecated; + +static inline int native_window_set_buffers_geometry( + struct ANativeWindow* window, + int w, int h, int format) +{ + return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_GEOMETRY, + w, h, format); +} + +/* + * native_window_set_buffers_dimensions(..., int w, int h) + * All buffers dequeued after this call will have the dimensions specified. + * In particular, all buffers will have a fixed-size, independent from the + * native-window size. They will be scaled according to the scaling mode + * (see native_window_set_scaling_mode) upon window composition. + * + * If w and h are 0, the normal behavior is restored. That is, dequeued buffers + * following this call will be sized to match the window's size. + * + * Calling this function will reset the window crop to a NULL value, which + * disables cropping of the buffers. + */ +static inline int native_window_set_buffers_dimensions( + struct ANativeWindow* window, + int w, int h) +{ + return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS, + w, h); +} + +/* + * native_window_set_buffers_user_dimensions(..., int w, int h) + * + * Sets the user buffer size for the window, which overrides the + * window's size. All buffers dequeued after this call will have the + * dimensions specified unless overridden by + * native_window_set_buffers_dimensions. All buffers will have a + * fixed-size, independent from the native-window size. They will be + * scaled according to the scaling mode (see + * native_window_set_scaling_mode) upon window composition. + * + * If w and h are 0, the normal behavior is restored. That is, the + * default buffer size will match the windows's size. + * + * Calling this function will reset the window crop to a NULL value, which + * disables cropping of the buffers. + */ +static inline int native_window_set_buffers_user_dimensions( + struct ANativeWindow* window, + int w, int h) +{ + return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS, + w, h); +} + +/* + * native_window_set_buffers_format(..., int format) + * All buffers dequeued after this call will have the format specified. + * + * If the specified format is 0, the default buffer format will be used. + */ +static inline int native_window_set_buffers_format( + struct ANativeWindow* window, + int format) +{ + return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_FORMAT, format); +} + +/* + * native_window_set_buffers_data_space(..., int dataSpace) + * All buffers queued after this call will be associated with the dataSpace + * parameter specified. + * + * dataSpace specifies additional information about the buffer that's dependent + * on the buffer format and the endpoints. For example, it can be used to convey + * the color space of the image data in the buffer, or it can be used to + * indicate that the buffers contain depth measurement data instead of color + * images. The default dataSpace is 0, HAL_DATASPACE_UNKNOWN, unless it has been + * overridden by the consumer. + */ +static inline int native_window_set_buffers_data_space( + struct ANativeWindow* window, + android_dataspace_t dataSpace) +{ + return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_DATASPACE, + dataSpace); +} + +/* + * native_window_set_buffers_transform(..., int transform) + * All buffers queued after this call will be displayed transformed according + * to the transform parameter specified. + */ +static inline int native_window_set_buffers_transform( + struct ANativeWindow* window, + int transform) +{ + return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TRANSFORM, + transform); +} + +/* + * native_window_set_buffers_sticky_transform(..., int transform) + * All buffers queued after this call will be displayed transformed according + * to the transform parameter specified applied on top of the regular buffer + * transform. Setting this transform will disable the transform hint. + * + * Temporary - This is only intended to be used by the LEGACY camera mode, do + * not use this for anything else. + */ +static inline int native_window_set_buffers_sticky_transform( + struct ANativeWindow* window, + int transform) +{ + return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM, + transform); +} + +/* + * native_window_set_buffers_timestamp(..., int64_t timestamp) + * All buffers queued after this call will be associated with the timestamp + * parameter specified. If the timestamp is set to NATIVE_WINDOW_TIMESTAMP_AUTO + * (the default), timestamps will be generated automatically when queueBuffer is + * called. The timestamp is measured in nanoseconds, and is normally monotonically + * increasing. The timestamp should be unaffected by time-of-day adjustments, + * and for a camera should be strictly monotonic but for a media player may be + * reset when the position is set. + */ +static inline int native_window_set_buffers_timestamp( + struct ANativeWindow* window, + int64_t timestamp) +{ + return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP, + timestamp); +} + +/* + * native_window_set_scaling_mode(..., int mode) + * All buffers queued after this call will be associated with the scaling mode + * specified. + */ +static inline int native_window_set_scaling_mode( + struct ANativeWindow* window, + int mode) +{ + return window->perform(window, NATIVE_WINDOW_SET_SCALING_MODE, + mode); +} + +/* + * native_window_api_connect(..., int api) + * connects an API to this window. only one API can be connected at a time. + * Returns -EINVAL if for some reason the window cannot be connected, which + * can happen if it's connected to some other API. + */ +static inline int native_window_api_connect( + struct ANativeWindow* window, int api) +{ + return window->perform(window, NATIVE_WINDOW_API_CONNECT, api); +} + +/* + * native_window_api_disconnect(..., int api) + * disconnect the API from this window. + * An error is returned if for instance the window wasn't connected in the + * first place. + */ +static inline int native_window_api_disconnect( + struct ANativeWindow* window, int api) +{ + return window->perform(window, NATIVE_WINDOW_API_DISCONNECT, api); +} + +/* + * native_window_dequeue_buffer_and_wait(...) + * Dequeue a buffer and wait on the fence associated with that buffer. The + * buffer may safely be accessed immediately upon this function returning. An + * error is returned if either of the dequeue or the wait operations fail. + */ +static inline int native_window_dequeue_buffer_and_wait(ANativeWindow *anw, + struct ANativeWindowBuffer** anb) { + return anw->dequeueBuffer_DEPRECATED(anw, anb); +} + +/* + * native_window_set_sideband_stream(..., native_handle_t*) + * Attach a sideband buffer stream to a native window. + */ +static inline int native_window_set_sideband_stream( + struct ANativeWindow* window, + native_handle_t* sidebandHandle) +{ + return window->perform(window, NATIVE_WINDOW_SET_SIDEBAND_STREAM, + sidebandHandle); +} + +/* + * native_window_set_surface_damage(..., android_native_rect_t* rects, int numRects) + * Set the surface damage (i.e., the region of the surface that has changed + * since the previous frame). The damage set by this call will be reset (to the + * default of full-surface damage) after calling queue, so this must be called + * prior to every frame with damage that does not cover the whole surface if the + * caller desires downstream consumers to use this optimization. + * + * The damage region is specified as an array of rectangles, with the important + * caveat that the origin of the surface is considered to be the bottom-left + * corner, as in OpenGL ES. + * + * If numRects is set to 0, rects may be NULL, and the surface damage will be + * set to the full surface (the same as if this function had not been called for + * this frame). + */ +static inline int native_window_set_surface_damage( + struct ANativeWindow* window, + const android_native_rect_t* rects, size_t numRects) +{ + return window->perform(window, NATIVE_WINDOW_SET_SURFACE_DAMAGE, + rects, numRects); +} + +/* + * native_window_set_shared_buffer_mode(..., bool sharedBufferMode) + * Enable/disable shared buffer mode + */ +static inline int native_window_set_shared_buffer_mode( + struct ANativeWindow* window, + bool sharedBufferMode) +{ + return window->perform(window, NATIVE_WINDOW_SET_SHARED_BUFFER_MODE, + sharedBufferMode); +} + +/* + * native_window_set_auto_refresh(..., autoRefresh) + * Enable/disable auto refresh when in shared buffer mode + */ +static inline int native_window_set_auto_refresh( + struct ANativeWindow* window, + bool autoRefresh) +{ + return window->perform(window, NATIVE_WINDOW_SET_AUTO_REFRESH, autoRefresh); +} + +static inline int native_window_get_refresh_cycle_duration( + struct ANativeWindow* window, + int64_t* outRefreshDuration) +{ + return window->perform(window, NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION, + outRefreshDuration); +} + +static inline int native_window_get_next_frame_id( + struct ANativeWindow* window, uint64_t* frameId) +{ + return window->perform(window, NATIVE_WINDOW_GET_NEXT_FRAME_ID, frameId); +} + +static inline int native_window_enable_frame_timestamps( + struct ANativeWindow* window, bool enable) +{ + return window->perform(window, NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS, + enable); +} + +static inline int native_window_get_compositor_timing( + struct ANativeWindow* window, + int64_t* compositeDeadline, int64_t* compositeInterval, + int64_t* compositeToPresentLatency) +{ + return window->perform(window, NATIVE_WINDOW_GET_COMPOSITOR_TIMING, + compositeDeadline, compositeInterval, compositeToPresentLatency); +} + +static inline int native_window_get_frame_timestamps( + struct ANativeWindow* window, uint64_t frameId, + int64_t* outRequestedPresentTime, int64_t* outAcquireTime, + int64_t* outLatchTime, int64_t* outFirstRefreshStartTime, + int64_t* outLastRefreshStartTime, int64_t* outGpuCompositionDoneTime, + int64_t* outDisplayPresentTime, int64_t* outDequeueReadyTime, + int64_t* outReleaseTime) +{ + return window->perform(window, NATIVE_WINDOW_GET_FRAME_TIMESTAMPS, + frameId, outRequestedPresentTime, outAcquireTime, outLatchTime, + outFirstRefreshStartTime, outLastRefreshStartTime, + outGpuCompositionDoneTime, outDisplayPresentTime, + outDequeueReadyTime, outReleaseTime); +} + +static inline int native_window_get_wide_color_support( + struct ANativeWindow* window, bool* outSupport) { + return window->perform(window, NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT, + outSupport); +} + +static inline int native_window_get_hdr_support(struct ANativeWindow* window, + bool* outSupport) { + return window->perform(window, NATIVE_WINDOW_GET_HDR_SUPPORT, outSupport); +} + +__END_DECLS diff --git a/libsystem/include/system/window.h b/libsystem/include/system/window.h index f43970549..efa10d647 100644 --- a/libsystem/include/system/window.h +++ b/libsystem/include/system/window.h @@ -17,997 +17,6 @@ #ifndef SYSTEM_CORE_INCLUDE_ANDROID_WINDOW_H #define SYSTEM_CORE_INCLUDE_ANDROID_WINDOW_H -#include <cutils/native_handle.h> -#include <errno.h> -#include <limits.h> -#include <stdint.h> -#include <string.h> -#include <sys/cdefs.h> -#include <system/graphics.h> -#include <unistd.h> -#include <stdbool.h> - -#ifndef __UNUSED -#define __UNUSED __attribute__((__unused__)) -#endif -#ifndef __deprecated -#define __deprecated __attribute__((__deprecated__)) -#endif - -__BEGIN_DECLS - -/*****************************************************************************/ - -#ifdef __cplusplus -#define ANDROID_NATIVE_UNSIGNED_CAST(x) static_cast<unsigned int>(x) -#else -#define ANDROID_NATIVE_UNSIGNED_CAST(x) ((unsigned int)(x)) -#endif - -#define ANDROID_NATIVE_MAKE_CONSTANT(a,b,c,d) \ - ((ANDROID_NATIVE_UNSIGNED_CAST(a) << 24) | \ - (ANDROID_NATIVE_UNSIGNED_CAST(b) << 16) | \ - (ANDROID_NATIVE_UNSIGNED_CAST(c) << 8) | \ - (ANDROID_NATIVE_UNSIGNED_CAST(d))) - -#define ANDROID_NATIVE_WINDOW_MAGIC \ - ANDROID_NATIVE_MAKE_CONSTANT('_','w','n','d') - -#define ANDROID_NATIVE_BUFFER_MAGIC \ - ANDROID_NATIVE_MAKE_CONSTANT('_','b','f','r') - -// --------------------------------------------------------------------------- - -// This #define may be used to conditionally compile device-specific code to -// support either the prior ANativeWindow interface, which did not pass libsync -// fences around, or the new interface that does. This #define is only present -// when the ANativeWindow interface does include libsync support. -#define ANDROID_NATIVE_WINDOW_HAS_SYNC 1 - -// --------------------------------------------------------------------------- - -typedef const native_handle_t* buffer_handle_t; - -// --------------------------------------------------------------------------- - -typedef struct android_native_rect_t -{ - int32_t left; - int32_t top; - int32_t right; - int32_t bottom; -} android_native_rect_t; - -// --------------------------------------------------------------------------- - -typedef struct android_native_base_t -{ - /* a magic value defined by the actual EGL native type */ - int magic; - - /* the sizeof() of the actual EGL native type */ - int version; - - void* reserved[4]; - - /* reference-counting interface */ - void (*incRef)(struct android_native_base_t* base); - void (*decRef)(struct android_native_base_t* base); -} android_native_base_t; - -typedef struct ANativeWindowBuffer -{ -#ifdef __cplusplus - ANativeWindowBuffer() { - common.magic = ANDROID_NATIVE_BUFFER_MAGIC; - common.version = sizeof(ANativeWindowBuffer); - memset(common.reserved, 0, sizeof(common.reserved)); - } - - // Implement the methods that sp<ANativeWindowBuffer> expects so that it - // can be used to automatically refcount ANativeWindowBuffer's. - void incStrong(const void* /*id*/) const { - common.incRef(const_cast<android_native_base_t*>(&common)); - } - void decStrong(const void* /*id*/) const { - common.decRef(const_cast<android_native_base_t*>(&common)); - } -#endif - - struct android_native_base_t common; - - int width; - int height; - int stride; - int format; - int usage; - - void* reserved[2]; - - buffer_handle_t handle; - - void* reserved_proc[8]; -} ANativeWindowBuffer_t; - -// Old typedef for backwards compatibility. -typedef ANativeWindowBuffer_t android_native_buffer_t; - -// --------------------------------------------------------------------------- - -/* attributes queriable with query() */ -enum { - NATIVE_WINDOW_WIDTH = 0, - NATIVE_WINDOW_HEIGHT = 1, - NATIVE_WINDOW_FORMAT = 2, - - /* The minimum number of buffers that must remain un-dequeued after a buffer - * has been queued. This value applies only if set_buffer_count was used to - * override the number of buffers and if a buffer has since been queued. - * Users of the set_buffer_count ANativeWindow method should query this - * value before calling set_buffer_count. If it is necessary to have N - * buffers simultaneously dequeued as part of the steady-state operation, - * and this query returns M then N+M buffers should be requested via - * native_window_set_buffer_count. - * - * Note that this value does NOT apply until a single buffer has been - * queued. In particular this means that it is possible to: - * - * 1. Query M = min undequeued buffers - * 2. Set the buffer count to N + M - * 3. Dequeue all N + M buffers - * 4. Cancel M buffers - * 5. Queue, dequeue, queue, dequeue, ad infinitum - */ - NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS = 3, - - /* Check whether queueBuffer operations on the ANativeWindow send the buffer - * to the window compositor. The query sets the returned 'value' argument - * to 1 if the ANativeWindow DOES send queued buffers directly to the window - * compositor and 0 if the buffers do not go directly to the window - * compositor. - * - * This can be used to determine whether protected buffer content should be - * sent to the ANativeWindow. Note, however, that a result of 1 does NOT - * indicate that queued buffers will be protected from applications or users - * capturing their contents. If that behavior is desired then some other - * mechanism (e.g. the GRALLOC_USAGE_PROTECTED flag) should be used in - * conjunction with this query. - */ - NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER = 4, - - /* Get the concrete type of a ANativeWindow. See below for the list of - * possible return values. - * - * This query should not be used outside the Android framework and will - * likely be removed in the near future. - */ - NATIVE_WINDOW_CONCRETE_TYPE = 5, - - - /* - * Default width and height of ANativeWindow buffers, these are the - * dimensions of the window buffers irrespective of the - * NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS call and match the native window - * size unless overridden by NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS. - */ - NATIVE_WINDOW_DEFAULT_WIDTH = 6, - NATIVE_WINDOW_DEFAULT_HEIGHT = 7, - - /* - * transformation that will most-likely be applied to buffers. This is only - * a hint, the actual transformation applied might be different. - * - * INTENDED USE: - * - * The transform hint can be used by a producer, for instance the GLES - * driver, to pre-rotate the rendering such that the final transformation - * in the composer is identity. This can be very useful when used in - * conjunction with the h/w composer HAL, in situations where it - * cannot handle arbitrary rotations. - * - * 1. Before dequeuing a buffer, the GL driver (or any other ANW client) - * queries the ANW for NATIVE_WINDOW_TRANSFORM_HINT. - * - * 2. The GL driver overrides the width and height of the ANW to - * account for NATIVE_WINDOW_TRANSFORM_HINT. This is done by querying - * NATIVE_WINDOW_DEFAULT_{WIDTH | HEIGHT}, swapping the dimensions - * according to NATIVE_WINDOW_TRANSFORM_HINT and calling - * native_window_set_buffers_dimensions(). - * - * 3. The GL driver dequeues a buffer of the new pre-rotated size. - * - * 4. The GL driver renders to the buffer such that the image is - * already transformed, that is applying NATIVE_WINDOW_TRANSFORM_HINT - * to the rendering. - * - * 5. The GL driver calls native_window_set_transform to apply - * inverse transformation to the buffer it just rendered. - * In order to do this, the GL driver needs - * to calculate the inverse of NATIVE_WINDOW_TRANSFORM_HINT, this is - * done easily: - * - * int hintTransform, inverseTransform; - * query(..., NATIVE_WINDOW_TRANSFORM_HINT, &hintTransform); - * inverseTransform = hintTransform; - * if (hintTransform & HAL_TRANSFORM_ROT_90) - * inverseTransform ^= HAL_TRANSFORM_ROT_180; - * - * - * 6. The GL driver queues the pre-transformed buffer. - * - * 7. The composer combines the buffer transform with the display - * transform. If the buffer transform happens to cancel out the - * display transform then no rotation is needed. - * - */ - NATIVE_WINDOW_TRANSFORM_HINT = 8, - - /* - * Boolean that indicates whether the consumer is running more than - * one buffer behind the producer. - */ - NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND = 9, - - /* - * The consumer gralloc usage bits currently set by the consumer. - * The values are defined in hardware/libhardware/include/gralloc.h. - */ - NATIVE_WINDOW_CONSUMER_USAGE_BITS = 10, - - /** - * Transformation that will by applied to buffers by the hwcomposer. - * This must not be set or checked by producer endpoints, and will - * disable the transform hint set in SurfaceFlinger (see - * NATIVE_WINDOW_TRANSFORM_HINT). - * - * INTENDED USE: - * Temporary - Please do not use this. This is intended only to be used - * by the camera's LEGACY mode. - * - * In situations where a SurfaceFlinger client wishes to set a transform - * that is not visible to the producer, and will always be applied in the - * hardware composer, the client can set this flag with - * native_window_set_buffers_sticky_transform. This can be used to rotate - * and flip buffers consumed by hardware composer without actually changing - * the aspect ratio of the buffers produced. - */ - NATIVE_WINDOW_STICKY_TRANSFORM = 11, - - /** - * The default data space for the buffers as set by the consumer. - * The values are defined in graphics.h. - */ - NATIVE_WINDOW_DEFAULT_DATASPACE = 12, - - /* - * Returns the age of the contents of the most recently dequeued buffer as - * the number of frames that have elapsed since it was last queued. For - * example, if the window is double-buffered, the age of any given buffer in - * steady state will be 2. If the dequeued buffer has never been queued, its - * age will be 0. - */ - NATIVE_WINDOW_BUFFER_AGE = 13, - - /* - * Returns the duration of the last dequeueBuffer call in microseconds - */ - NATIVE_WINDOW_LAST_DEQUEUE_DURATION = 14, - - /* - * Returns the duration of the last queueBuffer call in microseconds - */ - NATIVE_WINDOW_LAST_QUEUE_DURATION = 15, -}; - -/* Valid operations for the (*perform)() hook. - * - * Values marked as 'deprecated' are supported, but have been superceded by - * other functionality. - * - * Values marked as 'private' should be considered private to the framework. - * HAL implementation code with access to an ANativeWindow should not use these, - * as it may not interact properly with the framework's use of the - * ANativeWindow. - */ -enum { - NATIVE_WINDOW_SET_USAGE = 0, - NATIVE_WINDOW_CONNECT = 1, /* deprecated */ - NATIVE_WINDOW_DISCONNECT = 2, /* deprecated */ - NATIVE_WINDOW_SET_CROP = 3, /* private */ - NATIVE_WINDOW_SET_BUFFER_COUNT = 4, - NATIVE_WINDOW_SET_BUFFERS_GEOMETRY = 5, /* deprecated */ - NATIVE_WINDOW_SET_BUFFERS_TRANSFORM = 6, - NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP = 7, - NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS = 8, - NATIVE_WINDOW_SET_BUFFERS_FORMAT = 9, - NATIVE_WINDOW_SET_SCALING_MODE = 10, /* private */ - NATIVE_WINDOW_LOCK = 11, /* private */ - NATIVE_WINDOW_UNLOCK_AND_POST = 12, /* private */ - NATIVE_WINDOW_API_CONNECT = 13, /* private */ - NATIVE_WINDOW_API_DISCONNECT = 14, /* private */ - NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */ - NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* private */ - NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17,/* private */ - NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18, - NATIVE_WINDOW_SET_BUFFERS_DATASPACE = 19, - NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */ - NATIVE_WINDOW_SET_SHARED_BUFFER_MODE = 21, - NATIVE_WINDOW_SET_AUTO_REFRESH = 22, - NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 23, -}; - -/* parameter for NATIVE_WINDOW_[API_][DIS]CONNECT */ -enum { - /* Buffers will be queued by EGL via eglSwapBuffers after being filled using - * OpenGL ES. - */ - NATIVE_WINDOW_API_EGL = 1, - - /* Buffers will be queued after being filled using the CPU - */ - NATIVE_WINDOW_API_CPU = 2, - - /* Buffers will be queued by Stagefright after being filled by a video - * decoder. The video decoder can either be a software or hardware decoder. - */ - NATIVE_WINDOW_API_MEDIA = 3, - - /* Buffers will be queued by the the camera HAL. - */ - NATIVE_WINDOW_API_CAMERA = 4, -}; - -/* parameter for NATIVE_WINDOW_SET_BUFFERS_TRANSFORM */ -enum { - /* flip source image horizontally */ - NATIVE_WINDOW_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H , - /* flip source image vertically */ - NATIVE_WINDOW_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V, - /* rotate source image 90 degrees clock-wise, and is applied after TRANSFORM_FLIP_{H|V} */ - NATIVE_WINDOW_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90, - /* rotate source image 180 degrees */ - NATIVE_WINDOW_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180, - /* rotate source image 270 degrees clock-wise */ - NATIVE_WINDOW_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270, - /* transforms source by the inverse transform of the screen it is displayed onto. This - * transform is applied last */ - NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY = 0x08 -}; - -/* parameter for NATIVE_WINDOW_SET_SCALING_MODE - * keep in sync with Surface.java in frameworks/base */ -enum { - /* the window content is not updated (frozen) until a buffer of - * the window size is received (enqueued) - */ - NATIVE_WINDOW_SCALING_MODE_FREEZE = 0, - /* the buffer is scaled in both dimensions to match the window size */ - NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW = 1, - /* the buffer is scaled uniformly such that the smaller dimension - * of the buffer matches the window size (cropping in the process) - */ - NATIVE_WINDOW_SCALING_MODE_SCALE_CROP = 2, - /* the window is clipped to the size of the buffer's crop rectangle; pixels - * outside the crop rectangle are treated as if they are completely - * transparent. - */ - NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP = 3, -}; - -/* values returned by the NATIVE_WINDOW_CONCRETE_TYPE query */ -enum { - NATIVE_WINDOW_FRAMEBUFFER = 0, /* FramebufferNativeWindow */ - NATIVE_WINDOW_SURFACE = 1, /* Surface */ -}; - -/* parameter for NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP - * - * Special timestamp value to indicate that timestamps should be auto-generated - * by the native window when queueBuffer is called. This is equal to INT64_MIN, - * defined directly to avoid problems with C99/C++ inclusion of stdint.h. - */ -static const int64_t NATIVE_WINDOW_TIMESTAMP_AUTO = (-9223372036854775807LL-1); - -struct ANativeWindow -{ -#ifdef __cplusplus - ANativeWindow() - : flags(0), minSwapInterval(0), maxSwapInterval(0), xdpi(0), ydpi(0) - { - common.magic = ANDROID_NATIVE_WINDOW_MAGIC; - common.version = sizeof(ANativeWindow); - memset(common.reserved, 0, sizeof(common.reserved)); - } - - /* Implement the methods that sp<ANativeWindow> expects so that it - can be used to automatically refcount ANativeWindow's. */ - void incStrong(const void* /*id*/) const { - common.incRef(const_cast<android_native_base_t*>(&common)); - } - void decStrong(const void* /*id*/) const { - common.decRef(const_cast<android_native_base_t*>(&common)); - } -#endif - - struct android_native_base_t common; - - /* flags describing some attributes of this surface or its updater */ - const uint32_t flags; - - /* min swap interval supported by this updated */ - const int minSwapInterval; - - /* max swap interval supported by this updated */ - const int maxSwapInterval; - - /* horizontal and vertical resolution in DPI */ - const float xdpi; - const float ydpi; - - /* Some storage reserved for the OEM's driver. */ - intptr_t oem[4]; - - /* - * Set the swap interval for this surface. - * - * Returns 0 on success or -errno on error. - */ - int (*setSwapInterval)(struct ANativeWindow* window, - int interval); - - /* - * Hook called by EGL to acquire a buffer. After this call, the buffer - * is not locked, so its content cannot be modified. This call may block if - * no buffers are available. - * - * The window holds a reference to the buffer between dequeueBuffer and - * either queueBuffer or cancelBuffer, so clients only need their own - * reference if they might use the buffer after queueing or canceling it. - * Holding a reference to a buffer after queueing or canceling it is only - * allowed if a specific buffer count has been set. - * - * Returns 0 on success or -errno on error. - * - * XXX: This function is deprecated. It will continue to work for some - * time for binary compatibility, but the new dequeueBuffer function that - * outputs a fence file descriptor should be used in its place. - */ - int (*dequeueBuffer_DEPRECATED)(struct ANativeWindow* window, - struct ANativeWindowBuffer** buffer); - - /* - * hook called by EGL to lock a buffer. This MUST be called before modifying - * the content of a buffer. The buffer must have been acquired with - * dequeueBuffer first. - * - * Returns 0 on success or -errno on error. - * - * XXX: This function is deprecated. It will continue to work for some - * time for binary compatibility, but it is essentially a no-op, and calls - * to it should be removed. - */ - int (*lockBuffer_DEPRECATED)(struct ANativeWindow* window, - struct ANativeWindowBuffer* buffer); - - /* - * Hook called by EGL when modifications to the render buffer are done. - * This unlocks and post the buffer. - * - * The window holds a reference to the buffer between dequeueBuffer and - * either queueBuffer or cancelBuffer, so clients only need their own - * reference if they might use the buffer after queueing or canceling it. - * Holding a reference to a buffer after queueing or canceling it is only - * allowed if a specific buffer count has been set. - * - * Buffers MUST be queued in the same order than they were dequeued. - * - * Returns 0 on success or -errno on error. - * - * XXX: This function is deprecated. It will continue to work for some - * time for binary compatibility, but the new queueBuffer function that - * takes a fence file descriptor should be used in its place (pass a value - * of -1 for the fence file descriptor if there is no valid one to pass). - */ - int (*queueBuffer_DEPRECATED)(struct ANativeWindow* window, - struct ANativeWindowBuffer* buffer); - - /* - * hook used to retrieve information about the native window. - * - * Returns 0 on success or -errno on error. - */ - int (*query)(const struct ANativeWindow* window, - int what, int* value); - - /* - * hook used to perform various operations on the surface. - * (*perform)() is a generic mechanism to add functionality to - * ANativeWindow while keeping backward binary compatibility. - * - * DO NOT CALL THIS HOOK DIRECTLY. Instead, use the helper functions - * defined below. - * - * (*perform)() returns -ENOENT if the 'what' parameter is not supported - * by the surface's implementation. - * - * See above for a list of valid operations, such as - * NATIVE_WINDOW_SET_USAGE or NATIVE_WINDOW_CONNECT - */ - int (*perform)(struct ANativeWindow* window, - int operation, ... ); - - /* - * Hook used to cancel a buffer that has been dequeued. - * No synchronization is performed between dequeue() and cancel(), so - * either external synchronization is needed, or these functions must be - * called from the same thread. - * - * The window holds a reference to the buffer between dequeueBuffer and - * either queueBuffer or cancelBuffer, so clients only need their own - * reference if they might use the buffer after queueing or canceling it. - * Holding a reference to a buffer after queueing or canceling it is only - * allowed if a specific buffer count has been set. - * - * XXX: This function is deprecated. It will continue to work for some - * time for binary compatibility, but the new cancelBuffer function that - * takes a fence file descriptor should be used in its place (pass a value - * of -1 for the fence file descriptor if there is no valid one to pass). - */ - int (*cancelBuffer_DEPRECATED)(struct ANativeWindow* window, - struct ANativeWindowBuffer* buffer); - - /* - * Hook called by EGL to acquire a buffer. This call may block if no - * buffers are available. - * - * The window holds a reference to the buffer between dequeueBuffer and - * either queueBuffer or cancelBuffer, so clients only need their own - * reference if they might use the buffer after queueing or canceling it. - * Holding a reference to a buffer after queueing or canceling it is only - * allowed if a specific buffer count has been set. - * - * The libsync fence file descriptor returned in the int pointed to by the - * fenceFd argument will refer to the fence that must signal before the - * dequeued buffer may be written to. A value of -1 indicates that the - * caller may access the buffer immediately without waiting on a fence. If - * a valid file descriptor is returned (i.e. any value except -1) then the - * caller is responsible for closing the file descriptor. - * - * Returns 0 on success or -errno on error. - */ - int (*dequeueBuffer)(struct ANativeWindow* window, - struct ANativeWindowBuffer** buffer, int* fenceFd); - - /* - * Hook called by EGL when modifications to the render buffer are done. - * This unlocks and post the buffer. - * - * The window holds a reference to the buffer between dequeueBuffer and - * either queueBuffer or cancelBuffer, so clients only need their own - * reference if they might use the buffer after queueing or canceling it. - * Holding a reference to a buffer after queueing or canceling it is only - * allowed if a specific buffer count has been set. - * - * The fenceFd argument specifies a libsync fence file descriptor for a - * fence that must signal before the buffer can be accessed. If the buffer - * can be accessed immediately then a value of -1 should be used. The - * caller must not use the file descriptor after it is passed to - * queueBuffer, and the ANativeWindow implementation is responsible for - * closing it. - * - * Returns 0 on success or -errno on error. - */ - int (*queueBuffer)(struct ANativeWindow* window, - struct ANativeWindowBuffer* buffer, int fenceFd); - - /* - * Hook used to cancel a buffer that has been dequeued. - * No synchronization is performed between dequeue() and cancel(), so - * either external synchronization is needed, or these functions must be - * called from the same thread. - * - * The window holds a reference to the buffer between dequeueBuffer and - * either queueBuffer or cancelBuffer, so clients only need their own - * reference if they might use the buffer after queueing or canceling it. - * Holding a reference to a buffer after queueing or canceling it is only - * allowed if a specific buffer count has been set. - * - * The fenceFd argument specifies a libsync fence file decsriptor for a - * fence that must signal before the buffer can be accessed. If the buffer - * can be accessed immediately then a value of -1 should be used. - * - * Note that if the client has not waited on the fence that was returned - * from dequeueBuffer, that same fence should be passed to cancelBuffer to - * ensure that future uses of the buffer are preceded by a wait on that - * fence. The caller must not use the file descriptor after it is passed - * to cancelBuffer, and the ANativeWindow implementation is responsible for - * closing it. - * - * Returns 0 on success or -errno on error. - */ - int (*cancelBuffer)(struct ANativeWindow* window, - struct ANativeWindowBuffer* buffer, int fenceFd); -}; - - /* Backwards compatibility: use ANativeWindow (struct ANativeWindow in C). - * android_native_window_t is deprecated. - */ -typedef struct ANativeWindow ANativeWindow; -typedef struct ANativeWindow android_native_window_t __deprecated; - -/* - * native_window_set_usage(..., usage) - * Sets the intended usage flags for the next buffers - * acquired with (*lockBuffer)() and on. - * By default (if this function is never called), a usage of - * GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE - * is assumed. - * Calling this function will usually cause following buffers to be - * reallocated. - */ - -static inline int native_window_set_usage( - struct ANativeWindow* window, int usage) -{ - return window->perform(window, NATIVE_WINDOW_SET_USAGE, usage); -} - -/* deprecated. Always returns 0. Don't call. */ -static inline int native_window_connect( - struct ANativeWindow* window __UNUSED, int api __UNUSED) __deprecated; - -static inline int native_window_connect( - struct ANativeWindow* window __UNUSED, int api __UNUSED) { - return 0; -} - -/* deprecated. Always returns 0. Don't call. */ -static inline int native_window_disconnect( - struct ANativeWindow* window __UNUSED, int api __UNUSED) __deprecated; - -static inline int native_window_disconnect( - struct ANativeWindow* window __UNUSED, int api __UNUSED) { - return 0; -} - -/* - * native_window_set_crop(..., crop) - * Sets which region of the next queued buffers needs to be considered. - * Depending on the scaling mode, a buffer's crop region is scaled and/or - * cropped to match the surface's size. This function sets the crop in - * pre-transformed buffer pixel coordinates. - * - * The specified crop region applies to all buffers queued after it is called. - * - * If 'crop' is NULL, subsequently queued buffers won't be cropped. - * - * An error is returned if for instance the crop region is invalid, out of the - * buffer's bound or if the window is invalid. - */ -static inline int native_window_set_crop( - struct ANativeWindow* window, - android_native_rect_t const * crop) -{ - return window->perform(window, NATIVE_WINDOW_SET_CROP, crop); -} - -/* - * native_window_set_post_transform_crop(..., crop) - * Sets which region of the next queued buffers needs to be considered. - * Depending on the scaling mode, a buffer's crop region is scaled and/or - * cropped to match the surface's size. This function sets the crop in - * post-transformed pixel coordinates. - * - * The specified crop region applies to all buffers queued after it is called. - * - * If 'crop' is NULL, subsequently queued buffers won't be cropped. - * - * An error is returned if for instance the crop region is invalid, out of the - * buffer's bound or if the window is invalid. - */ -static inline int native_window_set_post_transform_crop( - struct ANativeWindow* window, - android_native_rect_t const * crop) -{ - return window->perform(window, NATIVE_WINDOW_SET_POST_TRANSFORM_CROP, crop); -} - -/* - * native_window_set_active_rect(..., active_rect) - * - * This function is deprecated and will be removed soon. For now it simply - * sets the post-transform crop for compatibility while multi-project commits - * get checked. - */ -static inline int native_window_set_active_rect( - struct ANativeWindow* window, - android_native_rect_t const * active_rect) __deprecated; - -static inline int native_window_set_active_rect( - struct ANativeWindow* window, - android_native_rect_t const * active_rect) -{ - return native_window_set_post_transform_crop(window, active_rect); -} - -/* - * native_window_set_buffer_count(..., count) - * Sets the number of buffers associated with this native window. - */ -static inline int native_window_set_buffer_count( - struct ANativeWindow* window, - size_t bufferCount) -{ - return window->perform(window, NATIVE_WINDOW_SET_BUFFER_COUNT, bufferCount); -} - -/* - * native_window_set_buffers_geometry(..., int w, int h, int format) - * All buffers dequeued after this call will have the dimensions and format - * specified. A successful call to this function has the same effect as calling - * native_window_set_buffers_size and native_window_set_buffers_format. - * - * XXX: This function is deprecated. The native_window_set_buffers_dimensions - * and native_window_set_buffers_format functions should be used instead. - */ -static inline int native_window_set_buffers_geometry( - struct ANativeWindow* window, - int w, int h, int format) __deprecated; - -static inline int native_window_set_buffers_geometry( - struct ANativeWindow* window, - int w, int h, int format) -{ - return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_GEOMETRY, - w, h, format); -} - -/* - * native_window_set_buffers_dimensions(..., int w, int h) - * All buffers dequeued after this call will have the dimensions specified. - * In particular, all buffers will have a fixed-size, independent from the - * native-window size. They will be scaled according to the scaling mode - * (see native_window_set_scaling_mode) upon window composition. - * - * If w and h are 0, the normal behavior is restored. That is, dequeued buffers - * following this call will be sized to match the window's size. - * - * Calling this function will reset the window crop to a NULL value, which - * disables cropping of the buffers. - */ -static inline int native_window_set_buffers_dimensions( - struct ANativeWindow* window, - int w, int h) -{ - return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS, - w, h); -} - -/* - * native_window_set_buffers_user_dimensions(..., int w, int h) - * - * Sets the user buffer size for the window, which overrides the - * window's size. All buffers dequeued after this call will have the - * dimensions specified unless overridden by - * native_window_set_buffers_dimensions. All buffers will have a - * fixed-size, independent from the native-window size. They will be - * scaled according to the scaling mode (see - * native_window_set_scaling_mode) upon window composition. - * - * If w and h are 0, the normal behavior is restored. That is, the - * default buffer size will match the windows's size. - * - * Calling this function will reset the window crop to a NULL value, which - * disables cropping of the buffers. - */ -static inline int native_window_set_buffers_user_dimensions( - struct ANativeWindow* window, - int w, int h) -{ - return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS, - w, h); -} - -/* - * native_window_set_buffers_format(..., int format) - * All buffers dequeued after this call will have the format specified. - * - * If the specified format is 0, the default buffer format will be used. - */ -static inline int native_window_set_buffers_format( - struct ANativeWindow* window, - int format) -{ - return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_FORMAT, format); -} - -/* - * native_window_set_buffers_data_space(..., int dataSpace) - * All buffers queued after this call will be associated with the dataSpace - * parameter specified. - * - * dataSpace specifies additional information about the buffer that's dependent - * on the buffer format and the endpoints. For example, it can be used to convey - * the color space of the image data in the buffer, or it can be used to - * indicate that the buffers contain depth measurement data instead of color - * images. The default dataSpace is 0, HAL_DATASPACE_UNKNOWN, unless it has been - * overridden by the consumer. - */ -static inline int native_window_set_buffers_data_space( - struct ANativeWindow* window, - android_dataspace_t dataSpace) -{ - return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_DATASPACE, - dataSpace); -} - -/* - * native_window_set_buffers_transform(..., int transform) - * All buffers queued after this call will be displayed transformed according - * to the transform parameter specified. - */ -static inline int native_window_set_buffers_transform( - struct ANativeWindow* window, - int transform) -{ - return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TRANSFORM, - transform); -} - -/* - * native_window_set_buffers_sticky_transform(..., int transform) - * All buffers queued after this call will be displayed transformed according - * to the transform parameter specified applied on top of the regular buffer - * transform. Setting this transform will disable the transform hint. - * - * Temporary - This is only intended to be used by the LEGACY camera mode, do - * not use this for anything else. - */ -static inline int native_window_set_buffers_sticky_transform( - struct ANativeWindow* window, - int transform) -{ - return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM, - transform); -} - -/* - * native_window_set_buffers_timestamp(..., int64_t timestamp) - * All buffers queued after this call will be associated with the timestamp - * parameter specified. If the timestamp is set to NATIVE_WINDOW_TIMESTAMP_AUTO - * (the default), timestamps will be generated automatically when queueBuffer is - * called. The timestamp is measured in nanoseconds, and is normally monotonically - * increasing. The timestamp should be unaffected by time-of-day adjustments, - * and for a camera should be strictly monotonic but for a media player may be - * reset when the position is set. - */ -static inline int native_window_set_buffers_timestamp( - struct ANativeWindow* window, - int64_t timestamp) -{ - return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP, - timestamp); -} - -/* - * native_window_set_scaling_mode(..., int mode) - * All buffers queued after this call will be associated with the scaling mode - * specified. - */ -static inline int native_window_set_scaling_mode( - struct ANativeWindow* window, - int mode) -{ - return window->perform(window, NATIVE_WINDOW_SET_SCALING_MODE, - mode); -} - -/* - * native_window_api_connect(..., int api) - * connects an API to this window. only one API can be connected at a time. - * Returns -EINVAL if for some reason the window cannot be connected, which - * can happen if it's connected to some other API. - */ -static inline int native_window_api_connect( - struct ANativeWindow* window, int api) -{ - return window->perform(window, NATIVE_WINDOW_API_CONNECT, api); -} - -/* - * native_window_api_disconnect(..., int api) - * disconnect the API from this window. - * An error is returned if for instance the window wasn't connected in the - * first place. - */ -static inline int native_window_api_disconnect( - struct ANativeWindow* window, int api) -{ - return window->perform(window, NATIVE_WINDOW_API_DISCONNECT, api); -} - -/* - * native_window_dequeue_buffer_and_wait(...) - * Dequeue a buffer and wait on the fence associated with that buffer. The - * buffer may safely be accessed immediately upon this function returning. An - * error is returned if either of the dequeue or the wait operations fail. - */ -static inline int native_window_dequeue_buffer_and_wait(ANativeWindow *anw, - struct ANativeWindowBuffer** anb) { - return anw->dequeueBuffer_DEPRECATED(anw, anb); -} - -/* - * native_window_set_sideband_stream(..., native_handle_t*) - * Attach a sideband buffer stream to a native window. - */ -static inline int native_window_set_sideband_stream( - struct ANativeWindow* window, - native_handle_t* sidebandHandle) -{ - return window->perform(window, NATIVE_WINDOW_SET_SIDEBAND_STREAM, - sidebandHandle); -} - -/* - * native_window_set_surface_damage(..., android_native_rect_t* rects, int numRects) - * Set the surface damage (i.e., the region of the surface that has changed - * since the previous frame). The damage set by this call will be reset (to the - * default of full-surface damage) after calling queue, so this must be called - * prior to every frame with damage that does not cover the whole surface if the - * caller desires downstream consumers to use this optimization. - * - * The damage region is specified as an array of rectangles, with the important - * caveat that the origin of the surface is considered to be the bottom-left - * corner, as in OpenGL ES. - * - * If numRects is set to 0, rects may be NULL, and the surface damage will be - * set to the full surface (the same as if this function had not been called for - * this frame). - */ -static inline int native_window_set_surface_damage( - struct ANativeWindow* window, - const android_native_rect_t* rects, size_t numRects) -{ - return window->perform(window, NATIVE_WINDOW_SET_SURFACE_DAMAGE, - rects, numRects); -} - -/* - * native_window_set_shared_buffer_mode(..., bool sharedBufferMode) - * Enable/disable shared buffer mode - */ -static inline int native_window_set_shared_buffer_mode( - struct ANativeWindow* window, - bool sharedBufferMode) -{ - return window->perform(window, NATIVE_WINDOW_SET_SHARED_BUFFER_MODE, - sharedBufferMode); -} - -/* - * native_window_set_auto_refresh(..., autoRefresh) - * Enable/disable auto refresh when in shared buffer mode - */ -static inline int native_window_set_auto_refresh( - struct ANativeWindow* window, - bool autoRefresh) -{ - return window->perform(window, NATIVE_WINDOW_SET_AUTO_REFRESH, autoRefresh); -} - -static inline int native_window_get_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) -{ - return window->perform(window, NATIVE_WINDOW_GET_FRAME_TIMESTAMPS, - framesAgo, outPostedTime, outAcquireTime, outRefreshStartTime, - outGlCompositionDoneTime, outDisplayRetireTime, outReleaseTime); -} - - -__END_DECLS +#include <system/window-deprecated.h> #endif /* SYSTEM_CORE_INCLUDE_ANDROID_WINDOW_H */ 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 050fc2f93..44b878d2c 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/Android.bp b/libutils/Android.bp index 109ac3326..7d293efa7 100644 --- a/libutils/Android.bp +++ b/libutils/Android.bp @@ -18,12 +18,10 @@ cc_library_headers { host_supported: true, header_libs: [ - "liblog_headers", "libsystem_headers", "libcutils_headers" ], export_header_lib_headers: [ - "liblog_headers", "libsystem_headers", "libcutils_headers" ], @@ -52,7 +50,6 @@ cc_library { "CallStack.cpp", "FileMap.cpp", "JenkinsHash.cpp", - "LinearTransform.cpp", "NativeHandle.cpp", "Printer.cpp", "PropertyMap.cpp", @@ -74,11 +71,11 @@ cc_library { cflags: ["-Werror"], include_dirs: ["external/safe-iop/include"], - header_libs: ["libutils_headers"], - export_header_lib_headers: ["libutils_headers"], - - shared_libs: [ - "liblog", + header_libs: [ + "libutils_headers", + ], + export_header_lib_headers: [ + "libutils_headers", ], arch: { @@ -90,7 +87,6 @@ cc_library { target: { android: { srcs: [ - "BlobCache.cpp", "Looper.cpp", "ProcessCallStack.cpp", "Trace.cpp", @@ -102,6 +98,8 @@ cc_library { "libbacktrace", "libcutils", "libdl", + "liblog", + "libvndksupport", ], sanitize: { diff --git a/libutils/BlobCache.cpp b/libutils/BlobCache.cpp deleted file mode 100644 index 126995b8c..000000000 --- a/libutils/BlobCache.cpp +++ /dev/null @@ -1,379 +0,0 @@ -/* - ** Copyright 2011, The Android Open Source Project - ** - ** Licensed under the Apache License, Version 2.0 (the "License"); - ** you may not use this file except in compliance with the License. - ** You may obtain a copy of the License at - ** - ** http://www.apache.org/licenses/LICENSE-2.0 - ** - ** Unless required by applicable law or agreed to in writing, software - ** distributed under the License is distributed on an "AS IS" BASIS, - ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ** See the License for the specific language governing permissions and - ** limitations under the License. - */ - -#define LOG_TAG "BlobCache" -//#define LOG_NDEBUG 0 - -#include <inttypes.h> -#include <stdlib.h> -#include <string.h> - -#include <utils/BlobCache.h> -#include <utils/Errors.h> -#include <utils/Log.h> - -#include <cutils/properties.h> - -namespace android { - -// BlobCache::Header::mMagicNumber value -static const uint32_t blobCacheMagic = ('_' << 24) + ('B' << 16) + ('b' << 8) + '$'; - -// BlobCache::Header::mBlobCacheVersion value -static const uint32_t blobCacheVersion = 3; - -// BlobCache::Header::mDeviceVersion value -static const uint32_t blobCacheDeviceVersion = 1; - -BlobCache::BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize): - mMaxKeySize(maxKeySize), - mMaxValueSize(maxValueSize), - mMaxTotalSize(maxTotalSize), - mTotalSize(0) { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); -#ifdef _WIN32 - srand(now); -#else - mRandState[0] = (now >> 0) & 0xFFFF; - mRandState[1] = (now >> 16) & 0xFFFF; - mRandState[2] = (now >> 32) & 0xFFFF; -#endif - ALOGV("initializing random seed using %lld", (unsigned long long)now); -} - -void BlobCache::set(const void* key, size_t keySize, const void* value, - size_t valueSize) { - if (mMaxKeySize < keySize) { - ALOGV("set: not caching because the key is too large: %zu (limit: %zu)", - keySize, mMaxKeySize); - return; - } - if (mMaxValueSize < valueSize) { - ALOGV("set: not caching because the value is too large: %zu (limit: %zu)", - valueSize, mMaxValueSize); - return; - } - if (mMaxTotalSize < keySize + valueSize) { - ALOGV("set: not caching because the combined key/value size is too " - "large: %zu (limit: %zu)", keySize + valueSize, mMaxTotalSize); - return; - } - if (keySize == 0) { - ALOGW("set: not caching because keySize is 0"); - return; - } - if (valueSize <= 0) { - ALOGW("set: not caching because valueSize is 0"); - return; - } - - sp<Blob> dummyKey(new Blob(key, keySize, false)); - CacheEntry dummyEntry(dummyKey, NULL); - - while (true) { - ssize_t index = mCacheEntries.indexOf(dummyEntry); - if (index < 0) { - // Create a new cache entry. - sp<Blob> keyBlob(new Blob(key, keySize, true)); - sp<Blob> valueBlob(new Blob(value, valueSize, true)); - size_t newTotalSize = mTotalSize + keySize + valueSize; - if (mMaxTotalSize < newTotalSize) { - if (isCleanable()) { - // Clean the cache and try again. - clean(); - continue; - } else { - ALOGV("set: not caching new key/value pair because the " - "total cache size limit would be exceeded: %zu " - "(limit: %zu)", - keySize + valueSize, mMaxTotalSize); - break; - } - } - mCacheEntries.add(CacheEntry(keyBlob, valueBlob)); - mTotalSize = newTotalSize; - ALOGV("set: created new cache entry with %zu byte key and %zu byte value", - keySize, valueSize); - } else { - // Update the existing cache entry. - sp<Blob> valueBlob(new Blob(value, valueSize, true)); - sp<Blob> oldValueBlob(mCacheEntries[index].getValue()); - size_t newTotalSize = mTotalSize + valueSize - oldValueBlob->getSize(); - if (mMaxTotalSize < newTotalSize) { - if (isCleanable()) { - // Clean the cache and try again. - clean(); - continue; - } else { - ALOGV("set: not caching new value because the total cache " - "size limit would be exceeded: %zu (limit: %zu)", - keySize + valueSize, mMaxTotalSize); - break; - } - } - mCacheEntries.editItemAt(index).setValue(valueBlob); - mTotalSize = newTotalSize; - ALOGV("set: updated existing cache entry with %zu byte key and %zu byte " - "value", keySize, valueSize); - } - break; - } -} - -size_t BlobCache::get(const void* key, size_t keySize, void* value, - size_t valueSize) { - if (mMaxKeySize < keySize) { - ALOGV("get: not searching because the key is too large: %zu (limit %zu)", - keySize, mMaxKeySize); - return 0; - } - sp<Blob> dummyKey(new Blob(key, keySize, false)); - CacheEntry dummyEntry(dummyKey, NULL); - ssize_t index = mCacheEntries.indexOf(dummyEntry); - if (index < 0) { - ALOGV("get: no cache entry found for key of size %zu", keySize); - return 0; - } - - // The key was found. Return the value if the caller's buffer is large - // enough. - sp<Blob> valueBlob(mCacheEntries[index].getValue()); - size_t valueBlobSize = valueBlob->getSize(); - if (valueBlobSize <= valueSize) { - ALOGV("get: copying %zu bytes to caller's buffer", valueBlobSize); - memcpy(value, valueBlob->getData(), valueBlobSize); - } else { - ALOGV("get: caller's buffer is too small for value: %zu (needs %zu)", - valueSize, valueBlobSize); - } - return valueBlobSize; -} - -static inline size_t align4(size_t size) { - return (size + 3) & ~3; -} - -size_t BlobCache::getFlattenedSize() const { - size_t size = align4(sizeof(Header) + PROPERTY_VALUE_MAX); - for (size_t i = 0; i < mCacheEntries.size(); i++) { - const CacheEntry& e(mCacheEntries[i]); - sp<Blob> keyBlob = e.getKey(); - sp<Blob> valueBlob = e.getValue(); - size += align4(sizeof(EntryHeader) + keyBlob->getSize() + - valueBlob->getSize()); - } - return size; -} - -status_t BlobCache::flatten(void* buffer, size_t size) const { - // Write the cache header - if (size < sizeof(Header)) { - ALOGE("flatten: not enough room for cache header"); - return BAD_VALUE; - } - Header* header = reinterpret_cast<Header*>(buffer); - header->mMagicNumber = blobCacheMagic; - header->mBlobCacheVersion = blobCacheVersion; - header->mDeviceVersion = blobCacheDeviceVersion; - header->mNumEntries = mCacheEntries.size(); - char buildId[PROPERTY_VALUE_MAX]; - header->mBuildIdLength = property_get("ro.build.id", buildId, ""); - memcpy(header->mBuildId, buildId, header->mBuildIdLength); - - // Write cache entries - uint8_t* byteBuffer = reinterpret_cast<uint8_t*>(buffer); - off_t byteOffset = align4(sizeof(Header) + header->mBuildIdLength); - for (size_t i = 0; i < mCacheEntries.size(); i++) { - const CacheEntry& e(mCacheEntries[i]); - sp<Blob> keyBlob = e.getKey(); - sp<Blob> valueBlob = e.getValue(); - size_t keySize = keyBlob->getSize(); - size_t valueSize = valueBlob->getSize(); - - size_t entrySize = sizeof(EntryHeader) + keySize + valueSize; - size_t totalSize = align4(entrySize); - if (byteOffset + totalSize > size) { - ALOGE("flatten: not enough room for cache entries"); - return BAD_VALUE; - } - - EntryHeader* eheader = reinterpret_cast<EntryHeader*>( - &byteBuffer[byteOffset]); - eheader->mKeySize = keySize; - eheader->mValueSize = valueSize; - - memcpy(eheader->mData, keyBlob->getData(), keySize); - memcpy(eheader->mData + keySize, valueBlob->getData(), valueSize); - - if (totalSize > entrySize) { - // We have padding bytes. Those will get written to storage, and contribute to the CRC, - // so make sure we zero-them to have reproducible results. - memset(eheader->mData + keySize + valueSize, 0, totalSize - entrySize); - } - - byteOffset += totalSize; - } - - return OK; -} - -status_t BlobCache::unflatten(void const* buffer, size_t size) { - // All errors should result in the BlobCache being in an empty state. - mCacheEntries.clear(); - - // Read the cache header - if (size < sizeof(Header)) { - ALOGE("unflatten: not enough room for cache header"); - return BAD_VALUE; - } - const Header* header = reinterpret_cast<const Header*>(buffer); - if (header->mMagicNumber != blobCacheMagic) { - ALOGE("unflatten: bad magic number: %" PRIu32, header->mMagicNumber); - return BAD_VALUE; - } - char buildId[PROPERTY_VALUE_MAX]; - int len = property_get("ro.build.id", buildId, ""); - if (header->mBlobCacheVersion != blobCacheVersion || - header->mDeviceVersion != blobCacheDeviceVersion || - len != header->mBuildIdLength || - strncmp(buildId, header->mBuildId, len)) { - // We treat version mismatches as an empty cache. - return OK; - } - - // Read cache entries - const uint8_t* byteBuffer = reinterpret_cast<const uint8_t*>(buffer); - off_t byteOffset = align4(sizeof(Header) + header->mBuildIdLength); - size_t numEntries = header->mNumEntries; - for (size_t i = 0; i < numEntries; i++) { - if (byteOffset + sizeof(EntryHeader) > size) { - mCacheEntries.clear(); - ALOGE("unflatten: not enough room for cache entry headers"); - return BAD_VALUE; - } - - const EntryHeader* eheader = reinterpret_cast<const EntryHeader*>( - &byteBuffer[byteOffset]); - size_t keySize = eheader->mKeySize; - size_t valueSize = eheader->mValueSize; - size_t entrySize = sizeof(EntryHeader) + keySize + valueSize; - - size_t totalSize = align4(entrySize); - if (byteOffset + totalSize > size) { - mCacheEntries.clear(); - ALOGE("unflatten: not enough room for cache entry headers"); - return BAD_VALUE; - } - - const uint8_t* data = eheader->mData; - set(data, keySize, data + keySize, valueSize); - - byteOffset += totalSize; - } - - return OK; -} - -long int BlobCache::blob_random() { -#ifdef _WIN32 - return rand(); -#else - return nrand48(mRandState); -#endif -} - -void BlobCache::clean() { - // Remove a random cache entry until the total cache size gets below half - // the maximum total cache size. - while (mTotalSize > mMaxTotalSize / 2) { - size_t i = size_t(blob_random() % (mCacheEntries.size())); - const CacheEntry& entry(mCacheEntries[i]); - mTotalSize -= entry.getKey()->getSize() + entry.getValue()->getSize(); - mCacheEntries.removeAt(i); - } -} - -bool BlobCache::isCleanable() const { - return mTotalSize > mMaxTotalSize / 2; -} - -BlobCache::Blob::Blob(const void* data, size_t size, bool copyData): - mData(copyData ? malloc(size) : data), - mSize(size), - mOwnsData(copyData) { - if (data != NULL && copyData) { - memcpy(const_cast<void*>(mData), data, size); - } -} - -BlobCache::Blob::~Blob() { - if (mOwnsData) { - free(const_cast<void*>(mData)); - } -} - -bool BlobCache::Blob::operator<(const Blob& rhs) const { - if (mSize == rhs.mSize) { - return memcmp(mData, rhs.mData, mSize) < 0; - } else { - return mSize < rhs.mSize; - } -} - -const void* BlobCache::Blob::getData() const { - return mData; -} - -size_t BlobCache::Blob::getSize() const { - return mSize; -} - -BlobCache::CacheEntry::CacheEntry() { -} - -BlobCache::CacheEntry::CacheEntry(const sp<Blob>& key, const sp<Blob>& value): - mKey(key), - mValue(value) { -} - -BlobCache::CacheEntry::CacheEntry(const CacheEntry& ce): - mKey(ce.mKey), - mValue(ce.mValue) { -} - -bool BlobCache::CacheEntry::operator<(const CacheEntry& rhs) const { - return *mKey < *rhs.mKey; -} - -const BlobCache::CacheEntry& BlobCache::CacheEntry::operator=(const CacheEntry& rhs) { - mKey = rhs.mKey; - mValue = rhs.mValue; - return *this; -} - -sp<BlobCache::Blob> BlobCache::CacheEntry::getKey() const { - return mKey; -} - -sp<BlobCache::Blob> BlobCache::CacheEntry::getValue() const { - return mValue; -} - -void BlobCache::CacheEntry::setValue(const sp<Blob>& value) { - mValue = value; -} - -} // namespace android diff --git a/libutils/CallStack.cpp b/libutils/CallStack.cpp index 699da7469..bd6015e79 100644 --- a/libutils/CallStack.cpp +++ b/libutils/CallStack.cpp @@ -16,9 +16,10 @@ #define LOG_TAG "CallStack" +#include <utils/CallStack.h> + #include <memory> -#include <utils/CallStack.h> #include <utils/Printer.h> #include <utils/Errors.h> #include <utils/Log.h> diff --git a/libutils/LinearTransform.cpp b/libutils/LinearTransform.cpp deleted file mode 100644 index 138ce8be7..000000000 --- a/libutils/LinearTransform.cpp +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define __STDC_LIMIT_MACROS - -#include <assert.h> -#include <stdint.h> - -#include <utils/LinearTransform.h> - -// disable sanitize as these functions may intentionally overflow (see comments below). -// the ifdef can be removed when host builds use clang. -#if defined(__clang__) -#define ATTRIBUTE_NO_SANITIZE_INTEGER __attribute__((no_sanitize("integer"))) -#else -#define ATTRIBUTE_NO_SANITIZE_INTEGER -#endif - -namespace android { - -// sanitize failure with T = int32_t and x = 0x80000000 -template<class T> -ATTRIBUTE_NO_SANITIZE_INTEGER -static inline T ABS(T x) { return (x < 0) ? -x : x; } - -// Static math methods involving linear transformations -// remote sanitize failure on overflow case. -ATTRIBUTE_NO_SANITIZE_INTEGER -static bool scale_u64_to_u64( - uint64_t val, - uint32_t N, - uint32_t D, - uint64_t* res, - bool round_up_not_down) { - uint64_t tmp1, tmp2; - uint32_t r; - - assert(res); - assert(D); - - // Let U32(X) denote a uint32_t containing the upper 32 bits of a 64 bit - // integer X. - // Let L32(X) denote a uint32_t containing the lower 32 bits of a 64 bit - // integer X. - // Let X[A, B] with A <= B denote bits A through B of the integer X. - // Let (A | B) denote the concatination of two 32 bit ints, A and B. - // IOW X = (A | B) => U32(X) == A && L32(X) == B - // - // compute M = val * N (a 96 bit int) - // --------------------------------- - // tmp2 = U32(val) * N (a 64 bit int) - // tmp1 = L32(val) * N (a 64 bit int) - // which means - // M = val * N = (tmp2 << 32) + tmp1 - tmp2 = (val >> 32) * N; - tmp1 = (val & UINT32_MAX) * N; - - // compute M[32, 95] - // tmp2 = tmp2 + U32(tmp1) - // = (U32(val) * N) + U32(L32(val) * N) - // = M[32, 95] - tmp2 += tmp1 >> 32; - - // if M[64, 95] >= D, then M/D has bits > 63 set and we have - // an overflow. - if ((tmp2 >> 32) >= D) { - *res = UINT64_MAX; - return false; - } - - // Divide. Going in we know - // tmp2 = M[32, 95] - // U32(tmp2) < D - r = tmp2 % D; - tmp2 /= D; - - // At this point - // tmp1 = L32(val) * N - // tmp2 = M[32, 95] / D - // = (M / D)[32, 95] - // r = M[32, 95] % D - // U32(tmp2) = 0 - // - // compute tmp1 = (r | M[0, 31]) - tmp1 = (tmp1 & UINT32_MAX) | ((uint64_t)r << 32); - - // Divide again. Keep the remainder around in order to round properly. - r = tmp1 % D; - tmp1 /= D; - - // At this point - // tmp2 = (M / D)[32, 95] - // tmp1 = (M / D)[ 0, 31] - // r = M % D - // U32(tmp1) = 0 - // U32(tmp2) = 0 - - // Pack the result and deal with the round-up case (As well as the - // remote possiblility over overflow in such a case). - *res = (tmp2 << 32) | tmp1; - if (r && round_up_not_down) { - ++(*res); - if (!(*res)) { - *res = UINT64_MAX; - return false; - } - } - - return true; -} - -// at least one known sanitize failure (see comment below) -ATTRIBUTE_NO_SANITIZE_INTEGER -static bool linear_transform_s64_to_s64( - int64_t val, - int64_t basis1, - int32_t N, - uint32_t D, - bool invert_frac, - int64_t basis2, - int64_t* out) { - uint64_t scaled, res; - uint64_t abs_val; - bool is_neg; - - if (!out) - return false; - - // Compute abs(val - basis_64). Keep track of whether or not this delta - // will be negative after the scale opertaion. - if (val < basis1) { - is_neg = true; - abs_val = basis1 - val; - } else { - is_neg = false; - abs_val = val - basis1; - } - - if (N < 0) - is_neg = !is_neg; - - if (!scale_u64_to_u64(abs_val, - invert_frac ? D : ABS(N), - invert_frac ? ABS(N) : D, - &scaled, - is_neg)) - return false; // overflow/undeflow - - // if scaled is >= 0x8000<etc>, then we are going to overflow or - // underflow unless ABS(basis2) is large enough to pull us back into the - // non-overflow/underflow region. - if (scaled & INT64_MIN) { - if (is_neg && (basis2 < 0)) - return false; // certain underflow - - if (!is_neg && (basis2 >= 0)) - return false; // certain overflow - - if (ABS(basis2) <= static_cast<int64_t>(scaled & INT64_MAX)) - return false; // not enough - - // Looks like we are OK - *out = (is_neg ? (-scaled) : scaled) + basis2; - } else { - // Scaled fits within signed bounds, so we just need to check for - // over/underflow for two signed integers. Basically, if both scaled - // and basis2 have the same sign bit, and the result has a different - // sign bit, then we have under/overflow. An easy way to compute this - // is - // (scaled_signbit XNOR basis_signbit) && - // (scaled_signbit XOR res_signbit) - // == - // (scaled_signbit XOR basis_signbit XOR 1) && - // (scaled_signbit XOR res_signbit) - - if (is_neg) - scaled = -scaled; // known sanitize failure - res = scaled + basis2; - - if ((scaled ^ basis2 ^ INT64_MIN) & (scaled ^ res) & INT64_MIN) - return false; - - *out = res; - } - - return true; -} - -bool LinearTransform::doForwardTransform(int64_t a_in, int64_t* b_out) const { - if (0 == a_to_b_denom) - return false; - - return linear_transform_s64_to_s64(a_in, - a_zero, - a_to_b_numer, - a_to_b_denom, - false, - b_zero, - b_out); -} - -bool LinearTransform::doReverseTransform(int64_t b_in, int64_t* a_out) const { - if (0 == a_to_b_numer) - return false; - - return linear_transform_s64_to_s64(b_in, - b_zero, - a_to_b_numer, - a_to_b_denom, - true, - a_zero, - a_out); -} - -template <class T> void LinearTransform::reduce(T* N, T* D) { - T a, b; - if (!N || !D || !(*D)) { - assert(false); - return; - } - - a = *N; - b = *D; - - if (a == 0) { - *D = 1; - return; - } - - // This implements Euclid's method to find GCD. - if (a < b) { - T tmp = a; - a = b; - b = tmp; - } - - while (1) { - // a is now the greater of the two. - const T remainder = a % b; - if (remainder == 0) { - *N /= b; - *D /= b; - return; - } - // by swapping remainder and b, we are guaranteeing that a is - // still the greater of the two upon entrance to the loop. - a = b; - b = remainder; - } -}; - -template void LinearTransform::reduce<uint64_t>(uint64_t* N, uint64_t* D); -template void LinearTransform::reduce<uint32_t>(uint32_t* N, uint32_t* D); - -// sanitize failure if *N = 0x80000000 -ATTRIBUTE_NO_SANITIZE_INTEGER -void LinearTransform::reduce(int32_t* N, uint32_t* D) { - if (N && D && *D) { - if (*N < 0) { - *N = -(*N); - reduce(reinterpret_cast<uint32_t*>(N), D); - *N = -(*N); - } else { - reduce(reinterpret_cast<uint32_t*>(N), D); - } - } -} - -} // namespace android diff --git a/libutils/Looper.cpp b/libutils/Looper.cpp index 77e69e4b3..6c57b2e54 100644 --- a/libutils/Looper.cpp +++ b/libutils/Looper.cpp @@ -13,17 +13,8 @@ // Debugs callback registration and invocation. #define DEBUG_CALLBACKS 0 -#include <errno.h> -#include <fcntl.h> -#include <inttypes.h> -#include <limits.h> -#include <string.h> -#include <sys/eventfd.h> -#include <unistd.h> - -#include <log/log.h> #include <utils/Looper.h> -#include <utils/Timers.h> +#include <sys/eventfd.h> namespace android { @@ -83,6 +74,7 @@ Looper::Looper(bool allowNonCallbacks) : Looper::~Looper() { close(mWakeEventFd); + mWakeEventFd = -1; if (mEpollFd >= 0) { close(mEpollFd); } @@ -412,7 +404,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/NativeHandle.cpp b/libutils/NativeHandle.cpp index e4daca7ff..97d06b8bd 100644 --- a/libutils/NativeHandle.cpp +++ b/libutils/NativeHandle.cpp @@ -19,14 +19,14 @@ namespace android { -sp<NativeHandle> NativeHandle::create( - native_handle_t* handle, bool ownsHandle) { +sp<NativeHandle> NativeHandle::create(native_handle_t* handle, bool ownsHandle) { return handle ? new NativeHandle(handle, ownsHandle) : NULL; } NativeHandle::NativeHandle(native_handle_t* handle, bool ownsHandle) -: mHandle(handle), mOwnsHandle(ownsHandle) -{} + : mHandle(handle), mOwnsHandle(ownsHandle) { + +} NativeHandle::~NativeHandle() { if (mOwnsHandle) { diff --git a/libutils/Printer.cpp b/libutils/Printer.cpp index 84af2930b..cbf042eb5 100644 --- a/libutils/Printer.cpp +++ b/libutils/Printer.cpp @@ -21,8 +21,6 @@ #include <utils/String8.h> #include <utils/Log.h> -#include <string.h> -#include <stdio.h> #include <stdlib.h> namespace android { diff --git a/libutils/ProcessCallStack.cpp b/libutils/ProcessCallStack.cpp index 983847c4c..b8fb6dc2a 100644 --- a/libutils/ProcessCallStack.cpp +++ b/libutils/ProcessCallStack.cpp @@ -17,20 +17,15 @@ #define LOG_TAG "ProcessCallStack" // #define LOG_NDEBUG 0 +#include <utils/ProcessCallStack.h> + #include <dirent.h> -#include <errno.h> -#include <stdio.h> -#include <string.h> #include <unistd.h> + #include <memory> -#include <utils/Log.h> -#include <utils/Errors.h> -#include <utils/ProcessCallStack.h> #include <utils/Printer.h> -#include <limits.h> - namespace android { enum { diff --git a/libutils/PropertyMap.cpp b/libutils/PropertyMap.cpp index 55207027b..4bcdd0f7f 100644 --- a/libutils/PropertyMap.cpp +++ b/libutils/PropertyMap.cpp @@ -16,11 +16,7 @@ #define LOG_TAG "PropertyMap" -#include <stdlib.h> -#include <string.h> - #include <utils/PropertyMap.h> -#include <utils/Log.h> // Enables debug output for the parser. #define DEBUG_PARSER 0 diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp index 4252ba6b2..24737b985 100644 --- a/libutils/RefBase.cpp +++ b/libutils/RefBase.cpp @@ -17,18 +17,9 @@ #define LOG_TAG "RefBase" // #define LOG_NDEBUG 0 -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - #include <utils/RefBase.h> #include <utils/CallStack.h> -#include <utils/Log.h> -#include <utils/threads.h> #ifndef __unused #define __unused __attribute__((__unused__)) @@ -769,6 +760,4 @@ void RefBase::renameRefId(RefBase* ref, ref->mRefs->renameWeakRefId(old_id, new_id); } -VirtualLightRefBase::~VirtualLightRefBase() {} - }; // namespace android diff --git a/libutils/SharedBuffer.cpp b/libutils/SharedBuffer.cpp index 957aedb8f..bad98b274 100644 --- a/libutils/SharedBuffer.cpp +++ b/libutils/SharedBuffer.cpp @@ -16,13 +16,13 @@ #define LOG_TAG "sharedbuffer" +#include "SharedBuffer.h" + #include <stdlib.h> #include <string.h> #include <log/log.h> -#include "SharedBuffer.h" - // --------------------------------------------------------------------------- namespace android { @@ -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/StopWatch.cpp b/libutils/StopWatch.cpp index 8c7b59645..219c13c67 100644 --- a/libutils/StopWatch.cpp +++ b/libutils/StopWatch.cpp @@ -16,9 +16,7 @@ #define LOG_TAG "StopWatch" -#include <string.h> -#include <stdlib.h> -#include <stdio.h> +#include <utils/StopWatch.h> /* for PRId64 */ #ifndef __STDC_FORMAT_MACROS @@ -27,8 +25,6 @@ #include <inttypes.h> #include <utils/Log.h> -#include <utils/Errors.h> -#include <utils/StopWatch.h> /*****************************************************************************/ diff --git a/libutils/String16.cpp b/libutils/String16.cpp index 9f5cfeab4..ad335c399 100644 --- a/libutils/String16.cpp +++ b/libutils/String16.cpp @@ -17,11 +17,7 @@ #include <utils/String16.h> #include <utils/Log.h> -#include <utils/Unicode.h> -#include <utils/threads.h> -#include <memory.h> -#include <stdio.h> #include <ctype.h> #include "SharedBuffer.h" diff --git a/libutils/String8.cpp b/libutils/String8.cpp index cacaf91b8..ad0e72ec1 100644 --- a/libutils/String8.cpp +++ b/libutils/String8.cpp @@ -21,9 +21,7 @@ #include <utils/Compat.h> #include <utils/Log.h> -#include <utils/Unicode.h> #include <utils/String16.h> -#include <utils/threads.h> #include <ctype.h> diff --git a/libutils/SystemClock.cpp b/libutils/SystemClock.cpp index 965e32c0f..28fc35145 100644 --- a/libutils/SystemClock.cpp +++ b/libutils/SystemClock.cpp @@ -19,17 +19,17 @@ * System clock functions. */ +#define LOG_TAG "SystemClock" + +#include <utils/SystemClock.h> + #include <sys/time.h> -#include <limits.h> -#include <fcntl.h> #include <string.h> #include <errno.h> #include <cutils/compiler.h> -#include <utils/SystemClock.h> -#include <utils/Timers.h> -#define LOG_TAG "SystemClock" +#include <utils/Timers.h> #include <utils/Log.h> namespace android { diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp index def739f9f..6317c32d4 100644 --- a/libutils/Threads.cpp +++ b/libutils/Threads.cpp @@ -18,16 +18,10 @@ #define LOG_TAG "libutils.threads" #include <assert.h> -#include <errno.h> -#include <memory.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> +#include <utils/Thread.h> +#include <utils/AndroidThreads.h> #if !defined(_WIN32) -# include <pthread.h> -# include <sched.h> # include <sys/resource.h> #else # include <windows.h> @@ -40,7 +34,6 @@ #include <sys/prctl.h> #endif -#include <utils/threads.h> #include <utils/Log.h> #include <cutils/sched_policy.h> diff --git a/libutils/Timers.cpp b/libutils/Timers.cpp index 201bc412c..b2df9a58f 100644 --- a/libutils/Timers.cpp +++ b/libutils/Timers.cpp @@ -20,7 +20,6 @@ #include <utils/Timers.h> #include <limits.h> -#include <sys/time.h> #include <time.h> #if defined(__ANDROID__) @@ -53,7 +52,7 @@ nsecs_t systemTime(int /*clock*/) int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime) { - int timeoutDelayMillis; + nsecs_t timeoutDelayMillis; if (timeoutTime > referenceTime) { uint64_t timeoutDelay = uint64_t(timeoutTime - referenceTime); if (timeoutDelay > uint64_t((INT_MAX - 1) * 1000000LL)) { @@ -64,5 +63,5 @@ int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime) } else { timeoutDelayMillis = 0; } - return timeoutDelayMillis; + return (int)timeoutDelayMillis; } diff --git a/libutils/Tokenizer.cpp b/libutils/Tokenizer.cpp index 2d0e83dcd..b68a2cfa3 100644 --- a/libutils/Tokenizer.cpp +++ b/libutils/Tokenizer.cpp @@ -16,14 +16,10 @@ #define LOG_TAG "Tokenizer" -#include <stdlib.h> -#include <unistd.h> +#include <utils/Tokenizer.h> #include <fcntl.h> -#include <errno.h> -#include <sys/types.h> #include <sys/stat.h> #include <utils/Log.h> -#include <utils/Tokenizer.h> // Enables debug output for the tokenizer. #define DEBUG_TOKENIZER 0 diff --git a/libutils/Trace.cpp b/libutils/Trace.cpp index 36fd80214..8530fdca0 100644 --- a/libutils/Trace.cpp +++ b/libutils/Trace.cpp @@ -14,12 +14,11 @@ * limitations under the License. */ -#include <utils/misc.h> #include <utils/Trace.h> +#include <utils/misc.h> static void traceInit() __attribute__((constructor)); -static void traceInit() -{ +static void traceInit() { ::android::add_sysprop_change_callback(atrace_update_tags, 0); } diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp index f1a41b96f..5fd915524 100644 --- a/libutils/Unicode.cpp +++ b/libutils/Unicode.cpp @@ -16,11 +16,10 @@ #define LOG_TAG "unicode" +#include <utils/Unicode.h> #include <limits.h> -#include <stddef.h> #include <log/log.h> -#include <utils/Unicode.h> #if defined(_WIN32) # undef nhtol diff --git a/libutils/VectorImpl.cpp b/libutils/VectorImpl.cpp index f7ca8f4f9..ef3277f42 100644 --- a/libutils/VectorImpl.cpp +++ b/libutils/VectorImpl.cpp @@ -16,13 +16,13 @@ #define LOG_TAG "Vector" +#include <utils/VectorImpl.h> + #include <stdio.h> #include <stdlib.h> #include <string.h> #include <log/log.h> -#include <utils/Errors.h> -#include <utils/VectorImpl.h> #include <safe_iop.h> diff --git a/libutils/include/utils/BlobCache.h b/libutils/include/utils/BlobCache.h deleted file mode 100644 index 65dca9fb4..000000000 --- a/libutils/include/utils/BlobCache.h +++ /dev/null @@ -1,249 +0,0 @@ -/* - ** Copyright 2011, The Android Open Source Project - ** - ** Licensed under the Apache License, Version 2.0 (the "License"); - ** you may not use this file except in compliance with the License. - ** You may obtain a copy of the License at - ** - ** http://www.apache.org/licenses/LICENSE-2.0 - ** - ** Unless required by applicable law or agreed to in writing, software - ** distributed under the License is distributed on an "AS IS" BASIS, - ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ** See the License for the specific language governing permissions and - ** limitations under the License. - */ - -#ifndef ANDROID_BLOB_CACHE_H -#define ANDROID_BLOB_CACHE_H - -#include <stddef.h> - -#include <utils/Flattenable.h> -#include <utils/RefBase.h> -#include <utils/SortedVector.h> -#include <utils/threads.h> - -namespace android { - -// A BlobCache is an in-memory cache for binary key/value pairs. A BlobCache -// does NOT provide any thread-safety guarantees. -// -// The cache contents can be serialized to an in-memory buffer or mmap'd file -// and then reloaded in a subsequent execution of the program. This -// serialization is non-portable and the data should only be used by the device -// that generated it. -class BlobCache : public RefBase { - -public: - - // Create an empty blob cache. The blob cache will cache key/value pairs - // with key and value sizes less than or equal to maxKeySize and - // maxValueSize, respectively. The total combined size of ALL cache entries - // (key sizes plus value sizes) will not exceed maxTotalSize. - BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize); - - // set inserts a new binary value into the cache and associates it with the - // given binary key. If the key or value are too large for the cache then - // the cache remains unchanged. This includes the case where a different - // value was previously associated with the given key - the old value will - // remain in the cache. If the given key and value are small enough to be - // put in the cache (based on the maxKeySize, maxValueSize, and maxTotalSize - // values specified to the BlobCache constructor), then the key/value pair - // will be in the cache after set returns. Note, however, that a subsequent - // call to set may evict old key/value pairs from the cache. - // - // Preconditions: - // key != NULL - // 0 < keySize - // value != NULL - // 0 < valueSize - void set(const void* key, size_t keySize, const void* value, - size_t valueSize); - - // get retrieves from the cache the binary value associated with a given - // binary key. If the key is present in the cache then the length of the - // binary value associated with that key is returned. If the value argument - // is non-NULL and the size of the cached value is less than valueSize bytes - // then the cached value is copied into the buffer pointed to by the value - // argument. If the key is not present in the cache then 0 is returned and - // the buffer pointed to by the value argument is not modified. - // - // Note that when calling get multiple times with the same key, the later - // calls may fail, returning 0, even if earlier calls succeeded. The return - // value must be checked for each call. - // - // Preconditions: - // key != NULL - // 0 < keySize - // 0 <= valueSize - size_t get(const void* key, size_t keySize, void* value, size_t valueSize); - - - // getFlattenedSize returns the number of bytes needed to store the entire - // serialized cache. - size_t getFlattenedSize() const; - - // flatten serializes the current contents of the cache into the memory - // pointed to by 'buffer'. The serialized cache contents can later be - // loaded into a BlobCache object using the unflatten method. The contents - // of the BlobCache object will not be modified. - // - // Preconditions: - // size >= this.getFlattenedSize() - status_t flatten(void* buffer, size_t size) const; - - // unflatten replaces the contents of the cache with the serialized cache - // contents in the memory pointed to by 'buffer'. The previous contents of - // the BlobCache will be evicted from the cache. If an error occurs while - // unflattening the serialized cache contents then the BlobCache will be - // left in an empty state. - // - status_t unflatten(void const* buffer, size_t size); - -private: - // Copying is disallowed. - BlobCache(const BlobCache&); - void operator=(const BlobCache&); - - // A random function helper to get around MinGW not having nrand48() - long int blob_random(); - - // clean evicts a randomly chosen set of entries from the cache such that - // the total size of all remaining entries is less than mMaxTotalSize/2. - void clean(); - - // isCleanable returns true if the cache is full enough for the clean method - // to have some effect, and false otherwise. - bool isCleanable() const; - - // A Blob is an immutable sized unstructured data blob. - class Blob : public RefBase { - public: - Blob(const void* data, size_t size, bool copyData); - ~Blob(); - - bool operator<(const Blob& rhs) const; - - const void* getData() const; - size_t getSize() const; - - private: - // Copying is not allowed. - Blob(const Blob&); - void operator=(const Blob&); - - // mData points to the buffer containing the blob data. - const void* mData; - - // mSize is the size of the blob data in bytes. - size_t mSize; - - // mOwnsData indicates whether or not this Blob object should free the - // memory pointed to by mData when the Blob gets destructed. - bool mOwnsData; - }; - - // A CacheEntry is a single key/value pair in the cache. - class CacheEntry { - public: - CacheEntry(); - CacheEntry(const sp<Blob>& key, const sp<Blob>& value); - CacheEntry(const CacheEntry& ce); - - bool operator<(const CacheEntry& rhs) const; - const CacheEntry& operator=(const CacheEntry&); - - sp<Blob> getKey() const; - sp<Blob> getValue() const; - - void setValue(const sp<Blob>& value); - - private: - - // mKey is the key that identifies the cache entry. - sp<Blob> mKey; - - // mValue is the cached data associated with the key. - sp<Blob> mValue; - }; - - // A Header is the header for the entire BlobCache serialization format. No - // need to make this portable, so we simply write the struct out. - struct Header { - // mMagicNumber is the magic number that identifies the data as - // serialized BlobCache contents. It must always contain 'Blb$'. - uint32_t mMagicNumber; - - // mBlobCacheVersion is the serialization format version. - uint32_t mBlobCacheVersion; - - // mDeviceVersion is the device-specific version of the cache. This can - // be used to invalidate the cache. - uint32_t mDeviceVersion; - - // mNumEntries is number of cache entries following the header in the - // data. - size_t mNumEntries; - - // mBuildId is the build id of the device when the cache was created. - // When an update to the build happens (via an OTA or other update) this - // is used to invalidate the cache. - int mBuildIdLength; - char mBuildId[]; - }; - - // An EntryHeader is the header for a serialized cache entry. No need to - // make this portable, so we simply write the struct out. Each EntryHeader - // is followed imediately by the key data and then the value data. - // - // The beginning of each serialized EntryHeader is 4-byte aligned, so the - // number of bytes that a serialized cache entry will occupy is: - // - // ((sizeof(EntryHeader) + keySize + valueSize) + 3) & ~3 - // - struct EntryHeader { - // mKeySize is the size of the entry key in bytes. - size_t mKeySize; - - // mValueSize is the size of the entry value in bytes. - size_t mValueSize; - - // mData contains both the key and value data for the cache entry. The - // key comes first followed immediately by the value. - uint8_t mData[]; - }; - - // mMaxKeySize is the maximum key size that will be cached. Calls to - // BlobCache::set with a keySize parameter larger than mMaxKeySize will - // simply not add the key/value pair to the cache. - const size_t mMaxKeySize; - - // mMaxValueSize is the maximum value size that will be cached. Calls to - // BlobCache::set with a valueSize parameter larger than mMaxValueSize will - // simply not add the key/value pair to the cache. - const size_t mMaxValueSize; - - // mMaxTotalSize is the maximum size that all cache entries can occupy. This - // includes space for both keys and values. When a call to BlobCache::set - // would otherwise cause this limit to be exceeded, either the key/value - // pair passed to BlobCache::set will not be cached or other cache entries - // will be evicted from the cache to make room for the new entry. - const size_t mMaxTotalSize; - - // mTotalSize is the total combined size of all keys and values currently in - // the cache. - size_t mTotalSize; - - // mRandState is the pseudo-random number generator state. It is passed to - // nrand48 to generate random numbers when needed. - unsigned short mRandState[3]; - - // mCacheEntries stores all the cache entries that are resident in memory. - // Cache entries are added to it by the 'set' method. - SortedVector<CacheEntry> mCacheEntries; -}; - -} - -#endif // ANDROID_BLOB_CACHE_H diff --git a/libutils/include/utils/Flattenable.h b/libutils/include/utils/Flattenable.h index 22b811a14..070c71026 100644 --- a/libutils/include/utils/Flattenable.h +++ b/libutils/include/utils/Flattenable.h @@ -189,11 +189,11 @@ public: } inline status_t flatten(void* buffer, size_t size) const { if (size < sizeof(T)) return NO_MEMORY; - *reinterpret_cast<T*>(buffer) = *static_cast<T const*>(this); + memcpy(buffer, static_cast<T const*>(this), sizeof(T)); return NO_ERROR; } inline status_t unflatten(void const* buffer, size_t) { - *static_cast<T*>(this) = *reinterpret_cast<T const*>(buffer); + memcpy(static_cast<T*>(this), buffer, sizeof(T)); return NO_ERROR; } }; diff --git a/libutils/include/utils/LightRefBase.h b/libutils/include/utils/LightRefBase.h new file mode 100644 index 000000000..65257edb9 --- /dev/null +++ b/libutils/include/utils/LightRefBase.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +/* + * See documentation in RefBase.h + */ + +#include <atomic> + +#include <sys/types.h> + +namespace android { + +class ReferenceRenamer; + +template <class T> +class LightRefBase +{ +public: + inline LightRefBase() : mCount(0) { } + inline void incStrong(__attribute__((unused)) const void* id) const { + mCount.fetch_add(1, std::memory_order_relaxed); + } + inline void decStrong(__attribute__((unused)) const void* id) const { + if (mCount.fetch_sub(1, std::memory_order_release) == 1) { + std::atomic_thread_fence(std::memory_order_acquire); + delete static_cast<const T*>(this); + } + } + //! DEBUGGING ONLY: Get current strong ref count. + inline int32_t getStrongCount() const { + return mCount.load(std::memory_order_relaxed); + } + + typedef LightRefBase<T> basetype; + +protected: + inline ~LightRefBase() { } + +private: + friend class ReferenceMover; + inline static void renameRefs(size_t /*n*/, const ReferenceRenamer& /*renamer*/) { } + inline static void renameRefId(T* /*ref*/, const void* /*old_id*/ , const void* /*new_id*/) { } + +private: + mutable std::atomic<int32_t> mCount; +}; + + +// This is a wrapper around LightRefBase that simply enforces a virtual +// destructor to eliminate the template requirement of LightRefBase +class VirtualLightRefBase : public LightRefBase<VirtualLightRefBase> { +public: + virtual ~VirtualLightRefBase() = default; +}; + +}; // namespace android diff --git a/libutils/include/utils/LinearTransform.h b/libutils/include/utils/LinearTransform.h deleted file mode 100644 index 04cb355c7..000000000 --- a/libutils/include/utils/LinearTransform.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _LIBS_UTILS_LINEAR_TRANSFORM_H -#define _LIBS_UTILS_LINEAR_TRANSFORM_H - -#include <stdint.h> - -namespace android { - -// LinearTransform defines a structure which hold the definition of a -// transformation from single dimensional coordinate system A into coordinate -// system B (and back again). Values in A and in B are 64 bit, the linear -// scale factor is expressed as a rational number using two 32 bit values. -// -// Specifically, let -// f(a) = b -// F(b) = f^-1(b) = a -// then -// -// f(a) = (((a - a_zero) * a_to_b_numer) / a_to_b_denom) + b_zero; -// -// and -// -// F(b) = (((b - b_zero) * a_to_b_denom) / a_to_b_numer) + a_zero; -// -struct LinearTransform { - int64_t a_zero; - int64_t b_zero; - int32_t a_to_b_numer; - uint32_t a_to_b_denom; - - // Transform from A->B - // Returns true on success, or false in the case of a singularity or an - // overflow. - bool doForwardTransform(int64_t a_in, int64_t* b_out) const; - - // Transform from B->A - // Returns true on success, or false in the case of a singularity or an - // overflow. - bool doReverseTransform(int64_t b_in, int64_t* a_out) const; - - // Helpers which will reduce the fraction N/D using Euclid's method. - template <class T> static void reduce(T* N, T* D); - static void reduce(int32_t* N, uint32_t* D); -}; - - -} - -#endif // _LIBS_UTILS_LINEAR_TRANSFORM_H diff --git a/libutils/include/utils/NativeHandle.h b/libutils/include/utils/NativeHandle.h index b82516879..73fe804cc 100644 --- a/libutils/include/utils/NativeHandle.h +++ b/libutils/include/utils/NativeHandle.h @@ -24,7 +24,7 @@ typedef struct native_handle native_handle_t; namespace android { -class NativeHandle: public LightRefBase<NativeHandle> { +class NativeHandle : public LightRefBase<NativeHandle> { public: // Create a refcounted wrapper around a native_handle_t, and declare // whether the wrapper owns the handle (so that it should clean up the @@ -41,7 +41,7 @@ private: friend class LightRefBase<NativeHandle>; NativeHandle(native_handle_t* handle, bool ownsHandle); - virtual ~NativeHandle(); + ~NativeHandle(); native_handle_t* mHandle; bool mOwnsHandle; diff --git a/libutils/include/utils/RefBase.h b/libutils/include/utils/RefBase.h index 36016cde6..223b6669d 100644 --- a/libutils/include/utils/RefBase.h +++ b/libutils/include/utils/RefBase.h @@ -177,6 +177,9 @@ #include <stdlib.h> #include <string.h> +// LightRefBase used to be declared in this header, so we have to include it +#include <utils/LightRefBase.h> + #include <utils/StrongPointer.h> #include <utils/TypeHelpers.h> @@ -216,7 +219,7 @@ inline bool operator _op_ (const U* o) const { \ class ReferenceRenamer { protected: - // destructor is purposedly not virtual so we avoid code overhead from + // destructor is purposely not virtual so we avoid code overhead from // subclasses; we have to make it protected to guarantee that it // cannot be called from this base class (and to make strict compilers // happy). @@ -246,13 +249,13 @@ public: { public: RefBase* refBase() const; - + void incWeak(const void* id); void decWeak(const void* id); - + // acquires a strong reference if there is already one. bool attemptIncStrong(const void* id); - + // acquires a weak reference if there is already one. // This is not always safe. see ProcessState.cpp and BpBinder.cpp // for proper use. @@ -268,12 +271,12 @@ public: // enable -- enable/disable tracking // retain -- when tracking is enable, if true, then we save a stack trace // for each reference and dereference; when retain == false, we - // match up references and dereferences and keep only the + // match up references and dereferences and keep only the // outstanding ones. - + void trackMe(bool enable, bool retain); }; - + weakref_type* createWeak(const void* id) const; weakref_type* getWeakRefs() const; @@ -345,56 +348,12 @@ private: // --------------------------------------------------------------------------- -template <class T> -class LightRefBase -{ -public: - inline LightRefBase() : mCount(0) { } - inline void incStrong(__attribute__((unused)) const void* id) const { - mCount.fetch_add(1, std::memory_order_relaxed); - } - inline void decStrong(__attribute__((unused)) const void* id) const { - if (mCount.fetch_sub(1, std::memory_order_release) == 1) { - std::atomic_thread_fence(std::memory_order_acquire); - delete static_cast<const T*>(this); - } - } - //! DEBUGGING ONLY: Get current strong ref count. - inline int32_t getStrongCount() const { - return mCount.load(std::memory_order_relaxed); - } - - typedef LightRefBase<T> basetype; - -protected: - inline ~LightRefBase() { } - -private: - friend class ReferenceMover; - inline static void renameRefs(size_t /*n*/, - const ReferenceRenamer& /*renamer*/) { } - inline static void renameRefId(T* /*ref*/, - const void* /*old_id*/ , const void* /*new_id*/) { } - -private: - mutable std::atomic<int32_t> mCount; -}; - -// This is a wrapper around LightRefBase that simply enforces a virtual -// destructor to eliminate the template requirement of LightRefBase -class VirtualLightRefBase : public LightRefBase<VirtualLightRefBase> { -public: - virtual ~VirtualLightRefBase(); -}; - -// --------------------------------------------------------------------------- - template <typename T> class wp { public: typedef typename RefBase::weakref_type weakref_type; - + inline wp() : m_ptr(0) { } wp(T* other); // NOLINT(implicit) @@ -405,31 +364,31 @@ public: template<typename U> wp(const wp<U>& other); // NOLINT(implicit) ~wp(); - + // Assignment wp& operator = (T* other); wp& operator = (const wp<T>& other); wp& operator = (const sp<T>& other); - + template<typename U> wp& operator = (U* other); template<typename U> wp& operator = (const wp<U>& other); template<typename U> wp& operator = (const sp<U>& other); - + void set_object_and_refs(T* other, weakref_type* refs); // promotion to sp - + sp<T> promote() const; // Reset - + void clear(); // Accessors - + inline weakref_type* get_refs() const { return m_refs; } - + inline T* unsafe_get() const { return m_ptr; } // Operators diff --git a/libutils/include/utils/Singleton.h b/libutils/include/utils/Singleton.h index abb72f510..9afedd4a0 100644 --- a/libutils/include/utils/Singleton.h +++ b/libutils/include/utils/Singleton.h @@ -18,9 +18,12 @@ #define ANDROID_UTILS_SINGLETON_H #include <stdint.h> + +// some vendor code assumes they have atoi() after including this file. +#include <stdlib.h> + #include <sys/types.h> #include <utils/Mutex.h> -#include <utils/threads.h> #include <cutils/compiler.h> namespace android { diff --git a/libutils/include/utils/SortedVector.h b/libutils/include/utils/SortedVector.h index 86f349645..5b2a23200 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 @@ -235,7 +252,7 @@ ssize_t SortedVector<TYPE>::removeItemsAt(size_t index, size_t count) { // --------------------------------------------------------------------------- template<class TYPE> -void SortedVector<TYPE>::do_construct(void* storage, size_t num) const { +UTILS_VECTOR_NO_CFI void SortedVector<TYPE>::do_construct(void* storage, size_t num) const { construct_type( reinterpret_cast<TYPE*>(storage), num ); } @@ -245,22 +262,22 @@ void SortedVector<TYPE>::do_destroy(void* storage, size_t num) const { } template<class TYPE> -void SortedVector<TYPE>::do_copy(void* dest, const void* from, size_t num) const { +UTILS_VECTOR_NO_CFI void SortedVector<TYPE>::do_copy(void* dest, const void* from, size_t num) const { copy_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num ); } template<class TYPE> -void SortedVector<TYPE>::do_splat(void* dest, const void* item, size_t num) const { +UTILS_VECTOR_NO_CFI void SortedVector<TYPE>::do_splat(void* dest, const void* item, size_t num) const { splat_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(item), num ); } template<class TYPE> -void SortedVector<TYPE>::do_move_forward(void* dest, const void* from, size_t num) const { +UTILS_VECTOR_NO_CFI void SortedVector<TYPE>::do_move_forward(void* dest, const void* from, size_t num) const { move_forward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num ); } template<class TYPE> -void SortedVector<TYPE>::do_move_backward(void* dest, const void* from, size_t num) const { +UTILS_VECTOR_NO_CFI void SortedVector<TYPE>::do_move_backward(void* dest, const void* from, size_t num) const { move_backward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num ); } diff --git a/libutils/include/utils/StrongPointer.h b/libutils/include/utils/StrongPointer.h index c2f772222..0c2060791 100644 --- a/libutils/include/utils/StrongPointer.h +++ b/libutils/include/utils/StrongPointer.h @@ -17,12 +17,6 @@ #ifndef ANDROID_STRONG_POINTER_H #define ANDROID_STRONG_POINTER_H -#include <cutils/atomic.h> - -#include <stdint.h> -#include <sys/types.h> -#include <stdlib.h> - // --------------------------------------------------------------------------- namespace android { diff --git a/libutils/include/utils/Trace.h b/libutils/include/utils/Trace.h index eeba40d65..5e9229c1e 100644 --- a/libutils/include/utils/Trace.h +++ b/libutils/include/utils/Trace.h @@ -19,16 +19,8 @@ #if defined(__ANDROID__) -#include <fcntl.h> #include <stdint.h> -#include <stdio.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include <cutils/compiler.h> -#include <utils/threads.h> + #include <cutils/trace.h> // See <cutils/trace.h> for more ATRACE_* macros. @@ -37,6 +29,7 @@ #define _PASTE(x, y) x ## y #define PASTE(x, y) _PASTE(x,y) #define ATRACE_NAME(name) android::ScopedTrace PASTE(___tracer, __LINE__) (ATRACE_TAG, name) + // ATRACE_CALL is an ATRACE_NAME that uses the current function name. #define ATRACE_CALL() ATRACE_NAME(__FUNCTION__) @@ -44,14 +37,13 @@ namespace android { class ScopedTrace { public: -inline ScopedTrace(uint64_t tag, const char* name) - : mTag(tag) { - atrace_begin(mTag,name); -} - -inline ~ScopedTrace() { - atrace_end(mTag); -} + inline ScopedTrace(uint64_t tag, const char* name) : mTag(tag) { + atrace_begin(mTag, name); + } + + inline ~ScopedTrace() { + atrace_end(mTag); + } private: uint64_t mTag; diff --git a/libutils/include/utils/TypeHelpers.h b/libutils/include/utils/TypeHelpers.h index 2a2522722..28fbca508 100644 --- a/libutils/include/utils/TypeHelpers.h +++ b/libutils/include/utils/TypeHelpers.h @@ -36,7 +36,7 @@ template <typename T> struct trait_trivial_ctor { enum { value = false }; }; template <typename T> struct trait_trivial_dtor { enum { value = false }; }; template <typename T> struct trait_trivial_copy { enum { value = false }; }; template <typename T> struct trait_trivial_move { enum { value = false }; }; -template <typename T> struct trait_pointer { enum { value = false }; }; +template <typename T> struct trait_pointer { enum { value = false }; }; template <typename T> struct trait_pointer<T*> { enum { value = true }; }; template <typename TYPE> @@ -59,13 +59,13 @@ template <typename T, typename U> struct aggregate_traits { enum { is_pointer = false, - has_trivial_ctor = + has_trivial_ctor = traits<T>::has_trivial_ctor && traits<U>::has_trivial_ctor, - has_trivial_dtor = + has_trivial_dtor = traits<T>::has_trivial_dtor && traits<U>::has_trivial_dtor, - has_trivial_copy = + has_trivial_copy = traits<T>::has_trivial_copy && traits<U>::has_trivial_copy, - has_trivial_move = + has_trivial_move = traits<T>::has_trivial_move && traits<U>::has_trivial_move }; }; diff --git a/libutils/include/utils/Vector.h b/libutils/include/utils/Vector.h index 9a643f9b0..7e00123f7 100644 --- a/libutils/include/utils/Vector.h +++ b/libutils/include/utils/Vector.h @@ -24,6 +24,20 @@ #include <utils/TypeHelpers.h> #include <utils/VectorImpl.h> +/* + * Used to blacklist some functions from CFI. + * + */ +#ifndef __has_attribute +#define __has_attribute(x) 0 +#endif + +#if __has_attribute(no_sanitize) +#define UTILS_VECTOR_NO_CFI __attribute__((no_sanitize("cfi"))) +#else +#define UTILS_VECTOR_NO_CFI +#endif + // --------------------------------------------------------------------------- namespace android { @@ -42,11 +56,11 @@ class Vector : private VectorImpl { public: typedef TYPE value_type; - - /*! + + /*! * Constructors and destructors */ - + Vector(); Vector(const Vector<TYPE>& rhs); explicit Vector(const SortedVector<TYPE>& rhs); @@ -54,7 +68,7 @@ public: /*! copy operator */ const Vector<TYPE>& operator = (const Vector<TYPE>& rhs) const; - Vector<TYPE>& operator = (const Vector<TYPE>& rhs); + Vector<TYPE>& operator = (const Vector<TYPE>& rhs); const Vector<TYPE>& operator = (const SortedVector<TYPE>& rhs) const; Vector<TYPE>& operator = (const SortedVector<TYPE>& rhs); @@ -65,7 +79,7 @@ public: inline void clear() { VectorImpl::clear(); } - /*! + /*! * vector stats */ @@ -87,13 +101,13 @@ public: /*! * C-style array access */ - - //! read-only C-style access + + //! read-only C-style access inline const TYPE* array() const; //! read-write C-style access TYPE* editArray(); - - /*! + + /*! * accessors */ @@ -113,10 +127,10 @@ public: //! grants right access to the top of the stack (last element) TYPE& editTop(); - /*! + /*! * append/insert another vector */ - + //! insert another vector at a given index ssize_t insertVectorAt(const Vector<TYPE>& vector, size_t index); @@ -130,10 +144,10 @@ public: //! append an array at the end of this vector ssize_t appendArray(const TYPE* array, size_t length); - /*! + /*! * add/insert/replace items */ - + //! insert one or several items initialized with their default constructor inline ssize_t insertAt(size_t index, size_t numItems = 1); //! insert one or several items initialized from a prototype item @@ -147,7 +161,7 @@ public: //! same as push() but returns the index the item was added at (or an error) inline ssize_t add(); //! same as push() but returns the index the item was added at (or an error) - ssize_t add(const TYPE& item); + ssize_t add(const TYPE& item); //! replace an item with a new one initialized with its default constructor inline ssize_t replaceAt(size_t index); //! replace an item with a new one @@ -165,10 +179,10 @@ public: /*! * sort (stable) the array */ - + typedef int (*compar_t)(const TYPE* lhs, const TYPE* rhs); typedef int (*compar_r_t)(const TYPE* lhs, const TYPE* rhs, void* state); - + inline status_t sort(compar_t cmp); inline status_t sort(compar_r_t cmp, void* state); @@ -237,7 +251,7 @@ Vector<TYPE>::~Vector() { template<class TYPE> inline Vector<TYPE>& Vector<TYPE>::operator = (const Vector<TYPE>& rhs) { VectorImpl::operator = (rhs); - return *this; + return *this; } template<class TYPE> inline @@ -255,7 +269,7 @@ Vector<TYPE>& Vector<TYPE>::operator = (const SortedVector<TYPE>& rhs) { template<class TYPE> inline const Vector<TYPE>& Vector<TYPE>::operator = (const SortedVector<TYPE>& rhs) const { VectorImpl::operator = (rhs); - return *this; + return *this; } template<class TYPE> inline @@ -380,7 +394,7 @@ status_t Vector<TYPE>::sort(Vector<TYPE>::compar_r_t cmp, void* state) { // --------------------------------------------------------------------------- template<class TYPE> -void Vector<TYPE>::do_construct(void* storage, size_t num) const { +UTILS_VECTOR_NO_CFI void Vector<TYPE>::do_construct(void* storage, size_t num) const { construct_type( reinterpret_cast<TYPE*>(storage), num ); } @@ -390,22 +404,22 @@ void Vector<TYPE>::do_destroy(void* storage, size_t num) const { } template<class TYPE> -void Vector<TYPE>::do_copy(void* dest, const void* from, size_t num) const { +UTILS_VECTOR_NO_CFI void Vector<TYPE>::do_copy(void* dest, const void* from, size_t num) const { copy_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num ); } template<class TYPE> -void Vector<TYPE>::do_splat(void* dest, const void* item, size_t num) const { +UTILS_VECTOR_NO_CFI void Vector<TYPE>::do_splat(void* dest, const void* item, size_t num) const { splat_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(item), num ); } template<class TYPE> -void Vector<TYPE>::do_move_forward(void* dest, const void* from, size_t num) const { +UTILS_VECTOR_NO_CFI void Vector<TYPE>::do_move_forward(void* dest, const void* from, size_t num) const { move_forward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num ); } template<class TYPE> -void Vector<TYPE>::do_move_backward(void* dest, const void* from, size_t num) const { +UTILS_VECTOR_NO_CFI void Vector<TYPE>::do_move_backward(void* dest, const void* from, size_t num) const { move_backward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num ); } diff --git a/libutils/misc.cpp b/libutils/misc.cpp index 216dc1430..d95fd056b 100644 --- a/libutils/misc.cpp +++ b/libutils/misc.cpp @@ -16,21 +16,19 @@ #define LOG_TAG "misc" -// -// Miscellaneous utility functions. -// #include <utils/misc.h> -#include <utils/Log.h> -#include <sys/stat.h> -#include <string.h> -#include <stdio.h> +#include <pthread.h> -#if !defined(_WIN32) -# include <pthread.h> +#include <utils/Log.h> +#include <utils/Vector.h> + +#if defined(__ANDROID__) +#include <dlfcn.h> +#include <vndksupport/linker.h> #endif -#include <utils/Vector.h> +extern "C" void do_report_sysprop_change(); using namespace android; @@ -70,7 +68,36 @@ void add_sysprop_change_callback(sysprop_change_callback cb, int priority) { #endif } +#if defined(__ANDROID__) +void (*get_report_sysprop_change_func())() { + void (*func)() = nullptr; + void* handle = android_load_sphal_library("libutils.so", RTLD_NOW); + if (handle != nullptr) { + func = reinterpret_cast<decltype(func)>(dlsym(handle, "do_report_sysprop_change")); + } + + return func; +} +#endif + void report_sysprop_change() { + do_report_sysprop_change(); + +#if defined(__ANDROID__) + // libutils.so is double loaded; from the default namespace and from the + // 'sphal' namespace. Redirect the sysprop change event to the other instance + // of libutils.so loaded in the 'sphal' namespace so that listeners attached + // to that instance is also notified with this event. + static auto func = get_report_sysprop_change_func(); + if (func != nullptr) { + (*func)(); + } +#endif +} + +}; // namespace android + +void do_report_sysprop_change() { #if !defined(_WIN32) pthread_mutex_lock(&gSyspropMutex); Vector<sysprop_change_callback_info> listeners; @@ -85,5 +112,3 @@ void report_sysprop_change() { } #endif } - -}; // namespace android diff --git a/libutils/tests/Android.bp b/libutils/tests/Android.bp index 7cae13351..08691756a 100644 --- a/libutils/tests/Android.bp +++ b/libutils/tests/Android.bp @@ -34,7 +34,6 @@ cc_test { target: { android: { srcs: [ - "BlobCache_test.cpp", "Looper_test.cpp", "RefBase_test.cpp", "SystemClock_test.cpp", diff --git a/libutils/tests/BlobCache_test.cpp b/libutils/tests/BlobCache_test.cpp deleted file mode 100644 index 1e2ff9828..000000000 --- a/libutils/tests/BlobCache_test.cpp +++ /dev/null @@ -1,425 +0,0 @@ -/* - ** Copyright 2011, The Android Open Source Project - ** - ** Licensed under the Apache License, Version 2.0 (the "License"); - ** you may not use this file except in compliance with the License. - ** You may obtain a copy of the License at - ** - ** http://www.apache.org/licenses/LICENSE-2.0 - ** - ** Unless required by applicable law or agreed to in writing, software - ** distributed under the License is distributed on an "AS IS" BASIS, - ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ** See the License for the specific language governing permissions and - ** limitations under the License. - */ - -#include <fcntl.h> -#include <stdio.h> - -#include <gtest/gtest.h> - -#include <utils/BlobCache.h> -#include <utils/Errors.h> - -namespace android { - -class BlobCacheTest : public ::testing::Test { -protected: - enum { - MAX_KEY_SIZE = 6, - MAX_VALUE_SIZE = 8, - MAX_TOTAL_SIZE = 13, - }; - - virtual void SetUp() { - mBC = new BlobCache(MAX_KEY_SIZE, MAX_VALUE_SIZE, MAX_TOTAL_SIZE); - } - - virtual void TearDown() { - mBC.clear(); - } - - sp<BlobCache> mBC; -}; - -TEST_F(BlobCacheTest, CacheSingleValueSucceeds) { - unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; - mBC->set("abcd", 4, "efgh", 4); - ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4)); - ASSERT_EQ('e', buf[0]); - ASSERT_EQ('f', buf[1]); - ASSERT_EQ('g', buf[2]); - ASSERT_EQ('h', buf[3]); -} - -TEST_F(BlobCacheTest, CacheTwoValuesSucceeds) { - unsigned char buf[2] = { 0xee, 0xee }; - mBC->set("ab", 2, "cd", 2); - mBC->set("ef", 2, "gh", 2); - ASSERT_EQ(size_t(2), mBC->get("ab", 2, buf, 2)); - ASSERT_EQ('c', buf[0]); - ASSERT_EQ('d', buf[1]); - ASSERT_EQ(size_t(2), mBC->get("ef", 2, buf, 2)); - ASSERT_EQ('g', buf[0]); - ASSERT_EQ('h', buf[1]); -} - -TEST_F(BlobCacheTest, GetOnlyWritesInsideBounds) { - unsigned char buf[6] = { 0xee, 0xee, 0xee, 0xee, 0xee, 0xee }; - mBC->set("abcd", 4, "efgh", 4); - ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf+1, 4)); - ASSERT_EQ(0xee, buf[0]); - ASSERT_EQ('e', buf[1]); - ASSERT_EQ('f', buf[2]); - ASSERT_EQ('g', buf[3]); - ASSERT_EQ('h', buf[4]); - ASSERT_EQ(0xee, buf[5]); -} - -TEST_F(BlobCacheTest, GetOnlyWritesIfBufferIsLargeEnough) { - unsigned char buf[3] = { 0xee, 0xee, 0xee }; - mBC->set("abcd", 4, "efgh", 4); - ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 3)); - ASSERT_EQ(0xee, buf[0]); - ASSERT_EQ(0xee, buf[1]); - ASSERT_EQ(0xee, buf[2]); -} - -TEST_F(BlobCacheTest, GetDoesntAccessNullBuffer) { - mBC->set("abcd", 4, "efgh", 4); - ASSERT_EQ(size_t(4), mBC->get("abcd", 4, NULL, 0)); -} - -TEST_F(BlobCacheTest, MultipleSetsCacheLatestValue) { - unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; - mBC->set("abcd", 4, "efgh", 4); - mBC->set("abcd", 4, "ijkl", 4); - ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4)); - ASSERT_EQ('i', buf[0]); - ASSERT_EQ('j', buf[1]); - ASSERT_EQ('k', buf[2]); - ASSERT_EQ('l', buf[3]); -} - -TEST_F(BlobCacheTest, SecondSetKeepsFirstValueIfTooLarge) { - unsigned char buf[MAX_VALUE_SIZE+1] = { 0xee, 0xee, 0xee, 0xee }; - mBC->set("abcd", 4, "efgh", 4); - mBC->set("abcd", 4, buf, MAX_VALUE_SIZE+1); - ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4)); - ASSERT_EQ('e', buf[0]); - ASSERT_EQ('f', buf[1]); - ASSERT_EQ('g', buf[2]); - ASSERT_EQ('h', buf[3]); -} - -TEST_F(BlobCacheTest, DoesntCacheIfKeyIsTooBig) { - char key[MAX_KEY_SIZE+1]; - unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; - for (int i = 0; i < MAX_KEY_SIZE+1; i++) { - key[i] = 'a'; - } - mBC->set(key, MAX_KEY_SIZE+1, "bbbb", 4); - ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE+1, buf, 4)); - ASSERT_EQ(0xee, buf[0]); - ASSERT_EQ(0xee, buf[1]); - ASSERT_EQ(0xee, buf[2]); - ASSERT_EQ(0xee, buf[3]); -} - -TEST_F(BlobCacheTest, DoesntCacheIfValueIsTooBig) { - char buf[MAX_VALUE_SIZE+1]; - for (int i = 0; i < MAX_VALUE_SIZE+1; i++) { - buf[i] = 'b'; - } - mBC->set("abcd", 4, buf, MAX_VALUE_SIZE+1); - for (int i = 0; i < MAX_VALUE_SIZE+1; i++) { - buf[i] = 0xee; - } - ASSERT_EQ(size_t(0), mBC->get("abcd", 4, buf, MAX_VALUE_SIZE+1)); - for (int i = 0; i < MAX_VALUE_SIZE+1; i++) { - SCOPED_TRACE(i); - ASSERT_EQ(0xee, buf[i]); - } -} - -TEST_F(BlobCacheTest, DoesntCacheIfKeyValuePairIsTooBig) { - // Check a testing assumptions - ASSERT_TRUE(MAX_TOTAL_SIZE < MAX_KEY_SIZE + MAX_VALUE_SIZE); - ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE); - - enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE + 1 }; - - char key[MAX_KEY_SIZE]; - char buf[bufSize]; - for (int i = 0; i < MAX_KEY_SIZE; i++) { - key[i] = 'a'; - } - for (int i = 0; i < bufSize; i++) { - buf[i] = 'b'; - } - - mBC->set(key, MAX_KEY_SIZE, buf, MAX_VALUE_SIZE); - ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE, NULL, 0)); -} - -TEST_F(BlobCacheTest, CacheMaxKeySizeSucceeds) { - char key[MAX_KEY_SIZE]; - unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; - for (int i = 0; i < MAX_KEY_SIZE; i++) { - key[i] = 'a'; - } - mBC->set(key, MAX_KEY_SIZE, "wxyz", 4); - ASSERT_EQ(size_t(4), mBC->get(key, MAX_KEY_SIZE, buf, 4)); - ASSERT_EQ('w', buf[0]); - ASSERT_EQ('x', buf[1]); - ASSERT_EQ('y', buf[2]); - ASSERT_EQ('z', buf[3]); -} - -TEST_F(BlobCacheTest, CacheMaxValueSizeSucceeds) { - char buf[MAX_VALUE_SIZE]; - for (int i = 0; i < MAX_VALUE_SIZE; i++) { - buf[i] = 'b'; - } - mBC->set("abcd", 4, buf, MAX_VALUE_SIZE); - for (int i = 0; i < MAX_VALUE_SIZE; i++) { - buf[i] = 0xee; - } - ASSERT_EQ(size_t(MAX_VALUE_SIZE), mBC->get("abcd", 4, buf, - MAX_VALUE_SIZE)); - for (int i = 0; i < MAX_VALUE_SIZE; i++) { - SCOPED_TRACE(i); - ASSERT_EQ('b', buf[i]); - } -} - -TEST_F(BlobCacheTest, CacheMaxKeyValuePairSizeSucceeds) { - // Check a testing assumption - ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE); - - enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE }; - - char key[MAX_KEY_SIZE]; - char buf[bufSize]; - for (int i = 0; i < MAX_KEY_SIZE; i++) { - key[i] = 'a'; - } - for (int i = 0; i < bufSize; i++) { - buf[i] = 'b'; - } - - mBC->set(key, MAX_KEY_SIZE, buf, bufSize); - ASSERT_EQ(size_t(bufSize), mBC->get(key, MAX_KEY_SIZE, NULL, 0)); -} - -TEST_F(BlobCacheTest, CacheMinKeyAndValueSizeSucceeds) { - unsigned char buf[1] = { 0xee }; - mBC->set("x", 1, "y", 1); - ASSERT_EQ(size_t(1), mBC->get("x", 1, buf, 1)); - ASSERT_EQ('y', buf[0]); -} - -TEST_F(BlobCacheTest, CacheSizeDoesntExceedTotalLimit) { - for (int i = 0; i < 256; i++) { - uint8_t k = i; - mBC->set(&k, 1, "x", 1); - } - int numCached = 0; - for (int i = 0; i < 256; i++) { - uint8_t k = i; - if (mBC->get(&k, 1, NULL, 0) == 1) { - numCached++; - } - } - ASSERT_GE(MAX_TOTAL_SIZE / 2, numCached); -} - -TEST_F(BlobCacheTest, ExceedingTotalLimitHalvesCacheSize) { - // Fill up the entire cache with 1 char key/value pairs. - const int maxEntries = MAX_TOTAL_SIZE / 2; - for (int i = 0; i < maxEntries; i++) { - uint8_t k = i; - mBC->set(&k, 1, "x", 1); - } - // Insert one more entry, causing a cache overflow. - { - uint8_t k = maxEntries; - mBC->set(&k, 1, "x", 1); - } - // Count the number of entries in the cache. - int numCached = 0; - for (int i = 0; i < maxEntries+1; i++) { - uint8_t k = i; - if (mBC->get(&k, 1, NULL, 0) == 1) { - numCached++; - } - } - ASSERT_EQ(maxEntries/2 + 1, numCached); -} - -class BlobCacheFlattenTest : public BlobCacheTest { -protected: - virtual void SetUp() { - BlobCacheTest::SetUp(); - mBC2 = new BlobCache(MAX_KEY_SIZE, MAX_VALUE_SIZE, MAX_TOTAL_SIZE); - } - - virtual void TearDown() { - mBC2.clear(); - BlobCacheTest::TearDown(); - } - - void roundTrip() { - size_t size = mBC->getFlattenedSize(); - uint8_t* flat = new uint8_t[size]; - ASSERT_EQ(OK, mBC->flatten(flat, size)); - ASSERT_EQ(OK, mBC2->unflatten(flat, size)); - delete[] flat; - } - - sp<BlobCache> mBC2; -}; - -TEST_F(BlobCacheFlattenTest, FlattenOneValue) { - unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; - mBC->set("abcd", 4, "efgh", 4); - roundTrip(); - ASSERT_EQ(size_t(4), mBC2->get("abcd", 4, buf, 4)); - ASSERT_EQ('e', buf[0]); - ASSERT_EQ('f', buf[1]); - ASSERT_EQ('g', buf[2]); - ASSERT_EQ('h', buf[3]); -} - -TEST_F(BlobCacheFlattenTest, FlattenFullCache) { - // Fill up the entire cache with 1 char key/value pairs. - const int maxEntries = MAX_TOTAL_SIZE / 2; - for (int i = 0; i < maxEntries; i++) { - uint8_t k = i; - mBC->set(&k, 1, &k, 1); - } - - roundTrip(); - - // Verify the deserialized cache - for (int i = 0; i < maxEntries; i++) { - uint8_t k = i; - uint8_t v = 0xee; - ASSERT_EQ(size_t(1), mBC2->get(&k, 1, &v, 1)); - ASSERT_EQ(k, v); - } -} - -TEST_F(BlobCacheFlattenTest, FlattenDoesntChangeCache) { - // Fill up the entire cache with 1 char key/value pairs. - const int maxEntries = MAX_TOTAL_SIZE / 2; - for (int i = 0; i < maxEntries; i++) { - uint8_t k = i; - mBC->set(&k, 1, &k, 1); - } - - size_t size = mBC->getFlattenedSize(); - uint8_t* flat = new uint8_t[size]; - ASSERT_EQ(OK, mBC->flatten(flat, size)); - delete[] flat; - - // Verify the cache that we just serialized - for (int i = 0; i < maxEntries; i++) { - uint8_t k = i; - uint8_t v = 0xee; - ASSERT_EQ(size_t(1), mBC->get(&k, 1, &v, 1)); - ASSERT_EQ(k, v); - } -} - -TEST_F(BlobCacheFlattenTest, FlattenCatchesBufferTooSmall) { - // Fill up the entire cache with 1 char key/value pairs. - const int maxEntries = MAX_TOTAL_SIZE / 2; - for (int i = 0; i < maxEntries; i++) { - uint8_t k = i; - mBC->set(&k, 1, &k, 1); - } - - size_t size = mBC->getFlattenedSize() - 1; - uint8_t* flat = new uint8_t[size]; - // ASSERT_EQ(BAD_VALUE, mBC->flatten(flat, size)); - // TODO: The above fails. I expect this is so because getFlattenedSize() - // overstimates the size by using PROPERTY_VALUE_MAX. - delete[] flat; -} - -TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadMagic) { - unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; - mBC->set("abcd", 4, "efgh", 4); - - size_t size = mBC->getFlattenedSize(); - uint8_t* flat = new uint8_t[size]; - ASSERT_EQ(OK, mBC->flatten(flat, size)); - flat[1] = ~flat[1]; - - // Bad magic should cause an error. - ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size)); - delete[] flat; - - // The error should cause the unflatten to result in an empty cache - ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4)); -} - -TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheVersion) { - unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; - mBC->set("abcd", 4, "efgh", 4); - - size_t size = mBC->getFlattenedSize(); - uint8_t* flat = new uint8_t[size]; - ASSERT_EQ(OK, mBC->flatten(flat, size)); - flat[5] = ~flat[5]; - - // Version mismatches shouldn't cause errors, but should not use the - // serialized entries - ASSERT_EQ(OK, mBC2->unflatten(flat, size)); - delete[] flat; - - // The version mismatch should cause the unflatten to result in an empty - // cache - ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4)); -} - -TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheDeviceVersion) { - unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; - mBC->set("abcd", 4, "efgh", 4); - - size_t size = mBC->getFlattenedSize(); - uint8_t* flat = new uint8_t[size]; - ASSERT_EQ(OK, mBC->flatten(flat, size)); - flat[10] = ~flat[10]; - - // Version mismatches shouldn't cause errors, but should not use the - // serialized entries - ASSERT_EQ(OK, mBC2->unflatten(flat, size)); - delete[] flat; - - // The version mismatch should cause the unflatten to result in an empty - // cache - ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4)); -} - -TEST_F(BlobCacheFlattenTest, UnflattenCatchesBufferTooSmall) { - unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; - mBC->set("abcd", 4, "efgh", 4); - - size_t size = mBC->getFlattenedSize(); - uint8_t* flat = new uint8_t[size]; - ASSERT_EQ(OK, mBC->flatten(flat, size)); - - // A buffer truncation shouldt cause an error - // ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size-1)); - // TODO: The above appears to fail because getFlattenedSize() is - // conservative. - delete[] flat; - - // The error should cause the unflatten to result in an empty cache - ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4)); -} - -} // namespace android diff --git a/libvndksupport/Android.bp b/libvndksupport/Android.bp new file mode 100644 index 000000000..b62422323 --- /dev/null +++ b/libvndksupport/Android.bp @@ -0,0 +1,15 @@ +subdirs = ["tests"] + +cc_library { + name: "libvndksupport", + srcs: ["linker.c"], + local_include_dirs: ["include/vndksupport"], + export_include_dirs: ["include"], + shared_libs: ["liblog"], +} + +llndk_library { + name: "libvndksupport", + symbol_file: "libvndksupport.map.txt", + export_include_dirs: ["include"], +} diff --git a/healthd/healthd_board_default.cpp b/libvndksupport/include/vndksupport/linker.h index eb55773de..f509564e1 100644 --- a/healthd/healthd_board_default.cpp +++ b/libvndksupport/include/vndksupport/linker.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,17 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#ifndef VNDKSUPPORT_LINKER_H_ +#define VNDKSUPPORT_LINKER_H_ -#include <healthd/healthd.h> +#ifdef __cplusplus +extern "C" { +#endif -void healthd_board_init(struct healthd_config*) -{ - // use defaults -} +void* android_load_sphal_library(const char* name, int flag); +int android_unload_sphal_library(void* handle); -int healthd_board_battery_update(struct android::BatteryProperties*) -{ - // return 0 to log periodic polled battery status to kernel log - return 0; +#ifdef __cplusplus } +#endif + +#endif // VNDKSUPPORT_LINKER_H_ diff --git a/libvndksupport/libvndksupport.map.txt b/libvndksupport/libvndksupport.map.txt new file mode 100644 index 000000000..16e38da1a --- /dev/null +++ b/libvndksupport/libvndksupport.map.txt @@ -0,0 +1,7 @@ +LIBVNDKSUPPORT { + global: + android_load_sphal_library; # vndk + android_unload_sphal_library; # vndk + local: + *; +}; diff --git a/libvndksupport/linker.c b/libvndksupport/linker.c new file mode 100644 index 000000000..289f153e7 --- /dev/null +++ b/libvndksupport/linker.c @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "linker.h" + +#include <android/dlext.h> +#include <dlfcn.h> + +#define LOG_TAG "vndksupport" +#include <log/log.h> + +extern struct android_namespace_t* android_get_exported_namespace(const char*); + +void* android_load_sphal_library(const char* name, int flag) { + struct android_namespace_t* sphal_namespace = android_get_exported_namespace("sphal"); + if (sphal_namespace != NULL) { + const android_dlextinfo dlextinfo = { + .flags = ANDROID_DLEXT_USE_NAMESPACE, .library_namespace = sphal_namespace, + }; + void* handle = android_dlopen_ext(name, flag, &dlextinfo); + if (!handle) { + ALOGE("Could not load %s from sphal namespace: %s.", name, dlerror()); + } + return handle; + } else { + ALOGI( + "sphal namespace is not configured for this process. " + "Loading %s from the current namespace instead.", + name); + return dlopen(name, flag); + } +} + +int android_unload_sphal_library(void* handle) { return dlclose(handle); } diff --git a/libvndksupport/tests/Android.bp b/libvndksupport/tests/Android.bp new file mode 100644 index 000000000..3587cf88a --- /dev/null +++ b/libvndksupport/tests/Android.bp @@ -0,0 +1,26 @@ +// Copyright (C) 2017 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +cc_test { + name: "libvndksupport-tests", + srcs: [ + "linker_test.cpp", + ], + + host_supported: false, + shared_libs: [ + "libvndksupport", + "libbase", + ] +} diff --git a/libvndksupport/tests/linker_test.cpp b/libvndksupport/tests/linker_test.cpp new file mode 100644 index 000000000..7ce27d411 --- /dev/null +++ b/libvndksupport/tests/linker_test.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <gtest/gtest.h> + +#include <android-base/strings.h> +#include <dirent.h> +#include <dlfcn.h> +#include <vndksupport/linker.h> +#include <string> + +// Since the test executable will be in /data and ld.config.txt does not +// configure sphal namespace for executables in /data, the call to +// android_load_sphal_library will always fallback to the plain dlopen from the +// default namespace. + +// Let's use libEGL_<chipset>.so as a SP-HAL in test +static std::string find_sphal_lib() { + const char* path = +#if defined(__LP64__) + "/vendor/lib64/egl"; +#else + "/vendor/lib/egl"; +#endif + std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path), closedir); + + dirent* dp; + while ((dp = readdir(dir.get())) != nullptr) { + std::string name = dp->d_name; + if (android::base::StartsWith(name, "libEGL_")) { + return std::string(path) + "/" + name; + } + } + return ""; +} + +TEST(linker, load_existing_lib) { + std::string name = find_sphal_lib(); + ASSERT_NE("", name); + void* handle = android_load_sphal_library(name.c_str(), RTLD_NOW | RTLD_LOCAL); + ASSERT_NE(nullptr, handle); + android_unload_sphal_library(handle); +} + +TEST(linker, load_nonexisting_lib) { + void* handle = android_load_sphal_library("libNeverUseThisName.so", RTLD_NOW | RTLD_LOCAL); + ASSERT_EQ(nullptr, handle); +} diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp index 76a4affdc..749832530 100644 --- a/logd/LogBuffer.cpp +++ b/logd/LogBuffer.cpp @@ -165,15 +165,17 @@ static enum match_type identical(LogBufferElement* elem, (lenl == sizeof(android_log_event_int_t)) && !fastcmp<memcmp>(msgl, msgr, sizeof(android_log_event_int_t) - sizeof(int32_t)) && - (elem->getTag() == LIBLOG_LOG_TAG)) + (elem->getTag() == LIBLOG_LOG_TAG)) { return SAME_LIBLOG; + } } // audit message (except sequence number) identical? if (last->isBinary()) { if (fastcmp<memcmp>(msgl, msgr, sizeof(android_log_event_string_t) - - sizeof(int32_t))) + sizeof(int32_t))) { return DIFFERENT; + } msgl += sizeof(android_log_event_string_t); lenl -= sizeof(android_log_event_string_t); msgr += sizeof(android_log_event_string_t); diff --git a/rootdir/Android.mk b/rootdir/Android.mk index 86fec6a56..48a46c606 100644 --- a/rootdir/Android.mk +++ b/rootdir/Android.mk @@ -173,4 +173,18 @@ $(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/init.environ.rc.in $(bcp_dep) bcp_md5 := bcp_dep := + ####################################### +# ld.config.txt +include $(CLEAR_VARS) + +LOCAL_MODULE := ld.config.txt +ifeq ($(PRODUCT_FULL_TREBLE),true) +LOCAL_SRC_FILES := etc/ld.config.txt +else +LOCAL_SRC_FILES := etc/ld.config.legacy.txt +endif +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_ETC) +LOCAL_MODULE_STEM := $(LOCAL_MODULE) +include $(BUILD_PREBUILT) diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt new file mode 100644 index 000000000..c22edfec6 --- /dev/null +++ b/rootdir/etc/ld.config.legacy.txt @@ -0,0 +1,15 @@ +# Copyright (C) 2017 The Android Open Source Project +# +# Bionic loader config file. +# This gives the exactly the same namespace setup in pre-O. +# + +# All binaries gets the same configuration 'legacy' +dir.legacy = /system +dir.legacy = /vendor +dir.legacy = /sbin + +[legacy] +namespace.default.isolated = false +namespace.default.search.paths = /system/${LIB}:/vendor/${LIB} +namespace.default.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}:/data/asan/vendor/${LIB}:/vendor/${LIB} diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt index e3468cab8..436589ec5 100644 --- a/rootdir/etc/ld.config.txt +++ b/rootdir/etc/ld.config.txt @@ -3,45 +3,111 @@ # Bionic loader config file. # -#dir.vendor=/vendor/bin/ -#dir.system=/system/bin/ +# Don't change the order here. +dir.system = /system/bin/ +dir.system = /system/xbin/ +dir.vendor = /vendor/bin/ -[vendor] +[system] +additional.namespaces = sphal,vndk,rs + +############################################################################### +# "default" namespace +# +# Framework-side code runs in this namespace. Anything from /vendor partition +# can't be loaded in this namespace. +############################################################################### +namespace.default.isolated = false +namespace.default.search.paths = /system/${LIB}:/vendor/${LIB} +namespace.default.permitted.paths = /system/${LIB}:/vendor/${LIB} + +namespace.default.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}:/data/asan/vendor/${LIB}:/vendor/${LIB} +namespace.default.asan.permitted.paths = /data/asan/system/${LIB}:/system/${LIB}:/data/asan/vendor/${LIB}:/vendor/${LIB} -# When this flag is set to true linker will -# set target_sdk_version for this binary to -# the version specified in <dirname>/.version -# file, where <dirname> = dirname(executable_path) +# TODO(b/37013858): remove all dependencies to /vendor/lib from system processes +# When this is done, comment out following three lines and remove the three +# lines above +#namespace.default.isolated = true +#namespace.default.search.paths = /system/${LIB} +#namespace.default.permitted.paths = /system/${LIB} # -# default value is false -enable.target.sdk.version = true +#namespace.default.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB} +#namespace.default.asan.permitted.paths = /data/asan/system/${LIB}:/system/${LIB} -# There is always the default namespace no -# need to mention it in this list -additional.namespaces=system +############################################################################### +# "sphal" namespace +# +# SP-HAL(Sameprocess-HAL)s are the only vendor libraries that are allowed to be +# loaded inside system processes. libEGL_<chipset>.so, libGLESv2_<chipset>.so, +# android.hardware.graphics.mapper@2.0-impl.so, etc are SP-HALs. +# +# This namespace is exclusivly for SP-HALs. When the framework tries to dynami- +# cally load SP-HALs, android_dlopen_ext() is used to explicitly specifying +# that they should be searched and loaded from this namespace. +# +# Note that there is no link from the default namespace to this namespace. +############################################################################### +namespace.sphal.isolated = true +namespace.sphal.visible = true +namespace.sphal.search.paths = /vendor/${LIB}/egl:/vendor/${LIB}/hw:/vendor/${LIB} +namespace.sphal.permitted.paths = /vendor/${LIB} -# Is the namespace isolated -namespace.default.isolated = true -namespace.default.search.paths = /vendor/${LIB} +namespace.sphal.asan.search.paths = /data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}:/vendor/${LIB} +namespace.sphal.asan.permitted.paths = /data/asan/vendor/${LIB}:/vendor/${LIB} -# TODO: property for asan search path? -namespace.default.permitted.paths = /vendor/${LIB} -namespace.default.asan.permitted.paths = /data/vendor/${LIB} -namespace.default.links = system +# Once in this namespace, access to libraries in /system/lib is restricted. Only +# libs listed here can be used. +namespace.sphal.links = default,vndk,rs -# Todo complete this list -namespace.default.link.system.shared_libs = libc.so:libm.so:libdl.so:libstdc++.so +# WARNING: only NDK libs can be listed here. +namespace.sphal.link.default.shared_libs = libc.so:libz.so:libm.so:libdl.so:libstdc++.so:liblog.so:libnativewindow.so:libEGL.so:libsync.so:libGLESv1_CM.so:libGLESv2.so:libvndksupport.so -namespace.system.isolated = true -namespace.system.search.paths = /system/${LIB}:/system/${LIB}/framework -namespace.system.permitted.paths = /system/${LIB} +# WARNING: only VNDK-SP libs can be listed here. DO NOT EDIT this line. +namespace.sphal.link.vndk.shared_libs = android.hardware.renderscript@1.0.so:android.hardware.graphics.allocator@2.0.so:android.hardware.graphics.mapper@2.0.so:android.hardware.graphics.common@1.0.so:android.hidl.memory@1.0.so:libhwbinder.so:libbase.so:libcutils.so:libhardware.so:libhidlbase.so:libhidlmemory.so:libhidltransport.so:libion.so:libutils.so:libc++.so -[system] -namespace.default.isolated = true -namespace.default.search.paths = /system/${LIB} -namespace.default.permitted.paths = /system/${LIB} +# Renderscript gets separate namespace +namespace.sphal.link.rs.shared_libs = libRS_internal.so -# app_process will setup additional vendor namespace manually. -# Note that zygote will need vendor namespace to setup list of public -# libraries provided by vendors to apps. +############################################################################### +# "rs" namespace +# +# This namespace is exclusively for Renderscript internal libraries. +# This namespace has slightly looser restriction than the vndk namespace because +# of the genuine characteristics of Renderscript; /data is in the permitted path +# to load the compiled *.so file and libmediandk.so can be used here. +############################################################################### +namespace.rs.isolated = true +namespace.rs.search.paths = /vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/vendor/${LIB} +namespace.rs.permitted.paths = /vendor/${LIB}:/data + +namespace.rs.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/data/asan/vendor/${LIB}:/vendor/${LIB} +namespace.rs.asan.permitted.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}:/data + +namespace.rs.links = default,vndk +namespace.rs.link.default.shared_libs = libc.so:libz.so:libm.so:libdl.so:libstdc++.so:liblog.so:libnativewindow.so:libEGL.so:libsync.so:libGLESv1_CM.so:libGLESv2.so:libmediandk.so:libui.so:libvndksupport.so +namespace.rs.link.vndk.shared_libs = android.hardware.renderscript@1.0.so:android.hardware.graphics.allocator@2.0.so:android.hardware.graphics.mapper@2.0.so:android.hardware.graphics.common@1.0.so:android.hidl.memory@1.0.so:libhwbinder.so:libbase.so:libcutils.so:libhardware.so:libhidlbase.so:libhidlmemory.so:libhidltransport.so:libion.so:libutils.so:libc++.so + +############################################################################### +# "vndk" namespace +# +# This namespace is exclusively for vndk-sp libs. +############################################################################### +namespace.vndk.isolated = true +namespace.vndk.search.paths = /vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/vendor/${LIB} +namespace.vndk.permitted.paths = /vendor/${LIB}/hw:/vendor/${LIB}/egl + +namespace.vndk.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/data/asan/vendor/${LIB}:/vendor/${LIB} +namespace.vndk.asan.permitted.paths = /data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl + +# When these NDK libs are required inside this namespace, then it is redirected +# to the default namespace. This is possible since their ABI is stable across +# Android releases. +namespace.vndk.links = default +namespace.vndk.link.default.shared_libs = android.hidl.memory@1.0-impl.so:libc.so:libz.so:libm.so:libdl.so:libstdc++.so:liblog.so:libnativewindow.so:libEGL.so:libsync.so:libvndksupport.so + + +[vendor] +namespace.default.isolated = false +namespace.default.search.paths = /vendor/${LIB}:/vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/system/${LIB} +namespace.default.asan.search.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/data/asan/system/${LIB}:/system/${LIB} diff --git a/rootdir/etc/public.libraries.android.txt b/rootdir/etc/public.libraries.android.txt index e70ed51fa..c5e149c9c 100644 --- a/rootdir/etc/public.libraries.android.txt +++ b/rootdir/etc/public.libraries.android.txt @@ -1,5 +1,6 @@ # See https://android.googlesource.com/platform/ndk/+/master/docs/PlatformApis.md libandroid.so +libaaudio.so libc.so libcamera2ndk.so libdl.so @@ -13,10 +14,12 @@ libjnigraphics.so liblog.so libmediandk.so libm.so +libnativewindow.so libOpenMAXAL.so libOpenSLES.so libRS.so libstdc++.so +libsync.so libvulkan.so libwebviewchromium_plat_support.so libz.so diff --git a/rootdir/etc/public.libraries.wear.txt b/rootdir/etc/public.libraries.wear.txt index e494ee08f..a4ca68318 100644 --- a/rootdir/etc/public.libraries.wear.txt +++ b/rootdir/etc/public.libraries.wear.txt @@ -1,5 +1,6 @@ # See https://android.googlesource.com/platform/ndk/+/master/docs/PlatformApis.md libandroid.so +libaaudio.so libc.so libcamera2ndk.so libdl.so @@ -13,9 +14,11 @@ libjnigraphics.so liblog.so libmediandk.so libm.so +libnativewindow.so libOpenMAXAL.so libOpenSLES.so libRS.so libstdc++.so +libsync.so libvulkan.so libz.so diff --git a/rootdir/init.rc b/rootdir/init.rc index 7644d28d7..4c2eb528c 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -302,14 +302,17 @@ on post-fs load_system_props # start essential services start logd + start servicemanager start hwservicemanager + start vndservicemanager # once everything is setup, no need to modify / mount rootfs rootfs / ro remount # 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 @@ -676,12 +679,6 @@ on property:vold.decrypt=trigger_shutdown_framework on property:sys.boot_completed=1 bootchart stop -on property:sys.boot_completed=1 && property:ro.build.type=user - write /proc/sys/kernel/modules_disabled 1 - -on property:sys.boot_completed=1 && property:ro.build.type=userdebug - write /proc/sys/kernel/modules_disabled 1 - # system server cannot write to /proc/sys files, # and chown/chmod does not work for /proc/sys/ entries. # So proxy writes through init. @@ -710,10 +707,9 @@ service ueventd /sbin/ueventd seclabel u:r:ueventd:s0 shutdown critical -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/rootdir/ueventd.rc b/rootdir/ueventd.rc index efd0da5d5..eadf219b5 100644 --- a/rootdir/ueventd.rc +++ b/rootdir/ueventd.rc @@ -52,6 +52,7 @@ subsystem sound /dev/ashmem 0666 root root /dev/binder 0666 root root /dev/hwbinder 0666 root root +/dev/vndbinder 0666 root root /dev/pmsg0 0222 root log 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/sdcard/sdcard.cpp b/sdcard/sdcard.cpp index df3ce853c..c342cf811 100644 --- a/sdcard/sdcard.cpp +++ b/sdcard/sdcard.cpp @@ -420,7 +420,7 @@ static bool should_use_sdcardfs(void) { } // Fall back to device opinion about state - if (property_get_bool(PROP_SDCARDFS_DEVICE, false)) { + if (property_get_bool(PROP_SDCARDFS_DEVICE, true)) { LOG(WARNING) << "Device explicitly enabled sdcardfs"; return supports_sdcardfs(); } else { diff --git a/storaged/Android.mk b/storaged/Android.mk new file mode 100644 index 000000000..5e6a3c0a1 --- /dev/null +++ b/storaged/Android.mk @@ -0,0 +1,45 @@ +# 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_info.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..2d8397fc8 --- /dev/null +++ b/storaged/README.properties @@ -0,0 +1,5 @@ +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.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..514798bff --- /dev/null +++ b/storaged/include/storaged.h @@ -0,0 +1,296 @@ +/* + * 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 <batteryservice/IBatteryPropertiesRegistrar.h> + +#include "storaged_info.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 ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +#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 +}; + + + +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); +}; + +// 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_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_uid_io; + bool proc_uid_io_available; // whether uid_io is accessible + 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, + public IBinder::DeathRecipient { +private: + time_t mTimer; + storaged_config mConfig; + disk_stats_publisher mDiskStats; + disk_stats_monitor mDsm; + uid_monitor mUidm; + time_t mStarttime; + sp<IBatteryPropertiesRegistrar> battery_properties; +public: + storaged_t(void); + ~storaged_t() {} + void event(void); + void event_checked(void); + void pause(void) { + sleep(mConfig.periodic_chores_interval_unit); + } + + 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, struct uid_records> 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); + void binderDied(const wp<IBinder>& who); +}; + +// 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_info.h b/storaged/include/storaged_info.h new file mode 100644 index 000000000..913c814ac --- /dev/null +++ b/storaged/include/storaged_info.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _STORAGED_INFO_H_ +#define _STORAGED_INFO_H_ + +#include <string.h> + +#define FRIEND_TEST(test_case_name, test_name) \ +friend class test_case_name##_##test_name##_Test + +using namespace std; + +class storage_info_t { +protected: + FRIEND_TEST(storaged_test, storage_info_t); + uint16_t eol; // pre-eol (end of life) information + uint16_t lifetime_a; // device life time estimation (type A) + uint16_t lifetime_b; // device life time estimation (type B) + string version; // version string + void publish(); +public: + storage_info_t() : eol(0), lifetime_a(0), lifetime_b(0) {} + virtual ~storage_info_t() {} + virtual bool report() = 0; +}; + +class emmc_info_t : public storage_info_t { +private: + const string emmc_sysfs = "/sys/bus/mmc/devices/mmc0:0001/"; + const string emmc_debugfs = "/d/mmc0/mmc0:0001/ext_csd"; + const char* emmc_ver_str[9] = { + "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0", "5.1" + }; +public: + virtual ~emmc_info_t() {} + bool report(); + bool report_sysfs(); + bool report_debugfs(); +}; + +class ufs_info_t : public storage_info_t { +private: + const string health_file = "/sys/devices/soc/624000.ufshc/health"; +public: + virtual ~ufs_info_t() {} + bool report(); +}; + +void report_storage_health(); + +#endif /* _STORAGED_INFO_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..901a8721b --- /dev/null +++ b/storaged/include/storaged_uid_monitor.h @@ -0,0 +1,110 @@ +/* + * 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) + uint64_t fsync; // number of fsync syscalls +}; + +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; +}; + +struct uid_records { + uint64_t start_ts; + std::vector<struct uid_record> entries; +}; + +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, end timestamp -> {start timestamp, vector of records} + std::map<uint64_t, struct uid_records> 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; + // start time for IO records + uint64_t start_ts; + + // 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, struct uid_records> 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..4d1e43014 --- /dev/null +++ b/storaged/main.cpp @@ -0,0 +1,153 @@ +/* + * 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> + +sp<storaged_t> storaged; + +// Function of storaged's main thread +void* storaged_main(void* /* unused */) { + storaged = new storaged_t(); + + 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 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 + report_storage_health(); + // Start the main thread of storaged + pthread_t storaged_main_thread; + errno = pthread_create(&storaged_main_thread, NULL, storaged_main, NULL); + 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); + + 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..54d429cd8 --- /dev/null +++ b/storaged/storaged.cpp @@ -0,0 +1,276 @@ +/* + * 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/IPCThreadState.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); + } +} + +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() { + if (!mConfig.proc_uid_io_available) + return; + + 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); + IInterface::asBinder(battery_properties)->linkToDeath(this); +} + +void storaged_t::binderDied(const wp<IBinder>& who) { + if (battery_properties != NULL && + IInterface::asBinder(battery_properties) == who) { + LOG_TO(SYSTEM, ERROR) << "batteryproperties service died, exiting"; + IPCThreadState::self()->stopProcess(); + exit(1); + } else { + LOG_TO(SYSTEM, ERROR) << "unknown service died"; + } +} + +/* storaged_t */ +storaged_t::storaged_t(void) { + 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_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.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..a24c7fba8 --- /dev/null +++ b/storaged/storaged.rc @@ -0,0 +1,7 @@ +service storaged /system/bin/storaged + class main + priority 10 + file /d/mmc0/mmc0:0001/ext_csd r + writepid /dev/cpuset/system-background/tasks + user root + group package_info
\ No newline at end of file diff --git a/storaged/storaged_info.cpp b/storaged/storaged_info.cpp new file mode 100644 index 000000000..434bd74ae --- /dev/null +++ b/storaged/storaged_info.cpp @@ -0,0 +1,184 @@ +/* + * 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 <stdio.h> +#include <string.h> + +#include <android-base/file.h> +#include <android-base/parseint.h> +#include <android-base/logging.h> +#include <android-base/strings.h> +#include <log/log_event_list.h> + +#include "storaged.h" + +using namespace std; +using namespace android::base; + +void report_storage_health() +{ + emmc_info_t mmc; + ufs_info_t ufs; + + mmc.report(); + ufs.report(); +} + +void storage_info_t::publish() +{ + android_log_event_list(EVENTLOGTAG_EMMCINFO) + << version << eol << lifetime_a << lifetime_b + << LOG_ID_EVENTS; +} + +bool emmc_info_t::report() +{ + if (!report_sysfs() && !report_debugfs()) + return false; + + publish(); + return true; +} + +bool emmc_info_t::report_sysfs() +{ + string buffer; + uint16_t rev = 0; + + if (!ReadFileToString(emmc_sysfs + "rev", &buffer)) { + return false; + } + + if (sscanf(buffer.c_str(), "0x%hx", &rev) < 1 || + rev < 7 || rev > ARRAY_SIZE(emmc_ver_str)) { + return false; + } + + version = "emmc "; + version += emmc_ver_str[rev]; + + if (!ReadFileToString(emmc_sysfs + "pre_eol_info", &buffer)) { + return false; + } + + if (sscanf(buffer.c_str(), "%hx", &eol) < 1 || eol == 0) { + return false; + } + + if (!ReadFileToString(emmc_sysfs + "life_time", &buffer)) { + return false; + } + + if (sscanf(buffer.c_str(), "0x%hx 0x%hx", &lifetime_a, &lifetime_b) < 2 || + (lifetime_a == 0 && lifetime_b == 0)) { + return false; + } + + return true; +} + +const size_t EXT_CSD_FILE_MIN_SIZE = 1024; +/* 2 characters in string for each byte */ +const size_t EXT_CSD_REV_IDX = 192 * 2; +const size_t EXT_PRE_EOL_INFO_IDX = 267 * 2; +const size_t EXT_DEVICE_LIFE_TIME_EST_A_IDX = 268 * 2; +const size_t EXT_DEVICE_LIFE_TIME_EST_B_IDX = 269 * 2; + +bool emmc_info_t::report_debugfs() +{ + string buffer; + uint16_t rev = 0; + + if (!ReadFileToString(emmc_debugfs, &buffer) || + buffer.length() < (size_t)EXT_CSD_FILE_MIN_SIZE) { + return false; + } + + string str = buffer.substr(EXT_CSD_REV_IDX, 2); + if (!ParseUint(str, &rev) || + rev < 7 || rev > ARRAY_SIZE(emmc_ver_str)) { + return false; + } + + version = "emmc "; + version += emmc_ver_str[rev]; + + str = buffer.substr(EXT_PRE_EOL_INFO_IDX, 2); + if (!ParseUint(str, &eol)) { + return false; + } + + str = buffer.substr(EXT_DEVICE_LIFE_TIME_EST_A_IDX, 2); + if (!ParseUint(str, &lifetime_a)) { + return false; + } + + str = buffer.substr(EXT_DEVICE_LIFE_TIME_EST_B_IDX, 2); + if (!ParseUint(str, &lifetime_b)) { + return false; + } + + return true; +} + +bool ufs_info_t::report() +{ + string buffer; + if (!ReadFileToString(health_file, &buffer)) { + return false; + } + + vector<string> lines = Split(buffer, "\n"); + if (lines.empty()) { + return false; + } + + char rev[8]; + if (sscanf(lines[0].c_str(), "ufs version: 0x%7s\n", rev) < 1) { + return false; + } + + version = "ufs " + string(rev); + + for (size_t i = 1; i < lines.size(); i++) { + char token[32]; + uint16_t val; + int ret; + if ((ret = sscanf(lines[i].c_str(), + "Health Descriptor[Byte offset 0x%*d]: %31s = 0x%hx", + token, &val)) < 2) { + continue; + } + + if (string(token) == "bPreEOLInfo") { + eol = val; + } else if (string(token) == "bDeviceLifeTimeEstA") { + lifetime_a = val; + } else if (string(token) == "bDeviceLifeTimeEstB") { + lifetime_b = val; + } + } + + if (eol == 0 || (lifetime_a == 0 && lifetime_b == 0)) { + return false; + } + + publish(); + return true; +} + diff --git a/storaged/storaged_service.cpp b/storaged/storaged_service.cpp new file mode 100644 index 000000000..b1d3bfd24 --- /dev/null +++ b/storaged/storaged_service.cpp @@ -0,0 +1,169 @@ +/* + * 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 <android-base/parseint.h> +#include <android-base/parsedouble.h> +#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> + +using namespace android::base; + +extern sp<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; + if(!ParseDouble(String8(args[i]).c_str(), &hours)) + return BAD_VALUE; + continue; + } + if (arg == String16("--time_window")) { + if (++i >= args.size()) + break; + if(!ParseInt(String8(args[i]).c_str(), &time_window)) + return BAD_VALUE; + continue; + } + if (arg == String16("--threshold")) { + if (++i >= args.size()) + break; + if(!ParseUint(String8(args[i]).c_str(), &threshold)) + return BAD_VALUE; + continue; + } + if (arg == String16("--force")) { + force_report = true; + continue; + } + } + + uint64_t last_ts = 0; + const std::map<uint64_t, struct uid_records>& records = + storaged->get_uid_records(hours, threshold, force_report); + for (const auto& it : records) { + if (last_ts != it.second.start_ts) { + dprintf(fd, "%llu", (unsigned long long)it.second.start_ts); + } + dprintf(fd, ",%llu\n", (unsigned long long)it.first); + last_ts = it.first; + + for (const auto& record : it.second.entries) { + dprintf(fd, "%s %ju %ju %ju %ju %ju %ju %ju %ju\n", + record.name.c_str(), + record.ios.bytes[READ][FOREGROUND][CHARGER_OFF], + record.ios.bytes[WRITE][FOREGROUND][CHARGER_OFF], + record.ios.bytes[READ][BACKGROUND][CHARGER_OFF], + record.ios.bytes[WRITE][BACKGROUND][CHARGER_OFF], + record.ios.bytes[READ][FOREGROUND][CHARGER_ON], + record.ios.bytes[WRITE][FOREGROUND][CHARGER_ON], + record.ios.bytes[READ][BACKGROUND][CHARGER_ON], + 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..5bb98e1e8 --- /dev/null +++ b/storaged/storaged_uid_monitor.cpp @@ -0,0 +1,278 @@ +/* + * 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 <unordered_map> + +#include <android-base/file.h> +#include <android-base/logging.h> +#include <android-base/macros.h> +#include <android-base/parseint.h> +#include <android-base/strings.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 (!ReadFileToString(UID_IO_STATS_PATH, &buffer)) { + PLOG_TO(SYSTEM, ERROR) << UID_IO_STATS_PATH << ": ReadFileToString failed"; + return uid_io_stats; + } + + std::vector<std::string> io_stats = Split(buffer, "\n"); + struct uid_info u; + bool refresh_uid = false; + + for (uint32_t i = 0; i < io_stats.size(); i++) { + if (io_stats[i].empty()) { + continue; + } + std::vector<std::string> fields = Split(io_stats[i], " "); + if (fields.size() < 11 || + !ParseUint(fields[0], &u.uid) || + !ParseUint(fields[1], &u.io[FOREGROUND].rchar) || + !ParseUint(fields[2], &u.io[FOREGROUND].wchar) || + !ParseUint(fields[3], &u.io[FOREGROUND].read_bytes) || + !ParseUint(fields[4], &u.io[FOREGROUND].write_bytes) || + !ParseUint(fields[5], &u.io[BACKGROUND].rchar) || + !ParseUint(fields[6], &u.io[BACKGROUND].wchar) || + !ParseUint(fields[7], &u.io[BACKGROUND].read_bytes) || + !ParseUint(fields[8], &u.io[BACKGROUND].write_bytes) || + !ParseUint(fields[9], &u.io[FOREGROUND].fsync) || + !ParseUint(fields[10], &u.io[BACKGROUND].fsync)) { + LOG_TO(SYSTEM, WARNING) << "Invalid I/O stats: \"" + << io_stats[i] << "\""; + continue; + } + + 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 (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, struct uid_records>& curr_records) +{ + int count = 0; + for (auto const& it : curr_records) { + count += it.second.entries.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); + } + + struct uid_records 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.entries.push_back(record); + } + } + + curr_io_stats.clear(); + new_records.start_ts = start_ts; + start_ts = curr_ts; + + if (new_records.entries.empty()) + return; + + // make some room for new records + int overflow = records_size(records) + + new_records.entries.size() - MAX_UID_RECORDS_SIZE; + while (overflow > 0 && records.size() > 0) { + auto del_it = records.begin(); + overflow -= del_it->second.entries.size(); + records.erase(records.begin()); + } + + records[curr_ts] = new_records; +} + +std::map<uint64_t, struct uid_records> 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, struct uid_records> 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.entries; + struct uid_records 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.entries.push_back(rec); + } + } + + if (filtered.entries.empty()) + continue; + + filtered.start_ts = it->second.start_ts; + dump_records.insert( + std::pair<uint64_t, struct uid_records>(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; + start_ts = time(NULL); + 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..74b743656 --- /dev/null +++ b/storaged/storaged_utils.cpp @@ -0,0 +1,232 @@ +/* + * 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; + } +} + +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) { + printf("name/uid fg_rchar fg_wchar fg_rbytes fg_wbytes " + "bg_rchar bg_wchar bg_rbytes bg_wbytes fg_fsync bg_fsync\n"); + + for (const auto& uid : uids) { + printf("%s %ju %ju %ju %ju %ju %ju %ju %ju %ju %ju\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, + uid.io[0].fsync, uid.io[1].fsync); + } + 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; +} + 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..b103ac1ec --- /dev/null +++ b/storaged/tests/storaged_test.cpp @@ -0,0 +1,351 @@ +/* + * 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" + +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; + memset(&stats, 0, sizeof(struct disk_stats)); + + 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)); + } +} + +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); + } +} + |