Merge "CCodec: clear deadline after component start returns"
diff --git a/camera/Camera.cpp b/camera/Camera.cpp
index d1618e4..2244682 100644
--- a/camera/Camera.cpp
+++ b/camera/Camera.cpp
@@ -71,10 +71,11 @@
}
sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,
- int clientUid, int clientPid, int targetSdkVersion, bool overrideToPortrait)
+ int clientUid, int clientPid, int targetSdkVersion, bool overrideToPortrait,
+ bool forceSlowJpegMode)
{
return CameraBaseT::connect(cameraId, clientPackageName, clientUid,
- clientPid, targetSdkVersion, overrideToPortrait);
+ clientPid, targetSdkVersion, overrideToPortrait, forceSlowJpegMode);
}
status_t Camera::reconnect()
diff --git a/camera/CameraBase.cpp b/camera/CameraBase.cpp
index 0a5bc12..9ae4607 100644
--- a/camera/CameraBase.cpp
+++ b/camera/CameraBase.cpp
@@ -163,7 +163,7 @@
sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
const String16& clientPackageName,
int clientUid, int clientPid, int targetSdkVersion,
- bool overrideToPortrait)
+ bool overrideToPortrait, bool forceSlowJpegMode)
{
ALOGV("%s: connect", __FUNCTION__);
sp<TCam> c = new TCam(cameraId);
@@ -173,9 +173,11 @@
binder::Status ret;
if (cs != nullptr) {
TCamConnectService fnConnectService = TCamTraits::fnConnectService;
- ALOGI("Connect camera (legacy API) - overrideToPortrait %d", overrideToPortrait);
+ ALOGI("Connect camera (legacy API) - overrideToPortrait %d, forceSlowJpegMode %d",
+ overrideToPortrait, forceSlowJpegMode);
ret = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,
- clientPid, targetSdkVersion, overrideToPortrait, /*out*/ &c->mCamera);
+ clientPid, targetSdkVersion, overrideToPortrait, forceSlowJpegMode,
+ /*out*/ &c->mCamera);
}
if (ret.isOk() && c->mCamera != nullptr) {
IInterface::asBinder(c->mCamera)->linkToDeath(c);
diff --git a/camera/aidl/android/hardware/ICameraService.aidl b/camera/aidl/android/hardware/ICameraService.aidl
index 01baba1..9f32595 100644
--- a/camera/aidl/android/hardware/ICameraService.aidl
+++ b/camera/aidl/android/hardware/ICameraService.aidl
@@ -84,7 +84,8 @@
String opPackageName,
int clientUid, int clientPid,
int targetSdkVersion,
- boolean overrideToPortrait);
+ boolean overrideToPortrait,
+ boolean forceSlowJpegMode);
/**
* Open a camera device through the new camera API
diff --git a/camera/include/camera/Camera.h b/camera/include/camera/Camera.h
index 26c36a7..21b57af 100644
--- a/camera/include/camera/Camera.h
+++ b/camera/include/camera/Camera.h
@@ -58,7 +58,7 @@
typedef ::android::hardware::ICameraClient TCamCallbacks;
typedef ::android::binder::Status(::android::hardware::ICameraService::*TCamConnectService)
(const sp<::android::hardware::ICameraClient>&,
- int, const String16&, int, int, int, bool,
+ int, const String16&, int, int, int, bool, bool,
/*out*/
sp<::android::hardware::ICamera>*);
static TCamConnectService fnConnectService;
@@ -82,7 +82,7 @@
static sp<Camera> connect(int cameraId,
const String16& clientPackageName,
int clientUid, int clientPid, int targetSdkVersion,
- bool overrideToPortrait);
+ bool overrideToPortrait, bool forceSlowJpegMode);
virtual ~Camera();
diff --git a/camera/include/camera/CameraBase.h b/camera/include/camera/CameraBase.h
index 9d0721b..b20dc1b 100644
--- a/camera/include/camera/CameraBase.h
+++ b/camera/include/camera/CameraBase.h
@@ -120,7 +120,7 @@
static sp<TCam> connect(int cameraId,
const String16& clientPackageName,
int clientUid, int clientPid, int targetSdkVersion,
- bool overrideToPortrait);
+ bool overrideToPortrait, bool forceSlowJpegMode);
virtual void disconnect();
void setListener(const sp<TCamListener>& listener);
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index 23d90cc..02047ae 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -696,7 +696,7 @@
CameraMetadata rawMetadata;
int targetSdkVersion = android_get_application_target_sdk_version();
binder::Status serviceRet = cs->getCameraCharacteristics(String16(cameraIdStr),
- targetSdkVersion, /*overrideToPortrait*/true, &rawMetadata);
+ targetSdkVersion, /*overrideToPortrait*/false, &rawMetadata);
if (!serviceRet.isOk()) {
switch(serviceRet.serviceSpecificErrorCode()) {
case hardware::ICameraService::ERROR_DISCONNECTED:
@@ -748,7 +748,7 @@
binder::Status serviceRet = cs->connectDevice(
callbacks, String16(cameraId), String16(""), {},
hardware::ICameraService::USE_CALLING_UID, /*oomScoreOffset*/0,
- targetSdkVersion, /*overrideToPortrait*/true, /*out*/&deviceRemote);
+ targetSdkVersion, /*overrideToPortrait*/false, /*out*/&deviceRemote);
if (!serviceRet.isOk()) {
ALOGE("%s: connect camera device failed: %s", __FUNCTION__, serviceRet.toString8().string());
diff --git a/camera/tests/CameraZSLTests.cpp b/camera/tests/CameraZSLTests.cpp
index bdfb84a..6423709 100644
--- a/camera/tests/CameraZSLTests.cpp
+++ b/camera/tests/CameraZSLTests.cpp
@@ -211,7 +211,7 @@
String16("ZSLTest"), hardware::ICameraService::USE_CALLING_UID,
hardware::ICameraService::USE_CALLING_PID,
/*targetSdkVersion*/__ANDROID_API_FUTURE__,
- /*overrideToPortrait*/false, &cameraDevice);
+ /*overrideToPortrait*/false, /*forceSlowJpegMode*/false, &cameraDevice);
EXPECT_TRUE(rc.isOk());
CameraParameters params(cameraDevice->getParameters());
diff --git a/drm/libmediadrm/DrmSessionManager.cpp b/drm/libmediadrm/DrmSessionManager.cpp
index 301538f..6744e25 100644
--- a/drm/libmediadrm/DrmSessionManager.cpp
+++ b/drm/libmediadrm/DrmSessionManager.cpp
@@ -36,13 +36,6 @@
using aidl::android::media::MediaResourceParcel;
using aidl::android::media::ClientInfoParcel;
-namespace {
-void ResourceManagerServiceDied(void* cookie) {
- auto thiz = static_cast<DrmSessionManager*>(cookie);
- thiz->binderDied();
-}
-}
-
using ::ndk::ScopedAStatus;
static String8 GetSessionIdString(const Vector<uint8_t> &sessionId) {
@@ -60,6 +53,12 @@
return vec;
}
+static Vector<uint8_t> toAndroidVec(const std::vector<uint8_t>& array) {
+ Vector<uint8_t> vec;
+ vec.appendArray(array.data(), array.size());
+ return vec;
+}
+
static std::vector<MediaResourceParcel> toResourceVec(
const Vector<uint8_t> &sessionId, int64_t value) {
using Type = aidl::android::media::MediaResourceType;
@@ -72,11 +71,6 @@
return resources;
}
-static std::shared_ptr<IResourceManagerService> getResourceManagerService() {
- ::ndk::SpAIBinder binder(AServiceManager_getService("media.resource_manager"));
- return IResourceManagerService::fromBinder(binder);
-}
-
bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2) {
if (sessionId1.size() != sessionId2.size()) {
return false;
@@ -96,16 +90,15 @@
}
DrmSessionManager::DrmSessionManager()
- : DrmSessionManager(getResourceManagerService()) {
+ : DrmSessionManager(nullptr) {
}
DrmSessionManager::DrmSessionManager(const std::shared_ptr<IResourceManagerService> &service)
: mService(service),
- mInitialized(false),
- mDeathRecipient(AIBinder_DeathRecipient_new(ResourceManagerServiceDied)) {
- if (mService == NULL) {
- ALOGE("Failed to init ResourceManagerService");
- }
+ mDeathRecipient(::ndk::ScopedAIBinder_DeathRecipient(
+ AIBinder_DeathRecipient_new(ResourceManagerServiceDied))) {
+ // Setting callback notification when DeathRecipient gets deleted.
+ AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), BinderUnlinkedCallback);
}
DrmSessionManager::~DrmSessionManager() {
@@ -114,14 +107,64 @@
}
}
-void DrmSessionManager::init() {
+status_t DrmSessionManager::init() {
Mutex::Autolock lock(mLock);
- if (mInitialized) {
+ getResourceManagerService_l();
+ if (mService == nullptr) {
+ ALOGE("Failed to init ResourceManagerService");
+ return DEAD_OBJECT;
+ }
+
+ return OK;
+}
+
+void DrmSessionManager::getResourceManagerService_l() {
+ if (mService != nullptr) {
return;
}
- mInitialized = true;
- if (mService != NULL) {
- AIBinder_linkToDeath(mService->asBinder().get(), mDeathRecipient.get(), this);
+
+ // Get binder interface to resource manager.
+ ::ndk::SpAIBinder binder(AServiceManager_waitForService("media.resource_manager"));
+ mService = IResourceManagerService::fromBinder(binder);
+ if (mService == nullptr) {
+ ALOGE("Failed to get ResourceManagerService");
+ return;
+ }
+
+ // Create the context that is passed as cookie to the binder death notification.
+ // The context gets deleted at BinderUnlinkedCallback.
+ BinderDiedContext* context = new BinderDiedContext{
+ .mDrmSessionManager = wp<DrmSessionManager>::fromExisting(this)};
+ // Register for the callbacks by linking to death notification.
+ AIBinder_linkToDeath(mService->asBinder().get(), mDeathRecipient.get(), context);
+
+ // If the RM was restarted, re-register all the resources.
+ if (mBinderDied) {
+ reRegisterAllResources_l();
+ mBinderDied = false;
+ }
+}
+
+void DrmSessionManager::reRegisterAllResources_l() {
+ if (mSessionMap.empty()) {
+ // Nothing to register.
+ ALOGV("No resources to add");
+ return;
+ }
+
+ if (mService == nullptr) {
+ ALOGW("Service isn't available");
+ return;
+ }
+
+ // Go through the session map and re-register all the resources for those sessions.
+ for (SessionInfoMap::const_iterator iter = mSessionMap.begin();
+ iter != mSessionMap.end(); ++iter) {
+ ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(iter->second.pid),
+ .uid = static_cast<int32_t>(iter->second.uid),
+ .id = iter->second.clientId};
+ mService->addResource(clientInfo, iter->second.drm,
+ toResourceVec(toAndroidVec(iter->first), iter->second.resourceValue));
}
}
@@ -137,7 +180,7 @@
}
static int64_t clientId = 0;
- mSessionMap[toStdVec(sessionId)] = (SessionInfo){pid, uid, clientId};
+ mSessionMap[toStdVec(sessionId)] = (SessionInfo){pid, uid, clientId, drm, INT64_MAX};
ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(pid),
.uid = static_cast<int32_t>(uid),
.id = clientId++};
@@ -154,6 +197,7 @@
}
auto info = it->second;
+ info.resourceValue = -1;
ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(info.pid),
.uid = static_cast<int32_t>(info.uid),
.id = info.clientId};
@@ -215,7 +259,31 @@
void DrmSessionManager::binderDied() {
ALOGW("ResourceManagerService died.");
Mutex::Autolock lock(mLock);
- mService.reset();
+ mService = nullptr;
+ mBinderDied = true;
+ // start an async operation that will reconnect with the RM and
+ // re-registers all the resources.
+ mGetServiceFuture = std::async(std::launch::async, [this] { getResourceManagerService(); });
+}
+
+void DrmSessionManager::ResourceManagerServiceDied(void* cookie) {
+ BinderDiedContext* context = reinterpret_cast<BinderDiedContext*>(cookie);
+
+ // Validate the context and check if the DrmSessionManager object is still in scope.
+ if (context != nullptr) {
+ sp<DrmSessionManager> thiz = context->mDrmSessionManager.promote();
+ if (thiz != nullptr) {
+ thiz->binderDied();
+ } else {
+ ALOGI("DrmSessionManager is out of scope already");
+ }
+ }
+}
+
+void DrmSessionManager::BinderUnlinkedCallback(void* cookie) {
+ BinderDiedContext* context = reinterpret_cast<BinderDiedContext*>(cookie);
+ // Since we don't need the context anymore, we are deleting it now.
+ delete context;
}
} // namespace android
diff --git a/drm/libmediadrm/include/mediadrm/DrmSessionManager.h b/drm/libmediadrm/include/mediadrm/DrmSessionManager.h
index c56bf01..025261d 100644
--- a/drm/libmediadrm/include/mediadrm/DrmSessionManager.h
+++ b/drm/libmediadrm/include/mediadrm/DrmSessionManager.h
@@ -27,8 +27,10 @@
#include <utils/threads.h>
#include <utils/Vector.h>
+#include <future>
#include <map>
#include <memory>
+#include <set>
#include <utility>
#include <vector>
@@ -38,6 +40,7 @@
using aidl::android::media::IResourceManagerClient;
using aidl::android::media::IResourceManagerService;
+using aidl::android::media::MediaResourceParcel;
bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2);
@@ -45,6 +48,9 @@
pid_t pid;
uid_t uid;
int64_t clientId;
+ std::shared_ptr<IResourceManagerClient> drm;
+ int64_t resourceValue;
+
};
typedef std::map<std::vector<uint8_t>, SessionInfo> SessionInfoMap;
@@ -66,20 +72,52 @@
size_t getSessionCount() const;
bool containsSession(const Vector<uint8_t>& sessionId) const;
- // implements DeathRecipient
- void binderDied();
-
protected:
virtual ~DrmSessionManager();
private:
- void init();
+ status_t init();
- std::shared_ptr<IResourceManagerService> mService;
+ // To set up the binder interface with the resource manager service.
+ void getResourceManagerService() {
+ Mutex::Autolock lock(mLock);
+ getResourceManagerService_l();
+ }
+ void getResourceManagerService_l();
+
+ // To add/register all the resources currently added/registered with
+ // the ResourceManagerService.
+ // This function will be called right after the death of the Resource
+ // Manager to make sure that the newly started ResourceManagerService
+ // knows about the current resource usage.
+ void reRegisterAllResources_l();
+
+ // For binder death handling
+ static void ResourceManagerServiceDied(void* cookie);
+ static void BinderUnlinkedCallback(void* cookie);
+ void binderDied();
+
+ // BinderDiedContext defines the cookie that is passed as DeathRecipient.
+ // Since this can maintain more context than a raw pointer, we can
+ // validate the scope of DrmSessionManager,
+ // before deferencing it upon the binder death.
+ struct BinderDiedContext {
+ wp<DrmSessionManager> mDrmSessionManager;
+ };
+
+ std::shared_ptr<IResourceManagerService> mService = nullptr;
mutable Mutex mLock;
SessionInfoMap mSessionMap;
- bool mInitialized;
+ bool mBinderDied = false;
::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+ /**
+ * Reconnecting with the ResourceManagerService, after its binder interface dies,
+ * is done asynchronously. It will also make sure that, all the resources
+ * asssociated with this DrmSessionManager are added with the new instance
+ * of the ResourceManagerService to persist the state of resources.
+ * We must store the reference of the furture to guarantee real asynchronous operation.
+ */
+ std::future<void> mGetServiceFuture;
DISALLOW_EVIL_CONSTRUCTORS(DrmSessionManager);
};
diff --git a/drm/libmediadrmrkp/Android.bp b/drm/libmediadrmrkp/Android.bp
new file mode 100644
index 0000000..e4a7a81
--- /dev/null
+++ b/drm/libmediadrmrkp/Android.bp
@@ -0,0 +1,44 @@
+cc_library {
+ name: "libmediadrmrkp",
+ vendor_available: true,
+ srcs: [
+ "src/**/*.cpp",
+ ],
+ export_include_dirs: [
+ "include"
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "liblog",
+ "android.hardware.drm-V1-ndk",
+ "android.hardware.security.rkp-V3-ndk",
+ ],
+ defaults: [
+ "keymint_use_latest_hal_aidl_ndk_shared",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
+
+cc_binary {
+ name: "test_libmediadrmrkp",
+ srcs: [
+ "test/*",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "liblog",
+ "android.hardware.drm-V1-ndk",
+ "android.hardware.security.rkp-V3-ndk",
+ ],
+ static_libs: [
+ "libmediadrmrkp",
+ ],
+ vendor: true,
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
\ No newline at end of file
diff --git a/drm/libmediadrmrkp/include/DrmRemotelyProvisionedComponent.h b/drm/libmediadrmrkp/include/DrmRemotelyProvisionedComponent.h
new file mode 100644
index 0000000..893f560
--- /dev/null
+++ b/drm/libmediadrmrkp/include/DrmRemotelyProvisionedComponent.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#ifndef DRM_RKP_COMPONENT_H_
+#define DRM_RKP_COMPONENT_H_
+
+#include <aidl/android/hardware/drm/IDrmPlugin.h>
+#include <aidl/android/hardware/security/keymint/BnRemotelyProvisionedComponent.h>
+#include <aidl/android/hardware/security/keymint/RpcHardwareInfo.h>
+
+namespace android::mediadrm {
+
+using ::aidl::android::hardware::drm::IDrmPlugin;
+using ::aidl::android::hardware::security::keymint::BnRemotelyProvisionedComponent;
+using ::aidl::android::hardware::security::keymint::DeviceInfo;
+using ::aidl::android::hardware::security::keymint::MacedPublicKey;
+using ::aidl::android::hardware::security::keymint::ProtectedData;
+using ::aidl::android::hardware::security::keymint::RpcHardwareInfo;
+using ::ndk::ScopedAStatus;
+
+class DrmRemotelyProvisionedComponent : public BnRemotelyProvisionedComponent {
+ public:
+ DrmRemotelyProvisionedComponent(std::shared_ptr<IDrmPlugin> drm, std::string drmVendor,
+ std::string drmDesc);
+ ScopedAStatus getHardwareInfo(RpcHardwareInfo* info) override;
+
+ ScopedAStatus generateEcdsaP256KeyPair(bool testMode, MacedPublicKey* macedPublicKey,
+ std::vector<uint8_t>* privateKeyHandle) override;
+
+ ScopedAStatus generateCertificateRequest(bool testMode,
+ const std::vector<MacedPublicKey>& keysToSign,
+ const std::vector<uint8_t>& endpointEncCertChain,
+ const std::vector<uint8_t>& challenge,
+ DeviceInfo* deviceInfo, ProtectedData* protectedData,
+ std::vector<uint8_t>* keysToSignMac) override;
+
+ ScopedAStatus generateCertificateRequestV2(const std::vector<MacedPublicKey>& keysToSign,
+ const std::vector<uint8_t>& challenge,
+ std::vector<uint8_t>* csr) override;
+
+ private:
+ std::shared_ptr<IDrmPlugin> mDrm;
+ std::string mDrmVendor;
+ std::string mDrmDesc;
+};
+} // namespace android::mediadrm
+
+#endif // DRM_RKP_COMPONENT_H_
\ No newline at end of file
diff --git a/drm/libmediadrmrkp/include/DrmRkpAdapter.h b/drm/libmediadrmrkp/include/DrmRkpAdapter.h
new file mode 100644
index 0000000..0554f6a
--- /dev/null
+++ b/drm/libmediadrmrkp/include/DrmRkpAdapter.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#ifndef DRM_RKP_ADAPTER_H_
+#define DRM_RKP_ADAPTER_H_
+
+#include <aidl/android/hardware/security/keymint/BnRemotelyProvisionedComponent.h>
+#include <map>
+#include <string>
+
+namespace android::mediadrm {
+using IRemotelyProvisionedComponent =
+ ::aidl::android::hardware::security::keymint::IRemotelyProvisionedComponent;
+std::map<std::string, std::shared_ptr<IRemotelyProvisionedComponent>>
+getDrmRemotelyProvisionedComponents();
+} // namespace android::mediadrm
+
+#endif // DRM_RKP_ADAPTER_H_
\ No newline at end of file
diff --git a/drm/libmediadrmrkp/src/DrmRemotelyProvisionedComponent.cpp b/drm/libmediadrmrkp/src/DrmRemotelyProvisionedComponent.cpp
new file mode 100644
index 0000000..9d11811
--- /dev/null
+++ b/drm/libmediadrmrkp/src/DrmRemotelyProvisionedComponent.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 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_TAG "DrmRemotelyProvisionedComponent"
+#include "DrmRemotelyProvisionedComponent.h"
+#include <log/log.h>
+
+namespace android::mediadrm {
+DrmRemotelyProvisionedComponent::DrmRemotelyProvisionedComponent(std::shared_ptr<IDrmPlugin> drm,
+ std::string drmVendor,
+ std::string drmDesc)
+ : mDrm(std::move(drm)), mDrmVendor(std::move(drmVendor)), mDrmDesc(std::move(drmDesc)) {}
+ScopedAStatus DrmRemotelyProvisionedComponent::getHardwareInfo(RpcHardwareInfo* info) {
+ info->versionNumber = 3;
+ info->rpcAuthorName = mDrmVendor;
+ info->supportedEekCurve = RpcHardwareInfo::CURVE_NONE;
+ info->supportedNumKeysInCsr = RpcHardwareInfo::MIN_SUPPORTED_NUM_KEYS_IN_CSR;
+ info->uniqueId = mDrmDesc;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus DrmRemotelyProvisionedComponent::generateEcdsaP256KeyPair(bool, MacedPublicKey*,
+ std::vector<uint8_t>*) {
+ return ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IRemotelyProvisionedComponent::STATUS_REMOVED,
+ "generateEcdsaP256KeyPair not supported."));
+}
+
+ScopedAStatus DrmRemotelyProvisionedComponent::generateCertificateRequest(
+ bool, const std::vector<MacedPublicKey>&, const std::vector<uint8_t>&,
+ const std::vector<uint8_t>&, DeviceInfo*, ProtectedData*, std::vector<uint8_t>*) {
+ return ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IRemotelyProvisionedComponent::STATUS_REMOVED,
+ "generateCertificateRequest not supported."));
+}
+
+ScopedAStatus DrmRemotelyProvisionedComponent::generateCertificateRequestV2(
+ const std::vector<MacedPublicKey>&, const std::vector<uint8_t>& challenge,
+ std::vector<uint8_t>* csr) {
+ // extract csr using setPropertyByteArray/getPropertyByteArray
+ auto status = mDrm->setPropertyByteArray("certificateSigningRequestChallenge", challenge);
+ if (!status.isOk()) {
+ ALOGE("setPropertyByteArray certificateSigningRequestChallenge failed. Details: [%s].",
+ status.getDescription().c_str());
+ return status;
+ }
+
+ status = mDrm->getPropertyByteArray("certificateSigningRequest", csr);
+ if (!status.isOk()) {
+ ALOGE("getPropertyByteArray certificateSigningRequest failed. Details: [%s].",
+ status.getDescription().c_str());
+ return status;
+ }
+
+ return ScopedAStatus::ok();
+}
+} // namespace android::mediadrm
\ No newline at end of file
diff --git a/drm/libmediadrmrkp/src/DrmRkpAdapter.cpp b/drm/libmediadrmrkp/src/DrmRkpAdapter.cpp
new file mode 100644
index 0000000..a2d4cc1
--- /dev/null
+++ b/drm/libmediadrmrkp/src/DrmRkpAdapter.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2023 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_TAG "DrmRkpAdapter"
+#include "DrmRkpAdapter.h"
+#include <aidl/android/hardware/drm/IDrmFactory.h>
+#include <aidl/android/hardware/drm/IDrmPlugin.h>
+#include <aidl/android/hardware/security/keymint/BnRemotelyProvisionedComponent.h>
+#include <android/binder_manager.h>
+#include <log/log.h>
+#include "DrmRemotelyProvisionedComponent.h"
+
+namespace android::mediadrm {
+using CryptoSchemes = ::aidl::android::hardware::drm::CryptoSchemes;
+using IDrmFactory = ::aidl::android::hardware::drm::IDrmFactory;
+using IDrmPlugin = ::aidl::android::hardware::drm::IDrmPlugin;
+
+std::map<std::string, std::shared_ptr<IRemotelyProvisionedComponent>>
+getDrmRemotelyProvisionedComponents() {
+ std::map<std::string, std::shared_ptr<IRemotelyProvisionedComponent>> comps;
+ AServiceManager_forEachDeclaredInstance(
+ IDrmFactory::descriptor, &comps, [](const char* instance, void* context) {
+ auto fullName = std::string(IDrmFactory::descriptor) + "/" + std::string(instance);
+ auto factory = IDrmFactory::fromBinder(
+ ::ndk::SpAIBinder(AServiceManager_waitForService(fullName.c_str())));
+ if (factory == nullptr) {
+ ALOGE("not found IDrmFactory. Instance name:[%s]", fullName.c_str());
+ return;
+ }
+
+ ALOGI("found IDrmFactory. Instance name:[%s]", fullName.c_str());
+ CryptoSchemes schemes{};
+ auto status = factory->getSupportedCryptoSchemes(&schemes);
+ if (!status.isOk()) {
+ ALOGE("getSupportedCryptoSchemes failed.Detail: [%s].",
+ status.getDescription().c_str());
+ return;
+ }
+
+ if (schemes.uuids.empty()) {
+ ALOGW("IDrmFactory Instance [%s] has empty supported schemes",
+ fullName.c_str());
+ return;
+ }
+
+ std::shared_ptr<IDrmPlugin> mDrm;
+ status = factory->createDrmPlugin(schemes.uuids[0], "DrmRkpAdapter", &mDrm);
+ if (!status.isOk()) {
+ ALOGE("createDrmPlugin failed.Detail: [%s].", status.getDescription().c_str());
+ return;
+ }
+
+ std::string drmVendor;
+ status = mDrm->getPropertyString("vendor", &drmVendor);
+ if (!status.isOk()) {
+ ALOGE("mDrm->getPropertyString(\"vendor\") failed.Detail: [%s].",
+ status.getDescription().c_str());
+ return;
+ }
+
+ std::string drmDesc;
+ status = mDrm->getPropertyString("description", &drmDesc);
+ if (!status.isOk()) {
+ ALOGE("mDrm->getPropertyString(\"description\") failed.Detail: [%s].",
+ status.getDescription().c_str());
+ return;
+ }
+
+ std::string compName = "DrmRemotelyProvisionedComponent_" + std::string(instance);
+ auto comps = static_cast<
+ std::map<std::string, std::shared_ptr<IRemotelyProvisionedComponent>>*>(
+ context);
+ (*comps)[compName] = ::ndk::SharedRefBase::make<DrmRemotelyProvisionedComponent>(
+ mDrm, drmVendor, drmDesc);
+ });
+ return comps;
+}
+} // namespace android::mediadrm
\ No newline at end of file
diff --git a/drm/libmediadrmrkp/test/test_main.cpp b/drm/libmediadrmrkp/test/test_main.cpp
new file mode 100644
index 0000000..d23dc3b
--- /dev/null
+++ b/drm/libmediadrmrkp/test/test_main.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+#include "DrmRkpAdapter.h"
+
+using ::aidl::android::hardware::security::keymint::MacedPublicKey;
+int main() {
+ std::vector<uint8_t> challenge(16);
+ std::vector<uint8_t> csr;
+ std::vector<MacedPublicKey> k;
+ for (auto const& e : android::mediadrm::getDrmRemotelyProvisionedComponents()) {
+ auto status = e.second.get()->generateCertificateRequestV2(k, challenge, &csr);
+ printf("%s calls generateCertificateRequestV2() gets status.isOk():%d\n",
+ e.first.c_str(), status.isOk());
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/include/private/media/VideoFrame.h b/include/private/media/VideoFrame.h
index d4025e5..78ea2a1 100644
--- a/include/private/media/VideoFrame.h
+++ b/include/private/media/VideoFrame.h
@@ -42,9 +42,15 @@
mWidth(width), mHeight(height),
mDisplayWidth(displayWidth), mDisplayHeight(displayHeight),
mTileWidth(tileWidth), mTileHeight(tileHeight), mDurationUs(0),
- mRotationAngle(angle), mBytesPerPixel(bpp), mRowBytes(bpp * width),
- mSize(hasData ? (bpp * width * height) : 0),
- mIccSize(iccSize), mBitDepth(bitDepth) {
+ mRotationAngle(angle), mBytesPerPixel(bpp), mIccSize(iccSize),
+ mBitDepth(bitDepth) {
+ uint32_t multVal;
+ mRowBytes = __builtin_mul_overflow(bpp, width, &multVal) ? 0 : multVal;
+ mSize = __builtin_mul_overflow(multVal, height, &multVal) ? 0 : multVal;
+ if (hasData && (mRowBytes == 0 || mSize == 0)) {
+ ALOGE("Frame rowBytes/ size overflow %dx%d bpp %d", width, height, bpp);
+ android_errorWriteLog(0x534e4554, "233006499");
+ }
}
void init(const VideoFrame& copy, const void* iccData, size_t iccSize) {
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 3d089de..6295b06 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -877,6 +877,16 @@
if (msg->findInt32(KEY_PUSH_BLANK_BUFFERS_ON_STOP, &pushBlankBuffersOnStop)) {
config->mPushBlankBuffersOnStop = pushBlankBuffersOnStop == 1;
}
+ // secure compoment or protected content default with
+ // "push-blank-buffers-on-shutdown" flag
+ if (!config->mPushBlankBuffersOnStop) {
+ int32_t usageProtected;
+ if (comp->getName().find(".secure") != std::string::npos) {
+ config->mPushBlankBuffersOnStop = true;
+ } else if (msg->findInt32("protected", &usageProtected) && usageProtected) {
+ config->mPushBlankBuffersOnStop = true;
+ }
+ }
}
}
setSurface(surface);
@@ -1872,18 +1882,14 @@
}
state->set(STOPPING);
}
- {
- Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
- const std::unique_ptr<Config> &config = *configLocked;
- if (config->mPushBlankBuffersOnStop) {
- mChannel->pushBlankBufferToOutputSurface();
- }
- }
mChannel->reset();
- (new AMessage(kWhatStop, this))->post();
+ bool pushBlankBuffer = mConfig.lock().get()->mPushBlankBuffersOnStop;
+ sp<AMessage> stopMessage(new AMessage(kWhatStop, this));
+ stopMessage->setInt32("pushBlankBuffer", pushBlankBuffer);
+ stopMessage->post();
}
-void CCodec::stop() {
+void CCodec::stop(bool pushBlankBuffer) {
std::shared_ptr<Codec2Client::Component> comp;
{
Mutexed<State>::Locked state(mState);
@@ -1902,7 +1908,7 @@
comp = state->comp;
}
status_t err = comp->stop();
- mChannel->stopUseOutputSurface();
+ mChannel->stopUseOutputSurface(pushBlankBuffer);
if (err != C2_OK) {
// TODO: convert err into status_t
mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
@@ -1967,21 +1973,16 @@
config->mInputSurfaceDataspace = HAL_DATASPACE_UNKNOWN;
}
}
- {
- Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
- const std::unique_ptr<Config> &config = *configLocked;
- if (config->mPushBlankBuffersOnStop) {
- mChannel->pushBlankBufferToOutputSurface();
- }
- }
mChannel->reset();
+ bool pushBlankBuffer = mConfig.lock().get()->mPushBlankBuffersOnStop;
// thiz holds strong ref to this while the thread is running.
sp<CCodec> thiz(this);
- std::thread([thiz, sendCallback] { thiz->release(sendCallback); }).detach();
+ std::thread([thiz, sendCallback, pushBlankBuffer]
+ { thiz->release(sendCallback, pushBlankBuffer); }).detach();
}
-void CCodec::release(bool sendCallback) {
+void CCodec::release(bool sendCallback, bool pushBlankBuffer) {
std::shared_ptr<Codec2Client::Component> comp;
{
Mutexed<State>::Locked state(mState);
@@ -1996,7 +1997,7 @@
comp = state->comp;
}
comp->release();
- mChannel->stopUseOutputSurface();
+ mChannel->stopUseOutputSurface(pushBlankBuffer);
{
Mutexed<State>::Locked state(mState);
@@ -2010,6 +2011,7 @@
}
status_t CCodec::setSurface(const sp<Surface> &surface) {
+ bool pushBlankBuffer = false;
{
Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
const std::unique_ptr<Config> &config = *configLocked;
@@ -2035,8 +2037,9 @@
return err;
}
}
+ pushBlankBuffer = config->mPushBlankBuffersOnStop;
}
- return mChannel->setSurface(surface);
+ return mChannel->setSurface(surface, pushBlankBuffer);
}
void CCodec::signalFlush() {
@@ -2335,7 +2338,11 @@
case kWhatStop: {
// C2Component::stop() should return within 500ms.
setDeadline(now, 1500ms, "stop");
- stop();
+ int32_t pushBlankBuffer;
+ if (!msg->findInt32("pushBlankBuffer", &pushBlankBuffer)) {
+ pushBlankBuffer = 0;
+ }
+ stop(static_cast<bool>(pushBlankBuffer));
break;
}
case kWhatFlush: {
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 91a107f..385912a 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -1025,8 +1025,8 @@
if (desiredRenderTimeNs < nowNs) {
desiredRenderTimeNs = nowNs;
}
- // We've just released a frame to the surface, so keep track of it and later check to see if it
- // is actually rendered.
+ // We've just queued a frame to the surface, so keep track of it and later check to see if it is
+ // actually rendered.
TrackedFrame frame;
frame.number = qbo.nextFrameNumber - 1;
frame.mediaTimeUs = mediaTimeUs;
@@ -1693,14 +1693,22 @@
mFirstValidFrameIndex = mFrameIndex.load(std::memory_order_relaxed);
}
-void CCodecBufferChannel::stopUseOutputSurface() {
- if (mOutputSurface.lock()->surface) {
+void CCodecBufferChannel::stopUseOutputSurface(bool pushBlankBuffer) {
+ sp<Surface> surface = mOutputSurface.lock()->surface;
+ if (surface) {
C2BlockPool::local_id_t outputPoolId;
{
Mutexed<BlockPools>::Locked pools(mBlockPools);
outputPoolId = pools->outputPoolId;
}
if (mComponent) mComponent->stopUsingOutputSurface(outputPoolId);
+
+ if (pushBlankBuffer) {
+ sp<ANativeWindow> anw = static_cast<ANativeWindow *>(surface.get());
+ if (anw) {
+ pushBlankBuffersToNativeWindow(anw.get());
+ }
+ }
}
}
@@ -2220,14 +2228,20 @@
}
}
-status_t CCodecBufferChannel::setSurface(const sp<Surface> &newSurface) {
+status_t CCodecBufferChannel::setSurface(const sp<Surface> &newSurface, bool pushBlankBuffer) {
static std::atomic_uint32_t surfaceGeneration{0};
uint32_t generation = (getpid() << 10) |
((surfaceGeneration.fetch_add(1, std::memory_order_relaxed) + 1)
& ((1 << 10) - 1));
sp<IGraphicBufferProducer> producer;
- int maxDequeueCount = mOutputSurface.lock()->maxDequeueBuffers;
+ int maxDequeueCount;
+ sp<Surface> oldSurface;
+ {
+ Mutexed<OutputSurface>::Locked outputSurface(mOutputSurface);
+ maxDequeueCount = outputSurface->maxDequeueBuffers;
+ oldSurface = outputSurface->surface;
+ }
if (newSurface) {
newSurface->setScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
newSurface->setDequeueTimeout(kDequeueTimeoutNs);
@@ -2262,8 +2276,18 @@
Mutexed<OutputSurface>::Locked output(mOutputSurface);
output->surface = newSurface;
output->generation = generation;
+ initializeFrameTrackingFor(static_cast<ANativeWindow *>(newSurface.get()));
}
- initializeFrameTrackingFor(static_cast<ANativeWindow *>(newSurface.get()));
+
+ if (oldSurface && pushBlankBuffer) {
+ // When ReleaseSurface was set from MediaCodec,
+ // pushing a blank buffer at the end might be necessary.
+ sp<ANativeWindow> anw = static_cast<ANativeWindow *>(oldSurface.get());
+ if (anw) {
+ pushBlankBuffersToNativeWindow(anw.get());
+ }
+ }
+
return OK;
}
@@ -2353,13 +2377,4 @@
}
}
-status_t CCodecBufferChannel::pushBlankBufferToOutputSurface() {
- Mutexed<OutputSurface>::Locked output(mOutputSurface);
- sp<ANativeWindow> nativeWindow = static_cast<ANativeWindow *>(output->surface.get());
- if (nativeWindow == nullptr) {
- return INVALID_OPERATION;
- }
- return pushBlankBuffersToNativeWindow(nativeWindow.get());
-}
-
} // namespace android
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index e68d8ef..763eae9 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -104,7 +104,7 @@
/**
* Set output graphic surface for rendering.
*/
- status_t setSurface(const sp<Surface> &surface);
+ status_t setSurface(const sp<Surface> &surface, bool pushBlankBuffer);
/**
* Set GraphicBufferSource object from which the component extracts input
@@ -153,8 +153,10 @@
/**
* Stop using buffers of the current output surface for other Codec
* instances to use the surface safely.
+ *
+ * \param pushBlankBuffer[in] push a blank buffer at the end if true
*/
- void stopUseOutputSurface();
+ void stopUseOutputSurface(bool pushBlankBuffer);
/**
* Stop queueing buffers to the component. This object should never queue
@@ -203,11 +205,6 @@
void setMetaMode(MetaMode mode);
- /**
- * Push a blank buffer to the configured native output surface.
- */
- status_t pushBlankBufferToOutputSurface();
-
private:
class QueueGuard;
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 3eb2e63..228ad7e 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -1175,6 +1175,11 @@
err = C2_CORRUPTED;
}
}
+
+ if (err != C2_OK) {
+ staticInfo->reset();
+ }
+
if (dynamicInfo) {
ALOGV("Grabbing dynamic HDR info from gralloc4 metadata");
dynamicInfo->reset();
diff --git a/media/codec2/sfplugin/include/media/stagefright/CCodec.h b/media/codec2/sfplugin/include/media/stagefright/CCodec.h
index ec18128..13713bc 100644
--- a/media/codec2/sfplugin/include/media/stagefright/CCodec.h
+++ b/media/codec2/sfplugin/include/media/stagefright/CCodec.h
@@ -109,9 +109,9 @@
void allocate(const sp<MediaCodecInfo> &codecInfo);
void configure(const sp<AMessage> &msg);
void start();
- void stop();
+ void stop(bool pushBlankBuffer);
void flush();
- void release(bool sendCallback);
+ void release(bool sendCallback, bool pushBlankBuffer);
/**
* Creates an input surface for the current device configuration compatible with CCodec.
diff --git a/media/libaudioclient/AidlConversion.cpp b/media/libaudioclient/AidlConversion.cpp
index bd10e44..2377fc8 100644
--- a/media/libaudioclient/AidlConversion.cpp
+++ b/media/libaudioclient/AidlConversion.cpp
@@ -528,7 +528,7 @@
ConversionResult<media::AudioTimestampInternal>
legacy2aidl_AudioTimestamp_AudioTimestampInternal(const AudioTimestamp& legacy) {
media::AudioTimestampInternal aidl;
- aidl.position = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy.mPosition));
+ aidl.position = VALUE_OR_RETURN(convertIntegral<int64_t>(legacy.mPosition));
aidl.sec = VALUE_OR_RETURN(convertIntegral<int64_t>(legacy.mTime.tv_sec));
aidl.nsec = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy.mTime.tv_nsec));
return aidl;
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 5bf6b656..0fa814c 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -1687,13 +1687,21 @@
status_t AudioTrack::setOutputDevice(audio_port_handle_t deviceId) {
AutoMutex lock(mLock);
- ALOGV("%s(%d): deviceId=%d mSelectedDeviceId=%d",
- __func__, mPortId, deviceId, mSelectedDeviceId);
+ ALOGV("%s(%d): deviceId=%d mSelectedDeviceId=%d mRoutedDeviceId %d",
+ __func__, mPortId, deviceId, mSelectedDeviceId, mRoutedDeviceId);
if (mSelectedDeviceId != deviceId) {
mSelectedDeviceId = deviceId;
- if (mStatus == NO_ERROR) {
- android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
- mProxy->interrupt();
+ if (mStatus == NO_ERROR && mSelectedDeviceId != mRoutedDeviceId) {
+ if (isPlaying_l()) {
+ android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
+ mProxy->interrupt();
+ } else {
+ // if the track is idle, try to restore now and
+ // defer to next start if not possible
+ if (restoreTrack_l("setOutputDevice") != OK) {
+ android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
+ }
+ }
}
}
return NO_ERROR;
diff --git a/media/libaudioclient/aidl/android/media/AudioTimestampInternal.aidl b/media/libaudioclient/aidl/android/media/AudioTimestampInternal.aidl
index 8bbfb57..1f16525 100644
--- a/media/libaudioclient/aidl/android/media/AudioTimestampInternal.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioTimestampInternal.aidl
@@ -22,8 +22,11 @@
* {@hide}
*/
parcelable AudioTimestampInternal {
- /** A frame position in AudioTrack::getPosition() units. */
- int position;
+ /**
+ * A frame position in AudioTrack::getPosition() units. Use 'long' to accommodate
+ * all values from 'uint32_t'.
+ */
+ long position;
/** corresponding CLOCK_MONOTONIC when frame is expected to present. */
long sec;
int nsec;
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index b6ee483..a754dcf 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -1116,6 +1116,9 @@
bool isPlaying() {
AutoMutex lock(mLock);
+ return isPlaying_l();
+ }
+ bool isPlaying_l() {
return mState == STATE_ACTIVE || mState == STATE_STOPPING;
}
diff --git a/media/libheadtracking/HeadTrackingProcessor.cpp b/media/libheadtracking/HeadTrackingProcessor.cpp
index 8502af0..54d08d2 100644
--- a/media/libheadtracking/HeadTrackingProcessor.cpp
+++ b/media/libheadtracking/HeadTrackingProcessor.cpp
@@ -98,7 +98,7 @@
mModeSelector.setScreenStable(mWorldToScreenTimestamp.value(), screenStable);
// Whenever the screen is unstable, recenter the head pose.
if (!screenStable) {
- recenter(true, false);
+ recenter(true, false, "calculate: screen movement");
}
mScreenHeadFusion.setWorldToScreenPose(mWorldToScreenTimestamp.value(),
worldToLogicalScreen);
@@ -110,7 +110,7 @@
// Auto-recenter.
bool headStable = mHeadStillnessDetector.calculate(timestamp);
if (headStable || !screenStable) {
- recenter(true, false);
+ recenter(true, false, "calculate: head movement");
worldToHead = mHeadPoseBias.getOutput();
}
@@ -140,16 +140,16 @@
HeadTrackingMode getActualMode() const override { return mModeSelector.getActualMode(); }
- void recenter(bool recenterHead, bool recenterScreen) override {
+ void recenter(bool recenterHead, bool recenterScreen, std::string source) override {
if (recenterHead) {
mHeadPoseBias.recenter();
mHeadStillnessDetector.reset();
- mLocalLog.log("recenter Head");
+ mLocalLog.log("recenter Head from %s", source.c_str());
}
if (recenterScreen) {
mScreenPoseBias.recenter();
mScreenStillnessDetector.reset();
- mLocalLog.log("recenter Screen");
+ mLocalLog.log("recenter Screen from %s", source.c_str());
}
// If a sensor being recentered is included in the current mode, apply rate limiting to
diff --git a/media/libheadtracking/include/media/HeadTrackingProcessor.h b/media/libheadtracking/include/media/HeadTrackingProcessor.h
index a3c1e97..d2b78f2 100644
--- a/media/libheadtracking/include/media/HeadTrackingProcessor.h
+++ b/media/libheadtracking/include/media/HeadTrackingProcessor.h
@@ -96,7 +96,8 @@
/**
* This causes the current poses for both the head and/or screen to be considered "center".
*/
- virtual void recenter(bool recenterHead = true, bool recenterScreen = true) = 0;
+ virtual void recenter(
+ bool recenterHead = true, bool recenterScreen = true, std::string source = "") = 0;
/**
* Set the predictor type.
diff --git a/media/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
index 266cb17..44e78d6 100644
--- a/media/libmediaplayerservice/Android.bp
+++ b/media/libmediaplayerservice/Android.bp
@@ -17,7 +17,8 @@
],
}
-cc_library {
+filegroup {
+ name: "libmediaplayerservice_sources",
srcs: [
"ActivityManager.cpp",
@@ -30,6 +31,14 @@
"StagefrightRecorder.cpp",
"TestPlayerStub.cpp",
],
+}
+
+cc_defaults {
+ name: "libmediaplayerservice_defaults",
+
+ srcs: [
+ ":libmediaplayerservice_sources",
+ ],
shared_libs: [
"android.hardware.media.c2@1.0",
@@ -83,6 +92,24 @@
"framework-permission-aidl-cpp",
],
+ cflags: [
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ "-Wall",
+ ],
+
+ sanitize: {
+ cfi: true,
+ },
+}
+
+cc_library {
+ name: "libmediaplayerservice",
+
+ defaults: [
+ "libmediaplayerservice_defaults",
+ ],
+
export_shared_lib_headers: [
"libmedia",
"framework-permission-aidl-cpp",
@@ -92,22 +119,9 @@
"libmediautils_headers",
],
- local_include_dirs: ["include"],
-
export_include_dirs: [
".",
],
- cflags: [
- "-Werror",
- "-Wno-error=deprecated-declarations",
- "-Wall",
- ],
-
- name: "libmediaplayerservice",
-
- sanitize: {
- cfi: true,
- },
-
+ local_include_dirs: ["include"],
}
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index e5f9789..075c385 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1840,7 +1840,6 @@
} else {
mAttributes = NULL;
}
-
setMinBufferCount();
}
@@ -3038,4 +3037,11 @@
}
return NO_ERROR;
}
+
+#ifdef FUZZ_MODE_MEDIA_PLAYER_SERVICE
+sp<MediaPlayerService> MediaPlayerService::createForFuzzTesting() {
+ return sp<MediaPlayerService>::make();
+}
+#endif // FUZZ_MODE_MEDIA_PLAYER_SERVICE
+
} // namespace android
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 86be3fe..d4ee8e5 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -505,6 +505,12 @@
SortedVector< wp<Client> > mClients;
SortedVector< wp<MediaRecorderClient> > mMediaRecorderClients;
int32_t mNextConnId;
+
+#ifdef FUZZ_MODE_MEDIA_PLAYER_SERVICE
+public:
+ friend class sp<MediaPlayerService>;
+ static sp<MediaPlayerService> createForFuzzTesting();
+#endif // FUZZ_MODE_MEDIA_PLAYER_SERVICE
};
// ----------------------------------------------------------------------------
diff --git a/media/libmediaplayerservice/fuzzer/Android.bp b/media/libmediaplayerservice/fuzzer/Android.bp
index 91216cb..f564efa 100644
--- a/media/libmediaplayerservice/fuzzer/Android.bp
+++ b/media/libmediaplayerservice/fuzzer/Android.bp
@@ -139,3 +139,26 @@
"libstagefright_httplive",
],
}
+
+cc_fuzz {
+ name: "media_player_service_fuzzer",
+ defaults: [
+ "service_fuzzer_defaults",
+ "libmediaplayerservice_defaults",
+ "fuzzer_disable_leaks",
+ ],
+ srcs: [
+ "media_player_service_fuzzer.cpp",
+ ],
+ fuzz_config: {
+ cc: [
+ "kyslov@google.com",
+ "ibaker@google.com",
+ ],
+ triage_assignee: "waghpawan@google.com",
+ },
+ cflags: [
+ "-DFUZZ_MODE_MEDIA_PLAYER_SERVICE",
+ ],
+ include_dirs: ["frameworks/av/media/libmediaplayerservice/"],
+}
diff --git a/media/libmediaplayerservice/fuzzer/media_player_service_fuzzer.cpp b/media/libmediaplayerservice/fuzzer/media_player_service_fuzzer.cpp
new file mode 100644
index 0000000..4e3b0fe
--- /dev/null
+++ b/media/libmediaplayerservice/fuzzer/media_player_service_fuzzer.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2023 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.
+ */
+
+#include <fuzzbinder/libbinder_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include <MediaPlayerService.h>
+
+using android::fuzzService;
+using android::MediaPlayerService;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ auto service = MediaPlayerService::createForFuzzTesting();
+ fuzzService(service, FuzzedDataProvider(data, size));
+ return 0;
+}
diff --git a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
index 2beb47f..0e594dd 100644
--- a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
+++ b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
@@ -24,9 +24,8 @@
#include <aidl/android/media/BnResourceManagerClient.h>
#include <aidl/android/media/BnResourceManagerService.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/ProcessInfoInterface.h>
#include <mediadrm/DrmSessionManager.h>
+#include <mediautils/ProcessInfoInterface.h>
#include <algorithm>
#include <iostream>
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 842327d..967c316 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -150,7 +150,8 @@
if (camera == 0) {
mCamera = Camera::connect(cameraId, clientName, clientUid, clientPid,
- /*targetSdkVersion*/__ANDROID_API_FUTURE__, /*overrideToPortrait*/true);
+ /*targetSdkVersion*/__ANDROID_API_FUTURE__, /*overrideToPortrait*/false,
+ /*forceSlowJpegMode*/false);
if (mCamera == 0) return -EBUSY;
mCameraFlags &= ~FLAGS_HOT_CAMERA;
} else {
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 4a67876..457c625 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -19,12 +19,12 @@
#define LOG_TAG "MediaCodec"
#include <utils/Log.h>
-#include <set>
-#include <stdlib.h>
-
-#include <inttypes.h>
-#include <stdlib.h>
#include <dlfcn.h>
+#include <inttypes.h>
+#include <future>
+#include <random>
+#include <set>
+#include <string>
#include <C2Buffer.h>
@@ -99,6 +99,7 @@
// These must be kept synchronized with the constants there.
static const char *kCodecLogSessionId = "android.media.mediacodec.log-session-id";
static const char *kCodecCodec = "android.media.mediacodec.codec"; /* e.g. OMX.google.aac.decoder */
+static const char *kCodecId = "android.media.mediacodec.id";
static const char *kCodecMime = "android.media.mediacodec.mime"; /* e.g. audio/mime */
static const char *kCodecMode = "android.media.mediacodec.mode"; /* audio, video */
static const char *kCodecModeVideo = "video"; /* values returned for kCodecMode */
@@ -210,6 +211,10 @@
////////////////////////////////////////////////////////////////////////////////
+/*
+ * Implementation of IResourceManagerClient interrface that facilitates
+ * MediaCodec reclaim for the ResourceManagerService.
+ */
struct ResourceManagerClient : public BnResourceManagerClient {
explicit ResourceManagerClient(MediaCodec* codec, int32_t pid, int32_t uid) :
mMediaCodec(codec), mPid(pid), mUid(uid) {}
@@ -218,11 +223,13 @@
sp<MediaCodec> codec = mMediaCodec.promote();
if (codec == NULL) {
// Codec is already gone, so remove the resources as well
- ::ndk::SpAIBinder binder(AServiceManager_getService("media.resource_manager"));
+ ::ndk::SpAIBinder binder(AServiceManager_waitForService("media.resource_manager"));
std::shared_ptr<IResourceManagerService> service =
IResourceManagerService::fromBinder(binder);
if (service == nullptr) {
- ALOGW("MediaCodec::ResourceManagerClient unable to find ResourceManagerService");
+ ALOGE("MediaCodec::ResourceManagerClient unable to find ResourceManagerService");
+ *_aidl_return = false;
+ return Status::fromStatus(STATUS_INVALID_OPERATION);
}
ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
.uid = static_cast<int32_t>(mUid),
@@ -270,76 +277,126 @@
DISALLOW_EVIL_CONSTRUCTORS(ResourceManagerClient);
};
-struct MediaCodec::ResourceManagerServiceProxy : public RefBase {
+/*
+ * Proxy for ResourceManagerService that communicates with the
+ * ResourceManagerService for MediaCodec
+ */
+struct MediaCodec::ResourceManagerServiceProxy :
+ public std::enable_shared_from_this<ResourceManagerServiceProxy> {
+
+ // BinderDiedContext defines the cookie that is passed as DeathRecipient.
+ // Since this can maintain more context than a raw pointer, we can
+ // validate the scope of ResourceManagerServiceProxy,
+ // before deferencing it upon the binder death.
+ struct BinderDiedContext {
+ std::weak_ptr<ResourceManagerServiceProxy> mRMServiceProxy;
+ };
+
ResourceManagerServiceProxy(pid_t pid, uid_t uid,
const std::shared_ptr<IResourceManagerClient> &client);
- virtual ~ResourceManagerServiceProxy();
-
+ ~ResourceManagerServiceProxy();
status_t init();
-
- // implements DeathRecipient
- static void BinderDiedCallback(void* cookie);
- void binderDied();
- static Mutex sLockCookies;
- static std::set<void*> sCookies;
- static void addCookie(void* cookie);
- static void removeCookie(void* cookie);
-
void addResource(const MediaResourceParcel &resource);
void removeResource(const MediaResourceParcel &resource);
void removeClient();
void markClientForPendingRemoval();
bool reclaimResource(const std::vector<MediaResourceParcel> &resources);
+ void notifyClientCreated();
+ void notifyClientStarted(ClientConfigParcel& clientConfig);
+ void notifyClientStopped(ClientConfigParcel& clientConfig);
+ void notifyClientConfigChanged(ClientConfigParcel& clientConfig);
inline void setCodecName(const char* name) {
mCodecName = name;
}
private:
- Mutex mLock;
+ // To get the binder interface to ResourceManagerService.
+ void getService() {
+ std::scoped_lock lock{mLock};
+ getService_l();
+ }
+
+ std::shared_ptr<IResourceManagerService> getService_l();
+
+ // To add/register all the resources currently added/registered with
+ // the ResourceManagerService.
+ // This function will be called right after the death of the Resource
+ // Manager to make sure that the newly started ResourceManagerService
+ // knows about the current resource usage.
+ void reRegisterAllResources_l();
+
+ void deinit() {
+ std::scoped_lock lock{mLock};
+ // Unregistering from DeathRecipient notification.
+ if (mService != nullptr) {
+ AIBinder_unlinkToDeath(mService->asBinder().get(), mDeathRecipient.get(), this);
+ mService = nullptr;
+ }
+ }
+
+ // For binder death handling
+ static void BinderDiedCallback(void* cookie);
+ static void BinderUnlinkedCallback(void* cookie);
+
+ void binderDied() {
+ std::scoped_lock lock{mLock};
+ ALOGE("ResourceManagerService died.");
+ mService = nullptr;
+ mBinderDied = true;
+ // start an async operation that will reconnect with the RM and
+ // re-registers all the resources.
+ mGetServiceFuture = std::async(std::launch::async, [this] { getService(); });
+ }
+
+
+private:
+ std::mutex mLock;
pid_t mPid;
uid_t mUid;
+ bool mBinderDied = false;
std::string mCodecName;
- std::shared_ptr<IResourceManagerService> mService;
+ /**
+ * Reconnecting with the ResourceManagerService, after its binder interface dies,
+ * is done asynchronously. It will also make sure that, all the resources
+ * asssociated with this Proxy (MediaCodec) is added with the new instance
+ * of the ResourceManagerService to persist the state of resources.
+ * We must store the reference of the furture to guarantee real asynchronous operation.
+ */
+ std::future<void> mGetServiceFuture;
+ // To maintain the list of all the resources currently added/registered with
+ // the ResourceManagerService.
+ std::set<MediaResourceParcel> mMediaResourceParcel;
std::shared_ptr<IResourceManagerClient> mClient;
::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+ std::shared_ptr<IResourceManagerService> mService;
};
MediaCodec::ResourceManagerServiceProxy::ResourceManagerServiceProxy(
- pid_t pid, uid_t uid, const std::shared_ptr<IResourceManagerClient> &client)
- : mPid(pid), mUid(uid), mClient(client),
- mDeathRecipient(AIBinder_DeathRecipient_new(BinderDiedCallback)) {
+ pid_t pid, uid_t uid, const std::shared_ptr<IResourceManagerClient> &client) :
+ mPid(pid), mUid(uid), mClient(client),
+ mDeathRecipient(::ndk::ScopedAIBinder_DeathRecipient(
+ AIBinder_DeathRecipient_new(BinderDiedCallback))) {
if (mUid == MediaCodec::kNoUid) {
mUid = AIBinder_getCallingUid();
}
if (mPid == MediaCodec::kNoPid) {
mPid = AIBinder_getCallingPid();
}
+ // Setting callback notification when DeathRecipient gets deleted.
+ AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), BinderUnlinkedCallback);
}
MediaCodec::ResourceManagerServiceProxy::~ResourceManagerServiceProxy() {
-
- // remove the cookie, so any in-flight death notification will get dropped
- // by our handler.
- removeCookie(this);
-
- Mutex::Autolock _l(mLock);
- if (mService != nullptr) {
- AIBinder_unlinkToDeath(mService->asBinder().get(), mDeathRecipient.get(), this);
- mService = nullptr;
- }
+ deinit();
}
status_t MediaCodec::ResourceManagerServiceProxy::init() {
- ::ndk::SpAIBinder binder(AServiceManager_getService("media.resource_manager"));
- mService = IResourceManagerService::fromBinder(binder);
- if (mService == nullptr) {
- ALOGE("Failed to get ResourceManagerService");
- return UNKNOWN_ERROR;
- }
+ std::scoped_lock lock{mLock};
int callerPid = AIBinder_getCallingPid();
int callerUid = AIBinder_getCallingUid();
+
if (mPid != callerPid || mUid != callerUid) {
// Media processes don't need special permissions to act on behalf of other processes.
if (callerUid != AID_MEDIA) {
@@ -352,60 +409,57 @@
}
}
+ mService = getService_l();
+ if (mService == nullptr) {
+ return DEAD_OBJECT;
+ }
+
// Kill clients pending removal.
mService->reclaimResourcesFromClientsPendingRemoval(mPid);
-
- // so our handler will process the death notifications
- addCookie(this);
-
- // after this, require mLock whenever using mService
- AIBinder_linkToDeath(mService->asBinder().get(), mDeathRecipient.get(), this);
return OK;
}
-//static
-// these are no_destroy to keep them from being destroyed at process exit
-// where some thread calls exit() while other threads are still running.
-// see b/194783918
-[[clang::no_destroy]] Mutex MediaCodec::ResourceManagerServiceProxy::sLockCookies;
-[[clang::no_destroy]] std::set<void*> MediaCodec::ResourceManagerServiceProxy::sCookies;
-
-//static
-void MediaCodec::ResourceManagerServiceProxy::addCookie(void* cookie) {
- Mutex::Autolock _l(sLockCookies);
- sCookies.insert(cookie);
-}
-
-//static
-void MediaCodec::ResourceManagerServiceProxy::removeCookie(void* cookie) {
- Mutex::Autolock _l(sLockCookies);
- sCookies.erase(cookie);
-}
-
-//static
-void MediaCodec::ResourceManagerServiceProxy::BinderDiedCallback(void* cookie) {
- Mutex::Autolock _l(sLockCookies);
- if (sCookies.find(cookie) != sCookies.end()) {
- auto thiz = static_cast<ResourceManagerServiceProxy*>(cookie);
- thiz->binderDied();
+std::shared_ptr<IResourceManagerService> MediaCodec::ResourceManagerServiceProxy::getService_l() {
+ if (mService != nullptr) {
+ return mService;
}
-}
-void MediaCodec::ResourceManagerServiceProxy::binderDied() {
- ALOGW("ResourceManagerService died.");
- Mutex::Autolock _l(mLock);
- mService = nullptr;
-}
-
-void MediaCodec::ResourceManagerServiceProxy::addResource(
- const MediaResourceParcel &resource) {
- std::vector<MediaResourceParcel> resources;
- resources.push_back(resource);
-
- Mutex::Autolock _l(mLock);
+ // Get binder interface to resource manager.
+ ::ndk::SpAIBinder binder(AServiceManager_waitForService("media.resource_manager"));
+ mService = IResourceManagerService::fromBinder(binder);
if (mService == nullptr) {
+ ALOGE("Failed to get ResourceManagerService");
+ return mService;
+ }
+
+ // Create the context that is passed as cookie to the binder death notification.
+ // The context gets deleted at BinderUnlinkedCallback.
+ BinderDiedContext* context = new BinderDiedContext{.mRMServiceProxy = weak_from_this()};
+ // Register for the callbacks by linking to death notification.
+ AIBinder_linkToDeath(mService->asBinder().get(), mDeathRecipient.get(), context);
+
+ // If the RM was restarted, re-register all the resources.
+ if (mBinderDied) {
+ reRegisterAllResources_l();
+ mBinderDied = false;
+ }
+ return mService;
+}
+
+void MediaCodec::ResourceManagerServiceProxy::reRegisterAllResources_l() {
+ if (mMediaResourceParcel.empty()) {
+ ALOGV("No resources to add");
return;
}
+
+ if (mService == nullptr) {
+ ALOGW("Service isn't available");
+ return;
+ }
+
+ std::vector<MediaResourceParcel> resources;
+ std::copy(mMediaResourceParcel.begin(), mMediaResourceParcel.end(),
+ std::back_inserter(resources));
ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
.uid = static_cast<int32_t>(mUid),
.id = getId(mClient),
@@ -413,50 +467,98 @@
mService->addResource(clientInfo, mClient, resources);
}
-void MediaCodec::ResourceManagerServiceProxy::removeResource(
- const MediaResourceParcel &resource) {
- std::vector<MediaResourceParcel> resources;
- resources.push_back(resource);
+void MediaCodec::ResourceManagerServiceProxy::BinderDiedCallback(void* cookie) {
+ BinderDiedContext* context = reinterpret_cast<BinderDiedContext*>(cookie);
- Mutex::Autolock _l(mLock);
- if (mService == nullptr) {
+ // Validate the context and check if the ResourceManagerServiceProxy object is still in scope.
+ if (context != nullptr) {
+ std::shared_ptr<ResourceManagerServiceProxy> thiz = context->mRMServiceProxy.lock();
+ if (thiz != nullptr) {
+ thiz->binderDied();
+ } else {
+ ALOGI("ResourceManagerServiceProxy is out of scope already");
+ }
+ }
+}
+
+void MediaCodec::ResourceManagerServiceProxy::BinderUnlinkedCallback(void* cookie) {
+ BinderDiedContext* context = reinterpret_cast<BinderDiedContext*>(cookie);
+ // Since we don't need the context anymore, we are deleting it now.
+ delete context;
+}
+
+void MediaCodec::ResourceManagerServiceProxy::addResource(
+ const MediaResourceParcel &resource) {
+ std::scoped_lock lock{mLock};
+ std::shared_ptr<IResourceManagerService> service = getService_l();
+ if (service == nullptr) {
+ ALOGW("Service isn't available");
return;
}
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(resource);
ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
.uid = static_cast<int32_t>(mUid),
.id = getId(mClient),
.name = mCodecName};
- mService->removeResource(clientInfo, resources);
+ service->addResource(clientInfo, mClient, resources);
+ mMediaResourceParcel.emplace(resource);
+}
+
+void MediaCodec::ResourceManagerServiceProxy::removeResource(
+ const MediaResourceParcel &resource) {
+ std::scoped_lock lock{mLock};
+ std::shared_ptr<IResourceManagerService> service = getService_l();
+ if (service == nullptr) {
+ ALOGW("Service isn't available");
+ return;
+ }
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(resource);
+ ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
+ .uid = static_cast<int32_t>(mUid),
+ .id = getId(mClient),
+ .name = mCodecName};
+ service->removeResource(clientInfo, resources);
+ mMediaResourceParcel.erase(resource);
}
void MediaCodec::ResourceManagerServiceProxy::removeClient() {
- Mutex::Autolock _l(mLock);
- if (mService == nullptr) {
+ std::scoped_lock lock{mLock};
+ std::shared_ptr<IResourceManagerService> service = getService_l();
+ if (service == nullptr) {
+ ALOGW("Service isn't available");
return;
}
ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
.uid = static_cast<int32_t>(mUid),
.id = getId(mClient),
.name = mCodecName};
- mService->removeClient(clientInfo);
+ service->removeClient(clientInfo);
+ mMediaResourceParcel.clear();
}
void MediaCodec::ResourceManagerServiceProxy::markClientForPendingRemoval() {
- Mutex::Autolock _l(mLock);
- if (mService == nullptr) {
+ std::scoped_lock lock{mLock};
+ std::shared_ptr<IResourceManagerService> service = getService_l();
+ if (service == nullptr) {
+ ALOGW("Service isn't available");
return;
}
ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
.uid = static_cast<int32_t>(mUid),
.id = getId(mClient),
.name = mCodecName};
- mService->markClientForPendingRemoval(clientInfo);
+ service->markClientForPendingRemoval(clientInfo);
+ mMediaResourceParcel.clear();
}
bool MediaCodec::ResourceManagerServiceProxy::reclaimResource(
const std::vector<MediaResourceParcel> &resources) {
- Mutex::Autolock _l(mLock);
- if (mService == NULL) {
+ std::scoped_lock lock{mLock};
+ std::shared_ptr<IResourceManagerService> service = getService_l();
+ if (service == nullptr) {
+ ALOGW("Service isn't available");
return false;
}
bool success;
@@ -464,10 +566,69 @@
.uid = static_cast<int32_t>(mUid),
.id = getId(mClient),
.name = mCodecName};
- Status status = mService->reclaimResource(clientInfo, resources, &success);
+ Status status = service->reclaimResource(clientInfo, resources, &success);
return status.isOk() && success;
}
+void MediaCodec::ResourceManagerServiceProxy::notifyClientCreated() {
+ std::scoped_lock lock{mLock};
+ std::shared_ptr<IResourceManagerService> service = getService_l();
+ if (service == nullptr) {
+ ALOGW("Service isn't available");
+ return;
+ }
+ ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
+ .uid = static_cast<int32_t>(mUid),
+ .id = getId(mClient),
+ .name = mCodecName};
+ service->notifyClientCreated(clientInfo);
+}
+
+void MediaCodec::ResourceManagerServiceProxy::notifyClientStarted(
+ ClientConfigParcel& clientConfig) {
+ std::scoped_lock lock{mLock};
+ std::shared_ptr<IResourceManagerService> service = getService_l();
+ if (service == nullptr) {
+ ALOGW("Service isn't available");
+ return;
+ }
+ clientConfig.clientInfo.pid = static_cast<int32_t>(mPid);
+ clientConfig.clientInfo.uid = static_cast<int32_t>(mUid);
+ clientConfig.clientInfo.id = getId(mClient);
+ clientConfig.clientInfo.name = mCodecName;
+ service->notifyClientStarted(clientConfig);
+}
+
+void MediaCodec::ResourceManagerServiceProxy::notifyClientStopped(
+ ClientConfigParcel& clientConfig) {
+ std::scoped_lock lock{mLock};
+ std::shared_ptr<IResourceManagerService> service = getService_l();
+ if (service == nullptr) {
+ ALOGW("Service isn't available");
+ return;
+ }
+ clientConfig.clientInfo.pid = static_cast<int32_t>(mPid);
+ clientConfig.clientInfo.uid = static_cast<int32_t>(mUid);
+ clientConfig.clientInfo.id = getId(mClient);
+ clientConfig.clientInfo.name = mCodecName;
+ service->notifyClientStopped(clientConfig);
+}
+
+void MediaCodec::ResourceManagerServiceProxy::notifyClientConfigChanged(
+ ClientConfigParcel& clientConfig) {
+ std::scoped_lock lock{mLock};
+ std::shared_ptr<IResourceManagerService> service = getService_l();
+ if (service == nullptr) {
+ ALOGW("Service isn't available");
+ return;
+ }
+ clientConfig.clientInfo.pid = static_cast<int32_t>(mPid);
+ clientConfig.clientInfo.uid = static_cast<int32_t>(mUid);
+ clientConfig.clientInfo.id = getId(mClient);
+ clientConfig.clientInfo.name = mCodecName;
+ service->notifyClientConfigChanged(clientConfig);
+}
+
////////////////////////////////////////////////////////////////////////////////
MediaCodec::BufferInfo::BufferInfo() : mOwnedByClient(false) {}
@@ -825,6 +986,23 @@
return new PersistentSurface(bufferProducer, bufferSource);
}
+// GenerateCodecId generates a 64bit Random ID for each codec that is created.
+// The Codec ID is generated as:
+// - A process-unique random high 32bits
+// - An atomic sequence low 32bits
+//
+static uint64_t GenerateCodecId() {
+ static std::atomic_uint64_t sId = [] {
+ std::random_device rd;
+ std::mt19937 gen(rd());
+ std::uniform_int_distribution<uint32_t> distrib(0, UINT32_MAX);
+ uint32_t randomID = distrib(gen);
+ uint64_t id = randomID;
+ return id << 32;
+ }();
+ return sId++;
+}
+
MediaCodec::MediaCodec(
const sp<ALooper> &looper, pid_t pid, uid_t uid,
std::function<sp<CodecBase>(const AString &, const char *)> getCodecBase,
@@ -867,7 +1045,8 @@
mInputBufferCounter(0),
mGetCodecBase(getCodecBase),
mGetCodecInfo(getCodecInfo) {
- mResourceManagerProxy = new ResourceManagerServiceProxy(pid, uid,
+ mCodecId = GenerateCodecId();
+ mResourceManagerProxy = std::make_shared<ResourceManagerServiceProxy>(pid, uid,
::ndk::SharedRefBase::make<ResourceManagerClient>(this, pid, uid));
if (!mGetCodecBase) {
mGetCodecBase = [](const AString &name, const char *owner) {
@@ -1755,6 +1934,12 @@
break;
}
}
+
+ if (OK == err) {
+ // Notify the ResourceManager that, this codec has been created
+ // (initialized) successfully.
+ mResourceManagerProxy->notifyClientCreated();
+ }
return err;
}
@@ -1808,6 +1993,7 @@
format->findString("log-session-id", &mLogSessionId);
if (nextMetricsHandle != 0) {
+ mediametrics_setInt64(nextMetricsHandle, kCodecId, mCodecId);
int32_t profile = 0;
if (format->findInt32("profile", &profile)) {
mediametrics_setInt32(nextMetricsHandle, kCodecProfile, profile);
@@ -1971,9 +2157,11 @@
std::vector<MediaResourceParcel> resources;
resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure,
toMediaResourceSubType(mDomain)));
- // Don't know the buffer size at this point, but it's fine to use 1 because
- // the reclaimResource call doesn't consider the requester's buffer size for now.
- resources.push_back(MediaResource::GraphicMemoryResource(1));
+ if (mDomain == DOMAIN_VIDEO || mDomain == DOMAIN_IMAGE) {
+ // Don't know the buffer size at this point, but it's fine to use 1 because
+ // the reclaimResource call doesn't consider the requester's buffer size for now.
+ resources.push_back(MediaResource::GraphicMemoryResource(1));
+ }
for (int i = 0; i <= kMaxRetry; ++i) {
sp<AMessage> response;
err = PostAndAwaitResponse(msg, &response);
@@ -2574,9 +2762,11 @@
std::vector<MediaResourceParcel> resources;
resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure,
toMediaResourceSubType(mDomain)));
- // Don't know the buffer size at this point, but it's fine to use 1 because
- // the reclaimResource call doesn't consider the requester's buffer size for now.
- resources.push_back(MediaResource::GraphicMemoryResource(1));
+ if (mDomain == DOMAIN_VIDEO || mDomain == DOMAIN_IMAGE) {
+ // Don't know the buffer size at this point, but it's fine to use 1 because
+ // the reclaimResource call doesn't consider the requester's buffer size for now.
+ resources.push_back(MediaResource::GraphicMemoryResource(1));
+ }
for (int i = 0; i <= kMaxRetry; ++i) {
if (i > 0) {
// Don't try to reclaim resource for the first time.
@@ -3320,6 +3510,17 @@
return true;
}
+
+inline void MediaCodec::initClientConfigParcel(ClientConfigParcel& clientConfig) {
+ clientConfig.codecType = toMediaResourceSubType(mDomain);
+ clientConfig.isEncoder = mFlags & kFlagIsEncoder;
+ clientConfig.isHardware = !MediaCodecList::isSoftwareCodec(mComponentName);
+ clientConfig.width = mWidth;
+ clientConfig.height = mHeight;
+ clientConfig.timeStamp = systemTime(SYSTEM_TIME_MONOTONIC) / 1000LL;
+ clientConfig.id = mCodecId;
+}
+
void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatCodecNotify:
@@ -3548,14 +3749,8 @@
mediametrics_setInt32(mMetricsHandle, kCodecSecure, 0);
}
- MediaCodecInfo::Attributes attr = mCodecInfo
- ? mCodecInfo->getAttributes()
- : MediaCodecInfo::Attributes(0);
- if (mDomain == DOMAIN_VIDEO || !(attr & MediaCodecInfo::kFlagIsSoftwareOnly)) {
- // software audio codecs are currently ignored.
- mResourceManagerProxy->addResource(MediaResource::CodecResource(
+ mResourceManagerProxy->addResource(MediaResource::CodecResource(
mFlags & kFlagIsSecure, toMediaResourceSubType(mDomain)));
- }
postPendingRepliesAndDeferredMessages("kWhatComponentAllocated");
break;
@@ -3725,6 +3920,11 @@
mResourceManagerProxy->addResource(
MediaResource::GraphicMemoryResource(getGraphicBufferSize()));
}
+ // Notify the RM that the codec is in use (has been started).
+ ClientConfigParcel clientConfig;
+ initClientConfigParcel(clientConfig);
+ mResourceManagerProxy->notifyClientStarted(clientConfig);
+
setState(STARTED);
postPendingRepliesAndDeferredMessages("kWhatStartCompleted");
@@ -3940,6 +4140,11 @@
mState, stateString(mState).c_str());
break;
}
+ // Notify the RM that the codec has been stopped.
+ ClientConfigParcel clientConfig;
+ initClientConfigParcel(clientConfig);
+ mResourceManagerProxy->notifyClientStopped(clientConfig);
+
setState(INITIALIZED);
if (mReplyID) {
postPendingRepliesAndDeferredMessages("kWhatStopCompleted");
@@ -5026,15 +5231,28 @@
postActivityNotificationIfPossible();
}
- // Notify mCrypto of video resolution changes
- if (mCrypto != NULL) {
- int32_t left, top, right, bottom, width, height;
- if (mOutputFormat->findRect("crop", &left, &top, &right, &bottom)) {
- mCrypto->notifyResolution(right - left + 1, bottom - top + 1);
- } else if (mOutputFormat->findInt32("width", &width)
- && mOutputFormat->findInt32("height", &height)) {
- mCrypto->notifyResolution(width, height);
+ // Update the width and the height.
+ int32_t left = 0, top = 0, right = 0, bottom = 0, width = 0, height = 0;
+ bool resolutionChanged = false;
+ if (mOutputFormat->findRect("crop", &left, &top, &right, &bottom)) {
+ mWidth = right - left + 1;
+ mHeight = bottom - top + 1;
+ resolutionChanged = true;
+ } else if (mOutputFormat->findInt32("width", &width) &&
+ mOutputFormat->findInt32("height", &height)) {
+ mWidth = width;
+ mHeight = height;
+ resolutionChanged = true;
+ }
+
+ // Notify mCrypto and the RM of video resolution changes
+ if (resolutionChanged) {
+ if (mCrypto != NULL) {
+ mCrypto->notifyResolution(mWidth, mHeight);
}
+ ClientConfigParcel clientConfig;
+ initClientConfigParcel(clientConfig);
+ mResourceManagerProxy->notifyClientConfigChanged(clientConfig);
}
updateHdrMetrics(false /* isConfig */);
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 0536f2a..d736734 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -639,9 +639,11 @@
numPageSamples = -1;
}
+ // insert, including accounting for the space used.
memcpy((uint8_t *)buffer->data() + mbuf->range_length(),
&numPageSamples,
sizeof(numPageSamples));
+ buffer->setRange(buffer->offset(), buffer->size() + sizeof(numPageSamples));
uint32_t type;
const void *data;
@@ -690,6 +692,8 @@
ssize_t minIndex = fetchAllTrackSamples();
+ buffer->setRange(0, 0); // start with an empty buffer
+
if (minIndex < 0) {
return ERROR_END_OF_STREAM;
}
@@ -705,25 +709,25 @@
sampleSize += sizeof(int32_t);
}
+ // capacity() is ok since we cleared out the buffer
if (buffer->capacity() < sampleSize) {
return -ENOMEM;
}
+ const size_t srclen = it->mBuffer->range_length();
const uint8_t *src =
(const uint8_t *)it->mBuffer->data()
+ it->mBuffer->range_offset();
- memcpy((uint8_t *)buffer->data(), src, it->mBuffer->range_length());
+ memcpy((uint8_t *)buffer->data(), src, srclen);
+ buffer->setRange(0, srclen);
status_t err = OK;
if (info->mTrackFlags & kIsVorbis) {
+ // adjusts range when it inserts the extra bits
err = appendVorbisNumPageSamples(it->mBuffer, buffer);
}
- if (err == OK) {
- buffer->setRange(0, sampleSize);
- }
-
return err;
}
diff --git a/media/libstagefright/SurfaceUtils.cpp b/media/libstagefright/SurfaceUtils.cpp
index f26311d..291b892 100644
--- a/media/libstagefright/SurfaceUtils.cpp
+++ b/media/libstagefright/SurfaceUtils.cpp
@@ -250,6 +250,11 @@
static_cast<Surface*>(nativeWindow)->getIGraphicBufferProducer()->allowAllocation(true);
+ // In nonblocking mode(timetout = 0), native_window_dequeue_buffer_and_wait()
+ // can fail with timeout. Changing to blocking mode will ensure that dequeue
+ // does not timeout.
+ static_cast<Surface*>(nativeWindow)->getIGraphicBufferProducer()->setDequeueTimeout(-1);
+
err = nativeWindow->query(nativeWindow,
NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs);
if (err != NO_ERROR) {
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index 4b4f65f..4df79ef 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -340,6 +340,14 @@
return mCropBottom - mCropTop + 1;
}
+bool ColorConverter::BitmapParams::isValid() const {
+ if (!((mStride & 1) == 0 // stride must be even
+ && mStride >= mBpp * cropWidth())) {
+ return false;
+ }
+ return true;
+}
+
status_t ColorConverter::convert(
const void *srcBits,
size_t srcWidth, size_t srcHeight, size_t srcStride,
@@ -359,9 +367,11 @@
dstWidth, dstHeight, dstStride,
dstCropLeft, dstCropTop, dstCropRight, dstCropBottom, mDstFormat);
- if (!((src.mCropLeft & 1) == 0
- && src.cropWidth() == dst.cropWidth()
- && src.cropHeight() == dst.cropHeight())) {
+ if (!(src.isValid()
+ && dst.isValid()
+ && (src.mCropLeft & 1) == 0
+ && src.cropWidth() == dst.cropWidth()
+ && src.cropHeight() == dst.cropHeight())) {
return ERROR_UNSUPPORTED;
}
@@ -463,6 +473,7 @@
}
}
+// Interleaved YUV 422 CbYCrY to RGB565
status_t ColorConverter::convertCbYCrY(
const BitmapParams &src, const BitmapParams &dst) {
// XXX Untested
@@ -485,10 +496,10 @@
+ dst.mCropTop * dst.mWidth + dst.mCropLeft;
const uint8_t *src_ptr = (const uint8_t *)src.mBits
- + (src.mCropTop * dst.mWidth + src.mCropLeft) * 2;
+ + (src.mCropTop * src.mWidth + src.mCropLeft) * 2;
for (size_t y = 0; y < src.cropHeight(); ++y) {
- for (size_t x = 0; x < src.cropWidth(); x += 2) {
+ for (size_t x = 0; x < src.cropWidth() - 1; x += 2) {
signed y1 = (signed)src_ptr[2 * x + 1] - _c16;
signed y2 = (signed)src_ptr[2 * x + 3] - _c16;
signed u = (signed)src_ptr[2 * x] - 128;
@@ -658,13 +669,15 @@
*u = ((uint8_t*)src_u)[x / 2] - 128;
*v = ((uint8_t*)src_v)[x / 2] - 128;
};
+ // this format stores 10 bits content with 16 bits
+ // converting it to 8 bits src
case OMX_COLOR_FormatYUV420Planar16:
return [](void *src_y, void *src_u, void *src_v, size_t x,
signed *y1, signed *y2, signed *u, signed *v) {
- *y1 = (signed)(((uint16_t*)src_y)[x] >> 2);
- *y2 = (signed)(((uint16_t*)src_y)[x + 1] >> 2);
- *u = (signed)(((uint16_t*)src_u)[x / 2] >> 2) - 128;
- *v = (signed)(((uint16_t*)src_v)[x / 2] >> 2) - 128;
+ *y1 = (uint8_t)(((uint16_t*)src_y)[x] >> 2);
+ *y2 = (uint8_t)(((uint16_t*)src_y)[x + 1] >> 2);
+ *u = (uint8_t)(((uint16_t*)src_u)[x / 2] >> 2) - 128;
+ *v = (uint8_t)(((uint16_t*)src_v)[x / 2] >> 2) - 128;
};
default:
TRESPASS();
@@ -1122,46 +1135,25 @@
status_t ColorConverter::convertQCOMYUV420SemiPlanar(
const BitmapParams &src, const BitmapParams &dst) {
- const uint8_t *src_y =
- (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft;
-
- const uint8_t *src_u =
- (const uint8_t *)src_y + src.mWidth * src.mHeight
- + src.mCropTop * src.mWidth + src.mCropLeft;
-
/* QCOMYUV420SemiPlanar is NV21, while MediaCodec uses NV12 */
return convertYUV420SemiPlanarBase(
- src, dst, src_y, src_u, src.mWidth /* row_inc */, true /* isNV21 */);
+ src, dst, src.mWidth /* row_inc */, true /* isNV21 */);
}
status_t ColorConverter::convertTIYUV420PackedSemiPlanar(
const BitmapParams &src, const BitmapParams &dst) {
- const uint8_t *src_y =
- (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft;
-
- const uint8_t *src_u =
- (const uint8_t *)src_y + src.mWidth * (src.mHeight - src.mCropTop / 2);
-
return convertYUV420SemiPlanarBase(
- src, dst, src_y, src_u, src.mWidth /* row_inc */);
+ src, dst, src.mWidth /* row_inc */);
}
status_t ColorConverter::convertYUV420SemiPlanar(
const BitmapParams &src, const BitmapParams &dst) {
- const uint8_t *src_y =
- (const uint8_t *)src.mBits + src.mCropTop * src.mStride + src.mCropLeft;
-
- const uint8_t *src_u =
- (const uint8_t *)src.mBits + src.mHeight * src.mStride +
- (src.mCropTop / 2) * src.mStride + src.mCropLeft;
-
return convertYUV420SemiPlanarBase(
- src, dst, src_y, src_u, src.mStride /* row_inc */);
+ src, dst, src.mStride /* row_inc */);
}
-status_t ColorConverter::convertYUV420SemiPlanarBase(
- const BitmapParams &src, const BitmapParams &dst,
- const uint8_t *src_y, const uint8_t *src_u, size_t row_inc, bool isNV21) {
+status_t ColorConverter::convertYUV420SemiPlanarBase(const BitmapParams &src,
+ const BitmapParams &dst, size_t row_inc, bool isNV21) {
const struct Coeffs *matrix = getMatrix();
if (!matrix) {
return ERROR_UNSUPPORTED;
@@ -1179,6 +1171,12 @@
uint16_t *dst_ptr = (uint16_t *)((uint8_t *)
dst.mBits + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp);
+ const uint8_t *src_y =
+ (const uint8_t *)src.mBits + src.mCropTop * row_inc + src.mCropLeft;
+
+ const uint8_t *src_u = (const uint8_t *)src.mBits + src.mHeight * row_inc +
+ (src.mCropTop / 2) * row_inc + src.mCropLeft;
+
for (size_t y = 0; y < src.cropHeight(); ++y) {
for (size_t x = 0; x < src.cropWidth(); x += 2) {
signed y1 = (signed)src_y[x] - _c16;
diff --git a/media/libstagefright/include/media/stagefright/ColorConverter.h b/media/libstagefright/include/media/stagefright/ColorConverter.h
index 7a05f00..da3267e 100644
--- a/media/libstagefright/include/media/stagefright/ColorConverter.h
+++ b/media/libstagefright/include/media/stagefright/ColorConverter.h
@@ -74,6 +74,8 @@
size_t cropWidth() const;
size_t cropHeight() const;
+ bool isValid() const;
+
void *mBits;
OMX_COLOR_FORMATTYPE mColorFormat;
size_t mWidth, mHeight;
@@ -121,7 +123,7 @@
status_t convertYUV420SemiPlanarBase(
const BitmapParams &src, const BitmapParams &dst,
- const uint8_t *src_y, const uint8_t *src_u, size_t row_inc, bool isNV21 = false);
+ size_t row_inc, bool isNV21 = false);
status_t convertTIYUV420PackedSemiPlanar(
const BitmapParams &src, const BitmapParams &dst);
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index ec2d13b..7bc2ca0 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -40,6 +40,7 @@
namespace android {
namespace media {
class MediaResourceParcel;
+class ClientConfigParcel;
} // media
} // android
} // aidl
@@ -71,6 +72,7 @@
using hardware::cas::native::V1_0::IDescrambler;
using aidl::android::media::MediaResourceParcel;
+using aidl::android::media::ClientConfigParcel;
struct MediaCodec : public AHandler {
enum Domain {
@@ -445,6 +447,8 @@
void updateTunnelPeek(const sp<AMessage> &msg);
void updatePlaybackDuration(const sp<AMessage> &msg);
+ inline void initClientConfigParcel(ClientConfigParcel& clientConfig);
+
sp<AMessage> mOutputFormat;
sp<AMessage> mInputFormat;
sp<AMessage> mCallback;
@@ -452,7 +456,7 @@
sp<AMessage> mAsyncReleaseCompleteNotification;
sp<AMessage> mOnFirstTunnelFrameReadyNotification;
- sp<ResourceManagerServiceProxy> mResourceManagerProxy;
+ std::shared_ptr<ResourceManagerServiceProxy> mResourceManagerProxy;
Domain mDomain;
AString mLogSessionId;
@@ -691,6 +695,8 @@
};
Histogram mLatencyHist;
+ // An unique ID for the codec - Used by the metrics.
+ uint64_t mCodecId = 0;
std::function<sp<CodecBase>(const AString &, const char *)> mGetCodecBase;
std::function<status_t(const AString &, sp<MediaCodecInfo> *)> mGetCodecInfo;
diff --git a/media/libstagefright/include/media/stagefright/ProcessInfoInterface.h b/media/libstagefright/include/media/stagefright/ProcessInfoInterface.h
deleted file mode 100644
index b7fc858..0000000
--- a/media/libstagefright/include/media/stagefright/ProcessInfoInterface.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#ifndef PROCESS_INFO_INTERFACE_H_
-#define PROCESS_INFO_INTERFACE_H_
-
-#include <utils/RefBase.h>
-
-namespace android {
-
-struct ProcessInfoInterface : public RefBase {
- virtual bool getPriority(int pid, int* priority) = 0;
- virtual bool isPidTrusted(int pid) = 0;
- virtual bool isPidUidTrusted(int pid, int uid) = 0;
- virtual bool overrideProcessInfo(int pid, int procState, int oomScore);
- virtual void removeProcessInfoOverride(int pid);
-
-protected:
- virtual ~ProcessInfoInterface() {}
-};
-
-} // namespace android
-
-#endif // PROCESS_INFO_INTERFACE_H_
diff --git a/media/utils/ProcessInfo.cpp b/media/utils/ProcessInfo.cpp
index 8437222..6296351 100644
--- a/media/utils/ProcessInfo.cpp
+++ b/media/utils/ProcessInfo.cpp
@@ -18,7 +18,7 @@
#define LOG_TAG "ProcessInfo"
#include <utils/Log.h>
-#include <media/stagefright/ProcessInfo.h>
+#include <mediautils/ProcessInfo.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
@@ -30,10 +30,64 @@
static constexpr int32_t INVALID_ADJ = -10000;
static constexpr int32_t NATIVE_ADJ = -1000;
+/* Make sure this matches with ActivityManager::PROCESS_STATE_NONEXISTENT
+ * #include <binder/ActivityManager.h>
+ * using ActivityManager::PROCESS_STATE_NONEXISTENT;
+ */
+static constexpr int32_t PROCESS_STATE_NONEXISTENT = 20;
+
ProcessInfo::ProcessInfo() {}
+/*
+ * Checks whether the list of processes with given pids exist or not.
+ *
+ * Arguments:
+ * - pids (input): List of pids for which to check whether they are Existent or not.
+ * - existent (output): boolean vector corresponds to Existent state of each pids.
+ *
+ * On successful return:
+ * - existent[i] true corresponds to pids[i] still active and
+ * - existent[i] false corresponds to pids[i] already terminated (Nonexistent)
+ * On unsuccessful return, the output argument existent is invalid.
+ */
+bool ProcessInfo::checkProcessExistent(const std::vector<int32_t>& pids,
+ std::vector<bool>* existent) {
+ sp<IBinder> binder = defaultServiceManager()->waitForService(String16("processinfo"));
+ sp<IProcessInfoService> service = interface_cast<IProcessInfoService>(binder);
+
+ // Get the process state of the applications managed/tracked by the ActivityManagerService.
+ // Don't have to look into the native processes.
+ // If we really need the state of native process, then we can use ==> mOverrideMap
+ size_t count = pids.size();
+ std::vector<int32_t> states(count, PROCESS_STATE_NONEXISTENT);
+ status_t err = service->getProcessStatesFromPids(count,
+ const_cast<int32_t*>(pids.data()),
+ states.data());
+ if (err != OK) {
+ ALOGE("%s: IProcessInfoService::getProcessStatesFromPids failed with %d",
+ __func__, err);
+ return false;
+ }
+
+ existent->clear();
+ for (size_t index = 0; index < states.size(); index++) {
+ // If this process is not tracked by ActivityManagerService, look for overrides.
+ if (states[index] == PROCESS_STATE_NONEXISTENT) {
+ std::scoped_lock lock{mOverrideLock};
+ std::map<int, ProcessInfoOverride>::iterator it =
+ mOverrideMap.find(pids[index]);
+ if (it != mOverrideMap.end()) {
+ states[index] = it->second.procState;
+ }
+ }
+ existent->push_back(states[index] != PROCESS_STATE_NONEXISTENT);
+ }
+
+ return true;
+}
+
bool ProcessInfo::getPriority(int pid, int* priority) {
- sp<IBinder> binder = defaultServiceManager()->getService(String16("processinfo"));
+ sp<IBinder> binder = defaultServiceManager()->waitForService(String16("processinfo"));
sp<IProcessInfoService> service = interface_cast<IProcessInfoService>(binder);
size_t length = 1;
diff --git a/media/libstagefright/include/media/stagefright/ProcessInfo.h b/media/utils/include/mediautils/ProcessInfo.h
similarity index 88%
rename from media/libstagefright/include/media/stagefright/ProcessInfo.h
rename to media/utils/include/mediautils/ProcessInfo.h
index 06b9c92..eb1efd6 100644
--- a/media/libstagefright/include/media/stagefright/ProcessInfo.h
+++ b/media/utils/include/mediautils/ProcessInfo.h
@@ -19,7 +19,7 @@
#define PROCESS_INFO_H_
#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/ProcessInfoInterface.h>
+#include <mediautils/ProcessInfoInterface.h>
#include <map>
#include <mutex>
#include <utils/Condition.h>
@@ -34,6 +34,8 @@
virtual bool isPidUidTrusted(int pid, int uid);
virtual bool overrideProcessInfo(int pid, int procState, int oomScore);
virtual void removeProcessInfoOverride(int pid);
+ bool checkProcessExistent(const std::vector<int32_t>& pids,
+ std::vector<bool>* existent) override;
protected:
virtual ~ProcessInfo();
diff --git a/media/utils/include/mediautils/ProcessInfoInterface.h b/media/utils/include/mediautils/ProcessInfoInterface.h
new file mode 100644
index 0000000..e3384ba
--- /dev/null
+++ b/media/utils/include/mediautils/ProcessInfoInterface.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef PROCESS_INFO_INTERFACE_H_
+#define PROCESS_INFO_INTERFACE_H_
+
+#include <vector>
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct ProcessInfoInterface : public RefBase {
+ /*
+ * Gets the priority of the process (with given pid) as oom score.
+ *
+ * @param[in] pid pid of the process.
+ * @param[out] priority of the process.
+ *
+ * @return true for successful return and false otherwise.
+ */
+ virtual bool getPriority(int pid, int* priority) = 0;
+ /*
+ * Check whether the given pid is trusted or not.
+ *
+ * @param[in] pid pid of the process.
+ *
+ * @return true for trusted process and false otherwise.
+ */
+ virtual bool isPidTrusted(int pid) = 0;
+ /*
+ * Check whether the given pid and uid is trusted or not.
+ *
+ * @param[in] pid pid of the process.
+ * @param[in] uid uid of the process.
+ *
+ * @return true for trusted process and false otherwise.
+ */
+ virtual bool isPidUidTrusted(int pid, int uid) = 0;
+ /*
+ * Override process state and oom score of the pid.
+ *
+ * @param[in] pid pid of the process.
+ * @param[in] procState new state of the process to override with.
+ * @param[in] oomScore new oom score of the process to override with.
+ *
+ * @return true upon success and false otherwise.
+ */
+ virtual bool overrideProcessInfo(int pid, int procState, int oomScore) = 0;
+ /*
+ * Remove the override info of the given process.
+ *
+ * @param[in] pid pid of the process.
+ */
+ virtual void removeProcessInfoOverride(int pid) = 0;
+ /*
+ * Checks whether the list of processes with given pids exist or not.
+ *
+ * @param[in] pids List of pids for which to check whether they are Existent or not.
+ * @param[out] existent boolean vector corresponds to Existent state of each pids.
+ *
+ * @return true for successful return and false otherwise.
+ * On successful return:
+ * - existent[i] true corresponds to pids[i] still active and
+ * - existent[i] false corresponds to pids[i] already terminated (Nonexistent)
+ * On unsuccessful return, the output argument existent is invalid.
+ */
+ virtual bool checkProcessExistent(const std::vector<int32_t>& pids,
+ std::vector<bool>* existent) {
+ // A default implementation.
+ (void)pids;
+ (void)existent;
+ return false;
+ }
+
+protected:
+ virtual ~ProcessInfoInterface() {}
+};
+
+} // namespace android
+
+#endif // PROCESS_INFO_INTERFACE_H_
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 75fa595..0e4bc6c 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -301,6 +301,10 @@
return mActiveClients;
}
+ // Returns 0 if not all active clients have the same exclusive preferred device
+ // or the number of active clients with the same exclusive preferred device
+ size_t sameExclusivePreferredDevicesCount() const;
+
bool useHwGain() const
{
return !devices().isEmpty() ? devices().itemAt(0)->hasGainController() : false;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 329e0ca..14c49ef 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -237,6 +237,27 @@
return clients;
}
+size_t AudioOutputDescriptor::sameExclusivePreferredDevicesCount() const
+{
+ audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
+ size_t count = 0;
+ for (const auto &client : getClientIterable()) {
+ if (client->active()) {
+ if (!(client->hasPreferredDevice() &&
+ client->isPreferredDeviceForExclusiveUse())) {
+ return 0;
+ }
+ if (deviceId == AUDIO_PORT_HANDLE_NONE) {
+ deviceId = client->preferredDeviceId();
+ } else if (deviceId != client->preferredDeviceId()) {
+ return 0;
+ }
+ count++;
+ }
+ }
+ return count;
+}
+
bool AudioOutputDescriptor::isAnyActive(VolumeSource volumeSourceToIgnore) const
{
return std::find_if(begin(mActiveClients), end(mActiveClients),
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index e2f42da..f00e4e3 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -282,10 +282,15 @@
break;
case STRATEGY_PHONE: {
- devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID);
- if (!devices.isEmpty()) break;
+ // TODO(b/243670205): remove this logic that gives preference to last removable devices
+ // once a UX decision has been made
devices = availableOutputDevices.getFirstDevicesFromTypes(
- getLastRemovableMediaDevices(GROUP_NONE, {AUDIO_DEVICE_OUT_BLE_HEADSET}));
+ getLastRemovableMediaDevices(GROUP_NONE, {
+ // excluding HEARING_AID and BLE_HEADSET because Dialer uses
+ // setCommunicationDevice to select them explicitly
+ AUDIO_DEVICE_OUT_HEARING_AID,
+ AUDIO_DEVICE_OUT_BLE_HEADSET
+ }));
if (!devices.isEmpty()) break;
devices = availableOutputDevices.getFirstDevicesFromTypes({
AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_EARPIECE,
@@ -301,7 +306,9 @@
if ((strategy == STRATEGY_SONIFICATION) ||
(getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)) {
- devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
+ // favor dock over speaker when available
+ devices = availableOutputDevices.getFirstDevicesFromTypes({
+ AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_SPEAKER});
}
// if SCO headset is connected and we are told to use it, play ringtone over
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 23d4b33..028c9a0 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2037,6 +2037,10 @@
outputDesc->stop();
return status;
}
+ if (client->hasPreferredDevice()) {
+ // playback activity with preferred device impacts routing occurred, inform upper layers
+ mpClientInterface->onRoutingUpdated();
+ }
if (delayMs != 0) {
usleep(delayMs * 1000);
}
@@ -2119,8 +2123,7 @@
outputDesc->setClientActive(client, true);
if (client->hasPreferredDevice(true)) {
- if (outputDesc->clientsList(true /*activeOnly*/).size() == 1 &&
- client->isPreferredDeviceForExclusiveUse()) {
+ if (outputDesc->sameExclusivePreferredDevicesCount() > 0) {
// Preferred device may be exclusive, use only if no other active clients on this output
devices = DeviceVector(
mAvailableOutputDevices.getDeviceFromId(client->preferredDeviceId()));
@@ -2282,6 +2285,11 @@
}
sp<TrackClientDescriptor> client = outputDesc->getClient(portId);
+ if (client->hasPreferredDevice(true)) {
+ // playback activity with preferred device impacts routing occurred, inform upper layers
+ mpClientInterface->onRoutingUpdated();
+ }
+
ALOGV("stopOutput() output %d, stream %d, session %d",
outputDesc->mIoHandle, client->stream(), client->session());
@@ -2319,7 +2327,8 @@
}
}
bool forceDeviceUpdate = false;
- if (client->hasPreferredDevice(true)) {
+ if (client->hasPreferredDevice(true) &&
+ outputDesc->sameExclusivePreferredDevicesCount() < 2) {
checkStrategyRoute(client->strategy(), AUDIO_IO_HANDLE_NONE);
forceDeviceUpdate = true;
}
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 91857f9..d283007 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -301,7 +301,8 @@
audio_stream_type_t stream = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_AudioStreamType_audio_stream_type_t(streamAidl));
- if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
+ if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT
+ && stream != AUDIO_STREAM_ASSISTANT && stream != AUDIO_STREAM_CALL_ASSISTANT) {
*_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(
legacy2aidl_audio_io_handle_t_int32_t(AUDIO_IO_HANDLE_NONE));
return Status::ok();
diff --git a/services/audiopolicy/service/SpatializerPoseController.cpp b/services/audiopolicy/service/SpatializerPoseController.cpp
index 4cba8cc..874bde4 100644
--- a/services/audiopolicy/service/SpatializerPoseController.cpp
+++ b/services/audiopolicy/service/SpatializerPoseController.cpp
@@ -216,7 +216,7 @@
mHeadSensor = INVALID_SENSOR;
}
- mProcessor->recenter(true /* recenterHead */, false /* recenterScreen */);
+ mProcessor->recenter(true /* recenterHead */, false /* recenterScreen */, __func__);
}
void SpatializerPoseController::setScreenSensor(int32_t sensor) {
@@ -253,7 +253,7 @@
mScreenSensor = INVALID_SENSOR;
}
- mProcessor->recenter(false /* recenterHead */, true /* recenterScreen */);
+ mProcessor->recenter(false /* recenterHead */, true /* recenterScreen */, __func__);
}
void SpatializerPoseController::setDesiredMode(HeadTrackingMode mode) {
@@ -300,7 +300,7 @@
void SpatializerPoseController::recenter() {
std::lock_guard lock(mMutex);
- mProcessor->recenter();
+ mProcessor->recenter(true /* recenterHead */, true /* recenterScreen */, __func__);
}
void SpatializerPoseController::onPose(int64_t timestamp, int32_t sensor, const Pose3f& pose,
@@ -339,7 +339,7 @@
mProcessor->setWorldToHeadPose(timestamp, pose,
twist.value_or(Twist3f()) / kTicksPerSecond);
if (isNewReference) {
- mProcessor->recenter(true, false);
+ mProcessor->recenter(true, false, __func__);
}
}
if (sensor == mScreenSensor) {
@@ -353,7 +353,7 @@
mProcessor->setWorldToScreenPose(timestamp, pose);
if (isNewReference) {
- mProcessor->recenter(false, true);
+ mProcessor->recenter(false, true, __func__);
}
}
}
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 8bfa588..42dce03 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -954,7 +954,7 @@
int api1CameraId, int facing, int sensorOrientation, int clientPid, uid_t clientUid,
int servicePid, std::pair<int, IPCTransport> deviceVersionAndTransport,
apiLevel effectiveApiLevel, bool overrideForPerfClass, bool overrideToPortrait,
- /*out*/sp<BasicClient>* client) {
+ bool forceSlowJpegMode, /*out*/sp<BasicClient>* client) {
// For HIDL devices
if (deviceVersionAndTransport.second == IPCTransport::HIDL) {
// Create CameraClient based on device version reported by the HAL.
@@ -987,9 +987,9 @@
sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
*client = new Camera2Client(cameraService, tmp, packageName, featureId,
cameraId, api1CameraId, facing, sensorOrientation, clientPid, clientUid,
- servicePid, overrideForPerfClass, overrideToPortrait);
- ALOGI("%s: Camera1 API (legacy), override to portrait %d", __FUNCTION__,
- overrideToPortrait);
+ servicePid, overrideForPerfClass, overrideToPortrait, forceSlowJpegMode);
+ ALOGI("%s: Camera1 API (legacy), override to portrait %d, forceSlowJpegMode %d",
+ __FUNCTION__, overrideToPortrait, forceSlowJpegMode);
} else { // Camera2 API route
sp<hardware::camera2::ICameraDeviceCallbacks> tmp =
static_cast<hardware::camera2::ICameraDeviceCallbacks*>(cameraCb.get());
@@ -1086,7 +1086,8 @@
sp<ICameraClient>{nullptr}, id, cameraId,
internalPackageName, /*systemNativeClient*/ false, {}, uid, USE_CALLING_PID,
API_1, /*shimUpdateOnly*/ true, /*oomScoreOffset*/ 0,
- /*targetSdkVersion*/ __ANDROID_API_FUTURE__, /*overrideToPortrait*/ true, /*out*/ tmp)
+ /*targetSdkVersion*/ __ANDROID_API_FUTURE__, /*overrideToPortrait*/ true,
+ /*forceSlowJpegMode*/false, /*out*/ tmp)
).isOk()) {
ALOGE("%s: Error initializing shim metadata: %s", __FUNCTION__, ret.toString8().string());
}
@@ -1603,6 +1604,7 @@
int clientPid,
int targetSdkVersion,
bool overrideToPortrait,
+ bool forceSlowJpegMode,
/*out*/
sp<ICamera>* device) {
@@ -1614,7 +1616,7 @@
ret = connectHelper<ICameraClient,Client>(cameraClient, id, api1CameraId,
clientPackageName,/*systemNativeClient*/ false, {}, clientUid, clientPid, API_1,
/*shimUpdateOnly*/ false, /*oomScoreOffset*/ 0, targetSdkVersion,
- overrideToPortrait, /*out*/client);
+ overrideToPortrait, forceSlowJpegMode, /*out*/client);
if(!ret.isOk()) {
logRejected(id, CameraThreadState::getCallingPid(), String8(clientPackageName),
@@ -1743,7 +1745,8 @@
ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,
/*api1CameraId*/-1, clientPackageNameAdj, systemNativeClient,clientFeatureId,
clientUid, USE_CALLING_PID, API_2, /*shimUpdateOnly*/ false, oomScoreOffset,
- targetSdkVersion, overrideToPortrait, /*out*/client);
+ targetSdkVersion, overrideToPortrait, /*forceSlowJpegMode*/false,
+ /*out*/client);
if(!ret.isOk()) {
logRejected(id, callingPid, String8(clientPackageNameAdj), ret.toString8());
@@ -1805,7 +1808,8 @@
int api1CameraId, const String16& clientPackageNameMaybe, bool systemNativeClient,
const std::optional<String16>& clientFeatureId, int clientUid, int clientPid,
apiLevel effectiveApiLevel, bool shimUpdateOnly, int oomScoreOffset, int targetSdkVersion,
- bool overrideToPortrait, /*out*/sp<CLIENT>& device) {
+ bool overrideToPortrait, bool forceSlowJpegMode,
+ /*out*/sp<CLIENT>& device) {
binder::Status ret = binder::Status::ok();
bool isNonSystemNdk = false;
@@ -1921,7 +1925,8 @@
clientFeatureId, cameraId, api1CameraId, facing, orientation,
clientPid, clientUid, getpid(),
deviceVersionAndTransport, effectiveApiLevel, overrideForPerfClass,
- overrideToPortrait, /*out*/&tmp)).isOk()) {
+ overrideToPortrait, forceSlowJpegMode,
+ /*out*/&tmp)).isOk()) {
return ret;
}
client = static_cast<CLIENT*>(tmp.get());
@@ -2043,6 +2048,7 @@
}
client->setImageDumpMask(mImageDumpMask);
+ client->setStreamUseCaseOverrides(mStreamUseCaseOverrides);
} // lock is destroyed, allow further connect calls
// Important: release the mutex here so the client can call back into the service from its
@@ -4418,6 +4424,13 @@
String8 activeClientString = mActiveClientManager.toString();
dprintf(fd, "Active Camera Clients:\n%s", activeClientString.string());
dprintf(fd, "Allowed user IDs: %s\n", toString(mAllowedUsers).string());
+ if (mStreamUseCaseOverrides.size() > 0) {
+ dprintf(fd, "Active stream use case overrides:");
+ for (int64_t useCaseOverride : mStreamUseCaseOverrides) {
+ dprintf(fd, " %" PRId64, useCaseOverride);
+ }
+ dprintf(fd, "\n");
+ }
dumpEventLog(fd);
@@ -4909,6 +4922,10 @@
return handleGetImageDumpMask(out);
} else if (args.size() >= 2 && args[0] == String16("set-camera-mute")) {
return handleSetCameraMute(args);
+ } else if (args.size() >= 2 && args[0] == String16("set-stream-use-case-override")) {
+ return handleSetStreamUseCaseOverrides(args);
+ } else if (args.size() >= 1 && args[0] == String16("clear-stream-use-case-override")) {
+ return handleClearStreamUseCaseOverrides();
} else if (args.size() >= 2 && args[0] == String16("watch")) {
return handleWatchCommand(args, in, out);
} else if (args.size() >= 2 && args[0] == String16("set-watchdog")) {
@@ -5081,6 +5098,43 @@
return OK;
}
+status_t CameraService::handleSetStreamUseCaseOverrides(const Vector<String16>& args) {
+ std::vector<int64_t> useCasesOverride;
+ for (size_t i = 1; i < args.size(); i++) {
+ int64_t useCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT;
+ String8 arg8 = String8(args[i]);
+ if (arg8 == "DEFAULT") {
+ useCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT;
+ } else if (arg8 == "PREVIEW") {
+ useCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW;
+ } else if (arg8 == "STILL_CAPTURE") {
+ useCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE;
+ } else if (arg8 == "VIDEO_RECORD") {
+ useCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD;
+ } else if (arg8 == "PREVIEW_VIDEO_STILL") {
+ useCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL;
+ } else if (arg8 == "VIDEO_CALL") {
+ useCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL;
+ } else {
+ ALOGE("%s: Invalid stream use case %s", __FUNCTION__, String8(args[i]).c_str());
+ return BAD_VALUE;
+ }
+ useCasesOverride.push_back(useCase);
+ }
+
+ Mutex::Autolock lock(mServiceLock);
+ mStreamUseCaseOverrides = std::move(useCasesOverride);
+
+ return OK;
+}
+
+status_t CameraService::handleClearStreamUseCaseOverrides() {
+ Mutex::Autolock lock(mServiceLock);
+ mStreamUseCaseOverrides.clear();
+
+ return OK;
+}
+
status_t CameraService::handleWatchCommand(const Vector<String16>& args, int inFd, int outFd) {
if (args.size() >= 3 && args[1] == String16("start")) {
return startWatchingTags(args, outFd);
@@ -5435,6 +5489,15 @@
" Valid values 0=OFF, 1=ON for JPEG\n"
" get-image-dump-mask returns the current image-dump-mask value\n"
" set-camera-mute <0/1> enable or disable camera muting\n"
+ " set-stream-use-case-override <usecase1> <usecase2> ... override stream use cases\n"
+ " Use cases applied in descending resolutions. So usecase1 is assigned to the\n"
+ " largest resolution, usecase2 is assigned to the 2nd largest resolution, and so\n"
+ " on. In case the number of usecases is smaller than the number of streams, the\n"
+ " last use case is assigned to all the remaining streams. In case of multiple\n"
+ " streams with the same resolution, the tie-breaker is (JPEG, RAW, YUV, and PRIV)\n"
+ " Valid values are (case sensitive): DEFAULT, PREVIEW, STILL_CAPTURE, VIDEO_RECORD,\n"
+ " PREVIEW_VIDEO_STILL, VIDEO_CALL\n"
+ " clear-stream-use-case-override clear the stream use case override\n"
" watch <start|stop|dump|print|clear> manages tag monitoring in connected clients\n"
" help print this message\n");
}
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 840e9b6..70293f4 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -141,7 +141,7 @@
virtual binder::Status connect(const sp<hardware::ICameraClient>& cameraClient,
int32_t cameraId, const String16& clientPackageName,
int32_t clientUid, int clientPid, int targetSdkVersion,
- bool overrideToPortrait,
+ bool overrideToPortrait, bool forceSlowJpegMode,
/*out*/
sp<hardware::ICamera>* device) override;
@@ -348,6 +348,13 @@
// Set Camera service watchdog
virtual status_t setCameraServiceWatchdog(bool enabled) = 0;
+ // Set stream use case overrides
+ virtual void setStreamUseCaseOverrides(
+ const std::vector<int64_t>& useCaseOverrides) = 0;
+
+ // Clear stream use case overrides
+ virtual void clearStreamUseCaseOverrides() = 0;
+
// The injection camera session to replace the internal camera
// session.
virtual status_t injectCamera(const String8& injectedCamId,
@@ -502,6 +509,7 @@
virtual bool canCastToApiClient(apiLevel level) const;
void setImageDumpMask(int /*mask*/) { }
+ void setStreamUseCaseOverrides(const std::vector<int64_t>& /*usecaseOverrides*/) { }
protected:
// Initialized in constructor
@@ -852,7 +860,8 @@
int api1CameraId, const String16& clientPackageNameMaybe, bool systemNativeClient,
const std::optional<String16>& clientFeatureId, int clientUid, int clientPid,
apiLevel effectiveApiLevel, bool shimUpdateOnly, int scoreOffset, int targetSdkVersion,
- bool overrideToPortrait, /*out*/sp<CLIENT>& device);
+ bool overrideToPortrait, bool forceSlowJpegMode,
+ /*out*/sp<CLIENT>& device);
// Lock guarding camera service state
Mutex mServiceLock;
@@ -1216,6 +1225,12 @@
// Set the camera mute state
status_t handleSetCameraMute(const Vector<String16>& args);
+ // Set the stream use case overrides
+ status_t handleSetStreamUseCaseOverrides(const Vector<String16>& args);
+
+ // Clear the stream use case overrides
+ status_t handleClearStreamUseCaseOverrides();
+
// Handle 'watch' command as passed through 'cmd'
status_t handleWatchCommand(const Vector<String16> &args, int inFd, int outFd);
@@ -1267,7 +1282,8 @@
const String8& cameraId, int api1CameraId, int facing, int sensorOrientation,
int clientPid, uid_t clientUid, int servicePid,
std::pair<int, IPCTransport> deviceVersionAndIPCTransport, apiLevel effectiveApiLevel,
- bool overrideForPerfClass, bool overrideToPortrait, /*out*/sp<BasicClient>* client);
+ bool overrideForPerfClass, bool overrideToPortrait, bool forceSlowJpegMode,
+ /*out*/sp<BasicClient>* client);
status_t checkCameraAccess(const String16& opPackageName);
@@ -1311,6 +1327,9 @@
// Camera Service watchdog flag
bool mCameraServiceWatchdogEnabled = true;
+ // Current stream use case overrides
+ std::vector<int64_t> mStreamUseCaseOverrides;
+
/**
* A listener class that implements the IBinder::DeathRecipient interface
* for use to call back the error state injected by the external camera, and
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 8e3f609..ad32682 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -62,7 +62,8 @@
uid_t clientUid,
int servicePid,
bool overrideForPerfClass,
- bool overrideToPortrait):
+ bool overrideToPortrait,
+ bool forceSlowJpegMode):
Camera2ClientBase(cameraService, cameraClient, clientPackageName,
false/*systemNativeClient - since no ndk for api1*/, clientFeatureId,
cameraDeviceId, api1CameraId, cameraFacing, sensorOrientation, clientPid,
@@ -78,6 +79,9 @@
SharedParameters::Lock l(mParameters);
l.mParameters.state = Parameters::DISCONNECTED;
+ if (forceSlowJpegMode) {
+ l.mParameters.isSlowJpegModeForced = true;
+ }
}
status_t Camera2Client::initialize(sp<CameraProviderManager> manager, const String8& monitorTags) {
@@ -2344,6 +2348,15 @@
return mDevice->setCameraMute(enabled);
}
+void Camera2Client::setStreamUseCaseOverrides(
+ const std::vector<int64_t>& useCaseOverrides) {
+ mDevice->setStreamUseCaseOverrides(useCaseOverrides);
+}
+
+void Camera2Client::clearStreamUseCaseOverrides() {
+ mDevice->clearStreamUseCaseOverrides();
+}
+
status_t Camera2Client::waitUntilCurrentRequestIdLocked() {
int32_t activeRequestId = mStreamingProcessor->getActiveRequestId();
if (activeRequestId != 0) {
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index 9c540a4..bbad6d8 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -92,6 +92,10 @@
virtual status_t setCameraServiceWatchdog(bool enabled);
+ virtual void setStreamUseCaseOverrides(
+ const std::vector<int64_t>& useCaseOverrides);
+ virtual void clearStreamUseCaseOverrides();
+
/**
* Interface used by CameraService
*/
@@ -108,7 +112,8 @@
uid_t clientUid,
int servicePid,
bool overrideForPerfClass,
- bool overrideToPortrait);
+ bool overrideToPortrait,
+ bool forceSlowJpegMode);
virtual ~Camera2Client();
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 8b2af90..23570c2 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -990,9 +990,8 @@
Size maxJpegSize = getMaxSize(getAvailableJpegSizes());
int64_t minFrameDurationNs = getJpegStreamMinFrameDurationNs(maxJpegSize);
- slowJpegMode = false;
- if (minFrameDurationNs > kSlowJpegModeThreshold) {
- slowJpegMode = true;
+ slowJpegMode = isSlowJpegModeForced || minFrameDurationNs > kSlowJpegModeThreshold;
+ if (slowJpegMode) {
// Slow jpeg devices does not support video snapshot without
// slowing down preview.
// TODO: support video size video snapshot only?
@@ -2089,7 +2088,7 @@
paramsFlattened = newParams.flatten();
params = newParams;
- slowJpegMode = false;
+ slowJpegMode = isSlowJpegModeForced;
Size pictureSize = { pictureWidth, pictureHeight };
bool zslFrameRateSupported = false;
int64_t jpegMinFrameDurationNs = getJpegStreamMinFrameDurationNs(pictureSize);
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index fd18a5d..2bd3d43 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -183,6 +183,8 @@
bool isDeviceZslSupported;
// Whether the device supports geometric distortion correction
bool isDistortionCorrectionSupported;
+ // Whether slowJpegMode is forced regardless of jpeg stream FPS
+ bool isSlowJpegModeForced;
// Overall camera state
enum State {
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 202599b..7ccd515 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -1750,6 +1750,15 @@
return mDevice->setCameraMute(enabled);
}
+void CameraDeviceClient::setStreamUseCaseOverrides(
+ const std::vector<int64_t>& useCaseOverrides) {
+ mDevice->setStreamUseCaseOverrides(useCaseOverrides);
+}
+
+void CameraDeviceClient::clearStreamUseCaseOverrides() {
+ mDevice->clearStreamUseCaseOverrides();
+}
+
binder::Status CameraDeviceClient::switchToOffline(
const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
const std::vector<int>& offlineOutputIds,
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 6bb64d6..c95bb4a 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -210,6 +210,9 @@
virtual status_t setCameraServiceWatchdog(bool enabled);
+ virtual void setStreamUseCaseOverrides(const std::vector<int64_t>& useCaseOverrides);
+ virtual void clearStreamUseCaseOverrides() override;
+
/**
* Device listener interface
*/
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
index acc805a..b6e5a9b 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
@@ -90,6 +90,12 @@
return INVALID_OPERATION;
}
+void CameraOfflineSessionClient::setStreamUseCaseOverrides(
+ const std::vector<int64_t>& /*useCaseOverrides*/) {
+}
+
+void CameraOfflineSessionClient::clearStreamUseCaseOverrides() {
+}
status_t CameraOfflineSessionClient::dump(int fd, const Vector<String16>& args) {
return BasicClient::dump(fd, args);
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
index 8edb64a..23e1f3d 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
@@ -87,6 +87,11 @@
status_t setCameraServiceWatchdog(bool enabled) override;
+ void setStreamUseCaseOverrides(
+ const std::vector<int64_t>& useCaseOverrides) override;
+
+ void clearStreamUseCaseOverrides() override;
+
// permissions management
status_t startCameraOps() override;
status_t finishCameraOps() override;
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 71d0f9e..8d4117a 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -343,6 +343,29 @@
}
template <typename TClientBase>
+void Camera2ClientBase<TClientBase>::notifyPhysicalCameraChange(const std::string &physicalId) {
+ // We're only interested in this notification if overrideToPortrait is turned on.
+ if (!TClientBase::mOverrideToPortrait) {
+ return;
+ }
+
+ String8 physicalId8(physicalId.c_str());
+ auto physicalCameraMetadata = mDevice->infoPhysical(physicalId8);
+ auto orientationEntry = physicalCameraMetadata.find(ANDROID_SENSOR_ORIENTATION);
+
+ if (orientationEntry.count == 1) {
+ int orientation = orientationEntry.data.i32[0];
+ int rotateAndCropMode = ANDROID_SCALER_ROTATE_AND_CROP_NONE;
+
+ if (orientation == 0 || orientation == 180) {
+ rotateAndCropMode = ANDROID_SCALER_ROTATE_AND_CROP_90;
+ }
+
+ static_cast<TClientBase *>(this)->setRotateAndCropOverride(rotateAndCropMode);
+ }
+}
+
+template <typename TClientBase>
status_t Camera2ClientBase<TClientBase>::notifyActive(float maxPreviewFps) {
if (!mDeviceActive) {
status_t res = TClientBase::startCameraStreamingOps();
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index d2dcdb1..705fe69 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -75,6 +75,7 @@
virtual void notifyError(int32_t errorCode,
const CaptureResultExtras& resultExtras);
+ virtual void notifyPhysicalCameraChange(const std::string &physicalId) override;
// Returns errors on app ops permission failures
virtual status_t notifyActive(float maxPreviewFps);
virtual void notifyIdle(int64_t /*requestCount*/, int64_t /*resultErrorCount*/,
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 69514f3..8f7b16d 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -464,6 +464,15 @@
void setImageDumpMask(int mask) { mImageDumpMask = mask; }
/**
+ * Set stream use case overrides
+ */
+ void setStreamUseCaseOverrides(const std::vector<int64_t>& useCaseOverrides) {
+ mStreamUseCaseOverrides = useCaseOverrides;
+ }
+
+ void clearStreamUseCaseOverrides() {}
+
+ /**
* The injection camera session to replace the internal camera
* session.
*/
@@ -477,6 +486,7 @@
protected:
bool mImageDumpMask = 0;
+ std::vector<int64_t> mStreamUseCaseOverrides;
};
}; // namespace android
diff --git a/services/camera/libcameraservice/common/CameraOfflineSessionBase.h b/services/camera/libcameraservice/common/CameraOfflineSessionBase.h
index f39b92a..63abcf0 100644
--- a/services/camera/libcameraservice/common/CameraOfflineSessionBase.h
+++ b/services/camera/libcameraservice/common/CameraOfflineSessionBase.h
@@ -40,6 +40,10 @@
// Required for API 1 and 2
virtual void notifyError(int32_t errorCode,
const CaptureResultExtras &resultExtras) = 0;
+
+ // Optional for API 1 and 2
+ virtual void notifyPhysicalCameraChange(const std::string &/*physicalId*/) {}
+
// May return an error since it checks appops
virtual status_t notifyActive(float maxPreviewFps) = 0;
virtual void notifyIdle(int64_t requestCount, int64_t resultError, bool deviceError,
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 4259efd..98583a5 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -2032,7 +2032,7 @@
}
CameraMetadata info2;
res = device->getCameraCharacteristics(true /*overrideForPerfClass*/, &info2,
- /*overrideToPortrait*/true);
+ /*overrideToPortrait*/false);
if (res == INVALID_OPERATION) {
dprintf(fd, " API2 not directly supported\n");
} else if (res != OK) {
@@ -2387,8 +2387,8 @@
if (overrideToPortrait) {
const auto &lensFacingEntry = characteristics->find(ANDROID_LENS_FACING);
const auto &sensorOrientationEntry = characteristics->find(ANDROID_SENSOR_ORIENTATION);
+ uint8_t lensFacing = lensFacingEntry.data.u8[0];
if (lensFacingEntry.count > 0 && sensorOrientationEntry.count > 0) {
- uint8_t lensFacing = lensFacingEntry.data.u8[0];
int32_t sensorOrientation = sensorOrientationEntry.data.i32[0];
int32_t newSensorOrientation = sensorOrientation;
@@ -2409,6 +2409,8 @@
}
if (characteristics->exists(ANDROID_INFO_DEVICE_STATE_ORIENTATIONS)) {
+ ALOGV("%s: Erasing ANDROID_INFO_DEVICE_STATE_ORIENTATIONS for lens facing %d",
+ __FUNCTION__, lensFacing);
characteristics->erase(ANDROID_INFO_DEVICE_STATE_ORIENTATIONS);
}
}
@@ -2444,8 +2446,8 @@
for (size_t i = 0; i < streamConfigs.count; i += 4) {
if ((streamConfigs.data.i32[i] == HAL_PIXEL_FORMAT_BLOB) && (streamConfigs.data.i32[i+3] ==
ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT)) {
- if (streamConfigs.data.i32[i+1] < thresholdW ||
- streamConfigs.data.i32[i+2] < thresholdH) {
+ if (streamConfigs.data.i32[i+1] * streamConfigs.data.i32[i+2] <
+ thresholdW * thresholdH) {
continue;
} else {
largeJpegCount ++;
@@ -2465,8 +2467,8 @@
mCameraCharacteristics.find(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
for (size_t i = 0; i < minDurations.count; i += 4) {
if (minDurations.data.i64[i] == HAL_PIXEL_FORMAT_BLOB) {
- if (minDurations.data.i64[i+1] < thresholdW ||
- minDurations.data.i64[i+2] < thresholdH) {
+ if ((int32_t)minDurations.data.i64[i+1] * (int32_t)minDurations.data.i64[i+2] <
+ thresholdW * thresholdH) {
continue;
} else {
largeJpegCount++;
@@ -2486,8 +2488,8 @@
mCameraCharacteristics.find(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS);
for (size_t i = 0; i < stallDurations.count; i += 4) {
if (stallDurations.data.i64[i] == HAL_PIXEL_FORMAT_BLOB) {
- if (stallDurations.data.i64[i+1] < thresholdW ||
- stallDurations.data.i64[i+2] < thresholdH) {
+ if ((int32_t)stallDurations.data.i64[i+1] * (int32_t)stallDurations.data.i64[i+2] <
+ thresholdW * thresholdH) {
continue;
} else {
largeJpegCount++;
diff --git a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
index d05e235..49bbd07 100644
--- a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
@@ -760,7 +760,7 @@
SessionConfigurationUtils::targetPerfClassPrimaryCamera(
perfClassPrimaryCameraIds, cameraId, targetSdkVersion);
res = mManager->getCameraCharacteristicsLocked(cameraId, overrideForPerfClass, &deviceInfo,
- /*overrideToPortrait*/true);
+ /*overrideToPortrait*/false);
if (res != OK) {
return res;
}
@@ -768,7 +768,8 @@
[this](const String8 &id, bool overrideForPerfClass) {
CameraMetadata physicalDeviceInfo;
mManager->getCameraCharacteristicsLocked(id.string(), overrideForPerfClass,
- &physicalDeviceInfo, /*overrideToPortrait*/true);
+ &physicalDeviceInfo,
+ /*overrideToPortrait*/false);
return physicalDeviceInfo;
};
std::vector<std::string> physicalCameraIds;
diff --git a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
index 468b644..4a89380 100644
--- a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
@@ -917,7 +917,7 @@
SessionConfigurationUtils::targetPerfClassPrimaryCamera(
perfClassPrimaryCameraIds, cameraId, targetSdkVersion);
res = mManager->getCameraCharacteristicsLocked(cameraId, overrideForPerfClass, &deviceInfo,
- /*overrideToPortrait*/true);
+ /*overrideToPortrait*/false);
if (res != OK) {
return res;
}
@@ -925,7 +925,7 @@
[this](const String8 &id, bool overrideForPerfClass) {
CameraMetadata physicalDeviceInfo;
mManager->getCameraCharacteristicsLocked(id.string(), overrideForPerfClass,
- &physicalDeviceInfo, /*overrideToPortrait*/true);
+ &physicalDeviceInfo, /*overrideToPortrait*/false);
return physicalDeviceInfo;
};
std::vector<std::string> physicalCameraIds;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 9a627f3..74dbe27 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -96,7 +96,10 @@
mLastTemplateId(-1),
mNeedFixupMonochromeTags(false),
mOverrideForPerfClass(overrideForPerfClass),
- mOverrideToPortrait(overrideToPortrait)
+ mOverrideToPortrait(overrideToPortrait),
+ mRotateAndCropOverride(ANDROID_SCALER_ROTATE_AND_CROP_NONE),
+ mComposerOutput(false),
+ mActivePhysicalId("")
{
ATRACE_CALL();
ALOGV("%s: Created device for camera %s", __FUNCTION__, mId.string());
@@ -1359,12 +1362,34 @@
set_camera_metadata_vendor_id(meta, mVendorTagId);
filteredParams.unlock(meta);
if (availableSessionKeys.count > 0) {
+ bool rotateAndCropSessionKey = false;
for (size_t i = 0; i < availableSessionKeys.count; i++) {
camera_metadata_ro_entry entry = params.find(
availableSessionKeys.data.i32[i]);
if (entry.count > 0) {
filteredParams.update(entry);
}
+ if (ANDROID_SCALER_ROTATE_AND_CROP == availableSessionKeys.data.i32[i]) {
+ rotateAndCropSessionKey = true;
+ }
+ }
+
+ if (rotateAndCropSessionKey) {
+ sp<CaptureRequest> request = new CaptureRequest();
+ PhysicalCameraSettings settingsList;
+ settingsList.metadata = filteredParams;
+ request->mSettingsList.push_back(settingsList);
+
+ auto rotateAndCropEntry = filteredParams.find(ANDROID_SCALER_ROTATE_AND_CROP);
+ if (rotateAndCropEntry.count > 0 &&
+ rotateAndCropEntry.data.u8[0] == ANDROID_SCALER_ROTATE_AND_CROP_AUTO) {
+ request->mRotateAndCropAuto = true;
+ } else {
+ request->mRotateAndCropAuto = false;
+ }
+
+ overrideAutoRotateAndCrop(request, mOverrideToPortrait, mRotateAndCropOverride);
+ filteredParams = request->mSettingsList.begin()->metadata;
}
}
@@ -2344,6 +2369,9 @@
tryRemoveFakeStreamLocked();
}
+ // Override stream use case based on "adb shell command"
+ overrideStreamUseCaseLocked();
+
// Start configuring the streams
ALOGV("%s: Camera %s: Starting stream configuration", __FUNCTION__, mId.string());
@@ -2373,7 +2401,7 @@
}
mGroupIdPhysicalCameraMap.clear();
- bool composerSurfacePresent = false;
+ mComposerOutput = false;
for (size_t i = 0; i < mOutputStreams.size(); i++) {
// Don't configure bidi streams twice, nor add them twice to the list
@@ -2416,7 +2444,7 @@
}
if (outputStream->usage & GraphicBuffer::USAGE_HW_COMPOSER) {
- composerSurfacePresent = true;
+ mComposerOutput = true;
}
}
@@ -2485,7 +2513,7 @@
}
}
- mRequestThread->setComposerSurface(composerSurfacePresent);
+ mRequestThread->setComposerSurface(mComposerOutput);
// Request thread needs to know to avoid using repeat-last-settings protocol
// across configure_streams() calls
@@ -3438,6 +3466,16 @@
latestRequestId = NAME_NOT_FOUND;
}
+ for (size_t i = 0; i < mNextRequests.size(); i++) {
+ auto& nextRequest = mNextRequests.editItemAt(i);
+ sp<CaptureRequest> captureRequest = nextRequest.captureRequest;
+ // Do not override rotate&crop for stream configurations that include
+ // SurfaceViews(HW_COMPOSER) output, unless mOverrideToPortrait is set.
+ // The display rotation there will be compensated by NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY
+ captureRequest->mRotateAndCropChanged = (mComposerOutput && !mOverrideToPortrait) ? false :
+ overrideAutoRotateAndCrop(captureRequest);
+ }
+
// 'mNextRequests' will at this point contain either a set of HFR batched requests
// or a single request from streaming or burst. In either case the first element
// should contain the latest camera settings that we need to check for any session
@@ -3583,18 +3621,13 @@
bool triggersMixedIn = (triggerCount > 0 || mPrevTriggers > 0);
mPrevTriggers = triggerCount;
- // Do not override rotate&crop for stream configurations that include
- // SurfaceViews(HW_COMPOSER) output, unless mOverrideToPortrait is set.
- // The display rotation there will be compensated by NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY
- bool rotateAndCropChanged = (mComposerOutput && !mOverrideToPortrait) ? false :
- overrideAutoRotateAndCrop(captureRequest);
bool testPatternChanged = overrideTestPattern(captureRequest);
// If the request is the same as last, or we had triggers now or last time or
// changing overrides this time
bool newRequest =
(mPrevRequest != captureRequest || triggersMixedIn ||
- rotateAndCropChanged || testPatternChanged) &&
+ captureRequest->mRotateAndCropChanged || testPatternChanged) &&
// Request settings are all the same within one batch, so only treat the first
// request in a batch as new
!(batchedRequest && i > 0);
@@ -4057,9 +4090,6 @@
camera_metadata_enum_android_scaler_rotate_and_crop_t rotateAndCropValue) {
ATRACE_CALL();
Mutex::Autolock l(mTriggerMutex);
- if (rotateAndCropValue == ANDROID_SCALER_ROTATE_AND_CROP_AUTO) {
- return BAD_VALUE;
- }
mRotateAndCropOverride = rotateAndCropValue;
return OK;
}
@@ -4123,6 +4153,19 @@
return OK;
}
+void Camera3Device::setStreamUseCaseOverrides(
+ const std::vector<int64_t>& useCaseOverrides) {
+ Mutex::Autolock il(mInterfaceLock);
+ Mutex::Autolock l(mLock);
+ mStreamUseCaseOverrides = useCaseOverrides;
+}
+
+void Camera3Device::clearStreamUseCaseOverrides() {
+ Mutex::Autolock il(mInterfaceLock);
+ Mutex::Autolock l(mLock);
+ mStreamUseCaseOverrides.clear();
+}
+
void Camera3Device::RequestThread::cleanUpFailedRequests(bool sendRequestError) {
if (mNextRequests.empty()) {
return;
@@ -4628,13 +4671,20 @@
return OK;
}
-bool Camera3Device::RequestThread::overrideAutoRotateAndCrop(
- const sp<CaptureRequest> &request) {
+bool Camera3Device::RequestThread::overrideAutoRotateAndCrop(const sp<CaptureRequest> &request) {
+ ATRACE_CALL();
+ Mutex::Autolock l(mTriggerMutex);
+ return Camera3Device::overrideAutoRotateAndCrop(request, this->mOverrideToPortrait,
+ this->mRotateAndCropOverride);
+}
+
+bool Camera3Device::overrideAutoRotateAndCrop(const sp<CaptureRequest> &request,
+ bool overrideToPortrait,
+ camera_metadata_enum_android_scaler_rotate_and_crop_t rotateAndCropOverride) {
ATRACE_CALL();
- if (mOverrideToPortrait) {
- Mutex::Autolock l(mTriggerMutex);
- uint8_t rotateAndCrop_u8 = mRotateAndCropOverride;
+ if (overrideToPortrait) {
+ uint8_t rotateAndCrop_u8 = rotateAndCropOverride;
CameraMetadata &metadata = request->mSettingsList.begin()->metadata;
metadata.update(ANDROID_SCALER_ROTATE_AND_CROP,
&rotateAndCrop_u8, 1);
@@ -4642,24 +4692,23 @@
}
if (request->mRotateAndCropAuto) {
- Mutex::Autolock l(mTriggerMutex);
CameraMetadata &metadata = request->mSettingsList.begin()->metadata;
auto rotateAndCropEntry = metadata.find(ANDROID_SCALER_ROTATE_AND_CROP);
if (rotateAndCropEntry.count > 0) {
- if (rotateAndCropEntry.data.u8[0] == mRotateAndCropOverride) {
+ if (rotateAndCropEntry.data.u8[0] == rotateAndCropOverride) {
return false;
} else {
- rotateAndCropEntry.data.u8[0] = mRotateAndCropOverride;
+ rotateAndCropEntry.data.u8[0] = rotateAndCropOverride;
return true;
}
} else {
- uint8_t rotateAndCrop_u8 = mRotateAndCropOverride;
- metadata.update(ANDROID_SCALER_ROTATE_AND_CROP,
- &rotateAndCrop_u8, 1);
+ uint8_t rotateAndCrop_u8 = rotateAndCropOverride;
+ metadata.update(ANDROID_SCALER_ROTATE_AND_CROP, &rotateAndCrop_u8, 1);
return true;
}
}
+
return false;
}
@@ -5145,6 +5194,10 @@
if (mRequestThread == nullptr) {
return INVALID_OPERATION;
}
+ if (rotateAndCropValue == ANDROID_SCALER_ROTATE_AND_CROP_AUTO) {
+ return BAD_VALUE;
+ }
+ mRotateAndCropOverride = rotateAndCropValue;
return mRequestThread->setRotateAndCropAutoBehavior(rotateAndCropValue);
}
@@ -5241,4 +5294,55 @@
return mInjectionMethods->stopInjection();
}
+void Camera3Device::overrideStreamUseCaseLocked() {
+ if (mStreamUseCaseOverrides.size() == 0) {
+ return;
+ }
+
+ // Start from an array of indexes in mStreamUseCaseOverrides, and sort them
+ // based first on size, and second on formats of [JPEG, RAW, YUV, PRIV].
+ std::vector<int> outputStreamsIndices(mOutputStreams.size());
+ for (size_t i = 0; i < outputStreamsIndices.size(); i++) {
+ outputStreamsIndices[i] = i;
+ }
+
+ std::sort(outputStreamsIndices.begin(), outputStreamsIndices.end(),
+ [&](int a, int b) -> bool {
+
+ auto formatScore = [](int format) {
+ switch (format) {
+ case HAL_PIXEL_FORMAT_BLOB:
+ return 4;
+ case HAL_PIXEL_FORMAT_RAW16:
+ case HAL_PIXEL_FORMAT_RAW10:
+ case HAL_PIXEL_FORMAT_RAW12:
+ return 3;
+ case HAL_PIXEL_FORMAT_YCBCR_420_888:
+ return 2;
+ case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+ return 1;
+ default:
+ return 0;
+ }
+ };
+
+ int sizeA = mOutputStreams[a]->getWidth() * mOutputStreams[a]->getHeight();
+ int sizeB = mOutputStreams[a]->getWidth() * mOutputStreams[a]->getHeight();
+ int formatAScore = formatScore(mOutputStreams[a]->getFormat());
+ int formatBScore = formatScore(mOutputStreams[b]->getFormat());
+ if (sizeA > sizeB ||
+ (sizeA == sizeB && formatAScore >= formatBScore)) {
+ return true;
+ } else {
+ return false;
+ }
+ });
+
+ size_t overlapSize = std::min(mStreamUseCaseOverrides.size(), mOutputStreams.size());
+ for (size_t i = 0; i < mOutputStreams.size(); i++) {
+ mOutputStreams[outputStreamsIndices[i]]->setStreamUseCase(
+ mStreamUseCaseOverrides[std::min(i, overlapSize-1)]);
+ }
+}
+
}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 1a50c02..a3acb4e 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -287,6 +287,13 @@
*/
status_t setCameraServiceWatchdog(bool enabled);
+ // Set stream use case overrides
+ void setStreamUseCaseOverrides(
+ const std::vector<int64_t>& useCaseOverrides);
+
+ // Clear stream use case overrides
+ void clearStreamUseCaseOverrides();
+
// Get the status trackeer for the camera device
wp<camera3::StatusTracker> getStatusTracker() { return mStatusTracker; }
@@ -596,6 +603,9 @@
// overriding of ROTATE_AND_CROP value and adjustment of coordinates
// in several other controls in both the request and the result
bool mRotateAndCropAuto;
+ // Indicates that the ROTATE_AND_CROP value within 'mSettingsList' was modified
+ // irrespective of the original value.
+ bool mRotateAndCropChanged = false;
// Whether this capture request has its zoom ratio set to 1.0x before
// the framework overrides it for camera HAL consumption.
@@ -782,6 +792,11 @@
*/
static nsecs_t getMonoToBoottimeOffset();
+ // Override rotate_and_crop control if needed
+ static bool overrideAutoRotateAndCrop(const sp<CaptureRequest> &request /*out*/,
+ bool overrideToPortrait,
+ camera_metadata_enum_android_scaler_rotate_and_crop_t rotateAndCropOverride);
+
struct RequestTrigger {
// Metadata tag number, e.g. android.control.aePrecaptureTrigger
uint32_t metadataTag;
@@ -935,7 +950,7 @@
status_t addFakeTriggerIds(const sp<CaptureRequest> &request);
// Override rotate_and_crop control if needed; returns true if the current value was changed
- bool overrideAutoRotateAndCrop(const sp<CaptureRequest> &request);
+ bool overrideAutoRotateAndCrop(const sp<CaptureRequest> &request /*out*/);
// Override test_pattern control if needed for camera mute; returns true
// if the current value was changed
@@ -1374,6 +1389,11 @@
// Whether the camera framework overrides the device characteristics for
// app compatibility reasons.
bool mOverrideToPortrait;
+ camera_metadata_enum_android_scaler_rotate_and_crop_t mRotateAndCropOverride;
+ bool mComposerOutput;
+
+ // Current active physical id of the logical multi-camera, if any
+ std::string mActivePhysicalId;
// The current minimum expected frame duration based on AE_TARGET_FPS_RANGE
nsecs_t mMinExpectedDuration = 0;
@@ -1463,6 +1483,8 @@
sp<Camera3DeviceInjectionMethods> mInjectionMethods;
+ void overrideStreamUseCaseLocked();
+
}; // class Camera3Device
}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3FakeStream.h b/services/camera/libcameraservice/device3/Camera3FakeStream.h
index a93d1da..1e9f478 100644
--- a/services/camera/libcameraservice/device3/Camera3FakeStream.h
+++ b/services/camera/libcameraservice/device3/Camera3FakeStream.h
@@ -101,6 +101,8 @@
virtual status_t setBatchSize(size_t batchSize) override;
virtual void onMinDurationChanged(nsecs_t /*duration*/, bool /*fixedFps*/) {}
+
+ virtual void setStreamUseCase(int64_t /*streamUseCase*/) {}
protected:
/**
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 3035aa5..4268e61 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -1390,6 +1390,11 @@
mFixedFps = fixedFps;
}
+void Camera3OutputStream::setStreamUseCase(int64_t streamUseCase) {
+ Mutex::Autolock l(mLock);
+ camera_stream::use_case = streamUseCase;
+}
+
void Camera3OutputStream::returnPrefetchedBuffersLocked() {
std::vector<Surface::BatchBuffer> batchedBuffers;
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index db988a0..a719d6b 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -253,6 +253,11 @@
virtual void onMinDurationChanged(nsecs_t duration, bool fixedFps) override;
/**
+ * Modify stream use case
+ */
+ virtual void setStreamUseCase(int64_t streamUseCase) override;
+
+ /**
* Apply ZSL related consumer usage quirk.
*/
static void applyZSLUsageQuirk(int format, uint64_t *consumerUsage /*inout*/);
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
index dbc6fe1..4baa7e8 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
@@ -117,6 +117,11 @@
* AE_TARGET_FPS_RANGE in the capture request.
*/
virtual void onMinDurationChanged(nsecs_t duration, bool fixedFps) = 0;
+
+ /**
+ * Modify the stream use case for this output.
+ */
+ virtual void setStreamUseCase(int64_t streamUseCase) = 0;
};
// Helper class to organize a synchronized mapping of stream IDs to stream instances
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
index 6569395..5021f29 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
@@ -521,27 +521,50 @@
if (result->partial_result != 0)
request.resultExtras.partialResultCount = result->partial_result;
- if ((result->result != nullptr) && !states.legacyClient && !states.overrideToPortrait) {
+ if (result->result != nullptr) {
camera_metadata_ro_entry entry;
auto ret = find_camera_metadata_ro_entry(result->result,
ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID, &entry);
if ((ret == OK) && (entry.count > 0)) {
std::string physicalId(reinterpret_cast<const char *>(entry.data.u8));
- auto deviceInfo = states.physicalDeviceInfoMap.find(physicalId);
- if (deviceInfo != states.physicalDeviceInfoMap.end()) {
- auto orientation = deviceInfo->second.find(ANDROID_SENSOR_ORIENTATION);
- if (orientation.count > 0) {
- ret = CameraUtils::getRotationTransform(deviceInfo->second,
- OutputConfiguration::MIRROR_MODE_AUTO, &request.transform);
- if (ret != OK) {
- ALOGE("%s: Failed to calculate current stream transformation: %s (%d)",
- __FUNCTION__, strerror(-ret), ret);
+ if (!states.activePhysicalId.empty() && physicalId != states.activePhysicalId) {
+ states.listener->notifyPhysicalCameraChange(physicalId);
+ }
+ states.activePhysicalId = physicalId;
+
+ if (!states.legacyClient && !states.overrideToPortrait) {
+ auto deviceInfo = states.physicalDeviceInfoMap.find(physicalId);
+ if (deviceInfo != states.physicalDeviceInfoMap.end()) {
+ auto orientation = deviceInfo->second.find(ANDROID_SENSOR_ORIENTATION);
+ if (orientation.count > 0) {
+ int32_t transform;
+ ret = CameraUtils::getRotationTransform(deviceInfo->second,
+ OutputConfiguration::MIRROR_MODE_AUTO, &transform);
+ if (ret == OK) {
+ // It is possible for camera providers to return the capture
+ // results after the processed frames. In such scenario, we will
+ // not be able to set the output transformation before the frames
+ // return back to the consumer for the current capture request
+ // but we could still try and configure it for any future requests
+ // that are still in flight. The assumption is that the physical
+ // device id remains the same for the duration of the pending queue.
+ for (size_t i = 0; i < states.inflightMap.size(); i++) {
+ auto &r = states.inflightMap.editValueAt(i);
+ if (r.requestTimeNs >= request.requestTimeNs) {
+ r.transform = transform;
+ }
+ }
+ } else {
+ ALOGE("%s: Failed to calculate current stream transformation: %s "
+ "(%d)", __FUNCTION__, strerror(-ret), ret);
+ }
+ } else {
+ ALOGE("%s: Physical device orientation absent!", __FUNCTION__);
}
} else {
- ALOGE("%s: Physical device orientation absent!", __FUNCTION__);
+ ALOGE("%s: Physical device not found in device info map found!",
+ __FUNCTION__);
}
- } else {
- ALOGE("%s: Physical device not found in device info map found!", __FUNCTION__);
}
}
}
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.h b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
index 019c8a8..d5328c5 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
@@ -108,6 +108,7 @@
nsecs_t& minFrameDuration;
bool& isFixedFps;
bool overrideToPortrait;
+ std::string &activePhysicalId;
};
void processCaptureResult(CaptureOutputStates& states, const camera_capture_result *result);
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
index 1e103f2..1bc9ef2 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
@@ -210,7 +210,7 @@
// Do not override characteristics for physical cameras
res = manager->getCameraCharacteristics(
physicalId, /*overrideForPerfClass*/false, &mPhysicalDeviceInfoMap[physicalId],
- /*overrideToPortrait*/true);
+ mOverrideToPortrait);
if (res != OK) {
SET_ERR_L("Could not retrieve camera %s characteristics: %s (%d)",
physicalId.c_str(), strerror(-res), res);
@@ -376,7 +376,7 @@
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this,
*this, *(mInterface), mLegacyClient, mMinExpectedDuration, mIsFixedFps,
- mOverrideToPortrait}, mResultMetadataQueue
+ mOverrideToPortrait, mActivePhysicalId}, mResultMetadataQueue
};
for (const auto& result : results) {
@@ -418,7 +418,7 @@
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this,
*this, *(mInterface), mLegacyClient, mMinExpectedDuration, mIsFixedFps,
- mOverrideToPortrait}, mResultMetadataQueue
+ mOverrideToPortrait, mActivePhysicalId}, mResultMetadataQueue
};
for (const auto& msg : msgs) {
camera3::notify(states, msg);
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp
index 816f96b..3c3db97 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp
@@ -111,6 +111,7 @@
listener = mListener.promote();
}
+ std::string activePhysicalId(""); // Unused
AidlCaptureOutputStates states {
{mId,
mOfflineReqsLock, mLastCompletedRegularFrameNumber,
@@ -125,7 +126,7 @@
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this,
*this, mBufferRecords, /*legacyClient*/ false, mMinExpectedDuration, mIsFixedFps,
- /*overrideToPortrait*/false}, mResultMetadataQueue
+ /*overrideToPortrait*/false, activePhysicalId}, mResultMetadataQueue
};
std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
@@ -157,6 +158,7 @@
listener = mListener.promote();
}
+ std::string activePhysicalId(""); // Unused
AidlCaptureOutputStates states {
{mId,
mOfflineReqsLock, mLastCompletedRegularFrameNumber,
@@ -171,7 +173,7 @@
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this,
*this, mBufferRecords, /*legacyClient*/ false, mMinExpectedDuration, mIsFixedFps,
- /*overrideToPortrait*/false}, mResultMetadataQueue
+ /*overrideToPortrait*/false, activePhysicalId}, mResultMetadataQueue
};
for (const auto& msg : msgs) {
camera3::notify(states, msg);
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
index 44c60cf..c675c63 100644
--- a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
@@ -163,7 +163,7 @@
}
res = manager->getCameraCharacteristics(mId.string(), mOverrideForPerfClass, &mDeviceInfo,
- mOverrideToPortrait);
+ /*overrideToPortrait*/false);
if (res != OK) {
SET_ERR_L("Could not retrieve camera characteristics: %s (%d)", strerror(-res), res);
session->close();
@@ -178,7 +178,7 @@
// Do not override characteristics for physical cameras
res = manager->getCameraCharacteristics(
physicalId, /*overrideForPerfClass*/false, &mPhysicalDeviceInfoMap[physicalId],
- /*overrideToPortrait*/true);
+ /*overrideToPortrait*/false);
if (res != OK) {
SET_ERR_L("Could not retrieve camera %s characteristics: %s (%d)",
physicalId.c_str(), strerror(-res), res);
@@ -365,8 +365,8 @@
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- *mInterface, mLegacyClient, mMinExpectedDuration, mIsFixedFps, mOverrideToPortrait},
- mResultMetadataQueue
+ *mInterface, mLegacyClient, mMinExpectedDuration, mIsFixedFps, mOverrideToPortrait,
+ mActivePhysicalId}, mResultMetadataQueue
};
//HidlCaptureOutputStates hidlStates {
@@ -428,8 +428,8 @@
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- *mInterface, mLegacyClient, mMinExpectedDuration, mIsFixedFps, mOverrideToPortrait},
- mResultMetadataQueue
+ *mInterface, mLegacyClient, mMinExpectedDuration, mIsFixedFps, mOverrideToPortrait,
+ mActivePhysicalId}, mResultMetadataQueue
};
for (const auto& result : results) {
@@ -476,8 +476,8 @@
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- *mInterface, mLegacyClient, mMinExpectedDuration, mIsFixedFps, mOverrideToPortrait},
- mResultMetadataQueue
+ *mInterface, mLegacyClient, mMinExpectedDuration, mIsFixedFps, mOverrideToPortrait,
+ mActivePhysicalId}, mResultMetadataQueue
};
for (const auto& msg : msgs) {
camera3::notify(states, msg);
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp b/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp
index 705408d..28b2b47 100644
--- a/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp
@@ -92,6 +92,7 @@
listener = mListener.promote();
}
+ std::string activePhysicalId("");
HidlCaptureOutputStates states {
{mId,
mOfflineReqsLock, mLastCompletedRegularFrameNumber,
@@ -106,7 +107,7 @@
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
mBufferRecords, /*legacyClient*/ false, mMinExpectedDuration, mIsFixedFps,
- /*overrideToPortrait*/false}, mResultMetadataQueue
+ /*overrideToPortrait*/false, activePhysicalId}, mResultMetadataQueue
};
std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
@@ -133,6 +134,7 @@
hardware::hidl_vec<hardware::camera::device::V3_4::PhysicalCameraMetadata> noPhysMetadata;
+ std::string activePhysicalId("");
HidlCaptureOutputStates states {
{mId,
mOfflineReqsLock, mLastCompletedRegularFrameNumber,
@@ -147,7 +149,7 @@
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
mBufferRecords, /*legacyClient*/ false, mMinExpectedDuration, mIsFixedFps,
- /*overrideToPortrait*/false}, mResultMetadataQueue
+ /*overrideToPortrait*/false, activePhysicalId}, mResultMetadataQueue
};
std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
@@ -169,6 +171,7 @@
listener = mListener.promote();
}
+ std::string activePhysicalId("");
HidlCaptureOutputStates states {
{mId,
mOfflineReqsLock, mLastCompletedRegularFrameNumber,
@@ -183,7 +186,7 @@
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
mBufferRecords, /*legacyClient*/ false, mMinExpectedDuration, mIsFixedFps,
- /*overrideToPortrait*/false}, mResultMetadataQueue
+ /*overrideToPortrait*/false, activePhysicalId}, mResultMetadataQueue
};
for (const auto& msg : msgs) {
camera3::notify(states, msg);
diff --git a/services/camera/libcameraservice/hidl/HidlCameraService.cpp b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
index 259e8a5..fc063ab 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraService.cpp
+++ b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
@@ -65,7 +65,7 @@
HStatus status = HStatus::NO_ERROR;
binder::Status serviceRet =
mAidlICameraService->getCameraCharacteristics(String16(cameraId.c_str()),
- /*targetSdkVersion*/__ANDROID_API_FUTURE__, /*overrideToPortrait*/true,
+ /*targetSdkVersion*/__ANDROID_API_FUTURE__, /*overrideToPortrait*/false,
&cameraMetadata);
HCameraMetadata hidlMetadata;
if (!serviceRet.isOk()) {
@@ -117,7 +117,7 @@
binder::Status serviceRet = mAidlICameraService->connectDevice(
callbacks, String16(cameraId.c_str()), String16(""), {},
hardware::ICameraService::USE_CALLING_UID, 0/*oomScoreOffset*/,
- /*targetSdkVersion*/__ANDROID_API_FUTURE__, /*overrideToPortrait*/true,
+ /*targetSdkVersion*/__ANDROID_API_FUTURE__, /*overrideToPortrait*/false,
/*out*/&deviceRemote);
HStatus status = HStatus::NO_ERROR;
if (!serviceRet.isOk()) {
diff --git a/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp b/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
index 09f8eb6..120d43d 100644
--- a/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
+++ b/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
@@ -321,6 +321,7 @@
rc = mCameraService->connect(this, cameraId, String16(),
android::CameraService::USE_CALLING_UID, android::CameraService::USE_CALLING_PID,
/*targetSdkVersion*/__ANDROID_API_FUTURE__, /*overrideToPortrait*/true,
+ /*forceSlowJpegMode*/false,
&cameraDevice);
if (!rc.isOk()) {
// camera not connected
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
index 7dde268..ad02959 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
@@ -127,7 +127,7 @@
size_t getUHRMaxJpegBufferSize(camera3::Size uhrMaxJpegSize,
camera3::Size defaultMaxJpegSize, size_t defaultMaxJpegBufferSize) {
- return (uhrMaxJpegSize.width * uhrMaxJpegSize.height) /
+ return ((float)uhrMaxJpegSize.width * uhrMaxJpegSize.height) /
(defaultMaxJpegSize.width * defaultMaxJpegSize.height) * defaultMaxJpegBufferSize;
}
diff --git a/services/mediametrics/statsd_codec.cpp b/services/mediametrics/statsd_codec.cpp
index c5957e9..cb5e783 100644
--- a/services/mediametrics/statsd_codec.cpp
+++ b/services/mediametrics/statsd_codec.cpp
@@ -444,6 +444,12 @@
}
AStatsEvent_writeInt32(event, hdrFormat);
+ int64_t codecId = 0;
+ if (item->getInt64("android.media.mediacodec.id", &codecId)) {
+ metrics_proto.set_codec_id(codecId);
+ }
+ AStatsEvent_writeInt64(event, codecId);
+
int err = AStatsEvent_write(event);
if (err < 0) {
ALOGE("Failed to write codec metrics to statsd (%d)", err);
diff --git a/services/mediaresourcemanager/Android.bp b/services/mediaresourcemanager/Android.bp
index 2b8245e..a2bd5e1 100644
--- a/services/mediaresourcemanager/Android.bp
+++ b/services/mediaresourcemanager/Android.bp
@@ -17,6 +17,7 @@
"aidl/android/media/MediaResourceParcel.aidl",
"aidl/android/media/MediaResourcePolicyParcel.aidl",
"aidl/android/media/ClientInfoParcel.aidl",
+ "aidl/android/media/ClientConfigParcel.aidl",
],
path: "aidl",
}
@@ -73,9 +74,11 @@
name: "libresourcemanagerservice",
srcs: [
+ "ResourceManagerMetrics.cpp",
"ResourceManagerService.cpp",
"ResourceObserverService.cpp",
"ServiceLog.cpp",
+ "UidObserver.cpp",
// TODO: convert to AIDL?
"IMediaResourceMonitor.cpp",
@@ -92,6 +95,7 @@
"libstatspull",
"libstatssocket",
"libprotobuf-cpp-lite",
+ "libactivitymanager_aidl",
],
static_libs: [
diff --git a/services/mediaresourcemanager/ResourceManagerMetrics.cpp b/services/mediaresourcemanager/ResourceManagerMetrics.cpp
new file mode 100644
index 0000000..f8cdb80
--- /dev/null
+++ b/services/mediaresourcemanager/ResourceManagerMetrics.cpp
@@ -0,0 +1,657 @@
+/*
+**
+** Copyright 2023, 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 "ResourceManagerMetrics"
+#include <utils/Log.h>
+#include <mediautils/ProcessInfo.h>
+
+#include <stats_media_metrics.h>
+
+#include "UidObserver.h"
+#include "ResourceManagerMetrics.h"
+
+#include <cmath>
+#include <sstream>
+
+namespace android {
+
+using stats::media_metrics::stats_write;
+using stats::media_metrics::MEDIA_CODEC_STARTED;
+using stats::media_metrics::MEDIA_CODEC_STOPPED;
+// Disabling this for now.
+#ifdef ENABLE_MEDIA_CODEC_CONCURRENT_USAGE_REPORTED
+using stats::media_metrics::MEDIA_CODEC_CONCURRENT_USAGE_REPORTED;
+#endif
+using stats::media_metrics::MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED;
+using stats::media_metrics::MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_SUCCESS;
+using stats::media_metrics::\
+ MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_NO_CLIENTS;
+using stats::media_metrics::\
+ MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_RECLAIM_RESOURCES;
+
+inline const char* getCodecType(MediaResourceSubType codecType) {
+ switch (codecType) {
+ case MediaResourceSubType::kAudioCodec: return "Audio";
+ case MediaResourceSubType::kVideoCodec: return "Video";
+ case MediaResourceSubType::kImageCodec: return "Image";
+ case MediaResourceSubType::kUnspecifiedSubType:
+ default:
+ return "Unspecified";
+ }
+ return "Unspecified";
+}
+
+static CodecBucket getCodecBucket(bool isHardware,
+ bool isEncoder,
+ MediaResourceSubType codecType) {
+ if (isHardware) {
+ switch (codecType) {
+ case MediaResourceSubType::kAudioCodec:
+ if (isEncoder) return HwAudioEncoder;
+ return HwAudioDecoder;
+ case MediaResourceSubType::kVideoCodec:
+ if (isEncoder) return HwVideoEncoder;
+ return HwVideoDecoder;
+ case MediaResourceSubType::kImageCodec:
+ if (isEncoder) return HwImageEncoder;
+ return HwImageDecoder;
+ case MediaResourceSubType::kUnspecifiedSubType:
+ default:
+ return CodecBucketUnspecified;
+ }
+ } else {
+ switch (codecType) {
+ case MediaResourceSubType::kAudioCodec:
+ if (isEncoder) return SwAudioEncoder;
+ return SwAudioDecoder;
+ case MediaResourceSubType::kVideoCodec:
+ if (isEncoder) return SwVideoEncoder;
+ return SwVideoDecoder;
+ case MediaResourceSubType::kImageCodec:
+ if (isEncoder) return SwImageEncoder;
+ return SwImageDecoder;
+ case MediaResourceSubType::kUnspecifiedSubType:
+ default:
+ return CodecBucketUnspecified;
+ }
+ }
+
+ return CodecBucketUnspecified;
+}
+
+static bool getLogMessage(int hwCount, int swCount, std::stringstream& logMsg) {
+ bool update = false;
+ logMsg.clear();
+
+ if (hwCount > 0) {
+ logMsg << " HW: " << hwCount;
+ update = true;
+ }
+ if (swCount > 0) {
+ logMsg << " SW: " << swCount;
+ update = true;
+ }
+
+ if (update) {
+ logMsg << " ] ";
+ }
+ return update;
+}
+
+ResourceManagerMetrics::ResourceManagerMetrics(const sp<ProcessInfoInterface>& processInfo) {
+ // Create a process termination watcher, with 5seconds of polling frequency.
+ mUidObserver = sp<UidObserver>::make(processInfo,
+ [this] (int32_t pid, uid_t uid) {
+ onProcessTerminated(pid, uid);
+ });
+ mUidObserver->start();
+}
+
+ResourceManagerMetrics::~ResourceManagerMetrics() {
+ mUidObserver->stop();
+}
+
+void ResourceManagerMetrics::addPid(int pid, uid_t uid) {
+ if (uid != 0) {
+ std::scoped_lock lock(mLock);
+ mUidObserver->add(pid, uid);
+ }
+}
+
+void ResourceManagerMetrics::notifyClientCreated(const ClientInfoParcel& clientInfo) {
+ std::scoped_lock lock(mLock);
+ // Update the resource instance count.
+ std::map<std::string, int>::iterator found = mConcurrentResourceCountMap.find(clientInfo.name);
+ if (found == mConcurrentResourceCountMap.end()) {
+ mConcurrentResourceCountMap[clientInfo.name] = 1;
+ } else {
+ found->second++;
+ }
+}
+
+void ResourceManagerMetrics::notifyClientReleased(const ClientInfoParcel& clientInfo) {
+ bool stopCalled = true;
+ ClientConfigParcel clientConfig;
+ {
+ std::scoped_lock lock(mLock);
+ ClientConfigMap::iterator found = mClientConfigMap.find(clientInfo.id);
+ if (found != mClientConfigMap.end()) {
+ // Release is called without Stop!
+ stopCalled = false;
+ clientConfig = found->second;
+ // Update the timestamp for stopping the codec.
+ clientConfig.timeStamp = systemTime(SYSTEM_TIME_MONOTONIC) / 1000LL;
+ }
+ }
+ if (!stopCalled) {
+ // call Stop to update the metrics.
+ notifyClientStopped(clientConfig);
+ }
+ {
+ std::scoped_lock lock(mLock);
+ // Update the resource instance count also.
+ std::map<std::string, int>::iterator found =
+ mConcurrentResourceCountMap.find(clientInfo.name);
+ if (found != mConcurrentResourceCountMap.end()) {
+ if (found->second > 0) {
+ found->second--;
+ }
+ }
+ }
+}
+
+void ResourceManagerMetrics::notifyClientConfigChanged(const ClientConfigParcel& clientConfig) {
+ std::scoped_lock lock(mLock);
+ ClientConfigMap::iterator entry = mClientConfigMap.find(clientConfig.clientInfo.id);
+ if (entry != mClientConfigMap.end() &&
+ (clientConfig.codecType == MediaResourceSubType::kVideoCodec ||
+ clientConfig.codecType == MediaResourceSubType::kImageCodec)) {
+ int pid = clientConfig.clientInfo.pid;
+ // Update the pixel count for this process
+ updatePixelCount(pid, clientConfig.width * (long)clientConfig.height,
+ entry->second.width * (long)entry->second.height);
+ // Update the resolution in the record.
+ entry->second.width = clientConfig.width;
+ entry->second.height = clientConfig.height;
+ }
+}
+
+void ResourceManagerMetrics::notifyClientStarted(const ClientConfigParcel& clientConfig) {
+ std::scoped_lock lock(mLock);
+ int pid = clientConfig.clientInfo.pid;
+ // We need to observer this process.
+ mUidObserver->add(pid, clientConfig.clientInfo.uid);
+
+ // Update the client config for thic client.
+ mClientConfigMap[clientConfig.clientInfo.id] = clientConfig;
+
+ // Update the concurrent codec count for this process.
+ CodecBucket codecBucket = getCodecBucket(clientConfig.isHardware,
+ clientConfig.isEncoder,
+ clientConfig.codecType);
+ increaseConcurrentCodecs(pid, codecBucket);
+
+ if (clientConfig.codecType == MediaResourceSubType::kVideoCodec ||
+ clientConfig.codecType == MediaResourceSubType::kImageCodec) {
+ // Update the pixel count for this process
+ increasePixelCount(pid, clientConfig.width * (long)clientConfig.height);
+ }
+
+ // System concurrent codec usage
+ int systemConcurrentCodecs = mConcurrentCodecsMap[codecBucket];
+ // Process/Application concurrent codec usage for this type of codec
+ const ConcurrentCodecs& concurrentCodecs = mProcessConcurrentCodecsMap[pid];
+ int appConcurrentCodecs = concurrentCodecs.mCurrent[codecBucket];
+ int hwVideoCodecs = concurrentCodecs.mHWVideoCodecs;
+ int swVideoCodecs = concurrentCodecs.mSWVideoCodecs;
+ int videoCodecs = concurrentCodecs.mVideoCodecs;
+ int audioCodecs = concurrentCodecs.mAudioCodecs;
+ int imageCodecs = concurrentCodecs.mImageCodecs;
+ // Process/Application's current pixel count.
+ long pixelCount = 0;
+ std::map<int32_t, PixelCount>::iterator it = mProcessPixelsMap.find(pid);
+ if (it != mProcessPixelsMap.end()) {
+ pixelCount = it->second.mCurrent;
+ }
+
+ int result = stats_write(
+ MEDIA_CODEC_STARTED,
+ clientConfig.clientInfo.uid,
+ clientConfig.id,
+ clientConfig.clientInfo.name.c_str(),
+ static_cast<int32_t>(clientConfig.codecType),
+ clientConfig.isEncoder,
+ clientConfig.isHardware,
+ clientConfig.width, clientConfig.height,
+ systemConcurrentCodecs,
+ appConcurrentCodecs,
+ pixelCount,
+ hwVideoCodecs,
+ swVideoCodecs,
+ videoCodecs,
+ audioCodecs,
+ imageCodecs);
+
+ ALOGV("%s: Pushed MEDIA_CODEC_STARTED atom: "
+ "Process[pid(%d): uid(%d)] "
+ "Codec: [%s: %ju] is %s %s %s "
+ "Timestamp: %jd "
+ "Resolution: %d x %d "
+ "ConcurrentCodec[%d]={System: %d App: %d} "
+ "AppConcurrentCodecs{Video: %d(HW[%d] SW[%d]) Audio: %d Image: %d} "
+ "result: %d",
+ __func__,
+ pid, clientConfig.clientInfo.uid,
+ clientConfig.clientInfo.name.c_str(),
+ clientConfig.id,
+ clientConfig.isHardware? "hardware" : "software",
+ getCodecType(clientConfig.codecType),
+ clientConfig.isEncoder? "encoder" : "decoder",
+ clientConfig.timeStamp,
+ clientConfig.width, clientConfig.height,
+ codecBucket, systemConcurrentCodecs, appConcurrentCodecs,
+ videoCodecs, hwVideoCodecs, swVideoCodecs, audioCodecs, imageCodecs,
+ result);
+}
+
+void ResourceManagerMetrics::notifyClientStopped(const ClientConfigParcel& clientConfig) {
+ std::scoped_lock lock(mLock);
+ int pid = clientConfig.clientInfo.pid;
+ // Update the concurrent codec count for this process.
+ CodecBucket codecBucket = getCodecBucket(clientConfig.isHardware,
+ clientConfig.isEncoder,
+ clientConfig.codecType);
+ decreaseConcurrentCodecs(pid, codecBucket);
+
+ if (clientConfig.codecType == MediaResourceSubType::kVideoCodec ||
+ clientConfig.codecType == MediaResourceSubType::kImageCodec) {
+ // Update the pixel count for this process
+ decreasePixelCount(pid, clientConfig.width * (long)clientConfig.height);
+ }
+
+ // System concurrent codec usage
+ int systemConcurrentCodecs = mConcurrentCodecsMap[codecBucket];
+ // Process/Application concurrent codec usage for this type of codec
+ int appConcurrentCodecs = 0;
+ std::map<int32_t, ConcurrentCodecs>::iterator found = mProcessConcurrentCodecsMap.find(pid);
+ if (found != mProcessConcurrentCodecsMap.end()) {
+ appConcurrentCodecs = found->second.mCurrent[codecBucket];
+ }
+ // Process/Application's current pixel count.
+ long pixelCount = 0;
+ std::map<int32_t, PixelCount>::iterator it = mProcessPixelsMap.find(pid);
+ if (it != mProcessPixelsMap.end()) {
+ pixelCount = it->second.mCurrent;
+ }
+
+ // calculate the usageTime as:
+ // MediaCodecStopped.clientConfig.timeStamp -
+ // MediaCodecStarted.clientConfig.timeStamp
+ int64_t usageTime = 0;
+ ClientConfigMap::iterator entry = mClientConfigMap.find(clientConfig.clientInfo.id);
+ if (entry != mClientConfigMap.end()) {
+ usageTime = clientConfig.timeStamp - entry->second.timeStamp;
+ // And we can erase this config now.
+ mClientConfigMap.erase(entry);
+ } else {
+ ALOGW("%s: Start Config is missing!", __func__);
+ }
+
+ int result = stats_write(
+ MEDIA_CODEC_STOPPED,
+ clientConfig.clientInfo.uid,
+ clientConfig.id,
+ clientConfig.clientInfo.name.c_str(),
+ static_cast<int32_t>(clientConfig.codecType),
+ clientConfig.isEncoder,
+ clientConfig.isHardware,
+ clientConfig.width, clientConfig.height,
+ systemConcurrentCodecs,
+ appConcurrentCodecs,
+ pixelCount,
+ usageTime);
+ ALOGV("%s: Pushed MEDIA_CODEC_STOPPED atom: "
+ "Process[pid(%d): uid(%d)] "
+ "Codec: [%s: %ju] is %s %s %s "
+ "Timestamp: %jd Usage time: %jd "
+ "Resolution: %d x %d "
+ "ConcurrentCodec[%d]={System: %d App: %d} "
+ "result: %d",
+ __func__,
+ pid, clientConfig.clientInfo.uid,
+ clientConfig.clientInfo.name.c_str(),
+ clientConfig.id,
+ clientConfig.isHardware? "hardware" : "software",
+ getCodecType(clientConfig.codecType),
+ clientConfig.isEncoder? "encoder" : "decoder",
+ clientConfig.timeStamp, usageTime,
+ clientConfig.width, clientConfig.height,
+ codecBucket, systemConcurrentCodecs, appConcurrentCodecs,
+ result);
+}
+
+void ResourceManagerMetrics::onProcessTerminated(int32_t pid, uid_t uid) {
+ std::scoped_lock lock(mLock);
+ // post MediaCodecConcurrentUsageReported for this terminated pid.
+ pushConcurrentUsageReport(pid, uid);
+}
+
+void ResourceManagerMetrics::pushConcurrentUsageReport(int32_t pid, uid_t uid) {
+ // Process/Application peak concurrent codec usage
+ std::map<int32_t, ConcurrentCodecs>::iterator found = mProcessConcurrentCodecsMap.find(pid);
+ if (found == mProcessConcurrentCodecsMap.end()) {
+ ALOGI("%s: No MEDIA_CODEC_CONCURRENT_USAGE_REPORTED atom Entry for: "
+ "Application[pid(%d): uid(%d)]", __func__, pid, uid);
+ return;
+ }
+ const ConcurrentCodecsMap& codecsMap = found->second.mPeak;
+ int peakHwAudioEncoderCount = codecsMap[HwAudioEncoder];
+ int peakHwAudioDecoderCount = codecsMap[HwAudioDecoder];
+ int peakHwVideoEncoderCount = codecsMap[HwVideoEncoder];
+ int peakHwVideoDecoderCount = codecsMap[HwVideoDecoder];
+ int peakHwImageEncoderCount = codecsMap[HwImageEncoder];
+ int peakHwImageDecoderCount = codecsMap[HwImageDecoder];
+ int peakSwAudioEncoderCount = codecsMap[SwAudioEncoder];
+ int peakSwAudioDecoderCount = codecsMap[SwAudioDecoder];
+ int peakSwVideoEncoderCount = codecsMap[SwVideoEncoder];
+ int peakSwVideoDecoderCount = codecsMap[SwVideoDecoder];
+ int peakSwImageEncoderCount = codecsMap[SwImageEncoder];
+ int peakSwImageDecoderCount = codecsMap[SwImageDecoder];
+
+ long peakPixels = 0;
+ std::map<int32_t, PixelCount>::iterator it = mProcessPixelsMap.find(pid);
+ if (it == mProcessPixelsMap.end()) {
+ ALOGI("%s: No Video Codec Entry for Application[pid(%d): uid(%d)]",
+ __func__, pid, uid);
+ } else {
+ peakPixels = it->second.mPeak;
+ }
+ std::string peakPixelsLog("Peak Pixels: " + std::to_string(peakPixels));
+
+ std::stringstream peakCodecLog;
+ peakCodecLog << "Peak { ";
+ std::stringstream logMsg;
+ if (getLogMessage(peakHwAudioEncoderCount, peakSwAudioEncoderCount, logMsg)) {
+ peakCodecLog << "AudioEnc[" << logMsg.str();
+ }
+ if (getLogMessage(peakHwAudioDecoderCount, peakSwAudioDecoderCount, logMsg)) {
+ peakCodecLog << "AudioDec[" << logMsg.str();
+ }
+ if (getLogMessage(peakHwVideoEncoderCount, peakSwVideoEncoderCount, logMsg)) {
+ peakCodecLog << "VideoEnc[" << logMsg.str();
+ }
+ if (getLogMessage(peakHwVideoDecoderCount, peakSwVideoDecoderCount, logMsg)) {
+ peakCodecLog << "VideoDec[" << logMsg.str();
+ }
+ if (getLogMessage(peakHwImageEncoderCount, peakSwImageEncoderCount, logMsg)) {
+ peakCodecLog << "ImageEnc[" << logMsg.str();
+ }
+ if (getLogMessage(peakHwImageDecoderCount, peakSwImageDecoderCount, logMsg)) {
+ peakCodecLog << "ImageDec[" << logMsg.str();
+ }
+ peakCodecLog << "}";
+
+#ifdef ENABLE_MEDIA_CODEC_CONCURRENT_USAGE_REPORTED
+ int result = stats_write(
+ MEDIA_CODEC_CONCURRENT_USAGE_REPORTED,
+ uid,
+ peakHwVideoDecoderCount,
+ peakHwVideoEncoderCount,
+ peakSwVideoDecoderCount,
+ peakSwVideoEncoderCount,
+ peakHwAudioDecoderCount,
+ peakHwAudioEncoderCount,
+ peakSwAudioDecoderCount,
+ peakSwAudioEncoderCount,
+ peakHwImageDecoderCount,
+ peakHwImageEncoderCount,
+ peakSwImageDecoderCount,
+ peakSwImageEncoderCount,
+ peakPixels);
+ ALOGI("%s: Pushed MEDIA_CODEC_CONCURRENT_USAGE_REPORTED atom: "
+ "Process[pid(%d): uid(%d)] %s %s result: %d",
+ __func__, pid, uid, peakCodecLog.str().c_str(), peakPixelsLog.c_str(), result);
+#else
+ ALOGI("%s: Concurrent Codec Usage Report for the Process[pid(%d): uid(%d)] is %s %s",
+ __func__, pid, uid, peakCodecLog.str().c_str(), peakPixelsLog.c_str());
+#endif
+}
+
+void ResourceManagerMetrics::pushReclaimAtom(const ClientInfoParcel& clientInfo,
+ const std::vector<int>& priorities,
+ const Vector<std::shared_ptr<IResourceManagerClient>>& clients,
+ const PidUidVector& idList, bool reclaimed) {
+ // Construct the metrics for codec reclaim as a pushed atom.
+ // 1. Information about the requester.
+ // - UID and the priority (oom score)
+ int32_t callingPid = clientInfo.pid;
+ int32_t requesterUid = clientInfo.uid;
+ std::string clientName = clientInfo.name;
+ int requesterPriority = priorities[0];
+
+ // 2. Information about the codec.
+ // - Name of the codec requested
+ // - Number of concurrent codecs running.
+ int32_t noOfConcurrentCodecs = 0;
+ std::map<std::string, int>::iterator found = mConcurrentResourceCountMap.find(clientName);
+ if (found != mConcurrentResourceCountMap.end()) {
+ noOfConcurrentCodecs = found->second;
+ }
+
+ // 3. Information about the Reclaim:
+ // - Status of reclaim request
+ // - How many codecs are reclaimed
+ // - For each codecs reclaimed, information of the process that it belonged to:
+ // - UID and the Priority (oom score)
+ int32_t reclaimStatus = MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_SUCCESS;
+ if (!reclaimed) {
+ if (clients.size() == 0) {
+ // No clients to reclaim from
+ reclaimStatus =
+ MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_NO_CLIENTS;
+ } else {
+ // Couldn't reclaim resources from the clients
+ reclaimStatus =
+ MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_RECLAIM_RESOURCES;
+ }
+ }
+ int32_t noOfCodecsReclaimed = clients.size();
+ int32_t targetIndex = 1;
+ for (PidUidVector::const_reference id : idList) {
+ int32_t targetUid = id.second;
+ int targetPriority = priorities[targetIndex];
+ // Post the pushed atom
+ int result = stats_write(
+ MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED,
+ requesterUid,
+ requesterPriority,
+ clientName.c_str(),
+ noOfConcurrentCodecs,
+ reclaimStatus,
+ noOfCodecsReclaimed,
+ targetIndex,
+ targetUid,
+ targetPriority);
+ ALOGI("%s: Pushed MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED atom: "
+ "Requester[pid(%d): uid(%d): priority(%d)] "
+ "Codec: [%s] "
+ "No of concurrent codecs: %d "
+ "Reclaim Status: %d "
+ "No of codecs reclaimed: %d "
+ "Target[%d][pid(%d): uid(%d): priority(%d)] result: %d",
+ __func__, callingPid, requesterUid, requesterPriority,
+ clientName.c_str(), noOfConcurrentCodecs,
+ reclaimStatus, noOfCodecsReclaimed,
+ targetIndex, id.first, targetUid, targetPriority, result);
+ targetIndex++;
+ }
+}
+
+void ResourceManagerMetrics::increaseConcurrentCodecs(int32_t pid,
+ CodecBucket codecBucket) {
+ // Increase the codec usage across the system.
+ mConcurrentCodecsMap[codecBucket]++;
+
+ // Now update the codec usage for this (pid) process.
+ std::map<int32_t, ConcurrentCodecs>::iterator found = mProcessConcurrentCodecsMap.find(pid);
+ if (found == mProcessConcurrentCodecsMap.end()) {
+ ConcurrentCodecs codecs;
+ codecs.mCurrent[codecBucket] = 1;
+ codecs.mPeak[codecBucket] = 1;
+ auto added = mProcessConcurrentCodecsMap.emplace(pid, codecs);
+ found = added.first;
+ } else {
+ found->second.mCurrent[codecBucket]++;
+ // Check if it's the peak count for this slot.
+ if (found->second.mPeak[codecBucket] < found->second.mCurrent[codecBucket]) {
+ found->second.mPeak[codecBucket] = found->second.mCurrent[codecBucket];
+ }
+ }
+
+ switch (codecBucket) {
+ case HwVideoEncoder:
+ case HwVideoDecoder:
+ case SwVideoEncoder:
+ case SwVideoDecoder:
+ if (codecBucket == HwVideoEncoder || codecBucket == HwVideoDecoder) {
+ found->second.mHWVideoCodecs++;
+ } else {
+ found->second.mSWVideoCodecs++;
+ }
+ found->second.mVideoCodecs++;
+ break;
+ case HwAudioEncoder:
+ case HwAudioDecoder:
+ case SwAudioEncoder:
+ case SwAudioDecoder:
+ found->second.mAudioCodecs++;
+ break;
+ case HwImageEncoder:
+ case HwImageDecoder:
+ case SwImageEncoder:
+ case SwImageDecoder:
+ found->second.mImageCodecs++;
+ break;
+ default:
+ break;
+ }
+}
+
+void ResourceManagerMetrics::decreaseConcurrentCodecs(int32_t pid,
+ CodecBucket codecBucket) {
+ // Decrease the codec usage across the system.
+ if (mConcurrentCodecsMap[codecBucket] > 0) {
+ mConcurrentCodecsMap[codecBucket]--;
+ }
+
+ // Now update the codec usage for this (pid) process.
+ std::map<int32_t, ConcurrentCodecs>::iterator found = mProcessConcurrentCodecsMap.find(pid);
+ if (found != mProcessConcurrentCodecsMap.end()) {
+ if (found->second.mCurrent[codecBucket] > 0) {
+ found->second.mCurrent[codecBucket]--;
+ }
+
+ switch (codecBucket) {
+ case HwVideoEncoder:
+ case HwVideoDecoder:
+ case SwVideoEncoder:
+ case SwVideoDecoder:
+ if (codecBucket == HwVideoEncoder || codecBucket == HwVideoDecoder) {
+ found->second.mHWVideoCodecs--;
+ } else {
+ found->second.mSWVideoCodecs--;
+ }
+ found->second.mVideoCodecs--;
+ break;
+ case HwAudioEncoder:
+ case HwAudioDecoder:
+ case SwAudioEncoder:
+ case SwAudioDecoder:
+ found->second.mAudioCodecs--;
+ break;
+ case HwImageEncoder:
+ case HwImageDecoder:
+ case SwImageEncoder:
+ case SwImageDecoder:
+ found->second.mImageCodecs--;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void ResourceManagerMetrics::increasePixelCount(int32_t pid, long pixels) {
+ // Now update the current pixel usage for this (pid) process.
+ std::map<int32_t, PixelCount>::iterator found = mProcessPixelsMap.find(pid);
+ if (found == mProcessPixelsMap.end()) {
+ PixelCount pixelCount {pixels, pixels};
+ mProcessPixelsMap.emplace(pid, pixelCount);
+ } else {
+ if (__builtin_add_overflow(found->second.mCurrent, pixels, &found->second.mCurrent)) {
+ ALOGI("Pixel Count overflow");
+ return;
+ }
+ // Check if it's the peak count for this slot.
+ if (found->second.mPeak < found->second.mCurrent) {
+ found->second.mPeak = found->second.mCurrent;
+ }
+ }
+}
+
+void ResourceManagerMetrics::updatePixelCount(int32_t pid, long newPixels, long lastPixels) {
+ // Since there is change in resolution, decrease it by last pixels and
+ // increase it by new pixels.
+ decreasePixelCount(pid, lastPixels);
+ increasePixelCount(pid, newPixels);
+}
+
+void ResourceManagerMetrics::decreasePixelCount(int32_t pid, long pixels) {
+ // Now update the current pixel usage for this (pid) process.
+ std::map<int32_t, PixelCount>::iterator found = mProcessPixelsMap.find(pid);
+ if (found != mProcessPixelsMap.end()) {
+ if (found->second.mCurrent < pixels) {
+ found->second.mCurrent = 0;
+ } else {
+ if (__builtin_sub_overflow(found->second.mCurrent, pixels, &found->second.mCurrent)) {
+ ALOGI("Pixel Count overflow");
+ return;
+ }
+ }
+ }
+}
+
+long ResourceManagerMetrics::getPeakConcurrentPixelCount(int pid) const {
+ std::map<int32_t, PixelCount>::const_iterator found = mProcessPixelsMap.find(pid);
+ if (found != mProcessPixelsMap.end()) {
+ return found->second.mPeak;
+ }
+
+ return 0;
+}
+
+long ResourceManagerMetrics::getCurrentConcurrentPixelCount(int pid) const {
+ std::map<int32_t, PixelCount>::const_iterator found = mProcessPixelsMap.find(pid);
+ if (found != mProcessPixelsMap.end()) {
+ return found->second.mCurrent;
+ }
+
+ return 0;
+}
+
+} // namespace android
diff --git a/services/mediaresourcemanager/ResourceManagerMetrics.h b/services/mediaresourcemanager/ResourceManagerMetrics.h
new file mode 100644
index 0000000..3124aa2
--- /dev/null
+++ b/services/mediaresourcemanager/ResourceManagerMetrics.h
@@ -0,0 +1,193 @@
+/*
+**
+** Copyright 2023, 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.
+*/
+
+#ifndef ANDROID_MEDIA_RESOURCEMANAGERMETRICS_H_
+#define ANDROID_MEDIA_RESOURCEMANAGERMETRICS_H_
+
+#include "ResourceManagerService.h"
+
+namespace android {
+
+using ::aidl::android::media::ClientInfoParcel;
+using ::aidl::android::media::ClientConfigParcel;
+using ::aidl::android::media::IResourceManagerClient;
+
+struct ProcessInfoInterface;
+
+class UidObserver;
+
+//
+// Enumeration for Codec bucket based on:
+// - Encoder or Decoder
+// - hardware implementation or not
+// - Audio/Video/Image codec
+//
+enum CodecBucket {
+ CodecBucketUnspecified = 0,
+ HwAudioEncoder = 1,
+ HwAudioDecoder = 2,
+ HwVideoEncoder = 3,
+ HwVideoDecoder = 4,
+ HwImageEncoder = 5,
+ HwImageDecoder = 6,
+ SwAudioEncoder = 7,
+ SwAudioDecoder = 8,
+ SwVideoEncoder = 9,
+ SwVideoDecoder = 10,
+ SwImageEncoder = 11,
+ SwImageDecoder = 12,
+ CodecBucketMaxSize = 13,
+};
+
+// Map of client id and client configuration, when it was started last.
+typedef std::map<int64_t, ClientConfigParcel> ClientConfigMap;
+
+// Map of pid and the uid.
+typedef std::map<int32_t, uid_t> PidUidMap;
+
+// Map of concurrent codes by Codec type bucket.
+struct ConcurrentCodecsMap {
+ int& operator[](CodecBucket index) {
+ return mCodec[index];
+ }
+
+ const int& operator[](CodecBucket index) const {
+ return mCodec[index];
+ }
+
+private:
+ int mCodec[CodecBucketMaxSize] = {0};
+};
+
+// Current and Peak ConcurrentCodecMap for a process.
+struct ConcurrentCodecs {
+ ConcurrentCodecsMap mCurrent;
+ ConcurrentCodecsMap mPeak;
+ // concurrent HW Video codecs.
+ int mHWVideoCodecs;
+ // concurrent SW Video codecs.
+ int mSWVideoCodecs;
+ // concurrent Video codecs.
+ int mVideoCodecs;
+ // concurrent Audio codecs.
+ int mAudioCodecs;
+ // concurrent Image codecs.
+ int mImageCodecs;
+};
+
+// Current and Peak pixel count for a process.
+struct PixelCount {
+ long mCurrent = 0;
+ long mPeak = 0;
+};
+
+//
+// ResourceManagerMetrics class that maintaines concurrent codec count based:
+//
+// 1. # of concurrent active codecs (initialized, but aren't released yet) of given
+// implementation (by codec name) across the system.
+//
+// 2. # of concurrent codec usage (started, but not stopped yet), which is
+// measured using codec type bucket (CodecBucket) for:
+// - each process/application.
+// - across the system.
+// Also the peak count of the same for each process/application is maintained.
+//
+// 3. # of Peak Concurrent Pixels for each process/application.
+// This should help with understanding the (video) memory usage per
+// application.
+//
+//
+class ResourceManagerMetrics {
+public:
+ ResourceManagerMetrics(const sp<ProcessInfoInterface>& processInfo);
+ ~ResourceManagerMetrics();
+
+ // To be called when a client is created.
+ void notifyClientCreated(const ClientInfoParcel& clientInfo);
+
+ // To be called when a client is released.
+ void notifyClientReleased(const ClientInfoParcel& clientInfo);
+
+ // To be called when a client is started.
+ void notifyClientStarted(const ClientConfigParcel& clientConfig);
+
+ // To be called when a client is stopped.
+ void notifyClientStopped(const ClientConfigParcel& clientConfig);
+
+ // To be called when a client's configuration has changed.
+ void notifyClientConfigChanged(const ClientConfigParcel& clientConfig);
+
+ // To be called when after a reclaim event.
+ void pushReclaimAtom(const ClientInfoParcel& clientInfo,
+ const std::vector<int>& priorities,
+ const Vector<std::shared_ptr<IResourceManagerClient>>& clients,
+ const PidUidVector& idList, bool reclaimed);
+
+ // Add this pid/uid set to monitor for the process termination state.
+ void addPid(int pid, uid_t uid = 0);
+
+ // Get the peak concurrent pixel count (associated with the video codecs) for the process.
+ long getPeakConcurrentPixelCount(int pid) const;
+ // Get the current concurrent pixel count (associated with the video codecs) for the process.
+ long getCurrentConcurrentPixelCount(int pid) const;
+
+private:
+ ResourceManagerMetrics(const ResourceManagerMetrics&) = delete;
+ ResourceManagerMetrics(ResourceManagerMetrics&&) = delete;
+ ResourceManagerMetrics& operator=(const ResourceManagerMetrics&) = delete;
+ ResourceManagerMetrics& operator=(ResourceManagerMetrics&&) = delete;
+
+ // To increase/decrease the concurrent codec usage for a given CodecBucket.
+ void increaseConcurrentCodecs(int32_t pid, CodecBucket codecBucket);
+ void decreaseConcurrentCodecs(int32_t pid, CodecBucket codecBucket);
+
+ // To increase/update/decrease the concurrent pixels usage for a process.
+ void increasePixelCount(int32_t pid, long pixels);
+ void updatePixelCount(int32_t pid, long newPixels, long lastPixels);
+ void decreasePixelCount(int32_t pid, long pixels);
+
+ // Issued when the process/application with given pid/uid is terminated.
+ void onProcessTerminated(int32_t pid, uid_t uid);
+
+ // To push conccuret codec usage of a process/application.
+ void pushConcurrentUsageReport(int32_t pid, uid_t uid);
+
+private:
+ std::mutex mLock;
+
+ // Map of client id and the configuration.
+ ClientConfigMap mClientConfigMap;
+
+ // Concurrent and Peak Pixel count for each process/application.
+ std::map<int32_t, PixelCount> mProcessPixelsMap;
+
+ // Map of resources (name) and number of concurrent instances
+ std::map<std::string, int> mConcurrentResourceCountMap;
+
+ // Map of concurrent codes by CodecBucket across the system.
+ ConcurrentCodecsMap mConcurrentCodecsMap;
+ // Map of concurrent and peak codes by CodecBucket for each process/application.
+ std::map<int32_t, ConcurrentCodecs> mProcessConcurrentCodecsMap;
+
+ // Uid Observer to monitor the application termination.
+ sp<UidObserver> mUidObserver;
+};
+
+} // namespace android
+
+#endif // ANDROID_MEDIA_RESOURCEMANAGERMETRICS_H_
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 5582528..28a17b8 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -26,31 +26,24 @@
#include <cutils/sched_policy.h>
#include <dirent.h>
#include <media/MediaResourcePolicy.h>
-#include <media/stagefright/ProcessInfo.h>
+#include <media/stagefright/foundation/ABase.h>
#include <mediautils/BatteryNotifier.h>
+#include <mediautils/ProcessInfo.h>
#include <mediautils/SchedulingPolicyService.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
-#include <stats_media_metrics.h>
#include "IMediaResourceMonitor.h"
+#include "ResourceManagerMetrics.h"
#include "ResourceManagerService.h"
#include "ResourceObserverService.h"
#include "ServiceLog.h"
namespace android {
-using stats::media_metrics::stats_write;
-using stats::media_metrics::MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED;
-using stats::media_metrics::MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_SUCCESS;
-using stats::media_metrics::\
- MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_NO_CLIENTS;
-using stats::media_metrics::\
- MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_RECLAIM_RESOURCES;
-
//static
std::mutex ResourceManagerService::sCookieLock;
//static
@@ -60,8 +53,8 @@
class DeathNotifier : public RefBase {
public:
- DeathNotifier(const std::shared_ptr<ResourceManagerService> &service, int pid,
- int64_t clientId);
+ DeathNotifier(const std::shared_ptr<ResourceManagerService> &service,
+ const ClientInfoParcel& clientInfo);
virtual ~DeathNotifier() {}
@@ -71,13 +64,12 @@
protected:
std::weak_ptr<ResourceManagerService> mService;
- int mPid;
- int64_t mClientId;
+ const ClientInfoParcel mClientInfo;
};
DeathNotifier::DeathNotifier(const std::shared_ptr<ResourceManagerService> &service,
- int pid, int64_t clientId)
- : mService(service), mPid(pid), mClientId(clientId) {}
+ const ClientInfoParcel& clientInfo)
+ : mService(service), mClientInfo(clientInfo) {}
//static
void DeathNotifier::BinderDiedCallback(void* cookie) {
@@ -104,16 +96,16 @@
return;
}
- service->overridePid(mPid, -1);
+ service->overridePid(mClientInfo.pid, -1);
// thiz is freed in the call below, so it must be last call referring thiz
- ClientInfoParcel clientInfo{.pid = mPid, .id = mClientId};
- service->removeResource(clientInfo, false /*checkValid*/);
+ service->removeResource(mClientInfo, false /*checkValid*/);
}
class OverrideProcessInfoDeathNotifier : public DeathNotifier {
public:
OverrideProcessInfoDeathNotifier(const std::shared_ptr<ResourceManagerService> &service,
- int pid) : DeathNotifier(service, pid, 0) {}
+ const ClientInfoParcel& clientInfo)
+ : DeathNotifier(service, clientInfo) {}
virtual ~OverrideProcessInfoDeathNotifier() {}
@@ -128,7 +120,7 @@
return;
}
- service->removeProcessInfoOverride(mPid);
+ service->removeProcessInfoOverride(mClientInfo.pid);
}
template <typename T>
@@ -141,7 +133,7 @@
}
static bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
- MediaResourceParcel resource) {
+ const MediaResourceParcel& resource) {
if (type != resource.type) {
return false;
}
@@ -201,7 +193,11 @@
ResourceInfo info;
info.uid = uid;
info.clientId = clientId;
- info.name = name;
+ if (name.empty()) {
+ info.name = "<unknown client>";
+ } else {
+ info.name = name;
+ }
info.client = client;
info.cookie = 0;
info.pendingRemoval = false;
@@ -291,10 +287,7 @@
snprintf(buffer, SIZE, " Id: %lld\n", (long long)infos[j].clientId);
result.append(buffer);
- std::string clientName = "<unknown client>";
- if (infos[j].client != nullptr) {
- clientName = infos[j].name;
- }
+ std::string clientName = infos[j].name;
snprintf(buffer, SIZE, " Name: %s\n", clientName.c_str());
result.append(buffer);
@@ -356,6 +349,8 @@
mCpuBoostCount(0),
mDeathRecipient(AIBinder_DeathRecipient_new(DeathNotifier::BinderDiedCallback)) {
mSystemCB->noteResetVideo();
+ // Create ResourceManagerMetrics that handles all the metrics.
+ mResourceManagerMetrics = std::make_unique<ResourceManagerMetrics>(mProcessInfo);
}
//static
@@ -509,49 +504,16 @@
}
if (info.cookie == 0 && client != nullptr) {
info.cookie = addCookieAndLink_l(client,
- new DeathNotifier(ref<ResourceManagerService>(), pid, clientId));
+ new DeathNotifier(ref<ResourceManagerService>(), clientInfo));
}
if (mObserverService != nullptr && !resourceAdded.empty()) {
mObserverService->onResourceAdded(uid, pid, resourceAdded);
}
notifyResourceGranted(pid, resources);
- // Increase the instance count of the resource associated with this client.
- increaseResourceInstanceCount(clientId, name);
-
return Status::ok();
}
-void ResourceManagerService::increaseResourceInstanceCount(int64_t clientId,
- const std::string& name) {
- // Check whether this client has been looked into already.
- if (mClientIdSet.find(clientId) == mClientIdSet.end()) {
- mClientIdSet.insert(clientId);
- // Update the resource instance count.
- auto found = mConcurrentResourceCountMap.find(name);
- if (found == mConcurrentResourceCountMap.end()) {
- mConcurrentResourceCountMap[name] = 1;
- } else {
- found->second++;
- }
- }
-}
-
-void ResourceManagerService::decreaseResourceInstanceCount(int64_t clientId,
- const std::string& name) {
- // Since this client has been removed, remove it from mClientIdSet
- mClientIdSet.erase(clientId);
- // Update the resource instance count also.
- auto found = mConcurrentResourceCountMap.find(name);
- if (found != mConcurrentResourceCountMap.end()) {
- if (found->second == 1) {
- mConcurrentResourceCountMap.erase(found);
- } else {
- found->second--;
- }
- }
-}
-
Status ResourceManagerService::removeResource(const ClientInfoParcel& clientInfo,
const std::vector<MediaResourceParcel>& resources) {
int32_t pid = clientInfo.pid;
@@ -656,9 +618,8 @@
onLastRemoved(it->second, info);
}
- // Since this client has been removed, decrease the corresponding
- // resources instance count.
- decreaseResourceInstanceCount(clientId, info.name);
+ // Since this client has been removed, update the metrics collector.
+ mResourceManagerMetrics->notifyClientReleased(clientInfo);
removeCookieAndUnlink_l(info.client, info.cookie);
@@ -790,73 +751,19 @@
void ResourceManagerService::pushReclaimAtom(const ClientInfoParcel& clientInfo,
const Vector<std::shared_ptr<IResourceManagerClient>>& clients,
const PidUidVector& idVector, bool reclaimed) {
- // Construct the metrics for codec reclaim as a pushed atom.
- // 1. Information about the requester.
- // - UID and the priority (oom score)
int32_t callingPid = clientInfo.pid;
- int32_t requesterUid = clientInfo.uid;
- std::string clientName = clientInfo.name;
int requesterPriority = -1;
getPriority_l(callingPid, &requesterPriority);
+ std::vector<int> priorities;
+ priorities.push_back(requesterPriority);
- // 2. Information about the codec.
- // - Name of the codec requested
- // - Number of concurrent codecs running.
- int32_t noOfConcurrentCodecs = 0;
- auto found = mConcurrentResourceCountMap.find(clientName);
- if (found != mConcurrentResourceCountMap.end()) {
- noOfConcurrentCodecs = found->second;
- }
-
- // 3. Information about the Reclaim:
- // - Status of reclaim request
- // - How many codecs are reclaimed
- // - For each codecs reclaimed, information of the process that it belonged to:
- // - UID and the Priority (oom score)
- int32_t reclaimStatus = MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_SUCCESS;
- if (!reclaimed) {
- if (clients.size() == 0) {
- // No clients to reclaim from
- reclaimStatus =
- MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_NO_CLIENTS;
- } else {
- // Couldn't reclaim resources from the clients
- reclaimStatus =
- MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_RECLAIM_RESOURCES;
- }
- }
- int32_t noOfCodecsReclaimed = clients.size();
- int32_t targetIndex = 1;
- for (const auto& id : idVector) {
- int32_t targetUid = id.second;
+ for (PidUidVector::const_reference id : idVector) {
int targetPriority = -1;
getPriority_l(id.first, &targetPriority);
- // Post the pushed atom
- int result = stats_write(
- MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED,
- requesterUid,
- requesterPriority,
- clientName.c_str(),
- noOfConcurrentCodecs,
- reclaimStatus,
- noOfCodecsReclaimed,
- targetIndex,
- targetUid,
- targetPriority);
- ALOGI("%s: Pushed MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED atom: "
- "Requester[pid(%d): uid(%d): priority(%d)] "
- "Codec: [%s] "
- "No of concurrent codecs: %d "
- "Reclaim Status: %d "
- "No of codecs reclaimed: %d "
- "Target[%d][pid(%d): uid(%d): priority(%d)] "
- "Atom Size: %d",
- __func__, callingPid, requesterUid, requesterPriority,
- clientName.c_str(), noOfConcurrentCodecs,
- reclaimStatus, noOfCodecsReclaimed,
- targetIndex, id.first, targetUid, targetPriority, result);
- targetIndex++;
+ priorities.push_back(targetPriority);
}
+ mResourceManagerMetrics->pushReclaimAtom(clientInfo, priorities, clients,
+ idVector, reclaimed);
}
bool ResourceManagerService::reclaimUnconditionallyFrom(
@@ -932,6 +839,7 @@
mOverridePidMap.erase(originalPid);
if (newPid != -1) {
mOverridePidMap.emplace(originalPid, newPid);
+ mResourceManagerMetrics->addPid(newPid);
}
}
@@ -965,8 +873,12 @@
return Status::fromServiceSpecificError(BAD_VALUE);
}
+ ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(pid),
+ .uid = 0,
+ .id = 0,
+ .name = "<unknown client>"};
uintptr_t cookie = addCookieAndLink_l(client,
- new OverrideProcessInfoDeathNotifier(ref<ResourceManagerService>(), pid));
+ new OverrideProcessInfoDeathNotifier(ref<ResourceManagerService>(), clientInfo));
mProcessInfoOverrideMap.emplace(pid, ProcessInfoOverride{cookie, client});
@@ -1281,4 +1193,32 @@
return true;
}
+Status ResourceManagerService::notifyClientCreated(const ClientInfoParcel& clientInfo) {
+ mResourceManagerMetrics->notifyClientCreated(clientInfo);
+ return Status::ok();
+}
+
+Status ResourceManagerService::notifyClientStarted(const ClientConfigParcel& clientConfig) {
+ mResourceManagerMetrics->notifyClientStarted(clientConfig);
+ return Status::ok();
+}
+
+Status ResourceManagerService::notifyClientStopped(const ClientConfigParcel& clientConfig) {
+ mResourceManagerMetrics->notifyClientStopped(clientConfig);
+ return Status::ok();
+}
+
+Status ResourceManagerService::notifyClientConfigChanged(const ClientConfigParcel& clientConfig) {
+ mResourceManagerMetrics->notifyClientConfigChanged(clientConfig);
+ return Status::ok();
+}
+
+long ResourceManagerService::getPeakConcurrentPixelCount(int pid) const {
+ return mResourceManagerMetrics->getPeakConcurrentPixelCount(pid);
+}
+
+long ResourceManagerService::getCurrentConcurrentPixelCount(int pid) const {
+ return mResourceManagerMetrics->getCurrentConcurrentPixelCount(pid);
+}
+
} // namespace android
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index 0016a19..1519e0e 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -39,6 +39,7 @@
class ResourceObserverService;
class ServiceLog;
struct ProcessInfoInterface;
+class ResourceManagerMetrics;
using Status = ::ndk::ScopedAStatus;
using ::aidl::android::media::IResourceManagerClient;
@@ -46,6 +47,7 @@
using ::aidl::android::media::MediaResourceParcel;
using ::aidl::android::media::MediaResourcePolicyParcel;
using ::aidl::android::media::ClientInfoParcel;
+using ::aidl::android::media::ClientConfigParcel;
typedef std::map<std::tuple<
MediaResource::Type, MediaResource::SubType, std::vector<uint8_t>>,
@@ -61,6 +63,7 @@
bool pendingRemoval{false};
};
+// vector of <PID, UID>
typedef std::vector<std::pair<int32_t, uid_t>> PidUidVector;
// TODO: convert these to std::map
@@ -118,6 +121,14 @@
Status removeResource(const ClientInfoParcel& clientInfo, bool checkValid);
+ Status notifyClientCreated(const ClientInfoParcel& clientInfo) override;
+
+ Status notifyClientStarted(const ClientConfigParcel& clientConfig) override;
+
+ Status notifyClientStopped(const ClientConfigParcel& clientConfig) override;
+
+ Status notifyClientConfigChanged(const ClientConfigParcel& clientConfig) override;
+
private:
friend class ResourceManagerServiceTest;
friend class DeathNotifier;
@@ -182,15 +193,15 @@
void removeCookieAndUnlink_l(const std::shared_ptr<IResourceManagerClient>& client,
uintptr_t cookie);
- // To increase/decrease the number of instances of a given resource
- // associated with a client.
- void increaseResourceInstanceCount(int64_t clientId, const std::string& name);
- void decreaseResourceInstanceCount(int64_t clientId, const std::string& name);
-
void pushReclaimAtom(const ClientInfoParcel& clientInfo,
const Vector<std::shared_ptr<IResourceManagerClient>>& clients,
const PidUidVector& idList, bool reclaimed);
+ // Get the peak concurrent pixel count (associated with the video codecs) for the process.
+ long getPeakConcurrentPixelCount(int pid) const;
+ // Get the current concurrent pixel count (associated with the video codecs) for the process.
+ long getCurrentConcurrentPixelCount(int pid) const;
+
mutable Mutex mLock;
sp<ProcessInfoInterface> mProcessInfo;
sp<SystemCallbackInterface> mSystemCB;
@@ -211,11 +222,7 @@
static std::map<uintptr_t, sp<DeathNotifier> > sCookieToDeathNotifierMap
GUARDED_BY(sCookieLock);
std::shared_ptr<ResourceObserverService> mObserverService;
-
- // List of active clients
- std::set<int64_t> mClientIdSet;
- // Map of resources (name) and number of concurrent instances
- std::map<std::string, int> mConcurrentResourceCountMap;
+ std::unique_ptr<ResourceManagerMetrics> mResourceManagerMetrics;
};
// ----------------------------------------------------------------------------
diff --git a/services/mediaresourcemanager/UidObserver.cpp b/services/mediaresourcemanager/UidObserver.cpp
new file mode 100644
index 0000000..f321ebc
--- /dev/null
+++ b/services/mediaresourcemanager/UidObserver.cpp
@@ -0,0 +1,182 @@
+/*
+**
+** Copyright 2023, 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 "ResourceManagerMetrics"
+
+#include <android/binder_process.h>
+#include <mediautils/ProcessInfo.h>
+#include "UidObserver.h"
+
+namespace {
+const char* kActivityServiceName = "activity";
+}; // namespace anonymous
+
+namespace android {
+
+UidObserver::UidObserver(const sp<ProcessInfoInterface>& processInfo,
+ OnProcessTerminated onProcessTerminated) :
+ mRegistered(false),
+ mOnProcessTerminated(std::move(onProcessTerminated)),
+ mProcessInfo(processInfo) {
+}
+
+UidObserver::~UidObserver() {
+ stop();
+}
+
+void UidObserver::start() {
+ // Use check service to see if the activity service is available
+ // If not available then register for notifications, instead of blocking
+ // till the service is ready
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->checkService(String16(kActivityServiceName));
+ if (!binder) {
+ sm->registerForNotifications(String16(kActivityServiceName), this);
+ } else {
+ registerWithActivityManager();
+ }
+}
+
+void UidObserver::stop() {
+ std::scoped_lock lock{mLock};
+
+ if (mRegistered) {
+ // Unregistered with ActivityManager
+ mAm.unregisterUidObserver(this);
+ mAm.unlinkToDeath(this);
+ mRegistered = false;
+ }
+}
+
+void UidObserver::add(int pid, uid_t uid) {
+ bool needToRegister = false;
+ {
+ std::scoped_lock lock(mLock);
+ std::map<uid_t, std::set<int32_t>>::iterator found = mUids.find(uid);
+ if (found != mUids.end()) {
+ found->second.insert(pid);
+ } else {
+ std::set<int32_t> pids{pid};
+ mUids.emplace(uid, std::move(pids));
+ }
+ needToRegister = !mRegistered;
+ }
+ if (needToRegister) {
+ start();
+ }
+}
+
+void UidObserver::registerWithActivityManager() {
+ std::scoped_lock lock{mLock};
+
+ if (mRegistered) {
+ return;
+ }
+ status_t res = mAm.linkToDeath(this);
+ // Register for UID gone.
+ mAm.registerUidObserver(this, ActivityManager::UID_OBSERVER_GONE,
+ ActivityManager::PROCESS_STATE_UNKNOWN,
+ String16("mediaserver"));
+ if (res == OK) {
+ mRegistered = true;
+ ALOGV("UidObserver: Registered with ActivityManager");
+ }
+}
+
+void UidObserver::onServiceRegistration(const String16& name, const sp<IBinder>&) {
+ if (name != String16(kActivityServiceName)) {
+ return;
+ }
+
+ registerWithActivityManager();
+}
+
+void UidObserver::getTerminatedProcesses(const std::vector<int32_t>& pids,
+ std::vector<int32_t>& terminatedPids) {
+ std::vector<bool> existent;
+ terminatedPids.clear();
+ if (mProcessInfo->checkProcessExistent(pids, &existent)) {
+ for (size_t index = 0; index < existent.size(); index++) {
+ if (!existent[index]) {
+ // This process has been terminated already.
+ terminatedPids.push_back(pids[index]);
+ }
+ }
+ }
+}
+
+// This callback will be issued for every UID that is gone/terminated.
+// Since one UID could have multiple PIDs, this callback can be issued
+// multiple times with that same UID for each activity/pid.
+// So, we need to check which one among the PIDs (that share the same UID)
+// is gone.
+void UidObserver::onUidGone(uid_t uid, bool /*disabled*/) {
+ std::vector<int32_t> terminatedPids;
+ {
+ std::scoped_lock lock{mLock};
+ std::map<uid_t, std::set<int32_t>>::iterator found = mUids.find(uid);
+ if (found != mUids.end()) {
+ if (found->second.size() == 1) {
+ terminatedPids.push_back(*(found->second.begin()));
+ // Only one PID. So we can remove this UID entry.
+ mUids.erase(found);
+ } else {
+ // There are multiple PIDs with the same UID.
+ // Get the list of all terminated PIDs (with the same UID)
+ std::vector<int32_t> pids;
+ std::copy(found->second.begin(), found->second.end(), std::back_inserter(pids));
+ getTerminatedProcesses(pids, terminatedPids);
+ for (int32_t pid : terminatedPids) {
+ // Remove all the terminated PIDs
+ found->second.erase(pid);
+ }
+ // If all PIDs under this UID have terminated, remove this UID entry.
+ if (found->second.size() == 0) {
+ mUids.erase(uid);
+ }
+ }
+ }
+ }
+
+ for (int32_t pid : terminatedPids) {
+ mOnProcessTerminated(pid, uid);
+ }
+}
+
+void UidObserver::onUidActive(uid_t /*uid*/) {
+}
+
+void UidObserver::onUidIdle(uid_t /*uid*/, bool /*disabled*/) {
+}
+
+void UidObserver::onUidStateChanged(uid_t /*uid*/,
+ int32_t /*procState*/,
+ int64_t /*procStateSeq*/,
+ int32_t /*capability*/) {
+}
+
+void UidObserver::onUidProcAdjChanged(uid_t /*uid*/) {
+}
+
+void UidObserver::binderDied(const wp<IBinder>& /*who*/) {
+ std::scoped_lock lock{mLock};
+ ALOGE("UidObserver: ActivityManager has died");
+ mRegistered = false;
+}
+
+} // namespace android
diff --git a/services/mediaresourcemanager/UidObserver.h b/services/mediaresourcemanager/UidObserver.h
new file mode 100644
index 0000000..ed76839
--- /dev/null
+++ b/services/mediaresourcemanager/UidObserver.h
@@ -0,0 +1,116 @@
+/*
+**
+** Copyright 2023, 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.
+*/
+
+#ifndef ANDROID_MEDIA_UIDOBSERVER_H_
+#define ANDROID_MEDIA_UIDOBSERVER_H_
+
+#include <map>
+#include <set>
+#include <mutex>
+#include <functional>
+#include <binder/ActivityManager.h>
+#include <binder/IUidObserver.h>
+#include <binder/BinderService.h>
+
+namespace android {
+
+using OnProcessTerminated = std::function<void(int32_t pid, uid_t)>;
+
+struct ProcessInfoInterface;
+
+//
+// UidObserver class
+//
+// This class implements a callback mechanism to notify the termination of the
+// process/applications that are registered with this class.
+//
+// It uses ActivityManager get notification on when an UID is not existent
+// anymore.
+// Since one UID could have multiple PIDs, it uses ActivityManager
+// (through ProcessInfoInterface) to query for the process/application
+// state for the pids.
+//
+class UidObserver :
+ public BnUidObserver,
+ public virtual IBinder::DeathRecipient,
+ public virtual IServiceManager::LocalRegistrationCallback {
+public:
+ explicit UidObserver(const sp<ProcessInfoInterface>& processInfo,
+ OnProcessTerminated onProcessTerminated);
+ virtual ~UidObserver();
+
+ // Start registration (with Application Manager)
+ void start();
+ // Stop registration (with Application Manager)
+ void stop();
+
+ // Add this pid/uid to set of Uid to be observed.
+ void add(int pid, uid_t uid);
+
+private:
+ UidObserver() = delete;
+ UidObserver(const UidObserver&) = delete;
+ UidObserver(UidObserver&&) = delete;
+ UidObserver& operator=(const UidObserver&) = delete;
+ UidObserver& operator=(UidObserver&&) = delete;
+
+ // IUidObserver implementation.
+ void onUidGone(uid_t uid, bool disabled) override;
+ void onUidActive(uid_t uid) override;
+ void onUidIdle(uid_t uid, bool disabled) override;
+ void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq,
+ int32_t capability) override;
+ void onUidProcAdjChanged(uid_t uid) override;
+
+ // IServiceManager::LocalRegistrationCallback implementation.
+ void onServiceRegistration(const String16& name,
+ const sp<IBinder>& binder) override;
+
+ // IBinder::DeathRecipient implementation.
+ void binderDied(const wp<IBinder> &who) override;
+
+ // Registers with Application Manager for UID gone event
+ // to track the termination of Applications.
+ void registerWithActivityManager();
+
+ /*
+ * For a list of input pids, it will check whether the corresponding
+ * processes are already terminated or not.
+ *
+ * @param[in] pids List of pids to check whether they are terminated.
+ * @param[out] terminatedPids List of pid of terminated processes.
+ *
+ * Upon return, terminatedPids returns list of all the termibated pids
+ * that will be a subset of input pids (in that order).
+ * If none of the input pids have terminated, terminatedPids will be empty.
+ */
+ void getTerminatedProcesses(const std::vector<int32_t>& pids,
+ std::vector<int32_t>& terminatedPids);
+
+ bool mRegistered = false;
+ std::mutex mLock;
+ ActivityManager mAm;
+ // map of UID and all the PIDs associated with it
+ // as one UID could have multiple PIDs.
+ std::map<uid_t, std::set<int32_t>> mUids;
+ OnProcessTerminated mOnProcessTerminated;
+ sp<ProcessInfoInterface> mProcessInfo;
+};
+
+} // namespace android
+
+#endif //ANDROID_MEDIA_UIDOBSERVER_H_
diff --git a/services/mediaresourcemanager/aidl/android/media/ClientConfigParcel.aidl b/services/mediaresourcemanager/aidl/android/media/ClientConfigParcel.aidl
new file mode 100644
index 0000000..3c9c8c7
--- /dev/null
+++ b/services/mediaresourcemanager/aidl/android/media/ClientConfigParcel.aidl
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 2023, 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.
+ */
+
+package android.media;
+
+import android.media.ClientInfoParcel;
+import android.media.MediaResourceSubType;
+
+/**
+ * Description of a Client(codec) configuration.
+ *
+ * {@hide}
+ */
+parcelable ClientConfigParcel {
+ /**
+ * Client info.
+ */
+ ClientInfoParcel clientInfo;
+
+ /**
+ * Type of codec (Audio/Video/Image).
+ */
+ MediaResourceSubType codecType;
+
+ /**
+ * true if this is an encoder, false if this is a decoder.
+ */
+ boolean isEncoder;
+
+ /**
+ * true if this is hardware codec, false otherwise.
+ */
+ boolean isHardware;
+
+ /*
+ * Video Resolution of the codec when it was configured, as width and height (in pixels).
+ */
+ int width;
+ int height;
+
+ /*
+ * Timestamp (in microseconds) when this configuration is created.
+ */
+ long timeStamp;
+ /*
+ * ID associated with the Codec.
+ * This will be used by the metrics:
+ * - Associate MediaCodecStarted with MediaCodecStopped Atom.
+ * - Correlate MediaCodecReported Atom for codec configuration parameters.
+ */
+ long id;
+}
diff --git a/services/mediaresourcemanager/aidl/android/media/IResourceManagerService.aidl b/services/mediaresourcemanager/aidl/android/media/IResourceManagerService.aidl
index 30ad41b..5071fa3 100644
--- a/services/mediaresourcemanager/aidl/android/media/IResourceManagerService.aidl
+++ b/services/mediaresourcemanager/aidl/android/media/IResourceManagerService.aidl
@@ -20,6 +20,7 @@
import android.media.MediaResourceParcel;
import android.media.MediaResourcePolicyParcel;
import android.media.ClientInfoParcel;
+import android.media.ClientConfigParcel;
/**
* ResourceManagerService interface that keeps track of media resource
@@ -125,4 +126,46 @@
* @param pid pid from which resources will be reclaimed.
*/
void reclaimResourcesFromClientsPendingRemoval(int pid);
+
+ /**
+ * Notify that the client has been created.
+ *
+ * This call is made to collect the (concurrent) metrics about the
+ * resources associated with the Codec (and also DRM sessions).
+ *
+ * @param clientInfo Information of the client.
+ */
+ void notifyClientCreated(in ClientInfoParcel clientInfo);
+
+ /**
+ * Notify that the client has been started.
+ *
+ * This call is made to collect the (concurrent) metrics about the
+ * resources associated with the Codec (and also DRM sessions).
+ *
+ * @param clientConfig Configuration information of the client.
+ */
+ void notifyClientStarted(in ClientConfigParcel clientConfig);
+
+ /**
+ * Notify that the client has been stopped.
+ *
+ * This call is made to collect the (concurrent) metrics about the
+ * resources associated with the Codec (and also DRM sessions).
+ *
+ * @param clientConfig Configuration information of the client.
+ */
+ void notifyClientStopped(in ClientConfigParcel clientConfig);
+
+ /**
+ * Notify that the client's configuration has changed.
+ *
+ * This call is made to collect the (concurrent) metrics about the
+ * resources associated with the Codec (and also DRM sessions).
+ * This is called after notifyClientStarted (and before notifyClientStopped)
+ * to make changes to some of the configurations associated with the client.
+ *
+ * @param clientConfig Configuration information of the client.
+ */
+ void notifyClientConfigChanged(in ClientConfigParcel clientConfig);
}
diff --git a/services/mediaresourcemanager/fuzzer/Android.bp b/services/mediaresourcemanager/fuzzer/Android.bp
index 1d7f14f..d98974f 100644
--- a/services/mediaresourcemanager/fuzzer/Android.bp
+++ b/services/mediaresourcemanager/fuzzer/Android.bp
@@ -40,10 +40,12 @@
"libbinder",
"libbinder_ndk",
"libmedia",
+ "libmediautils",
"libutils",
"libstats_media_metrics",
"libstatspull",
"libstatssocket",
+ "libactivitymanager_aidl",
],
fuzz_config: {
cc: [
diff --git a/services/mediaresourcemanager/fuzzer/mediaresourcemanager_fuzzer.cpp b/services/mediaresourcemanager/fuzzer/mediaresourcemanager_fuzzer.cpp
index 5c2fef9..6fa9831 100644
--- a/services/mediaresourcemanager/fuzzer/mediaresourcemanager_fuzzer.cpp
+++ b/services/mediaresourcemanager/fuzzer/mediaresourcemanager_fuzzer.cpp
@@ -22,8 +22,8 @@
#include <aidl/android/media/BnResourceManagerClient.h>
#include <media/MediaResource.h>
#include <media/MediaResourcePolicy.h>
-#include <media/stagefright/ProcessInfoInterface.h>
#include <media/stagefright/foundation/ADebug.h>
+#include <mediautils/ProcessInfoInterface.h>
#include "ResourceManagerService.h"
#include "fuzzer/FuzzedDataProvider.h"
diff --git a/services/mediaresourcemanager/test/Android.bp b/services/mediaresourcemanager/test/Android.bp
index 60bb8c3..6695c12 100644
--- a/services/mediaresourcemanager/test/Android.bp
+++ b/services/mediaresourcemanager/test/Android.bp
@@ -19,9 +19,11 @@
"liblog",
"libmedia",
"libutils",
+ "libmediautils",
"libstats_media_metrics",
"libstatspull",
"libstatssocket",
+ "libactivitymanager_aidl",
],
include_dirs: [
"frameworks/av/include",
@@ -66,10 +68,12 @@
"libbinder_ndk",
"liblog",
"libmedia",
+ "libmediautils",
"libutils",
"libstats_media_metrics",
"libstatspull",
"libstatssocket",
+ "libactivitymanager_aidl",
],
include_dirs: [
"frameworks/av/include",
diff --git a/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
index 8194e23..474ff0f 100644
--- a/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
+++ b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
@@ -15,13 +15,14 @@
*/
#include <gtest/gtest.h>
+#include <android/binder_process.h>
#include "ResourceManagerService.h"
#include <aidl/android/media/BnResourceManagerClient.h>
#include <media/MediaResource.h>
#include <media/MediaResourcePolicy.h>
#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/ProcessInfoInterface.h>
+#include <mediautils/ProcessInfoInterface.h>
namespace android {
@@ -197,13 +198,20 @@
return static_cast<TestClient*>(testClient.get());
}
- ResourceManagerServiceTestBase()
- : mSystemCB(new TestSystemCallback()),
- mService(::ndk::SharedRefBase::make<ResourceManagerService>(
- new TestProcessInfo, mSystemCB)),
- mTestClient1(::ndk::SharedRefBase::make<TestClient>(kTestPid1, kTestUid1, mService)),
- mTestClient2(::ndk::SharedRefBase::make<TestClient>(kTestPid2, kTestUid2, mService)),
- mTestClient3(::ndk::SharedRefBase::make<TestClient>(kTestPid2, kTestUid2, mService)) {
+ ResourceManagerServiceTestBase() {
+ ALOGI("ResourceManagerServiceTestBase created");
+ }
+
+ void SetUp() override {
+ // Need thread pool to receive callbacks, otherwise oneway callbacks are
+ // silently ignored.
+ ABinderProcess_startThreadPool();
+ mSystemCB = new TestSystemCallback();
+ mService = ::ndk::SharedRefBase::make<ResourceManagerService>(
+ new TestProcessInfo, mSystemCB);
+ mTestClient1 = ::ndk::SharedRefBase::make<TestClient>(kTestPid1, kTestUid1, mService);
+ mTestClient2 = ::ndk::SharedRefBase::make<TestClient>(kTestPid2, kTestUid2, mService);
+ mTestClient3 = ::ndk::SharedRefBase::make<TestClient>(kTestPid2, kTestUid2, mService);
}
std::shared_ptr<IResourceManagerClient> createTestClient(int pid, int uid) {
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index 41cccb8..4e575f0 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -1367,6 +1367,143 @@
// CPU boost is not expected to be reclaimed when marked as pending removal
EXPECT_FALSE(toTestClient(cpuBoostMarkedClient)->checkIfReclaimedAndReset());
}
+
+ inline void initClientConfigParcel(bool encoder, bool hw,
+ int32_t width, int32_t height,
+ int64_t id,
+ const ClientInfoParcel& clientInfo,
+ ClientConfigParcel& clientConfig) {
+ clientConfig.codecType = MediaResource::SubType::kVideoCodec;
+ clientConfig.isEncoder = encoder;
+ clientConfig.isHardware = hw;
+ clientConfig.width = width;
+ clientConfig.height = height;
+ clientConfig.timeStamp = systemTime(SYSTEM_TIME_MONOTONIC) / 1000LL;
+ clientConfig.id = id;
+ clientConfig.clientInfo = clientInfo;
+ }
+
+ void testConcurrentCodecs() {
+ std::shared_ptr<IResourceManagerClient> testClient4 =
+ createTestClient(kTestPid1, kTestUid1);
+ ClientInfoParcel client1Info{.pid = static_cast<int32_t>(kTestPid1),
+ .uid = static_cast<int32_t>(kTestUid1),
+ .id = getId(mTestClient1),
+ .name = "none"};
+ ClientInfoParcel client2Info{.pid = static_cast<int32_t>(kTestPid2),
+ .uid = static_cast<int32_t>(kTestUid2),
+ .id = getId(mTestClient2),
+ .name = "none"};
+ ClientInfoParcel client3Info{.pid = static_cast<int32_t>(kTestPid2),
+ .uid = static_cast<int32_t>(kTestUid2),
+ .id = getId(mTestClient3),
+ .name = "none"};
+ ClientInfoParcel client4Info{.pid = static_cast<int32_t>(kTestPid1),
+ .uid = static_cast<int32_t>(kTestUid1),
+ .id = getId(testClient4),
+ .name = "none"};
+ ClientConfigParcel client1Config;
+ ClientConfigParcel client2Config;
+ ClientConfigParcel client3Config;
+ ClientConfigParcel client4Config;
+
+ // HW Video Encoder @ 1080P.
+ initClientConfigParcel(true, true, 1920, 1080, 11111111,
+ client1Info, client1Config);
+ // HW Video Decoder @ 4K.
+ initClientConfigParcel(true, true, 2160, 3840, 22222222,
+ client2Info, client2Config);
+ // SW Video Encoder @ 1080P.
+ initClientConfigParcel(true, true, 1920, 1080, 33333333,
+ client3Info, client3Config);
+ // SW Video Decoder @ 4K.
+ initClientConfigParcel(true, true, 2160, 3840, 44444444,
+ client4Info, client4Config);
+
+ // Start client1 at 1080P.
+ mService->notifyClientStarted(client1Config);
+ long peakPixelCountP1 = mService->getPeakConcurrentPixelCount(kTestPid1);
+ long currentPixelCountP1 = mService->getCurrentConcurrentPixelCount(kTestPid1);
+ EXPECT_TRUE(peakPixelCountP1 = client1Config.width * client1Config.height);
+ EXPECT_TRUE(currentPixelCountP1 = client1Config.width * client1Config.height);
+
+ // Stop client1.
+ mService->notifyClientStopped(client1Config);
+ peakPixelCountP1 = mService->getPeakConcurrentPixelCount(kTestPid1);
+ currentPixelCountP1 = mService->getCurrentConcurrentPixelCount(kTestPid1);
+ EXPECT_TRUE(peakPixelCountP1 == client1Config.width * client1Config.height);
+ EXPECT_TRUE(currentPixelCountP1 == 0);
+
+ // Start client1 at 1080P.
+ mService->notifyClientStarted(client1Config);
+ // Start client2 at 4K.
+ mService->notifyClientStarted(client2Config);
+
+ // Verify the Peak and Current Concurrent pixel count for both the process
+ // (kTestPid1, kTestPid2)
+ peakPixelCountP1 = mService->getPeakConcurrentPixelCount(kTestPid1);
+ currentPixelCountP1 = mService->getCurrentConcurrentPixelCount(kTestPid1);
+ long peakPixelCountP2 = mService->getPeakConcurrentPixelCount(kTestPid2);
+ long currentPixelCountP2 = mService->getCurrentConcurrentPixelCount(kTestPid2);
+ EXPECT_TRUE(peakPixelCountP1 == client1Config.width * client1Config.height);
+ EXPECT_TRUE(currentPixelCountP1 == client1Config.width * client1Config.height);
+ EXPECT_TRUE(peakPixelCountP2 == client2Config.width * client2Config.height);
+ EXPECT_TRUE(currentPixelCountP2 == client2Config.width * client2Config.height);
+
+ // Start client3 at 1080P.
+ mService->notifyClientStarted(client3Config);
+ // Start client4 at 4K.
+ mService->notifyClientStarted(client4Config);
+
+ // Verify the Peak and Current Concurrent pixel count for both the process
+ // (kTestPid1, kTestPid2)
+ peakPixelCountP1 = mService->getPeakConcurrentPixelCount(kTestPid1);
+ currentPixelCountP1 = mService->getCurrentConcurrentPixelCount(kTestPid1);
+ peakPixelCountP2 = mService->getPeakConcurrentPixelCount(kTestPid2);
+ currentPixelCountP2 = mService->getCurrentConcurrentPixelCount(kTestPid2);
+ EXPECT_TRUE(peakPixelCountP1 ==
+ (client1Config.width * client1Config.height +
+ client4Config.width * client4Config.height));
+ EXPECT_TRUE(currentPixelCountP1 ==
+ (client1Config.width * client1Config.height +
+ client4Config.width * client4Config.height));
+ EXPECT_TRUE(peakPixelCountP2 ==
+ (client2Config.width * client2Config.height +
+ client3Config.width * client3Config.height));
+ EXPECT_TRUE(currentPixelCountP2 ==
+ (client2Config.width * client2Config.height +
+ client3Config.width * client3Config.height));
+
+ // Stop client4
+ mService->notifyClientStopped(client4Config);
+ currentPixelCountP1 = mService->getCurrentConcurrentPixelCount(kTestPid1);
+ EXPECT_TRUE(currentPixelCountP1 == client1Config.width * client1Config.height);
+
+ // Stop client1
+ mService->notifyClientStopped(client1Config);
+
+ // Stop client2
+ mService->notifyClientStopped(client2Config);
+ currentPixelCountP2 = mService->getCurrentConcurrentPixelCount(kTestPid2);
+ EXPECT_TRUE(currentPixelCountP2 == client3Config.width * client3Config.height);
+ // Stop client3
+ mService->notifyClientStopped(client3Config);
+
+ // Verify the Peak and Current Concurrent pixel count for both the process
+ // (kTestPid1, kTestPid2)
+ peakPixelCountP1 = mService->getPeakConcurrentPixelCount(kTestPid1);
+ currentPixelCountP1 = mService->getCurrentConcurrentPixelCount(kTestPid1);
+ peakPixelCountP2 = mService->getPeakConcurrentPixelCount(kTestPid2);
+ currentPixelCountP2 = mService->getCurrentConcurrentPixelCount(kTestPid2);
+ EXPECT_TRUE(peakPixelCountP1 ==
+ (client1Config.width * client1Config.height +
+ client4Config.width * client4Config.height));
+ EXPECT_TRUE(currentPixelCountP1 == 0);
+ EXPECT_TRUE(peakPixelCountP2 ==
+ (client2Config.width * client2Config.height +
+ client3Config.width * client3Config.height));
+ EXPECT_TRUE(currentPixelCountP2 == 0);
+ }
};
TEST_F(ResourceManagerServiceTest, config) {
@@ -1451,4 +1588,8 @@
testReclaimResourcesFromMarkedClients_removesBiggestMarkedClientForSomeResources();
}
+TEST_F(ResourceManagerServiceTest, concurrentCodecs) {
+ testConcurrentCodecs();
+}
+
} // namespace android
diff --git a/services/mediaresourcemanager/test/ResourceObserverService_test.cpp b/services/mediaresourcemanager/test/ResourceObserverService_test.cpp
index a0d728c..85769d5 100644
--- a/services/mediaresourcemanager/test/ResourceObserverService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceObserverService_test.cpp
@@ -166,11 +166,14 @@
class ResourceObserverServiceTest : public ResourceManagerServiceTestBase {
public:
- ResourceObserverServiceTest() : ResourceManagerServiceTestBase(),
- mObserverService(::ndk::SharedRefBase::make<ResourceObserverService>()),
- mTestObserver1(::ndk::SharedRefBase::make<TestObserver>("observer1")),
- mTestObserver2(::ndk::SharedRefBase::make<TestObserver>("observer2")),
- mTestObserver3(::ndk::SharedRefBase::make<TestObserver>("observer3")) {
+ ResourceObserverServiceTest() : ResourceManagerServiceTestBase() {}
+
+ void SetUp() override {
+ ResourceManagerServiceTestBase::SetUp();
+ mObserverService = ::ndk::SharedRefBase::make<ResourceObserverService>();
+ mTestObserver1 = ::ndk::SharedRefBase::make<TestObserver>("observer1");
+ mTestObserver2 = ::ndk::SharedRefBase::make<TestObserver>("observer2");
+ mTestObserver3 = ::ndk::SharedRefBase::make<TestObserver>("observer3");
mService->setObserverService(mObserverService);
}