/* * Copyright (C) 2022 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. */ // LOG_TAG defined via build flag. #ifndef LOG_TAG #define LOG_TAG "AidlSensorManager" #endif #include "DirectReportChannel.h" #include "EventQueue.h" #include "SensorManagerAidl.h" #include "utils.h" #include #include #include #include namespace android { namespace frameworks { namespace sensorservice { namespace implementation { using ::aidl::android::frameworks::sensorservice::IDirectReportChannel; using ::aidl::android::frameworks::sensorservice::IEventQueue; using ::aidl::android::frameworks::sensorservice::IEventQueueCallback; using ::aidl::android::frameworks::sensorservice::ISensorManager; using ::aidl::android::hardware::common::Ashmem; using ::aidl::android::hardware::sensors::ISensors; using ::aidl::android::hardware::sensors::SensorInfo; using ::aidl::android::hardware::sensors::SensorType; using ::android::frameworks::sensorservice::implementation::SensorManagerAidl; static const char* POLL_THREAD_NAME = "aidl_ssvc_poll"; SensorManagerAidl::SensorManagerAidl(JavaVM* vm) : mLooper(new Looper(false)), mStopThread(true), mJavaVm(vm) {} SensorManagerAidl::~SensorManagerAidl() { // Stops pollAll inside the thread. std::lock_guard lock(mThreadMutex); mStopThread = true; if (mLooper != nullptr) { mLooper->wake(); } if (mPollThread.joinable()) { mPollThread.join(); } ::android::SensorManager::removeInstanceForPackage( String16(ISensorManager::descriptor)); } ndk::ScopedAStatus createDirectChannel(::android::SensorManager& manager, size_t size, int type, const native_handle_t* handle, std::shared_ptr* chan) { int channelId = manager.createDirectChannel(size, type, handle); if (channelId < 0) { return convertResult(channelId); } if (channelId == 0) { return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_UNKNOWN_ERROR); } *chan = ndk::SharedRefBase::make(manager, channelId); return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus SensorManagerAidl::createAshmemDirectChannel( const Ashmem& in_mem, int64_t in_size, std::shared_ptr* _aidl_return) { if (in_size > in_mem.size || in_size < ISensors::DIRECT_REPORT_SENSOR_EVENT_TOTAL_LENGTH) { return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_BAD_VALUE); } native_handle_t* handle = native_handle_create(1, 0); handle->data[0] = dup(in_mem.fd.get()); auto status = createDirectChannel(getInternalManager(), in_size, SENSOR_DIRECT_MEM_TYPE_ASHMEM, handle, _aidl_return); int result = native_handle_close(handle); CHECK(result == 0) << "Failed to close the native_handle_t: " << result; result = native_handle_delete(handle); CHECK(result == 0) << "Failed to delete the native_handle_t: " << result; return status; } ndk::ScopedAStatus SensorManagerAidl::createGrallocDirectChannel( const ndk::ScopedFileDescriptor& in_mem, int64_t in_size, std::shared_ptr* _aidl_return) { native_handle_t* handle = native_handle_create(1, 0); handle->data[0] = dup(in_mem.get()); auto status = createDirectChannel(getInternalManager(), in_size, SENSOR_DIRECT_MEM_TYPE_GRALLOC, handle, _aidl_return); int result = native_handle_close(handle); CHECK(result == 0) << "Failed to close the native_handle_t: " << result; result = native_handle_delete(handle); CHECK(result == 0) << "Failed to delete the native_handle_t: " << result; return status; } ndk::ScopedAStatus SensorManagerAidl::createEventQueue( const std::shared_ptr& in_callback, std::shared_ptr* _aidl_return) { if (in_callback == nullptr) { return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_BAD_VALUE); } sp<::android::Looper> looper = getLooper(); if (looper == nullptr) { LOG(ERROR) << "::android::SensorManagerAidl::createEventQueue cannot initialize looper"; return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_UNKNOWN_ERROR); } String8 package(String8::format("aidl_client_pid_%d", AIBinder_getCallingPid())); sp<::android::SensorEventQueue> internalQueue = getInternalManager().createEventQueue(package); if (internalQueue == nullptr) { LOG(ERROR) << "::android::SensorManagerAidl::createEventQueue returns nullptr."; return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_UNKNOWN_ERROR); } *_aidl_return = ndk::SharedRefBase::make(in_callback, looper, internalQueue); return ndk::ScopedAStatus::ok(); } SensorInfo convertSensor(Sensor src) { SensorInfo dst; dst.sensorHandle = src.getHandle(); dst.name = src.getName(); dst.vendor = src.getVendor(); dst.version = src.getVersion(); dst.type = static_cast(src.getType()); dst.typeAsString = src.getStringType(); // maxRange uses maxValue because ::android::Sensor wraps the // internal sensor_t in this way. dst.maxRange = src.getMaxValue(); dst.resolution = src.getResolution(); dst.power = src.getPowerUsage(); dst.minDelayUs = src.getMinDelay(); dst.fifoReservedEventCount = src.getFifoReservedEventCount(); dst.fifoMaxEventCount = src.getFifoMaxEventCount(); dst.requiredPermission = src.getRequiredPermission(); dst.maxDelayUs = src.getMaxDelay(); dst.flags = src.getFlags(); return dst; } ndk::ScopedAStatus SensorManagerAidl::getDefaultSensor(SensorType in_type, SensorInfo* _aidl_return) { ::android::Sensor const* sensor = getInternalManager().getDefaultSensor(static_cast(in_type)); if (!sensor) { return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_NOT_EXIST); } *_aidl_return = convertSensor(*sensor); return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus SensorManagerAidl::getSensorList(std::vector* _aidl_return) { Sensor const* const* list; _aidl_return->clear(); ssize_t count = getInternalManager().getSensorList(&list); if (count < 0 || list == nullptr) { LOG(ERROR) << "SensorMAanger::getSensorList failed with count: " << count; return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_UNKNOWN_ERROR); } _aidl_return->reserve(static_cast(count)); for (ssize_t i = 0; i < count; ++i) { _aidl_return->push_back(convertSensor(*list[i])); } return ndk::ScopedAStatus::ok(); } ::android::SensorManager& SensorManagerAidl::getInternalManager() { int32_t version; ndk::ScopedAStatus status = getInterfaceVersion(&version); if (!status.isOk()) { LOG(ERROR) << "Failed to get interface version with error: " << status.getDescription(); version = -1; } String16 packageName = String16(ISensorManager::descriptor); packageName += String16("@") + String16(std::to_string(version).c_str()); return ::android::SensorManager::getInstanceForPackage(packageName); } /* One global looper for all event queues created from this SensorManager. */ sp SensorManagerAidl::getLooper() { std::lock_guard lock(mThreadMutex); if (!mJavaVm) { LOG(ERROR) << "No Java VM. This must be running in a test or fuzzer."; return mLooper; } if (!mPollThread.joinable()) { // if thread not initialized, start thread mStopThread = false; std::thread pollThread{[&stopThread = mStopThread, looper = mLooper, javaVm = mJavaVm] { struct sched_param p = {}; p.sched_priority = 10; if (sched_setscheduler(0 /* current thread*/, SCHED_FIFO, &p) != 0) { LOG(ERROR) << "Could not use SCHED_FIFO for looper thread: " << strerror(errno); } // set looper Looper::setForThread(looper); // Attach the thread to JavaVM so that pollAll do not crash if the thread // eventually calls into Java. JavaVMAttachArgs args{.version = JNI_VERSION_1_2, .name = POLL_THREAD_NAME, .group = nullptr}; JNIEnv* env; if (javaVm->AttachCurrentThread(&env, &args) != JNI_OK) { LOG(FATAL) << "Cannot attach SensorManager looper thread to Java VM."; } LOG(INFO) << POLL_THREAD_NAME << " started."; for (;;) { int pollResult = looper->pollAll(-1 /* timeout */); if (pollResult == Looper::POLL_WAKE) { if (stopThread == true) { LOG(INFO) << POLL_THREAD_NAME << ": requested to stop"; break; } else { LOG(INFO) << POLL_THREAD_NAME << ": spurious wake up, back to work"; } } else { LOG(ERROR) << POLL_THREAD_NAME << ": Looper::pollAll returns unexpected " << pollResult; break; } } if (javaVm->DetachCurrentThread() != JNI_OK) { LOG(ERROR) << "Cannot detach SensorManager looper thread from Java VM."; } LOG(INFO) << POLL_THREAD_NAME << " is terminated."; }}; mPollThread = std::move(pollThread); } return mLooper; } } // namespace implementation } // namespace sensorservice } // namespace frameworks } // namespace android