1 /* 2 ** 3 ** Copyright 2015, The Android Open Source Project 4 ** 5 ** Licensed under the Apache License, Version 2.0 (the "License"); 6 ** you may not use this file except in compliance with the License. 7 ** You may obtain a copy of the License at 8 ** 9 ** http://www.apache.org/licenses/LICENSE-2.0 10 ** 11 ** Unless required by applicable law or agreed to in writing, software 12 ** distributed under the License is distributed on an "AS IS" BASIS, 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 ** See the License for the specific language governing permissions and 15 ** limitations under the License. 16 */ 17 18 //#define LOG_NDEBUG 0 19 #define LOG_TAG "ResourceManagerService" 20 #include <utils/Log.h> 21 22 #include <binder/IServiceManager.h> 23 #include <dirent.h> 24 #include <media/stagefright/ProcessInfo.h> 25 #include <string.h> 26 #include <sys/types.h> 27 #include <sys/stat.h> 28 #include <sys/time.h> 29 #include <unistd.h> 30 31 #include "ResourceManagerService.h" 32 #include "ServiceLog.h" 33 34 namespace android { 35 36 template <typename T> 37 static String8 getString(const Vector<T> &items) { 38 String8 itemsStr; 39 for (size_t i = 0; i < items.size(); ++i) { 40 itemsStr.appendFormat("%s ", items[i].toString().string()); 41 } 42 return itemsStr; 43 } 44 45 static bool hasResourceType(String8 type, Vector<MediaResource> resources) { 46 for (size_t i = 0; i < resources.size(); ++i) { 47 if (resources[i].mType == type) { 48 return true; 49 } 50 } 51 return false; 52 } 53 54 static bool hasResourceType(String8 type, ResourceInfos infos) { 55 for (size_t i = 0; i < infos.size(); ++i) { 56 if (hasResourceType(type, infos[i].resources)) { 57 return true; 58 } 59 } 60 return false; 61 } 62 63 static ResourceInfos& getResourceInfosForEdit( 64 int pid, 65 PidResourceInfosMap& map) { 66 ssize_t index = map.indexOfKey(pid); 67 if (index < 0) { 68 // new pid 69 ResourceInfos infosForPid; 70 map.add(pid, infosForPid); 71 } 72 73 return map.editValueFor(pid); 74 } 75 76 static ResourceInfo& getResourceInfoForEdit( 77 int64_t clientId, 78 const sp<IResourceManagerClient> client, 79 ResourceInfos& infos) { 80 for (size_t i = 0; i < infos.size(); ++i) { 81 if (infos[i].clientId == clientId) { 82 return infos.editItemAt(i); 83 } 84 } 85 ResourceInfo info; 86 info.clientId = clientId; 87 info.client = client; 88 infos.push_back(info); 89 return infos.editItemAt(infos.size() - 1); 90 } 91 92 status_t ResourceManagerService::dump(int fd, const Vector<String16>& /* args */) { 93 Mutex::Autolock lock(mLock); 94 95 String8 result; 96 const size_t SIZE = 256; 97 char buffer[SIZE]; 98 99 snprintf(buffer, SIZE, "ResourceManagerService: %p\n", this); 100 result.append(buffer); 101 result.append(" Policies:\n"); 102 snprintf(buffer, SIZE, " SupportsMultipleSecureCodecs: %d\n", mSupportsMultipleSecureCodecs); 103 result.append(buffer); 104 snprintf(buffer, SIZE, " SupportsSecureWithNonSecureCodec: %d\n", mSupportsSecureWithNonSecureCodec); 105 result.append(buffer); 106 107 result.append(" Processes:\n"); 108 for (size_t i = 0; i < mMap.size(); ++i) { 109 snprintf(buffer, SIZE, " Pid: %d\n", mMap.keyAt(i)); 110 result.append(buffer); 111 112 const ResourceInfos &infos = mMap.valueAt(i); 113 for (size_t j = 0; j < infos.size(); ++j) { 114 result.append(" Client:\n"); 115 snprintf(buffer, SIZE, " Id: %lld\n", (long long)infos[j].clientId); 116 result.append(buffer); 117 118 snprintf(buffer, SIZE, " Name: %s\n", infos[j].client->getName().string()); 119 result.append(buffer); 120 121 Vector<MediaResource> resources = infos[j].resources; 122 result.append(" Resources:\n"); 123 for (size_t k = 0; k < resources.size(); ++k) { 124 snprintf(buffer, SIZE, " %s\n", resources[k].toString().string()); 125 result.append(buffer); 126 } 127 } 128 } 129 result.append(" Events logs (most recent at top):\n"); 130 result.append(mServiceLog->toString(" " /* linePrefix */)); 131 132 write(fd, result.string(), result.size()); 133 return OK; 134 } 135 136 ResourceManagerService::ResourceManagerService() 137 : mProcessInfo(new ProcessInfo()), 138 mServiceLog(new ServiceLog()), 139 mSupportsMultipleSecureCodecs(true), 140 mSupportsSecureWithNonSecureCodec(true) {} 141 142 ResourceManagerService::ResourceManagerService(sp<ProcessInfoInterface> processInfo) 143 : mProcessInfo(processInfo), 144 mServiceLog(new ServiceLog()), 145 mSupportsMultipleSecureCodecs(true), 146 mSupportsSecureWithNonSecureCodec(true) {} 147 148 ResourceManagerService::~ResourceManagerService() {} 149 150 void ResourceManagerService::config(const Vector<MediaResourcePolicy> &policies) { 151 String8 log = String8::format("config(%s)", getString(policies).string()); 152 mServiceLog->add(log); 153 154 Mutex::Autolock lock(mLock); 155 for (size_t i = 0; i < policies.size(); ++i) { 156 String8 type = policies[i].mType; 157 String8 value = policies[i].mValue; 158 if (type == kPolicySupportsMultipleSecureCodecs) { 159 mSupportsMultipleSecureCodecs = (value == "true"); 160 } else if (type == kPolicySupportsSecureWithNonSecureCodec) { 161 mSupportsSecureWithNonSecureCodec = (value == "true"); 162 } 163 } 164 } 165 166 void ResourceManagerService::addResource( 167 int pid, 168 int64_t clientId, 169 const sp<IResourceManagerClient> client, 170 const Vector<MediaResource> &resources) { 171 String8 log = String8::format("addResource(pid %d, clientId %lld, resources %s)", 172 pid, (long long) clientId, getString(resources).string()); 173 mServiceLog->add(log); 174 175 Mutex::Autolock lock(mLock); 176 ResourceInfos& infos = getResourceInfosForEdit(pid, mMap); 177 ResourceInfo& info = getResourceInfoForEdit(clientId, client, infos); 178 // TODO: do the merge instead of append. 179 info.resources.appendVector(resources); 180 } 181 182 void ResourceManagerService::removeResource(int pid, int64_t clientId) { 183 String8 log = String8::format( 184 "removeResource(pid %d, clientId %lld)", 185 pid, (long long) clientId); 186 mServiceLog->add(log); 187 188 Mutex::Autolock lock(mLock); 189 ssize_t index = mMap.indexOfKey(pid); 190 if (index < 0) { 191 ALOGV("removeResource: didn't find pid %d for clientId %lld", pid, (long long) clientId); 192 return; 193 } 194 bool found = false; 195 ResourceInfos &infos = mMap.editValueAt(index); 196 for (size_t j = 0; j < infos.size(); ++j) { 197 if (infos[j].clientId == clientId) { 198 j = infos.removeAt(j); 199 found = true; 200 break; 201 } 202 } 203 if (!found) { 204 ALOGV("didn't find client"); 205 } 206 } 207 208 void ResourceManagerService::getClientForResource_l( 209 int callingPid, const MediaResource *res, Vector<sp<IResourceManagerClient>> *clients) { 210 if (res == NULL) { 211 return; 212 } 213 sp<IResourceManagerClient> client; 214 if (getLowestPriorityBiggestClient_l(callingPid, res->mType, &client)) { 215 clients->push_back(client); 216 } 217 } 218 219 bool ResourceManagerService::reclaimResource( 220 int callingPid, const Vector<MediaResource> &resources) { 221 String8 log = String8::format("reclaimResource(callingPid %d, resources %s)", 222 callingPid, getString(resources).string()); 223 mServiceLog->add(log); 224 225 Vector<sp<IResourceManagerClient>> clients; 226 { 227 Mutex::Autolock lock(mLock); 228 const MediaResource *secureCodec = NULL; 229 const MediaResource *nonSecureCodec = NULL; 230 const MediaResource *graphicMemory = NULL; 231 for (size_t i = 0; i < resources.size(); ++i) { 232 String8 type = resources[i].mType; 233 if (resources[i].mType == kResourceSecureCodec) { 234 secureCodec = &resources[i]; 235 } else if (type == kResourceNonSecureCodec) { 236 nonSecureCodec = &resources[i]; 237 } else if (type == kResourceGraphicMemory) { 238 graphicMemory = &resources[i]; 239 } 240 } 241 242 // first pass to handle secure/non-secure codec conflict 243 if (secureCodec != NULL) { 244 if (!mSupportsMultipleSecureCodecs) { 245 if (!getAllClients_l(callingPid, String8(kResourceSecureCodec), &clients)) { 246 return false; 247 } 248 } 249 if (!mSupportsSecureWithNonSecureCodec) { 250 if (!getAllClients_l(callingPid, String8(kResourceNonSecureCodec), &clients)) { 251 return false; 252 } 253 } 254 } 255 if (nonSecureCodec != NULL) { 256 if (!mSupportsSecureWithNonSecureCodec) { 257 if (!getAllClients_l(callingPid, String8(kResourceSecureCodec), &clients)) { 258 return false; 259 } 260 } 261 } 262 263 if (clients.size() == 0) { 264 // if no secure/non-secure codec conflict, run second pass to handle other resources. 265 getClientForResource_l(callingPid, graphicMemory, &clients); 266 } 267 268 if (clients.size() == 0) { 269 // if we are here, run the third pass to free one codec with the same type. 270 getClientForResource_l(callingPid, secureCodec, &clients); 271 getClientForResource_l(callingPid, nonSecureCodec, &clients); 272 } 273 274 if (clients.size() == 0) { 275 // if we are here, run the fourth pass to free one codec with the different type. 276 if (secureCodec != NULL) { 277 MediaResource temp(String8(kResourceNonSecureCodec), 1); 278 getClientForResource_l(callingPid, &temp, &clients); 279 } 280 if (nonSecureCodec != NULL) { 281 MediaResource temp(String8(kResourceSecureCodec), 1); 282 getClientForResource_l(callingPid, &temp, &clients); 283 } 284 } 285 } 286 287 if (clients.size() == 0) { 288 return false; 289 } 290 291 sp<IResourceManagerClient> failedClient; 292 for (size_t i = 0; i < clients.size(); ++i) { 293 log = String8::format("reclaimResource from client %p", clients[i].get()); 294 mServiceLog->add(log); 295 if (!clients[i]->reclaimResource()) { 296 failedClient = clients[i]; 297 break; 298 } 299 } 300 301 { 302 Mutex::Autolock lock(mLock); 303 bool found = false; 304 for (size_t i = 0; i < mMap.size(); ++i) { 305 ResourceInfos &infos = mMap.editValueAt(i); 306 for (size_t j = 0; j < infos.size();) { 307 if (infos[j].client == failedClient) { 308 j = infos.removeAt(j); 309 found = true; 310 } else { 311 ++j; 312 } 313 } 314 if (found) { 315 break; 316 } 317 } 318 if (!found) { 319 ALOGV("didn't find failed client"); 320 } 321 } 322 323 return (failedClient == NULL); 324 } 325 326 bool ResourceManagerService::getAllClients_l( 327 int callingPid, const String8 &type, Vector<sp<IResourceManagerClient>> *clients) { 328 Vector<sp<IResourceManagerClient>> temp; 329 for (size_t i = 0; i < mMap.size(); ++i) { 330 ResourceInfos &infos = mMap.editValueAt(i); 331 for (size_t j = 0; j < infos.size(); ++j) { 332 if (hasResourceType(type, infos[j].resources)) { 333 if (!isCallingPriorityHigher_l(callingPid, mMap.keyAt(i))) { 334 // some higher/equal priority process owns the resource, 335 // this request can't be fulfilled. 336 ALOGE("getAllClients_l: can't reclaim resource %s from pid %d", 337 type.string(), mMap.keyAt(i)); 338 return false; 339 } 340 temp.push_back(infos[j].client); 341 } 342 } 343 } 344 if (temp.size() == 0) { 345 ALOGV("getAllClients_l: didn't find any resource %s", type.string()); 346 return true; 347 } 348 clients->appendVector(temp); 349 return true; 350 } 351 352 bool ResourceManagerService::getLowestPriorityBiggestClient_l( 353 int callingPid, const String8 &type, sp<IResourceManagerClient> *client) { 354 int lowestPriorityPid; 355 int lowestPriority; 356 int callingPriority; 357 if (!mProcessInfo->getPriority(callingPid, &callingPriority)) { 358 ALOGE("getLowestPriorityBiggestClient_l: can't get process priority for pid %d", 359 callingPid); 360 return false; 361 } 362 if (!getLowestPriorityPid_l(type, &lowestPriorityPid, &lowestPriority)) { 363 return false; 364 } 365 if (lowestPriority <= callingPriority) { 366 ALOGE("getLowestPriorityBiggestClient_l: lowest priority %d vs caller priority %d", 367 lowestPriority, callingPriority); 368 return false; 369 } 370 371 if (!getBiggestClient_l(lowestPriorityPid, type, client)) { 372 return false; 373 } 374 return true; 375 } 376 377 bool ResourceManagerService::getLowestPriorityPid_l( 378 const String8 &type, int *lowestPriorityPid, int *lowestPriority) { 379 int pid = -1; 380 int priority = -1; 381 for (size_t i = 0; i < mMap.size(); ++i) { 382 if (mMap.valueAt(i).size() == 0) { 383 // no client on this process. 384 continue; 385 } 386 if (!hasResourceType(type, mMap.valueAt(i))) { 387 // doesn't have the requested resource type 388 continue; 389 } 390 int tempPid = mMap.keyAt(i); 391 int tempPriority; 392 if (!mProcessInfo->getPriority(tempPid, &tempPriority)) { 393 ALOGV("getLowestPriorityPid_l: can't get priority of pid %d, skipped", tempPid); 394 // TODO: remove this pid from mMap? 395 continue; 396 } 397 if (pid == -1 || tempPriority > priority) { 398 // initial the value 399 pid = tempPid; 400 priority = tempPriority; 401 } 402 } 403 if (pid != -1) { 404 *lowestPriorityPid = pid; 405 *lowestPriority = priority; 406 } 407 return (pid != -1); 408 } 409 410 bool ResourceManagerService::isCallingPriorityHigher_l(int callingPid, int pid) { 411 int callingPidPriority; 412 if (!mProcessInfo->getPriority(callingPid, &callingPidPriority)) { 413 return false; 414 } 415 416 int priority; 417 if (!mProcessInfo->getPriority(pid, &priority)) { 418 return false; 419 } 420 421 return (callingPidPriority < priority); 422 } 423 424 bool ResourceManagerService::getBiggestClient_l( 425 int pid, const String8 &type, sp<IResourceManagerClient> *client) { 426 ssize_t index = mMap.indexOfKey(pid); 427 if (index < 0) { 428 ALOGE("getBiggestClient_l: can't find resource info for pid %d", pid); 429 return false; 430 } 431 432 sp<IResourceManagerClient> clientTemp; 433 uint64_t largestValue = 0; 434 const ResourceInfos &infos = mMap.valueAt(index); 435 for (size_t i = 0; i < infos.size(); ++i) { 436 Vector<MediaResource> resources = infos[i].resources; 437 for (size_t j = 0; j < resources.size(); ++j) { 438 if (resources[j].mType == type) { 439 if (resources[j].mValue > largestValue) { 440 largestValue = resources[j].mValue; 441 clientTemp = infos[i].client; 442 } 443 } 444 } 445 } 446 447 if (clientTemp == NULL) { 448 ALOGE("getBiggestClient_l: can't find resource type %s for pid %d", type.string(), pid); 449 return false; 450 } 451 452 *client = clientTemp; 453 return true; 454 } 455 456 } // namespace android 457