1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "ECOService"
19
20 #include "eco/ECOService.h"
21
22 #include <cutils/atomic.h>
23 #include <inttypes.h>
24 #include <pthread.h>
25 #include <stdio.h>
26 #include <sys/types.h>
27
28 #include <algorithm>
29 #include <climits>
30 #include <cstring>
31 #include <ctime>
32 #include <string>
33
34 #include "eco/ECODebug.h"
35
36 namespace android {
37 namespace media {
38 namespace eco {
39
ECOService()40 ECOService::ECOService() : BnECOService() {
41 ALOGD("ECOService created");
42 updateLogLevel();
43 }
44
obtainSession(int32_t width,int32_t height,bool isCameraRecording,std::shared_ptr<::android::media::eco::IECOSession> * _aidl_return)45 /*virtual*/ ::ndk::ScopedAStatus ECOService::obtainSession(
46 int32_t width, int32_t height, bool isCameraRecording,
47 std::shared_ptr<::android::media::eco::IECOSession>* _aidl_return) {
48 ECOLOGI("ECOService::obtainSession w: %d, h: %d, isCameraRecording: %d", width, height,
49 isCameraRecording);
50
51 bool disable = property_get_bool(kDisableEcoServiceProperty, false);
52 if (disable) {
53 ECOLOGE("ECOService:: Failed to obtainSession as ECOService is disable");
54 return STATUS_ERROR(ERROR_UNSUPPORTED, "ECOService is disable");
55 }
56
57 if (width <= 0) {
58 return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "Width can not be <= 0");
59 }
60
61 if (height <= 0) {
62 return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "Height can not be <= 0");
63 }
64
65 SessionConfig newCfg(width, height, isCameraRecording);
66
67 ECOLOGD("session count before is %zu", mSessionConfigToSessionMap.size());
68
69 Mutex::Autolock lock(mServiceLock);
70 bool foundSession = false;
71 // Instead of looking up the map directly, take the chance to scan the map and evict all the
72 // invalid sessions.
73 SanitizeSession([&](MapIterType iter) {
74 if (iter->first == newCfg) {
75 std::shared_ptr<ECOSession> session = iter->second.lock();
76 if (session != nullptr) {
77 foundSession = true;
78 *_aidl_return = session;
79 }
80 }
81 });
82
83 if (foundSession) {
84 return ndk::ScopedAStatus::ok();
85 }
86
87 // Create a new session and add it to the record.
88 std::shared_ptr<ECOSession> newSession =
89 ECOSession::createECOSession(width, height, isCameraRecording);
90 if (newSession == nullptr) {
91 ECOLOGE("ECOService failed to create ECOSession w: %d, h: %d, isCameraRecording: %d", width,
92 height, isCameraRecording);
93 return STATUS_ERROR(ERROR_UNSUPPORTED, "Failed to create eco session");
94 }
95 *_aidl_return = newSession;
96 // Insert the new session into the map.
97 mSessionConfigToSessionMap[newCfg] = newSession;
98 ECOLOGD("session count after is %zu", mSessionConfigToSessionMap.size());
99
100 return ndk::ScopedAStatus::ok();
101 }
102
getNumOfSessions(int32_t * _aidl_return)103 /*virtual*/ ::ndk::ScopedAStatus ECOService::getNumOfSessions(int32_t* _aidl_return) {
104 Mutex::Autolock lock(mServiceLock);
105 SanitizeSession(std::function<void(MapIterType it)>()); // empty callback
106 *_aidl_return = mSessionConfigToSessionMap.size();
107 return ndk::ScopedAStatus::ok();
108 }
109
getSessions(std::vector<::ndk::SpAIBinder> * _aidl_return)110 /*virtual*/ ::ndk::ScopedAStatus ECOService::getSessions(
111 std::vector<::ndk::SpAIBinder>* _aidl_return) {
112 // Clear all the entries in the vector.
113 _aidl_return->clear();
114
115 Mutex::Autolock lock(mServiceLock);
116 SanitizeSession([&](MapIterType iter) {
117 std::shared_ptr<ECOSession> session = iter->second.lock();
118 if (session != nullptr) {
119 _aidl_return->push_back(session->asBinder());
120 }
121 });
122 return ndk::ScopedAStatus::ok();
123 }
124
isEmptySession(const std::weak_ptr<ECOSession> & entry)125 inline bool isEmptySession(const std::weak_ptr<ECOSession>& entry) {
126 std::shared_ptr<ECOSession> session = entry.lock();
127 return session == nullptr;
128 }
129
SanitizeSession(const std::function<void (std::unordered_map<SessionConfig,std::weak_ptr<ECOSession>,SessionConfigHash>::iterator it)> & callback)130 void ECOService::SanitizeSession(
131 const std::function<void(std::unordered_map<SessionConfig, std::weak_ptr<ECOSession>,
132 SessionConfigHash>::iterator it)>& callback) {
133 for (auto it = mSessionConfigToSessionMap.begin(), end = mSessionConfigToSessionMap.end();
134 it != end;) {
135 if (isEmptySession(it->second)) {
136 it = mSessionConfigToSessionMap.erase(it);
137 } else {
138 if (callback != nullptr) {
139 callback(it);
140 };
141 it++;
142 }
143 }
144 }
145
binderDied(const std::weak_ptr<AIBinder> &)146 /*virtual*/ void ECOService::binderDied(const std::weak_ptr<AIBinder>& /*who*/) {}
147
dump(int fd,const std::vector<std::string> & args)148 status_t ECOService::dump(int fd, const std::vector<std::string>& args) {
149 Mutex::Autolock lock(mServiceLock);
150 dprintf(fd, "\n== ECO Service info: ==\n\n");
151 dprintf(fd, "Number of ECOServices: %zu\n", mSessionConfigToSessionMap.size());
152 for (auto it = mSessionConfigToSessionMap.begin(), end = mSessionConfigToSessionMap.end();
153 it != end; it++) {
154 std::shared_ptr<ECOSession> session = std::shared_ptr<ECOSession>(it->second);
155 if (session != nullptr) {
156 session->dump(fd, args);
157 }
158 }
159
160 return NO_ERROR;
161 }
162
163 } // namespace eco
164 } // namespace media
165 } // namespace android
166