Skip to content

Commit

Permalink
Add support for combining and remove individual resource
Browse files Browse the repository at this point in the history
- Fix ResourceManagerSerivce handling of adding same-type
resource in multiple calls, combine entries with the same
<type, subtype>. This is not required in existing usage,
bug could be required if we allow same type to be added
incrementally (eg. memory usage).

- Add api for removing some resources. Currently we can
add resources in multiple calls, but removeResource always
remove all resources of that client. We need this to toggle
battery stat On/Off based on actual usage of the codec.

- Add unit tests for the above.

bug: 138381810
test: ResourceManagerService_test; CTS ResourceManangerTest.

Change-Id: Icdba6c6b4c517755291668c52764169aac3071ea
  • Loading branch information
Chong Zhang committed Aug 20, 2019
1 parent 57eeeb0 commit fb092d3
Show file tree
Hide file tree
Showing 7 changed files with 254 additions and 82 deletions.
25 changes: 23 additions & 2 deletions media/libmedia/IResourceManagerService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ enum {
CONFIG = IBinder::FIRST_CALL_TRANSACTION,
ADD_RESOURCE,
REMOVE_RESOURCE,
REMOVE_CLIENT,
RECLAIM_RESOURCE,
};

Expand Down Expand Up @@ -87,15 +88,25 @@ class BpResourceManagerService : public BpInterface<IResourceManagerService>
remote()->transact(ADD_RESOURCE, data, &reply);
}

