Merge "gralloc: move codec2 to GraphicBufferAllocator/Mapper"
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index 8eb030a..7a0f63b 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -76,6 +76,10 @@
sp<hardware::ICameraService> CameraManagerGlobal::getCameraService() {
Mutex::Autolock _l(mLock);
+ return getCameraServiceLocked();
+}
+
+sp<hardware::ICameraService> CameraManagerGlobal::getCameraServiceLocked() {
if (mCameraService.get() == nullptr) {
if (isCameraServiceDisabled()) {
return mCameraService;
@@ -216,8 +220,12 @@
if (pair.second) {
for (auto& pair : mDeviceStatusMap) {
const String8& cameraId = pair.first;
- int32_t status = pair.second;
-
+ int32_t status = pair.second.status;
+ // Don't send initial callbacks for camera ids which don't support
+ // camera2
+ if (!pair.second.supportsHAL3) {
+ continue;
+ }
sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
ACameraManager_AvailabilityCallback cb = isStatusAvailable(status) ?
callback->onCameraAvailable : callback->onCameraUnavailable;
@@ -236,20 +244,32 @@
mCallbacks.erase(cb);
}
+bool CameraManagerGlobal::supportsCamera2ApiLocked(const String8 &cameraId) {
+ bool camera2Support = false;
+ auto cs = getCameraServiceLocked();
+ binder::Status serviceRet =
+ cs->supportsCameraApi(String16(cameraId),
+ hardware::ICameraService::API_VERSION_2, &camera2Support);
+ if (!serviceRet.isOk()) {
+ ALOGE("%s: supportsCameraApi2Locked() call failed for cameraId %s",
+ __FUNCTION__, cameraId.c_str());
+ return false;
+ }
+ return camera2Support;
+}
+
void CameraManagerGlobal::getCameraIdList(std::vector<String8>* cameraIds) {
// Ensure that we have initialized/refreshed the list of available devices
- auto cs = getCameraService();
Mutex::Autolock _l(mLock);
-
+ // Needed to make sure we're connected to cameraservice
+ getCameraServiceLocked();
for(auto& deviceStatus : mDeviceStatusMap) {
- if (deviceStatus.second == hardware::ICameraServiceListener::STATUS_NOT_PRESENT ||
- deviceStatus.second == hardware::ICameraServiceListener::STATUS_ENUMERATING) {
+ if (deviceStatus.second.status == hardware::ICameraServiceListener::STATUS_NOT_PRESENT ||
+ deviceStatus.second.status ==
+ hardware::ICameraServiceListener::STATUS_ENUMERATING) {
continue;
}
- bool camera2Support = false;
- binder::Status serviceRet = cs->supportsCameraApi(String16(deviceStatus.first),
- hardware::ICameraService::API_VERSION_2, &camera2Support);
- if (!serviceRet.isOk() || !camera2Support) {
+ if (!deviceStatus.second.supportsHAL3) {
continue;
}
cameraIds->push_back(deviceStatus.first);
@@ -377,7 +397,7 @@
bool firstStatus = (mDeviceStatusMap.count(cameraId) == 0);
int32_t oldStatus = firstStatus ?
status : // first status
- mDeviceStatusMap[cameraId];
+ mDeviceStatusMap[cameraId].status;
if (!firstStatus &&
isStatusAvailable(status) == isStatusAvailable(oldStatus)) {
@@ -385,16 +405,19 @@
return;
}
+ bool supportsHAL3 = supportsCamera2ApiLocked(cameraId);
// Iterate through all registered callbacks
- mDeviceStatusMap[cameraId] = status;
- for (auto cb : mCallbacks) {
- sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
- ACameraManager_AvailabilityCallback cbFp = isStatusAvailable(status) ?
- cb.mAvailable : cb.mUnavailable;
- msg->setPointer(kCallbackFpKey, (void *) cbFp);
- msg->setPointer(kContextKey, cb.mContext);
- msg->setString(kCameraIdKey, AString(cameraId));
- msg->post();
+ mDeviceStatusMap[cameraId] = StatusAndHAL3Support(status, supportsHAL3);
+ if (supportsHAL3) {
+ for (auto cb : mCallbacks) {
+ sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
+ ACameraManager_AvailabilityCallback cbFp = isStatusAvailable(status) ?
+ cb.mAvailable : cb.mUnavailable;
+ msg->setPointer(kCallbackFpKey, (void *) cbFp);
+ msg->setPointer(kContextKey, cb.mContext);
+ msg->setString(kCameraIdKey, AString(cameraId));
+ msg->post();
+ }
}
if (status == hardware::ICameraServiceListener::STATUS_NOT_PRESENT) {
mDeviceStatusMap.erase(cameraId);
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
index 8c1da36..e945ba0 100644
--- a/camera/ndk/impl/ACameraManager.h
+++ b/camera/ndk/impl/ACameraManager.h
@@ -66,9 +66,9 @@
private:
sp<hardware::ICameraService> mCameraService;
- const int kCameraServicePollDelay = 500000; // 0.5s
- const char* kCameraServiceName = "media.camera";
- Mutex mLock;
+ const int kCameraServicePollDelay = 500000; // 0.5s
+ const char* kCameraServiceName = "media.camera";
+ Mutex mLock;
class DeathNotifier : public IBinder::DeathRecipient {
public:
@@ -156,12 +156,14 @@
sp<CallbackHandler> mHandler;
sp<ALooper> mCbLooper; // Looper thread where callbacks actually happen on
+ sp<hardware::ICameraService> getCameraServiceLocked();
void onCameraAccessPrioritiesChanged();
void onStatusChanged(int32_t status, const String8& cameraId);
void onStatusChangedLocked(int32_t status, const String8& cameraId);
// Utils for status
static bool validStatus(int32_t status);
static bool isStatusAvailable(int32_t status);
+ bool supportsCamera2ApiLocked(const String8 &cameraId);
// The sort logic must match the logic in
// libcameraservice/common/CameraProviderManager.cpp::getAPI1CompatibleCameraDeviceIds
@@ -184,8 +186,16 @@
}
};
+ struct StatusAndHAL3Support {
+ int32_t status = hardware::ICameraServiceListener::STATUS_NOT_PRESENT;
+ bool supportsHAL3 = false;
+ StatusAndHAL3Support(int32_t st, bool HAL3support):
+ status(st), supportsHAL3(HAL3support) { };
+ StatusAndHAL3Support() = default;
+ };
+
// Map camera_id -> status
- std::map<String8, int32_t, CameraIdComparator> mDeviceStatusMap;
+ std::map<String8, StatusAndHAL3Support, CameraIdComparator> mDeviceStatusMap;
// For the singleton instance
static Mutex sLock;
diff --git a/cmds/screenrecord/Android.bp b/cmds/screenrecord/Android.bp
index 6bdbab1..72008c2 100644
--- a/cmds/screenrecord/Android.bp
+++ b/cmds/screenrecord/Android.bp
@@ -31,6 +31,7 @@
shared_libs: [
"libstagefright",
"libmedia",
+ "libmediandk",
"libmedia_omx",
"libutils",
"libbinder",
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index 4a24b96..b534f8a 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -45,13 +45,15 @@
#include <gui/SurfaceComposerClient.h>
#include <gui/ISurfaceComposer.h>
#include <ui/DisplayInfo.h>
+#include <media/NdkMediaCodec.h>
+#include <media/NdkMediaFormatPriv.h>
+#include <media/NdkMediaMuxer.h>
#include <media/openmax/OMX_IVCommon.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaMuxer.h>
#include <media/stagefright/PersistentSurface.h>
#include <mediadrm/ICrypto.h>
#include <media/MediaCodecBuffer.h>
@@ -71,7 +73,6 @@
using android::ISurfaceComposer;
using android::MediaCodec;
using android::MediaCodecBuffer;
-using android::MediaMuxer;
using android::Overlay;
using android::PersistentSurface;
using android::PhysicalDisplayId;
@@ -377,7 +378,7 @@
* (as little endian uint64).
*/
static status_t writeWinscopeMetadata(const Vector<int64_t>& timestamps,
- const ssize_t metaTrackIdx, const sp<MediaMuxer>& muxer) {
+ const ssize_t metaTrackIdx, AMediaMuxer *muxer) {
ALOGV("Writing metadata");
int64_t systemTimeToElapsedTimeOffsetMicros = (android::elapsedRealtimeNano()
- systemTime(SYSTEM_TIME_MONOTONIC)) / 1000;
@@ -393,7 +394,13 @@
+ systemTimeToElapsedTimeOffsetMicros), pos);
pos += sizeof(uint64_t);
}
- return muxer->writeSampleData(buffer, metaTrackIdx, timestamps[0], 0);
+ AMediaCodecBufferInfo bufferInfo = {
+ 0,
+ static_cast<int32_t>(buffer->size()),
+ timestamps[0],
+ 0
+ };
+ return AMediaMuxer_writeSampleData(muxer, metaTrackIdx, buffer->data(), &bufferInfo);
}
/*
@@ -406,7 +413,7 @@
* The muxer must *not* have been started before calling.
*/
static status_t runEncoder(const sp<MediaCodec>& encoder,
- const sp<MediaMuxer>& muxer, FILE* rawFp, const sp<IBinder>& display,
+ AMediaMuxer *muxer, FILE* rawFp, const sp<IBinder>& display,
const sp<IBinder>& virtualDpy, uint8_t orientation) {
static int kTimeout = 250000; // be responsive on signal
status_t err;
@@ -513,8 +520,13 @@
// TODO
sp<ABuffer> buffer = new ABuffer(
buffers[bufIndex]->data(), buffers[bufIndex]->size());
- err = muxer->writeSampleData(buffer, trackIdx,
- ptsUsec, flags);
+ AMediaCodecBufferInfo bufferInfo = {
+ 0,
+ static_cast<int32_t>(buffer->size()),
+ ptsUsec,
+ flags
+ };
+ err = AMediaMuxer_writeSampleData(muxer, trackIdx, buffer->data(), &bufferInfo);
if (err != NO_ERROR) {
fprintf(stderr,
"Failed writing data to muxer (err=%d)\n", err);
@@ -547,15 +559,18 @@
ALOGV("Encoder format changed");
sp<AMessage> newFormat;
encoder->getOutputFormat(&newFormat);
+ // TODO remove when MediaCodec has been replaced with AMediaCodec
+ AMediaFormat *ndkFormat = AMediaFormat_fromMsg(&newFormat);
if (muxer != NULL) {
- trackIdx = muxer->addTrack(newFormat);
+ trackIdx = AMediaMuxer_addTrack(muxer, ndkFormat);
if (gOutputFormat == FORMAT_MP4) {
- sp<AMessage> metaFormat = new AMessage;
- metaFormat->setString(KEY_MIME, kMimeTypeApplicationOctetstream);
- metaTrackIdx = muxer->addTrack(metaFormat);
+ AMediaFormat *metaFormat = AMediaFormat_new();
+ AMediaFormat_setString(metaFormat, AMEDIAFORMAT_KEY_MIME, kMimeTypeApplicationOctetstream);
+ metaTrackIdx = AMediaMuxer_addTrack(muxer, metaFormat);
+ AMediaFormat_delete(metaFormat);
}
ALOGV("Starting muxer");
- err = muxer->start();
+ err = AMediaMuxer_start(muxer);
if (err != NO_ERROR) {
fprintf(stderr, "Unable to start muxer (err=%d)\n", err);
return err;
@@ -762,7 +777,7 @@
return err;
}
- sp<MediaMuxer> muxer = NULL;
+ AMediaMuxer *muxer = nullptr;
FILE* rawFp = NULL;
switch (gOutputFormat) {
case FORMAT_MP4:
@@ -781,15 +796,15 @@
abort();
}
if (gOutputFormat == FORMAT_MP4) {
- muxer = new MediaMuxer(fd, MediaMuxer::OUTPUT_FORMAT_MPEG_4);
+ muxer = AMediaMuxer_new(fd, AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4);
} else if (gOutputFormat == FORMAT_WEBM) {
- muxer = new MediaMuxer(fd, MediaMuxer::OUTPUT_FORMAT_WEBM);
+ muxer = AMediaMuxer_new(fd, AMEDIAMUXER_OUTPUT_FORMAT_WEBM);
} else {
- muxer = new MediaMuxer(fd, MediaMuxer::OUTPUT_FORMAT_THREE_GPP);
+ muxer = AMediaMuxer_new(fd, AMEDIAMUXER_OUTPUT_FORMAT_THREE_GPP);
}
close(fd);
if (gRotate) {
- muxer->setOrientationHint(90); // TODO: does this do anything?
+ AMediaMuxer_setOrientationHint(muxer, 90); // TODO: does this do anything?
}
break;
}
@@ -860,7 +875,7 @@
if (muxer != NULL) {
// If we don't stop muxer explicitly, i.e. let the destructor run,
// it may hang (b/11050628).
- err = muxer->stop();
+ err = AMediaMuxer_stop(muxer);
} else if (rawFp != stdout) {
fclose(rawFp);
}
diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp
index 34a2f69..6b1b475 100644
--- a/drm/libmediadrm/Android.bp
+++ b/drm/libmediadrm/Android.bp
@@ -37,7 +37,6 @@
],
shared_libs: [
- "libbinder",
"libbinder_ndk",
"libcutils",
"libdl",
@@ -95,8 +94,6 @@
"android.hardware.drm@1.0",
"android.hardware.drm@1.1",
"android.hardware.drm@1.2",
- "libbinder",
- "libhidlbase",
"liblog",
"libmediametrics",
"libprotobuf-cpp-lite",
@@ -134,8 +131,6 @@
"android.hardware.drm@1.1",
"android.hardware.drm@1.2",
"libbase",
- "libbinder",
- "libhidlbase",
"liblog",
"libmediametrics",
"libprotobuf-cpp-full",
@@ -149,3 +144,25 @@
],
}
+cc_library_shared {
+ name: "libmediadrmmetrics_consumer",
+ srcs: [
+ "DrmMetricsConsumer.cpp",
+ ],
+
+ include_dirs: [
+ "frameworks/av/media/libmedia/include"
+ ],
+
+ shared_libs: [
+ "android.hardware.drm@1.0",
+ "android.hardware.drm@1.1",
+ "android.hardware.drm@1.2",
+ "libbinder",
+ "libhidlbase",
+ "liblog",
+ "libmediadrm",
+ "libmediadrmmetrics_full",
+ "libutils",
+ ],
+}
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index 55b9bb8..18772e0 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -20,7 +20,6 @@
#include <android/hardware/drm/1.0/types.h>
#include <android/hidl/manager/1.2/IServiceManager.h>
-#include <binder/IMemory.h>
#include <hidl/ServiceManagement.h>
#include <hidlmemory/FrameworkUtils.h>
#include <media/hardware/CryptoAPI.h>
@@ -251,7 +250,7 @@
/**
- * If the heap base isn't set, get the heap base from the IMemory
+ * If the heap base isn't set, get the heap base from the HidlMemory
* and send it to the HAL so it can map a remote heap of the same
* size. Once the heap base is established, shared memory buffers
* are sent by providing an offset into the heap and a buffer size.
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index f3028d8..5b32a04 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -38,6 +38,8 @@
#include <mediadrm/DrmHal.h>
#include <mediadrm/DrmSessionClientInterface.h>
#include <mediadrm/DrmSessionManager.h>
+#include <mediadrm/IDrmMetricsConsumer.h>
+#include <mediadrm/DrmUtils.h>
#include <vector>
@@ -387,44 +389,8 @@
mPluginV1_2.clear();
}
-Vector<sp<IDrmFactory>> DrmHal::makeDrmFactories() {
- Vector<sp<IDrmFactory>> factories;
-
- auto manager = hardware::defaultServiceManager1_2();
-
- if (manager != NULL) {
- manager->listManifestByInterface(drm::V1_0::IDrmFactory::descriptor,
- [&factories](const hidl_vec<hidl_string> ®istered) {
- for (const auto &instance : registered) {
- auto factory = drm::V1_0::IDrmFactory::getService(instance);
- if (factory != NULL) {
- factories.push_back(factory);
- }
- }
- }
- );
- manager->listManifestByInterface(drm::V1_1::IDrmFactory::descriptor,
- [&factories](const hidl_vec<hidl_string> ®istered) {
- for (const auto &instance : registered) {
- auto factory = drm::V1_1::IDrmFactory::getService(instance);
- if (factory != NULL) {
- factories.push_back(factory);
- }
- }
- }
- );
- manager->listManifestByInterface(drm::V1_2::IDrmFactory::descriptor,
- [&factories](const hidl_vec<hidl_string> ®istered) {
- for (const auto &instance : registered) {
- auto factory = drm::V1_2::IDrmFactory::getService(instance);
- if (factory != NULL) {
- factories.push_back(factory);
- }
- }
- }
- );
- }
-
+std::vector<sp<IDrmFactory>> DrmHal::makeDrmFactories() {
+ std::vector<sp<IDrmFactory>> factories(DrmUtils::MakeDrmFactories());
if (factories.size() == 0) {
// must be in passthrough mode, load the default passthrough service
auto passthrough = IDrmFactory::getService();
@@ -1362,11 +1328,11 @@
return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
}
-status_t DrmHal::getMetrics(PersistableBundle* metrics) {
- if (metrics == nullptr) {
+status_t DrmHal::getMetrics(const sp<IDrmMetricsConsumer> &consumer) {
+ if (consumer == nullptr) {
return UNEXPECTED_NULL;
}
- mMetrics.Export(metrics);
+ consumer->consumeFrameworkMetrics(mMetrics);
// Append vendor metrics if they are supported.
if (mPluginV1_1 != NULL) {
@@ -1393,11 +1359,7 @@
if (status != Status::OK) {
ALOGV("Error getting plugin metrics: %d", status);
} else {
- PersistableBundle pluginBundle;
- if (MediaDrmMetrics::HidlMetricsToBundle(
- pluginMetrics, &pluginBundle) == OK) {
- metrics->putPersistableBundle(String16(vendor), pluginBundle);
- }
+ consumer->consumeHidlMetrics(vendor, pluginMetrics);
}
err = toStatusT(status);
});
diff --git a/drm/libmediadrm/DrmMetrics.cpp b/drm/libmediadrm/DrmMetrics.cpp
index 3080802..996fd19 100644
--- a/drm/libmediadrm/DrmMetrics.cpp
+++ b/drm/libmediadrm/DrmMetrics.cpp
@@ -29,143 +29,12 @@
using ::android::String16;
using ::android::String8;
using ::android::drm_metrics::DrmFrameworkMetrics;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
using ::android::hardware::drm::V1_0::EventType;
using ::android::hardware::drm::V1_2::KeyStatusType;
using ::android::hardware::drm::V1_1::DrmMetricGroup;
-using ::android::os::PersistableBundle;
namespace {
-template <typename T> std::string GetAttributeName(T type);
-
-template <> std::string GetAttributeName<KeyStatusType>(KeyStatusType type) {
- static const char *type_names[] = {"USABLE", "EXPIRED",
- "OUTPUT_NOT_ALLOWED", "STATUS_PENDING",
- "INTERNAL_ERROR"};
- if (((size_t)type) > arraysize(type_names)) {
- return "UNKNOWN_TYPE";
- }
- return type_names[(size_t)type];
-}
-
-template <> std::string GetAttributeName<EventType>(EventType type) {
- static const char *type_names[] = {"PROVISION_REQUIRED", "KEY_NEEDED",
- "KEY_EXPIRED", "VENDOR_DEFINED",
- "SESSION_RECLAIMED"};
- if (((size_t)type) > arraysize(type_names)) {
- return "UNKNOWN_TYPE";
- }
- return type_names[(size_t)type];
-}
-
-template <typename T>
-void ExportCounterMetric(const android::CounterMetric<T> &counter,
- PersistableBundle *metrics) {
- if (!metrics) {
- ALOGE("metrics was unexpectedly null.");
- return;
- }
- std::string success_count_name = counter.metric_name() + ".ok.count";
- std::string error_count_name = counter.metric_name() + ".error.count";
- std::vector<int64_t> status_values;
- counter.ExportValues(
- [&](const android::status_t status, const int64_t value) {
- if (status == android::OK) {
- metrics->putLong(android::String16(success_count_name.c_str()),
- value);
- } else {
- int64_t total_errors(0);
- metrics->getLong(android::String16(error_count_name.c_str()),
- &total_errors);
- metrics->putLong(android::String16(error_count_name.c_str()),
- total_errors + value);
- status_values.push_back(status);
- }
- });
- if (!status_values.empty()) {
- std::string error_list_name = counter.metric_name() + ".error.list";
- metrics->putLongVector(android::String16(error_list_name.c_str()),
- status_values);
- }
-}
-
-template <typename T>
-void ExportCounterMetricWithAttributeNames(
- const android::CounterMetric<T> &counter, PersistableBundle *metrics) {
- if (!metrics) {
- ALOGE("metrics was unexpectedly null.");
- return;
- }
- counter.ExportValues([&](const T &attribute, const int64_t value) {
- std::string name = counter.metric_name() + "." +
- GetAttributeName(attribute) + ".count";
- metrics->putLong(android::String16(name.c_str()), value);
- });
-}
-
-template <typename T>
-void ExportEventMetric(const android::EventMetric<T> &event,
- PersistableBundle *metrics) {
- if (!metrics) {
- ALOGE("metrics was unexpectedly null.");
- return;
- }
- std::string success_count_name = event.metric_name() + ".ok.count";
- std::string error_count_name = event.metric_name() + ".error.count";
- std::string timing_name = event.metric_name() + ".ok.average_time_micros";
- std::vector<int64_t> status_values;
- event.ExportValues([&](const android::status_t &status,
- const android::EventStatistics &value) {
- if (status == android::OK) {
- metrics->putLong(android::String16(success_count_name.c_str()),
- value.count);
- metrics->putLong(android::String16(timing_name.c_str()),
- value.mean);
- } else {
- int64_t total_errors(0);
- metrics->getLong(android::String16(error_count_name.c_str()),
- &total_errors);
- metrics->putLong(android::String16(error_count_name.c_str()),
- total_errors + value.count);
- status_values.push_back(status);
- }
- });
- if (!status_values.empty()) {
- std::string error_list_name = event.metric_name() + ".error.list";
- metrics->putLongVector(android::String16(error_list_name.c_str()),
- status_values);
- }
-}
-
-void ExportSessionLifespans(
- const std::map<std::string, std::pair<int64_t, int64_t>> &mSessionLifespans,
- PersistableBundle *metrics) {
- if (!metrics) {
- ALOGE("metrics was unexpectedly null.");
- return;
- }
-
- if (mSessionLifespans.empty()) {
- return;
- }
-
- PersistableBundle startTimesBundle;
- PersistableBundle endTimesBundle;
- for (auto it = mSessionLifespans.begin(); it != mSessionLifespans.end();
- it++) {
- String16 key(it->first.c_str(), it->first.size());
- startTimesBundle.putLong(key, it->second.first);
- endTimesBundle.putLong(key, it->second.second);
- }
- metrics->putPersistableBundle(
- android::String16("drm.mediadrm.session_start_times_ms"),
- startTimesBundle);
- metrics->putPersistableBundle(
- android::String16("drm.mediadrm.session_end_times_ms"), endTimesBundle);
-}
-
std::string ToHexString(const android::Vector<uint8_t> &sessionId) {
std::ostringstream out;
out << std::hex << std::setfill('0');
@@ -175,31 +44,6 @@
return out.str();
}
-template <typename CT>
-void SetValue(const String16 &name, DrmMetricGroup::ValueType type,
- const CT &value, PersistableBundle *bundle) {
- switch (type) {
- case DrmMetricGroup::ValueType::INT64_TYPE:
- bundle->putLong(name, value.int64Value);
- break;
- case DrmMetricGroup::ValueType::DOUBLE_TYPE:
- bundle->putDouble(name, value.doubleValue);
- break;
- case DrmMetricGroup::ValueType::STRING_TYPE:
- bundle->putString(name, String16(value.stringValue.c_str()));
- break;
- default:
- ALOGE("Unexpected value type: %hhu", type);
- }
-}
-
-inline String16 MakeIndexString(unsigned int index) {
- std::string str("[");
- str.append(std::to_string(index));
- str.append("]");
- return String16(str.c_str());
-}
-
} // namespace
namespace android {
@@ -237,23 +81,6 @@
}
}
-void MediaDrmMetrics::Export(PersistableBundle *metrics) {
- if (!metrics) {
- ALOGE("metrics was unexpectedly null.");
- return;
- }
- ExportCounterMetric(mOpenSessionCounter, metrics);
- ExportCounterMetric(mCloseSessionCounter, metrics);
- ExportEventMetric(mGetKeyRequestTimeUs, metrics);
- ExportEventMetric(mProvideKeyResponseTimeUs, metrics);
- ExportCounterMetric(mGetProvisionRequestCounter, metrics);
- ExportCounterMetric(mProvideProvisionResponseCounter, metrics);
- ExportCounterMetricWithAttributeNames(mKeyStatusChangeCounter, metrics);
- ExportCounterMetricWithAttributeNames(mEventCounter, metrics);
- ExportCounterMetric(mGetDeviceUniqueIdCounter, metrics);
- ExportSessionLifespans(mSessionLifespans, metrics);
-}
-
status_t MediaDrmMetrics::GetSerializedMetrics(std::string *serializedMetrics) {
if (!serializedMetrics) {
@@ -361,62 +188,14 @@
return OK;
}
+std::map<std::string, std::pair<int64_t, int64_t>> MediaDrmMetrics::GetSessionLifespans() const {
+ return mSessionLifespans;
+}
+
int64_t MediaDrmMetrics::GetCurrentTimeMs() {
struct timeval tv;
gettimeofday(&tv, NULL);
return ((int64_t)tv.tv_sec * 1000) + ((int64_t)tv.tv_usec / 1000);
}
-status_t MediaDrmMetrics::HidlMetricsToBundle(
- const hidl_vec<DrmMetricGroup> &hidlMetricGroups,
- PersistableBundle *bundleMetricGroups) {
- if (bundleMetricGroups == nullptr) {
- return UNEXPECTED_NULL;
- }
- if (hidlMetricGroups.size() == 0) {
- return OK;
- }
-
- int groupIndex = 0;
- std::map<String16, int> indexMap;
- for (const auto &hidlMetricGroup : hidlMetricGroups) {
- PersistableBundle bundleMetricGroup;
- for (const auto &hidlMetric : hidlMetricGroup.metrics) {
- String16 metricName(hidlMetric.name.c_str());
- PersistableBundle bundleMetric;
- // Add metric component values.
- for (const auto &value : hidlMetric.values) {
- SetValue(String16(value.componentName.c_str()), value.type,
- value, &bundleMetric);
- }
- // Set metric attributes.
- PersistableBundle bundleMetricAttributes;
- for (const auto &attribute : hidlMetric.attributes) {
- SetValue(String16(attribute.name.c_str()), attribute.type,
- attribute, &bundleMetricAttributes);
- }
- // Add attributes to the bundle metric.
- bundleMetric.putPersistableBundle(String16("attributes"),
- bundleMetricAttributes);
- // Add one layer of indirection, allowing for repeated metric names.
- PersistableBundle repeatedMetrics;
- bundleMetricGroup.getPersistableBundle(metricName,
- &repeatedMetrics);
- int index = indexMap[metricName];
- repeatedMetrics.putPersistableBundle(MakeIndexString(index),
- bundleMetric);
- indexMap[metricName] = ++index;
-
- // Add the bundle metric to the group of metrics.
- bundleMetricGroup.putPersistableBundle(metricName,
- repeatedMetrics);
- }
- // Add the bundle metric group to the collection of groups.
- bundleMetricGroups->putPersistableBundle(MakeIndexString(groupIndex++),
- bundleMetricGroup);
- }
-
- return OK;
-}
-
} // namespace android
diff --git a/drm/libmediadrm/DrmMetricsConsumer.cpp b/drm/libmediadrm/DrmMetricsConsumer.cpp
new file mode 100644
index 0000000..b47b4ff
--- /dev/null
+++ b/drm/libmediadrm/DrmMetricsConsumer.cpp
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2018 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 "DrmMetricsConsumer"
+
+#include <android-base/macros.h>
+#include <mediadrm/DrmMetricsConsumer.h>
+#include <mediadrm/DrmMetrics.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+
+using ::android::String16;
+using ::android::String8;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::drm::V1_0::EventType;
+using ::android::hardware::drm::V1_2::KeyStatusType;
+using ::android::hardware::drm::V1_1::DrmMetricGroup;
+using ::android::os::PersistableBundle;
+
+namespace {
+
+template <typename T> std::string GetAttributeName(T type);
+
+template <> std::string GetAttributeName<KeyStatusType>(KeyStatusType type) {
+ static const char *type_names[] = {"USABLE", "EXPIRED",
+ "OUTPUT_NOT_ALLOWED", "STATUS_PENDING",
+ "INTERNAL_ERROR"};
+ if (((size_t)type) > arraysize(type_names)) {
+ return "UNKNOWN_TYPE";
+ }
+ return type_names[(size_t)type];
+}
+
+template <> std::string GetAttributeName<EventType>(EventType type) {
+ static const char *type_names[] = {"PROVISION_REQUIRED", "KEY_NEEDED",
+ "KEY_EXPIRED", "VENDOR_DEFINED",
+ "SESSION_RECLAIMED"};
+ if (((size_t)type) > arraysize(type_names)) {
+ return "UNKNOWN_TYPE";
+ }
+ return type_names[(size_t)type];
+}
+
+template <typename T>
+void ExportCounterMetric(const android::CounterMetric<T> &counter,
+ PersistableBundle *metrics) {
+ if (!metrics) {
+ ALOGE("metrics was unexpectedly null.");
+ return;
+ }
+ std::string success_count_name = counter.metric_name() + ".ok.count";
+ std::string error_count_name = counter.metric_name() + ".error.count";
+ std::vector<int64_t> status_values;
+ counter.ExportValues(
+ [&](const android::status_t status, const int64_t value) {
+ if (status == android::OK) {
+ metrics->putLong(android::String16(success_count_name.c_str()),
+ value);
+ } else {
+ int64_t total_errors(0);
+ metrics->getLong(android::String16(error_count_name.c_str()),
+ &total_errors);
+ metrics->putLong(android::String16(error_count_name.c_str()),
+ total_errors + value);
+ status_values.push_back(status);
+ }
+ });
+ if (!status_values.empty()) {
+ std::string error_list_name = counter.metric_name() + ".error.list";
+ metrics->putLongVector(android::String16(error_list_name.c_str()),
+ status_values);
+ }
+}
+
+template <typename T>
+void ExportCounterMetricWithAttributeNames(
+ const android::CounterMetric<T> &counter, PersistableBundle *metrics) {
+ if (!metrics) {
+ ALOGE("metrics was unexpectedly null.");
+ return;
+ }
+ counter.ExportValues([&](const T &attribute, const int64_t value) {
+ std::string name = counter.metric_name() + "." +
+ GetAttributeName(attribute) + ".count";
+ metrics->putLong(android::String16(name.c_str()), value);
+ });
+}
+
+template <typename T>
+void ExportEventMetric(const android::EventMetric<T> &event,
+ PersistableBundle *metrics) {
+ if (!metrics) {
+ ALOGE("metrics was unexpectedly null.");
+ return;
+ }
+ std::string success_count_name = event.metric_name() + ".ok.count";
+ std::string error_count_name = event.metric_name() + ".error.count";
+ std::string timing_name = event.metric_name() + ".ok.average_time_micros";
+ std::vector<int64_t> status_values;
+ event.ExportValues([&](const android::status_t &status,
+ const android::EventStatistics &value) {
+ if (status == android::OK) {
+ metrics->putLong(android::String16(success_count_name.c_str()),
+ value.count);
+ metrics->putLong(android::String16(timing_name.c_str()),
+ value.mean);
+ } else {
+ int64_t total_errors(0);
+ metrics->getLong(android::String16(error_count_name.c_str()),
+ &total_errors);
+ metrics->putLong(android::String16(error_count_name.c_str()),
+ total_errors + value.count);
+ status_values.push_back(status);
+ }
+ });
+ if (!status_values.empty()) {
+ std::string error_list_name = event.metric_name() + ".error.list";
+ metrics->putLongVector(android::String16(error_list_name.c_str()),
+ status_values);
+ }
+}
+
+void ExportSessionLifespans(
+ const std::map<std::string, std::pair<int64_t, int64_t>> &sessionLifespans,
+ PersistableBundle *metrics) {
+ if (!metrics) {
+ ALOGE("metrics was unexpectedly null.");
+ return;
+ }
+
+ if (sessionLifespans.empty()) {
+ return;
+ }
+
+ PersistableBundle startTimesBundle;
+ PersistableBundle endTimesBundle;
+ for (auto it = sessionLifespans.begin(); it != sessionLifespans.end();
+ it++) {
+ String16 key(it->first.c_str(), it->first.size());
+ startTimesBundle.putLong(key, it->second.first);
+ endTimesBundle.putLong(key, it->second.second);
+ }
+ metrics->putPersistableBundle(
+ android::String16("drm.mediadrm.session_start_times_ms"),
+ startTimesBundle);
+ metrics->putPersistableBundle(
+ android::String16("drm.mediadrm.session_end_times_ms"), endTimesBundle);
+}
+
+template <typename CT>
+void SetValue(const String16 &name, DrmMetricGroup::ValueType type,
+ const CT &value, PersistableBundle *bundle) {
+ switch (type) {
+ case DrmMetricGroup::ValueType::INT64_TYPE:
+ bundle->putLong(name, value.int64Value);
+ break;
+ case DrmMetricGroup::ValueType::DOUBLE_TYPE:
+ bundle->putDouble(name, value.doubleValue);
+ break;
+ case DrmMetricGroup::ValueType::STRING_TYPE:
+ bundle->putString(name, String16(value.stringValue.c_str()));
+ break;
+ default:
+ ALOGE("Unexpected value type: %hhu", type);
+ }
+}
+
+inline String16 MakeIndexString(unsigned int index) {
+ std::string str("[");
+ str.append(std::to_string(index));
+ str.append("]");
+ return String16(str.c_str());
+}
+
+} // namespace
+
+namespace android {
+
+status_t DrmMetricsConsumer::consumeFrameworkMetrics(const MediaDrmMetrics &metrics) {
+ ExportCounterMetric(metrics.mOpenSessionCounter, mBundle);
+ ExportCounterMetric(metrics.mCloseSessionCounter, mBundle);
+ ExportEventMetric(metrics.mGetKeyRequestTimeUs, mBundle);
+ ExportEventMetric(metrics.mProvideKeyResponseTimeUs, mBundle);
+ ExportCounterMetric(metrics.mGetProvisionRequestCounter, mBundle);
+ ExportCounterMetric(metrics.mProvideProvisionResponseCounter, mBundle);
+ ExportCounterMetricWithAttributeNames(metrics.mKeyStatusChangeCounter, mBundle);
+ ExportCounterMetricWithAttributeNames(metrics.mEventCounter, mBundle);
+ ExportCounterMetric(metrics.mGetDeviceUniqueIdCounter, mBundle);
+ ExportSessionLifespans(metrics.GetSessionLifespans(), mBundle);
+ return android::OK;
+}
+
+status_t DrmMetricsConsumer::consumeHidlMetrics(
+ const String8 &vendor,
+ const hidl_vec<DrmMetricGroup> &pluginMetrics) {
+ PersistableBundle pluginBundle;
+ if (DrmMetricsConsumer::HidlMetricsToBundle(
+ pluginMetrics, &pluginBundle) == OK) {
+ mBundle->putPersistableBundle(String16(vendor), pluginBundle);
+ }
+ return android::OK;
+}
+
+status_t DrmMetricsConsumer::HidlMetricsToBundle(
+ const hidl_vec<DrmMetricGroup> &hidlMetricGroups,
+ PersistableBundle *bundleMetricGroups) {
+ if (bundleMetricGroups == nullptr) {
+ return UNEXPECTED_NULL;
+ }
+ if (hidlMetricGroups.size() == 0) {
+ return OK;
+ }
+
+ int groupIndex = 0;
+ std::map<String16, int> indexMap;
+ for (const auto &hidlMetricGroup : hidlMetricGroups) {
+ PersistableBundle bundleMetricGroup;
+ for (const auto &hidlMetric : hidlMetricGroup.metrics) {
+ String16 metricName(hidlMetric.name.c_str());
+ PersistableBundle bundleMetric;
+ // Add metric component values.
+ for (const auto &value : hidlMetric.values) {
+ SetValue(String16(value.componentName.c_str()), value.type,
+ value, &bundleMetric);
+ }
+ // Set metric attributes.
+ PersistableBundle bundleMetricAttributes;
+ for (const auto &attribute : hidlMetric.attributes) {
+ SetValue(String16(attribute.name.c_str()), attribute.type,
+ attribute, &bundleMetricAttributes);
+ }
+ // Add attributes to the bundle metric.
+ bundleMetric.putPersistableBundle(String16("attributes"),
+ bundleMetricAttributes);
+ // Add one layer of indirection, allowing for repeated metric names.
+ PersistableBundle repeatedMetrics;
+ bundleMetricGroup.getPersistableBundle(metricName,
+ &repeatedMetrics);
+ int index = indexMap[metricName];
+ repeatedMetrics.putPersistableBundle(MakeIndexString(index),
+ bundleMetric);
+ indexMap[metricName] = ++index;
+
+ // Add the bundle metric to the group of metrics.
+ bundleMetricGroup.putPersistableBundle(metricName,
+ repeatedMetrics);
+ }
+ // Add the bundle metric group to the collection of groups.
+ bundleMetricGroups->putPersistableBundle(MakeIndexString(groupIndex++),
+ bundleMetricGroup);
+ }
+
+ return OK;
+}
+
+} // namespace android
+
diff --git a/drm/libmediadrm/DrmUtils.cpp b/drm/libmediadrm/DrmUtils.cpp
index a126a1d..3549637 100644
--- a/drm/libmediadrm/DrmUtils.cpp
+++ b/drm/libmediadrm/DrmUtils.cpp
@@ -75,7 +75,7 @@
auto factory = Hal::getService(instance);
if (factory != nullptr) {
ALOGI("found %s %s", Hal::descriptor, instance.c_str());
- if (factory->isCryptoSchemeSupported(uuid)) {
+ if (!uuid || factory->isCryptoSchemeSupported(uuid)) {
factories.push_back(factory);
}
}
diff --git a/drm/libmediadrm/include/mediadrm/BundleDrmMetricsConsumer.h b/drm/libmediadrm/include/mediadrm/BundleDrmMetricsConsumer.h
deleted file mode 100644
index 1bcb352..0000000
--- a/drm/libmediadrm/include/mediadrm/BundleDrmMetricsConsumer.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <binder/PersistableBundle.h>
-#include <mediadrm/IDrmMetricsConsumer.h>
-#include <utils/Errors.h>
-
-#ifndef ANDROID_BUNDLEMETRICSCONSUMER_H_
-
-#define ANDROID_BUNDLEMETRICSCONSUMER_H_
-
-namespace android {
-
-/**
- * IDrmMetricsConsumer which saves IDrm/ICrypto metrics into a PersistableBundle.
- *
- * Example usage:
- *
- * PersistableBundle bundle;
- * BundleDrmMetricsConsumer consumer(&bundle);
- * drm->exportMetrics(&consumer);
- * crypto->exportMetrics(&consumer);
- * // bundle now contains metrics from drm/crypto.
- *
- */
-struct BundleDrmMetricsConsumer : public IDrmMetricsConsumer {
- BundleDrmMetricsConsumer(os::PersistableBundle*) {}
-
- status_t consumeFrameworkMetrics(const MediaDrmMetrics &) override {
- return OK;
- }
-
- status_t consumeHidlMetrics(
- const String8 &/*vendor*/,
- const hidl_vec<DrmMetricGroup> &/*pluginMetrics*/) override {
- return OK;
- }
-
-private:
- DISALLOW_EVIL_CONSTRUCTORS(BundleDrmMetricsConsumer);
-};
-
-} // namespace android
-
-#endif // ANDROID_BUNDLEMETRICSCONSUMER_H_
diff --git a/drm/libmediadrm/include/mediadrm/DrmHal.h b/drm/libmediadrm/include/mediadrm/DrmHal.h
index f261d89..3b4639b 100644
--- a/drm/libmediadrm/include/mediadrm/DrmHal.h
+++ b/drm/libmediadrm/include/mediadrm/DrmHal.h
@@ -30,6 +30,7 @@
#include <mediadrm/DrmSessionManager.h>
#include <mediadrm/IDrm.h>
#include <mediadrm/IDrmClient.h>
+#include <mediadrm/IDrmMetricsConsumer.h>
#include <utils/threads.h>
namespace drm = ::android::hardware::drm;
@@ -136,7 +137,7 @@
virtual status_t setPropertyString(String8 const &name, String8 const &value ) const;
virtual status_t setPropertyByteArray(String8 const &name,
Vector<uint8_t> const &value ) const;
- virtual status_t getMetrics(os::PersistableBundle *metrics);
+ virtual status_t getMetrics(const sp<IDrmMetricsConsumer> &consumer);
virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
String8 const &algorithm);
@@ -197,7 +198,7 @@
mutable Mutex mEventLock;
mutable Mutex mNotifyLock;
- const Vector<sp<IDrmFactory>> mFactories;
+ const std::vector<sp<IDrmFactory>> mFactories;
sp<IDrmPlugin> mPlugin;
sp<drm::V1_1::IDrmPlugin> mPluginV1_1;
sp<drm::V1_2::IDrmPlugin> mPluginV1_2;
@@ -218,7 +219,7 @@
*/
status_t mInitCheck;
- Vector<sp<IDrmFactory>> makeDrmFactories();
+ std::vector<sp<IDrmFactory>> makeDrmFactories();
sp<IDrmPlugin> makeDrmPlugin(const sp<IDrmFactory>& factory,
const uint8_t uuid[16], const String8& appPackageName);
diff --git a/drm/libmediadrm/include/mediadrm/DrmMetrics.h b/drm/libmediadrm/include/mediadrm/DrmMetrics.h
index 833ffa4..100b8f7 100644
--- a/drm/libmediadrm/include/mediadrm/DrmMetrics.h
+++ b/drm/libmediadrm/include/mediadrm/DrmMetrics.h
@@ -75,55 +75,14 @@
void SetAppUid(uid_t appUid) { mAppUid = appUid; }
uid_t GetAppUid() const { return mAppUid; }
- // Export the metrics to a PersistableBundle.
- void Export(os::PersistableBundle* metricsBundle);
-
// Get the serialized metrics. Metrics are formatted as a serialized
// DrmFrameworkMetrics proto. If there is a failure serializing the metrics,
// this returns an error. The parameter |serlializedMetrics| is owned by the
// caller and must not be null.
status_t GetSerializedMetrics(std::string* serializedMetrics);
- // Converts the DRM plugin metrics to a PersistableBundle. All of the metrics
- // found in |pluginMetrics| are added to the |metricsBundle| parameter.
- // |pluginBundle| is owned by the caller and must not be null.
- //
- // Each item in the pluginMetrics vector is added as a new PersistableBundle. E.g.
- // DrmMetricGroup {
- // metrics[0] {
- // name: "buf_copy"
- // attributes[0] {
- // name: "size"
- // type: INT64_TYPE
- // int64Value: 1024
- // }
- // values[0] {
- // componentName: "operation_count"
- // type: INT64_TYPE
- // int64Value: 75
- // }
- // values[1] {
- // component_name: "average_time_seconds"
- // type: DOUBLE_TYPE
- // doubleValue: 0.00000042
- // }
- // }
- // }
- //
- // becomes
- //
- // metricsBundle {
- // "0": (PersistableBundle) {
- // "attributes" : (PersistableBundle) {
- // "size" : (int64) 1024
- // }
- // "operation_count" : (int64) 75
- // "average_time_seconds" : (double) 0.00000042
- // }
- //
- static status_t HidlMetricsToBundle(
- const hardware::hidl_vec<hardware::drm::V1_1::DrmMetricGroup>& pluginMetrics,
- os::PersistableBundle* metricsBundle);
+ // Get copy of session lifetimes.
+ std::map<std::string, std::pair<int64_t, int64_t>> GetSessionLifespans() const;
protected:
// This is visible for testing only.
diff --git a/drm/libmediadrm/include/mediadrm/DrmMetricsConsumer.h b/drm/libmediadrm/include/mediadrm/DrmMetricsConsumer.h
new file mode 100644
index 0000000..bbbf4b5
--- /dev/null
+++ b/drm/libmediadrm/include/mediadrm/DrmMetricsConsumer.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/PersistableBundle.h>
+#include <mediadrm/IDrmMetricsConsumer.h>
+#include <utils/Errors.h>
+
+#ifndef ANDROID_METRICSCONSUMER_H_
+
+#define ANDROID_METRICSCONSUMER_H_
+
+namespace android {
+
+/**
+ * IDrmMetricsConsumer which saves IDrm/ICrypto metrics into a PersistableBundle.
+ *
+ * Example usage:
+ *
+ * PersistableBundle bundle;
+ * DrmMetricsConsumer consumer(&bundle);
+ * drm->exportMetrics(&consumer);
+ * crypto->exportMetrics(&consumer);
+ * // bundle now contains metrics from drm/crypto.
+ *
+ */
+struct DrmMetricsConsumer : public IDrmMetricsConsumer {
+ DrmMetricsConsumer(os::PersistableBundle *bundle) : mBundle(bundle) {}
+
+ status_t consumeFrameworkMetrics(const MediaDrmMetrics &) override;
+
+ status_t consumeHidlMetrics(
+ const String8 &/*vendor*/,
+ const hidl_vec<DrmMetricGroup> &/*pluginMetrics*/) override;
+
+ // Converts the DRM plugin metrics to a PersistableBundle. All of the metrics
+ // found in |pluginMetrics| are added to the |metricsBundle| parameter.
+ // |pluginBundle| is owned by the caller and must not be null.
+ //
+ // Each item in the pluginMetrics vector is added as a new PersistableBundle. E.g.
+ // DrmMetricGroup {
+ // metrics[0] {
+ // name: "buf_copy"
+ // attributes[0] {
+ // name: "size"
+ // type: INT64_TYPE
+ // int64Value: 1024
+ // }
+ // values[0] {
+ // componentName: "operation_count"
+ // type: INT64_TYPE
+ // int64Value: 75
+ // }
+ // values[1] {
+ // component_name: "average_time_seconds"
+ // type: DOUBLE_TYPE
+ // doubleValue: 0.00000042
+ // }
+ // }
+ // }
+ //
+ // becomes
+ //
+ // metricsBundle {
+ // "0": (PersistableBundle) {
+ // "attributes" : (PersistableBundle) {
+ // "size" : (int64) 1024
+ // }
+ // "operation_count" : (int64) 75
+ // "average_time_seconds" : (double) 0.00000042
+ // }
+ //
+ static status_t HidlMetricsToBundle(
+ const hardware::hidl_vec<hardware::drm::V1_1::DrmMetricGroup>& pluginMetrics,
+ os::PersistableBundle* metricsBundle);
+
+private:
+ os::PersistableBundle *mBundle;
+ DISALLOW_EVIL_CONSTRUCTORS(DrmMetricsConsumer);
+};
+
+} // namespace android
+
+#endif // ANDROID_METRICSCONSUMER_H_
diff --git a/drm/libmediadrm/include/mediadrm/IDrm.h b/drm/libmediadrm/include/mediadrm/IDrm.h
index 4103d5d..0177c24 100644
--- a/drm/libmediadrm/include/mediadrm/IDrm.h
+++ b/drm/libmediadrm/include/mediadrm/IDrm.h
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-#include <binder/IInterface.h>
-#include <binder/PersistableBundle.h>
#include <media/stagefright/foundation/ABase.h>
#include <media/drm/DrmAPI.h>
#include <mediadrm/IDrmClient.h>
+#include <mediadrm/IDrmMetricsConsumer.h>
#ifndef ANDROID_IDRM_H_
@@ -107,7 +106,7 @@
virtual status_t setPropertyByteArray(String8 const &name,
Vector<uint8_t> const &value) const = 0;
- virtual status_t getMetrics(os::PersistableBundle *metrics) = 0;
+ virtual status_t getMetrics(const sp<IDrmMetricsConsumer> &consumer) = 0;
virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
String8 const &algorithm) = 0;
diff --git a/drm/libmediadrm/include/mediadrm/IDrmMetricsConsumer.h b/drm/libmediadrm/include/mediadrm/IDrmMetricsConsumer.h
index efa61d8..aef35c3 100644
--- a/drm/libmediadrm/include/mediadrm/IDrmMetricsConsumer.h
+++ b/drm/libmediadrm/include/mediadrm/IDrmMetricsConsumer.h
@@ -55,8 +55,8 @@
* ----------------------------------------
*
* For an example implementation of IDrmMetricsConsumer, please
- * see BundleDrmMetricsConsumer. BundleDrmMetricsConsumer consumes
- * IDrm/ICrypto metrics and saves the metrics to a PersistableBundle.
+ * see DrmMetricsConsumer. DrmMetricsConsumer consumes IDrm/ICrypto
+ * metrics and saves the metrics to a PersistableBundle.
*
*/
struct IDrmMetricsConsumer : public RefBase {
diff --git a/drm/libmediadrm/interface/mediadrm/DrmUtils.h b/drm/libmediadrm/interface/mediadrm/DrmUtils.h
index 3017274..20b3fe9 100644
--- a/drm/libmediadrm/interface/mediadrm/DrmUtils.h
+++ b/drm/libmediadrm/interface/mediadrm/DrmUtils.h
@@ -21,7 +21,6 @@
#include <android/hardware/drm/1.0/IDrmFactory.h>
#include <utils/Errors.h> // for status_t
#include <utils/StrongPointer.h>
-#include <binder/Parcel.h>
#include <vector>
using namespace ::android::hardware::drm;
@@ -39,17 +38,17 @@
sp<ICrypto> MakeCrypto(status_t *pstatus = nullptr);
-template<typename BA>
-void WriteByteArray(Parcel &obj, const BA &vec) {
+template<typename BA, typename PARCEL>
+void WriteByteArray(PARCEL &obj, const BA &vec) {
obj.writeInt32(vec.size());
if (vec.size()) {
obj.write(vec.data(), vec.size());
}
}
-template<typename ET, typename BA>
+template<typename ET, typename BA, typename PARCEL>
void WriteEventToParcel(
- Parcel &obj,
+ PARCEL &obj,
ET eventType,
const BA &sessionId,
const BA &data) {
@@ -58,18 +57,18 @@
obj.writeInt32(eventType);
}
-template<typename BA>
+template<typename BA, typename PARCEL>
void WriteExpirationUpdateToParcel(
- Parcel &obj,
+ PARCEL &obj,
const BA &sessionId,
int64_t expiryTimeInMS) {
WriteByteArray(obj, sessionId);
obj.writeInt64(expiryTimeInMS);
}
-template<typename BA, typename KSL>
+template<typename BA, typename KSL, typename PARCEL>
void WriteKeysChange(
- Parcel &obj,
+ PARCEL &obj,
const BA &sessionId,
const KSL &keyStatusList,
bool hasNewUsableKey) {
@@ -82,7 +81,7 @@
obj.writeInt32(hasNewUsableKey);
}
-std::vector<sp<::V1_0::IDrmFactory>> MakeDrmFactories(const uint8_t uuid[16]);
+std::vector<sp<::V1_0::IDrmFactory>> MakeDrmFactories(const uint8_t uuid[16] = nullptr);
std::vector<sp<::V1_0::IDrmPlugin>> MakeDrmPlugins(const uint8_t uuid[16],
const char *appPackageName);
diff --git a/drm/libmediadrm/tests/Android.bp b/drm/libmediadrm/tests/Android.bp
index 2e39943..7471e05 100644
--- a/drm/libmediadrm/tests/Android.bp
+++ b/drm/libmediadrm/tests/Android.bp
@@ -24,6 +24,8 @@
"libbinder",
"libhidlbase",
"liblog",
+ "libmediadrm",
+ "libmediadrmmetrics_consumer",
"libmediadrmmetrics_full",
"libmediametrics",
"libprotobuf-cpp-full",
diff --git a/drm/libmediadrm/tests/DrmMetrics_test.cpp b/drm/libmediadrm/tests/DrmMetrics_test.cpp
index 5c8a1b0..f362d60 100644
--- a/drm/libmediadrm/tests/DrmMetrics_test.cpp
+++ b/drm/libmediadrm/tests/DrmMetrics_test.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "DrmMetricsTest"
#include "mediadrm/DrmMetrics.h"
+#include "mediadrm/DrmMetricsConsumer.h"
#include <android/hardware/drm/1.0/types.h>
#include <android/hardware/drm/1.1/types.h>
@@ -58,8 +59,9 @@
TEST_F(MediaDrmMetricsTest, EmptySuccess) {
MediaDrmMetrics metrics;
PersistableBundle bundle;
+ DrmMetricsConsumer consumer(&bundle);
- metrics.Export(&bundle);
+ consumer.consumeFrameworkMetrics(metrics);
EXPECT_TRUE(bundle.empty());
}
@@ -85,8 +87,9 @@
metrics.mEventCounter.Increment(EventType::PROVISION_REQUIRED);
PersistableBundle bundle;
+ DrmMetricsConsumer consumer(&bundle);
- metrics.Export(&bundle);
+ consumer.consumeFrameworkMetrics(metrics);
EXPECT_EQ(11U, bundle.size());
// Verify the list of pairs of int64 metrics.
@@ -174,7 +177,8 @@
metrics.SetSessionEnd(sessionId1);
PersistableBundle bundle;
- metrics.Export(&bundle);
+ DrmMetricsConsumer consumer(&bundle);
+ consumer.consumeFrameworkMetrics(metrics);
EXPECT_EQ(35U, bundle.size());
// Verify the list of pairs of int64 metrics.
@@ -421,7 +425,7 @@
hidl_vec<DrmMetricGroup> hidlMetricGroups;
PersistableBundle bundleMetricGroups;
- ASSERT_EQ(OK, MediaDrmMetrics::HidlMetricsToBundle(hidlMetricGroups, &bundleMetricGroups));
+ ASSERT_EQ(OK, DrmMetricsConsumer::HidlMetricsToBundle(hidlMetricGroups, &bundleMetricGroups));
ASSERT_EQ(0U, bundleMetricGroups.size());
}
@@ -441,7 +445,7 @@
} } };
PersistableBundle bundleMetricGroups;
- ASSERT_EQ(OK, MediaDrmMetrics::HidlMetricsToBundle(hidl_vec<DrmMetricGroup>({hidlMetricGroup}),
+ ASSERT_EQ(OK, DrmMetricsConsumer::HidlMetricsToBundle(hidl_vec<DrmMetricGroup>({hidlMetricGroup}),
&bundleMetricGroups));
ASSERT_EQ(1U, bundleMetricGroups.size());
PersistableBundle bundleMetricGroup;
diff --git a/drm/mediadrm/plugins/clearkey/common/ClearKeyUUID.cpp b/drm/mediadrm/plugins/clearkey/common/ClearKeyUUID.cpp
index 0259a42..4e7daec 100644
--- a/drm/mediadrm/plugins/clearkey/common/ClearKeyUUID.cpp
+++ b/drm/mediadrm/plugins/clearkey/common/ClearKeyUUID.cpp
@@ -20,20 +20,28 @@
namespace clearkeydrm {
+namespace {
+
+const std::array<uint8_t, 16> kCommonPsshBoxUUID{
+ 0x10,0x77,0xEF,0xEC,0xC0,0xB2,0x4D,0x02,
+ 0xAC,0xE3,0x3C,0x1E,0x52,0xE2,0xFB,0x4B
+};
+
+// To be used in mpd to specify drm scheme for players
+const std::array<uint8_t, 16> kClearKeyUUID{
+ 0xE2,0x71,0x9D,0x58,0xA9,0x85,0xB3,0xC9,
+ 0x78,0x1A,0xB0,0x30,0xAF,0x78,0xD3,0x0E
+};
+
+}
+
bool isClearKeyUUID(const uint8_t uuid[16]) {
- static const uint8_t kCommonPsshBoxUUID[16] = {
- 0x10,0x77,0xEF,0xEC,0xC0,0xB2,0x4D,0x02,
- 0xAC,0xE3,0x3C,0x1E,0x52,0xE2,0xFB,0x4B
- };
+ return !memcmp(uuid, kCommonPsshBoxUUID.data(), kCommonPsshBoxUUID.size()) ||
+ !memcmp(uuid, kClearKeyUUID.data(), kClearKeyUUID.size());
+}
- // To be used in mpd to specify drm scheme for players
- static const uint8_t kClearKeyUUID[16] = {
- 0xE2,0x71,0x9D,0x58,0xA9,0x85,0xB3,0xC9,
- 0x78,0x1A,0xB0,0x30,0xAF,0x78,0xD3,0x0E
- };
-
- return !memcmp(uuid, kCommonPsshBoxUUID, sizeof(kCommonPsshBoxUUID)) ||
- !memcmp(uuid, kClearKeyUUID, sizeof(kClearKeyUUID));
+std::vector<std::array<uint8_t, 16>> getSupportedCryptoSchemes() {
+ return {kCommonPsshBoxUUID, kClearKeyUUID};
}
} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/include/ClearKeyUUID.h b/drm/mediadrm/plugins/clearkey/common/include/ClearKeyUUID.h
index ac99418..fe10fba 100644
--- a/drm/mediadrm/plugins/clearkey/common/include/ClearKeyUUID.h
+++ b/drm/mediadrm/plugins/clearkey/common/include/ClearKeyUUID.h
@@ -17,12 +17,16 @@
#ifndef CLEARKEY_UUID_H_
#define CLEARKEY_UUID_H_
-#include <stdint.h>
+#include <array>
+#include <cstdint>
+#include <vector>
namespace clearkeydrm {
bool isClearKeyUUID(const uint8_t uuid[16]);
+std::vector<std::array<uint8_t, 16>> getSupportedCryptoSchemes();
+
} // namespace clearkeydrm
#endif // CLEARKEY_UUID_H_
diff --git a/drm/mediadrm/plugins/clearkey/hidl/Android.bp b/drm/mediadrm/plugins/clearkey/hidl/Android.bp
index a153ce2..eb623f9 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/hidl/Android.bp
@@ -43,6 +43,7 @@
"android.hardware.drm@1.0",
"android.hardware.drm@1.1",
"android.hardware.drm@1.2",
+ "android.hardware.drm@1.3",
"libbase",
"libbinder",
"libcrypto",
@@ -82,6 +83,7 @@
defaults: ["clearkey_service_defaults"],
srcs: ["service.cpp"],
init_rc: ["android.hardware.drm@1.2-service.clearkey.rc"],
+ vintf_fragments: ["manifest_android.hardware.drm@1.3-service.clearkey.xml"],
}
cc_binary {
name: "android.hardware.drm@1.2-service-lazy.clearkey",
@@ -89,4 +91,5 @@
defaults: ["clearkey_service_defaults"],
srcs: ["serviceLazy.cpp"],
init_rc: ["android.hardware.drm@1.2-service-lazy.clearkey.rc"],
+ vintf_fragments: ["manifest_android.hardware.drm@1.3-service.clearkey.xml"],
}
diff --git a/drm/mediadrm/plugins/clearkey/hidl/CreatePluginFactories.cpp b/drm/mediadrm/plugins/clearkey/hidl/CreatePluginFactories.cpp
index 1410d77..bfb0e05 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/CreatePluginFactories.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/CreatePluginFactories.cpp
@@ -22,7 +22,7 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_3 {
namespace clearkey {
extern "C" {
@@ -38,7 +38,7 @@
} // extern "C"
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_3
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/CryptoFactory.cpp b/drm/mediadrm/plugins/clearkey/hidl/CryptoFactory.cpp
index 2a48db6..a6ed3bd 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/CryptoFactory.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/CryptoFactory.cpp
@@ -27,9 +27,12 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_3 {
namespace clearkey {
+using ::android::hardware::drm::V1_0::Status;
+using ::android::hardware::drm::V1_2::clearkey::CryptoPlugin;
+
Return<bool> CryptoFactory::isCryptoSchemeSupported(
const hidl_array<uint8_t, 16> &uuid)
{
@@ -60,7 +63,7 @@
}
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_3
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmFactory.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmFactory.cpp
index 9fb5bbe..ccc73b6 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmFactory.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmFactory.cpp
@@ -15,6 +15,7 @@
*/
//#define LOG_NDEBUG 0
+#include <vector>
#define LOG_TAG "hidl_ClearKeyDrmFactory"
#include <utils/Log.h>
@@ -30,11 +31,13 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_3 {
namespace clearkey {
using ::android::hardware::drm::V1_0::Status;
using ::android::hardware::drm::V1_1::SecurityLevel;
+using ::android::hardware::drm::V1_2::clearkey::DrmPlugin;
+using ::android::hardware::drm::V1_2::clearkey::SessionLibrary;
using ::android::hardware::Void;
Return<bool> DrmFactory::isCryptoSchemeSupported(
@@ -78,8 +81,18 @@
return Void();
}
+Return<void> DrmFactory::getSupportedCryptoSchemes(
+ getSupportedCryptoSchemes_cb _hidl_cb) {
+ std::vector<hidl_array<uint8_t, 16>> schemes;
+ for (const auto &scheme : clearkeydrm::getSupportedCryptoSchemes()) {
+ schemes.push_back(scheme);
+ }
+ _hidl_cb(schemes);
+ return Void();
+}
+
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_3
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service-lazy.clearkey.rc b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service-lazy.clearkey.rc
index 9afd3d7..cff4d74 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service-lazy.clearkey.rc
+++ b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service-lazy.clearkey.rc
@@ -5,6 +5,8 @@
interface android.hardware.drm@1.1::IDrmFactory clearkey
interface android.hardware.drm@1.2::ICryptoFactory clearkey
interface android.hardware.drm@1.2::IDrmFactory clearkey
+ interface android.hardware.drm@1.3::ICryptoFactory clearkey
+ interface android.hardware.drm@1.3::IDrmFactory clearkey
disabled
oneshot
class hal
diff --git a/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service.clearkey.rc b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service.clearkey.rc
index 5ba669d..dca232a 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service.clearkey.rc
+++ b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service.clearkey.rc
@@ -5,6 +5,8 @@
interface android.hardware.drm@1.1::IDrmFactory clearkey
interface android.hardware.drm@1.2::ICryptoFactory clearkey
interface android.hardware.drm@1.2::IDrmFactory clearkey
+ interface android.hardware.drm@1.3::ICryptoFactory clearkey
+ interface android.hardware.drm@1.3::IDrmFactory clearkey
class hal
user media
group media mediadrm
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/CreatePluginFactories.h b/drm/mediadrm/plugins/clearkey/hidl/include/CreatePluginFactories.h
index 6368f3d..c1c188e 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/CreatePluginFactories.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/CreatePluginFactories.h
@@ -17,17 +17,17 @@
#ifndef CLEARKEY_CREATE_PLUGIN_FACTORIES_H_
#define CLEARKEY_CREATE_PLUGIN_FACTORIES_H_
-#include <android/hardware/drm/1.2/ICryptoFactory.h>
-#include <android/hardware/drm/1.2/IDrmFactory.h>
+#include <android/hardware/drm/1.3/ICryptoFactory.h>
+#include <android/hardware/drm/1.3/IDrmFactory.h>
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_3 {
namespace clearkey {
-using ::android::hardware::drm::V1_2::ICryptoFactory;
-using ::android::hardware::drm::V1_2::IDrmFactory;
+using ::android::hardware::drm::V1_3::ICryptoFactory;
+using ::android::hardware::drm::V1_3::IDrmFactory;
extern "C" {
IDrmFactory* createDrmFactory();
@@ -35,7 +35,7 @@
}
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_3
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/CryptoFactory.h b/drm/mediadrm/plugins/clearkey/hidl/include/CryptoFactory.h
index 203bb2d..cb4811b 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/CryptoFactory.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/CryptoFactory.h
@@ -18,17 +18,17 @@
#define CLEARKEY_CRYPTO_FACTORY_H_
#include <android/hardware/drm/1.0/ICryptoPlugin.h>
-#include <android/hardware/drm/1.2/ICryptoFactory.h>
+#include <android/hardware/drm/1.3/ICryptoFactory.h>
#include "ClearKeyTypes.h"
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_3 {
namespace clearkey {
-using ::android::hardware::drm::V1_2::ICryptoFactory;
+using ::android::hardware::drm::V1_3::ICryptoFactory;
using ::android::hardware::drm::V1_0::ICryptoPlugin;
using ::android::hardware::hidl_array;
using ::android::hardware::hidl_string;
@@ -52,7 +52,7 @@
};
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_3
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/DrmFactory.h b/drm/mediadrm/plugins/clearkey/hidl/include/DrmFactory.h
index 4ca856d..403a8ec 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/DrmFactory.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DrmFactory.h
@@ -18,16 +18,17 @@
#define CLEARKEY_DRM_FACTORY_H_
#include <android/hardware/drm/1.2/IDrmPlugin.h>
-#include <android/hardware/drm/1.2/IDrmFactory.h>
+#include <android/hardware/drm/1.3/IDrmFactory.h>
#include "ClearKeyTypes.h"
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_3 {
namespace clearkey {
+using ::android::hardware::drm::V1_1::SecurityLevel;
using ::android::hardware::hidl_array;
using ::android::hardware::hidl_string;
using ::android::hardware::Return;
@@ -51,12 +52,15 @@
const hidl_string& appPackageName,
createPlugin_cb _hidl_cb) override;
+ Return<void> getSupportedCryptoSchemes(
+ getSupportedCryptoSchemes_cb _hidl_cb) override;
+
private:
CLEARKEY_DISALLOW_COPY_AND_ASSIGN(DrmFactory);
};
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_3
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/manifest_android.hardware.drm@1.3-service.clearkey.xml b/drm/mediadrm/plugins/clearkey/hidl/manifest_android.hardware.drm@1.3-service.clearkey.xml
new file mode 100644
index 0000000..229ee96
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/manifest_android.hardware.drm@1.3-service.clearkey.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.drm</name>
+ <transport>hwbinder</transport>
+ <fqname>@1.3::ICryptoFactory/clearkey</fqname>
+ <fqname>@1.3::IDrmFactory/clearkey</fqname>
+ </hal>
+</manifest>
diff --git a/drm/mediadrm/plugins/clearkey/hidl/service.cpp b/drm/mediadrm/plugins/clearkey/hidl/service.cpp
index b39ea01..b62baae 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/service.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/service.cpp
@@ -25,10 +25,10 @@
using ::android::hardware::joinRpcThreadpool;
using ::android::sp;
-using android::hardware::drm::V1_2::ICryptoFactory;
-using android::hardware::drm::V1_2::IDrmFactory;
-using android::hardware::drm::V1_2::clearkey::CryptoFactory;
-using android::hardware::drm::V1_2::clearkey::DrmFactory;
+using android::hardware::drm::V1_3::ICryptoFactory;
+using android::hardware::drm::V1_3::IDrmFactory;
+using android::hardware::drm::V1_3::clearkey::CryptoFactory;
+using android::hardware::drm::V1_3::clearkey::DrmFactory;
int main(int /* argc */, char** /* argv */) {
sp<IDrmFactory> drmFactory = new DrmFactory;
diff --git a/drm/mediadrm/plugins/clearkey/hidl/serviceLazy.cpp b/drm/mediadrm/plugins/clearkey/hidl/serviceLazy.cpp
index a510487..b3e0179 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/serviceLazy.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/serviceLazy.cpp
@@ -25,10 +25,10 @@
using ::android::hardware::joinRpcThreadpool;
using ::android::sp;
-using android::hardware::drm::V1_2::ICryptoFactory;
-using android::hardware::drm::V1_2::IDrmFactory;
-using android::hardware::drm::V1_2::clearkey::CryptoFactory;
-using android::hardware::drm::V1_2::clearkey::DrmFactory;
+using android::hardware::drm::V1_3::ICryptoFactory;
+using android::hardware::drm::V1_3::IDrmFactory;
+using android::hardware::drm::V1_3::clearkey::CryptoFactory;
+using android::hardware::drm::V1_3::clearkey::DrmFactory;
using android::hardware::LazyServiceRegistrar;
int main(int /* argc */, char** /* argv */) {
diff --git a/include/media/DataSource.h b/include/media/DataSource.h
deleted file mode 120000
index 198b27e..0000000
--- a/include/media/DataSource.h
+++ /dev/null
@@ -1 +0,0 @@
-stagefright/DataSource.h
\ No newline at end of file
diff --git a/media/libstagefright/include/media/stagefright/DataSource.h b/include/media/DataSource.h
similarity index 97%
rename from media/libstagefright/include/media/stagefright/DataSource.h
rename to include/media/DataSource.h
index 83d3e5d..8efa809 100644
--- a/media/libstagefright/include/media/stagefright/DataSource.h
+++ b/include/media/DataSource.h
@@ -19,14 +19,14 @@
#define DATA_SOURCE_H_
#include <sys/types.h>
+
+#include <android/IDataSource.h>
#include <media/stagefright/MediaErrors.h>
#include <media/DataSourceBase.h>
-#include <media/IDataSource.h>
#include <media/MediaExtractorPluginApi.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
-#include <drm/DrmManagerClient.h>
namespace android {
diff --git a/media/codec2/hidl/services/vendor.cpp b/media/codec2/hidl/services/vendor.cpp
index 65bb6f7..81bffeb 100644
--- a/media/codec2/hidl/services/vendor.cpp
+++ b/media/codec2/hidl/services/vendor.cpp
@@ -23,7 +23,9 @@
#include <hidl/HidlTransportSupport.h>
#include <minijail.h>
+#include <util/C2InterfaceHelper.h>
#include <C2Component.h>
+#include <C2Config.h>
// This is the absolute on-device path of the prebuild_etc module
// "android.hardware.media.c2@1.1-default-seccomp_policy" in Android.bp.
@@ -37,11 +39,14 @@
"/vendor/etc/seccomp_policy/"
"android.hardware.media.c2@1.1-extended-seccomp-policy";
-class DummyC2Store : public C2ComponentStore {
+class StoreImpl : public C2ComponentStore {
public:
- DummyC2Store() = default;
+ StoreImpl()
+ : mReflectorHelper(std::make_shared<C2ReflectorHelper>()),
+ mInterface(mReflectorHelper) {
+ }
- virtual ~DummyC2Store() override = default;
+ virtual ~StoreImpl() override = default;
virtual C2String getName() const override {
return "default";
@@ -71,31 +76,69 @@
}
virtual c2_status_t query_sm(
- const std::vector<C2Param*>& /* stackParams */,
- const std::vector<C2Param::Index>& /* heapParamIndices */,
- std::vector<std::unique_ptr<C2Param>>* const /* heapParams */) const override {
- return C2_OMITTED;
+ const std::vector<C2Param*>& stackParams,
+ const std::vector<C2Param::Index>& heapParamIndices,
+ std::vector<std::unique_ptr<C2Param>>* const heapParams) const override {
+ return mInterface.query(stackParams, heapParamIndices, C2_MAY_BLOCK, heapParams);
}
virtual c2_status_t config_sm(
- const std::vector<C2Param*>& /* params */,
- std::vector<std::unique_ptr<C2SettingResult>>* const /* failures */) override {
- return C2_OMITTED;
+ const std::vector<C2Param*>& params,
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures) override {
+ return mInterface.config(params, C2_MAY_BLOCK, failures);
}
virtual std::shared_ptr<C2ParamReflector> getParamReflector() const override {
- return nullptr;
+ return mReflectorHelper;
}
virtual c2_status_t querySupportedParams_nb(
- std::vector<std::shared_ptr<C2ParamDescriptor>>* const /* params */) const override {
- return C2_OMITTED;
+ std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const override {
+ return mInterface.querySupportedParams(params);
}
virtual c2_status_t querySupportedValues_sm(
- std::vector<C2FieldSupportedValuesQuery>& /* fields */) const override {
- return C2_OMITTED;
+ std::vector<C2FieldSupportedValuesQuery>& fields) const override {
+ return mInterface.querySupportedValues(fields, C2_MAY_BLOCK);
}
+
+private:
+ class Interface : public C2InterfaceHelper {
+ public:
+ Interface(const std::shared_ptr<C2ReflectorHelper> &helper)
+ : C2InterfaceHelper(helper) {
+ setDerivedInstance(this);
+
+ addParameter(
+ DefineParam(mIonUsageInfo, "ion-usage")
+ .withDefault(new C2StoreIonUsageInfo())
+ .withFields({
+ C2F(mIonUsageInfo, usage).flags(
+ {C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE}),
+ C2F(mIonUsageInfo, capacity).inRange(0, UINT32_MAX, 1024),
+ C2F(mIonUsageInfo, heapMask).any(),
+ C2F(mIonUsageInfo, allocFlags).flags({}),
+ C2F(mIonUsageInfo, minAlignment).equalTo(0)
+ })
+ .withSetter(SetIonUsage)
+ .build());
+ }
+
+ virtual ~Interface() = default;
+
+ private:
+ static C2R SetIonUsage(bool /* mayBlock */, C2P<C2StoreIonUsageInfo> &me) {
+ // Vendor's TODO: put appropriate mapping logic
+ me.set().heapMask = ~0;
+ me.set().allocFlags = 0;
+ me.set().minAlignment = 0;
+ return C2R::Ok();
+ }
+
+ std::shared_ptr<C2StoreIonUsageInfo> mIonUsageInfo;
+ };
+ std::shared_ptr<C2ReflectorHelper> mReflectorHelper;
+ Interface mInterface;
};
int main(int /* argc */, char** /* argv */) {
@@ -124,7 +167,7 @@
// /* implementation of C2ComponentStore */);
LOG(DEBUG) << "Instantiating Codec2's IComponentStore service...";
store = new utils::ComponentStore(
- std::make_shared<DummyC2Store>());
+ std::make_shared<StoreImpl>());
if (store == nullptr) {
LOG(ERROR) << "Cannot create Codec2's IComponentStore service.";
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index c78cdc1..31e5406 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -1524,7 +1524,9 @@
{
Mutexed<State>::Locked state(mState);
- state->set(FLUSHED);
+ if (state->get() == FLUSHING) {
+ state->set(FLUSHED);
+ }
}
mCallback->onFlushCompleted();
}
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 39f3f35..2bcb7e2 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -826,10 +826,8 @@
bool secure = mComponent->getName().find(".secure") != std::string::npos;
std::shared_ptr<C2AllocatorStore> allocatorStore = GetCodec2PlatformAllocatorStore();
- int poolMask = property_get_int32(
- "debug.stagefright.c2-poolmask",
- 1 << C2PlatformAllocatorStore::ION |
- 1 << C2PlatformAllocatorStore::BUFFERQUEUE);
+ int poolMask = GetCodec2PoolMask();
+ C2PlatformAllocatorStore::id_t preferredLinearId = GetPreferredLinearAllocatorId(poolMask);
if (inputFormat != nullptr) {
bool graphic = (iStreamFormat.value == C2BufferData::GRAPHIC);
@@ -839,7 +837,7 @@
// set default allocator ID.
pools->inputAllocatorId = (graphic) ? C2PlatformAllocatorStore::GRALLOC
- : C2PlatformAllocatorStore::ION;
+ : preferredLinearId;
// query C2PortAllocatorsTuning::input from component. If an allocator ID is obtained
// from component, create the input block pool with given ID. Otherwise, use default IDs.
@@ -978,7 +976,7 @@
// set default allocator ID.
pools->outputAllocatorId = (graphic) ? C2PlatformAllocatorStore::GRALLOC
- : C2PlatformAllocatorStore::ION;
+ : preferredLinearId;
// query C2PortAllocatorsTuning::output from component, or use default allocator if
// unsuccessful.
@@ -1670,6 +1668,14 @@
mMetaMode = mode;
}
+void CCodecBufferChannel::setCrypto(const sp<ICrypto> &crypto) {
+ mCrypto = crypto;
+}
+
+void CCodecBufferChannel::setDescrambler(const sp<IDescrambler> &descrambler) {
+ mDescrambler = descrambler;
+}
+
status_t toStatusT(c2_status_t c2s, c2_operation_t c2op) {
// C2_OK is always translated to OK.
if (c2s == C2_OK) {
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index c0fa138..82fec18 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -56,6 +56,9 @@
virtual ~CCodecBufferChannel();
// BufferChannelBase interface
+ void setCrypto(const sp<ICrypto> &crypto) override;
+ void setDescrambler(const sp<IDescrambler> &descrambler) override;
+
virtual status_t queueInputBuffer(const sp<MediaCodecBuffer> &buffer) override;
virtual status_t queueSecureInputBuffer(
const sp<MediaCodecBuffer> &buffer,
@@ -318,6 +321,9 @@
std::atomic_bool mInputMetEos;
std::once_flag mRenderWarningFlag;
+ sp<ICrypto> mCrypto;
+ sp<IDescrambler> mDescrambler;
+
inline bool hasCryptoOrDescrambler() {
return mCrypto != nullptr || mDescrambler != nullptr;
}
diff --git a/media/codec2/vndk/C2Buffer.cpp b/media/codec2/vndk/C2Buffer.cpp
index 2d99b53..0b08f31 100644
--- a/media/codec2/vndk/C2Buffer.cpp
+++ b/media/codec2/vndk/C2Buffer.cpp
@@ -22,14 +22,17 @@
#include <map>
#include <mutex>
-#include <C2AllocatorIon.h>
+#include <C2AllocatorBlob.h>
#include <C2AllocatorGralloc.h>
+#include <C2AllocatorIon.h>
#include <C2BufferPriv.h>
#include <C2BlockInternal.h>
+#include <C2PlatformSupport.h>
#include <bufferpool/ClientManager.h>
namespace {
+using android::C2AllocatorBlob;
using android::C2AllocatorGralloc;
using android::C2AllocatorIon;
using android::hardware::media::bufferpool::BufferPoolData;
@@ -393,10 +396,29 @@
std::shared_ptr<C2LinearBlock> _C2BlockFactory::CreateLinearBlock(
const C2Handle *handle) {
// TODO: get proper allocator? and mutex?
- static std::unique_ptr<C2AllocatorIon> sAllocator = std::make_unique<C2AllocatorIon>(0);
+ static std::unique_ptr<C2Allocator> sAllocator = []{
+ std::unique_ptr<C2Allocator> allocator;
+ if (android::GetPreferredLinearAllocatorId(android::GetCodec2PoolMask()) ==
+ android::C2PlatformAllocatorStore::BLOB) {
+ allocator = std::make_unique<C2AllocatorBlob>(android::C2PlatformAllocatorStore::BLOB);
+ } else {
+ allocator = std::make_unique<C2AllocatorIon>(android::C2PlatformAllocatorStore::ION);
+ }
+ return allocator;
+ }();
+
+ if (sAllocator == nullptr)
+ return nullptr;
+
+ bool isValidHandle = false;
+ if (sAllocator->getId() == android::C2PlatformAllocatorStore::BLOB) {
+ isValidHandle = C2AllocatorBlob::isValid(handle);
+ } else {
+ isValidHandle = C2AllocatorIon::isValid(handle);
+ }
std::shared_ptr<C2LinearAllocation> alloc;
- if (C2AllocatorIon::isValid(handle)) {
+ if (isValidHandle) {
c2_status_t err = sAllocator->priorLinearAllocation(handle, &alloc);
if (err == C2_OK) {
std::shared_ptr<C2LinearBlock> block = _C2BlockFactory::CreateLinearBlock(alloc);
@@ -409,10 +431,29 @@
std::shared_ptr<C2LinearBlock> _C2BlockFactory::CreateLinearBlock(
const C2Handle *cHandle, const std::shared_ptr<BufferPoolData> &data) {
// TODO: get proper allocator? and mutex?
- static std::unique_ptr<C2AllocatorIon> sAllocator = std::make_unique<C2AllocatorIon>(0);
+ static std::unique_ptr<C2Allocator> sAllocator = []{
+ std::unique_ptr<C2Allocator> allocator;
+ if (android::GetPreferredLinearAllocatorId(android::GetCodec2PoolMask()) ==
+ android::C2PlatformAllocatorStore::BLOB) {
+ allocator = std::make_unique<C2AllocatorBlob>(android::C2PlatformAllocatorStore::BLOB);
+ } else {
+ allocator = std::make_unique<C2AllocatorIon>(android::C2PlatformAllocatorStore::ION);
+ }
+ return allocator;
+ }();
+
+ if (sAllocator == nullptr)
+ return nullptr;
+
+ bool isValidHandle = false;
+ if (sAllocator->getId() == android::C2PlatformAllocatorStore::BLOB) {
+ isValidHandle = C2AllocatorBlob::isValid(cHandle);
+ } else {
+ isValidHandle = C2AllocatorIon::isValid(cHandle);
+ }
std::shared_ptr<C2LinearAllocation> alloc;
- if (C2AllocatorIon::isValid(cHandle)) {
+ if (isValidHandle) {
c2_status_t err = sAllocator->priorLinearAllocation(cHandle, &alloc);
const std::shared_ptr<C2PooledBlockPoolData> poolData =
std::make_shared<C2PooledBlockPoolData>(data);
diff --git a/media/codec2/vndk/C2Store.cpp b/media/codec2/vndk/C2Store.cpp
index 5b2bd7b..d16527e 100644
--- a/media/codec2/vndk/C2Store.cpp
+++ b/media/codec2/vndk/C2Store.cpp
@@ -18,6 +18,7 @@
#define LOG_NDEBUG 0
#include <utils/Log.h>
+#include <C2AllocatorBlob.h>
#include <C2AllocatorGralloc.h>
#include <C2AllocatorIon.h>
#include <C2BufferPriv.h>
@@ -26,6 +27,7 @@
#include <C2Config.h>
#include <C2PlatformStorePluginLoader.h>
#include <C2PlatformSupport.h>
+#include <cutils/properties.h>
#include <util/C2InterfaceHelper.h>
#include <dlfcn.h>
@@ -35,6 +37,10 @@
#include <memory>
#include <mutex>
+#ifdef __ANDROID_APEX__
+#include <android-base/properties.h>
+#endif
+
namespace android {
/**
@@ -71,6 +77,9 @@
~C2PlatformAllocatorStoreImpl() override = default;
private:
+ /// returns a shared-singleton blob allocator (gralloc-backed)
+ std::shared_ptr<C2Allocator> fetchBlobAllocator();
+
/// returns a shared-singleton ion allocator
std::shared_ptr<C2Allocator> fetchIonAllocator();
@@ -93,10 +102,12 @@
c2_status_t C2PlatformAllocatorStoreImpl::fetchAllocator(
id_t id, std::shared_ptr<C2Allocator> *const allocator) {
allocator->reset();
+ if (id == C2AllocatorStore::DEFAULT_LINEAR) {
+ id = GetPreferredLinearAllocatorId(GetCodec2PoolMask());
+ }
switch (id) {
// TODO: should we implement a generic registry for all, and use that?
case C2PlatformAllocatorStore::ION:
- case C2AllocatorStore::DEFAULT_LINEAR:
*allocator = fetchIonAllocator();
break;
@@ -109,6 +120,10 @@
*allocator = fetchBufferQueueAllocator();
break;
+ case C2PlatformAllocatorStore::BLOB:
+ *allocator = fetchBlobAllocator();
+ break;
+
default:
// Try to create allocator from platform store plugins.
c2_status_t res =
@@ -218,6 +233,18 @@
return allocator;
}
+std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchBlobAllocator() {
+ static std::mutex mutex;
+ static std::weak_ptr<C2Allocator> blobAllocator;
+ std::lock_guard<std::mutex> lock(mutex);
+ std::shared_ptr<C2Allocator> allocator = blobAllocator.lock();
+ if (allocator == nullptr) {
+ allocator = std::make_shared<C2AllocatorBlob>(C2PlatformAllocatorStore::BLOB);
+ blobAllocator = allocator;
+ }
+ return allocator;
+}
+
std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchGrallocAllocator() {
static std::mutex mutex;
static std::weak_ptr<C2Allocator> grallocAllocator;
@@ -288,6 +315,18 @@
return gPreferredComponentStore ? gPreferredComponentStore : GetCodec2PlatformComponentStore();
}
+int GetCodec2PoolMask() {
+ return property_get_int32(
+ "debug.stagefright.c2-poolmask",
+ 1 << C2PlatformAllocatorStore::ION |
+ 1 << C2PlatformAllocatorStore::BUFFERQUEUE);
+}
+
+C2PlatformAllocatorStore::id_t GetPreferredLinearAllocatorId(int poolMask) {
+ return ((poolMask >> C2PlatformAllocatorStore::BLOB) & 1) ? C2PlatformAllocatorStore::BLOB
+ : C2PlatformAllocatorStore::ION;
+}
+
namespace {
class _C2BlockPoolCache {
@@ -304,11 +343,25 @@
std::shared_ptr<C2Allocator> allocator;
c2_status_t res = C2_NOT_FOUND;
+ if (allocatorId == C2AllocatorStore::DEFAULT_LINEAR) {
+ allocatorId = GetPreferredLinearAllocatorId(GetCodec2PoolMask());
+ }
switch(allocatorId) {
case C2PlatformAllocatorStore::ION:
- case C2AllocatorStore::DEFAULT_LINEAR:
res = allocatorStore->fetchAllocator(
- C2AllocatorStore::DEFAULT_LINEAR, &allocator);
+ C2PlatformAllocatorStore::ION, &allocator);
+ if (res == C2_OK) {
+ std::shared_ptr<C2BlockPool> ptr =
+ std::make_shared<C2PooledBlockPool>(
+ allocator, poolId);
+ *pool = ptr;
+ mBlockPools[poolId] = ptr;
+ mComponents[poolId] = component;
+ }
+ break;
+ case C2PlatformAllocatorStore::BLOB:
+ res = allocatorStore->fetchAllocator(
+ C2PlatformAllocatorStore::BLOB, &allocator);
if (res == C2_OK) {
std::shared_ptr<C2BlockPool> ptr =
std::make_shared<C2PooledBlockPool>(
@@ -599,9 +652,33 @@
struct Setter {
static C2R setIonUsage(bool /* mayBlock */, C2P<C2StoreIonUsageInfo> &me) {
+#ifdef __ANDROID_APEX__
+ static int32_t defaultHeapMask = [] {
+ int32_t heapmask = base::GetIntProperty(
+ "ro.com.android.media.swcodec.ion.heapmask", int32_t(0xFFFFFFFF));
+ ALOGD("Default ION heapmask = %d", heapmask);
+ return heapmask;
+ }();
+ static int32_t defaultFlags = [] {
+ int32_t flags = base::GetIntProperty(
+ "ro.com.android.media.swcodec.ion.flags", 0);
+ ALOGD("Default ION flags = %d", flags);
+ return flags;
+ }();
+ static uint32_t defaultAlign = [] {
+ uint32_t align = base::GetUintProperty(
+ "ro.com.android.media.swcodec.ion.align", 0u);
+ ALOGD("Default ION align = %d", align);
+ return align;
+ }();
+ me.set().heapMask = defaultHeapMask;
+ me.set().allocFlags = defaultFlags;
+ me.set().minAlignment = defaultAlign;
+#else
me.set().heapMask = ~0;
me.set().allocFlags = 0;
me.set().minAlignment = 0;
+#endif
return C2R::Ok();
}
};
diff --git a/media/codec2/vndk/include/C2PlatformSupport.h b/media/codec2/vndk/include/C2PlatformSupport.h
index f31282c..a14e0d3 100644
--- a/media/codec2/vndk/include/C2PlatformSupport.h
+++ b/media/codec2/vndk/include/C2PlatformSupport.h
@@ -66,6 +66,15 @@
BUFFERQUEUE,
/**
+ * ID of the gralloc backed platform allocator for linear blob buffer.
+ *
+ * C2Handle layout is not public. Use C2AllocatorGralloc::UnwrapNativeCodec2GrallocHandle
+ * to get the underlying gralloc handle from a C2Handle, and WrapNativeCodec2GrallocHandle
+ * to create a C2Handle from a gralloc handle - for C2Allocator::priorAllocation.
+ */
+ BLOB,
+
+ /**
* ID of indicating the end of platform allocator definition.
*
* \note always put this macro in the last place.
@@ -131,6 +140,20 @@
*/
void SetPreferredCodec2ComponentStore(std::shared_ptr<C2ComponentStore> store);
+/**
+ * Returns the pool mask.
+ * \retval the default pool mask should be adopted if it could not be obtained from property
+ * "debug.stagefright.c2-poolmask"
+ */
+int GetCodec2PoolMask();
+
+/**
+ * Returns the preferred linear buffer allocator id from param poolMask.
+ * C2PlatformAllocatorStore::ION should be chosen as fallback allocator if BLOB is not enabled from
+ * param poolMask.
+ */
+C2PlatformAllocatorStore::id_t GetPreferredLinearAllocatorId(int poolMask);
+
} // namespace android
#endif // STAGEFRIGHT_CODEC2_PLATFORM_SUPPORT_H_
diff --git a/media/extractors/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index 4012ece..bfb2deb 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -635,7 +635,8 @@
currentPageSamples -= mStartGranulePosition;
AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_VALID_SAMPLES, currentPageSamples);
}
- mCurGranulePosition = mCurrentPage.mGranulePosition - currentPageSamples;
+ (void) __builtin_sub_overflow(mCurrentPage.mGranulePosition, currentPageSamples,
+ &mCurGranulePosition);
}
int64_t timeUs = getTimeUsOfGranule(mCurGranulePosition);
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
index 463f606..baada22 100644
--- a/media/libaaudio/src/Android.bp
+++ b/media/libaaudio/src/Android.bp
@@ -54,6 +54,10 @@
},
},
+ stubs: {
+ symbol_file: "libaaudio.map.txt",
+ versions: ["28"],
+ },
}
cc_library {
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 308e9d3..97155e4 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -409,7 +409,7 @@
// Thus the IAudioFlingerClient must be a singleton per process.
virtual void registerClient(const sp<IAudioFlingerClient>& client) = 0;
- // retrieve the audio recording buffer size
+ // retrieve the audio recording buffer size in bytes
// FIXME This API assumes a route, and so should be deprecated.
virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format,
audio_channel_mask_t channelMask) const = 0;
diff --git a/media/libdatasource/include/datasource/HTTPBase.h b/media/libdatasource/include/datasource/HTTPBase.h
index 8b20187..656e85e 100644
--- a/media/libdatasource/include/datasource/HTTPBase.h
+++ b/media/libdatasource/include/datasource/HTTPBase.h
@@ -21,6 +21,7 @@
#include <media/DataSource.h>
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/MediaErrors.h>
+#include <utils/KeyedVector.h>
#include <utils/List.h>
#include <utils/threads.h>
diff --git a/media/libheif/HeifDecoderImpl.cpp b/media/libheif/HeifDecoderImpl.cpp
index b80f4b4..9d79f89 100644
--- a/media/libheif/HeifDecoderImpl.cpp
+++ b/media/libheif/HeifDecoderImpl.cpp
@@ -21,10 +21,10 @@
#include <stdio.h>
+#include <android/IDataSource.h>
#include <binder/IMemory.h>
#include <binder/MemoryDealer.h>
#include <drm/drm_framework_common.h>
-#include <media/IDataSource.h>
#include <media/mediametadataretriever.h>
#include <media/MediaSource.h>
#include <media/stagefright/foundation/ADebug.h>
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index b064f08..e8ff463 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -23,6 +23,14 @@
path: "aidl",
}
+filegroup {
+ name: "mediaextractorservice_aidl",
+ srcs: [
+ "aidl/android/IMediaExtractorService.aidl",
+ ],
+ path: "aidl",
+}
+
aidl_interface {
name: "resourcemanager_aidl_interface",
local_include_dir: "aidl",
@@ -249,13 +257,13 @@
name: "libmedia",
srcs: [
+ ":mediaextractorservice_aidl",
"IDataSource.cpp",
"BufferingSettings.cpp",
"mediaplayer.cpp",
"IMediaHTTPConnection.cpp",
"IMediaHTTPService.cpp",
"IMediaExtractor.cpp",
- "IMediaExtractorService.cpp",
"IMediaPlayerService.cpp",
"IMediaPlayerClient.cpp",
"IMediaRecorderClient.cpp",
@@ -305,6 +313,7 @@
"libprocessgroup",
"libutils",
"libbinder",
+ "libbinder_ndk",
"libsonivox",
"libandroidicu",
"libexpat",
@@ -327,11 +336,11 @@
static_libs: [
"libc_malloc_debug_backtrace", // for memory heap analysis
- "resourcemanager_aidl_interface-unstable-cpp",
+ "resourcemanager_aidl_interface-ndk_platform",
],
export_static_lib_headers: [
- "resourcemanager_aidl_interface-unstable-cpp",
+ "resourcemanager_aidl_interface-ndk_platform",
],
export_include_dirs: [
diff --git a/media/libmedia/IDataSource.cpp b/media/libmedia/IDataSource.cpp
index 61f0a68..e96a113 100644
--- a/media/libmedia/IDataSource.cpp
+++ b/media/libmedia/IDataSource.cpp
@@ -19,8 +19,7 @@
#include <utils/Log.h>
#include <utils/Timers.h>
-#include <media/IDataSource.h>
-
+#include <android/IDataSource.h>
#include <binder/IMemory.h>
#include <binder/Parcel.h>
#include <media/stagefright/foundation/ADebug.h>
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
index fb6d3a2..7389851 100644
--- a/media/libmedia/IMediaExtractor.cpp
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -25,7 +25,7 @@
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
#include <binder/PermissionCache.h>
-#include <media/IMediaExtractor.h>
+#include <android/IMediaExtractor.h>
#include <media/stagefright/MetaData.h>
namespace android {
diff --git a/media/libmedia/IMediaExtractorService.cpp b/media/libmedia/IMediaExtractorService.cpp
deleted file mode 100644
index 243b09d..0000000
--- a/media/libmedia/IMediaExtractorService.cpp
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
-**
-** Copyright 2007, 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 "IMediaExtractorService"
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <binder/Parcel.h>
-#include <media/IMediaExtractorService.h>
-
-namespace android {
-
-enum {
- MAKE_EXTRACTOR = IBinder::FIRST_CALL_TRANSACTION,
- MAKE_IDATA_SOURCE_FD,
- GET_SUPPORTED_TYPES,
-};
-
-class BpMediaExtractorService : public BpInterface<IMediaExtractorService>
-{
-public:
- explicit BpMediaExtractorService(const sp<IBinder>& impl)
- : BpInterface<IMediaExtractorService>(impl)
- {
- }
-
- virtual sp<IMediaExtractor> makeExtractor(const sp<IDataSource> &source, const char *mime) {
- Parcel data, reply;
- data.writeInterfaceToken(IMediaExtractorService::getInterfaceDescriptor());
- data.writeStrongBinder(IInterface::asBinder(source));
- if (mime != NULL) {
- data.writeCString(mime);
- }
- status_t ret = remote()->transact(MAKE_EXTRACTOR, data, &reply);
- if (ret == NO_ERROR) {
- return interface_cast<IMediaExtractor>(reply.readStrongBinder());
- }
- return NULL;
- }
-
- virtual sp<IDataSource> makeIDataSource(int fd, int64_t offset, int64_t length)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IMediaExtractorService::getInterfaceDescriptor());
- data.writeFileDescriptor(fd);
- data.writeInt64(offset);
- data.writeInt64(length);
- status_t ret = remote()->transact(MAKE_IDATA_SOURCE_FD, data, &reply);
- ALOGV("fd:%d offset:%lld length:%lld ret:%d",
- fd, (long long)offset, (long long)length, ret);
- if (ret == NO_ERROR) {
- return interface_cast<IDataSource>(reply.readStrongBinder());
- }
- return nullptr;
- }
-
- virtual std::unordered_set<std::string> getSupportedTypes() {
- std::unordered_set<std::string> supportedTypes;
- Parcel data, reply;
- data.writeInterfaceToken(IMediaExtractorService::getInterfaceDescriptor());
- status_t ret = remote()->transact(GET_SUPPORTED_TYPES, data, &reply);
- if (ret == NO_ERROR) {
- // process reply
- while(true) {
- const char *ext = reply.readCString();
- if (!ext) {
- break;
- }
- supportedTypes.insert(std::string(ext));
- }
- }
- return supportedTypes;
- }
-};
-
-IMPLEMENT_META_INTERFACE(MediaExtractorService, "android.media.IMediaExtractorService");
-
-// ----------------------------------------------------------------------
-
-status_t BnMediaExtractorService::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch (code) {
-
- case MAKE_EXTRACTOR: {
- CHECK_INTERFACE(IMediaExtractorService, data, reply);
- sp<IBinder> b;
- status_t ret = data.readStrongBinder(&b);
- if (ret != NO_ERROR || b == NULL) {
- ALOGE("Error reading source from parcel");
- return ret;
- }
- // If we make an extractor through Binder, enabled shared memory
- // for MediaBuffers for this process.
- MediaBuffer::useSharedMemory();
- sp<IDataSource> source = interface_cast<IDataSource>(b);
- const char *mime = data.readCString();
- sp<IMediaExtractor> ex = makeExtractor(source, mime);
- reply->writeStrongBinder(IInterface::asBinder(ex));
- return NO_ERROR;
- }
-
- case MAKE_IDATA_SOURCE_FD: {
- CHECK_INTERFACE(IMediaExtractorService, data, reply);
- const int fd = dup(data.readFileDescriptor()); // -1 fd checked in makeIDataSource
- const int64_t offset = data.readInt64();
- const int64_t length = data.readInt64();
- ALOGV("fd %d offset%lld length:%lld", fd, (long long)offset, (long long)length);
- sp<IDataSource> source = makeIDataSource(fd, offset, length);
- reply->writeStrongBinder(IInterface::asBinder(source));
- // The FileSource closes the descriptor, so if it is not created
- // we need to close the descriptor explicitly.
- if (source.get() == nullptr && fd != -1) {
- close(fd);
- }
- return NO_ERROR;
- }
-
- case GET_SUPPORTED_TYPES:
- {
- CHECK_INTERFACE(IMediaExtractorService, data, reply);
- std::unordered_set<std::string> supportedTypes = getSupportedTypes();
- for (auto it = supportedTypes.begin(); it != supportedTypes.end(); ++it) {
- reply->writeCString((*it).c_str());
- }
- return NO_ERROR;
- }
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-// ----------------------------------------------------------------------------
-
-} // namespace android
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index d95bc8e..8a3b84e 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -19,8 +19,8 @@
#include <stdint.h>
#include <sys/types.h>
+#include <android/IDataSource.h>
#include <binder/Parcel.h>
-#include <media/IDataSource.h>
#include <media/IMediaHTTPService.h>
#include <media/IMediaMetadataRetriever.h>
#include <processgroup/sched_policy.h>
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index ea06665..20bc23d 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -19,18 +19,15 @@
#include <stdint.h>
#include <sys/types.h>
+#include <android/IDataSource.h>
#include <binder/Parcel.h>
-
+#include <gui/IGraphicBufferProducer.h>
#include <media/AudioResamplerPublic.h>
#include <media/AVSyncSettings.h>
#include <media/BufferingSettings.h>
-
-#include <media/IDataSource.h>
#include <media/IMediaHTTPService.h>
#include <media/IMediaPlayer.h>
#include <media/IStreamSource.h>
-
-#include <gui/IGraphicBufferProducer.h>
#include <utils/String8.h>
namespace android {
diff --git a/media/libmedia/MediaResource.cpp b/media/libmedia/MediaResource.cpp
index fe86d27..0936a99 100644
--- a/media/libmedia/MediaResource.cpp
+++ b/media/libmedia/MediaResource.cpp
@@ -35,7 +35,7 @@
this->value = value;
}
-MediaResource::MediaResource(Type type, const std::vector<uint8_t> &id, int64_t value) {
+MediaResource::MediaResource(Type type, const std::vector<int8_t> &id, int64_t value) {
this->type = type;
this->subType = SubType::kUnspecifiedSubType;
this->id = id;
@@ -66,11 +66,11 @@
}
//static
-MediaResource MediaResource::DrmSessionResource(const std::vector<uint8_t> &id, int64_t value) {
+MediaResource MediaResource::DrmSessionResource(const std::vector<int8_t> &id, int64_t value) {
return MediaResource(Type::kDrmSession, id, value);
}
-static String8 bytesToHexString(const std::vector<uint8_t> &bytes) {
+static String8 bytesToHexString(const std::vector<int8_t> &bytes) {
String8 str;
for (auto &b : bytes) {
str.appendFormat("%02x", b);
diff --git a/media/libmedia/MediaResourcePolicy.cpp b/media/libmedia/MediaResourcePolicy.cpp
index c463179..afa971d 100644
--- a/media/libmedia/MediaResourcePolicy.cpp
+++ b/media/libmedia/MediaResourcePolicy.cpp
@@ -16,20 +16,21 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "MediaResourcePolicy"
-#include <utils/Log.h>
+
+#include <aidl/android/media/IResourceManagerService.h>
#include <media/MediaResourcePolicy.h>
-#include <android/media/IResourceManagerService.h>
+#include <utils/Log.h>
namespace android {
-using android::media::IResourceManagerService;
+using aidl::android::media::IResourceManagerService;
//static
-const ::std::string& MediaResourcePolicy::kPolicySupportsMultipleSecureCodecs() {
- return IResourceManagerService::kPolicySupportsMultipleSecureCodecs();
+const char* MediaResourcePolicy::kPolicySupportsMultipleSecureCodecs() {
+ return IResourceManagerService::kPolicySupportsMultipleSecureCodecs;
}
//static
-const ::std::string& MediaResourcePolicy::kPolicySupportsSecureWithNonSecureCodec() {
- return IResourceManagerService::kPolicySupportsSecureWithNonSecureCodec();
+const char* MediaResourcePolicy::kPolicySupportsSecureWithNonSecureCodec() {
+ return IResourceManagerService::kPolicySupportsSecureWithNonSecureCodec;
}
MediaResourcePolicy::MediaResourcePolicy(
diff --git a/media/libmedia/aidl/android/IDataSource.aidl b/media/libmedia/aidl/android/IDataSource.aidl
new file mode 100644
index 0000000..fb954bf
--- /dev/null
+++ b/media/libmedia/aidl/android/IDataSource.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android;
+
+/** @hide */
+interface IDataSource {
+ // Stub for manual implementation
+}
diff --git a/media/libmedia/aidl/android/IMediaExtractor.aidl b/media/libmedia/aidl/android/IMediaExtractor.aidl
new file mode 100644
index 0000000..5ba68e6
--- /dev/null
+++ b/media/libmedia/aidl/android/IMediaExtractor.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android;
+
+/** @hide */
+interface IMediaExtractor {
+ // Stub for manual implementation
+}
diff --git a/media/libmedia/aidl/android/IMediaExtractorService.aidl b/media/libmedia/aidl/android/IMediaExtractorService.aidl
new file mode 100644
index 0000000..c57fa16
--- /dev/null
+++ b/media/libmedia/aidl/android/IMediaExtractorService.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android;
+
+import android.IDataSource;
+import android.IMediaExtractor;
+
+/**
+ * Binder interface for the media extractor service
+ *
+ * @hide
+ */
+interface IMediaExtractorService {
+
+ IMediaExtractor makeExtractor(IDataSource source, @nullable @utf8InCpp String mime);
+ IDataSource makeIDataSource(in FileDescriptor fd, long offset, long length);
+ @utf8InCpp String[] getSupportedTypes();
+}
diff --git a/media/libmedia/include/media/IDataSource.h b/media/libmedia/include/android/IDataSource.h
similarity index 100%
rename from media/libmedia/include/media/IDataSource.h
rename to media/libmedia/include/android/IDataSource.h
diff --git a/media/libmedia/include/media/IMediaExtractor.h b/media/libmedia/include/android/IMediaExtractor.h
similarity index 100%
rename from media/libmedia/include/media/IMediaExtractor.h
rename to media/libmedia/include/android/IMediaExtractor.h
diff --git a/media/libmedia/include/media/IMediaExtractorService.h b/media/libmedia/include/media/IMediaExtractorService.h
deleted file mode 100644
index 5ce2cdb..0000000
--- a/media/libmedia/include/media/IMediaExtractorService.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2013 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_IMEDIAEXTRACTORSERVICE_H
-#define ANDROID_IMEDIAEXTRACTORSERVICE_H
-
-#include <unordered_set>
-
-#include <binder/IInterface.h>
-#include <binder/IMemory.h>
-#include <binder/Parcel.h>
-#include <media/IDataSource.h>
-#include <media/IMediaExtractor.h>
-
-namespace android {
-
-class IMediaExtractorService: public IInterface
-{
-public:
- DECLARE_META_INTERFACE(MediaExtractorService);
-
- virtual sp<IMediaExtractor> makeExtractor(const sp<IDataSource> &source, const char *mime) = 0;
-
- virtual sp<IDataSource> makeIDataSource(int fd, int64_t offset, int64_t length) = 0;
-
- virtual std::unordered_set<std::string> getSupportedTypes() = 0;
-};
-
-class BnMediaExtractorService: public BnInterface<IMediaExtractorService>
-{
-public:
- virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
- uint32_t flags = 0);
-};
-
-} // namespace android
-
-#endif // ANDROID_IMEDIAEXTRACTORSERVICE_H
diff --git a/media/libmedia/include/media/MediaResource.h b/media/libmedia/include/media/MediaResource.h
index caf03b1..e7362c1 100644
--- a/media/libmedia/include/media/MediaResource.h
+++ b/media/libmedia/include/media/MediaResource.h
@@ -18,13 +18,14 @@
#ifndef ANDROID_MEDIA_RESOURCE_H
#define ANDROID_MEDIA_RESOURCE_H
-#include <android/media/MediaResourceParcel.h>
+#include <aidl/android/media/MediaResourceParcel.h>
+#include <utils/String8.h>
namespace android {
-using android::media::MediaResourceParcel;
-using android::media::MediaResourceSubType;
-using android::media::MediaResourceType;
+using aidl::android::media::MediaResourceParcel;
+using aidl::android::media::MediaResourceSubType;
+using aidl::android::media::MediaResourceType;
class MediaResource : public MediaResourceParcel {
public:
@@ -34,13 +35,13 @@
MediaResource() = delete;
MediaResource(Type type, int64_t value);
MediaResource(Type type, SubType subType, int64_t value);
- MediaResource(Type type, const std::vector<uint8_t> &id, int64_t value);
+ MediaResource(Type type, const std::vector<int8_t> &id, int64_t value);
static MediaResource CodecResource(bool secure, bool video);
static MediaResource GraphicMemoryResource(int64_t value);
static MediaResource CpuBoostResource();
static MediaResource VideoBatteryResource();
- static MediaResource DrmSessionResource(const std::vector<uint8_t> &id, int64_t value);
+ static MediaResource DrmSessionResource(const std::vector<int8_t> &id, int64_t value);
};
inline static const char *asString(MediaResource::Type i, const char *def = "??") {
diff --git a/media/libmedia/include/media/MediaResourcePolicy.h b/media/libmedia/include/media/MediaResourcePolicy.h
index 7ae1a73..052395b 100644
--- a/media/libmedia/include/media/MediaResourcePolicy.h
+++ b/media/libmedia/include/media/MediaResourcePolicy.h
@@ -18,19 +18,20 @@
#ifndef ANDROID_MEDIA_RESOURCE_POLICY_H
#define ANDROID_MEDIA_RESOURCE_POLICY_H
-#include <android/media/MediaResourcePolicyParcel.h>
+#include <aidl/android/media/MediaResourcePolicyParcel.h>
+#include <utils/String8.h>
namespace android {
-using media::MediaResourcePolicyParcel;
+using aidl::android::media::MediaResourcePolicyParcel;
class MediaResourcePolicy : public MediaResourcePolicyParcel {
public:
MediaResourcePolicy() = delete;
MediaResourcePolicy(const std::string& type, const std::string& value);
- static const ::std::string& kPolicySupportsMultipleSecureCodecs();
- static const ::std::string& kPolicySupportsSecureWithNonSecureCodec();
+ static const char* kPolicySupportsMultipleSecureCodecs();
+ static const char* kPolicySupportsSecureWithNonSecureCodec();
};
String8 toString(const MediaResourcePolicyParcel &policy);
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 26908e5..60d2f85 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -17,6 +17,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "MediaPlayerNative"
+#include <utils/Log.h>
#include <fcntl.h>
#include <inttypes.h>
@@ -24,25 +25,15 @@
#include <sys/types.h>
#include <unistd.h>
-#include <utils/Log.h>
-#include <binder/IServiceManager.h>
+#include <android/IDataSource.h>
#include <binder/IPCThreadState.h>
-
-#include <gui/Surface.h>
-
#include <media/mediaplayer.h>
#include <media/AudioResamplerPublic.h>
#include <media/AudioSystem.h>
#include <media/AVSyncSettings.h>
-#include <media/IDataSource.h>
-#include <media/MediaAnalyticsItem.h>
-
-#include <binder/MemoryBase.h>
-
#include <utils/KeyedVector.h>
#include <utils/String8.h>
-
#include <system/audio.h>
#include <system/window.h>
diff --git a/media/libmediametrics/IMediaAnalyticsService.cpp b/media/libmediametrics/IMediaAnalyticsService.cpp
index 4324f6d..534aece 100644
--- a/media/libmediametrics/IMediaAnalyticsService.cpp
+++ b/media/libmediametrics/IMediaAnalyticsService.cpp
@@ -34,8 +34,11 @@
namespace android {
+// TODO: Currently ONE_WAY transactions, make both ONE_WAY and synchronous options.
+
enum {
- SUBMIT_ITEM_ONEWAY = IBinder::FIRST_CALL_TRANSACTION,
+ SUBMIT_ITEM = IBinder::FIRST_CALL_TRANSACTION,
+ SUBMIT_BUFFER,
};
class BpMediaAnalyticsService: public BpInterface<IMediaAnalyticsService>
@@ -62,7 +65,30 @@
}
status = remote()->transact(
- SUBMIT_ITEM_ONEWAY, data, nullptr /* reply */, IBinder::FLAG_ONEWAY);
+ SUBMIT_ITEM, data, nullptr /* reply */, IBinder::FLAG_ONEWAY);
+ ALOGW_IF(status != NO_ERROR, "%s: bad response from service for submit, status=%d",
+ __func__, status);
+ return status;
+ }
+
+ status_t submitBuffer(const char *buffer, size_t length) override
+ {
+ if (buffer == nullptr || length > INT32_MAX) {
+ return BAD_VALUE;
+ }
+ ALOGV("%s: (ONEWAY) length:%zu", __func__, length);
+
+ Parcel data;
+ data.writeInterfaceToken(IMediaAnalyticsService::getInterfaceDescriptor());
+
+ status_t status = data.writeInt32(length)
+ ?: data.write((uint8_t*)buffer, length);
+ if (status != NO_ERROR) {
+ return status;
+ }
+
+ status = remote()->transact(
+ SUBMIT_BUFFER, data, nullptr /* reply */, IBinder::FLAG_ONEWAY);
ALOGW_IF(status != NO_ERROR, "%s: bad response from service for submit, status=%d",
__func__, status);
return status;
@@ -76,10 +102,8 @@
status_t BnMediaAnalyticsService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
- const int clientPid = IPCThreadState::self()->getCallingPid();
-
switch (code) {
- case SUBMIT_ITEM_ONEWAY: {
+ case SUBMIT_ITEM: {
CHECK_INTERFACE(IMediaAnalyticsService, data, reply);
MediaAnalyticsItem * const item = MediaAnalyticsItem::create();
@@ -87,12 +111,25 @@
if (status != NO_ERROR) { // assume failure logged in item
return status;
}
- // TODO: remove this setPid.
- item->setPid(clientPid);
status = submitInternal(item, true /* release */);
// assume failure logged by submitInternal
return NO_ERROR;
- } break;
+ }
+ case SUBMIT_BUFFER: {
+ CHECK_INTERFACE(IMediaAnalyticsService, data, reply);
+ int32_t length;
+ status_t status = data.readInt32(&length);
+ if (status != NO_ERROR || length <= 0) {
+ return BAD_VALUE;
+ }
+ const void *ptr = data.readInplace(length);
+ if (ptr == nullptr) {
+ return BAD_VALUE;
+ }
+ status = submitBuffer(static_cast<const char *>(ptr), length);
+ // assume failure logged by submitBuffer
+ return NO_ERROR;
+ }
default:
return BBinder::onTransact(code, data, reply, flags);
diff --git a/media/libmediametrics/MediaAnalyticsItem.cpp b/media/libmediametrics/MediaAnalyticsItem.cpp
index 14dce79..8025e49 100644
--- a/media/libmediametrics/MediaAnalyticsItem.cpp
+++ b/media/libmediametrics/MediaAnalyticsItem.cpp
@@ -35,6 +35,10 @@
#include <media/MediaAnalyticsItem.h>
#include <private/android_filesystem_config.h>
+// Max per-property string size before truncation in toString().
+// Do not make too large, as this is used for dumpsys purposes.
+static constexpr size_t kMaxPropertyStringSize = 4096;
+
namespace android {
#define DEBUG_SERVICEACCESS 0
@@ -367,70 +371,18 @@
}
std::string MediaAnalyticsItem::toString(int version) const {
-
- // v0 : released with 'o'
- // v1 : bug fix (missing pid/finalized separator),
- // adds apk name, apk version code
-
- if (version <= PROTO_FIRST) {
- // default to original v0 format, until proper parsers are in place
- version = PROTO_V0;
- } else if (version > PROTO_LAST) {
- version = PROTO_LAST;
- }
-
std::string result;
- char buffer[512];
+ char buffer[kMaxPropertyStringSize];
- if (version == PROTO_V0) {
- result = "(";
- } else {
- snprintf(buffer, sizeof(buffer), "[%d:", version);
- result.append(buffer);
- }
-
- // same order as we spill into the parcel, although not required
- // key+session are our primary matching criteria
- result.append(mKey.c_str());
- result.append(":0:"); // sessionID
-
- snprintf(buffer, sizeof(buffer), "%d:", mUid);
+ snprintf(buffer, sizeof(buffer), "[%d:%s:%d:%d:%lld:%s:%zu:",
+ version, mKey.c_str(), mPid, mUid, (long long)mTimestamp,
+ mPkgName.c_str(), mPropCount);
result.append(buffer);
-
- if (version >= PROTO_V1) {
- result.append(mPkgName);
- snprintf(buffer, sizeof(buffer), ":%" PRId64 ":", mPkgVersionCode);
- result.append(buffer);
- }
-
- // in 'o' (v1) , the separator between pid and finalized was omitted
- if (version <= PROTO_V0) {
- snprintf(buffer, sizeof(buffer), "%d", mPid);
- } else {
- snprintf(buffer, sizeof(buffer), "%d:", mPid);
- }
- result.append(buffer);
-
- snprintf(buffer, sizeof(buffer), "%d:", 0 /* finalized */); // TODO: remove this.
- result.append(buffer);
- snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mTimestamp);
- result.append(buffer);
-
- // set of items
- int count = mPropCount;
- snprintf(buffer, sizeof(buffer), "%d:", count);
- result.append(buffer);
- for (int i = 0 ; i < count; i++ ) {
+ for (size_t i = 0 ; i < mPropCount; ++i) {
mProps[i].toString(buffer, sizeof(buffer));
result.append(buffer);
}
-
- if (version == PROTO_V0) {
- result.append(")");
- } else {
- result.append("]");
- }
-
+ result.append("]");
return result;
}
@@ -451,8 +403,9 @@
}
}
+namespace mediametrics {
//static
-bool MediaAnalyticsItem::isEnabled() {
+bool BaseItem::isEnabled() {
// completely skip logging from certain UIDs. We do this here
// to avoid the multi-second timeouts while we learn that
// sepolicy will not let us find the service.
@@ -481,25 +434,47 @@
class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
virtual void binderDied(const wp<IBinder> &) {
ALOGW("Reacquire service connection on next request");
- MediaAnalyticsItem::dropInstance();
+ BaseItem::dropInstance();
}
};
static sp<MediaMetricsDeathNotifier> sNotifier;
// static
-sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
+sp<IMediaAnalyticsService> BaseItem::sAnalyticsService;
static std::mutex sServiceMutex;
static int sRemainingBindAttempts = SVC_TRIES;
// static
-void MediaAnalyticsItem::dropInstance() {
+void BaseItem::dropInstance() {
std::lock_guard _l(sServiceMutex);
sRemainingBindAttempts = SVC_TRIES;
sAnalyticsService = nullptr;
}
+// static
+bool BaseItem::submitBuffer(const char *buffer, size_t size) {
+/*
+ MediaAnalyticsItem item;
+ status_t status = item.readFromByteString(buffer, size);
+ ALOGD("%s: status:%d, size:%zu, item:%s", __func__, status, size, item.toString().c_str());
+ return item.selfrecord();
+ */
+
+ ALOGD_IF(DEBUG_API, "%s: delivering %zu bytes", __func__, size);
+ sp<IMediaAnalyticsService> svc = getInstance();
+ if (svc != nullptr) {
+ const status_t status = svc->submitBuffer(buffer, size);
+ if (status != NO_ERROR) {
+ ALOGW("%s: failed(%d) to record: %zu bytes", __func__, status, size);
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
//static
-sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
+sp<IMediaAnalyticsService> BaseItem::getInstance() {
static const char *servicename = "media.metrics";
static const bool enabled = isEnabled(); // singleton initialized
@@ -537,6 +512,8 @@
return sAnalyticsService;
}
+} // namespace mediametrics
+
// merge the info from 'incoming' into this record.
// we finish with a union of this+incoming and special handling for collisions
bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) {
@@ -633,6 +610,7 @@
while (*ptr != 0) {
if (ptr >= bufferptrmax) {
ALOGE("%s: buffer exceeded", __func__);
+ return BAD_VALUE;
}
++ptr;
}
@@ -657,39 +635,41 @@
return INVALID_OPERATION;
}
const uint16_t version = 0;
- const uint32_t header_len =
- sizeof(uint32_t) // overall length
- + sizeof(header_len) // header length
- + sizeof(version) // encoding version
- + sizeof(uint16_t) // key length
+ const uint32_t header_size =
+ sizeof(uint32_t) // total size
+ + sizeof(header_size) // header size
+ + sizeof(version) // encoding version
+ + sizeof(uint16_t) // key size
+ keySizeZeroTerminated // key, zero terminated
- + sizeof(int32_t) // pid
- + sizeof(int32_t) // uid
- + sizeof(int64_t) // timestamp
+ + sizeof(int32_t) // pid
+ + sizeof(int32_t) // uid
+ + sizeof(int64_t) // timestamp
;
- uint32_t len = header_len
+ uint32_t size = header_size
+ sizeof(uint32_t) // # properties
;
for (size_t i = 0 ; i < mPropCount; ++i) {
- const size_t size = mProps[i].getByteStringSize();
- if (size > UINT_MAX - 1) {
- ALOGW("%s: prop %zu has size %zu", __func__, i, size);
+ const size_t propSize = mProps[i].getByteStringSize();
+ if (propSize > UINT16_MAX) {
+ ALOGW("%s: prop %zu size %zu too large", __func__, i, propSize);
return INVALID_OPERATION;
}
- len += size;
+ if (__builtin_add_overflow(size, propSize, &size)) {
+ ALOGW("%s: item size overflow at property %zu", __func__, i);
+ return INVALID_OPERATION;
+ }
}
- // TODO: consider package information and timestamp.
-
- // now that we have a size... let's allocate and fill
- char *build = (char *)calloc(1 /* nmemb */, len);
+ // since we fill every byte in the buffer (there is no padding),
+ // malloc is used here instead of calloc.
+ char * const build = (char *)malloc(size);
if (build == nullptr) return NO_MEMORY;
char *filling = build;
- char *buildmax = build + len;
- if (insert(len, &filling, buildmax) != NO_ERROR
- || insert(header_len, &filling, buildmax) != NO_ERROR
+ char *buildmax = build + size;
+ if (insert((uint32_t)size, &filling, buildmax) != NO_ERROR
+ || insert(header_size, &filling, buildmax) != NO_ERROR
|| insert(version, &filling, buildmax) != NO_ERROR
|| insert((uint16_t)keySizeZeroTerminated, &filling, buildmax) != NO_ERROR
|| insert(mKey.c_str(), &filling, buildmax) != NO_ERROR
@@ -697,26 +677,27 @@
|| insert((int32_t)mUid, &filling, buildmax) != NO_ERROR
|| insert((int64_t)mTimestamp, &filling, buildmax) != NO_ERROR
|| insert((uint32_t)mPropCount, &filling, buildmax) != NO_ERROR) {
- ALOGD("%s:could not write header", __func__);
+ ALOGE("%s:could not write header", __func__); // shouldn't happen
free(build);
return INVALID_OPERATION;
}
for (size_t i = 0 ; i < mPropCount; ++i) {
if (mProps[i].writeToByteString(&filling, buildmax) != NO_ERROR) {
free(build);
- ALOGD("%s:could not write prop %zu of %zu", __func__, i, mPropCount);
+ // shouldn't happen
+ ALOGE("%s:could not write prop %zu of %zu", __func__, i, mPropCount);
return INVALID_OPERATION;
}
}
if (filling != buildmax) {
- ALOGE("problems populating; wrote=%d planned=%d",
- (int)(filling - build), len);
+ ALOGE("%s: problems populating; wrote=%d planned=%d",
+ __func__, (int)(filling - build), (int)size);
free(build);
return INVALID_OPERATION;
}
*pbuffer = build;
- *plength = len;
+ *plength = size;
return NO_ERROR;
}
@@ -727,40 +708,41 @@
const char *read = bufferptr;
const char *readend = bufferptr + length;
- uint32_t len;
- uint32_t header_len;
- int16_t version;
- int16_t key_len;
+ uint32_t size;
+ uint32_t header_size;
+ uint16_t version;
+ uint16_t key_size;
char *key = nullptr;
int32_t pid;
int32_t uid;
int64_t timestamp;
uint32_t propCount;
- if (extract(&len, &read, readend) != NO_ERROR
- || extract(&header_len, &read, readend) != NO_ERROR
+ if (extract(&size, &read, readend) != NO_ERROR
+ || extract(&header_size, &read, readend) != NO_ERROR
|| extract(&version, &read, readend) != NO_ERROR
- || extract(&key_len, &read, readend) != NO_ERROR
+ || extract(&key_size, &read, readend) != NO_ERROR
|| extract(&key, &read, readend) != NO_ERROR
|| extract(&pid, &read, readend) != NO_ERROR
|| extract(&uid, &read, readend) != NO_ERROR
|| extract(×tamp, &read, readend) != NO_ERROR
- || len > length
- || header_len > len) {
+ || size > length
+ || strlen(key) + 1 != key_size
+ || header_size > size) {
free(key);
- ALOGD("%s: invalid header", __func__);
+ ALOGW("%s: invalid header", __func__);
return INVALID_OPERATION;
}
mKey = key;
free(key);
const size_t pos = read - bufferptr;
- if (pos > header_len) {
- ALOGD("%s: invalid header pos:%zu > header_len:%u",
- __func__, pos, header_len);
+ if (pos > header_size) {
+ ALOGW("%s: invalid header pos:%zu > header_size:%u",
+ __func__, pos, header_size);
return INVALID_OPERATION;
- } else if (pos < header_len) {
- ALOGD("%s: mismatched header pos:%zu < header_len:%u, advancing",
- __func__, pos, header_len);
- read += (header_len - pos);
+ } else if (pos < header_size) {
+ ALOGW("%s: mismatched header pos:%zu < header_size:%u, advancing",
+ __func__, pos, header_size);
+ read += (header_size - pos);
}
if (extract(&propCount, &read, readend) != NO_ERROR) {
ALOGD("%s: cannot read prop count", __func__);
@@ -772,7 +754,7 @@
for (size_t i = 0; i < propCount; ++i) {
Prop *prop = allocateProp();
if (prop->readFromByteString(&read, readend) != NO_ERROR) {
- ALOGD("%s: cannot read prop %zu", __func__, i);
+ ALOGW("%s: cannot read prop %zu", __func__, i);
return INVALID_OPERATION;
}
}
@@ -910,8 +892,10 @@
return header + payload;
}
+namespace mediametrics {
+
// TODO: fold into a template later.
-status_t MediaAnalyticsItem::writeToByteString(
+status_t BaseItem::writeToByteString(
const char *name, int32_t value, char **bufferpptr, char *bufferptrmax)
{
const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value);
@@ -922,7 +906,7 @@
?: insert(value, bufferpptr, bufferptrmax);
}
-status_t MediaAnalyticsItem::writeToByteString(
+status_t BaseItem::writeToByteString(
const char *name, int64_t value, char **bufferpptr, char *bufferptrmax)
{
const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value);
@@ -933,7 +917,7 @@
?: insert(value, bufferpptr, bufferptrmax);
}
-status_t MediaAnalyticsItem::writeToByteString(
+status_t BaseItem::writeToByteString(
const char *name, double value, char **bufferpptr, char *bufferptrmax)
{
const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value);
@@ -944,7 +928,7 @@
?: insert(value, bufferpptr, bufferptrmax);
}
-status_t MediaAnalyticsItem::writeToByteString(
+status_t BaseItem::writeToByteString(
const char *name, const std::pair<int64_t, int64_t> &value, char **bufferpptr, char *bufferptrmax)
{
const size_t len = 2 + 1 + strlen(name) + 1 + 8 + 8;
@@ -956,9 +940,15 @@
?: insert(value.second, bufferpptr, bufferptrmax);
}
-status_t MediaAnalyticsItem::writeToByteString(
+status_t BaseItem::writeToByteString(
const char *name, char * const &value, char **bufferpptr, char *bufferptrmax)
{
+ return writeToByteString(name, (const char *)value, bufferpptr, bufferptrmax);
+}
+
+status_t BaseItem::writeToByteString(
+ const char *name, const char * const &value, char **bufferpptr, char *bufferptrmax)
+{
const size_t len = 2 + 1 + strlen(name) + 1 + strlen(value) + 1;
if (len > UINT16_MAX) return BAD_VALUE;
return insert((uint16_t)len, bufferpptr, bufferptrmax)
@@ -967,7 +957,8 @@
?: insert(value, bufferpptr, bufferptrmax);
}
-status_t MediaAnalyticsItem::writeToByteString(
+
+status_t BaseItem::writeToByteString(
const char *name, const none_t &, char **bufferpptr, char *bufferptrmax)
{
const size_t len = 2 + 1 + strlen(name) + 1;
@@ -977,22 +968,24 @@
?: insert(name, bufferpptr, bufferptrmax);
}
+} // namespace mediametrics
+
status_t MediaAnalyticsItem::Prop::writeToByteString(
char **bufferpptr, char *bufferptrmax) const
{
switch (mType) {
case kTypeInt32:
- return MediaAnalyticsItem::writeToByteString(mName, u.int32Value, bufferpptr, bufferptrmax);
+ return BaseItem::writeToByteString(mName, u.int32Value, bufferpptr, bufferptrmax);
case kTypeInt64:
- return MediaAnalyticsItem::writeToByteString(mName, u.int64Value, bufferpptr, bufferptrmax);
+ return BaseItem::writeToByteString(mName, u.int64Value, bufferpptr, bufferptrmax);
case kTypeDouble:
- return MediaAnalyticsItem::writeToByteString(mName, u.doubleValue, bufferpptr, bufferptrmax);
+ return BaseItem::writeToByteString(mName, u.doubleValue, bufferpptr, bufferptrmax);
case kTypeRate:
- return MediaAnalyticsItem::writeToByteString(mName, u.rate, bufferpptr, bufferptrmax);
+ return BaseItem::writeToByteString(mName, u.rate, bufferpptr, bufferptrmax);
case kTypeCString:
- return MediaAnalyticsItem::writeToByteString(mName, u.CStringValue, bufferpptr, bufferptrmax);
+ return BaseItem::writeToByteString(mName, u.CStringValue, bufferpptr, bufferptrmax);
case kTypeNone:
- return MediaAnalyticsItem::writeToByteString(mName, none_t{}, bufferpptr, bufferptrmax);
+ return BaseItem::writeToByteString(mName, none_t{}, bufferpptr, bufferptrmax);
default:
ALOGE("%s: found bad prop type: %d, name %s",
__func__, mType, mName); // no payload sent
diff --git a/media/libmediametrics/include/IMediaAnalyticsService.h b/media/libmediametrics/include/IMediaAnalyticsService.h
index 1453b5f..30c63e7 100644
--- a/media/libmediametrics/include/IMediaAnalyticsService.h
+++ b/media/libmediametrics/include/IMediaAnalyticsService.h
@@ -49,6 +49,8 @@
may be silent and return 0 - success).
*/
virtual status_t submit(MediaAnalyticsItem *item) = 0;
+
+ virtual status_t submitBuffer(const char *buffer, size_t length) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/media/libmediametrics/include/MediaAnalyticsItem.h b/media/libmediametrics/include/MediaAnalyticsItem.h
index 5558211..bff7c9b 100644
--- a/media/libmediametrics/include/MediaAnalyticsItem.h
+++ b/media/libmediametrics/include/MediaAnalyticsItem.h
@@ -36,50 +36,346 @@
class Parcel;
/*
- * Media Metrics
- * Byte String format for communication of MediaAnalyticsItem.
+ * MediaMetrics Item
*
- * .... begin of item
- * .... begin of header
- * (uint32) length: including the length field itself
- * (uint32) header length, including header_length and length fields.
- * (uint16) version: 0
- * (uint16) key length, including zero termination
- * (int8)+ key string, including 0 termination
+ * Byte string format.
+ *
+ * For Java
+ * int64 corresponds to long
+ * int32, uint32 corresponds to int
+ * uint16 corresponds to char
+ * uint8, int8 corresponds to byte
+ *
+ * Hence uint8 and uint32 values are limited to INT8_MAX and INT32_MAX.
+ *
+ * Physical layout of integers and doubles within the MediaMetrics byte string
+ * is in Native / host order, which is nearly always little endian.
+ *
+ * -- begin of item
+ * -- begin of header
+ * (uint32) item size: including the item size field
+ * (uint32) header size, including the item size and header size fields.
+ * (uint16) version: exactly 0
+ * (uint16) key size, that is key strlen + 1 for zero termination.
+ * (int8)+ key string which is 0 terminated
* (int32) pid
* (int32) uid
* (int64) timestamp
- * .... end of header
- * .... begin body
- * (uint32) properties
- * #properties of the following:
- * (uint16) property_length, including property_length field itself
+ * -- end of header
+ * -- begin body
+ * (uint32) number of properties
+ * -- repeat for number of properties
+ * (uint16) property size, including property size field itself
* (uint8) type of property
* (int8)+ key string, including 0 termination
- * based on type of property (above), one of:
+ * based on type of property (given above), one of:
* (int32)
* (int64)
* (double)
* (int8)+ for cstring, including 0 termination
* (int64, int64) for rate
- * .... end body
- * .... end of item
+ * -- end body
+ * -- end of item
*/
+namespace mediametrics {
+
+// Type must match MediaMetrics.java
+enum Type {
+ kTypeNone = 0,
+ kTypeInt32 = 1,
+ kTypeInt64 = 2,
+ kTypeDouble = 3,
+ kTypeCString = 4,
+ kTypeRate = 5,
+};
+
+template<size_t N>
+static inline bool startsWith(const std::string &s, const char (&comp)[N]) {
+ return !strncmp(s.c_str(), comp, N-1);
+}
+
+/**
+ * Media Metrics BaseItem
+ *
+ * A base class which contains utility static functions to write to a byte stream
+ * and access the Media Metrics service.
+ */
+
+class BaseItem {
+ friend class MediaMetricsDeathNotifier; // for dropInstance
+ // enabled 1, disabled 0
+public:
+ // are we collecting analytics data
+ static bool isEnabled();
+
+protected:
+ static constexpr const char * const EnabledProperty = "media.metrics.enabled";
+ static constexpr const char * const EnabledPropertyPersist = "persist.media.metrics.enabled";
+ static const int EnabledProperty_default = 1;
+
+ // let's reuse a binder connection
+ static sp<IMediaAnalyticsService> sAnalyticsService;
+ static sp<IMediaAnalyticsService> getInstance();
+ static void dropInstance();
+ static bool submitBuffer(const char *buffer, size_t len);
+
+ static status_t writeToByteString(
+ const char *name, int32_t value, char **bufferpptr, char *bufferptrmax);
+ static status_t writeToByteString(
+ const char *name, int64_t value, char **bufferpptr, char *bufferptrmax);
+ static status_t writeToByteString(
+ const char *name, double value, char **bufferpptr, char *bufferptrmax);
+ static status_t writeToByteString(
+ const char *name, const std::pair<int64_t, int64_t> &value,
+ char **bufferpptr, char *bufferptrmax);
+ static status_t writeToByteString(
+ const char *name, char * const &value, char **bufferpptr, char *bufferptrmax);
+ static status_t writeToByteString(
+ const char *name, const char * const &value, char **bufferpptr, char *bufferptrmax);
+ struct none_t {}; // for kTypeNone
+ static status_t writeToByteString(
+ const char *name, const none_t &, char **bufferpptr, char *bufferptrmax);
+
+ template<typename T>
+ static status_t sizeOfByteString(const char *name, const T& value) {
+ return 2 + 1 + strlen(name) + 1 + sizeof(value);
+ }
+ template<> // static
+ status_t sizeOfByteString(const char *name, char * const &value) {
+ return 2 + 1 + strlen(name) + 1 + strlen(value) + 1;
+ }
+ template<> // static
+ status_t sizeOfByteString(const char *name, const char * const &value) {
+ return 2 + 1 + strlen(name) + 1 + strlen(value) + 1;
+ }
+ template<> // static
+ status_t sizeOfByteString(const char *name, const none_t &) {
+ return 2 + 1 + strlen(name) + 1;
+ }
+};
+
+/**
+ * Media Metrics BufferedItem
+ *
+ * A base class which represents a put-only Media Metrics item, storing
+ * the Media Metrics data in a buffer with begin and end pointers.
+ *
+ * If a property key is entered twice, it will be stored in the buffer twice,
+ * and (implementation defined) the last value for that key will be used
+ * by the Media Metrics service.
+ *
+ * For realloc, a baseRealloc pointer must be passed in either explicitly
+ * or implicitly in the constructor. This will be updated with the value used on realloc.
+ */
+class BufferedItem : public BaseItem {
+public:
+ static inline constexpr uint16_t kVersion = 0;
+
+ virtual ~BufferedItem() = default;
+ BufferedItem(const BufferedItem&) = delete;
+ BufferedItem& operator=(const BufferedItem&) = delete;
+
+ BufferedItem(const std::string key, char *begin, char *end)
+ : BufferedItem(key.c_str(), begin, end) { }
+
+ BufferedItem(const char *key, char *begin, char *end)
+ : BufferedItem(key, begin, end, nullptr) { }
+
+ BufferedItem(const char *key, char **begin, char *end)
+ : BufferedItem(key, *begin, end, begin) { }
+
+ BufferedItem(const char *key, char *begin, char *end, char **baseRealloc)
+ : mBegin(begin)
+ , mEnd(end)
+ , mBaseRealloc(baseRealloc)
+ {
+ init(key);
+ }
+
+ template<typename T>
+ BufferedItem &set(const char *key, const T& value) {
+ reallocFor(sizeOfByteString(key, value));
+ if (mStatus == NO_ERROR) {
+ mStatus = BaseItem::writeToByteString(key, value, &mBptr, mEnd);
+ ++mPropCount;
+ }
+ return *this;
+ }
+
+ template<typename T>
+ BufferedItem &set(const std::string& key, const T& value) {
+ return set(key.c_str(), value);
+ }
+
+ BufferedItem &setPid(pid_t pid) {
+ if (mStatus == NO_ERROR) {
+ copyTo(mBegin + mHeaderLen - 16, (int32_t)pid);
+ }
+ return *this;
+ }
+
+ BufferedItem &setUid(uid_t uid) {
+ if (mStatus == NO_ERROR) {
+ copyTo(mBegin + mHeaderLen - 12, (int32_t)uid);
+ }
+ return *this;
+ }
+
+ BufferedItem &setTimestamp(nsecs_t timestamp) {
+ if (mStatus == NO_ERROR) {
+ copyTo(mBegin + mHeaderLen - 8, (int64_t)timestamp);
+ }
+ return *this;
+ }
+
+ bool record() {
+ return updateHeader()
+ && BaseItem::submitBuffer(getBuffer(), getLength());
+ }
+
+ bool isValid () const {
+ return mStatus == NO_ERROR;
+ }
+
+ char *getBuffer() const { return mBegin; }
+ size_t getLength() const { return mBptr - mBegin; }
+ size_t getRemaining() const { return mEnd - mBptr; }
+ size_t getCapacity() const { return mEnd - mBegin; }
+
+ bool updateHeader() {
+ if (mStatus != NO_ERROR) return false;
+ copyTo(mBegin + 0, (uint32_t)getLength());
+ copyTo(mBegin + 4, (uint32_t)mHeaderLen);
+ copyTo(mBegin + mHeaderLen, (uint32_t)mPropCount);
+ return true;
+ }
+
+protected:
+ BufferedItem() = default;
+
+ void reallocFor(size_t required) {
+ if (mStatus != NO_ERROR) return;
+ const size_t remaining = getRemaining();
+ if (required <= remaining) return;
+ if (mBaseRealloc == nullptr) {
+ mStatus = NO_MEMORY;
+ return;
+ }
+
+ const size_t current = getLength();
+ size_t minimum = current + required;
+ if (minimum > SSIZE_MAX >> 1) {
+ mStatus = NO_MEMORY;
+ return;
+ }
+ minimum <<= 1;
+ void *newptr = realloc(*mBaseRealloc, minimum);
+ if (newptr == nullptr) {
+ mStatus = NO_MEMORY;
+ return;
+ }
+ if (newptr != *mBaseRealloc) {
+ // ALOGD("base changed! current:%zu new size %zu", current, minimum);
+ if (*mBaseRealloc == nullptr) {
+ memcpy(newptr, mBegin, current);
+ }
+ mBegin = (char *)newptr;
+ *mBaseRealloc = mBegin;
+ mEnd = mBegin + minimum;
+ mBptr = mBegin + current;
+ } else {
+ // ALOGD("base kept! current:%zu new size %zu", current, minimum);
+ mEnd = mBegin + minimum;
+ }
+ }
+ template<typename T>
+ void copyTo(char *ptr, const T& value) {
+ memcpy(ptr, &value, sizeof(value));
+ }
+
+ void init(const char *key) {
+ mBptr = mBegin;
+ const size_t keylen = strlen(key) + 1;
+ mHeaderLen = 4 + 4 + 2 + 2 + keylen + 4 + 4 + 8;
+ reallocFor(mHeaderLen);
+ if (mStatus != NO_ERROR) return;
+ mBptr = mBegin + mHeaderLen + 4; // this includes propcount.
+
+ if (mEnd < mBptr || keylen > UINT16_MAX) {
+ mStatus = NO_MEMORY;
+ mBptr = mEnd;
+ return;
+ }
+ copyTo(mBegin + 8, kVersion);
+ copyTo(mBegin + 10, (uint16_t)keylen);
+ strcpy(mBegin + 12, key);
+
+ // initialize some parameters (that could be overridden)
+ setPid(-1);
+ setUid(-1);
+ setTimestamp(0);
+ }
+
+ char *mBegin = nullptr;
+ char *mEnd = nullptr;
+ char **mBaseRealloc = nullptr; // set to an address if realloc should be done.
+ // upon return, that pointer is updated with
+ // whatever needs to be freed.
+ char *mBptr = nullptr;
+ status_t mStatus = NO_ERROR;
+ uint32_t mPropCount = 0;
+ uint32_t mHeaderLen = 0;
+};
+
+/**
+ * MediaMetrics Item is a stack allocated media analytics item used for
+ * fast logging. It falls over to a malloc if needed.
+ *
+ * This is templated with a buffer size to allocate on the stack.
+ */
+template <size_t N = 4096>
+class Item : public BufferedItem {
+public:
+ explicit Item(const std::string key) : Item(key.c_str()) { }
+
+ // Since this class will not be defined before the base class, we initialize variables
+ // in our own order.
+ explicit Item(const char *key) {
+ mBegin = mBuffer;
+ mEnd = mBuffer + N;
+ mBaseRealloc = &mReallocPtr;
+ init(key);
+ }
+
+ ~Item() override {
+ if (mReallocPtr != nullptr) { // do the check before calling free to avoid overhead.
+ free(mReallocPtr);
+ }
+ }
+
+private:
+ char *mReallocPtr = nullptr; // set non-null by base class if realloc happened.
+ char mBuffer[N];
+};
+
+} // mediametrics
+
/**
* Media Metrics MediaAnalyticsItem
*
* A mutable item representing an event or record that will be
- * logged with the Media Metrics service.
+ * logged with the Media Metrics service. For client logging, one should
+ * use the mediametrics::Item.
*
+ * The MediaAnalyticsItem is designed for the service as it has getters.
*/
-
-class MediaAnalyticsItem {
+class MediaAnalyticsItem : public mediametrics::BaseItem {
friend class MediaMetricsJNI; // TODO: remove this access
- friend class MediaMetricsDeathNotifier; // for dropInstance
public:
+ // TODO: remove this duplicate definition when frameworks base is updated.
enum Type {
kTypeNone = 0,
kTypeInt32 = 1,
@@ -281,28 +577,12 @@
status_t writeToByteString(char **bufferptr, size_t *length) const;
status_t readFromByteString(const char *bufferptr, size_t length);
- static status_t writeToByteString(
- const char *name, int32_t value, char **bufferpptr, char *bufferptrmax);
- static status_t writeToByteString(
- const char *name, int64_t value, char **bufferpptr, char *bufferptrmax);
- static status_t writeToByteString(
- const char *name, double value, char **bufferpptr, char *bufferptrmax);
- static status_t writeToByteString(
- const char *name, const std::pair<int64_t, int64_t> &value, char **bufferpptr, char *bufferptrmax);
- static status_t writeToByteString(
- const char *name, char * const &value, char **bufferpptr, char *bufferptrmax);
- struct none_t {}; // for kTypeNone
- static status_t writeToByteString(
- const char *name, const none_t &, char **bufferpptr, char *bufferptrmax);
std::string toString() const;
std::string toString(int version) const;
const char *toCString();
const char *toCString(int version);
- // are we collecting analytics data
- static bool isEnabled();
-
protected:
// merge fields from arg into this
@@ -316,15 +596,7 @@
int32_t writeToParcel0(Parcel *) const;
int32_t readFromParcel0(const Parcel&);
- // enabled 1, disabled 0
- static constexpr const char * const EnabledProperty = "media.metrics.enabled";
- static constexpr const char * const EnabledPropertyPersist = "persist.media.metrics.enabled";
- static const int EnabledProperty_default = 1;
- // let's reuse a binder connection
- static sp<IMediaAnalyticsService> sAnalyticsService;
- static sp<IMediaAnalyticsService> getInstance();
- static void dropInstance();
// checks equality even with nullptr.
static bool stringEquals(const char *a, const char *b) {
@@ -435,7 +707,29 @@
}
bool isNamed(const char *name) const {
- return strcmp(name, mName) == 0;
+ return stringEquals(name, mName);
+ }
+
+ template <typename T> void visit(T f) const {
+ switch (mType) {
+ case MediaAnalyticsItem::kTypeInt32:
+ f(u.int32Value);
+ return;
+ case MediaAnalyticsItem::kTypeInt64:
+ f(u.int64Value);
+ return;
+ case MediaAnalyticsItem::kTypeDouble:
+ f(u.doubleValue);
+ return;
+ case MediaAnalyticsItem::kTypeRate:
+ f(u.rate);
+ return;
+ case MediaAnalyticsItem::kTypeCString:
+ f(u.CStringValue);
+ return;
+ default:
+ return;
+ }
}
template <typename T> bool get(T *value) const = delete;
diff --git a/media/libmediaplayerservice/StagefrightMetadataRetriever.h b/media/libmediaplayerservice/StagefrightMetadataRetriever.h
index ee51290..c09a501 100644
--- a/media/libmediaplayerservice/StagefrightMetadataRetriever.h
+++ b/media/libmediaplayerservice/StagefrightMetadataRetriever.h
@@ -18,7 +18,7 @@
#define STAGEFRIGHT_METADATA_RETRIEVER_H_
-#include <media/IMediaExtractor.h>
+#include <android/IMediaExtractor.h>
#include <media/MediaMetadataRetrieverInterface.h>
#include <utils/KeyedVector.h>
diff --git a/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceMediaHTTP.h b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceMediaHTTP.h
index b5124dc..2f94ada 100644
--- a/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceMediaHTTP.h
+++ b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceMediaHTTP.h
@@ -19,6 +19,7 @@
#define PLAYER_SERVICE_MEDIA_HTTP_H_
#include <datasource/MediaHTTP.h>
+#include <drm/DrmManagerClient.h>
#include <media/stagefright/foundation/AString.h>
namespace android {
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 00e3443..a49e72e 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -30,12 +30,13 @@
#include <media/DataSource.h>
#include <media/MediaBufferHolder.h>
#include <media/MediaSource.h>
-#include <media/IMediaExtractorService.h>
+#include <android/IMediaExtractorService.h>
#include <media/IMediaHTTPService.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/InterfaceUtils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaClock.h>
#include <media/stagefright/MediaDefs.h>
@@ -75,7 +76,6 @@
mUIDValid(uidValid),
mUID(uid),
mMediaClock(mediaClock),
- mFd(-1),
mBitrate(-1LL),
mPendingReadBufferTypes(0) {
ALOGV("GenericSource");
@@ -98,10 +98,7 @@
mUri.clear();
mUriHeaders.clear();
mSources.clear();
- if (mFd >= 0) {
- close(mFd);
- mFd = -1;
- }
+ mFd.reset();
mOffset = 0;
mLength = 0;
mStarted = false;
@@ -137,11 +134,11 @@
status_t NuPlayer::GenericSource::setDataSource(
int fd, int64_t offset, int64_t length) {
Mutex::Autolock _l(mLock);
- ALOGV("setDataSource %d/%lld/%lld", fd, (long long)offset, (long long)length);
+ ALOGV("setDataSource %d/%lld/%lld (%s)", fd, (long long)offset, (long long)length, nameForFd(fd).c_str());
resetDataSource();
- mFd = dup(fd);
+ mFd.reset(dup(fd));
mOffset = offset;
mLength = length;
@@ -413,24 +410,19 @@
} else {
if (property_get_bool("media.stagefright.extractremote", true) &&
!PlayerServiceFileSource::requiresDrm(
- mFd, mOffset, mLength, nullptr /* mime */)) {
+ mFd.get(), mOffset, mLength, nullptr /* mime */)) {
sp<IBinder> binder =
defaultServiceManager()->getService(String16("media.extractor"));
if (binder != nullptr) {
ALOGD("FileSource remote");
sp<IMediaExtractorService> mediaExService(
interface_cast<IMediaExtractorService>(binder));
- sp<IDataSource> source =
- mediaExService->makeIDataSource(mFd, mOffset, mLength);
+ sp<IDataSource> source;
+ mediaExService->makeIDataSource(mFd, mOffset, mLength, &source);
ALOGV("IDataSource(FileSource): %p %d %lld %lld",
- source.get(), mFd, (long long)mOffset, (long long)mLength);
+ source.get(), mFd.get(), (long long)mOffset, (long long)mLength);
if (source.get() != nullptr) {
mDataSource = CreateDataSourceFromIDataSource(source);
- if (mDataSource != nullptr) {
- // Close the local file descriptor as it is not needed anymore.
- close(mFd);
- mFd = -1;
- }
} else {
ALOGW("extractor service cannot make data source");
}
@@ -440,12 +432,8 @@
}
if (mDataSource == nullptr) {
ALOGD("FileSource local");
- mDataSource = new PlayerServiceFileSource(mFd, mOffset, mLength);
+ mDataSource = new PlayerServiceFileSource(mFd.get(), mOffset, mLength);
}
- // TODO: close should always be done on mFd, see the lines following
- // CreateDataSourceFromIDataSource above,
- // and the FileSource constructor should dup the mFd argument as needed.
- mFd = -1;
}
if (mDataSource == NULL) {
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 4d1905d..7a2ab8f 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -23,6 +23,7 @@
#include "ATSParser.h"
+#include <android-base/unique_fd.h>
#include <media/mediaplayer.h>
#include <media/stagefright/MediaBuffer.h>
@@ -154,7 +155,7 @@
sp<IMediaHTTPService> mHTTPService;
AString mUri;
KeyedVector<String8, String8> mUriHeaders;
- int mFd;
+ base::unique_fd mFd;
int64_t mOffset;
int64_t mLength;
diff --git a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
index 9a8ed8d..f114046 100644
--- a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
+++ b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
@@ -23,7 +23,6 @@
#include <aidl/android/media/BnResourceManagerClient.h>
#include <aidl/android/media/BnResourceManagerService.h>
-#include <android/media/BnResourceManagerClient.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/ProcessInfoInterface.h>
@@ -37,110 +36,11 @@
namespace android {
-using ::android::binder::Status;
-using ::android::media::ResourceManagerService;
-using ::ndk::ScopedAStatus;
-
-using NdkBnResourceManagerClient = ::aidl::android::media::BnResourceManagerClient;
-using NdkBnResourceManagerService = ::aidl::android::media::BnResourceManagerService;
-using NdkMediaResource = ::aidl::android::media::MediaResourceParcel;
-using NdkResourceManagerClient = ::aidl::android::media::IResourceManagerClient;
-
-using FwkBnResourceManagerClient = ::android::media::BnResourceManagerClient;
-using FwkMediaResource = ::android::media::MediaResourceParcel;
-
-namespace {
-
-struct FwkResourceManagerClientImpl : public FwkBnResourceManagerClient {
- FwkResourceManagerClientImpl(const std::shared_ptr<NdkResourceManagerClient> &client)
- : mClient(client) {
- }
-
- Status reclaimResource(bool* _aidl_return) override {
- mClient->reclaimResource(_aidl_return);
- return Status::ok();
- }
-
- Status getName(std::string* _aidl_return) override {
- mClient->getName(_aidl_return);
- return Status::ok();
- }
-
-private:
- std::shared_ptr<NdkResourceManagerClient> mClient;
-};
-
-FwkMediaResource NdkToFwkMediaResource(const NdkMediaResource &in) {
- FwkMediaResource out{};
- out.type = static_cast<decltype(out.type)>(in.type);
- out.subType = static_cast<decltype(out.subType)>(in.subType);
- auto v(reinterpret_cast<const uint8_t *>(in.id.data()));
- out.id.assign(v, v + in.id.size());
- out.value = in.value;
- return out;
-}
-
-std::vector<FwkMediaResource> NdkToFwkMediaResourceVec(const std::vector<NdkMediaResource> &in) {
- std::vector<FwkMediaResource> out;
- for (auto e : in) {
- out.push_back(NdkToFwkMediaResource(e));
- }
- return out;
-}
-
-ScopedAStatus FwkToNdkStatus(Status err) {
- return ScopedAStatus(AStatus_fromExceptionCode(err.serviceSpecificErrorCode()));
-}
-
-struct NdkResourceManagerServiceImpl : public NdkBnResourceManagerService {
- using NdkMediaResourcePolicy = ::aidl::android::media::MediaResourcePolicyParcel;
-
- NdkResourceManagerServiceImpl(const sp<ResourceManagerService> &service)
- : mService(service) {}
-
- ScopedAStatus config(const std::vector<NdkMediaResourcePolicy>& in_policies) override {
- (void)in_policies;
- return ScopedAStatus::ok();
- }
-
- ScopedAStatus addResource(int32_t in_pid, int32_t in_uid, int64_t in_clientId,
- const std::shared_ptr<NdkResourceManagerClient>& in_client,
- const std::vector<NdkMediaResource>& in_resources) override {
- sp<FwkBnResourceManagerClient> client(new FwkResourceManagerClientImpl(in_client));
- std::vector<FwkMediaResource> resources(NdkToFwkMediaResourceVec(in_resources));
- auto err = mService->addResource(in_pid, in_uid, in_clientId, client, resources);
- return FwkToNdkStatus(err);
- }
-
- ScopedAStatus removeResource(int32_t in_pid, int64_t in_clientId,
- const std::vector<NdkMediaResource>& in_resources) override {
- std::vector<FwkMediaResource> resources(NdkToFwkMediaResourceVec(in_resources));
- auto err = mService->removeResource(in_pid, in_clientId, resources);
- return FwkToNdkStatus(err);
- }
-
- ScopedAStatus removeClient(int32_t in_pid, int64_t in_clientId) override{
- auto err = mService->removeClient(in_pid, in_clientId);
- return FwkToNdkStatus(err);
- }
-
- ScopedAStatus reclaimResource(int32_t in_callingPid,
- const std::vector<NdkMediaResource>& in_resources, bool* _aidl_return) override {
- std::vector<FwkMediaResource> resources(NdkToFwkMediaResourceVec(in_resources));
- auto err = mService->reclaimResource(in_callingPid, resources, _aidl_return);
- return FwkToNdkStatus(err);
- }
-
-private:
- sp<ResourceManagerService> mService;
-};
-
-template <typename Impl>
-std::shared_ptr<NdkResourceManagerClient> NdkImplToIface(const Impl &impl) {
- return std::static_pointer_cast<NdkResourceManagerClient>(impl);
-}
-
-}
+using Status = ::ndk::ScopedAStatus;
+using ::aidl::android::media::BnResourceManagerClient;
+using ::aidl::android::media::BnResourceManagerService;
+using ::aidl::android::media::MediaResourceParcel;
+using ::aidl::android::media::IResourceManagerClient;
static Vector<uint8_t> toAndroidVector(const std::vector<uint8_t> &vec) {
Vector<uint8_t> aVec;
@@ -169,27 +69,27 @@
DISALLOW_EVIL_CONSTRUCTORS(FakeProcessInfo);
};
-struct FakeDrm : public NdkBnResourceManagerClient {
+struct FakeDrm : public BnResourceManagerClient {
FakeDrm(const std::vector<uint8_t>& sessionId, const sp<DrmSessionManager>& manager)
: mSessionId(toAndroidVector(sessionId)),
mReclaimed(false),
mDrmSessionManager(manager) {}
- ScopedAStatus reclaimResource(bool* _aidl_return) {
+ Status reclaimResource(bool* _aidl_return) {
mReclaimed = true;
mDrmSessionManager->removeSession(mSessionId);
*_aidl_return = true;
- return ScopedAStatus::ok();
+ return Status::ok();
}
- ScopedAStatus getName(::std::string* _aidl_return) {
+ Status getName(::std::string* _aidl_return) {
String8 name("FakeDrm[");
for (size_t i = 0; i < mSessionId.size(); ++i) {
name.appendFormat("%02x", mSessionId[i]);
}
name.append("]");
*_aidl_return = name;
- return ScopedAStatus::ok();
+ return Status::ok();
}
bool isReclaimed() const {
@@ -215,8 +115,7 @@
virtual void noteResetVideo() override {}
- virtual bool requestCpusetBoost(
- bool /*enable*/, const sp<IInterface> &/*client*/) override {
+ virtual bool requestCpusetBoost(bool /*enable*/) override {
return true;
}
@@ -237,21 +136,25 @@
class DrmSessionManagerTest : public ::testing::Test {
public:
DrmSessionManagerTest()
- : mService(new ResourceManagerService(new FakeProcessInfo(), new FakeSystemCallback())),
- mDrmSessionManager(new DrmSessionManager(std::shared_ptr<NdkBnResourceManagerService>(new NdkResourceManagerServiceImpl(mService)))),
- mTestDrm1(new FakeDrm(kTestSessionId1, mDrmSessionManager)),
- mTestDrm2(new FakeDrm(kTestSessionId2, mDrmSessionManager)),
- mTestDrm3(new FakeDrm(kTestSessionId3, mDrmSessionManager)) {
+ : mService(::ndk::SharedRefBase::make<ResourceManagerService>
+ (new FakeProcessInfo(), new FakeSystemCallback())),
+ mDrmSessionManager(new DrmSessionManager(mService)),
+ mTestDrm1(::ndk::SharedRefBase::make<FakeDrm>(
+ kTestSessionId1, mDrmSessionManager)),
+ mTestDrm2(::ndk::SharedRefBase::make<FakeDrm>(
+ kTestSessionId2, mDrmSessionManager)),
+ mTestDrm3(::ndk::SharedRefBase::make<FakeDrm>(
+ kTestSessionId3, mDrmSessionManager)) {
}
protected:
void addSession() {
- mDrmSessionManager->addSession(kTestPid1, NdkImplToIface(mTestDrm1), mTestDrm1->mSessionId);
- mDrmSessionManager->addSession(kTestPid2, NdkImplToIface(mTestDrm2), mTestDrm2->mSessionId);
- mDrmSessionManager->addSession(kTestPid2, NdkImplToIface(mTestDrm3), mTestDrm3->mSessionId);
+ mDrmSessionManager->addSession(kTestPid1, mTestDrm1, mTestDrm1->mSessionId);
+ mDrmSessionManager->addSession(kTestPid2, mTestDrm2, mTestDrm2->mSessionId);
+ mDrmSessionManager->addSession(kTestPid2, mTestDrm3, mTestDrm3->mSessionId);
}
- sp<ResourceManagerService> mService;
+ std::shared_ptr<ResourceManagerService> mService;
sp<DrmSessionManager> mDrmSessionManager;
std::shared_ptr<FakeDrm> mTestDrm1;
std::shared_ptr<FakeDrm> mTestDrm2;
@@ -302,8 +205,9 @@
// add a session from a higher priority process.
const std::vector<uint8_t> sid{1, 3, 5};
- std::shared_ptr<FakeDrm> drm(new FakeDrm(sid, mDrmSessionManager));
- mDrmSessionManager->addSession(15, NdkImplToIface(drm), drm->mSessionId);
+ std::shared_ptr<FakeDrm> drm =
+ ::ndk::SharedRefBase::make<FakeDrm>(sid, mDrmSessionManager);
+ mDrmSessionManager->addSession(15, drm, drm->mSessionId);
// make sure mTestDrm2 is reclaimed next instead of mTestDrm3
mDrmSessionManager->useSession(mTestDrm3->mSessionId);
@@ -323,9 +227,9 @@
EXPECT_FALSE(mDrmSessionManager->reclaimSession(kTestPid2));
// add sessions from same pid
- mDrmSessionManager->addSession(kTestPid2, NdkImplToIface(mTestDrm1), mTestDrm1->mSessionId);
- mDrmSessionManager->addSession(kTestPid2, NdkImplToIface(mTestDrm2), mTestDrm2->mSessionId);
- mDrmSessionManager->addSession(kTestPid2, NdkImplToIface(mTestDrm3), mTestDrm3->mSessionId);
+ mDrmSessionManager->addSession(kTestPid2, mTestDrm1, mTestDrm1->mSessionId);
+ mDrmSessionManager->addSession(kTestPid2, mTestDrm2, mTestDrm2->mSessionId);
+ mDrmSessionManager->addSession(kTestPid2, mTestDrm3, mTestDrm3->mSessionId);
// use some but not all sessions
mDrmSessionManager->useSession(mTestDrm1->mSessionId);
diff --git a/media/libmediatranscoding/Android.bp b/media/libmediatranscoding/Android.bp
new file mode 100644
index 0000000..8f0e278
--- /dev/null
+++ b/media/libmediatranscoding/Android.bp
@@ -0,0 +1,15 @@
+// AIDL interfaces of MediaTranscoding.
+aidl_interface {
+ name: "mediatranscoding_aidl_interface",
+ local_include_dir: "aidl",
+ srcs: [
+ "aidl/android/media/IMediaTranscodingService.aidl",
+ "aidl/android/media/ITranscodingServiceClient.aidl",
+ "aidl/android/media/TranscodingErrorCode.aidl",
+ "aidl/android/media/TranscodingType.aidl",
+ "aidl/android/media/TranscodingVideoCodecType.aidl",
+ "aidl/android/media/TranscodingJob.aidl",
+ "aidl/android/media/TranscodingRequest.aidl",
+ "aidl/android/media/TranscodingResult.aidl",
+ ],
+}
diff --git a/media/libmediatranscoding/OWNERS b/media/libmediatranscoding/OWNERS
new file mode 100644
index 0000000..02287cb
--- /dev/null
+++ b/media/libmediatranscoding/OWNERS
@@ -0,0 +1,3 @@
+akersten@google.com
+hkuang@google.com
+lnilsson@google.com
diff --git a/media/libmediatranscoding/aidl/android/media/IMediaTranscodingService.aidl b/media/libmediatranscoding/aidl/android/media/IMediaTranscodingService.aidl
new file mode 100644
index 0000000..cae8ff0
--- /dev/null
+++ b/media/libmediatranscoding/aidl/android/media/IMediaTranscodingService.aidl
@@ -0,0 +1,81 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.media.TranscodingJob;
+import android.media.TranscodingRequest;
+import android.media.ITranscodingServiceClient;
+
+/**
+ * Binder interface for MediaTranscodingService.
+ *
+ * {@hide}
+ */
+interface IMediaTranscodingService {
+ /**
+ * Register the client with the MediaTranscodingService.
+ *
+ * Client must call this function to register itself with the service in order to perform
+ * transcoding. This function will return a unique positive Id assigned by the service.
+ * Client should save this Id and use it for all the transaction with the service.
+ *
+ * @param client interface for the MediaTranscodingService to call the client.
+ * @return a unique positive Id assigned to the client by the service, -1 means failed to
+ * register.
+ */
+ int registerClient(in ITranscodingServiceClient client);
+
+ /**
+ * Unregister the client with the MediaTranscodingService.
+ *
+ * Client will not be able to perform any more transcoding after unregister.
+ *
+ * @param clientId assigned Id of the client.
+ * @return true if succeeds, false otherwise.
+ */
+ boolean unregisterClient(in int clientId);
+
+ /**
+ * Submits a transcoding request to MediaTranscodingService.
+ *
+ * @param clientId assigned Id of the client.
+ * @param request a TranscodingRequest contains transcoding configuration.
+ * @param job(output variable) a TranscodingJob generated by the MediaTranscodingService.
+ * @return a unique positive jobId generated by the MediaTranscodingService, -1 means failure.
+ */
+ int submitRequest(in int clientId,
+ in TranscodingRequest request,
+ out TranscodingJob job);
+
+ /**
+ * Cancels a transcoding job.
+ *
+ * @param clientId assigned id of the client.
+ * @param jobId a TranscodingJob generated by the MediaTranscodingService.
+ * @return true if succeeds, false otherwise.
+ */
+ boolean cancelJob(in int clientId, in int jobId);
+
+ /**
+ * Queries the job detail associated with a jobId.
+ *
+ * @param jobId a TranscodingJob generated by the MediaTranscodingService.
+ * @param job(output variable) the TranscodingJob associated with the jobId.
+ * @return true if succeeds, false otherwise.
+ */
+ boolean getJobWithId(in int jobId, out TranscodingJob job);
+}
diff --git a/media/libmediatranscoding/aidl/android/media/ITranscodingServiceClient.aidl b/media/libmediatranscoding/aidl/android/media/ITranscodingServiceClient.aidl
new file mode 100644
index 0000000..29b6f35
--- /dev/null
+++ b/media/libmediatranscoding/aidl/android/media/ITranscodingServiceClient.aidl
@@ -0,0 +1,75 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.media.TranscodingErrorCode;
+import android.media.TranscodingJob;
+import android.media.TranscodingResult;
+
+/**
+ * ITranscodingServiceClient interface for the MediaTranscodingervice to communicate with the
+ * client.
+ *
+ * {@hide}
+ */
+//TODO(hkuang): Implement the interface.
+interface ITranscodingServiceClient {
+ /**
+ * Retrieves the name of the client.
+ */
+ @utf8InCpp String getName();
+
+ /**
+ * Called when the transcoding associated with the jobId finished.
+ *
+ * @param jobId jobId assigned by the MediaTranscodingService upon receiving request.
+ * @param result contains the transcoded file stats and other transcoding metrics if requested.
+ */
+ oneway void onTranscodingFinished(in int jobId, in TranscodingResult result);
+
+ /**
+ * Called when the transcoding associated with the jobId failed.
+ *
+ * @param jobId jobId assigned by the MediaTranscodingService upon receiving request.
+ * @param errorCode error code that indicates the error.
+ */
+ oneway void onTranscodingFailed(in int jobId, in TranscodingErrorCode errorCode);
+
+ /**
+ * Called when the transcoding configuration associated with the jobId gets updated, i.e. wait
+ * number in the job queue.
+ *
+ * <p> This will only be called if client set requestUpdate to be true in the TranscodingRequest
+ * submitted to the MediaTranscodingService.
+ *
+ * @param jobId jobId assigned by the MediaTranscodingService upon receiving request.
+ * @param oldAwaitNumber previous number of jobs ahead of current job.
+ * @param newAwaitNumber updated number of jobs ahead of current job.
+ */
+ oneway void onAwaitNumberOfJobsChanged(in int jobId, in int oldAwaitNumber, in int newAwaitNumber);
+
+ /**
+ * Called when there is an update on the progress of the TranscodingJob.
+ *
+ * <p> This will only be called if client set requestUpdate to be true in the TranscodingRequest
+ * submitted to the MediaTranscodingService.
+ *
+ * @param jobId jobId assigned by the MediaTranscodingService upon receiving request.
+ * @param progress an integer number ranging from 0 ~ 100 inclusive.
+ */
+ oneway void onProgressUpdate(in int jobId, in int progress);
+}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingErrorCode.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingErrorCode.aidl
new file mode 100644
index 0000000..7f47fdc
--- /dev/null
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingErrorCode.aidl
@@ -0,0 +1,33 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/**
+ * Type enums of video transcoding errors.
+ *
+ * {@hide}
+ */
+@Backing(type = "int")
+enum TranscodingErrorCode {
+ kUnknown = 0,
+ kUnsupported = 1,
+ kDecoderError = 2,
+ kEncoderError = 3,
+ kExtractorError = 4,
+ kMuxerError = 5,
+ kInvalidBitstream = 6
+}
\ No newline at end of file
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingJob.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingJob.aidl
new file mode 100644
index 0000000..42ad8ad
--- /dev/null
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingJob.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.media.TranscodingRequest;
+
+/**
+ * TranscodingJob is generated by the MediaTranscodingService upon receiving a TranscodingRequest.
+ * It contains all the necessary configuration generated by the MediaTranscodingService for the
+ * TranscodingRequest.
+ *
+ * {@hide}
+ */
+//TODO(hkuang): Implement the parcelable.
+parcelable TranscodingJob {
+ /**
+ * A unique positive Id generated by the MediaTranscodingService.
+ */
+ int jobId;
+
+ /**
+ * The request associated with the TranscodingJob.
+ */
+ TranscodingRequest request;
+
+ /**
+ * Current number of jobs ahead of this job. The service schedules the job based on the priority
+ * passed from the client. Client could specify whether to receive updates when the
+ * awaitNumberOfJobs changes through setting requestProgressUpdate in the TranscodingRequest.
+ */
+ int awaitNumberOfJobs;
+}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingRequest.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingRequest.aidl
new file mode 100644
index 0000000..6b51ee3
--- /dev/null
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingRequest.aidl
@@ -0,0 +1,58 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.media.TranscodingType;
+
+/**
+ * TranscodingRequest contains the desired configuration for the transcoding.
+ *
+ * {@hide}
+ */
+//TODO(hkuang): Implement the parcelable.
+parcelable TranscodingRequest {
+ /**
+ * Name of file to be transcoded.
+ */
+ @utf8InCpp String fileName;
+
+ /**
+ * Type of the transcoding.
+ */
+ TranscodingType transcodingType;
+
+ /**
+ * Input source file descriptor.
+ */
+ ParcelFileDescriptor inFd;
+
+ /**
+ * Output transcoded file descriptor.
+ */
+ ParcelFileDescriptor outFd;
+
+ /**
+ * Priority of this transcoding. Service will schedule the transcoding based on the priority.
+ */
+ // TODO(hkuang): Define the priority level.
+ int priority;
+
+ /**
+ * Whether to receive update on progress and change of awaitNumJobs.
+ */
+ boolean requestUpdate;
+}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingResult.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingResult.aidl
new file mode 100644
index 0000000..a41e025
--- /dev/null
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingResult.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.media.TranscodingJob;
+
+/**
+ * Result of the transcoding.
+ *
+ * {@hide}
+ */
+//TODO(hkuang): Implement the parcelable.
+parcelable TranscodingResult {
+ /**
+ * The jobId associated with the TranscodingResult.
+ */
+ int jobId;
+
+ /**
+ * Actual bitrate of the transcoded video in bits per second. This will only present for video
+ * transcoding. -1 means not available.
+ */
+ int actualBitrateBps;
+
+ // TODO(hkuang): Add more fields.
+}
\ No newline at end of file
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingType.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingType.aidl
new file mode 100644
index 0000000..9184c87
--- /dev/null
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingType.aidl
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/**
+ * Type of transcoding.
+ *
+ * {@hide}
+ */
+@Backing(type = "int")
+enum TranscodingType {
+ kUnknown = 0,
+ kVideoTranscoding = 1,
+ kImageTranscoding = 2,
+}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingVideoCodecType.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingVideoCodecType.aidl
new file mode 100644
index 0000000..5dab4f2
--- /dev/null
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingVideoCodecType.aidl
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/**
+ * Type enums of video codec type.
+ *
+ * {@hide}
+ */
+@Backing(type = "int")
+enum TranscodingVideoCodecType {
+ kUnspecified = 0,
+ kAvc = 1,
+ kHevc = 2,
+}
\ No newline at end of file
diff --git a/media/libstagefright/ACodecBufferChannel.cpp b/media/libstagefright/ACodecBufferChannel.cpp
index aa4c22a..bf8f09c 100644
--- a/media/libstagefright/ACodecBufferChannel.cpp
+++ b/media/libstagefright/ACodecBufferChannel.cpp
@@ -433,4 +433,12 @@
it->mClientBuffer);
}
+void ACodecBufferChannel::setCrypto(const sp<ICrypto> &crypto) {
+ mCrypto = crypto;
+}
+
+void ACodecBufferChannel::setDescrambler(const sp<IDescrambler> &descrambler) {
+ mDescrambler = descrambler;
+}
+
} // namespace android
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 76eadf7..e78e1e7 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -227,6 +227,7 @@
"libaudioutils",
"libbase",
"libbinder",
+ "libbinder_ndk",
"libcamera_client",
"libcutils",
"libdatasource",
diff --git a/media/libstagefright/CallbackDataSource.cpp b/media/libstagefright/CallbackDataSource.cpp
index dea83d4..eb3cb45 100644
--- a/media/libstagefright/CallbackDataSource.cpp
+++ b/media/libstagefright/CallbackDataSource.cpp
@@ -20,9 +20,9 @@
#include "include/CallbackDataSource.h"
+#include <android/IDataSource.h>
#include <binder/IMemory.h>
#include <binder/IPCThreadState.h>
-#include <media/IDataSource.h>
#include <media/stagefright/foundation/ADebug.h>
#include <algorithm>
diff --git a/media/libstagefright/CodecBase.cpp b/media/libstagefright/CodecBase.cpp
index 5765883..5b724aa 100644
--- a/media/libstagefright/CodecBase.cpp
+++ b/media/libstagefright/CodecBase.cpp
@@ -26,14 +26,6 @@
namespace android {
-void BufferChannelBase::setCrypto(const sp<ICrypto> &crypto) {
- mCrypto = crypto;
-}
-
-void BufferChannelBase::setDescrambler(const sp<IDescrambler> &descrambler) {
- mDescrambler = descrambler;
-}
-
void BufferChannelBase::IMemoryToSharedBuffer(
const sp<IMemory> &memory,
int32_t heapSeqNum,
diff --git a/media/libstagefright/FrameCaptureLayer.cpp b/media/libstagefright/FrameCaptureLayer.cpp
index 29642be..815057d 100644
--- a/media/libstagefright/FrameCaptureLayer.cpp
+++ b/media/libstagefright/FrameCaptureLayer.cpp
@@ -32,6 +32,8 @@
namespace android {
static const int64_t kAcquireBufferTimeoutNs = 100000000LL;
+static constexpr float kDefaultMaxMasteringLuminance = 1000.0;
+static constexpr float kDefaultMaxContentLuminance = 1000.0;
ui::Dataspace translateDataspace(ui::Dataspace dataspace) {
ui::Dataspace updatedDataspace = dataspace;
@@ -93,6 +95,14 @@
layerSettings->source.buffer.textureName = textureName;
layerSettings->source.buffer.usePremultipliedAlpha = false;
layerSettings->source.buffer.isY410BT2020 = isHdrY410(mBufferItem);
+ bool hasSmpte2086 = mBufferItem.mHdrMetadata.validTypes & HdrMetadata::SMPTE2086;
+ bool hasCta861_3 = mBufferItem.mHdrMetadata.validTypes & HdrMetadata::CTA861_3;
+ layerSettings->source.buffer.maxMasteringLuminance = hasSmpte2086
+ ? mBufferItem.mHdrMetadata.smpte2086.maxLuminance
+ : kDefaultMaxMasteringLuminance;
+ layerSettings->source.buffer.maxContentLuminance = hasCta861_3
+ ? mBufferItem.mHdrMetadata.cta8613.maxContentLightLevel
+ : kDefaultMaxContentLuminance;
// Set filtering to false since the capture itself doesn't involve
// any scaling, metadata retriever JNI is scaling the bitmap if
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 14564c9..257dd0f 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -27,11 +27,11 @@
#include <android/hardware/cas/native/1.0/IDescrambler.h>
#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
-#include <android/media/BnResourceManagerClient.h>
-#include <android/media/IResourceManagerService.h>
+#include <aidl/android/media/BnResourceManagerClient.h>
+#include <aidl/android/media/IResourceManagerService.h>
+#include <android/binder_ibinder.h>
+#include <android/binder_manager.h>
#include <binder/IMemory.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
#include <binder/MemoryDealer.h>
#include <cutils/properties.h>
#include <gui/BufferQueue.h>
@@ -64,9 +64,10 @@
namespace android {
-using ::android::binder::Status;
-using ::android::media::BnResourceManagerClient;
-using ::android::media::IResourceManagerService;
+using Status = ::ndk::ScopedAStatus;
+using aidl::android::media::BnResourceManagerClient;
+using aidl::android::media::IResourceManagerClient;
+using aidl::android::media::IResourceManagerService;
// key for media statistics
static const char *kCodecKeyName = "codec";
@@ -111,7 +112,7 @@
static bool kEmitHistogram = false;
-static int64_t getId(const sp<IResourceManagerClient> &client) {
+static int64_t getId(const std::shared_ptr<IResourceManagerClient> &client) {
return (int64_t) client.get();
}
@@ -164,7 +165,6 @@
return Status::ok();
}
-protected:
virtual ~ResourceManagerClient() {}
private:
@@ -173,93 +173,99 @@
DISALLOW_EVIL_CONSTRUCTORS(ResourceManagerClient);
};
-struct MediaCodec::ResourceManagerServiceProxy : public IBinder::DeathRecipient {
- ResourceManagerServiceProxy(pid_t pid, uid_t uid);
- ~ResourceManagerServiceProxy();
+struct MediaCodec::ResourceManagerServiceProxy : public RefBase {
+ ResourceManagerServiceProxy(pid_t pid, uid_t uid,
+ const std::shared_ptr<IResourceManagerClient> &client);
+ virtual ~ResourceManagerServiceProxy();
void init();
// implements DeathRecipient
- virtual void binderDied(const wp<IBinder>& /*who*/);
+ static void BinderDiedCallback(void* cookie);
+ void binderDied();
- void addResource(
- int64_t clientId,
- const sp<IResourceManagerClient> &client,
- const std::vector<MediaResourceParcel> &resources);
-
- void removeResource(
- int64_t clientId,
- const std::vector<MediaResourceParcel> &resources);
-
- void removeClient(int64_t clientId);
-
+ void addResource(const MediaResourceParcel &resource);
+ void removeResource(const MediaResourceParcel &resource);
+ void removeClient();
bool reclaimResource(const std::vector<MediaResourceParcel> &resources);
private:
Mutex mLock;
- sp<android::media::IResourceManagerService> mService;
pid_t mPid;
uid_t mUid;
+ std::shared_ptr<IResourceManagerService> mService;
+ std::shared_ptr<IResourceManagerClient> mClient;
+ ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
};
MediaCodec::ResourceManagerServiceProxy::ResourceManagerServiceProxy(
- pid_t pid, uid_t uid)
- : mPid(pid), mUid(uid) {
+ pid_t pid, uid_t uid, const std::shared_ptr<IResourceManagerClient> &client)
+ : mPid(pid), mUid(uid), mClient(client),
+ mDeathRecipient(AIBinder_DeathRecipient_new(BinderDiedCallback)) {
if (mPid == MediaCodec::kNoPid) {
- mPid = IPCThreadState::self()->getCallingPid();
+ mPid = AIBinder_getCallingPid();
}
}
MediaCodec::ResourceManagerServiceProxy::~ResourceManagerServiceProxy() {
- if (mService != NULL) {
- IInterface::asBinder(mService)->unlinkToDeath(this);
+ if (mService != nullptr) {
+ AIBinder_unlinkToDeath(mService->asBinder().get(), mDeathRecipient.get(), this);
}
}
void MediaCodec::ResourceManagerServiceProxy::init() {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("media.resource_manager"));
- mService = interface_cast<IResourceManagerService>(binder);
- if (mService == NULL) {
+ ::ndk::SpAIBinder binder(AServiceManager_getService("media.resource_manager"));
+ mService = IResourceManagerService::fromBinder(binder);
+ if (mService == nullptr) {
ALOGE("Failed to get ResourceManagerService");
return;
}
- IInterface::asBinder(mService)->linkToDeath(this);
+
+ AIBinder_linkToDeath(mService->asBinder().get(), mDeathRecipient.get(), this);
}
-void MediaCodec::ResourceManagerServiceProxy::binderDied(const wp<IBinder>& /*who*/) {
+//static
+void MediaCodec::ResourceManagerServiceProxy::BinderDiedCallback(void* cookie) {
+ auto thiz = static_cast<ResourceManagerServiceProxy*>(cookie);
+ thiz->binderDied();
+}
+
+void MediaCodec::ResourceManagerServiceProxy::binderDied() {
ALOGW("ResourceManagerService died.");
Mutex::Autolock _l(mLock);
- mService.clear();
+ mService = nullptr;
}
void MediaCodec::ResourceManagerServiceProxy::addResource(
- int64_t clientId,
- const sp<IResourceManagerClient> &client,
- const std::vector<MediaResourceParcel> &resources) {
+ const MediaResourceParcel &resource) {
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(resource);
+
Mutex::Autolock _l(mLock);
- if (mService == NULL) {
+ if (mService == nullptr) {
return;
}
- mService->addResource(mPid, mUid, clientId, client, resources);
+ mService->addResource(mPid, mUid, getId(mClient), mClient, resources);
}
void MediaCodec::ResourceManagerServiceProxy::removeResource(
- int64_t clientId,
- const std::vector<MediaResourceParcel> &resources) {
+ const MediaResourceParcel &resource) {
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(resource);
+
Mutex::Autolock _l(mLock);
- if (mService == NULL) {
+ if (mService == nullptr) {
return;
}
- mService->removeResource(mPid, clientId, resources);
+ mService->removeResource(mPid, getId(mClient), resources);
}
-void MediaCodec::ResourceManagerServiceProxy::removeClient(int64_t clientId) {
+void MediaCodec::ResourceManagerServiceProxy::removeClient() {
Mutex::Autolock _l(mLock);
- if (mService == NULL) {
+ if (mService == nullptr) {
return;
}
- mService->removeClient(mPid, clientId);
+ mService->removeClient(mPid, getId(mClient));
}
bool MediaCodec::ResourceManagerServiceProxy::reclaimResource(
@@ -579,19 +585,19 @@
mCpuBoostRequested(false),
mLatencyUnknown(0) {
if (uid == kNoUid) {
- mUid = IPCThreadState::self()->getCallingUid();
+ mUid = AIBinder_getCallingUid();
} else {
mUid = uid;
}
- mResourceManagerClient = new ResourceManagerClient(this);
- mResourceManagerService = new ResourceManagerServiceProxy(pid, mUid);
+ mResourceManagerProxy = new ResourceManagerServiceProxy(pid, mUid,
+ ::ndk::SharedRefBase::make<ResourceManagerClient>(this));
initMediametrics();
}
MediaCodec::~MediaCodec() {
CHECK_EQ(mState, UNINITIALIZED);
- mResourceManagerService->removeClient(getId(mResourceManagerClient));
+ mResourceManagerProxy->removeClient();
flushMediametrics();
}
@@ -792,7 +798,7 @@
if (mBatteryChecker != nullptr) {
mBatteryChecker->onCodecActivity([this] () {
- addResource(MediaResource::VideoBatteryResource());
+ mResourceManagerProxy->addResource(MediaResource::VideoBatteryResource());
});
}
@@ -832,7 +838,7 @@
if (mBatteryChecker != nullptr) {
mBatteryChecker->onCodecActivity([this] () {
- addResource(MediaResource::VideoBatteryResource());
+ mResourceManagerProxy->addResource(MediaResource::VideoBatteryResource());
});
}
@@ -942,7 +948,7 @@
}
status_t MediaCodec::init(const AString &name) {
- mResourceManagerService->init();
+ mResourceManagerProxy->init();
// save init parameters for reset
mInitName = name;
@@ -955,37 +961,41 @@
mCodecInfo.clear();
bool secureCodec = false;
- AString tmp = name;
- if (tmp.endsWith(".secure")) {
- secureCodec = true;
- tmp.erase(tmp.size() - 7, 7);
- }
- const sp<IMediaCodecList> mcl = MediaCodecList::getInstance();
- if (mcl == NULL) {
- mCodec = NULL; // remove the codec.
- return NO_INIT; // if called from Java should raise IOException
- }
- for (const AString &codecName : { name, tmp }) {
- ssize_t codecIdx = mcl->findCodecByName(codecName.c_str());
- if (codecIdx < 0) {
- continue;
+ const char *owner = "";
+ if (!name.startsWith("android.filter.")) {
+ AString tmp = name;
+ if (tmp.endsWith(".secure")) {
+ secureCodec = true;
+ tmp.erase(tmp.size() - 7, 7);
}
- mCodecInfo = mcl->getCodecInfo(codecIdx);
- Vector<AString> mediaTypes;
- mCodecInfo->getSupportedMediaTypes(&mediaTypes);
- for (size_t i = 0; i < mediaTypes.size(); i++) {
- if (mediaTypes[i].startsWith("video/")) {
- mIsVideo = true;
- break;
+ const sp<IMediaCodecList> mcl = MediaCodecList::getInstance();
+ if (mcl == NULL) {
+ mCodec = NULL; // remove the codec.
+ return NO_INIT; // if called from Java should raise IOException
+ }
+ for (const AString &codecName : { name, tmp }) {
+ ssize_t codecIdx = mcl->findCodecByName(codecName.c_str());
+ if (codecIdx < 0) {
+ continue;
}
+ mCodecInfo = mcl->getCodecInfo(codecIdx);
+ Vector<AString> mediaTypes;
+ mCodecInfo->getSupportedMediaTypes(&mediaTypes);
+ for (size_t i = 0; i < mediaTypes.size(); i++) {
+ if (mediaTypes[i].startsWith("video/")) {
+ mIsVideo = true;
+ break;
+ }
+ }
+ break;
}
- break;
- }
- if (mCodecInfo == nullptr) {
- return NAME_NOT_FOUND;
+ if (mCodecInfo == nullptr) {
+ return NAME_NOT_FOUND;
+ }
+ owner = mCodecInfo->getOwnerName();
}
- mCodec = GetCodecBase(name, mCodecInfo->getOwnerName());
+ mCodec = GetCodecBase(name, owner);
if (mCodec == NULL) {
return NAME_NOT_FOUND;
}
@@ -1014,9 +1024,11 @@
new BufferCallback(new AMessage(kWhatCodecNotify, this))));
sp<AMessage> msg = new AMessage(kWhatInit, this);
- msg->setObject("codecInfo", mCodecInfo);
- // name may be different from mCodecInfo->getCodecName() if we stripped
- // ".secure"
+ if (mCodecInfo) {
+ msg->setObject("codecInfo", mCodecInfo);
+ // name may be different from mCodecInfo->getCodecName() if we stripped
+ // ".secure"
+ }
msg->setString("name", name);
if (mMetricsHandle != 0) {
@@ -1035,7 +1047,7 @@
for (int i = 0; i <= kMaxRetry; ++i) {
if (i > 0) {
// Don't try to reclaim resource for the first time.
- if (!mResourceManagerService->reclaimResource(resources)) {
+ if (!mResourceManagerProxy->reclaimResource(resources)) {
break;
}
}
@@ -1150,7 +1162,7 @@
for (int i = 0; i <= kMaxRetry; ++i) {
if (i > 0) {
// Don't try to reclaim resource for the first time.
- if (!mResourceManagerService->reclaimResource(resources)) {
+ if (!mResourceManagerProxy->reclaimResource(resources)) {
break;
}
}
@@ -1271,19 +1283,6 @@
return size;
}
-void MediaCodec::addResource(const MediaResourceParcel &resource) {
- std::vector<MediaResourceParcel> resources;
- resources.push_back(resource);
- mResourceManagerService->addResource(
- getId(mResourceManagerClient), mResourceManagerClient, resources);
-}
-
-void MediaCodec::removeResource(const MediaResourceParcel &resource) {
- std::vector<MediaResourceParcel> resources;
- resources.push_back(resource);
- mResourceManagerService->removeResource(getId(mResourceManagerClient), resources);
-}
-
status_t MediaCodec::start() {
sp<AMessage> msg = new AMessage(kWhatStart, this);
@@ -1296,7 +1295,7 @@
for (int i = 0; i <= kMaxRetry; ++i) {
if (i > 0) {
// Don't try to reclaim resource for the first time.
- if (!mResourceManagerService->reclaimResource(resources)) {
+ if (!mResourceManagerProxy->reclaimResource(resources)) {
break;
}
// Recover codec from previous error before retry start.
@@ -1734,7 +1733,7 @@
totalPixel = width * height;
}
if (totalPixel >= 1920 * 1080) {
- addResource(MediaResource::CpuBoostResource());
+ mResourceManagerProxy->addResource(MediaResource::CpuBoostResource());
mCpuBoostRequested = true;
}
}
@@ -2070,9 +2069,9 @@
mComponentName.c_str());
}
- const char *owner = mCodecInfo->getOwnerName();
+ const char *owner = mCodecInfo ? mCodecInfo->getOwnerName() : "";
if (mComponentName.startsWith("OMX.google.")
- && (owner == nullptr || strncmp(owner, "default", 8) == 0)) {
+ && strncmp(owner, "default", 8) == 0) {
mFlags |= kFlagUsesSoftwareRenderer;
} else {
mFlags &= ~kFlagUsesSoftwareRenderer;
@@ -2089,7 +2088,8 @@
if (mIsVideo) {
// audio codec is currently ignored.
- addResource(MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));
+ mResourceManagerProxy->addResource(
+ MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));
}
(new AMessage)->postReply(mReplyID);
@@ -2210,8 +2210,8 @@
CHECK_EQ(mState, STARTING);
if (mIsVideo) {
- addResource(MediaResource::GraphicMemoryResource(
- getGraphicBufferSize()));
+ mResourceManagerProxy->addResource(
+ MediaResource::GraphicMemoryResource(getGraphicBufferSize()));
}
setState(STARTED);
(new AMessage)->postReply(mReplyID);
@@ -2435,7 +2435,7 @@
mBatteryChecker->onClientRemoved();
}
- mResourceManagerService->removeClient(getId(mResourceManagerClient));
+ mResourceManagerProxy->removeClient();
(new AMessage)->postReply(mReplyID);
break;
@@ -2480,12 +2480,14 @@
setState(INITIALIZING);
sp<RefBase> codecInfo;
- CHECK(msg->findObject("codecInfo", &codecInfo));
+ (void)msg->findObject("codecInfo", &codecInfo);
AString name;
CHECK(msg->findString("name", &name));
sp<AMessage> format = new AMessage;
- format->setObject("codecInfo", codecInfo);
+ if (codecInfo) {
+ format->setObject("codecInfo", codecInfo);
+ }
format->setString("componentName", name);
mCodec->initiateAllocateComponent(format);
@@ -3150,7 +3152,8 @@
{
if (mBatteryChecker != nullptr) {
mBatteryChecker->onCheckBatteryTimer(msg, [this] () {
- removeResource(MediaResource::VideoBatteryResource());
+ mResourceManagerProxy->removeResource(
+ MediaResource::VideoBatteryResource());
});
}
break;
diff --git a/media/libstagefright/MediaCodecListOverrides.cpp b/media/libstagefright/MediaCodecListOverrides.cpp
index 6b5b50e..4a167d1 100644
--- a/media/libstagefright/MediaCodecListOverrides.cpp
+++ b/media/libstagefright/MediaCodecListOverrides.cpp
@@ -265,7 +265,7 @@
}
}
global_results->add(
- MediaResourcePolicy::kPolicySupportsMultipleSecureCodecs().c_str(),
+ MediaResourcePolicy::kPolicySupportsMultipleSecureCodecs(),
supportMultipleSecureCodecs);
}
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index 120f354..2457561 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -27,8 +27,8 @@
#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MediaExtractorFactory.h>
-#include <media/IMediaExtractor.h>
-#include <media/IMediaExtractorService.h>
+#include <android/IMediaExtractor.h>
+#include <android/IMediaExtractorService.h>
#include <nativeloader/dlext_namespaces.h>
#include <private/android_filesystem_config.h>
#include <cutils/properties.h>
@@ -54,9 +54,13 @@
sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor"));
if (binder != 0) {
- sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder));
- sp<IMediaExtractor> ex = mediaExService->makeExtractor(
- CreateIDataSourceFromDataSource(source), mime);
+ sp<IMediaExtractorService> mediaExService(
+ interface_cast<IMediaExtractorService>(binder));
+ sp<IMediaExtractor> ex;
+ mediaExService->makeExtractor(
+ CreateIDataSourceFromDataSource(source),
+ mime ? std::make_unique<std::string>(mime) : nullptr,
+ &ex);
return ex;
} else {
ALOGE("extractor service not running");
@@ -262,7 +266,7 @@
return strcmp(first->def.extractor_name, second->def.extractor_name) < 0;
}
-static std::unordered_set<std::string> gSupportedExtensions;
+static std::vector<std::string> gSupportedExtensions;
// static
void MediaExtractorFactory::LoadExtractors() {
@@ -308,7 +312,7 @@
if (ext == nullptr) {
break;
}
- gSupportedExtensions.insert(std::string(ext));
+ gSupportedExtensions.push_back(std::string(ext));
}
}
}
@@ -317,7 +321,7 @@
}
// static
-std::unordered_set<std::string> MediaExtractorFactory::getSupportedTypes() {
+std::vector<std::string> MediaExtractorFactory::getSupportedTypes() {
if (getuid() == AID_MEDIA_EX) {
return gSupportedExtensions;
}
@@ -326,9 +330,11 @@
if (binder != 0) {
sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder));
- return mediaExService->getSupportedTypes();
+ std::vector<std::string> supportedTypes;
+ mediaExService->getSupportedTypes(&supportedTypes);
+ return supportedTypes;
}
- return std::unordered_set<std::string>();
+ return std::vector<std::string>();
}
status_t MediaExtractorFactory::dump(int fd, const Vector<String16>&) {
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index ce73676..6fd0805 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -35,7 +35,7 @@
StagefrightMediaScanner::~StagefrightMediaScanner() {}
-static std::unordered_set<std::string> gSupportedExtensions;
+static std::vector<std::string> gSupportedExtensions;
static bool FileHasAcceptableExtension(const char *extension) {
@@ -44,7 +44,12 @@
gSupportedExtensions = MediaExtractorFactory::getSupportedTypes();
}
- return gSupportedExtensions.count(std::string(extension + 1)) != 0;
+ for (auto ext: gSupportedExtensions) {
+ if (ext == (extension + 1)) {
+ return true;
+ }
+ }
+ return false;
}
MediaScanResult StagefrightMediaScanner::processFile(
diff --git a/media/libstagefright/filters/MediaFilter.cpp b/media/libstagefright/filters/MediaFilter.cpp
index 777ab5b..c7baa73 100644
--- a/media/libstagefright/filters/MediaFilter.cpp
+++ b/media/libstagefright/filters/MediaFilter.cpp
@@ -20,13 +20,12 @@
#include <inttypes.h>
#include <utils/Trace.h>
-#include <binder/MemoryDealer.h>
-
-#include <media/stagefright/BufferProducerWrapper.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/BufferProducerWrapper.h>
+#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaFilter.h>
@@ -42,11 +41,121 @@
#include "SaturationFilter.h"
#include "ZeroFilter.h"
-#include "../include/ACodecBufferChannel.h"
-#include "../include/SharedMemoryBuffer.h"
-
namespace android {
+class MediaFilter::BufferChannel : public BufferChannelBase {
+public:
+ BufferChannel(const sp<AMessage> &in, const sp<AMessage> &out)
+ : mInputBufferFilled(in), mOutputBufferDrained(out) {
+ }
+
+ ~BufferChannel() override = default;
+
+ // BufferChannelBase
+
+ status_t queueInputBuffer(const sp<MediaCodecBuffer> &buffer) override {
+ sp<AMessage> msg = mInputBufferFilled->dup();
+ msg->setObject("buffer", buffer);
+ msg->post();
+ return OK;
+ }
+
+ status_t queueSecureInputBuffer(
+ const sp<MediaCodecBuffer> &,
+ bool,
+ const uint8_t *,
+ const uint8_t *,
+ CryptoPlugin::Mode,
+ CryptoPlugin::Pattern,
+ const CryptoPlugin::SubSample *,
+ size_t,
+ AString *) override {
+ return INVALID_OPERATION;
+ }
+
+ status_t renderOutputBuffer(
+ const sp<MediaCodecBuffer> &buffer, int64_t /* timestampNs */) override {
+ sp<AMessage> msg = mOutputBufferDrained->dup();
+ msg->setObject("buffer", buffer);
+ msg->post();
+ return OK;
+ }
+
+ status_t discardBuffer(const sp<MediaCodecBuffer> &buffer) override {
+ if (FindBufferIndex(&mInputBuffers, buffer) >= 0) {
+ sp<AMessage> msg = mInputBufferFilled->dup();
+ msg->setObject("buffer", buffer);
+ msg->post();
+ return OK;
+ }
+ sp<AMessage> msg = mOutputBufferDrained->dup();
+ msg->setObject("buffer", buffer);
+ msg->post();
+ return OK;
+ }
+
+ void getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
+ if (!array) {
+ return;
+ }
+ array->clear();
+ array->appendVector(mInputBuffers);
+ }
+
+ void getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
+ if (!array) {
+ return;
+ }
+ array->clear();
+ array->appendVector(mOutputBuffers);
+ }
+
+ // For MediaFilter
+
+ void fillThisBuffer(const sp<MediaCodecBuffer> &buffer) {
+ ssize_t index = FindBufferIndex(&mInputBuffers, buffer);
+ mCallback->onInputBufferAvailable(index, buffer);
+ }
+
+ void drainThisBuffer(const sp<MediaCodecBuffer> &buffer, int flags) {
+ ssize_t index = FindBufferIndex(&mOutputBuffers, buffer);
+ buffer->meta()->setInt32("flags", flags);
+ mCallback->onOutputBufferAvailable(index, buffer);
+ }
+
+ template <class T>
+ void setInputBuffers(T begin, T end) {
+ mInputBuffers.clear();
+ for (T it = begin; it != end; ++it) {
+ mInputBuffers.push_back(it->mData);
+ }
+ }
+
+ template <class T>
+ void setOutputBuffers(T begin, T end) {
+ mOutputBuffers.clear();
+ for (T it = begin; it != end; ++it) {
+ mOutputBuffers.push_back(it->mData);
+ }
+ }
+
+private:
+ sp<AMessage> mInputBufferFilled;
+ sp<AMessage> mOutputBufferDrained;
+ Vector<sp<MediaCodecBuffer>> mInputBuffers;
+ Vector<sp<MediaCodecBuffer>> mOutputBuffers;
+
+ static ssize_t FindBufferIndex(
+ Vector<sp<MediaCodecBuffer>> *array, const sp<MediaCodecBuffer> &buffer) {
+ for (size_t i = 0; i < array->size(); ++i) {
+ if (array->itemAt(i) == buffer) {
+ return i;
+ }
+ }
+ return -1;
+ }
+};
+
// parameter: number of input and output buffers
static const size_t kBufferCountActual = 4;
@@ -54,9 +163,6 @@
: mState(UNINITIALIZED),
mGeneration(0),
mGraphicBufferListener(NULL) {
- mBufferChannel = std::make_shared<ACodecBufferChannel>(
- new AMessage(kWhatInputBufferFilled, this),
- new AMessage(kWhatOutputBufferDrained, this));
}
MediaFilter::~MediaFilter() {
@@ -65,6 +171,11 @@
//////////////////// PUBLIC FUNCTIONS //////////////////////////////////////////
std::shared_ptr<BufferChannelBase> MediaFilter::getBufferChannel() {
+ if (!mBufferChannel) {
+ mBufferChannel = std::make_shared<BufferChannel>(
+ new AMessage(kWhatInputBufferFilled, this),
+ new AMessage(kWhatOutputBufferDrained, this));
+ }
return mBufferChannel;
}
@@ -212,28 +323,23 @@
const bool isInput = portIndex == kPortIndexInput;
const size_t bufferSize = isInput ? mMaxInputSize : mMaxOutputSize;
- CHECK(mDealer[portIndex] == NULL);
CHECK(mBuffers[portIndex].isEmpty());
ALOGV("Allocating %zu buffers of size %zu on %s port",
kBufferCountActual, bufferSize,
isInput ? "input" : "output");
- size_t totalSize = kBufferCountActual * bufferSize;
-
- mDealer[portIndex] = new MemoryDealer(totalSize, "MediaFilter");
-
+ // trigger output format change
+ sp<AMessage> outputFormat = mOutputFormat->dup();
for (size_t i = 0; i < kBufferCountActual; ++i) {
- sp<IMemory> mem = mDealer[portIndex]->allocate(bufferSize);
- CHECK(mem.get() != NULL);
-
BufferInfo info;
info.mStatus = BufferInfo::OWNED_BY_US;
info.mBufferID = i;
info.mGeneration = mGeneration;
info.mOutputFlags = 0;
- info.mData = new SharedMemoryBuffer(
- isInput ? mInputFormat : mOutputFormat, mem);
+ info.mData = new MediaCodecBuffer(
+ isInput ? mInputFormat : outputFormat,
+ new ABuffer(bufferSize));
info.mData->meta()->setInt64("timeUs", 0);
mBuffers[portIndex].push_back(info);
@@ -243,27 +349,24 @@
&mBuffers[portIndex].editItemAt(i));
}
}
-
- std::vector<ACodecBufferChannel::BufferAndId> array(mBuffers[portIndex].size());
- for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
- array[i] = {mBuffers[portIndex][i].mData, mBuffers[portIndex][i].mBufferID};
- }
- if (portIndex == kPortIndexInput) {
- mBufferChannel->setInputBufferArray(array);
+ if (isInput) {
+ mBufferChannel->setInputBuffers(
+ mBuffers[portIndex].begin(), mBuffers[portIndex].end());
} else {
- mBufferChannel->setOutputBufferArray(array);
+ mBufferChannel->setOutputBuffers(
+ mBuffers[portIndex].begin(), mBuffers[portIndex].end());
}
return OK;
}
-MediaFilter::BufferInfo* MediaFilter::findBufferByID(
- uint32_t portIndex, IOMX::buffer_id bufferID,
+MediaFilter::BufferInfo* MediaFilter::findBuffer(
+ uint32_t portIndex, const sp<MediaCodecBuffer> &buffer,
ssize_t *index) {
for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
BufferInfo *info = &mBuffers[portIndex].editItemAt(i);
- if (info->mBufferID == bufferID) {
+ if (info->mData == buffer) {
if (index != NULL) {
*index = i;
}
@@ -293,7 +396,7 @@
info->mStatus = BufferInfo::OWNED_BY_UPSTREAM;
- mBufferChannel->fillThisBuffer(info->mBufferID);
+ mBufferChannel->fillThisBuffer(info->mData);
}
void MediaFilter::postDrainThisBuffer(BufferInfo *info) {
@@ -304,7 +407,7 @@
sp<AMessage> reply = new AMessage(kWhatOutputBufferDrained, this);
reply->setInt32("buffer-id", info->mBufferID);
- mBufferChannel->drainThisBuffer(info->mBufferID, info->mOutputFlags);
+ mBufferChannel->drainThisBuffer(info->mData, info->mOutputFlags);
info->mStatus = BufferInfo::OWNED_BY_UPSTREAM;
}
@@ -359,7 +462,7 @@
outputInfo->mOutputFlags = 0;
int32_t eos = 0;
if (inputInfo->mData->meta()->findInt32("eos", &eos) && eos != 0) {
- outputInfo->mOutputFlags |= OMX_BUFFERFLAG_EOS;
+ outputInfo->mOutputFlags |= BUFFER_FLAG_END_OF_STREAM;
mPortEOS[kPortIndexOutput] = true;
outputInfo->mData->meta()->setInt32("eos", eos);
postEOS();
@@ -400,8 +503,7 @@
return;
}
- // HACK - need "OMX.google" to use MediaCodec's software renderer
- mCallback->onComponentAllocated("OMX.google.MediaFilter");
+ mCallback->onComponentAllocated(mComponentName.c_str());
mState = INITIALIZED;
ALOGV("Handled kWhatAllocateComponent.");
}
@@ -477,6 +579,7 @@
mOutputFormat->setRect("crop", 0, 0, mStride, mSliceHeight);
mOutputFormat->setInt32("width", mWidth);
mOutputFormat->setInt32("height", mHeight);
+ mOutputFormat->setInt32("using-sw-renderer", 1);
mCallback->onComponentConfigured(mInputFormat, mOutputFormat);
mState = CONFIGURED;
@@ -509,9 +612,11 @@
}
void MediaFilter::onInputBufferFilled(const sp<AMessage> &msg) {
- IOMX::buffer_id bufferID;
- CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID));
- BufferInfo *info = findBufferByID(kPortIndexInput, bufferID);
+ sp<RefBase> obj;
+ CHECK(msg->findObject("buffer", &obj));
+ sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
+ ssize_t index = -1;
+ BufferInfo *info = findBuffer(kPortIndexInput, buffer, &index);
if (mState != STARTED) {
// we're not running, so we'll just keep that buffer...
@@ -520,7 +625,7 @@
}
if (info->mGeneration != mGeneration) {
- ALOGV("Caught a stale input buffer [ID %d]", bufferID);
+ ALOGV("Caught a stale input buffer [index %zd]", index);
// buffer is stale (taken before a flush/shutdown) - repost it
CHECK_EQ(info->mStatus, BufferInfo::OWNED_BY_US);
postFillThisBuffer(info);
@@ -530,30 +635,9 @@
CHECK_EQ(info->mStatus, BufferInfo::OWNED_BY_UPSTREAM);
info->mStatus = BufferInfo::OWNED_BY_US;
- sp<MediaCodecBuffer> buffer;
int32_t err = OK;
bool eos = false;
- sp<RefBase> obj;
- if (!msg->findObject("buffer", &obj)) {
- // these are unfilled buffers returned by client
- CHECK(msg->findInt32("err", &err));
-
- if (err == OK) {
- // buffers with no errors are returned on MediaCodec.flush
- ALOGV("saw unfilled buffer (MediaCodec.flush)");
- postFillThisBuffer(info);
- return;
- } else {
- ALOGV("saw error %d instead of an input buffer", err);
- eos = true;
- }
-
- buffer.clear();
- } else {
- buffer = static_cast<MediaCodecBuffer *>(obj.get());
- }
-
int32_t isCSD;
if (buffer != NULL && buffer->meta()->findInt32("csd", &isCSD)
&& isCSD != 0) {
@@ -577,13 +661,15 @@
mInputEOSResult = err;
}
- ALOGV("Handled kWhatInputBufferFilled. [ID %u]", bufferID);
+ ALOGV("Handled kWhatInputBufferFilled. [index %zd]", index);
}
void MediaFilter::onOutputBufferDrained(const sp<AMessage> &msg) {
- IOMX::buffer_id bufferID;
- CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID));
- BufferInfo *info = findBufferByID(kPortIndexOutput, bufferID);
+ sp<RefBase> obj;
+ CHECK(msg->findObject("buffer", &obj));
+ sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
+ ssize_t index = -1;
+ BufferInfo *info = findBuffer(kPortIndexOutput, buffer, &index);
if (mState != STARTED) {
// we're not running, so we'll just keep that buffer...
@@ -592,7 +678,7 @@
}
if (info->mGeneration != mGeneration) {
- ALOGV("Caught a stale output buffer [ID %d]", bufferID);
+ ALOGV("Caught a stale output buffer [index %zd]", index);
// buffer is stale (taken before a flush/shutdown) - keep it
CHECK_EQ(info->mStatus, BufferInfo::OWNED_BY_US);
return;
@@ -605,8 +691,7 @@
processBuffers();
- ALOGV("Handled kWhatOutputBufferDrained. [ID %u]",
- bufferID);
+ ALOGV("Handled kWhatOutputBufferDrained. [index %zd]", index);
}
void MediaFilter::onShutdown(const sp<AMessage> &msg) {
@@ -739,7 +824,7 @@
return;
}
- eosBuf->mOutputFlags = OMX_BUFFERFLAG_EOS;
+ eosBuf->mOutputFlags = BUFFER_FLAG_END_OF_STREAM;
eosBuf->mGeneration = mGeneration;
eosBuf->mData->setRange(0, 0);
postDrainThisBuffer(eosBuf);
diff --git a/media/libstagefright/include/ACodecBufferChannel.h b/media/libstagefright/include/ACodecBufferChannel.h
index 3a087d1..5f65575 100644
--- a/media/libstagefright/include/ACodecBufferChannel.h
+++ b/media/libstagefright/include/ACodecBufferChannel.h
@@ -67,6 +67,9 @@
virtual ~ACodecBufferChannel();
// BufferChannelBase interface
+ void setCrypto(const sp<ICrypto> &crypto) override;
+ void setDescrambler(const sp<IDescrambler> &descrambler) override;
+
virtual status_t queueInputBuffer(const sp<MediaCodecBuffer> &buffer) override;
virtual status_t queueSecureInputBuffer(
const sp<MediaCodecBuffer> &buffer,
@@ -135,6 +138,9 @@
sp<MemoryDealer> makeMemoryDealer(size_t heapSize);
+ sp<ICrypto> mCrypto;
+ sp<IDescrambler> mDescrambler;
+
bool hasCryptoOrDescrambler() {
return mCrypto != NULL || mDescrambler != NULL;
}
diff --git a/media/libstagefright/include/media/stagefright/CodecBase.h b/media/libstagefright/include/media/stagefright/CodecBase.h
index e728c00..bc7881c 100644
--- a/media/libstagefright/include/media/stagefright/CodecBase.h
+++ b/media/libstagefright/include/media/stagefright/CodecBase.h
@@ -257,15 +257,15 @@
*/
class BufferChannelBase {
public:
+ BufferChannelBase() = default;
virtual ~BufferChannelBase() = default;
inline void setCallback(std::unique_ptr<CodecBase::BufferCallback> &&callback) {
mCallback = std::move(callback);
}
- void setCrypto(const sp<ICrypto> &crypto);
-
- void setDescrambler(const sp<IDescrambler> &descrambler);
+ virtual void setCrypto(const sp<ICrypto> &) {}
+ virtual void setDescrambler(const sp<IDescrambler> &) {}
/**
* Queue an input buffer into the buffer channel.
@@ -336,8 +336,6 @@
protected:
std::unique_ptr<CodecBase::BufferCallback> mCallback;
- sp<ICrypto> mCrypto;
- sp<IDescrambler> mDescrambler;
};
} // namespace android
diff --git a/media/libstagefright/include/media/stagefright/InterfaceUtils.h b/media/libstagefright/include/media/stagefright/InterfaceUtils.h
index b83a958..671f2ff 100644
--- a/media/libstagefright/include/media/stagefright/InterfaceUtils.h
+++ b/media/libstagefright/include/media/stagefright/InterfaceUtils.h
@@ -20,7 +20,7 @@
#include <utils/RefBase.h>
#include <media/stagefright/RemoteMediaExtractor.h>
#include <media/MediaSource.h>
-#include <media/IMediaExtractor.h>
+#include <android/IMediaExtractor.h>
#include <media/IMediaSource.h>
namespace android {
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 78d00b1..78cb01c 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -29,6 +29,14 @@
#include <media/stagefright/FrameRenderTracker.h>
#include <utils/Vector.h>
+namespace aidl {
+namespace android {
+namespace media {
+class MediaResourceParcel;
+} // media
+} // android
+} // aidl
+
namespace android {
struct ABuffer;
@@ -51,13 +59,9 @@
namespace V1_0 {
struct IDescrambler;
}}}}
-namespace media {
-class IResourceManagerClient;
-class MediaResourceParcel;
-}
+
using hardware::cas::native::V1_0::IDescrambler;
-using media::IResourceManagerClient;
-using media::MediaResourceParcel;
+using aidl::android::media::MediaResourceParcel;
struct MediaCodec : public AHandler {
enum ConfigureFlags {
@@ -315,8 +319,7 @@
sp<AMessage> mCallback;
sp<AMessage> mOnFrameRenderedNotification;
- sp<IResourceManagerClient> mResourceManagerClient;
- sp<ResourceManagerServiceProxy> mResourceManagerService;
+ sp<ResourceManagerServiceProxy> mResourceManagerProxy;
bool mIsVideo;
int32_t mVideoWidth;
@@ -410,8 +413,6 @@
bool isExecuting() const;
uint64_t getGraphicBufferSize();
- void addResource(const MediaResourceParcel &resource);
- void removeResource(const MediaResourceParcel &resource);
void requestCpuBoostIfNeeded();
bool hasPendingBuffer(int portIndex);
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
index 2ab98e1..745e342 100644
--- a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
+++ b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
@@ -22,7 +22,7 @@
#include <unordered_set>
#include <android/dlext.h>
-#include <media/IMediaExtractor.h>
+#include <android/IMediaExtractor.h>
namespace android {
@@ -36,7 +36,7 @@
static sp<IMediaExtractor> CreateFromService(
const sp<DataSource> &source, const char *mime = NULL);
static status_t dump(int fd, const Vector<String16>& args);
- static std::unordered_set<std::string> getSupportedTypes();
+ static std::vector<std::string> getSupportedTypes();
static void LoadExtractors();
private:
diff --git a/media/libstagefright/include/media/stagefright/MediaFilter.h b/media/libstagefright/include/media/stagefright/MediaFilter.h
index a28c49d..1255e0f 100644
--- a/media/libstagefright/include/media/stagefright/MediaFilter.h
+++ b/media/libstagefright/include/media/stagefright/MediaFilter.h
@@ -21,9 +21,7 @@
namespace android {
-class ACodecBufferChannel;
struct GraphicBufferListener;
-class MemoryDealer;
struct SimpleFilter;
struct MediaFilter : public CodecBase {
@@ -65,6 +63,8 @@
sp<MediaCodecBuffer> mData;
};
+ class BufferChannel;
+
enum State {
UNINITIALIZED,
INITIALIZED,
@@ -104,7 +104,6 @@
sp<AMessage> mInputFormat;
sp<AMessage> mOutputFormat;
- sp<MemoryDealer> mDealer[2];
Vector<BufferInfo> mBuffers[2];
Vector<BufferInfo*> mAvailableInputBuffers;
Vector<BufferInfo*> mAvailableOutputBuffers;
@@ -113,15 +112,15 @@
sp<SimpleFilter> mFilter;
sp<GraphicBufferListener> mGraphicBufferListener;
- std::shared_ptr<ACodecBufferChannel> mBufferChannel;
+ std::shared_ptr<BufferChannel> mBufferChannel;
// helper functions
void signalProcessBuffers();
void signalError(status_t error);
status_t allocateBuffersOnPort(OMX_U32 portIndex);
- BufferInfo *findBufferByID(
- uint32_t portIndex, uint32_t bufferID,
+ BufferInfo *findBuffer(
+ uint32_t portIndex, const sp<MediaCodecBuffer> &buffer,
ssize_t *index = NULL);
void postFillThisBuffer(BufferInfo *info);
void postDrainThisBuffer(BufferInfo *info);
diff --git a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
index 4307110..98e4b22 100644
--- a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
@@ -21,7 +21,7 @@
#include <media/mediaplayer.h>
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/foundation/AudioPresentationInfo.h>
-#include <media/IMediaExtractor.h>
+#include <android/IMediaExtractor.h>
#include <media/MediaSource.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
diff --git a/media/libstagefright/include/media/stagefright/RemoteDataSource.h b/media/libstagefright/include/media/stagefright/RemoteDataSource.h
index 83273cb..d82be8a 100644
--- a/media/libstagefright/include/media/stagefright/RemoteDataSource.h
+++ b/media/libstagefright/include/media/stagefright/RemoteDataSource.h
@@ -17,10 +17,10 @@
#ifndef REMOTE_DATA_SOURCE_H_
#define REMOTE_DATA_SOURCE_H_
+#include <android/IDataSource.h>
#include <binder/IMemory.h>
#include <binder/MemoryDealer.h>
#include <media/DataSource.h>
-#include <media/IDataSource.h>
namespace android {
diff --git a/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
index 9925114..2bf5a8b 100644
--- a/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
@@ -17,7 +17,7 @@
#ifndef REMOTE_MEDIA_EXTRACTOR_H_
#define REMOTE_MEDIA_EXTRACTOR_H_
-#include <media/IMediaExtractor.h>
+#include <android/IMediaExtractor.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/foundation/ABase.h>
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index 1f65372..7b22b05 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -40,7 +40,7 @@
ALOGI("ServiceManager: %p", sm.get());
AIcu_initializeIcuOrDie();
MediaPlayerService::instantiate();
- media::ResourceManagerService::instantiate();
+ ResourceManagerService::instantiate();
registerExtensions();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 0eb46f4..f83d530 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -79,7 +79,6 @@
"android.hidl.token@1.0-utils",
"libandroid_runtime_lazy",
"libbase",
- "libbinder",
"libdatasource",
"libmedia",
"libmediadrm",
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index 8a95982..3af9771 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -20,6 +20,10 @@
#include <inttypes.h>
#include <unistd.h>
+#include <iostream>
+#include <fstream>
+#include <string>
+
#include <media/NdkMediaDrm.h>
#include <cutils/properties.h>
@@ -28,12 +32,10 @@
#include <gui/Surface.h>
#include <android-base/properties.h>
-#include <binder/PermissionController.h>
#include <mediadrm/DrmUtils.h>
#include <mediadrm/IDrm.h>
#include <mediadrm/IDrmClient.h>
#include <media/stagefright/MediaErrors.h>
-#include <binder/IServiceManager.h>
#include <media/NdkMediaCrypto.h>
@@ -236,24 +238,15 @@
}
static status_t GetAppPackageName(String8 *packageName) {
- sp<IServiceManager> serviceManager = defaultServiceManager();
- sp<IBinder> binder = serviceManager->getService(String16("permission"));
-
- sp<IPermissionController> permissionContol = interface_cast<IPermissionController>(binder);
- if (permissionContol == NULL) {
- ALOGE("Failed to get permission service");
+ // todo(robertshih): use refactored/renamed libneuralnetworks_packageinfo which is stable
+ std::string appName;
+ std::ifstream cmdline("/proc/self/cmdline");
+ std::getline(cmdline, appName);
+ cmdline.close();
+ if (appName.empty()) {
return UNKNOWN_ERROR;
}
-
- Vector<String16> packages;
- permissionContol->getPackagesForUid(getuid(), packages);
-
- if (packages.isEmpty()) {
- ALOGE("Unable to get package name for current UID");
- return UNKNOWN_ERROR;
- }
-
- *packageName = String8(packages[0]);
+ *packageName = String8(appName.c_str());
return OK;
}
diff --git a/media/ndk/include/media/NdkMediaMuxer.h b/media/ndk/include/media/NdkMediaMuxer.h
index 3fdeea4..9de3fbf 100644
--- a/media/ndk/include/media/NdkMediaMuxer.h
+++ b/media/ndk/include/media/NdkMediaMuxer.h
@@ -51,6 +51,7 @@
typedef enum {
AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4 = 0,
AMEDIAMUXER_OUTPUT_FORMAT_WEBM = 1,
+ AMEDIAMUXER_OUTPUT_FORMAT_THREE_GPP = 2,
} OutputFormat;
#if __ANDROID_API__ >= 21
diff --git a/media/utils/ISchedulingPolicyService.cpp b/media/utils/ISchedulingPolicyService.cpp
index b210404..e60e230 100644
--- a/media/utils/ISchedulingPolicyService.cpp
+++ b/media/utils/ISchedulingPolicyService.cpp
@@ -62,12 +62,12 @@
return reply.readInt32();
}
- virtual int requestCpusetBoost(bool enable, const sp<IInterface>& client)
+ virtual int requestCpusetBoost(bool enable, const sp<IBinder>& client)
{
Parcel data, reply;
data.writeInterfaceToken(ISchedulingPolicyService::getInterfaceDescriptor());
data.writeInt32(enable);
- data.writeStrongBinder(IInterface::asBinder(client));
+ data.writeStrongBinder(client);
status_t status = remote()->transact(REQUEST_CPUSET_BOOST, data, &reply, 0);
if (status != NO_ERROR) {
return status;
diff --git a/media/utils/ISchedulingPolicyService.h b/media/utils/ISchedulingPolicyService.h
index e4f7c0d..6fa100a 100644
--- a/media/utils/ISchedulingPolicyService.h
+++ b/media/utils/ISchedulingPolicyService.h
@@ -29,7 +29,7 @@
virtual int requestPriority(/*pid_t*/int32_t pid, /*pid_t*/int32_t tid,
int32_t prio, bool isForApp, bool asynchronous) = 0;
- virtual int requestCpusetBoost(bool enable, const sp<IInterface>& client) = 0;
+ virtual int requestCpusetBoost(bool enable, const sp<IBinder>& client) = 0;
};
class BnSchedulingPolicyService : public BnInterface<ISchedulingPolicyService>
diff --git a/media/utils/SchedulingPolicyService.cpp b/media/utils/SchedulingPolicyService.cpp
index 4e9792f..ad38862 100644
--- a/media/utils/SchedulingPolicyService.cpp
+++ b/media/utils/SchedulingPolicyService.cpp
@@ -59,7 +59,7 @@
return ret;
}
-int requestCpusetBoost(bool enable, const sp<IInterface> &client)
+int requestCpusetBoost(bool enable, const sp<IBinder> &client)
{
int ret;
sMutex.lock();
diff --git a/media/utils/include/mediautils/SchedulingPolicyService.h b/media/utils/include/mediautils/SchedulingPolicyService.h
index a33539f..546cec5 100644
--- a/media/utils/include/mediautils/SchedulingPolicyService.h
+++ b/media/utils/include/mediautils/SchedulingPolicyService.h
@@ -21,7 +21,7 @@
namespace android {
-class IInterface;
+class IBinder;
// Request elevated priority for thread tid, whose thread group leader must be pid.
// The priority parameter is currently restricted to either 1 or 2.
// The asynchronous parameter should be 'true' to return immediately,
@@ -35,7 +35,7 @@
// for the server to receive death notifications. When 'enable' is 'false', server
// will attempt to move media.codec process back to the original cpuset, and
// 'client' is ignored in this case.
-int requestCpusetBoost(bool enable, const sp<IInterface> &client);
+int requestCpusetBoost(bool enable, const sp<IBinder> &client);
} // namespace android
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 9756abb..6ecb356 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1589,33 +1589,58 @@
proposed.format = format;
sp<DeviceHalInterface> dev = mPrimaryHardwareDev->hwDevice();
- size_t frames = 0;
- for (;;) {
- // Note: config is currently a const parameter for get_input_buffer_size()
- // but we use a copy from proposed in case config changes from the call.
- config = proposed;
- status_t result = dev->getInputBufferSize(&config, &frames);
- if (result == OK && frames != 0) {
- break; // hal success, config is the result
- }
- // change one parameter of the configuration each iteration to a more "common" value
- // to see if the device will support it.
- if (proposed.format != AUDIO_FORMAT_PCM_16_BIT) {
- proposed.format = AUDIO_FORMAT_PCM_16_BIT;
- } else if (proposed.sample_rate != 44100) { // 44.1 is claimed as must in CDD as well as
- proposed.sample_rate = 44100; // legacy AudioRecord.java. TODO: Query hw?
- } else {
- ALOGW("getInputBufferSize failed with minimum buffer size sampleRate %u, "
- "format %#x, channelMask 0x%X",
- sampleRate, format, channelMask);
- break; // retries failed, break out of loop with frames == 0.
- }
- }
+ std::vector<audio_channel_mask_t> channelMasks = {channelMask};
+ if (channelMask != AUDIO_CHANNEL_IN_MONO)
+ channelMasks.push_back(AUDIO_CHANNEL_IN_MONO);
+ if (channelMask != AUDIO_CHANNEL_IN_STEREO)
+ channelMasks.push_back(AUDIO_CHANNEL_IN_STEREO);
+
+ std::vector<audio_format_t> formats = {format};
+ if (format != AUDIO_FORMAT_PCM_16_BIT)
+ formats.push_back(AUDIO_FORMAT_PCM_16_BIT);
+
+ std::vector<uint32_t> sampleRates = {sampleRate};
+ static const uint32_t SR_44100 = 44100;
+ static const uint32_t SR_48000 = 48000;
+
+ if (sampleRate != SR_48000)
+ sampleRates.push_back(SR_48000);
+ if (sampleRate != SR_44100)
+ sampleRates.push_back(SR_44100);
+
mHardwareStatus = AUDIO_HW_IDLE;
- if (frames > 0 && config.sample_rate != sampleRate) {
- frames = destinationFramesPossible(frames, sampleRate, config.sample_rate);
+
+ for (auto testChannelMask : channelMasks) {
+ config.channel_mask = testChannelMask;
+ for (auto testFormat : formats) {
+ config.format = testFormat;
+ for (auto testSampleRate : sampleRates) {
+ config.sample_rate = testSampleRate;
+ size_t bytes = 0;
+ status_t result = dev->getInputBufferSize(&config, &bytes);
+ if (result != OK || bytes == 0) {
+ continue;
+ }
+
+ if (config.sample_rate != sampleRate || config.channel_mask != channelMask ||
+ config.format != format) {
+ uint32_t dstChannelCount = audio_channel_count_from_in_mask(channelMask);
+ uint32_t srcChannelCount =
+ audio_channel_count_from_in_mask(config.channel_mask);
+ size_t srcFrames =
+ bytes / audio_bytes_per_frame(srcChannelCount, config.format);
+ size_t dstFrames = destinationFramesPossible(
+ srcFrames, config.sample_rate, sampleRate);
+ bytes = dstFrames * audio_bytes_per_frame(dstChannelCount, format);
+ }
+ return bytes;
+ }
+ }
}
- return frames; // may be converted to bytes at the Java level.
+
+ ALOGW("getInputBufferSize failed with minimum buffer size sampleRate %u, "
+ "format %#x, channelMask %#x",sampleRate, format, channelMask);
+ return 0;
}
uint32_t AudioFlinger::getInputFramesLost(audio_io_handle_t ioHandle) const
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 4be21b1..357e432 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1825,7 +1825,7 @@
// TODO: We may also match on address as well as device type for
// AUDIO_DEVICE_OUT_BUS, AUDIO_DEVICE_OUT_ALL_A2DP, AUDIO_DEVICE_OUT_REMOTE_SUBMIX
- if (type == MIXER || type == DIRECT) {
+ if (type == MIXER || type == DIRECT || type == OFFLOAD) {
// TODO: This property should be ensure that only contains one single device type.
mTimestampCorrectedDevice = (audio_devices_t)property_get_int64(
"audio.timestamp.corrected_output_device",
@@ -3616,7 +3616,13 @@
// Tally underrun frames as we are inserting 0s here.
for (const auto& track : activeTracks) {
- if (track->mFillingUpStatus == Track::FS_ACTIVE) {
+ if (track->mFillingUpStatus == Track::FS_ACTIVE
+ && !track->isStopped()
+ && !track->isPaused()
+ && !track->isTerminated()) {
+ ALOGV("%s: track(%d) %s underrun due to thread sleep of %zu frames",
+ __func__, track->id(), track->getTrackStateAsString(),
+ mNormalFrameCount);
track->mAudioTrackServerProxy->tallyUnderrunFrames(mNormalFrameCount);
}
}
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 051f1e3..91dbfa4 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -202,6 +202,38 @@
audio_format_t format() const { return mFormat; }
int id() const { return mId; }
+ const char *getTrackStateAsString() const {
+ if (isTerminated()) {
+ return "TERMINATED";
+ }
+ switch (mState) {
+ case IDLE:
+ return "IDLE";
+ case STOPPING_1: // for Fast and Offload
+ return "STOPPING_1";
+ case STOPPING_2: // for Fast and Offload
+ return "STOPPING_2";
+ case STOPPED:
+ return "STOPPED";
+ case RESUMING:
+ return "RESUMING";
+ case ACTIVE:
+ return "ACTIVE";
+ case PAUSING:
+ return "PAUSING";
+ case PAUSED:
+ return "PAUSED";
+ case FLUSHED:
+ return "FLUSHED";
+ case STARTING_1: // for RecordTrack
+ return "STARTING_1";
+ case STARTING_2: // for RecordTrack
+ return "STARTING_2";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
protected:
DISALLOW_COPY_AND_ASSIGN(TrackBase);
@@ -248,7 +280,7 @@
// Upper case characters are final states.
// Lower case characters are transitory.
- const char *getTrackStateString() const {
+ const char *getTrackStateAsCodedString() const {
if (isTerminated()) {
return "T ";
}
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 23c2209..2437202 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -743,7 +743,7 @@
(mClient == 0) ? getpid() : mClient->pid(),
mSessionId,
mPortId,
- getTrackStateString(),
+ getTrackStateAsCodedString(),
mCblk->mFlags,
mFormat,
@@ -2241,7 +2241,7 @@
(mClient == 0) ? getpid() : mClient->pid(),
mSessionId,
mPortId,
- getTrackStateString(),
+ getTrackStateAsCodedString(),
mCblk->mFlags,
mFormat,
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 3188892..2541365 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -5130,6 +5130,7 @@
*lastFrameNumber = mRepeatingLastFrameNumber;
}
mRepeatingLastFrameNumber = hardware::camera2::ICameraDeviceUser::NO_IN_FLIGHT_REPEATING_FRAMES;
+ mRequestSignal.signal();
return OK;
}
diff --git a/services/mediaanalytics/Android.bp b/services/mediaanalytics/Android.bp
index dc72064..2eaabe1 100644
--- a/services/mediaanalytics/Android.bp
+++ b/services/mediaanalytics/Android.bp
@@ -30,6 +30,7 @@
name: "libmediaanalyticsservice",
srcs: [
+ "AudioAnalytics.cpp",
"iface_statsd.cpp",
"MediaAnalyticsService.cpp",
"statsd_audiopolicy.cpp",
diff --git a/services/mediaanalytics/AudioAnalytics.cpp b/services/mediaanalytics/AudioAnalytics.cpp
new file mode 100644
index 0000000..638c4ab
--- /dev/null
+++ b/services/mediaanalytics/AudioAnalytics.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AudioAnalytics"
+#include <utils/Log.h>
+
+#include "AudioAnalytics.h"
+
+#include <audio_utils/clock.h> // clock conversions
+
+namespace android::mediametrics {
+
+AudioAnalytics::AudioAnalytics()
+{
+ ALOGD("%s", __func__);
+}
+
+AudioAnalytics::~AudioAnalytics()
+{
+ ALOGD("%s", __func__);
+}
+
+status_t AudioAnalytics::submit(
+ const std::shared_ptr<const MediaAnalyticsItem>& item, bool isTrusted)
+{
+ if (startsWith(item->getKey(), "audio.")) {
+ return mTimeMachine.put(item, isTrusted)
+ ?: mTransactionLog.put(item);
+ }
+ return BAD_VALUE;
+}
+
+std::pair<std::string, int32_t> AudioAnalytics::dump(int32_t lines) const
+{
+ std::stringstream ss;
+ int32_t ll = lines;
+
+ if (ll > 0) {
+ ss << "TransactionLog:\n";
+ --ll;
+ }
+ if (ll > 0) {
+ auto [s, l] = mTransactionLog.dump(ll);
+ ss << s;
+ ll -= l;
+ }
+ if (ll > 0) {
+ ss << "TimeMachine:\n";
+ --ll;
+ }
+ if (ll > 0) {
+ auto [s, l] = mTimeMachine.dump(ll);
+ ss << s;
+ ll -= l;
+ }
+ return { ss.str(), lines - ll };
+}
+
+} // namespace android
diff --git a/services/mediaanalytics/AudioAnalytics.h b/services/mediaanalytics/AudioAnalytics.h
new file mode 100644
index 0000000..366a809
--- /dev/null
+++ b/services/mediaanalytics/AudioAnalytics.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "TimeMachine.h"
+#include "TransactionLog.h"
+
+namespace android::mediametrics {
+
+class AudioAnalytics
+{
+public:
+ AudioAnalytics();
+ ~AudioAnalytics();
+
+ // TODO: update with conditions for keys.
+ /**
+ * Returns success if AudioAnalytics recognizes item.
+ *
+ * AudioAnalytics requires the item key to start with "audio.".
+ *
+ * A trusted source can create a new key, an untrusted source
+ * can only modify the key if the uid will match that authorized
+ * on the existing key.
+ *
+ * \param item the item to be submitted.
+ * \param isTrusted whether the transaction comes from a trusted source.
+ * In this case, a trusted source is verified by binder
+ * UID to be a system service by MediaMetrics service.
+ * Do not use true if you haven't really checked!
+ */
+ status_t submit(const std::shared_ptr<const MediaAnalyticsItem>& item, bool isTrusted);
+
+ /**
+ * Returns a pair consisting of the dump string, and the number of lines in the string.
+ *
+ * The number of lines in the returned pair is used as an optimization
+ * for subsequent line limiting.
+ *
+ * The TimeMachine and the TransactionLog are dumped separately under
+ * different locks, so may not be 100% consistent with the last data
+ * delivered.
+ *
+ * \param lines the maximum number of lines in the string returned.
+ */
+ std::pair<std::string, int32_t> dump(int32_t lines = INT32_MAX) const;
+
+private:
+ // The following are locked internally
+ TimeMachine mTimeMachine;
+ TransactionLog mTransactionLog;
+};
+
+} // namespace android::mediametrics
diff --git a/services/mediaanalytics/MediaAnalyticsService.cpp b/services/mediaanalytics/MediaAnalyticsService.cpp
index 1ed8b74..a131e1a 100644
--- a/services/mediaanalytics/MediaAnalyticsService.cpp
+++ b/services/mediaanalytics/MediaAnalyticsService.cpp
@@ -22,14 +22,16 @@
#include <pwd.h> //getpwuid
-#include <audio_utils/clock.h> // clock conversions
#include <android/content/pm/IPackageManagerNative.h> // package info
+#include <audio_utils/clock.h> // clock conversions
#include <binder/IPCThreadState.h> // get calling uid
#include <cutils/properties.h> // for property_get
#include <private/android_filesystem_config.h> // UID
namespace android {
+using namespace mediametrics;
+
// individual records kept in memory: age or count
// age: <= 28 hours (1 1/6 days)
// count: hard limit of # records
@@ -49,6 +51,12 @@
// TODO: need to look at tuning kMaxRecords and friends for low-memory devices
+/* static */
+nsecs_t MediaAnalyticsService::roundTime(nsecs_t timeNs)
+{
+ return (timeNs + NANOS_PER_SECOND / 2) / NANOS_PER_SECOND * NANOS_PER_SECOND;
+}
+
MediaAnalyticsService::MediaAnalyticsService()
: mMaxRecords(kMaxRecords),
mMaxRecordAgeNs(kMaxRecordAgeNs),
@@ -68,38 +76,38 @@
status_t MediaAnalyticsService::submitInternal(MediaAnalyticsItem *item, bool release)
{
- // we control these, generally not trusting user input
- nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
- // round nsecs to seconds
- now = (now + NANOS_PER_SECOND / 2) / NANOS_PER_SECOND * NANOS_PER_SECOND;
- // TODO: if we convert to boot time, do we need to round timestamp?
- item->setTimestamp(now);
+ // calling PID is 0 for one-way calls.
+ const pid_t pid = IPCThreadState::self()->getCallingPid();
+ const pid_t pid_given = item->getPid();
+ const uid_t uid = IPCThreadState::self()->getCallingUid();
+ const uid_t uid_given = item->getUid();
- const int pid = IPCThreadState::self()->getCallingPid();
- const int uid = IPCThreadState::self()->getCallingUid();
- const int uid_given = item->getUid();
- const int pid_given = item->getPid();
+ //ALOGD("%s: caller pid=%d uid=%d, item pid=%d uid=%d", __func__,
+ // (int)pid, (int)uid, (int) pid_given, (int)uid_given);
- ALOGV("%s: caller has uid=%d, embedded uid=%d", __func__, uid, uid_given);
bool isTrusted;
switch (uid) {
+ case AID_AUDIOSERVER:
+ case AID_BLUETOOTH:
+ case AID_CAMERA:
case AID_DRM:
case AID_MEDIA:
case AID_MEDIA_CODEC:
case AID_MEDIA_EX:
case AID_MEDIA_DRM:
+ case AID_SYSTEM:
// trusted source, only override default values
isTrusted = true;
- if (uid_given == -1) {
+ if (uid_given == (uid_t)-1) {
item->setUid(uid);
}
- if (pid_given == -1) {
- item->setPid(pid);
+ if (pid_given == (pid_t)-1) {
+ item->setPid(pid); // if one-way then this is 0.
}
break;
default:
isTrusted = false;
- item->setPid(pid);
+ item->setPid(pid); // always use calling pid, if one-way then this is 0.
item->setUid(uid);
break;
}
@@ -138,12 +146,24 @@
return BAD_VALUE;
}
- // send to statsd
- extern bool dump2Statsd(MediaAnalyticsItem *item); // extern hook
- (void)dump2Statsd(item); // failure should be logged in function.
+ if (!isTrusted || item->getTimestamp() == 0) {
+ // WestWorld logs two times for events: ElapsedRealTimeNs (BOOTTIME) and
+ // WallClockTimeNs (REALTIME). The new audio keys use BOOTTIME.
+ //
+ // TODO: Reevaluate time base with other teams.
+ const bool useBootTime = startsWith(item->getKey(), "audio.");
+ const int64_t now = systemTime(useBootTime ? SYSTEM_TIME_BOOTTIME : SYSTEM_TIME_REALTIME);
+ item->setTimestamp(now);
+ }
- if (!release) item = item->dup();
- saveItem(item);
+ // now attach either the item or its dup to a const shared pointer
+ std::shared_ptr<const MediaAnalyticsItem> sitem(release ? item : item->dup());
+
+ (void)mAudioAnalytics.submit(sitem, isTrusted);
+
+ extern bool dump2Statsd(const std::shared_ptr<const MediaAnalyticsItem>& item);
+ (void)dump2Statsd(sitem); // failure should be logged in function.
+ saveItem(sitem);
return NO_ERROR;
}
@@ -245,6 +265,9 @@
mItems.clear();
// shall we clear the summary data too?
}
+ // TODO: maybe consider a better way of dumping audio analytics info.
+ constexpr int32_t linesToDump = 1000;
+ result.append(mAudioAnalytics.dump(linesToDump).first.c_str());
}
write(fd, result.string(), result.size());
@@ -323,7 +346,7 @@
// if item != NULL, it's the item we just inserted
// true == more items eligible to be recovered
-bool MediaAnalyticsService::expirations_l(MediaAnalyticsItem *item)
+bool MediaAnalyticsService::expirations_l(const std::shared_ptr<const MediaAnalyticsItem>& item)
{
bool more = false;
@@ -346,7 +369,7 @@
for (; i < mItems.size(); ++i) {
auto &oitem = mItems[i];
nsecs_t when = oitem->getTimestamp();
- if (oitem.get() == item) {
+ if (oitem.get() == item.get()) {
break;
}
if (now > when && (now - when) <= mMaxRecordAgeNs) {
@@ -382,7 +405,7 @@
} while (more);
}
-void MediaAnalyticsService::saveItem(MediaAnalyticsItem *item)
+void MediaAnalyticsService::saveItem(const std::shared_ptr<const MediaAnalyticsItem>& item)
{
std::lock_guard _l(mLock);
// we assume the items are roughly in time order.
@@ -401,11 +424,14 @@
if (isTrusted) return true;
// untrusted uids can only send us a limited set of keys
const std::string &key = item->getKey();
+ if (startsWith(key, "audio.")) return true;
for (const char *allowedKey : {
+ // legacy audio
"audiopolicy",
"audiorecord",
"audiothread",
"audiotrack",
+ // other media
"codec",
"extractor",
"nuplayer",
@@ -489,9 +515,10 @@
if (!status.isOk()) {
ALOGE("%s: getNamesForUids failed: %s",
__func__, status.exceptionMessage().c_str());
- }
- if (!names[0].empty()) {
- pkg = names[0].c_str();
+ } else {
+ if (!names[0].empty()) {
+ pkg = names[0].c_str();
+ }
}
}
diff --git a/services/mediaanalytics/MediaAnalyticsService.h b/services/mediaanalytics/MediaAnalyticsService.h
index eb7d725..5bdc48f 100644
--- a/services/mediaanalytics/MediaAnalyticsService.h
+++ b/services/mediaanalytics/MediaAnalyticsService.h
@@ -26,6 +26,8 @@
#include <media/IMediaAnalyticsService.h>
#include <utils/String8.h>
+#include "AudioAnalytics.h"
+
namespace android {
class MediaAnalyticsService : public BnMediaAnalyticsService
@@ -45,10 +47,21 @@
return submitInternal(item, false /* release */);
}
+ status_t submitBuffer(const char *buffer, size_t length) override {
+ MediaAnalyticsItem *item = new MediaAnalyticsItem();
+ return item->readFromByteString(buffer, length)
+ ?: submitInternal(item, true /* release */);
+ }
+
status_t dump(int fd, const Vector<String16>& args) override;
static constexpr const char * const kServiceName = "media.metrics";
+ /**
+ * Rounds time to the nearest second.
+ */
+ static nsecs_t roundTime(nsecs_t timeNs);
+
protected:
// Internal call where release is true if ownership of item is transferred
@@ -60,10 +73,10 @@
// input validation after arrival from client
static bool isContentValid(const MediaAnalyticsItem *item, bool isTrusted);
bool isRateLimited(MediaAnalyticsItem *) const;
- void saveItem(MediaAnalyticsItem *);
+ void saveItem(const std::shared_ptr<const MediaAnalyticsItem>& item);
// The following methods are GUARDED_BY(mLock)
- bool expirations_l(MediaAnalyticsItem *);
+ bool expirations_l(const std::shared_ptr<const MediaAnalyticsItem>& item);
// support for generating output
void dumpQueue_l(String8 &result, int dumpProto);
@@ -104,6 +117,8 @@
std::atomic<int64_t> mItemsSubmitted{}; // accessed outside of lock.
+ mediametrics::AudioAnalytics mAudioAnalytics;
+
std::mutex mLock;
// statistics about our analytics
int64_t mItemsFinalized = 0; // GUARDED_BY(mLock)
diff --git a/services/mediaanalytics/TimeMachine.h b/services/mediaanalytics/TimeMachine.h
new file mode 100644
index 0000000..578b838
--- /dev/null
+++ b/services/mediaanalytics/TimeMachine.h
@@ -0,0 +1,484 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <any>
+#include <map>
+#include <sstream>
+#include <string>
+#include <variant>
+#include <vector>
+
+#include <media/MediaAnalyticsItem.h>
+#include <utils/Timers.h>
+
+namespace android::mediametrics {
+
+// define a way of printing the monostate
+inline std::ostream & operator<< (std::ostream& s,
+ std::monostate const& v __unused) {
+ s << "none_item";
+ return s;
+}
+
+// define a way of printing a variant
+// see https://en.cppreference.com/w/cpp/utility/variant/visit
+template <typename T0, typename ... Ts>
+std::ostream & operator<< (std::ostream& s,
+ std::variant<T0, Ts...> const& v) {
+ std::visit([&s](auto && arg){ s << std::forward<decltype(arg)>(arg); }, v);
+ return s;
+}
+
+/**
+ * The TimeMachine is used to record timing changes of MediaAnalyticItem
+ * properties.
+ *
+ * Any URL that ends with '!' will have a time sequence that keeps duplicates.
+ *
+ * The TimeMachine is NOT thread safe.
+ */
+class TimeMachine {
+
+ using Elem = std::variant<std::monostate, int32_t, int64_t, double, std::string>;
+ using PropertyHistory = std::multimap<int64_t /* time */, Elem>;
+
+ // KeyHistory contains no lock.
+ // Access is through the TimeMachine, and a hash-striped lock is used
+ // before calling into KeyHistory.
+ class KeyHistory {
+ public:
+ template <typename T>
+ KeyHistory(T key, pid_t pid, uid_t uid, int64_t time)
+ : mKey(key)
+ , mPid(pid)
+ , mUid(uid)
+ , mCreationTime(time)
+ , mLastModificationTime(time)
+ {
+ putValue("_pid", (int32_t)pid, time);
+ putValue("_uid", (int32_t)uid, time);
+ }
+
+ status_t checkPermission(uid_t uidCheck) const {
+ return uidCheck != (uid_t)-1 && uidCheck != mUid ? PERMISSION_DENIED : NO_ERROR;
+ }
+
+ template <typename T>
+ status_t getValue(const std::string &property, T* value, int64_t time = 0) const {
+ if (time == 0) time = systemTime(SYSTEM_TIME_BOOTTIME);
+ const auto tsptr = mPropertyMap.find(property);
+ if (tsptr == mPropertyMap.end()) return BAD_VALUE;
+ const auto& timeSequence = tsptr->second;
+ auto eptr = timeSequence.upper_bound(time);
+ if (eptr == timeSequence.begin()) return BAD_VALUE;
+ --eptr;
+ if (eptr == timeSequence.end()) return BAD_VALUE;
+ const T* vptr = std::get_if<T>(&eptr->second);
+ if (vptr == nullptr) return BAD_VALUE;
+ *value = *vptr;
+ return NO_ERROR;
+ }
+
+ template <typename T>
+ status_t getValue(const std::string &property, T defaultValue, int64_t time = 0) const {
+ T value;
+ return getValue(property, &value, time) != NO_ERROR ? defaultValue : value;
+ }
+
+ void putProp(
+ const std::string &name, const MediaAnalyticsItem::Prop &prop, int64_t time = 0) {
+ prop.visit([&](auto value) { putValue(name, value, time); });
+ }
+
+ template <typename T>
+ void putValue(const std::string &property,
+ T&& e, int64_t time = 0) {
+ if (time == 0) time = systemTime(SYSTEM_TIME_BOOTTIME);
+ mLastModificationTime = time;
+ auto& timeSequence = mPropertyMap[property];
+ Elem el{std::forward<T>(e)};
+ if (timeSequence.empty() // no elements
+ || property.back() == '!' // keep duplicates TODO: remove?
+ || timeSequence.rbegin()->second != el) { // value changed
+ timeSequence.emplace(time, std::move(el));
+ }
+ }
+
+ // Explicitly ignore rate properties - we don't expose them for now.
+ void putValue(
+ const std::string &property __unused,
+ std::pair<int64_t, int64_t>& e __unused,
+ int64_t time __unused) {
+ }
+
+ std::pair<std::string, int32_t> dump(int32_t lines, int64_t time) const {
+ std::stringstream ss;
+ int32_t ll = lines;
+ for (auto& tsPair : mPropertyMap) {
+ if (ll <= 0) break;
+ ss << dump(mKey, tsPair, time);
+ --ll;
+ }
+ return { ss.str(), lines - ll };
+ }
+
+ int64_t getLastModificationTime() const { return mLastModificationTime; }
+
+ private:
+ static std::string dump(
+ const std::string &key,
+ const std::pair<std::string /* prop */, PropertyHistory>& tsPair,
+ int64_t time) {
+ const auto timeSequence = tsPair.second;
+ auto eptr = timeSequence.lower_bound(time);
+ if (eptr == timeSequence.end()) {
+ return tsPair.first + "={};\n";
+ }
+ std::stringstream ss;
+ ss << key << "." << tsPair.first << "={";
+ do {
+ ss << eptr->first << ":" << eptr->second << ",";
+ } while (++eptr != timeSequence.end());
+ ss << "};\n";
+ return ss.str();
+ }
+
+ const std::string mKey;
+ const pid_t mPid __unused;
+ const uid_t mUid;
+ const int64_t mCreationTime __unused;
+
+ int64_t mLastModificationTime;
+ std::map<std::string /* property */, PropertyHistory> mPropertyMap;
+ };
+
+ using History = std::map<std::string /* key */, std::shared_ptr<KeyHistory>>;
+
+ static inline constexpr size_t kKeyLowWaterMark = 500;
+ static inline constexpr size_t kKeyHighWaterMark = 1000;
+
+ // Estimated max data space usage is 3KB * kKeyHighWaterMark.
+
+public:
+
+ TimeMachine() = default;
+ TimeMachine(size_t keyLowWaterMark, size_t keyHighWaterMark)
+ : mKeyLowWaterMark(keyLowWaterMark)
+ , mKeyHighWaterMark(keyHighWaterMark) {
+ LOG_ALWAYS_FATAL_IF(keyHighWaterMark <= keyLowWaterMark,
+ "%s: required that keyHighWaterMark:%zu > keyLowWaterMark:%zu",
+ __func__, keyHighWaterMark, keyLowWaterMark);
+ }
+
+ /**
+ * Put all the properties from an item into the Time Machine log.
+ */
+ status_t put(const std::shared_ptr<const MediaAnalyticsItem>& item, bool isTrusted = false) {
+ const int64_t time = item->getTimestamp();
+ const std::string &key = item->getKey();
+
+ std::shared_ptr<KeyHistory> keyHistory;
+ {
+ std::vector<std::any> garbage;
+ std::lock_guard lock(mLock);
+
+ auto it = mHistory.find(key);
+ if (it == mHistory.end()) {
+ if (!isTrusted) return PERMISSION_DENIED;
+
+ (void)gc_l(garbage);
+
+ // no keylock needed here as we are sole owner
+ // until placed on mHistory.
+ keyHistory = std::make_shared<KeyHistory>(
+ key, item->getPid(), item->getUid(), time);
+ mHistory[key] = keyHistory;
+ } else {
+ keyHistory = it->second;
+ }
+ }
+
+ // deferred contains remote properties (for other keys) to do later.
+ std::vector<const MediaAnalyticsItem::Prop *> deferred;
+ {
+ // handle local properties
+ std::lock_guard lock(getLockForKey(key));
+ if (!isTrusted) {
+ status_t status = keyHistory->checkPermission(item->getUid());
+ if (status != NO_ERROR) return status;
+ }
+
+ for (const auto &prop : *item) {
+ const std::string &name = prop.getName();
+ if (name.size() == 0 || name[0] == '_') continue;
+
+ // Cross key settings are with [key]property
+ if (name[0] == '[') {
+ if (!isTrusted) continue;
+ deferred.push_back(&prop);
+ } else {
+ keyHistory->putProp(name, prop, time);
+ }
+ }
+ }
+
+ // handle remote properties, if any
+ for (const auto propptr : deferred) {
+ const auto &prop = *propptr;
+ const std::string &name = prop.getName();
+ size_t end = name.find_first_of(']'); // TODO: handle nested [] or escape?
+ if (end == 0) continue;
+ std::string remoteKey = name.substr(1, end - 1);
+ std::string remoteName = name.substr(end + 1);
+ if (remoteKey.size() == 0 || remoteName.size() == 0) continue;
+ std::shared_ptr<KeyHistory> remoteKeyHistory;
+ {
+ std::lock_guard lock(mLock);
+ auto it = mHistory.find(remoteKey);
+ if (it == mHistory.end()) continue;
+ remoteKeyHistory = it->second;
+ }
+ std::lock_guard(getLockForKey(remoteKey));
+ remoteKeyHistory->putProp(remoteName, prop, time);
+ }
+ return NO_ERROR;
+ }
+
+ template <typename T>
+ status_t get(const std::string &key, const std::string &property,
+ T* value, int32_t uidCheck = -1, int64_t time = 0) const {
+ std::shared_ptr<KeyHistory> keyHistory;
+ {
+ std::lock_guard lock(mLock);
+ const auto it = mHistory.find(key);
+ if (it == mHistory.end()) return BAD_VALUE;
+ keyHistory = it->second;
+ }
+ std::lock_guard lock(getLockForKey(key));
+ return keyHistory->checkPermission(uidCheck)
+ ?: keyHistory->getValue(property, value, time);
+ }
+
+ /**
+ * Individual property put.
+ *
+ * Put takes in a time (if none is provided then BOOTTIME is used).
+ */
+ template <typename T>
+ status_t put(const std::string &url, T &&e, int64_t time = 0) {
+ std::string key;
+ std::string prop;
+ std::shared_ptr<KeyHistory> keyHistory =
+ getKeyHistoryFromUrl(url, &key, &prop);
+ if (keyHistory == nullptr) return BAD_VALUE;
+ if (time == 0) time = systemTime(SYSTEM_TIME_BOOTTIME);
+ std::lock_guard lock(getLockForKey(key));
+ keyHistory->putValue(prop, std::forward<T>(e), time);
+ return NO_ERROR;
+ }
+
+ /**
+ * Individual property get
+ */
+ template <typename T>
+ status_t get(const std::string &url, T* value, int32_t uidCheck, int64_t time = 0) const {
+ std::string key;
+ std::string prop;
+ std::shared_ptr<KeyHistory> keyHistory =
+ getKeyHistoryFromUrl(url, &key, &prop);
+ if (keyHistory == nullptr) return BAD_VALUE;
+
+ std::lock_guard lock(getLockForKey(key));
+ return keyHistory->checkPermission(uidCheck)
+ ?: keyHistory->getValue(prop, value, time);
+ }
+
+ /**
+ * Individual property get with default
+ */
+ template <typename T>
+ T get(const std::string &url, const T &defaultValue, int32_t uidCheck,
+ int64_t time = 0) const {
+ T value;
+ return get(url, &value, uidCheck, time) == NO_ERROR
+ ? value : defaultValue;
+ }
+
+ /**
+ * Returns number of keys in the Time Machine.
+ */
+ size_t size() const {
+ std::lock_guard lock(mLock);
+ return mHistory.size();
+ }
+
+ /**
+ * Clears all properties from the Time Machine.
+ */
+ void clear() {
+ std::lock_guard lock(mLock);
+ mHistory.clear();
+ }
+
+ /**
+ * Returns a pair consisting of the TimeMachine state as a string
+ * and the number of lines in the string.
+ *
+ * The number of lines in the returned pair is used as an optimization
+ * for subsequent line limiting.
+ *
+ * \param lines the maximum number of lines in the string returned.
+ * \param key selects only that key.
+ * \param time to start the dump from.
+ */
+ std::pair<std::string, int32_t> dump(
+ int32_t lines = INT32_MAX, const std::string &key = {}, int64_t time = 0) const {
+ std::lock_guard lock(mLock);
+ if (!key.empty()) { // use std::regex
+ const auto it = mHistory.find(key);
+ if (it == mHistory.end()) return {};
+ std::lock_guard lock(getLockForKey(it->first));
+ return it->second->dump(lines, time);
+ }
+
+ std::stringstream ss;
+ int32_t ll = lines;
+ for (const auto &keyPair : mHistory) {
+ std::lock_guard lock(getLockForKey(keyPair.first));
+ if (lines <= 0) break;
+ auto [s, l] = keyPair.second->dump(ll, time);
+ ss << s;
+ ll -= l;
+ }
+ return { ss.str(), lines - ll };
+ }
+
+private:
+
+ // Obtains the lock for a KeyHistory.
+ std::mutex &getLockForKey(const std::string &key) const {
+ return mKeyLocks[std::hash<std::string>{}(key) % std::size(mKeyLocks)];
+ }
+
+ // Finds a KeyHistory from a URL. Returns nullptr if not found.
+ std::shared_ptr<KeyHistory> getKeyHistoryFromUrl(
+ std::string url, std::string* key, std::string *prop) const {
+ std::lock_guard lock(mLock);
+
+ auto it = mHistory.upper_bound(url);
+ if (it == mHistory.begin()) {
+ return nullptr;
+ }
+ --it; // go to the actual key, if it exists.
+
+ const std::string& itKey = it->first;
+ if (strncmp(itKey.c_str(), url.c_str(), itKey.size())) {
+ return nullptr;
+ }
+ if (key) *key = itKey;
+ if (prop) *prop = url.substr(itKey.size() + 1);
+ return it->second;
+ }
+
+ // GUARDED_BY mLock
+ /**
+ * Garbage collects if the TimeMachine size exceeds the high water mark.
+ *
+ * \param garbage a type-erased vector of elements to be destroyed
+ * outside of lock. Move large items to be destroyed here.
+ *
+ * \return true if garbage collection was done.
+ */
+ bool gc_l(std::vector<std::any>& garbage) {
+ // TODO: something better than this for garbage collection.
+ if (mHistory.size() < mKeyHighWaterMark) return false;
+
+ ALOGD("%s: garbage collection", __func__);
+
+ // erase everything explicitly expired.
+ std::multimap<int64_t, std::string> accessList;
+ // use a stale vector with precise type to avoid type erasure overhead in garbage
+ std::vector<std::shared_ptr<KeyHistory>> stale;
+
+ for (auto it = mHistory.begin(); it != mHistory.end();) {
+ const std::string& key = it->first;
+ std::shared_ptr<KeyHistory> &keyHist = it->second;
+
+ std::lock_guard lock(getLockForKey(it->first));
+ int64_t expireTime = keyHist->getValue("_expire", -1 /* default */);
+ if (expireTime != -1) {
+ stale.emplace_back(std::move(it->second));
+ it = mHistory.erase(it);
+ } else {
+ accessList.emplace(keyHist->getLastModificationTime(), key);
+ ++it;
+ }
+ }
+
+ if (mHistory.size() > mKeyLowWaterMark) {
+ const size_t toDelete = mHistory.size() - mKeyLowWaterMark;
+ auto it = accessList.begin();
+ for (size_t i = 0; i < toDelete; ++i) {
+ auto it2 = mHistory.find(it->second);
+ stale.emplace_back(std::move(it2->second));
+ mHistory.erase(it2);
+ ++it;
+ }
+ }
+ garbage.emplace_back(std::move(accessList));
+ garbage.emplace_back(std::move(stale));
+
+ ALOGD("%s(%zu, %zu): key size:%zu",
+ __func__, mKeyLowWaterMark, mKeyHighWaterMark,
+ mHistory.size());
+ return true;
+ }
+
+ const size_t mKeyLowWaterMark = kKeyLowWaterMark;
+ const size_t mKeyHighWaterMark = kKeyHighWaterMark;
+
+ /**
+ * Locking Strategy
+ *
+ * Each key in the History has a KeyHistory. To get a shared pointer to
+ * the KeyHistory requires a lookup of mHistory under mLock. Once the shared
+ * pointer to KeyHistory is obtained, the mLock for mHistory can be released.
+ *
+ * Once the shared pointer to the key's KeyHistory is obtained, the KeyHistory
+ * can be locked for read and modification through the method getLockForKey().
+ *
+ * Instead of having a mutex per KeyHistory, we use a hash striped lock
+ * which assigns a mutex based on the hash of the key string.
+ *
+ * Once the last shared pointer reference to KeyHistory is released, it is
+ * destroyed. This is done through the garbage collection method.
+ *
+ * This two level locking allows multiple threads to access the TimeMachine
+ * in parallel.
+ */
+
+ mutable std::mutex mLock; // Lock for mHistory
+ History mHistory; // GUARDED_BY mLock
+
+ // KEY_LOCKS is the number of mutexes for keys.
+ // It need not be a power of 2, but faster that way.
+ static inline constexpr size_t KEY_LOCKS = 256;
+ mutable std::mutex mKeyLocks[KEY_LOCKS]; // Hash-striped lock for KeyHistory based on key.
+};
+
+} // namespace android::mediametrics
diff --git a/services/mediaanalytics/TransactionLog.h b/services/mediaanalytics/TransactionLog.h
new file mode 100644
index 0000000..ca37862
--- /dev/null
+++ b/services/mediaanalytics/TransactionLog.h
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <any>
+#include <map>
+#include <sstream>
+#include <string>
+
+#include <media/MediaAnalyticsItem.h>
+
+namespace android::mediametrics {
+
+/**
+ * The TransactionLog is used to record MediaAnalyticsItems to present
+ * different views on the time information (selected by audio, and sorted by key).
+ *
+ * The TransactionLog will always present data in timestamp order. (Perhaps we
+ * just make this submit order).
+ *
+ * These Views have a cost in shared pointer storage, so they aren't quite free.
+ *
+ * The TransactionLog is NOT thread safe.
+ */
+class TransactionLog {
+public:
+ // In long term run, the garbage collector aims to keep the
+ // Transaction Log between the Low Water Mark and the High Water Mark.
+
+ // low water mark
+ static inline constexpr size_t kLogItemsLowWater = 5000;
+ // high water mark
+ static inline constexpr size_t kLogItemsHighWater = 10000;
+
+ // Estimated max data usage is 1KB * kLogItemsHighWater.
+
+ TransactionLog() = default;
+
+ TransactionLog(size_t lowWaterMark, size_t highWaterMark)
+ : mLowWaterMark(lowWaterMark)
+ , mHighWaterMark(highWaterMark) {
+ LOG_ALWAYS_FATAL_IF(highWaterMark <= lowWaterMark,
+ "%s: required that highWaterMark:%zu > lowWaterMark:%zu",
+ __func__, highWaterMark, lowWaterMark);
+ }
+
+ /**
+ * Put an item in the TransactionLog.
+ */
+ status_t put(const std::shared_ptr<const MediaAnalyticsItem>& item) {
+ const std::string& key = item->getKey();
+ const int64_t time = item->getTimestamp();
+
+ std::vector<std::any> garbage; // objects destroyed after lock.
+ std::lock_guard lock(mLock);
+
+ (void)gc_l(garbage);
+ mLog.emplace(time, item);
+ mItemMap[key].emplace(time, item);
+ return NO_ERROR; // no errors for now.
+ }
+
+ /**
+ * Returns all records within [startTime, endTime]
+ */
+ std::vector<std::shared_ptr<const MediaAnalyticsItem>> get(
+ int64_t startTime = 0, int64_t endTime = INT64_MAX) const {
+ std::lock_guard lock(mLock);
+ return getItemsInRange_l(mLog, startTime, endTime);
+ }
+
+ /**
+ * Returns all records for a key within [startTime, endTime]
+ */
+ std::vector<std::shared_ptr<const MediaAnalyticsItem>> get(
+ const std::string& key,
+ int64_t startTime = 0, int64_t endTime = INT64_MAX) const {
+ std::lock_guard lock(mLock);
+ auto mapIt = mItemMap.find(key);
+ if (mapIt == mItemMap.end()) return {};
+ return getItemsInRange_l(mapIt->second, startTime, endTime);
+ }
+
+ /**
+ * Returns a pair consisting of the Transaction Log as a string
+ * and the number of lines in the string.
+ *
+ * The number of lines in the returned pair is used as an optimization
+ * for subsequent line limiting.
+ *
+ * \param lines the maximum number of lines in the string returned.
+ */
+ std::pair<std::string, int32_t> dump(int32_t lines) const {
+ std::stringstream ss;
+ int32_t ll = lines;
+ std::lock_guard lock(mLock);
+
+ // All audio items in time order.
+ if (ll > 0) {
+ ss << "Consolidated:\n";
+ --ll;
+ }
+ for (const auto &log : mLog) {
+ if (ll <= 0) break;
+ ss << " " << log.second->toString() << "\n";
+ --ll;
+ }
+
+ // Grouped by item key (category)
+ if (ll > 0) {
+ ss << "Categorized:\n";
+ --ll;
+ }
+ for (const auto &itemMap : mItemMap) {
+ if (ll <= 0) break;
+ ss << " " << itemMap.first << "\n";
+ --ll;
+ for (const auto &item : itemMap.second) {
+ if (ll <= 0) break;
+ ss << " { " << item.first << ", " << item.second->toString() << " }\n";
+ --ll;
+ }
+ }
+ return { ss.str(), lines - ll };
+ }
+
+ /**
+ * Returns number of Items in the TransactionLog.
+ */
+ size_t size() const {
+ std::lock_guard lock(mLock);
+ return mLog.size();
+ }
+
+ /**
+ * Clears all Items from the TransactionLog.
+ */
+ // TODO: Garbage Collector, sweep and expire old values
+ void clear() {
+ std::lock_guard lock(mLock);
+ mLog.clear();
+ mItemMap.clear();
+ }
+
+private:
+ using MapTimeItem =
+ std::multimap<int64_t /* time */, std::shared_ptr<const MediaAnalyticsItem>>;
+
+ // GUARDED_BY mLock
+ /**
+ * Garbage collects if the TimeMachine size exceeds the high water mark.
+ *
+ * \param garbage a type-erased vector of elements to be destroyed
+ * outside of lock. Move large items to be destroyed here.
+ *
+ * \return true if garbage collection was done.
+ */
+ bool gc_l(std::vector<std::any>& garbage) {
+ if (mLog.size() < mHighWaterMark) return false;
+
+ ALOGD("%s: garbage collection", __func__);
+
+ auto eraseEnd = mLog.begin();
+ size_t toRemove = mLog.size() - mLowWaterMark;
+ // remove at least those elements.
+
+ // use a stale vector with precise type to avoid type erasure overhead in garbage
+ std::vector<std::shared_ptr<const MediaAnalyticsItem>> stale;
+
+ for (size_t i = 0; i < toRemove; ++i) {
+ stale.emplace_back(std::move(eraseEnd->second));
+ ++eraseEnd; // amortized O(1)
+ }
+ // ensure that eraseEnd is an lower bound on timeToErase.
+ const int64_t timeToErase = eraseEnd->first;
+ while (eraseEnd != mLog.end()) {
+ auto it = eraseEnd;
+ --it; // amortized O(1)
+ if (it->first != timeToErase) {
+ break; // eraseEnd represents a unique time jump.
+ }
+ stale.emplace_back(std::move(eraseEnd->second));
+ ++eraseEnd;
+ }
+
+ mLog.erase(mLog.begin(), eraseEnd); // O(ptr_diff)
+
+ size_t itemMapCount = 0;
+ for (auto it = mItemMap.begin(); it != mItemMap.end();) {
+ auto &keyHist = it->second;
+ auto it2 = keyHist.lower_bound(timeToErase);
+ if (it2 == keyHist.end()) {
+ garbage.emplace_back(std::move(keyHist)); // directly move keyhist to garbage
+ it = mItemMap.erase(it);
+ } else {
+ for (auto it3 = keyHist.begin(); it3 != it2; ++it3) {
+ stale.emplace_back(std::move(it3->second));
+ }
+ keyHist.erase(keyHist.begin(), it2);
+ itemMapCount += keyHist.size();
+ ++it;
+ }
+ }
+
+ garbage.emplace_back(std::move(stale));
+
+ ALOGD("%s(%zu, %zu): log size:%zu item map size:%zu, item map items:%zu",
+ __func__, mLowWaterMark, mHighWaterMark,
+ mLog.size(), mItemMap.size(), itemMapCount);
+ return true;
+ }
+
+ static std::vector<std::shared_ptr<const MediaAnalyticsItem>> getItemsInRange_l(
+ const MapTimeItem& map,
+ int64_t startTime = 0, int64_t endTime = INT64_MAX) {
+ auto it = map.lower_bound(startTime);
+ if (it == map.end()) return {};
+
+ auto it2 = map.upper_bound(endTime);
+
+ std::vector<std::shared_ptr<const MediaAnalyticsItem>> ret;
+ while (it != it2) {
+ ret.push_back(it->second);
+ ++it;
+ }
+ return ret;
+ }
+
+ const size_t mLowWaterMark = kLogItemsHighWater;
+ const size_t mHighWaterMark = kLogItemsHighWater;
+
+ mutable std::mutex mLock;
+
+ // GUARDED_BY mLock
+ MapTimeItem mLog;
+
+ // GUARDED_BY mLock
+ std::map<std::string /* item_key */, MapTimeItem> mItemMap;
+};
+
+} // namespace android::mediametrics
diff --git a/services/mediaanalytics/iface_statsd.cpp b/services/mediaanalytics/iface_statsd.cpp
index e02c9cf..dccc76a 100644
--- a/services/mediaanalytics/iface_statsd.cpp
+++ b/services/mediaanalytics/iface_statsd.cpp
@@ -27,6 +27,7 @@
#include <pthread.h>
#include <unistd.h>
+#include <memory>
#include <string.h>
#include <pwd.h>
@@ -48,7 +49,7 @@
struct statsd_hooks {
const char *key;
- bool (*handler)(MediaAnalyticsItem *);
+ bool (*handler)(const MediaAnalyticsItem *);
};
// keep this sorted, so we can do binary searches
@@ -69,7 +70,7 @@
};
// give me a record, i'll look at the type and upload appropriately
-bool dump2Statsd(MediaAnalyticsItem *item) {
+bool dump2Statsd(const std::shared_ptr<const MediaAnalyticsItem>& item) {
if (item == NULL) return false;
// get the key
@@ -82,7 +83,7 @@
for (const auto &statsd_handler : statsd_handlers) {
if (key == statsd_handler.key) {
- return statsd_handler.handler(item);
+ return statsd_handler.handler(item.get());
}
}
return false;
diff --git a/services/mediaanalytics/iface_statsd.h b/services/mediaanalytics/iface_statsd.h
index 014929b..1c48118 100644
--- a/services/mediaanalytics/iface_statsd.h
+++ b/services/mediaanalytics/iface_statsd.h
@@ -19,17 +19,17 @@
extern bool enabled_statsd;
// component specific dumpers
-extern bool statsd_audiopolicy(MediaAnalyticsItem *);
-extern bool statsd_audiorecord(MediaAnalyticsItem *);
-extern bool statsd_audiothread(MediaAnalyticsItem *);
-extern bool statsd_audiotrack(MediaAnalyticsItem *);
-extern bool statsd_codec(MediaAnalyticsItem *);
-extern bool statsd_extractor(MediaAnalyticsItem *);
-extern bool statsd_nuplayer(MediaAnalyticsItem *);
-extern bool statsd_recorder(MediaAnalyticsItem *);
+extern bool statsd_audiopolicy(const MediaAnalyticsItem *);
+extern bool statsd_audiorecord(const MediaAnalyticsItem *);
+extern bool statsd_audiothread(const MediaAnalyticsItem *);
+extern bool statsd_audiotrack(const MediaAnalyticsItem *);
+extern bool statsd_codec(const MediaAnalyticsItem *);
+extern bool statsd_extractor(const MediaAnalyticsItem *);
+extern bool statsd_nuplayer(const MediaAnalyticsItem *);
+extern bool statsd_recorder(const MediaAnalyticsItem *);
-extern bool statsd_mediadrm(MediaAnalyticsItem *);
-extern bool statsd_widevineCDM(MediaAnalyticsItem *);
-extern bool statsd_drmmanager(MediaAnalyticsItem *);
+extern bool statsd_mediadrm(const MediaAnalyticsItem *);
+extern bool statsd_widevineCDM(const MediaAnalyticsItem *);
+extern bool statsd_drmmanager(const MediaAnalyticsItem *);
} // namespace android
diff --git a/services/mediaanalytics/statsd_audiopolicy.cpp b/services/mediaanalytics/statsd_audiopolicy.cpp
index 95cb274..4e17040 100644
--- a/services/mediaanalytics/statsd_audiopolicy.cpp
+++ b/services/mediaanalytics/statsd_audiopolicy.cpp
@@ -37,12 +37,12 @@
namespace android {
-bool statsd_audiopolicy(MediaAnalyticsItem *item)
+bool statsd_audiopolicy(const MediaAnalyticsItem *item)
{
if (item == NULL) return false;
// these go into the statsd wrapper
- nsecs_t timestamp = item->getTimestamp();
+ const nsecs_t timestamp = MediaAnalyticsService::roundTime(item->getTimestamp());
std::string pkgName = item->getPkgName();
int64_t pkgVersionCode = item->getPkgVersionCode();
int64_t mediaApexVersion = 0;
diff --git a/services/mediaanalytics/statsd_audiorecord.cpp b/services/mediaanalytics/statsd_audiorecord.cpp
index 7c7a62c..a102178 100644
--- a/services/mediaanalytics/statsd_audiorecord.cpp
+++ b/services/mediaanalytics/statsd_audiorecord.cpp
@@ -37,12 +37,12 @@
namespace android {
-bool statsd_audiorecord(MediaAnalyticsItem *item)
+bool statsd_audiorecord(const MediaAnalyticsItem *item)
{
if (item == NULL) return false;
// these go into the statsd wrapper
- nsecs_t timestamp = item->getTimestamp();
+ const nsecs_t timestamp = MediaAnalyticsService::roundTime(item->getTimestamp());
std::string pkgName = item->getPkgName();
int64_t pkgVersionCode = item->getPkgVersionCode();
int64_t mediaApexVersion = 0;
diff --git a/services/mediaanalytics/statsd_audiothread.cpp b/services/mediaanalytics/statsd_audiothread.cpp
index e9d6b17..cf8cff2 100644
--- a/services/mediaanalytics/statsd_audiothread.cpp
+++ b/services/mediaanalytics/statsd_audiothread.cpp
@@ -37,12 +37,12 @@
namespace android {
-bool statsd_audiothread(MediaAnalyticsItem *item)
+bool statsd_audiothread(const MediaAnalyticsItem *item)
{
if (item == NULL) return false;
// these go into the statsd wrapper
- nsecs_t timestamp = item->getTimestamp();
+ const nsecs_t timestamp = MediaAnalyticsService::roundTime(item->getTimestamp());
std::string pkgName = item->getPkgName();
int64_t pkgVersionCode = item->getPkgVersionCode();
int64_t mediaApexVersion = 0;
diff --git a/services/mediaanalytics/statsd_audiotrack.cpp b/services/mediaanalytics/statsd_audiotrack.cpp
index 57cda99..35f11d6 100644
--- a/services/mediaanalytics/statsd_audiotrack.cpp
+++ b/services/mediaanalytics/statsd_audiotrack.cpp
@@ -37,12 +37,12 @@
namespace android {
-bool statsd_audiotrack(MediaAnalyticsItem *item)
+bool statsd_audiotrack(const MediaAnalyticsItem *item)
{
if (item == NULL) return false;
// these go into the statsd wrapper
- nsecs_t timestamp = item->getTimestamp();
+ const nsecs_t timestamp = MediaAnalyticsService::roundTime(item->getTimestamp());
std::string pkgName = item->getPkgName();
int64_t pkgVersionCode = item->getPkgVersionCode();
int64_t mediaApexVersion = 0;
diff --git a/services/mediaanalytics/statsd_codec.cpp b/services/mediaanalytics/statsd_codec.cpp
index bf82e50..72e2c17 100644
--- a/services/mediaanalytics/statsd_codec.cpp
+++ b/services/mediaanalytics/statsd_codec.cpp
@@ -37,12 +37,12 @@
namespace android {
-bool statsd_codec(MediaAnalyticsItem *item)
+bool statsd_codec(const MediaAnalyticsItem *item)
{
if (item == NULL) return false;
// these go into the statsd wrapper
- nsecs_t timestamp = item->getTimestamp();
+ const nsecs_t timestamp = MediaAnalyticsService::roundTime(item->getTimestamp());
std::string pkgName = item->getPkgName();
int64_t pkgVersionCode = item->getPkgVersionCode();
int64_t mediaApexVersion = 0;
diff --git a/services/mediaanalytics/statsd_drm.cpp b/services/mediaanalytics/statsd_drm.cpp
index 845383d..6903e76 100644
--- a/services/mediaanalytics/statsd_drm.cpp
+++ b/services/mediaanalytics/statsd_drm.cpp
@@ -38,11 +38,11 @@
namespace android {
// mediadrm
-bool statsd_mediadrm(MediaAnalyticsItem *item)
+bool statsd_mediadrm(const MediaAnalyticsItem *item)
{
if (item == NULL) return false;
- nsecs_t timestamp = item->getTimestamp();
+ const nsecs_t timestamp = MediaAnalyticsService::roundTime(item->getTimestamp());
std::string pkgName = item->getPkgName();
int64_t pkgVersionCode = item->getPkgVersionCode();
int64_t mediaApexVersion = 0;
@@ -75,11 +75,11 @@
}
// widevineCDM
-bool statsd_widevineCDM(MediaAnalyticsItem *item)
+bool statsd_widevineCDM(const MediaAnalyticsItem *item)
{
if (item == NULL) return false;
- nsecs_t timestamp = item->getTimestamp();
+ const nsecs_t timestamp = MediaAnalyticsService::roundTime(item->getTimestamp());
std::string pkgName = item->getPkgName();
int64_t pkgVersionCode = item->getPkgVersionCode();
int64_t mediaApexVersion = 0;
@@ -105,11 +105,11 @@
}
// drmmanager
-bool statsd_drmmanager(MediaAnalyticsItem *item)
+bool statsd_drmmanager(const MediaAnalyticsItem *item)
{
if (item == NULL) return false;
- nsecs_t timestamp = item->getTimestamp();
+ const nsecs_t timestamp = MediaAnalyticsService::roundTime(item->getTimestamp());
std::string pkgName = item->getPkgName();
int64_t pkgVersionCode = item->getPkgVersionCode();
int64_t mediaApexVersion = 0;
diff --git a/services/mediaanalytics/statsd_extractor.cpp b/services/mediaanalytics/statsd_extractor.cpp
index d84930c..b5c692e 100644
--- a/services/mediaanalytics/statsd_extractor.cpp
+++ b/services/mediaanalytics/statsd_extractor.cpp
@@ -37,12 +37,12 @@
namespace android {
-bool statsd_extractor(MediaAnalyticsItem *item)
+bool statsd_extractor(const MediaAnalyticsItem *item)
{
if (item == NULL) return false;
// these go into the statsd wrapper
- nsecs_t timestamp = item->getTimestamp();
+ const nsecs_t timestamp = MediaAnalyticsService::roundTime(item->getTimestamp());
std::string pkgName = item->getPkgName();
int64_t pkgVersionCode = item->getPkgVersionCode();
int64_t mediaApexVersion = 0;
diff --git a/services/mediaanalytics/statsd_nuplayer.cpp b/services/mediaanalytics/statsd_nuplayer.cpp
index e6e0f2c..3390233 100644
--- a/services/mediaanalytics/statsd_nuplayer.cpp
+++ b/services/mediaanalytics/statsd_nuplayer.cpp
@@ -41,12 +41,12 @@
* handles nuplayer AND nuplayer2
* checks for the union of what the two players generate
*/
-bool statsd_nuplayer(MediaAnalyticsItem *item)
+bool statsd_nuplayer(const MediaAnalyticsItem *item)
{
if (item == NULL) return false;
// these go into the statsd wrapper
- nsecs_t timestamp = item->getTimestamp();
+ const nsecs_t timestamp = MediaAnalyticsService::roundTime(item->getTimestamp());
std::string pkgName = item->getPkgName();
int64_t pkgVersionCode = item->getPkgVersionCode();
int64_t mediaApexVersion = 0;
diff --git a/services/mediaanalytics/statsd_recorder.cpp b/services/mediaanalytics/statsd_recorder.cpp
index d286f00..afb74da 100644
--- a/services/mediaanalytics/statsd_recorder.cpp
+++ b/services/mediaanalytics/statsd_recorder.cpp
@@ -37,12 +37,12 @@
namespace android {
-bool statsd_recorder(MediaAnalyticsItem *item)
+bool statsd_recorder(const MediaAnalyticsItem *item)
{
if (item == NULL) return false;
// these go into the statsd wrapper
- nsecs_t timestamp = item->getTimestamp();
+ const nsecs_t timestamp = MediaAnalyticsService::roundTime(item->getTimestamp());
std::string pkgName = item->getPkgName();
int64_t pkgVersionCode = item->getPkgVersionCode();
int64_t mediaApexVersion = 0;
diff --git a/services/mediaanalytics/tests/mediametrics_tests.cpp b/services/mediaanalytics/tests/mediametrics_tests.cpp
index 09ca114..89b5383 100644
--- a/services/mediaanalytics/tests/mediametrics_tests.cpp
+++ b/services/mediaanalytics/tests/mediametrics_tests.cpp
@@ -26,6 +26,15 @@
using namespace android;
+static size_t countNewlines(const char *s) {
+ size_t count = 0;
+ while ((s = strchr(s, '\n')) != nullptr) {
+ ++s;
+ ++count;
+ }
+ return count;
+}
+
TEST(mediametrics_tests, instantiate) {
sp mediaMetrics = new MediaAnalyticsService();
status_t status;
@@ -281,3 +290,322 @@
}
ASSERT_EQ(31, mask);
}
+
+TEST(mediametrics_tests, item_expansion) {
+ mediametrics::Item<1> item("I");
+ item.set("i32", (int32_t)1)
+ .set("i64", (int64_t)2)
+ .set("double", (double)3.125)
+ .set("string", "abcdefghijklmnopqrstuvwxyz")
+ .set("rate", std::pair<int64_t, int64_t>(11, 12));
+ ASSERT_TRUE(item.updateHeader());
+
+ MediaAnalyticsItem item2;
+ item2.readFromByteString(item.getBuffer(), item.getLength());
+ ASSERT_EQ((pid_t)-1, item2.getPid());
+ ASSERT_EQ((uid_t)-1, item2.getUid());
+ int mask = 0;
+ for (auto &prop : item2) {
+ const char *name = prop.getName();
+ if (!strcmp(name, "i32")) {
+ int32_t i32;
+ ASSERT_TRUE(prop.get(&i32));
+ ASSERT_EQ(1, i32);
+ mask |= 1;
+ } else if (!strcmp(name, "i64")) {
+ int64_t i64;
+ ASSERT_TRUE(prop.get(&i64));
+ ASSERT_EQ(2, i64);
+ mask |= 2;
+ } else if (!strcmp(name, "double")) {
+ double d;
+ ASSERT_TRUE(prop.get(&d));
+ ASSERT_EQ(3.125, d);
+ mask |= 4;
+ } else if (!strcmp(name, "string")) {
+ const char *s;
+ ASSERT_TRUE(prop.get(&s));
+ ASSERT_EQ(0, strcmp(s, "abcdefghijklmnopqrstuvwxyz"));
+ mask |= 8;
+ } else if (!strcmp(name, "rate")) {
+ std::pair<int64_t, int64_t> r;
+ ASSERT_TRUE(prop.get(&r));
+ ASSERT_EQ(11, r.first);
+ ASSERT_EQ(12, r.second);
+ mask |= 16;
+ } else {
+ FAIL();
+ }
+ }
+ ASSERT_EQ(31, mask);
+}
+
+TEST(mediametrics_tests, item_expansion2) {
+ mediametrics::Item<1> item("Bigly");
+ item.setPid(123)
+ .setUid(456);
+ constexpr size_t count = 10000;
+
+ for (size_t i = 0; i < count; ++i) {
+ // printf("recording %zu, %p, len:%zu of %zu remaining:%zu \n", i, item.getBuffer(), item.getLength(), item.getCapacity(), item.getRemaining());
+ item.set(std::to_string(i).c_str(), (int32_t)i);
+ }
+ ASSERT_TRUE(item.updateHeader());
+
+ MediaAnalyticsItem item2;
+ printf("begin buffer:%p length:%zu\n", item.getBuffer(), item.getLength());
+ fflush(stdout);
+ item2.readFromByteString(item.getBuffer(), item.getLength());
+
+ ASSERT_EQ((pid_t)123, item2.getPid());
+ ASSERT_EQ((uid_t)456, item2.getUid());
+ for (size_t i = 0; i < count; ++i) {
+ int32_t i32;
+ ASSERT_TRUE(item2.getInt32(std::to_string(i).c_str(), &i32));
+ ASSERT_EQ((int32_t)i, i32);
+ }
+}
+
+TEST(mediametrics_tests, time_machine_storage) {
+ auto item = std::make_shared<MediaAnalyticsItem>("Key");
+ (*item).set("i32", (int32_t)1)
+ .set("i64", (int64_t)2)
+ .set("double", (double)3.125)
+ .set("string", "abcdefghijklmnopqrstuvwxyz")
+ .set("rate", std::pair<int64_t, int64_t>(11, 12));
+
+ // Let's put the item in
+ android::mediametrics::TimeMachine timeMachine;
+ ASSERT_EQ(NO_ERROR, timeMachine.put(item, true));
+
+ // Can we read the values?
+ int32_t i32;
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key", "i32", &i32, -1));
+ ASSERT_EQ(1, i32);
+
+ int64_t i64;
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key", "i64", &i64, -1));
+ ASSERT_EQ(2, i64);
+
+ double d;
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key", "double", &d, -1));
+ ASSERT_EQ(3.125, d);
+
+ std::string s;
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key", "string", &s, -1));
+ ASSERT_EQ("abcdefghijklmnopqrstuvwxyz", s);
+
+ // Using fully qualified name?
+ i32 = 0;
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key.i32", &i32, -1));
+ ASSERT_EQ(1, i32);
+
+ i64 = 0;
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key.i64", &i64, -1));
+ ASSERT_EQ(2, i64);
+
+ d = 0.;
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key.double", &d, -1));
+ ASSERT_EQ(3.125, d);
+
+ s.clear();
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key.string", &s, -1));
+ ASSERT_EQ("abcdefghijklmnopqrstuvwxyz", s);
+}
+
+TEST(mediametrics_tests, time_machine_remote_key) {
+ auto item = std::make_shared<MediaAnalyticsItem>("Key1");
+ (*item).set("one", (int32_t)1)
+ .set("two", (int32_t)2);
+
+ android::mediametrics::TimeMachine timeMachine;
+ ASSERT_EQ(NO_ERROR, timeMachine.put(item, true));
+
+ auto item2 = std::make_shared<MediaAnalyticsItem>("Key2");
+ (*item2).set("three", (int32_t)3)
+ .set("[Key1]four", (int32_t)4) // affects Key1
+ .set("[Key1]five", (int32_t)5); // affects key1
+
+ ASSERT_EQ(NO_ERROR, timeMachine.put(item2, true));
+
+ auto item3 = std::make_shared<MediaAnalyticsItem>("Key2");
+ (*item3).set("six", (int32_t)6)
+ .set("[Key1]seven", (int32_t)7); // affects Key1
+
+ ASSERT_EQ(NO_ERROR, timeMachine.put(item3, false)); // remote keys not allowed.
+
+ // Can we read the values?
+ int32_t i32;
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key1.one", &i32, -1));
+ ASSERT_EQ(1, i32);
+
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key1.two", &i32, -1));
+ ASSERT_EQ(2, i32);
+
+ ASSERT_EQ(BAD_VALUE, timeMachine.get("Key1.three", &i32, -1));
+
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key2.three", &i32, -1));
+ ASSERT_EQ(3, i32);
+
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key1.four", &i32, -1));
+ ASSERT_EQ(4, i32);
+
+ ASSERT_EQ(BAD_VALUE, timeMachine.get("Key2.four", &i32, -1));
+
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key1.five", &i32, -1));
+ ASSERT_EQ(5, i32);
+
+ ASSERT_EQ(BAD_VALUE, timeMachine.get("Key2.five", &i32, -1));
+
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key2.six", &i32, -1));
+ ASSERT_EQ(6, i32);
+
+ ASSERT_EQ(BAD_VALUE, timeMachine.get("Key2.seven", &i32, -1));
+}
+
+TEST(mediametrics_tests, time_machine_gc) {
+ auto item = std::make_shared<MediaAnalyticsItem>("Key1");
+ (*item).set("one", (int32_t)1)
+ .set("two", (int32_t)2)
+ .setTimestamp(10);
+
+ android::mediametrics::TimeMachine timeMachine(1, 2); // keep at most 2 keys.
+
+ ASSERT_EQ((size_t)0, timeMachine.size());
+
+ ASSERT_EQ(NO_ERROR, timeMachine.put(item, true));
+
+ ASSERT_EQ((size_t)1, timeMachine.size());
+
+ auto item2 = std::make_shared<MediaAnalyticsItem>("Key2");
+ (*item2).set("three", (int32_t)3)
+ .set("[Key1]three", (int32_t)3)
+ .setTimestamp(11);
+
+ ASSERT_EQ(NO_ERROR, timeMachine.put(item2, true));
+ ASSERT_EQ((size_t)2, timeMachine.size());
+
+ //printf("Before\n%s\n\n", timeMachine.dump().c_str());
+
+ auto item3 = std::make_shared<MediaAnalyticsItem>("Key3");
+ (*item3).set("six", (int32_t)6)
+ .set("[Key1]four", (int32_t)4) // affects Key1
+ .set("[Key1]five", (int32_t)5) // affects key1
+ .setTimestamp(12);
+
+ ASSERT_EQ(NO_ERROR, timeMachine.put(item3, true));
+
+ ASSERT_EQ((size_t)2, timeMachine.size());
+
+ // Can we read the values?
+ int32_t i32;
+ ASSERT_EQ(BAD_VALUE, timeMachine.get("Key1.one", &i32, -1));
+ ASSERT_EQ(BAD_VALUE, timeMachine.get("Key1.two", &i32, -1));
+ ASSERT_EQ(BAD_VALUE, timeMachine.get("Key1.three", &i32, -1));
+ ASSERT_EQ(BAD_VALUE, timeMachine.get("Key1.four", &i32, -1));
+ ASSERT_EQ(BAD_VALUE, timeMachine.get("Key1.five", &i32, -1));
+
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key2.three", &i32, -1));
+ ASSERT_EQ(3, i32);
+
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key3.six", &i32, -1));
+ ASSERT_EQ(6, i32);
+
+ printf("After\n%s\n", timeMachine.dump().first.c_str());
+}
+
+TEST(mediametrics_tests, transaction_log_gc) {
+ auto item = std::make_shared<MediaAnalyticsItem>("Key1");
+ (*item).set("one", (int32_t)1)
+ .set("two", (int32_t)2)
+ .setTimestamp(10);
+
+ android::mediametrics::TransactionLog transactionLog(1, 2); // keep at most 2 items
+ ASSERT_EQ((size_t)0, transactionLog.size());
+
+ ASSERT_EQ(NO_ERROR, transactionLog.put(item));
+ ASSERT_EQ((size_t)1, transactionLog.size());
+
+ auto item2 = std::make_shared<MediaAnalyticsItem>("Key2");
+ (*item2).set("three", (int32_t)3)
+ .set("[Key1]three", (int32_t)3)
+ .setTimestamp(11);
+
+ ASSERT_EQ(NO_ERROR, transactionLog.put(item2));
+ ASSERT_EQ((size_t)2, transactionLog.size());
+
+ auto item3 = std::make_shared<MediaAnalyticsItem>("Key3");
+ (*item3).set("six", (int32_t)6)
+ .set("[Key1]four", (int32_t)4) // affects Key1
+ .set("[Key1]five", (int32_t)5) // affects key1
+ .setTimestamp(12);
+
+ ASSERT_EQ(NO_ERROR, transactionLog.put(item3));
+ ASSERT_EQ((size_t)2, transactionLog.size());
+}
+
+TEST(mediametrics_tests, audio_analytics_permission) {
+ auto item = std::make_shared<MediaAnalyticsItem>("audio.1");
+ (*item).set("one", (int32_t)1)
+ .set("two", (int32_t)2)
+ .setTimestamp(10);
+
+ auto item2 = std::make_shared<MediaAnalyticsItem>("audio.1");
+ (*item2).set("three", (int32_t)3)
+ .setTimestamp(11);
+
+ auto item3 = std::make_shared<MediaAnalyticsItem>("audio.2");
+ (*item3).set("four", (int32_t)4)
+ .setTimestamp(12);
+
+ android::mediametrics::AudioAnalytics audioAnalytics;
+
+ // untrusted entities cannot create a new key.
+ ASSERT_EQ(PERMISSION_DENIED, audioAnalytics.submit(item, false /* isTrusted */));
+ ASSERT_EQ(PERMISSION_DENIED, audioAnalytics.submit(item2, false /* isTrusted */));
+
+ // TODO: Verify contents of AudioAnalytics.
+ // Currently there is no getter API in AudioAnalytics besides dump.
+ ASSERT_EQ(4, audioAnalytics.dump(1000).second /* lines */);
+
+ ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item, true /* isTrusted */));
+ // untrusted entities can add to an existing key
+ ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item2, false /* isTrusted */));
+
+ // Check that we have some info in the dump.
+ ASSERT_LT(4, audioAnalytics.dump(1000).second /* lines */);
+}
+
+TEST(mediametrics_tests, audio_analytics_dump) {
+ auto item = std::make_shared<MediaAnalyticsItem>("audio.1");
+ (*item).set("one", (int32_t)1)
+ .set("two", (int32_t)2)
+ .setTimestamp(10);
+
+ auto item2 = std::make_shared<MediaAnalyticsItem>("audio.1");
+ (*item2).set("three", (int32_t)3)
+ .setTimestamp(11);
+
+ auto item3 = std::make_shared<MediaAnalyticsItem>("audio.2");
+ (*item3).set("four", (int32_t)4)
+ .setTimestamp(12);
+
+ android::mediametrics::AudioAnalytics audioAnalytics;
+
+ ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item, true /* isTrusted */));
+ // untrusted entities can add to an existing key
+ ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item2, false /* isTrusted */));
+ ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item3, true /* isTrusted */));
+
+ // find out how many lines we have.
+ auto [string, lines] = audioAnalytics.dump(1000);
+ ASSERT_EQ(lines, (int32_t) countNewlines(string.c_str()));
+
+ printf("AudioAnalytics: %s", string.c_str());
+ // ensure that dump operates over those lines.
+ for (int32_t ll = 0; ll < lines; ++ll) {
+ auto [s, l] = audioAnalytics.dump(ll);
+ ASSERT_EQ(ll, l);
+ ASSERT_EQ(ll, (int32_t) countNewlines(s.c_str()));
+ }
+}
diff --git a/services/mediaextractor/MediaExtractorService.cpp b/services/mediaextractor/MediaExtractorService.cpp
index 6239fb2..9e814d1 100644
--- a/services/mediaextractor/MediaExtractorService.cpp
+++ b/services/mediaextractor/MediaExtractorService.cpp
@@ -29,48 +29,57 @@
namespace android {
-MediaExtractorService::MediaExtractorService()
- : BnMediaExtractorService() {
+MediaExtractorService::MediaExtractorService() {
MediaExtractorFactory::LoadExtractors();
}
-sp<IMediaExtractor> MediaExtractorService::makeExtractor(
- const sp<IDataSource> &remoteSource, const char *mime) {
- ALOGV("@@@ MediaExtractorService::makeExtractor for %s", mime);
+MediaExtractorService::~MediaExtractorService() {
+ ALOGE("should not be in ~MediaExtractorService");
+}
+
+::android::binder::Status MediaExtractorService::makeExtractor(
+ const ::android::sp<::android::IDataSource>& remoteSource,
+ const ::std::unique_ptr< ::std::string> &mime,
+ ::android::sp<::android::IMediaExtractor>* _aidl_return) {
+ ALOGV("@@@ MediaExtractorService::makeExtractor for %s", mime.get()->c_str());
sp<DataSource> localSource = CreateDataSourceFromIDataSource(remoteSource);
- sp<IMediaExtractor> extractor = MediaExtractorFactory::CreateFromService(localSource, mime);
+ sp<IMediaExtractor> extractor = MediaExtractorFactory::CreateFromService(
+ localSource,
+ mime.get() ? mime.get()->c_str() : nullptr);
ALOGV("extractor service created %p (%s)",
extractor.get(),
extractor == nullptr ? "" : extractor->name());
if (extractor != nullptr) {
- registerMediaExtractor(extractor, localSource, mime);
- return extractor;
+ registerMediaExtractor(extractor, localSource, mime.get() ? mime.get()->c_str() : nullptr);
}
- return nullptr;
+ *_aidl_return = extractor;
+ return binder::Status::ok();
}
-sp<IDataSource> MediaExtractorService::makeIDataSource(int fd, int64_t offset, int64_t length)
-{
- sp<DataSource> source = DataSourceFactory::getInstance()->CreateFromFd(fd, offset, length);
- return CreateIDataSourceFromDataSource(source);
+::android::binder::Status MediaExtractorService::makeIDataSource(
+ const base::unique_fd &fd,
+ int64_t offset,
+ int64_t length,
+ ::android::sp<::android::IDataSource>* _aidl_return) {
+ // the caller will close the fd owned by the unique_fd upon return of this function,
+ // so we need to dup() it to retain it.
+ sp<DataSource> source = DataSourceFactory::getInstance()->CreateFromFd(dup(fd.get()), offset, length);
+ *_aidl_return = CreateIDataSourceFromDataSource(source);
+ return binder::Status::ok();
}
-std::unordered_set<std::string> MediaExtractorService::getSupportedTypes() {
- return MediaExtractorFactory::getSupportedTypes();
+::android::binder::Status MediaExtractorService::getSupportedTypes(
+ ::std::vector<::std::string>* _aidl_return) {
+ *_aidl_return = MediaExtractorFactory::getSupportedTypes();
+ return binder::Status::ok();
}
status_t MediaExtractorService::dump(int fd, const Vector<String16>& args) {
return MediaExtractorFactory::dump(fd, args) || dumpExtractors(fd, args);
}
-status_t MediaExtractorService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
- uint32_t flags)
-{
- return BnMediaExtractorService::onTransact(code, data, reply, flags);
-}
-
} // namespace android
diff --git a/services/mediaextractor/MediaExtractorService.h b/services/mediaextractor/MediaExtractorService.h
index c9cebcf..1b61c4b 100644
--- a/services/mediaextractor/MediaExtractorService.h
+++ b/services/mediaextractor/MediaExtractorService.h
@@ -18,31 +18,33 @@
#define ANDROID_MEDIA_EXTRACTOR_SERVICE_H
#include <binder/BinderService.h>
-#include <media/IMediaExtractorService.h>
-#include <media/IMediaExtractor.h>
+#include <android/BnMediaExtractorService.h>
+#include <android/IMediaExtractor.h>
namespace android {
class MediaExtractorService : public BinderService<MediaExtractorService>, public BnMediaExtractorService
{
- friend class BinderService<MediaExtractorService>; // for MediaExtractorService()
public:
MediaExtractorService();
- virtual ~MediaExtractorService() { }
- virtual void onFirstRef() { }
+ virtual ~MediaExtractorService();
static const char* getServiceName() { return "media.extractor"; }
- virtual sp<IMediaExtractor> makeExtractor(const sp<IDataSource> &source, const char *mime);
+ virtual ::android::binder::Status makeExtractor(
+ const ::android::sp<::android::IDataSource>& source,
+ const ::std::unique_ptr< ::std::string> &mime,
+ ::android::sp<::android::IMediaExtractor>* _aidl_return);
- virtual sp<IDataSource> makeIDataSource(int fd, int64_t offset, int64_t length);
+ virtual ::android::binder::Status makeIDataSource(
+ const base::unique_fd &fd,
+ int64_t offset,
+ int64_t length,
+ ::android::sp<::android::IDataSource>* _aidl_return);
- virtual std::unordered_set<std::string> getSupportedTypes();
+ virtual ::android::binder::Status getSupportedTypes(::std::vector<::std::string>* _aidl_return);
- virtual status_t dump(int fd, const Vector<String16>& args);
-
- virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
- uint32_t flags);
+ virtual status_t dump(int fd, const Vector<String16>& args);
private:
Mutex mLock;
diff --git a/services/mediaresourcemanager/Android.bp b/services/mediaresourcemanager/Android.bp
index d468406..a3519d5 100644
--- a/services/mediaresourcemanager/Android.bp
+++ b/services/mediaresourcemanager/Android.bp
@@ -12,6 +12,7 @@
"libmedia",
"libmediautils",
"libbinder",
+ "libbinder_ndk",
"libutils",
"liblog",
],
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index ae832c7..877c44d 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -19,6 +19,8 @@
#define LOG_TAG "ResourceManagerService"
#include <utils/Log.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
#include <binder/IMediaResourceMonitor.h>
#include <binder/IServiceManager.h>
#include <cutils/sched_policy.h>
@@ -38,28 +40,25 @@
namespace android {
-namespace media {
+DeathNotifier::DeathNotifier(const std::shared_ptr<ResourceManagerService> &service,
+ int pid, int64_t clientId)
+ : mService(service), mPid(pid), mClientId(clientId) {}
-class DeathNotifier : public IBinder::DeathRecipient {
-public:
- DeathNotifier(const wp<ResourceManagerService> &service, int pid, int64_t clientId)
- : mService(service), mPid(pid), mClientId(clientId) {}
+//static
+void DeathNotifier::BinderDiedCallback(void* cookie) {
+ auto thiz = static_cast<DeathNotifier*>(cookie);
+ thiz->binderDied();
+}
- virtual void binderDied(const wp<IBinder> & /* who */) override {
- // Don't check for pid validity since we know it's already dead.
- sp<ResourceManagerService> service = mService.promote();
- if (service == nullptr) {
- ALOGW("ResourceManagerService is dead as well.");
- return;
- }
- service->removeResource(mPid, mClientId, false);
+void DeathNotifier::binderDied() {
+ // Don't check for pid validity since we know it's already dead.
+ std::shared_ptr<ResourceManagerService> service = mService.lock();
+ if (service == nullptr) {
+ ALOGW("ResourceManagerService is dead as well.");
+ return;
}
-
-private:
- wp<ResourceManagerService> mService;
- int mPid;
- int64_t mClientId;
-};
+ service->removeResource(mPid, mClientId, false);
+}
template <typename T>
static String8 getString(const std::vector<T> &items) {
@@ -104,7 +103,7 @@
static ResourceInfo& getResourceInfoForEdit(
uid_t uid,
int64_t clientId,
- const sp<IResourceManagerClient>& client,
+ const std::shared_ptr<IResourceManagerClient>& client,
ResourceInfos& infos) {
ssize_t index = infos.indexOfKey(clientId);
@@ -135,14 +134,15 @@
}
}
-status_t ResourceManagerService::dump(int fd, const Vector<String16>& /* args */) {
+binder_status_t ResourceManagerService::dump(
+ int fd, const char** /*args*/, uint32_t /*numArgs*/) {
String8 result;
if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
result.format("Permission Denial: "
"can't dump ResourceManagerService from pid=%d, uid=%d\n",
- IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid());
+ AIBinder_getCallingPid(),
+ AIBinder_getCallingUid());
write(fd, result.string(), result.size());
return PERMISSION_DENIED;
}
@@ -206,7 +206,7 @@
struct SystemCallbackImpl :
public ResourceManagerService::SystemCallbackInterface {
- SystemCallbackImpl() {}
+ SystemCallbackImpl() : mClientToken(new BBinder()) {}
virtual void noteStartVideo(int uid) override {
BatteryNotifier::getInstance().noteStartVideo(uid);
@@ -217,9 +217,8 @@
virtual void noteResetVideo() override {
BatteryNotifier::getInstance().noteResetVideo();
}
- virtual bool requestCpusetBoost(
- bool enable, const sp<IInterface> &client) override {
- return android::requestCpusetBoost(enable, client);
+ virtual bool requestCpusetBoost(bool enable) override {
+ return android::requestCpusetBoost(enable, mClientToken);
}
protected:
@@ -227,6 +226,7 @@
private:
DISALLOW_EVIL_CONSTRUCTORS(SystemCallbackImpl);
+ sp<IBinder> mClientToken;
};
ResourceManagerService::ResourceManagerService()
@@ -240,10 +240,26 @@
mServiceLog(new ServiceLog()),
mSupportsMultipleSecureCodecs(true),
mSupportsSecureWithNonSecureCodec(true),
- mCpuBoostCount(0) {
+ mCpuBoostCount(0),
+ mDeathRecipient(AIBinder_DeathRecipient_new(DeathNotifier::BinderDiedCallback)) {
mSystemCB->noteResetVideo();
}
+//static
+void ResourceManagerService::instantiate() {
+ std::shared_ptr<ResourceManagerService> service =
+ ::ndk::SharedRefBase::make<ResourceManagerService>();
+ binder_status_t status =
+ AServiceManager_addService(service->asBinder().get(), getServiceName());
+ if (status != STATUS_OK) {
+ return;
+ }
+ // TODO: mediaserver main() is already starting the thread pool,
+ // move this to mediaserver main() when other services in mediaserver
+ // are converted to ndk-platform aidl.
+ //ABinderProcess_startThreadPool();
+}
+
ResourceManagerService::~ResourceManagerService() {}
Status ResourceManagerService::config(const std::vector<MediaResourcePolicyParcel>& policies) {
@@ -271,7 +287,7 @@
// Request it on every new instance of kCpuBoost, as the media.codec
// could have died, if we only do it the first time subsequent instances
// never gets the boost.
- if (mSystemCB->requestCpusetBoost(true, this) != OK) {
+ if (mSystemCB->requestCpusetBoost(true) != OK) {
ALOGW("couldn't request cpuset boost");
}
mCpuBoostCount++;
@@ -287,7 +303,7 @@
&& resource.subType == MediaResource::SubType::kUnspecifiedSubType
&& mCpuBoostCount > 0) {
if (--mCpuBoostCount == 0) {
- mSystemCB->requestCpusetBoost(false, this);
+ mSystemCB->requestCpusetBoost(false);
}
} else if (resource.type == MediaResource::Type::kBattery
&& resource.subType == MediaResource::SubType::kVideoCodec) {
@@ -316,7 +332,7 @@
int32_t pid,
int32_t uid,
int64_t clientId,
- const sp<IResourceManagerClient>& client,
+ const std::shared_ptr<IResourceManagerClient>& client,
const std::vector<MediaResourceParcel>& resources) {
String8 log = String8::format("addResource(pid %d, clientId %lld, resources %s)",
pid, (long long) clientId, getString(resources).string());
@@ -352,8 +368,9 @@
}
}
if (info.deathNotifier == nullptr && client != nullptr) {
- info.deathNotifier = new DeathNotifier(this, pid, clientId);
- IInterface::asBinder(client)->linkToDeath(info.deathNotifier);
+ info.deathNotifier = new DeathNotifier(ref<ResourceManagerService>(), pid, clientId);
+ AIBinder_linkToDeath(client->asBinder().get(),
+ mDeathRecipient.get(), info.deathNotifier.get());
}
notifyResourceGranted(pid, resources);
return Status::ok();
@@ -442,18 +459,20 @@
onLastRemoved(it->second, info);
}
- IInterface::asBinder(info.client)->unlinkToDeath(info.deathNotifier);
+ AIBinder_unlinkToDeath(info.client->asBinder().get(),
+ mDeathRecipient.get(), info.deathNotifier.get());
infos.removeItemsAt(index);
return Status::ok();
}
void ResourceManagerService::getClientForResource_l(
- int callingPid, const MediaResourceParcel *res, Vector<sp<IResourceManagerClient>> *clients) {
+ int callingPid, const MediaResourceParcel *res,
+ Vector<std::shared_ptr<IResourceManagerClient>> *clients) {
if (res == NULL) {
return;
}
- sp<IResourceManagerClient> client;
+ std::shared_ptr<IResourceManagerClient> client;
if (getLowestPriorityBiggestClient_l(callingPid, res->type, &client)) {
clients->push_back(client);
}
@@ -468,7 +487,7 @@
mServiceLog->add(log);
*_aidl_return = false;
- Vector<sp<IResourceManagerClient>> clients;
+ Vector<std::shared_ptr<IResourceManagerClient>> clients;
{
Mutex::Autolock lock(mLock);
if (!mProcessInfo->isValidPid(callingPid)) {
@@ -547,7 +566,7 @@
return Status::ok();
}
- sp<IResourceManagerClient> failedClient;
+ std::shared_ptr<IResourceManagerClient> failedClient;
for (size_t i = 0; i < clients.size(); ++i) {
log = String8::format("reclaimResource from client %p", clients[i].get());
mServiceLog->add(log);
@@ -590,8 +609,9 @@
}
bool ResourceManagerService::getAllClients_l(
- int callingPid, MediaResource::Type type, Vector<sp<IResourceManagerClient>> *clients) {
- Vector<sp<IResourceManagerClient>> temp;
+ int callingPid, MediaResource::Type type,
+ Vector<std::shared_ptr<IResourceManagerClient>> *clients) {
+ Vector<std::shared_ptr<IResourceManagerClient>> temp;
for (size_t i = 0; i < mMap.size(); ++i) {
ResourceInfos &infos = mMap.editValueAt(i);
for (size_t j = 0; j < infos.size(); ++j) {
@@ -616,7 +636,8 @@
}
bool ResourceManagerService::getLowestPriorityBiggestClient_l(
- int callingPid, MediaResource::Type type, sp<IResourceManagerClient> *client) {
+ int callingPid, MediaResource::Type type,
+ std::shared_ptr<IResourceManagerClient> *client) {
int lowestPriorityPid;
int lowestPriority;
int callingPriority;
@@ -688,14 +709,14 @@
}
bool ResourceManagerService::getBiggestClient_l(
- int pid, MediaResource::Type type, sp<IResourceManagerClient> *client) {
+ int pid, MediaResource::Type type, std::shared_ptr<IResourceManagerClient> *client) {
ssize_t index = mMap.indexOfKey(pid);
if (index < 0) {
ALOGE("getBiggestClient_l: can't find resource info for pid %d", pid);
return false;
}
- sp<IResourceManagerClient> clientTemp;
+ std::shared_ptr<IResourceManagerClient> clientTemp;
uint64_t largestValue = 0;
const ResourceInfos &infos = mMap.valueAt(index);
for (size_t i = 0; i < infos.size(); ++i) {
@@ -720,5 +741,4 @@
return true;
}
-} // namespace media
} // namespace android
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index b5b9f86..ae12d7b 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -18,9 +18,8 @@
#ifndef ANDROID_MEDIA_RESOURCEMANAGERSERVICE_H
#define ANDROID_MEDIA_RESOURCEMANAGERSERVICE_H
-#include <android/media/BnResourceManagerService.h>
+#include <aidl/android/media/BnResourceManagerService.h>
#include <arpa/inet.h>
-#include <binder/BinderService.h>
#include <media/MediaResource.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
@@ -30,22 +29,26 @@
namespace android {
+class DeathNotifier;
+class ResourceManagerService;
class ServiceLog;
struct ProcessInfoInterface;
-namespace media {
-
-using android::binder::Status;
+using Status = ::ndk::ScopedAStatus;
+using ::aidl::android::media::IResourceManagerClient;
+using ::aidl::android::media::BnResourceManagerService;
+using ::aidl::android::media::MediaResourceParcel;
+using ::aidl::android::media::MediaResourcePolicyParcel;
typedef std::map<std::tuple<
- MediaResource::Type, MediaResource::SubType, std::vector<uint8_t>>,
+ MediaResource::Type, MediaResource::SubType, std::vector<int8_t>>,
MediaResourceParcel> ResourceList;
struct ResourceInfo {
int64_t clientId;
uid_t uid;
- sp<IResourceManagerClient> client;
- sp<IBinder::DeathRecipient> deathNotifier;
+ std::shared_ptr<IResourceManagerClient> client;
+ sp<DeathNotifier> deathNotifier;
ResourceList resources;
};
@@ -53,27 +56,42 @@
typedef KeyedVector<int64_t, ResourceInfo> ResourceInfos;
typedef KeyedVector<int, ResourceInfos> PidResourceInfosMap;
-class ResourceManagerService
- : public BinderService<ResourceManagerService>,
- public BnResourceManagerService
-{
+class DeathNotifier : public RefBase {
+public:
+ DeathNotifier(const std::shared_ptr<ResourceManagerService> &service,
+ int pid, int64_t clientId);
+
+ ~DeathNotifier() {}
+
+ // Implement death recipient
+ static void BinderDiedCallback(void* cookie);
+ void binderDied();
+
+private:
+ std::weak_ptr<ResourceManagerService> mService;
+ int mPid;
+ int64_t mClientId;
+};
+class ResourceManagerService : public BnResourceManagerService {
public:
struct SystemCallbackInterface : public RefBase {
virtual void noteStartVideo(int uid) = 0;
virtual void noteStopVideo(int uid) = 0;
virtual void noteResetVideo() = 0;
- virtual bool requestCpusetBoost(
- bool enable, const sp<IInterface> &client) = 0;
+ virtual bool requestCpusetBoost(bool enable) = 0;
};
static char const *getServiceName() { return "media.resource_manager"; }
+ static void instantiate();
- virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual inline binder_status_t dump(
+ int /*fd*/, const char** /*args*/, uint32_t /*numArgs*/);
ResourceManagerService();
explicit ResourceManagerService(
const sp<ProcessInfoInterface> &processInfo,
const sp<SystemCallbackInterface> &systemResource);
+ virtual ~ResourceManagerService();
// IResourceManagerService interface
Status config(const std::vector<MediaResourcePolicyParcel>& policies) override;
@@ -82,7 +100,7 @@
int32_t pid,
int32_t uid,
int64_t clientId,
- const sp<IResourceManagerClient>& client,
+ const std::shared_ptr<IResourceManagerClient>& client,
const std::vector<MediaResourceParcel>& resources) override;
Status removeResource(
@@ -102,9 +120,6 @@
Status removeResource(int pid, int64_t clientId, bool checkValid);
-protected:
- virtual ~ResourceManagerService();
-
private:
friend class ResourceManagerServiceTest;
@@ -112,13 +127,13 @@
// Returns false if any client belongs to a process with higher priority than the
// calling process. The clients will remain unchanged if returns false.
bool getAllClients_l(int callingPid, MediaResource::Type type,
- Vector<sp<IResourceManagerClient>> *clients);
+ Vector<std::shared_ptr<IResourceManagerClient>> *clients);
// Gets the client who owns specified resource type from lowest possible priority process.
// Returns false if the calling process priority is not higher than the lowest process
// priority. The client will remain unchanged if returns false.
bool getLowestPriorityBiggestClient_l(int callingPid, MediaResource::Type type,
- sp<IResourceManagerClient> *client);
+ std::shared_ptr<IResourceManagerClient> *client);
// Gets lowest priority process that has the specified resource type.
// Returns false if failed. The output parameters will remain unchanged if failed.
@@ -126,14 +141,15 @@
// Gets the client who owns biggest piece of specified resource type from pid.
// Returns false if failed. The client will remain unchanged if failed.
- bool getBiggestClient_l(int pid, MediaResource::Type type, sp<IResourceManagerClient> *client);
+ bool getBiggestClient_l(int pid, MediaResource::Type type,
+ std::shared_ptr<IResourceManagerClient> *client);
bool isCallingPriorityHigher_l(int callingPid, int pid);
- // A helper function basically calls getLowestPriorityBiggestClient_l and add the result client
- // to the given Vector.
- void getClientForResource_l(int callingPid,
- const MediaResourceParcel *res, Vector<sp<IResourceManagerClient>> *clients);
+ // A helper function basically calls getLowestPriorityBiggestClient_l and add
+ // the result client to the given Vector.
+ void getClientForResource_l(int callingPid, const MediaResourceParcel *res,
+ Vector<std::shared_ptr<IResourceManagerClient>> *clients);
void onFirstAdded(const MediaResourceParcel& res, const ResourceInfo& clientInfo);
void onLastRemoved(const MediaResourceParcel& res, const ResourceInfo& clientInfo);
@@ -149,10 +165,10 @@
bool mSupportsMultipleSecureCodecs;
bool mSupportsSecureWithNonSecureCodec;
int32_t mCpuBoostCount;
+ ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
};
// ----------------------------------------------------------------------------
-} // namespace media
} // namespace android
#endif // ANDROID_MEDIA_RESOURCEMANAGERSERVICE_H
diff --git a/services/mediaresourcemanager/test/Android.bp b/services/mediaresourcemanager/test/Android.bp
index 543c87c..b6c548c 100644
--- a/services/mediaresourcemanager/test/Android.bp
+++ b/services/mediaresourcemanager/test/Android.bp
@@ -5,6 +5,7 @@
test_suites: ["device-tests"],
shared_libs: [
"libbinder",
+ "libbinder_ndk",
"liblog",
"libmedia",
"libresourcemanagerservice",
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index 203baf5..168fde9 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -21,18 +21,28 @@
#include <gtest/gtest.h>
#include "ResourceManagerService.h"
-#include <android/media/BnResourceManagerClient.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>
+namespace aidl {
namespace android {
namespace media {
+bool operator== (const MediaResourceParcel& lhs, const MediaResourceParcel& rhs) {
+ return lhs.type == rhs.type && lhs.subType == rhs.subType &&
+ lhs.id == rhs.id && lhs.value == rhs.value;
+}}}}
-using ::android::binder::Status;
+namespace android {
-static int64_t getId(const sp<IResourceManagerClient>& client) {
+using Status = ::ndk::ScopedAStatus;
+using ::aidl::android::media::BnResourceManagerClient;
+using ::aidl::android::media::IResourceManagerService;
+using ::aidl::android::media::IResourceManagerClient;
+
+static int64_t getId(const std::shared_ptr<IResourceManagerClient>& client) {
return (int64_t) client.get();
}
@@ -89,8 +99,7 @@
mEventCount++;
}
- virtual bool requestCpusetBoost(
- bool enable, const sp<IInterface> &/*client*/) override {
+ virtual bool requestCpusetBoost(bool enable) override {
mLastEvent = {enable ? EventType::CPUSET_ENABLE : EventType::CPUSET_DISABLE, 0};
mEventCount++;
return true;
@@ -112,12 +121,11 @@
struct TestClient : public BnResourceManagerClient {
- TestClient(int pid, sp<ResourceManagerService> service)
+ TestClient(int pid, const std::shared_ptr<ResourceManagerService> &service)
: mReclaimed(false), mPid(pid), mService(service) {}
Status reclaimResource(bool* _aidl_return) override {
- sp<IResourceManagerClient> client(this);
- mService->removeClient(mPid, (int64_t) client.get());
+ mService->removeClient(mPid, getId(ref<TestClient>()));
mReclaimed = true;
*_aidl_return = true;
return Status::ok();
@@ -136,13 +144,12 @@
mReclaimed = false;
}
-protected:
virtual ~TestClient() {}
private:
bool mReclaimed;
int mPid;
- sp<ResourceManagerService> mService;
+ std::shared_ptr<ResourceManagerService> mService;
DISALLOW_EVIL_CONSTRUCTORS(TestClient);
};
@@ -172,10 +179,11 @@
public:
ResourceManagerServiceTest()
: mSystemCB(new TestSystemCallback()),
- mService(new ResourceManagerService(new TestProcessInfo, mSystemCB)),
- mTestClient1(new TestClient(kTestPid1, mService)),
- mTestClient2(new TestClient(kTestPid2, mService)),
- mTestClient3(new TestClient(kTestPid2, mService)) {
+ mService(::ndk::SharedRefBase::make<ResourceManagerService>(
+ new TestProcessInfo, mSystemCB)),
+ mTestClient1(::ndk::SharedRefBase::make<TestClient>(kTestPid1, mService)),
+ mTestClient2(::ndk::SharedRefBase::make<TestClient>(kTestPid2, mService)),
+ mTestClient3(::ndk::SharedRefBase::make<TestClient>(kTestPid2, mService)) {
}
protected:
@@ -193,7 +201,7 @@
static void expectEqResourceInfo(const ResourceInfo &info,
int uid,
- sp<IResourceManagerClient> client,
+ std::shared_ptr<IResourceManagerClient> client,
const std::vector<MediaResourceParcel> &resources) {
EXPECT_EQ(uid, info.uid);
EXPECT_EQ(client, info.client);
@@ -334,11 +342,11 @@
std::vector<MediaResourcePolicyParcel> policies1;
policies1.push_back(
MediaResourcePolicy(
- IResourceManagerService::kPolicySupportsMultipleSecureCodecs(),
+ IResourceManagerService::kPolicySupportsMultipleSecureCodecs,
"true"));
policies1.push_back(
MediaResourcePolicy(
- IResourceManagerService::kPolicySupportsSecureWithNonSecureCodec(),
+ IResourceManagerService::kPolicySupportsSecureWithNonSecureCodec,
"false"));
mService->config(policies1);
EXPECT_TRUE(mService->mSupportsMultipleSecureCodecs);
@@ -347,11 +355,11 @@
std::vector<MediaResourcePolicyParcel> policies2;
policies2.push_back(
MediaResourcePolicy(
- IResourceManagerService::kPolicySupportsMultipleSecureCodecs(),
+ IResourceManagerService::kPolicySupportsMultipleSecureCodecs,
"false"));
policies2.push_back(
MediaResourcePolicy(
- IResourceManagerService::kPolicySupportsSecureWithNonSecureCodec(),
+ IResourceManagerService::kPolicySupportsSecureWithNonSecureCodec,
"true"));
mService->config(policies2);
EXPECT_FALSE(mService->mSupportsMultipleSecureCodecs);
@@ -458,7 +466,7 @@
addResource();
MediaResource::Type type = MediaResource::Type::kSecureCodec;
- Vector<sp<IResourceManagerClient> > clients;
+ Vector<std::shared_ptr<IResourceManagerClient> > clients;
EXPECT_FALSE(mService->getAllClients_l(kLowPriorityPid, type, &clients));
// some higher priority process (e.g. kTestPid2) owns the resource, so getAllClients_l
// will fail.
@@ -667,7 +675,7 @@
void testGetLowestPriorityBiggestClient() {
MediaResource::Type type = MediaResource::Type::kGraphicMemory;
- sp<IResourceManagerClient> client;
+ std::shared_ptr<IResourceManagerClient> client;
EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(kHighPriorityPid, type, &client));
addResource();
@@ -706,7 +714,7 @@
void testGetBiggestClient() {
MediaResource::Type type = MediaResource::Type::kGraphicMemory;
- sp<IResourceManagerClient> client;
+ std::shared_ptr<IResourceManagerClient> client;
EXPECT_FALSE(mService->getBiggestClient_l(kTestPid2, type, &client));
addResource();
@@ -799,10 +807,10 @@
}
sp<TestSystemCallback> mSystemCB;
- sp<ResourceManagerService> mService;
- sp<IResourceManagerClient> mTestClient1;
- sp<IResourceManagerClient> mTestClient2;
- sp<IResourceManagerClient> mTestClient3;
+ std::shared_ptr<ResourceManagerService> mService;
+ std::shared_ptr<IResourceManagerClient> mTestClient1;
+ std::shared_ptr<IResourceManagerClient> mTestClient2;
+ std::shared_ptr<IResourceManagerClient> mTestClient3;
};
TEST_F(ResourceManagerServiceTest, config) {
@@ -862,5 +870,4 @@
testCpusetBoost();
}
-} // namespace media
} // namespace android
diff --git a/services/mediatranscoding/.clang-format b/services/mediatranscoding/.clang-format
new file mode 100644
index 0000000..f14cc88
--- /dev/null
+++ b/services/mediatranscoding/.clang-format
@@ -0,0 +1,33 @@
+---
+BasedOnStyle: Google
+AllowShortFunctionsOnASingleLine: Inline
+AllowShortIfStatementsOnASingleLine: true
+AllowShortLoopsOnASingleLine: true
+BinPackArguments: true
+BinPackParameters: true
+CommentPragmas: NOLINT:.*
+ContinuationIndentWidth: 8
+DerivePointerAlignment: false
+IndentWidth: 4
+PointerAlignment: Left
+TabWidth: 4
+
+# Deviations from the above file:
+# "Don't indent the section label"
+AccessModifierOffset: -4
+# "Each line of text in your code should be at most 100 columns long."
+ColumnLimit: 100
+# "Constructor initializer lists can be all on one line or with subsequent
+# lines indented eight spaces.". clang-format does not support having the colon
+# on the same line as the constructor function name, so this is the best
+# approximation of that rule, which makes all entries in the list (except the
+# first one) have an eight space indentation.
+ConstructorInitializerIndentWidth: 6
+# There is nothing in go/droidcppstyle about case labels, but there seems to be
+# more code that does not indent the case labels in frameworks/base.
+IndentCaseLabels: false
+# There have been some bugs in which subsequent formatting operations introduce
+# weird comment jumps.
+ReflowComments: false
+# Android does support C++11 now.
+Standard: Cpp11
\ No newline at end of file
diff --git a/services/mediatranscoding/Android.bp b/services/mediatranscoding/Android.bp
new file mode 100644
index 0000000..3dc43f1
--- /dev/null
+++ b/services/mediatranscoding/Android.bp
@@ -0,0 +1,60 @@
+// service library
+cc_library_shared {
+ name: "libmediatranscodingservice",
+
+ srcs: ["MediaTranscodingService.cpp"],
+
+ shared_libs: [
+ "libbinder_ndk",
+ "liblog",
+ ],
+
+ static_libs: [
+ "mediatranscoding_aidl_interface-ndk_platform",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+}
+
+cc_binary {
+ name: "mediatranscoding",
+
+ srcs: [
+ "main_mediatranscodingservice.cpp",
+ ],
+
+ shared_libs: [
+ // TODO(hkuang): Use libbinder_ndk
+ "libbinder",
+ "libutils",
+ "liblog",
+ "libbase",
+ "libmediatranscodingservice",
+ ],
+
+ static_libs: [
+ "mediatranscoding_aidl_interface-ndk_platform",
+ ],
+
+ target: {
+ android: {
+ product_variables: {
+ malloc_not_svelte: {
+ // Scudo increases memory footprint, so only enable on
+ // non-svelte devices.
+ shared_libs: ["libc_scudo"],
+ },
+ },
+ },
+ },
+
+ init_rc: ["mediatranscoding.rc"],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+}
diff --git a/services/mediatranscoding/MODULE_LICENSE_APACHE2 b/services/mediatranscoding/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/services/mediatranscoding/MODULE_LICENSE_APACHE2
diff --git a/services/mediatranscoding/MediaTranscodingService.cpp b/services/mediatranscoding/MediaTranscodingService.cpp
new file mode 100644
index 0000000..2680cee
--- /dev/null
+++ b/services/mediatranscoding/MediaTranscodingService.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaTranscodingService"
+#include "MediaTranscodingService.h"
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <utils/Log.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+namespace media {
+
+using android::media::MediaTranscodingService;
+
+MediaTranscodingService::MediaTranscodingService() {
+ ALOGV("MediaTranscodingService is created");
+}
+
+MediaTranscodingService::~MediaTranscodingService() {
+ ALOGE("Should not be in ~MediaTranscodingService");
+}
+
+binder_status_t MediaTranscodingService::dump(int /* fd */, const char** /*args*/,
+ uint32_t /*numArgs*/) {
+ // TODO(hkuang): Add implementation.
+ return OK;
+}
+
+//static
+void MediaTranscodingService::instantiate() {
+ std::shared_ptr<MediaTranscodingService> service =
+ ::ndk::SharedRefBase::make<MediaTranscodingService>();
+ binder_status_t status =
+ AServiceManager_addService(service->asBinder().get(), getServiceName());
+ if (status != STATUS_OK) {
+ return;
+ }
+}
+
+Status MediaTranscodingService::registerClient(
+ const std::shared_ptr<ITranscodingServiceClient>& /*in_client*/,
+ int32_t* /*_aidl_return*/) {
+ // TODO(hkuang): Add implementation.
+ return Status::ok();
+}
+
+Status MediaTranscodingService::unregisterClient(int32_t /*clientId*/, bool* /*_aidl_return*/) {
+ // TODO(hkuang): Add implementation.
+ return Status::ok();
+}
+
+Status MediaTranscodingService::submitRequest(int32_t /*clientId*/,
+ const TranscodingRequest& /*request*/,
+ TranscodingJob* /*job*/, int32_t* /*_aidl_return*/) {
+ // TODO(hkuang): Add implementation.
+ return Status::ok();
+}
+
+Status MediaTranscodingService::cancelJob(int32_t /*in_clientId*/, int32_t /*in_jobId*/,
+ bool* /*_aidl_return*/) {
+ // TODO(hkuang): Add implementation.
+ return Status::ok();
+}
+
+Status MediaTranscodingService::getJobWithId(int32_t /*in_jobId*/, TranscodingJob* /*out_job*/,
+ bool* /*_aidl_return*/) {
+ // TODO(hkuang): Add implementation.
+ return Status::ok();
+}
+
+} // namespace media
+} // namespace android
diff --git a/services/mediatranscoding/MediaTranscodingService.h b/services/mediatranscoding/MediaTranscodingService.h
new file mode 100644
index 0000000..c2c30b9
--- /dev/null
+++ b/services/mediatranscoding/MediaTranscodingService.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_TRANSCODING_SERVICE_H
+#define ANDROID_MEDIA_TRANSCODING_SERVICE_H
+
+#include <aidl/android/media/BnMediaTranscodingService.h>
+#include <binder/IServiceManager.h>
+
+namespace android {
+
+namespace media {
+
+using Status = ::ndk::ScopedAStatus;
+using ::aidl::android::media::BnMediaTranscodingService;
+using ::aidl::android::media::ITranscodingServiceClient;
+using ::aidl::android::media::TranscodingJob;
+using ::aidl::android::media::TranscodingRequest;
+
+class MediaTranscodingService : public BnMediaTranscodingService {
+public:
+ MediaTranscodingService();
+ virtual ~MediaTranscodingService();
+
+ static void instantiate();
+
+ static const char* getServiceName() { return "media.transcoding"; }
+
+ Status registerClient(const std::shared_ptr<ITranscodingServiceClient>& in_client,
+ int32_t* _aidl_return) override;
+
+ Status unregisterClient(int32_t clientId, bool* _aidl_return) override;
+
+ Status submitRequest(int32_t in_clientId, const TranscodingRequest& in_request,
+ TranscodingJob* out_job, int32_t* _aidl_return) override;
+
+ Status cancelJob(int32_t in_clientId, int32_t in_jobId, bool* _aidl_return) override;
+
+ Status getJobWithId(int32_t in_jobId, TranscodingJob* out_job, bool* _aidl_return) override;
+
+ virtual inline binder_status_t dump(int /*fd*/, const char** /*args*/, uint32_t /*numArgs*/);
+
+private:
+};
+
+} // namespace media
+} // namespace android
+
+#endif // ANDROID_MEDIA_TRANSCODING_SERVICE_H
diff --git a/services/mediatranscoding/NOTICE b/services/mediatranscoding/NOTICE
new file mode 100644
index 0000000..9f46052
--- /dev/null
+++ b/services/mediatranscoding/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-2019, The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/services/mediatranscoding/OWNERS b/services/mediatranscoding/OWNERS
new file mode 100644
index 0000000..825c586
--- /dev/null
+++ b/services/mediatranscoding/OWNERS
@@ -0,0 +1,4 @@
+akersten@google.com
+hkuang@google.com
+lnilsson@google.com
+
diff --git a/services/mediatranscoding/main_mediatranscodingservice.cpp b/services/mediatranscoding/main_mediatranscodingservice.cpp
new file mode 100644
index 0000000..1978eb4
--- /dev/null
+++ b/services/mediatranscoding/main_mediatranscodingservice.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+
+#include "MediaTranscodingService.h"
+
+using namespace android;
+
+int main(int argc __unused, char** argv) {
+ LOG(INFO) << "media transcoding service starting";
+
+ // TODO(hkuang): Start the service with libbinder_ndk.
+ strcpy(argv[0], "media.transcoding");
+ sp<ProcessState> proc(ProcessState::self());
+ sp<IServiceManager> sm = defaultServiceManager();
+ android::media::MediaTranscodingService::instantiate();
+
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+}
diff --git a/services/mediatranscoding/mediatranscoding.rc b/services/mediatranscoding/mediatranscoding.rc
new file mode 100644
index 0000000..2dc547f
--- /dev/null
+++ b/services/mediatranscoding/mediatranscoding.rc
@@ -0,0 +1,6 @@
+service media.transcoding /system/bin/mediatranscoding
+ class main
+ user media
+ group media
+ ioprio rt 4
+ writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
diff --git a/services/oboeservice/AAudioClientTracker.cpp b/services/oboeservice/AAudioClientTracker.cpp
index 8572561..6e14434 100644
--- a/services/oboeservice/AAudioClientTracker.cpp
+++ b/services/oboeservice/AAudioClientTracker.cpp
@@ -75,10 +75,10 @@
std::lock_guard<std::mutex> lock(mLock);
if (mNotificationClients.count(pid) == 0) {
- sp<NotificationClient> notificationClient = new NotificationClient(pid);
+ sp<IBinder> binder = IInterface::asBinder(client);
+ sp<NotificationClient> notificationClient = new NotificationClient(pid, binder);
mNotificationClients[pid] = notificationClient;
- sp<IBinder> binder = IInterface::asBinder(client);
status_t status = binder->linkToDeath(notificationClient);
ALOGW_IF(status != NO_ERROR, "registerClient() linkToDeath = %d\n", status);
return AAudioConvert_androidToAAudioResult(status);
@@ -113,7 +113,7 @@
if (notificationClient == 0) {
// This will get called the first time the audio server registers an internal stream.
ALOGV("registerClientStream(%d,) unrecognized pid\n", pid);
- notificationClient = new NotificationClient(pid);
+ notificationClient = new NotificationClient(pid, nullptr);
mNotificationClients[pid] = notificationClient;
}
notificationClient->registerClientStream(serviceStream);
@@ -136,8 +136,8 @@
return AAUDIO_OK;
}
-AAudioClientTracker::NotificationClient::NotificationClient(pid_t pid)
- : mProcessId(pid) {
+AAudioClientTracker::NotificationClient::NotificationClient(pid_t pid, const sp<IBinder>& binder)
+ : mProcessId(pid), mBinder(binder) {
}
AAudioClientTracker::NotificationClient::~NotificationClient() {
diff --git a/services/oboeservice/AAudioClientTracker.h b/services/oboeservice/AAudioClientTracker.h
index accf1a7..00ff467 100644
--- a/services/oboeservice/AAudioClientTracker.h
+++ b/services/oboeservice/AAudioClientTracker.h
@@ -73,7 +73,7 @@
*/
class NotificationClient : public IBinder::DeathRecipient {
public:
- NotificationClient(pid_t pid);
+ NotificationClient(pid_t pid, const android::sp<IBinder>& binder);
virtual ~NotificationClient();
int32_t getStreamCount();
@@ -91,6 +91,8 @@
mutable std::mutex mLock;
const pid_t mProcessId;
std::set<android::sp<AAudioServiceStreamBase>> mStreams;
+ // hold onto binder to receive death notifications
+ android::sp<IBinder> mBinder;
};
mutable std::mutex mLock;