| /* |
| * Copyright (C) 2019 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_NDEBUG 0 |
| #define LOG_TAG "ECOService" |
| |
| #include "eco/ECOService.h" |
| |
| #include <cutils/atomic.h> |
| #include <inttypes.h> |
| #include <pthread.h> |
| #include <stdio.h> |
| #include <sys/types.h> |
| |
| #include <algorithm> |
| #include <climits> |
| #include <cstring> |
| #include <ctime> |
| #include <string> |
| |
| #include "eco/ECODebug.h" |
| |
| namespace android { |
| namespace media { |
| namespace eco { |
| |
| ECOService::ECOService() : BnECOService() { |
| ALOGD("ECOService created"); |
| updateLogLevel(); |
| } |
| |
| /*virtual*/ ::ndk::ScopedAStatus ECOService::obtainSession( |
| int32_t width, int32_t height, bool isCameraRecording, |
| std::shared_ptr<::android::media::eco::IECOSession>* _aidl_return) { |
| ECOLOGI("ECOService::obtainSession w: %d, h: %d, isCameraRecording: %d", width, height, |
| isCameraRecording); |
| |
| bool disable = property_get_bool(kDisableEcoServiceProperty, false); |
| if (disable) { |
| ECOLOGE("ECOService:: Failed to obtainSession as ECOService is disable"); |
| return STATUS_ERROR(ERROR_UNSUPPORTED, "ECOService is disable"); |
| } |
| |
| if (width <= 0) { |
| return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "Width can not be <= 0"); |
| } |
| |
| if (height <= 0) { |
| return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "Height can not be <= 0"); |
| } |
| |
| SessionConfig newCfg(width, height, isCameraRecording); |
| |
| ECOLOGD("session count before is %zu", mSessionConfigToSessionMap.size()); |
| |
| Mutex::Autolock lock(mServiceLock); |
| bool foundSession = false; |
| // Instead of looking up the map directly, take the chance to scan the map and evict all the |
| // invalid sessions. |
| SanitizeSession([&](MapIterType iter) { |
| if (iter->first == newCfg) { |
| std::shared_ptr<ECOSession> session = iter->second.lock(); |
| if (session != nullptr) { |
| foundSession = true; |
| *_aidl_return = session; |
| } |
| } |
| }); |
| |
| if (foundSession) { |
| return ndk::ScopedAStatus::ok(); |
| } |
| |
| // Create a new session and add it to the record. |
| std::shared_ptr<ECOSession> newSession = |
| ECOSession::createECOSession(width, height, isCameraRecording); |
| if (newSession == nullptr) { |
| ECOLOGE("ECOService failed to create ECOSession w: %d, h: %d, isCameraRecording: %d", width, |
| height, isCameraRecording); |
| return STATUS_ERROR(ERROR_UNSUPPORTED, "Failed to create eco session"); |
| } |
| *_aidl_return = newSession; |
| // Insert the new session into the map. |
| mSessionConfigToSessionMap[newCfg] = newSession; |
| ECOLOGD("session count after is %zu", mSessionConfigToSessionMap.size()); |
| |
| return ndk::ScopedAStatus::ok(); |
| } |
| |
| /*virtual*/ ::ndk::ScopedAStatus ECOService::getNumOfSessions(int32_t* _aidl_return) { |
| Mutex::Autolock lock(mServiceLock); |
| SanitizeSession(std::function<void(MapIterType it)>()); // empty callback |
| *_aidl_return = mSessionConfigToSessionMap.size(); |
| return ndk::ScopedAStatus::ok(); |
| } |
| |
| /*virtual*/ ::ndk::ScopedAStatus ECOService::getSessions( |
| std::vector<::ndk::SpAIBinder>* _aidl_return) { |
| // Clear all the entries in the vector. |
| _aidl_return->clear(); |
| |
| Mutex::Autolock lock(mServiceLock); |
| SanitizeSession([&](MapIterType iter) { |
| std::shared_ptr<ECOSession> session = iter->second.lock(); |
| if (session != nullptr) { |
| _aidl_return->push_back(session->asBinder()); |
| } |
| }); |
| return ndk::ScopedAStatus::ok(); |
| } |
| |
| inline bool isEmptySession(const std::weak_ptr<ECOSession>& entry) { |
| std::shared_ptr<ECOSession> session = entry.lock(); |
| return session == nullptr; |
| } |
| |
| void ECOService::SanitizeSession( |
| const std::function<void(std::unordered_map<SessionConfig, std::weak_ptr<ECOSession>, |
| SessionConfigHash>::iterator it)>& callback) { |
| for (auto it = mSessionConfigToSessionMap.begin(), end = mSessionConfigToSessionMap.end(); |
| it != end;) { |
| if (isEmptySession(it->second)) { |
| it = mSessionConfigToSessionMap.erase(it); |
| } else { |
| if (callback != nullptr) { |
| callback(it); |
| }; |
| it++; |
| } |
| } |
| } |
| |
| /*virtual*/ void ECOService::binderDied(const std::weak_ptr<AIBinder>& /*who*/) {} |
| |
| status_t ECOService::dump(int fd, const std::vector<std::string>& args) { |
| Mutex::Autolock lock(mServiceLock); |
| dprintf(fd, "\n== ECO Service info: ==\n\n"); |
| dprintf(fd, "Number of ECOServices: %zu\n", mSessionConfigToSessionMap.size()); |
| for (auto it = mSessionConfigToSessionMap.begin(), end = mSessionConfigToSessionMap.end(); |
| it != end; it++) { |
| std::shared_ptr<ECOSession> session = std::shared_ptr<ECOSession>(it->second); |
| if (session != nullptr) { |
| session->dump(fd, args); |
| } |
| } |
| |
| return NO_ERROR; |
| } |
| |
| } // namespace eco |
| } // namespace media |
| } // namespace android |