virtual void removeResource(int pid, int64_t clientId) {
virtual void removeResource(int pid, int64_t clientId, const Vector<MediaResource> &resources) {
Parcel data, reply;
data.writeInterfaceToken(IResourceManagerService::getInterfaceDescriptor());
data.writeInt32(pid);
data.writeInt64(clientId);
writeToParcel(&data, resources);

remote()->transact(REMOVE_RESOURCE, data, &reply);
}

virtual void removeClient(int pid, int64_t clientId) {
Parcel data, reply;
data.writeInterfaceToken(IResourceManagerService::getInterfaceDescriptor());
data.writeInt32(pid);
data.writeInt64(clientId);

remote()->transact(REMOVE_CLIENT, data, &reply);
}

virtual bool reclaimResource(int callingPid, const Vector<MediaResource> &resources) {
Parcel data, reply;
data.writeInterfaceToken(IResourceManagerService::getInterfaceDescriptor());
Expand Down Expand Up @@ -148,7 +159,17 @@ status_t BnResourceManagerService::onTransact(
CHECK_INTERFACE(IResourceManagerService, data, reply);
int pid = data.readInt32();
int64_t clientId = data.readInt64();
removeResource(pid, clientId);
Vector<MediaResource> resources;
readFromParcel(data, &resources);
removeResource(pid, clientId, resources);
return NO_ERROR;
} break;

case REMOVE_CLIENT: {
CHECK_INTERFACE(IResourceManagerService, data, reply);
int pid = data.readInt32();
int64_t clientId = data.readInt64();
removeClient(pid, clientId);
return NO_ERROR;
} break;

Expand Down
5 changes: 4 additions & 1 deletion media/libmedia/include/media/IResourceManagerService.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ class IResourceManagerService: public IInterface
const sp<IResourceManagerClient> client,
const Vector<MediaResource> &resources) = 0;

virtual void removeResource(int pid, int64_t clientId) = 0;
virtual void removeResource(int pid, int64_t clientId,
const Vector<MediaResource> &resources) = 0;

virtual void removeClient(int pid, int64_t clientId) = 0;

virtual bool reclaimResource(
int callingPid,
Expand Down
2 changes: 2 additions & 0 deletions media/libmedia/include/media/MediaResource.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ inline static const char *asString(MediaResource::Type i, const char *def = "??"
case MediaResource::kSecureCodec: return "secure-codec";
case MediaResource::kNonSecureCodec: return "non-secure-codec";
case MediaResource::kGraphicMemory: return "graphic-memory";
case MediaResource::kCpuBoost: return "cpu-boost";
case MediaResource::kBattery: return "battery";
default: return def;
}
}
Expand Down
2 changes: 1 addition & 1 deletion media/libstagefright/MediaCodec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ void MediaCodec::ResourceManagerServiceProxy::removeResource(int64_t clientId) {
if (mService == NULL) {
return;
}
mService->removeResource(mPid, clientId);
mService->removeClient(mPid, clientId);
}

bool MediaCodec::ResourceManagerServiceProxy::reclaimResource(
Expand Down
176 changes: 117 additions & 59 deletions services/mediaresourcemanager/ResourceManagerService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ static String8 getString(const Vector<T> &items) {
return itemsStr;
}

static bool hasResourceType(MediaResource::Type type, const Vector<MediaResource>& resources) {
for (size_t i = 0; i < resources.size(); ++i) {
if (resources[i].mType == type) {
static bool hasResourceType(MediaResource::Type type, const ResourceList& resources) {
for (auto it = resources.begin(); it != resources.end(); it++) {
if (it->second.mType == type) {
return true;
}
}
Expand Down Expand Up @@ -107,19 +107,18 @@ static ResourceInfo& getResourceInfoForEdit(
int64_t clientId,
const sp<IResourceManagerClient>& client,
ResourceInfos& infos) {
for (size_t i = 0; i < infos.size(); ++i) {
if (infos[i].clientId == clientId) {
return infos.editItemAt(i);
}
ssize_t index = infos.indexOfKey(clientId);

if (index < 0) {
ResourceInfo info;
info.uid = uid;
info.clientId = clientId;
info.client = client;

index = infos.add(clientId, info);
}
ResourceInfo info;
info.uid = uid;
info.clientId = clientId;
info.client = client;
info.cpuBoost = false;
info.batteryNoted = false;
infos.push_back(info);
return infos.editItemAt(infos.size() - 1);

return infos.editValueAt(index);
}

static void notifyResourceGranted(int pid, const Vector<MediaResource> &resources) {
Expand Down Expand Up @@ -186,10 +185,10 @@ status_t ResourceManagerService::dump(int fd, const Vector<String16>& /* args */
snprintf(buffer, SIZE, " Name: %s\n", infos[j].client->getName().string());
result.append(buffer);

Vector<MediaResource> resources = infos[j].resources;
const ResourceList &resources = infos[j].resources;
result.append(" Resources:\n");
for (size_t k = 0; k < resources.size(); ++k) {
snprintf(buffer, SIZE, " %s\n", resources[k].toString().string());
for (auto it = resources.begin(); it != resources.end(); it++) {
snprintf(buffer, SIZE, " %s\n", it->second.toString().string());
result.append(buffer);
}
}
Expand Down Expand Up @@ -231,6 +230,38 @@ void ResourceManagerService::config(const Vector<MediaResourcePolicy> &policies)
}
}

void ResourceManagerService::onFirstAdded(
const MediaResource& resource, const ResourceInfo& clientInfo) {
// first time added
if (resource.mType == MediaResource::kCpuBoost
&& resource.mSubType == MediaResource::kUnspecifiedSubType) {
// Request it on every new instance of kCpuBoost, as the media.codec
// could have died, if we only do it the first time subsequent instances
// never gets the boost.
if (requestCpusetBoost(true, this) != OK) {
ALOGW("couldn't request cpuset boost");
}
mCpuBoostCount++;
} else if (resource.mType == MediaResource::kBattery
&& resource.mSubType == MediaResource::kVideoCodec) {
BatteryNotifier::getInstance().noteStartVideo(clientInfo.uid);
}
}

void ResourceManagerService::onLastRemoved(
const MediaResource& resource, const ResourceInfo& clientInfo) {
if (resource.mType == MediaResource::kCpuBoost
&& resource.mSubType == MediaResource::kUnspecifiedSubType
&& mCpuBoostCount > 0) {
if (--mCpuBoostCount == 0) {
requestCpusetBoost(false, this);
}
} else if (resource.mType == MediaResource::kBattery
&& resource.mSubType == MediaResource::kVideoCodec) {
BatteryNotifier::getInstance().noteStopVideo(clientInfo.uid);
}
}

void ResourceManagerService::addResource(
int pid,
int uid,
Expand All @@ -248,24 +279,14 @@ void ResourceManagerService::addResource(
}
ResourceInfos& infos = getResourceInfosForEdit(pid, mMap);
ResourceInfo& info = getResourceInfoForEdit(uid, clientId, client, infos);
// TODO: do the merge instead of append.
info.resources.appendVector(resources);

for (size_t i = 0; i < resources.size(); ++i) {
if (resources[i].mType == MediaResource::kCpuBoost && !info.cpuBoost) {
info.cpuBoost = true;
// Request it on every new instance of kCpuBoost, as the media.codec
// could have died, if we only do it the first time subsequent instances
// never gets the boost.
if (requestCpusetBoost(true, this) != OK) {
ALOGW("couldn't request cpuset boost");
}
mCpuBoostCount++;
} else if (resources[i].mType == MediaResource::kBattery
&& resources[i].mSubType == MediaResource::kVideoCodec
&& !info.batteryNoted) {
info.batteryNoted = true;
BatteryNotifier::getInstance().noteStartVideo(info.uid);
const auto resType = std::make_pair(resources[i].mType, resources[i].mSubType);
if (info.resources.find(resType) == info.resources.end()) {
onFirstAdded(resources[i], info);
info.resources[resType] = resources[i];
} else {
info.resources[resType].mValue += resources[i].mValue;
}
}
if (info.deathNotifier == nullptr) {
Expand All @@ -275,7 +296,48 @@ void ResourceManagerService::addResource(
notifyResourceGranted(pid, resources);
}

void ResourceManagerService::removeResource(int pid, int64_t clientId) {
void ResourceManagerService::removeResource(int pid, int64_t clientId,
const Vector<MediaResource> &resources) {
String8 log = String8::format("removeResource(pid %d, clientId %lld, resources %s)",
pid, (long long) clientId, getString(resources).string());
mServiceLog->add(log);

Mutex::Autolock lock(mLock);
if (!mProcessInfo->isValidPid(pid)) {
ALOGE("Rejected removeResource call with invalid pid.");
return;
}
ssize_t index = mMap.indexOfKey(pid);
if (index < 0) {
ALOGV("removeResource: didn't find pid %d for clientId %lld", pid, (long long) clientId);
return;
}
ResourceInfos &infos = mMap.editValueAt(index);

index = infos.indexOfKey(clientId);
if (index < 0) {
ALOGV("removeResource: didn't find clientId %lld", (long long) clientId);
return;
}

ResourceInfo &info = infos.editValueAt(index);

for (size_t i = 0; i < resources.size(); ++i) {
const auto resType = std::make_pair(resources[i].mType, resources[i].mSubType);
// ignore if we don't have it
if (info.resources.find(resType) != info.resources.end()) {
MediaResource &resource = info.resources[resType];
if (resource.mValue > resources[i].mValue) {
resource.mValue -= resources[i].mValue;
} else {
onLastRemoved(resources[i], info);
info.resources.erase(resType);
}
}
}
}

void ResourceManagerService::removeClient(int pid, int64_t clientId) {
removeResource(pid, clientId, true);
}

Expand All @@ -295,27 +357,22 @@ void ResourceManagerService::removeResource(int pid, int64_t clientId, bool chec
ALOGV("removeResource: didn't find pid %d for clientId %lld", pid, (long long) clientId);
return;
}
bool found = false;
ResourceInfos &infos = mMap.editValueAt(index);
for (size_t j = 0; j < infos.size(); ++j) {
if (infos[j].clientId == clientId) {
if (infos[j].cpuBoost && mCpuBoostCount > 0) {
if (--mCpuBoostCount == 0) {
requestCpusetBoost(false, this);
}
}
if (infos[j].batteryNoted) {
BatteryNotifier::getInstance().noteStopVideo(infos[j].uid);
}
IInterface::asBinder(infos[j].client)->unlinkToDeath(infos[j].deathNotifier);
j = infos.removeAt(j);
found = true;
break;
}

index = infos.indexOfKey(clientId);
if (index < 0) {
ALOGV("removeResource: didn't find clientId %lld", (long long) clientId);
return;
}
if (!found) {
ALOGV("didn't find client");

const ResourceInfo &info = infos[index];
for (auto it = info.resources.begin(); it != info.resources.end(); it++) {
onLastRemoved(it->second, info);
}

IInterface::asBinder(info.client)->unlinkToDeath(info.deathNotifier);

infos.removeItemsAt(index);
}

void ResourceManagerService::getClientForResource_l(
Expand Down Expand Up @@ -426,7 +483,7 @@ bool ResourceManagerService::reclaimResource(
ResourceInfos &infos = mMap.editValueAt(i);
for (size_t j = 0; j < infos.size();) {
if (infos[j].client == failedClient) {
j = infos.removeAt(j);
j = infos.removeItemsAt(j);
found = true;
} else {
++j;
Expand Down Expand Up @@ -554,11 +611,12 @@ bool ResourceManagerService::getBiggestClient_l(
uint64_t largestValue = 0;
const ResourceInfos &infos = mMap.valueAt(index);
for (size_t i = 0; i < infos.size(); ++i) {
Vector<MediaResource> resources = infos[i].resources;
for (size_t j = 0; j < resources.size(); ++j) {
if (resources[j].mType == type) {
if (resources[j].mValue > largestValue) {
largestValue = resources[j].mValue;
const ResourceList &resources = infos[i].resources;
for (auto it = resources.begin(); it != resources.end(); it++) {
const MediaResource &resource = it->second;
if (resource.mType == type) {
if (resource.mValue > largestValue) {
largestValue = resource.mValue;
clientTemp = infos[i].client;
}
}
Expand Down
16 changes: 11 additions & 5 deletions services/mediaresourcemanager/ResourceManagerService.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,17 @@ namespace android {
class ServiceLog;
struct ProcessInfoInterface;

typedef std::map<std::pair<MediaResource::Type, MediaResource::SubType>, MediaResource> ResourceList;
struct ResourceInfo {
int64_t clientId;
uid_t uid;
sp<IResourceManagerClient> client;
sp<IBinder::DeathRecipient> deathNotifier;
Vector<MediaResource> resources;
bool cpuBoost;
bool batteryNoted;
ResourceList resources;
};

typedef Vector<ResourceInfo> ResourceInfos;
// TODO: convert these to std::map
typedef KeyedVector<int64_t, ResourceInfo> ResourceInfos;
typedef KeyedVector<int, ResourceInfos> PidResourceInfosMap;

class ResourceManagerService
Expand All @@ -68,7 +68,10 @@ class ResourceManagerService
const sp<IResourceManagerClient> client,
const Vector<MediaResource> &resources);

virtual void removeResource(int pid, int64_t clientId);
virtual void removeResource(int pid, int64_t clientId,
const Vector<MediaResource> &resources);

virtual void removeClient(int pid, int64_t clientId);

// Tries to reclaim resource from processes with lower priority than the calling process
// according to the requested resources.
Expand Down Expand Up @@ -110,6 +113,9 @@ class ResourceManagerService
void getClientForResource_l(
int callingPid, const MediaResource *res, Vector<sp<IResourceManagerClient>> *clients);

void onFirstAdded(const MediaResource& res, const ResourceInfo& clientInfo);
void onLastRemoved(const MediaResource& res, const ResourceInfo& clientInfo);

mutable Mutex mLock;
sp<ProcessInfoInterface> mProcessInfo;
sp<ServiceLog> mServiceLog;
Expand Down
Loading

0 comments on commit fb092d3

Please sign in to comment.