Merge "Consolidate libaudioclient buffers p1"
diff --git a/apex/manifest.json b/apex/manifest.json
index 5d72031..2cf7296 100644
--- a/apex/manifest.json
+++ b/apex/manifest.json
@@ -1,6 +1,6 @@
{
"name": "com.android.media",
- "version": 319999900,
+ "version": 339999900,
"requireNativeLibs": [
"libandroid.so",
"libbinder_ndk.so",
diff --git a/apex/manifest_codec.json b/apex/manifest_codec.json
index b0d962d..82463a2 100644
--- a/apex/manifest_codec.json
+++ b/apex/manifest_codec.json
@@ -1,6 +1,6 @@
{
"name": "com.android.media.swcodec",
- "version": 319999900,
+ "version": 339999900,
"requireNativeLibs": [
":sphal"
]
diff --git a/camera/CameraSessionStats.cpp b/camera/CameraSessionStats.cpp
index bc83ec1..2a07ffc 100644
--- a/camera/CameraSessionStats.cpp
+++ b/camera/CameraSessionStats.cpp
@@ -118,6 +118,12 @@
return err;
}
+ int streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT;
+ if ((err = parcel->readInt32(&streamUseCase)) != OK) {
+ ALOGE("%s: Failed to read stream use case from parcel", __FUNCTION__);
+ return err;
+ }
+
mWidth = width;
mHeight = height;
mFormat = format;
@@ -132,6 +138,7 @@
mHistogramBins = std::move(histogramBins);
mHistogramCounts = std::move(histogramCounts);
mDynamicRangeProfile = dynamicRangeProfile;
+ mStreamUseCase = streamUseCase;
return OK;
}
@@ -214,6 +221,11 @@
return err;
}
+ if ((err = parcel->writeInt32(mStreamUseCase)) != OK) {
+ ALOGE("%s: Failed to write stream use case!", __FUNCTION__);
+ return err;
+ }
+
return OK;
}
diff --git a/camera/CameraUtils.cpp b/camera/CameraUtils.cpp
index af3c492..3473780 100644
--- a/camera/CameraUtils.cpp
+++ b/camera/CameraUtils.cpp
@@ -18,6 +18,7 @@
//#define LOG_NDEBUG 0
#include <camera/CameraUtils.h>
+#include <camera/camera2/OutputConfiguration.h>
#include <media/hardware/HardwareAPI.h>
#include <android-base/properties.h>
@@ -31,7 +32,7 @@
const char *kCameraServiceDisabledProperty = "config.disable_cameraservice";
status_t CameraUtils::getRotationTransform(const CameraMetadata& staticInfo,
- /*out*/int32_t* transform) {
+ int mirrorMode, /*out*/int32_t* transform) {
ALOGV("%s", __FUNCTION__);
if (transform == NULL) {
@@ -55,9 +56,18 @@
int32_t& flags = *transform;
- bool mirror = (entryFacing.data.u8[0] == ANDROID_LENS_FACING_FRONT);
+ int32_t mirror = 0;
+ if (mirrorMode == OutputConfiguration::MIRROR_MODE_AUTO &&
+ entryFacing.data.u8[0] == ANDROID_LENS_FACING_FRONT) {
+ mirror = NATIVE_WINDOW_TRANSFORM_FLIP_H;
+ } else if (mirrorMode == OutputConfiguration::MIRROR_MODE_H) {
+ mirror = NATIVE_WINDOW_TRANSFORM_FLIP_H;
+ } else if (mirrorMode == OutputConfiguration::MIRROR_MODE_V) {
+ mirror = NATIVE_WINDOW_TRANSFORM_FLIP_V;
+ }
+
int orientation = entry.data.i32[0];
- if (!mirror) {
+ if (mirror == 0) {
switch (orientation) {
case 0:
flags = 0;
@@ -77,25 +87,25 @@
return INVALID_OPERATION;
}
} else {
- // Front camera needs to be horizontally flipped for mirror-like behavior.
+ // - Front camera needs to be horizontally flipped for mirror-like behavior.
+ // - Application-specified mirroring needs to be applied.
// Note: Flips are applied before rotates; using XOR here as some of these flags are
// composed in terms of other flip/rotation flags, and are not bitwise-ORable.
switch (orientation) {
case 0:
- flags = NATIVE_WINDOW_TRANSFORM_FLIP_H;
+ flags = mirror;
break;
case 90:
- flags = NATIVE_WINDOW_TRANSFORM_FLIP_H ^
+ flags = mirror ^
NATIVE_WINDOW_TRANSFORM_ROT_270;
break;
case 180:
- flags = NATIVE_WINDOW_TRANSFORM_FLIP_H ^
+ flags = mirror ^
NATIVE_WINDOW_TRANSFORM_ROT_180;
break;
case 270:
- flags = NATIVE_WINDOW_TRANSFORM_FLIP_H ^
+ flags = mirror ^
NATIVE_WINDOW_TRANSFORM_ROT_90;
-
break;
default:
ALOGE("%s: Invalid HAL android.sensor.orientation value: %d",
diff --git a/camera/aidl/android/hardware/ICameraService.aidl b/camera/aidl/android/hardware/ICameraService.aidl
index 3687b15..1e748c7 100644
--- a/camera/aidl/android/hardware/ICameraService.aidl
+++ b/camera/aidl/android/hardware/ICameraService.aidl
@@ -187,6 +187,8 @@
*/
const int EVENT_NONE = 0;
const int EVENT_USER_SWITCHED = 1; // The argument is the set of new foreground user IDs.
+ const int EVENT_USB_DEVICE_ATTACHED = 2; // The argument is the deviceId and vendorId
+ const int EVENT_USB_DEVICE_DETACHED = 3; // The argument is the deviceId and vendorId
oneway void notifySystemEvent(int eventId, in int[] args);
/**
diff --git a/camera/camera2/OutputConfiguration.cpp b/camera/camera2/OutputConfiguration.cpp
index 15c9dc9..4300f9a 100644
--- a/camera/camera2/OutputConfiguration.cpp
+++ b/camera/camera2/OutputConfiguration.cpp
@@ -81,6 +81,18 @@
return mDynamicRangeProfile;
}
+int OutputConfiguration::getStreamUseCase() const {
+ return mStreamUseCase;
+}
+
+int OutputConfiguration::getTimestampBase() const {
+ return mTimestampBase;
+}
+
+int OutputConfiguration::getMirrorMode() const {
+ return mMirrorMode;
+}
+
OutputConfiguration::OutputConfiguration() :
mRotation(INVALID_ROTATION),
mSurfaceSetID(INVALID_SET_ID),
@@ -90,7 +102,10 @@
mIsDeferred(false),
mIsShared(false),
mIsMultiResolution(false),
- mDynamicRangeProfile(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) {
+ mDynamicRangeProfile(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD),
+ mStreamUseCase(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT),
+ mTimestampBase(TIMESTAMP_BASE_DEFAULT),
+ mMirrorMode(MIRROR_MODE_AUTO) {
}
OutputConfiguration::OutputConfiguration(const android::Parcel& parcel) :
@@ -177,6 +192,24 @@
return err;
}
+ int streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT;
+ if ((err = parcel->readInt32(&streamUseCase)) != OK) {
+ ALOGE("%s: Failed to read stream use case from parcel", __FUNCTION__);
+ return err;
+ }
+
+ int timestampBase = TIMESTAMP_BASE_DEFAULT;
+ if ((err = parcel->readInt32(×tampBase)) != OK) {
+ ALOGE("%s: Failed to read timestamp base from parcel", __FUNCTION__);
+ return err;
+ }
+
+ int mirrorMode = MIRROR_MODE_AUTO;
+ if ((err = parcel->readInt32(&mirrorMode)) != OK) {
+ ALOGE("%s: Failed to read mirroring mode from parcel", __FUNCTION__);
+ return err;
+ }
+
mRotation = rotation;
mSurfaceSetID = setID;
mSurfaceType = surfaceType;
@@ -185,6 +218,9 @@
mIsDeferred = isDeferred != 0;
mIsShared = isShared != 0;
mIsMultiResolution = isMultiResolution != 0;
+ mStreamUseCase = streamUseCase;
+ mTimestampBase = timestampBase;
+ mMirrorMode = mirrorMode;
for (auto& surface : surfaceShims) {
ALOGV("%s: OutputConfiguration: %p, name %s", __FUNCTION__,
surface.graphicBufferProducer.get(),
@@ -196,8 +232,11 @@
mDynamicRangeProfile = dynamicProfile;
ALOGV("%s: OutputConfiguration: rotation = %d, setId = %d, surfaceType = %d,"
- " physicalCameraId = %s, isMultiResolution = %d", __FUNCTION__, mRotation,
- mSurfaceSetID, mSurfaceType, String8(mPhysicalCameraId).string(), mIsMultiResolution);
+ " physicalCameraId = %s, isMultiResolution = %d, streamUseCase = %d, timestampBase = %d,"
+ " mirrorMode = %d",
+ __FUNCTION__, mRotation, mSurfaceSetID, mSurfaceType,
+ String8(mPhysicalCameraId).string(), mIsMultiResolution, mStreamUseCase, timestampBase,
+ mMirrorMode);
return err;
}
@@ -213,6 +252,9 @@
mPhysicalCameraId = physicalId;
mIsMultiResolution = false;
mDynamicRangeProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD;
+ mStreamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT;
+ mTimestampBase = TIMESTAMP_BASE_DEFAULT;
+ mMirrorMode = MIRROR_MODE_AUTO;
}
OutputConfiguration::OutputConfiguration(
@@ -222,7 +264,10 @@
: mGbps(gbps), mRotation(rotation), mSurfaceSetID(surfaceSetID), mSurfaceType(surfaceType),
mWidth(width), mHeight(height), mIsDeferred(false), mIsShared(isShared),
mPhysicalCameraId(physicalCameraId), mIsMultiResolution(false),
- mDynamicRangeProfile(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) { }
+ mDynamicRangeProfile(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD),
+ mStreamUseCase(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT),
+ mTimestampBase(TIMESTAMP_BASE_DEFAULT),
+ mMirrorMode(MIRROR_MODE_AUTO) { }
status_t OutputConfiguration::writeToParcel(android::Parcel* parcel) const {
@@ -272,6 +317,15 @@
err = parcel->writeInt32(mDynamicRangeProfile ? 1 : 0);
if (err != OK) return err;
+ err = parcel->writeInt32(mStreamUseCase);
+ if (err != OK) return err;
+
+ err = parcel->writeInt32(mTimestampBase);
+ if (err != OK) return err;
+
+ err = parcel->writeInt32(mMirrorMode);
+ if (err != OK) return err;
+
return OK;
}
diff --git a/camera/cameraserver/Android.bp b/camera/cameraserver/Android.bp
index 6d884cb..22bb234 100644
--- a/camera/cameraserver/Android.bp
+++ b/camera/cameraserver/Android.bp
@@ -43,6 +43,7 @@
"android.hardware.camera.provider@2.5",
"android.hardware.camera.provider@2.6",
"android.hardware.camera.provider@2.7",
+ "android.hardware.camera.provider-V1-ndk",
"android.hardware.camera.device@1.0",
"android.hardware.camera.device@3.2",
"android.hardware.camera.device@3.4",
diff --git a/camera/include/camera/CameraSessionStats.h b/camera/include/camera/CameraSessionStats.h
index 1209a20..ab2d903 100644
--- a/camera/include/camera/CameraSessionStats.h
+++ b/camera/include/camera/CameraSessionStats.h
@@ -64,19 +64,24 @@
// Dynamic range profile
int mDynamicRangeProfile;
+ // Stream use case
+ int mStreamUseCase;
CameraStreamStats() :
mWidth(0), mHeight(0), mFormat(0), mDataSpace(0), mUsage(0),
mRequestCount(0), mErrorCount(0), mStartLatencyMs(0),
mMaxHalBuffers(0), mMaxAppBuffers(0), mHistogramType(HISTOGRAM_TYPE_UNKNOWN),
- mDynamicRangeProfile(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) {}
+ mDynamicRangeProfile(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD),
+ mStreamUseCase(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT) {}
CameraStreamStats(int width, int height, int format, int dataSpace, int64_t usage,
- int maxHalBuffers, int maxAppBuffers, int dynamicRangeProfile)
+ int maxHalBuffers, int maxAppBuffers, int dynamicRangeProfile,
+ int streamUseCase)
: mWidth(width), mHeight(height), mFormat(format), mDataSpace(dataSpace),
mUsage(usage), mRequestCount(0), mErrorCount(0), mStartLatencyMs(0),
mMaxHalBuffers(maxHalBuffers), mMaxAppBuffers(maxAppBuffers),
mHistogramType(HISTOGRAM_TYPE_UNKNOWN),
- mDynamicRangeProfile(dynamicRangeProfile) {}
+ mDynamicRangeProfile(dynamicRangeProfile),
+ mStreamUseCase(streamUseCase) {}
virtual status_t readFromParcel(const android::Parcel* parcel) override;
virtual status_t writeToParcel(android::Parcel* parcel) const override;
diff --git a/camera/include/camera/CameraUtils.h b/camera/include/camera/CameraUtils.h
index a397ccd..31d25e7 100644
--- a/camera/include/camera/CameraUtils.h
+++ b/camera/include/camera/CameraUtils.h
@@ -37,10 +37,13 @@
* metadata. This is based on the sensor orientation and lens facing
* attributes of the camera device.
*
+ * If mirrorMode is not AUTO, it will be used to override the lens
+ * facing based mirror.
+ *
* Returns OK on success, or a negative error code.
*/
static status_t getRotationTransform(const CameraMetadata& staticInfo,
- /*out*/int32_t* transform);
+ int mirrorMode, /*out*/int32_t* transform);
/**
* Check if the image data is VideoNativeHandleMetadata, that contains a native handle.
diff --git a/camera/include/camera/camera2/OutputConfiguration.h b/camera/include/camera/camera2/OutputConfiguration.h
index 1631903..d7abfba 100644
--- a/camera/include/camera/camera2/OutputConfiguration.h
+++ b/camera/include/camera/camera2/OutputConfiguration.h
@@ -38,6 +38,20 @@
SURFACE_TYPE_SURFACE_VIEW = 0,
SURFACE_TYPE_SURFACE_TEXTURE = 1
};
+ enum TimestampBaseType {
+ TIMESTAMP_BASE_DEFAULT = 0,
+ TIMESTAMP_BASE_SENSOR = 1,
+ TIMESTAMP_BASE_MONOTONIC = 2,
+ TIMESTAMP_BASE_REALTIME = 3,
+ TIMESTAMP_BASE_CHOREOGRAPHER_SYNCED = 4
+ };
+ enum MirrorModeType {
+ MIRROR_MODE_AUTO = 0,
+ MIRROR_MODE_NONE = 1,
+ MIRROR_MODE_H = 2,
+ MIRROR_MODE_V = 3,
+ };
+
const std::vector<sp<IGraphicBufferProducer>>& getGraphicBufferProducers() const;
int getRotation() const;
int getSurfaceSetID() const;
@@ -49,6 +63,9 @@
bool isShared() const;
String16 getPhysicalCameraId() const;
bool isMultiResolution() const;
+ int getStreamUseCase() const;
+ int getTimestampBase() const;
+ int getMirrorMode() const;
// set of sensor pixel mode resolutions allowed {MAX_RESOLUTION, DEFAULT_MODE};
const std::vector<int32_t>& getSensorPixelModesUsed() const;
@@ -91,7 +108,10 @@
mPhysicalCameraId == other.mPhysicalCameraId &&
mIsMultiResolution == other.mIsMultiResolution &&
sensorPixelModesUsedEqual(other) &&
- mDynamicRangeProfile == other.mDynamicRangeProfile);
+ mDynamicRangeProfile == other.mDynamicRangeProfile &&
+ mStreamUseCase == other.mStreamUseCase &&
+ mTimestampBase == other.mTimestampBase &&
+ mMirrorMode == other.mMirrorMode);
}
bool operator != (const OutputConfiguration& other) const {
return !(*this == other);
@@ -131,6 +151,15 @@
if (mDynamicRangeProfile != other.mDynamicRangeProfile) {
return mDynamicRangeProfile < other.mDynamicRangeProfile;
}
+ if (mStreamUseCase != other.mStreamUseCase) {
+ return mStreamUseCase < other.mStreamUseCase;
+ }
+ if (mTimestampBase != other.mTimestampBase) {
+ return mTimestampBase < other.mTimestampBase;
+ }
+ if (mMirrorMode != other.mMirrorMode) {
+ return mMirrorMode < other.mMirrorMode;
+ }
return gbpsLessThan(other);
}
@@ -156,6 +185,9 @@
bool mIsMultiResolution;
std::vector<int32_t> mSensorPixelModesUsed;
int mDynamicRangeProfile;
+ int mStreamUseCase;
+ int mTimestampBase;
+ int mMirrorMode;
};
} // namespace params
} // namespace camera2
diff --git a/camera/ndk/NdkCameraCaptureSession.cpp b/camera/ndk/NdkCameraCaptureSession.cpp
index 1ac8482..9c98778 100644
--- a/camera/ndk/NdkCameraCaptureSession.cpp
+++ b/camera/ndk/NdkCameraCaptureSession.cpp
@@ -29,6 +29,7 @@
#include "impl/ACameraCaptureSession.h"
#include "impl/ACameraCaptureSession.inc"
+#include "NdkCameraCaptureSession.inc"
using namespace android;
@@ -72,22 +73,16 @@
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
ATRACE_CALL();
- if (session == nullptr || requests == nullptr || numRequests < 1) {
- ALOGE("%s: Error: invalid input: session %p, numRequest %d, requests %p",
- __FUNCTION__, session, numRequests, requests);
- return ACAMERA_ERROR_INVALID_PARAMETER;
- }
+ return captureTemplate(session, cbs, numRequests, requests, captureSequenceId);
+}
- if (session->isClosed()) {
- ALOGE("%s: session %p is already closed", __FUNCTION__, session);
- if (captureSequenceId != nullptr) {
- *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
- }
- return ACAMERA_ERROR_SESSION_CLOSED;
- }
-
- return session->capture(
- cbs, numRequests, requests, captureSequenceId);
+EXPORT
+camera_status_t ACameraCaptureSession_captureV2(
+ ACameraCaptureSession* session, /*optional*/ACameraCaptureSession_captureCallbacksV2* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ ATRACE_CALL();
+ return captureTemplate(session, cbs, numRequests, requests, captureSequenceId);
}
EXPORT
@@ -97,22 +92,26 @@
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
ATRACE_CALL();
- if (session == nullptr || requests == nullptr || numRequests < 1) {
- ALOGE("%s: Error: invalid input: session %p, numRequest %d, requests %p",
- __FUNCTION__, session, numRequests, requests);
- return ACAMERA_ERROR_INVALID_PARAMETER;
- }
+ return captureTemplate(session, lcbs, numRequests, requests, captureSequenceId);
+}
- if (session->isClosed()) {
- ALOGE("%s: session %p is already closed", __FUNCTION__, session);
- if (captureSequenceId) {
- *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
- }
- return ACAMERA_ERROR_SESSION_CLOSED;
- }
+EXPORT
+camera_status_t ACameraCaptureSession_logicalCamera_captureV2(
+ ACameraCaptureSession* session,
+ /*optional*/ACameraCaptureSession_logicalCamera_captureCallbacksV2* lcbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ ATRACE_CALL();
+ return captureTemplate(session, lcbs, numRequests, requests, captureSequenceId);
+}
- return session->capture(
- lcbs, numRequests, requests, captureSequenceId);
+EXPORT
+camera_status_t ACameraCaptureSession_setRepeatingRequestV2(
+ ACameraCaptureSession* session, /*optional*/ACameraCaptureSession_captureCallbacksV2* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ ATRACE_CALL();
+ return setRepeatingRequestTemplate(session, cbs, numRequests, requests, captureSequenceId);
}
EXPORT
@@ -121,23 +120,10 @@
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
ATRACE_CALL();
- if (session == nullptr || requests == nullptr || numRequests < 1) {
- ALOGE("%s: Error: invalid input: session %p, numRequest %d, requests %p",
- __FUNCTION__, session, numRequests, requests);
- return ACAMERA_ERROR_INVALID_PARAMETER;
- }
-
- if (session->isClosed()) {
- ALOGE("%s: session %p is already closed", __FUNCTION__, session);
- if (captureSequenceId) {
- *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
- }
- return ACAMERA_ERROR_SESSION_CLOSED;
- }
-
- return session->setRepeatingRequest(cbs, numRequests, requests, captureSequenceId);
+ return setRepeatingRequestTemplate(session, cbs, numRequests, requests, captureSequenceId);
}
+
EXPORT
camera_status_t ACameraCaptureSession_logicalCamera_setRepeatingRequest(
ACameraCaptureSession* session,
@@ -145,21 +131,18 @@
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
ATRACE_CALL();
- if (session == nullptr || requests == nullptr || numRequests < 1) {
- ALOGE("%s: Error: invalid input: session %p, numRequest %d, requests %p",
- __FUNCTION__, session, numRequests, requests);
- return ACAMERA_ERROR_INVALID_PARAMETER;
- }
+ return setRepeatingRequestTemplate(session, lcbs, numRequests, requests, captureSequenceId);
+}
- if (session->isClosed()) {
- ALOGE("%s: session %p is already closed", __FUNCTION__, session);
- if (captureSequenceId) {
- *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
- }
- return ACAMERA_ERROR_SESSION_CLOSED;
- }
- return session->setRepeatingRequest(lcbs, numRequests, requests, captureSequenceId);
+EXPORT
+camera_status_t ACameraCaptureSession_logicalCamera_setRepeatingRequestV2(
+ ACameraCaptureSession* session,
+ /*optional*/ACameraCaptureSession_logicalCamera_captureCallbacksV2* lcbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ ATRACE_CALL();
+ return setRepeatingRequestTemplate(session, lcbs, numRequests, requests, captureSequenceId);
}
EXPORT
diff --git a/camera/ndk/NdkCameraCaptureSession.inc b/camera/ndk/NdkCameraCaptureSession.inc
new file mode 100644
index 0000000..258e20d
--- /dev/null
+++ b/camera/ndk/NdkCameraCaptureSession.inc
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2022 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 "impl/ACameraCaptureSession.h"
+
+#include <camera/NdkCameraCaptureSession.h>
+
+using namespace android;
+
+template <class CallbackType>
+camera_status_t captureTemplate(
+ ACameraCaptureSession* session,
+ /*optional*/CallbackType* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ ATRACE_CALL();
+ if (session == nullptr || requests == nullptr || numRequests < 1) {
+ ALOGE("%s: Error: invalid input: session %p, numRequest %d, requests %p",
+ __FUNCTION__, session, numRequests, requests);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ if (session->isClosed()) {
+ ALOGE("%s: session %p is already closed", __FUNCTION__, session);
+ if (captureSequenceId) {
+ *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+ }
+ return ACAMERA_ERROR_SESSION_CLOSED;
+ }
+
+ return session->capture(
+ cbs, numRequests, requests, captureSequenceId);
+}
+
+template <class CallbackType>
+camera_status_t setRepeatingRequestTemplate(
+ ACameraCaptureSession* session,
+ /*optional*/CallbackType* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ ATRACE_CALL();
+ if (session == nullptr || requests == nullptr || numRequests < 1) {
+ ALOGE("%s: Error: invalid input: session %p, numRequest %d, requests %p",
+ __FUNCTION__, session, numRequests, requests);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ if (session->isClosed()) {
+ ALOGE("%s: session %p is already closed", __FUNCTION__, session);
+ if (captureSequenceId) {
+ *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+ }
+ return ACAMERA_ERROR_SESSION_CLOSED;
+ }
+
+ return session->setRepeatingRequest(cbs, numRequests, requests, captureSequenceId);
+}
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index dd652c7..7997768 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -26,8 +26,6 @@
#include "ACaptureRequest.h"
#include "ACameraCaptureSession.h"
-#include "ACameraCaptureSession.inc"
-
ACameraDevice::~ACameraDevice() {
mDevice->stopLooperAndDisconnect();
}
@@ -913,6 +911,7 @@
case kWhatOnError:
case kWhatSessionStateCb:
case kWhatCaptureStart:
+ case kWhatCaptureStart2:
case kWhatCaptureResult:
case kWhatLogicalCaptureResult:
case kWhatCaptureFail:
@@ -985,6 +984,7 @@
}
case kWhatSessionStateCb:
case kWhatCaptureStart:
+ case kWhatCaptureStart2:
case kWhatCaptureResult:
case kWhatLogicalCaptureResult:
case kWhatCaptureFail:
@@ -1004,6 +1004,7 @@
sp<CaptureRequest> requestSp = nullptr;
switch (msg->what()) {
case kWhatCaptureStart:
+ case kWhatCaptureStart2:
case kWhatCaptureResult:
case kWhatLogicalCaptureResult:
case kWhatCaptureFail:
@@ -1055,6 +1056,35 @@
freeACaptureRequest(request);
break;
}
+ case kWhatCaptureStart2:
+ {
+ ACameraCaptureSession_captureCallback_startV2 onStart2;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onStart2);
+ if (!found) {
+ ALOGE("%s: Cannot find capture startV2 callback!", __FUNCTION__);
+ return;
+ }
+ if (onStart2 == nullptr) {
+ return;
+ }
+ int64_t timestamp;
+ found = msg->findInt64(kTimeStampKey, ×tamp);
+ if (!found) {
+ ALOGE("%s: Cannot find timestamp!", __FUNCTION__);
+ return;
+ }
+ int64_t frameNumber;
+ found = msg->findInt64(kFrameNumberKey, &frameNumber);
+ if (!found) {
+ ALOGE("%s: Cannot find frame number!", __FUNCTION__);
+ return;
+ }
+
+ ACaptureRequest* request = allocateACaptureRequest(requestSp, mId);
+ (*onStart2)(context, session.get(), request, timestamp, frameNumber);
+ freeACaptureRequest(request);
+ break;
+ }
case kWhatCaptureResult:
{
ACameraCaptureSession_captureCallback_result onResult;
@@ -1285,7 +1315,8 @@
ACameraCaptureSession_captureCallbacks* cbs) :
mSession(session), mRequests(requests),
mIsRepeating(isRepeating),
- mIsLogicalCameraCallback(false) {
+ mIsLogicalCameraCallback(false),
+ mIs2Callback(false) {
initCaptureCallbacks(cbs);
if (cbs != nullptr) {
@@ -1301,7 +1332,8 @@
ACameraCaptureSession_logicalCamera_captureCallbacks* lcbs) :
mSession(session), mRequests(requests),
mIsRepeating(isRepeating),
- mIsLogicalCameraCallback(true) {
+ mIsLogicalCameraCallback(true),
+ mIs2Callback(false) {
initCaptureCallbacks(lcbs);
if (lcbs != nullptr) {
@@ -1310,6 +1342,40 @@
}
}
+CameraDevice::CallbackHolder::CallbackHolder(
+ sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest> >& requests,
+ bool isRepeating,
+ ACameraCaptureSession_captureCallbacksV2* cbs) :
+ mSession(session), mRequests(requests),
+ mIsRepeating(isRepeating),
+ mIsLogicalCameraCallback(false),
+ mIs2Callback(true) {
+ initCaptureCallbacksV2(cbs);
+
+ if (cbs != nullptr) {
+ mOnCaptureCompleted = cbs->onCaptureCompleted;
+ mOnCaptureFailed = cbs->onCaptureFailed;
+ }
+}
+
+CameraDevice::CallbackHolder::CallbackHolder(
+ sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest> >& requests,
+ bool isRepeating,
+ ACameraCaptureSession_logicalCamera_captureCallbacksV2* lcbs) :
+ mSession(session), mRequests(requests),
+ mIsRepeating(isRepeating),
+ mIsLogicalCameraCallback(true),
+ mIs2Callback(true) {
+ initCaptureCallbacksV2(lcbs);
+
+ if (lcbs != nullptr) {
+ mOnLogicalCameraCaptureCompleted = lcbs->onLogicalCameraCaptureCompleted;
+ mOnLogicalCameraCaptureFailed = lcbs->onLogicalCameraCaptureFailed;
+ }
+}
+
void
CameraDevice::checkRepeatingSequenceCompleteLocked(
const int sequenceId, const int64_t lastFrameNumber) {
@@ -1536,7 +1602,6 @@
const CaptureResultExtras& resultExtras,
int64_t timestamp) {
binder::Status ret = binder::Status::ok();
-
sp<CameraDevice> dev = mDevice.promote();
if (dev == nullptr) {
return ret; // device has been closed
@@ -1551,11 +1616,14 @@
int sequenceId = resultExtras.requestId;
int32_t burstId = resultExtras.burstId;
+ int64_t frameNumber = resultExtras.frameNumber;
auto it = dev->mSequenceCallbackMap.find(sequenceId);
if (it != dev->mSequenceCallbackMap.end()) {
CallbackHolder cbh = (*it).second;
+ bool v2Callback = cbh.mIs2Callback;
ACameraCaptureSession_captureCallback_start onStart = cbh.mOnCaptureStarted;
+ ACameraCaptureSession_captureCallback_startV2 onStart2 = cbh.mOnCaptureStarted2;
sp<ACameraCaptureSession> session = cbh.mSession;
if ((size_t) burstId >= cbh.mRequests.size()) {
ALOGE("%s: Error: request index %d out of bound (size %zu)",
@@ -1563,12 +1631,19 @@
dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
}
sp<CaptureRequest> request = cbh.mRequests[burstId];
- sp<AMessage> msg = new AMessage(kWhatCaptureStart, dev->mHandler);
+ sp<AMessage> msg = nullptr;
+ if (v2Callback) {
+ msg = new AMessage(kWhatCaptureStart2, dev->mHandler);
+ msg->setPointer(kCallbackFpKey, (void*) onStart2);
+ } else {
+ msg = new AMessage(kWhatCaptureStart, dev->mHandler);
+ msg->setPointer(kCallbackFpKey, (void *)onStart);
+ }
msg->setPointer(kContextKey, cbh.mContext);
msg->setObject(kSessionSpKey, session);
- msg->setPointer(kCallbackFpKey, (void*) onStart);
msg->setObject(kCaptureRequestKey, request);
msg->setInt64(kTimeStampKey, timestamp);
+ msg->setInt64(kFrameNumberKey, frameNumber);
dev->postSessionMsgAndCleanup(msg);
}
return ret;
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index 344d964..17988fe 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -215,6 +215,7 @@
kWhatSessionStateCb, // onReady, onActive
// Capture callbacks
kWhatCaptureStart, // onCaptureStarted
+ kWhatCaptureStart2, // onCaptureStarted
kWhatCaptureResult, // onCaptureProgressed, onCaptureCompleted
kWhatLogicalCaptureResult, // onLogicalCameraCaptureCompleted
kWhatCaptureFail, // onCaptureFailed
@@ -294,11 +295,18 @@
const Vector<sp<CaptureRequest> >& requests,
bool isRepeating,
ACameraCaptureSession_logicalCamera_captureCallbacks* lcbs);
-
- template <class T>
- void initCaptureCallbacks(T* cbs) {
+ CallbackHolder(sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest> >& requests,
+ bool isRepeating,
+ ACameraCaptureSession_captureCallbacksV2* cbs);
+ CallbackHolder(sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest> >& requests,
+ bool isRepeating,
+ ACameraCaptureSession_logicalCamera_captureCallbacksV2* lcbs);
+ void clearCallbacks() {
mContext = nullptr;
mOnCaptureStarted = nullptr;
+ mOnCaptureStarted2 = nullptr;
mOnCaptureProgressed = nullptr;
mOnCaptureCompleted = nullptr;
mOnLogicalCameraCaptureCompleted = nullptr;
@@ -307,6 +315,24 @@
mOnCaptureSequenceCompleted = nullptr;
mOnCaptureSequenceAborted = nullptr;
mOnCaptureBufferLost = nullptr;
+ }
+
+ template <class T>
+ void initCaptureCallbacksV2(T* cbs) {
+ clearCallbacks();
+ if (cbs != nullptr) {
+ mContext = cbs->context;
+ mOnCaptureStarted2 = cbs->onCaptureStarted;
+ mOnCaptureProgressed = cbs->onCaptureProgressed;
+ mOnCaptureSequenceCompleted = cbs->onCaptureSequenceCompleted;
+ mOnCaptureSequenceAborted = cbs->onCaptureSequenceAborted;
+ mOnCaptureBufferLost = cbs->onCaptureBufferLost;
+ }
+ }
+
+ template <class T>
+ void initCaptureCallbacks(T* cbs) {
+ clearCallbacks();
if (cbs != nullptr) {
mContext = cbs->context;
mOnCaptureStarted = cbs->onCaptureStarted;
@@ -320,9 +346,11 @@
Vector<sp<CaptureRequest> > mRequests;
const bool mIsRepeating;
const bool mIsLogicalCameraCallback;
+ const bool mIs2Callback;
void* mContext;
ACameraCaptureSession_captureCallback_start mOnCaptureStarted;
+ ACameraCaptureSession_captureCallback_startV2 mOnCaptureStarted2;
ACameraCaptureSession_captureCallback_result mOnCaptureProgressed;
ACameraCaptureSession_captureCallback_result mOnCaptureCompleted;
ACameraCaptureSession_logicalCamera_captureCallback_result mOnLogicalCameraCaptureCompleted;
diff --git a/camera/ndk/include/camera/NdkCameraCaptureSession.h b/camera/ndk/include/camera/NdkCameraCaptureSession.h
index 2b7f040..b0fd00c 100644
--- a/camera/ndk/include/camera/NdkCameraCaptureSession.h
+++ b/camera/ndk/include/camera/NdkCameraCaptureSession.h
@@ -811,6 +811,184 @@
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) __INTRODUCED_IN(29);
+/**
+ * The definition of camera capture start callback. The same as
+ * {@link ACameraCaptureSession_captureCallbacks#onCaptureStarted}, except that
+ * it has the frame number of the capture as well.
+ *
+ * @param context The optional application context provided by user in
+ * {@link ACameraCaptureSession_captureCallbacks}.
+ * @param session The camera capture session of interest.
+ * @param request The capture request that is starting. Note that this pointer points to a copy of
+ * capture request sent by application, so the address is different to what
+ * application sent but the content will match. This request will be freed by
+ * framework immediately after this callback returns.
+ * @param timestamp The timestamp when the capture is started. This timestamp will match
+ * {@link ACAMERA_SENSOR_TIMESTAMP} of the {@link ACameraMetadata} in
+ * {@link ACameraCaptureSession_captureCallbacks#onCaptureCompleted} callback.
+ * @param frameNumber the frame number of the capture started
+ */
+typedef void (*ACameraCaptureSession_captureCallback_startV2)(
+ void* context, ACameraCaptureSession* session,
+ const ACaptureRequest* request, int64_t timestamp, int64_t frameNumber);
+/**
+ * This has the same functionality as ACameraCaptureSession_captureCallbacks,
+ * with the exception that captureCallback_startV2 callback is
+ * used, instead of captureCallback_start, to support retrieving the frame number.
+ */
+typedef struct ACameraCaptureSession_captureCallbacksV2 {
+ /**
+ * Same as ACameraCaptureSession_captureCallbacks
+ */
+ void* context;
+
+ /**
+ * Same as {@link ACameraCaptureSession_captureCallbacks#onCaptureStarted},
+ * except that it has the frame number of the capture added in the parameter
+ * list.
+ */
+ ACameraCaptureSession_captureCallback_startV2 onCaptureStarted;
+
+ /**
+ * Same as {@link ACameraCaptureSession_captureCallbacks#onCaptureProgressed}.
+ */
+ ACameraCaptureSession_captureCallback_result onCaptureProgressed;
+
+ /**
+ * Same as {@link ACameraCaptureSession_captureCallbacks#onCaptureCompleted}.
+ */
+ ACameraCaptureSession_captureCallback_result onCaptureCompleted;
+
+ /**
+ * Same as {@link ACameraCaptureSession_captureCallbacks#onCaptureFailed}.
+ */
+ ACameraCaptureSession_captureCallback_failed onCaptureFailed;
+
+ /**
+ * Same as {@link ACameraCaptureSession_captureCallbacks#onCaptureSequenceCompleted}.
+ */
+ ACameraCaptureSession_captureCallback_sequenceEnd onCaptureSequenceCompleted;
+
+ /**
+ * Same as {@link ACameraCaptureSession_captureCallbacks#onCaptureSequenceAborted}.
+ */
+ ACameraCaptureSession_captureCallback_sequenceAbort onCaptureSequenceAborted;
+
+ /**
+ * Same as {@link ACameraCaptureSession_captureCallbacks#onCaptureBufferLost}.
+ */
+ ACameraCaptureSession_captureCallback_bufferLost onCaptureBufferLost;
+
+
+} ACameraCaptureSession_captureCallbacksV2;
+
+/**
+ * This has the same functionality as ACameraCaptureSession_logicalCamera_captureCallbacks,
+ * with the exception that an captureCallback_startV2 callback is
+ * used, instead of captureCallback_start, to support retrieving frame number.
+ */
+typedef struct ACameraCaptureSession_logicalCamera_captureCallbacksV2 {
+ /**
+ * Same as ACameraCaptureSession_captureCallbacks
+ */
+ void* context;
+
+ /**
+ * Same as {@link ACameraCaptureSession_captureCallbacks#onCaptureStarted},
+ * except that it has the frame number of the capture added in the parameter
+ * list.
+ */
+ ACameraCaptureSession_captureCallback_startV2 onCaptureStarted;
+
+
+ /**
+ * Same as {@link ACameraCaptureSession_captureCallbacks#onCaptureProgressed}.
+ */
+ ACameraCaptureSession_captureCallback_result onCaptureProgressed;
+
+ /**
+ * Same as
+ * {@link ACameraCaptureSession_logicalCamera_captureCallbacks#onLogicalCaptureCompleted}.
+ */
+ ACameraCaptureSession_logicalCamera_captureCallback_result onLogicalCameraCaptureCompleted;
+
+ /**
+ * This callback is called instead of {@link onLogicalCameraCaptureCompleted} when the
+ * camera device failed to produce a capture result for the
+ * request.
+ *
+ * <p>Other requests are unaffected, and some or all image buffers from
+ * the capture may have been pushed to their respective output
+ * streams.</p>
+ *
+ * <p>Note that the ACaptureRequest pointer in the callback will not match what application has
+ * submitted, but the contents the ACaptureRequest will match what application submitted.</p>
+ *
+ * @see ALogicalCameraCaptureFailure
+ */
+ ACameraCaptureSession_logicalCamera_captureCallback_failed onLogicalCameraCaptureFailed;
+
+ /**
+ * Same as {@link ACameraCaptureSession_captureCallbacks#onCaptureSequenceCompleted}.
+ */
+ ACameraCaptureSession_captureCallback_sequenceEnd onCaptureSequenceCompleted;
+
+ /**
+ * Same as {@link ACameraCaptureSession_captureCallbacks#onCaptureSequenceAborted}.
+ */
+ ACameraCaptureSession_captureCallback_sequenceAbort onCaptureSequenceAborted;
+
+ /**
+ * Same as {@link ACameraCaptureSession_captureCallbacks#onCaptureBufferLost}.
+ */
+ ACameraCaptureSession_captureCallback_bufferLost onCaptureBufferLost;
+
+} ACameraCaptureSession_logicalCamera_captureCallbacksV2;
+
+/**
+ * This has the same functionality as ACameraCaptureSession_capture, with added
+ * support for v2 of camera callbacks, where the onCaptureStarted callback
+ * adds frame number in its parameter list.
+ */
+camera_status_t ACameraCaptureSession_captureV2(
+ ACameraCaptureSession* session,
+ /*optional*/ACameraCaptureSession_captureCallbacksV2* callbacks,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) __INTRODUCED_IN(33);
+
+/**
+ * This has the same functionality as ACameraCaptureSession_logical_setRepeatingRequest, with added
+ * support for v2 of logical multi-camera callbacks where the onCaptureStarted
+ * callback adds frame number in its parameter list.
+ */
+camera_status_t ACameraCaptureSession_setRepeatingRequestV2(
+ ACameraCaptureSession* session,
+ /*optional*/ACameraCaptureSession_captureCallbacksV2* callbacks,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) __INTRODUCED_IN(33);
+
+/**
+ * This has the same functionality as ACameraCaptureSession_logical_capture, with added
+ * support for v2 of logical multi-camera callbacks where the onCaptureStarted callback
+ * adds frame number in its parameter list.
+ */
+camera_status_t ACameraCaptureSession_logicalCamera_captureV2(
+ ACameraCaptureSession* session,
+ /*optional*/ACameraCaptureSession_logicalCamera_captureCallbacksV2* callbacks,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) __INTRODUCED_IN(33);
+
+/**
+ * This has the same functionality as ACameraCaptureSession_logical_setRepeatingRequest, with added
+ * support for v2 of logical multi-camera callbacks where the onCaptureStarted
+ * callback adds frame number in its parameter list.
+ */
+camera_status_t ACameraCaptureSession_logicalCamera_setRepeatingRequestV2(
+ ACameraCaptureSession* session,
+ /*optional*/ACameraCaptureSession_logicalCamera_captureCallbacksV2* callbacks,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) __INTRODUCED_IN(33);
+
__END_DECLS
#endif /* _NDK_CAMERA_CAPTURE_SESSION_H */
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index bd281c8..4911429 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -72,6 +72,8 @@
ACAMERA_DISTORTION_CORRECTION,
ACAMERA_HEIC,
ACAMERA_HEIC_INFO,
+ ACAMERA_AUTOMOTIVE,
+ ACAMERA_AUTOMOTIVE_LENS,
ACAMERA_SECTION_COUNT,
ACAMERA_VENDOR = 0x8000
@@ -115,6 +117,8 @@
<< 16,
ACAMERA_HEIC_START = ACAMERA_HEIC << 16,
ACAMERA_HEIC_INFO_START = ACAMERA_HEIC_INFO << 16,
+ ACAMERA_AUTOMOTIVE_START = ACAMERA_AUTOMOTIVE << 16,
+ ACAMERA_AUTOMOTIVE_LENS_START = ACAMERA_AUTOMOTIVE_LENS << 16,
ACAMERA_VENDOR_START = ACAMERA_VENDOR << 16
} acamera_metadata_section_start_t;
@@ -2694,6 +2698,9 @@
* with PRIMARY_CAMERA.</p>
* <p>When ACAMERA_LENS_POSE_REFERENCE is UNDEFINED, this position cannot be accurately
* represented by the camera device, and will be represented as <code>(0, 0, 0)</code>.</p>
+ * <p>When ACAMERA_LENS_POSE_REFERENCE is AUTOMOTIVE, then this position is relative to the
+ * origin of the automotive sensor coordinate system, which is at the center of the rear
+ * axle.</p>
*
* @see ACAMERA_LENS_DISTORTION
* @see ACAMERA_LENS_INTRINSIC_CALIBRATION
@@ -4206,6 +4213,55 @@
*/
ACAMERA_SCALER_MULTI_RESOLUTION_STREAM_SUPPORTED = // byte (acamera_metadata_enum_android_scaler_multi_resolution_stream_supported_t)
ACAMERA_SCALER_START + 24,
+ /**
+ * <p>The stream use cases supported by this camera device.</p>
+ *
+ * <p>Type: int32[n] (acamera_metadata_enum_android_scaler_available_stream_use_cases_t)</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>The stream use case indicates the purpose of a particular camera stream from
+ * the end-user perspective. Some examples of camera use cases are: preview stream for
+ * live viewfinder shown to the user, still capture for generating high quality photo
+ * capture, video record for encoding the camera output for the purpose of future playback,
+ * and video call for live realtime video conferencing.</p>
+ * <p>With this flag, the camera device can optimize the image processing pipeline
+ * parameters, such as tuning, sensor mode, and ISP settings, indepedent of
+ * the properties of the immediate camera output surface. For example, if the output
+ * surface is a SurfaceTexture, the stream use case flag can be used to indicate whether
+ * the camera frames eventually go to display, video encoder,
+ * still image capture, or all of them combined.</p>
+ * <p>The application sets the use case of a camera stream by calling
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/params/OutputConfiguration.html#setStreamUseCase">OutputConfiguration#setStreamUseCase</a>.</p>
+ * <p>A camera device with
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE">CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE</a>
+ * capability must support the following stream use cases:</p>
+ * <ul>
+ * <li>DEFAULT</li>
+ * <li>PREVIEW</li>
+ * <li>STILL_CAPTURE</li>
+ * <li>VIDEO_RECORD</li>
+ * <li>PREVIEW_VIDEO_STILL</li>
+ * <li>VIDEO_CALL</li>
+ * </ul>
+ * <p>The guaranteed stream combinations related to stream use case for a camera device with
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE">CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE</a>
+ * capability is documented in the camera device
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">guideline</a>. The
+ * application is strongly recommended to use one of the guaranteed stream combintations.
+ * If the application creates a session with a stream combination not in the guaranteed
+ * list, or with mixed DEFAULT and non-DEFAULT use cases within the same session,
+ * the camera device may ignore some stream use cases due to hardware constraints
+ * and implementation details.</p>
+ * <p>For stream combinations not covered by the stream use case mandatory lists, such as
+ * reprocessable session, constrained high speed session, or RAW stream combinations, the
+ * application should leave stream use cases within the session as DEFAULT.</p>
+ */
+ ACAMERA_SCALER_AVAILABLE_STREAM_USE_CASES = // int32[n] (acamera_metadata_enum_android_scaler_available_stream_use_cases_t)
+ ACAMERA_SCALER_START + 25,
ACAMERA_SCALER_END,
/**
@@ -7150,6 +7206,87 @@
ACAMERA_HEIC_START + 5,
ACAMERA_HEIC_END,
+ /**
+ * <p>Location of the cameras on the automotive devices.</p>
+ *
+ * <p>Type: byte (acamera_metadata_enum_android_automotive_location_t)</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>This enum defines the locations of the cameras relative to the vehicle body frame on
+ * <a href="https://source.android.com/devices/sensors/sensor-types#auto_axes">the automotive sensor coordinate system</a>.
+ * If the system has FEATURE_AUTOMOTIVE, the camera will have this entry in its static
+ * metadata.</p>
+ * <ul>
+ * <li>INTERIOR is the inside of the vehicle body frame (or the passenger cabin).</li>
+ * <li>EXTERIOR is the outside of the vehicle body frame.</li>
+ * <li>EXTRA is the extra vehicle such as a trailer.</li>
+ * </ul>
+ * <p>Each side of the vehicle body frame on this coordinate system is defined as below:</p>
+ * <ul>
+ * <li>FRONT is where the Y-axis increases toward.</li>
+ * <li>REAR is where the Y-axis decreases toward.</li>
+ * <li>LEFT is where the X-axis decreases toward.</li>
+ * <li>RIGHT is where the X-axis increases toward.</li>
+ * </ul>
+ * <p>If the camera has either EXTERIOR_OTHER or EXTRA_OTHER, its static metadata will list
+ * the following entries, so that applications can determine the camera's exact location:</p>
+ * <ul>
+ * <li>ACAMERA_LENS_POSE_REFERENCE</li>
+ * <li>ACAMERA_LENS_POSE_ROTATION</li>
+ * <li>ACAMERA_LENS_POSE_TRANSLATION</li>
+ * </ul>
+ *
+ * @see ACAMERA_LENS_POSE_REFERENCE
+ * @see ACAMERA_LENS_POSE_ROTATION
+ * @see ACAMERA_LENS_POSE_TRANSLATION
+ */
+ ACAMERA_AUTOMOTIVE_LOCATION = // byte (acamera_metadata_enum_android_automotive_location_t)
+ ACAMERA_AUTOMOTIVE_START,
+ ACAMERA_AUTOMOTIVE_END,
+
+ /**
+ * <p>The direction of the camera faces relative to the vehicle body frame and the
+ * passenger seats.</p>
+ *
+ * <p>Type: byte[n] (acamera_metadata_enum_android_automotive_lens_facing_t)</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>This enum defines the lens facing characteristic of the cameras on the automotive
+ * devices with locations ACAMERA_AUTOMOTIVE_LOCATION defines. If the system has
+ * FEATURE_AUTOMOTIVE, the camera will have this entry in its static metadata.</p>
+ * <p>When ACAMERA_AUTOMOTIVE_LOCATION is INTERIOR, this has one or more INTERIOR_*
+ * values or a single EXTERIOR_* value. When this has more than one INTERIOR_*,
+ * the first value must be the one for the seat closest to the optical axis. If this
+ * contains INTERIOR_OTHER, all other values will be ineffective.</p>
+ * <p>When ACAMERA_AUTOMOTIVE_LOCATION is EXTERIOR_* or EXTRA, this has a single
+ * EXTERIOR_* value.</p>
+ * <p>If a camera has INTERIOR_OTHER or EXTERIOR_OTHER, or more than one camera is at the
+ * same location and facing the same direction, their static metadata will list the
+ * following entries, so that applications can determain their lenses' exact facing
+ * directions:</p>
+ * <ul>
+ * <li>ACAMERA_LENS_POSE_REFERENCE</li>
+ * <li>ACAMERA_LENS_POSE_ROTATION</li>
+ * <li>ACAMERA_LENS_POSE_TRANSLATION</li>
+ * </ul>
+ *
+ * @see ACAMERA_AUTOMOTIVE_LOCATION
+ * @see ACAMERA_LENS_POSE_REFERENCE
+ * @see ACAMERA_LENS_POSE_ROTATION
+ * @see ACAMERA_LENS_POSE_TRANSLATION
+ */
+ ACAMERA_AUTOMOTIVE_LENS_FACING = // byte[n] (acamera_metadata_enum_android_automotive_lens_facing_t)
+ ACAMERA_AUTOMOTIVE_LENS_START,
+ ACAMERA_AUTOMOTIVE_LENS_END,
+
} acamera_metadata_tag_t;
/**
@@ -8542,6 +8679,14 @@
*/
ACAMERA_LENS_POSE_REFERENCE_UNDEFINED = 2,
+ /**
+ * <p>The value of ACAMERA_LENS_POSE_TRANSLATION is relative to the origin of the
+ * automotive sensor coodinate system, which is at the center of the rear axle.</p>
+ *
+ * @see ACAMERA_LENS_POSE_TRANSLATION
+ */
+ ACAMERA_LENS_POSE_REFERENCE_AUTOMOTIVE = 3,
+
} acamera_metadata_enum_android_lens_pose_reference_t;
@@ -9142,6 +9287,35 @@
ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR
= 16,
+ /**
+ * <p>The camera device supports selecting a per-stream use case via
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/params/OutputConfiguration.html#setStreamUseCase">OutputConfiguration#setStreamUseCase</a>
+ * so that the device can optimize camera pipeline parameters such as tuning, sensor
+ * mode, or ISP settings for a specific user scenario.
+ * Some sample usages of this capability are:
+ * * Distinguish high quality YUV captures from a regular YUV stream where
+ * the image quality may not be as good as the JPEG stream, or
+ * * Use one stream to serve multiple purposes: viewfinder, video recording and
+ * still capture. This is common with applications that wish to apply edits equally
+ * to preview, saved images, and saved videos.</p>
+ * <p>This capability requires the camera device to support the following
+ * stream use cases:
+ * * DEFAULT for backward compatibility where the application doesn't set
+ * a stream use case
+ * * PREVIEW for live viewfinder and in-app image analysis
+ * * STILL_CAPTURE for still photo capture
+ * * VIDEO_RECORD for recording video clips
+ * * PREVIEW_VIDEO_STILL for one single stream used for viewfinder, video
+ * recording, and still capture.
+ * * VIDEO_CALL for long running video calls</p>
+ * <p><a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#SCALER_AVAILABLE_STREAM_USE_CASES">CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES</a>
+ * lists all of the supported stream use cases.</p>
+ * <p>Refer to <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">CameraDevice#createCaptureSession</a> for the
+ * mandatory stream combinations involving stream use cases, which can also be queried
+ * via <a href="https://developer.android.com/reference/android/hardware/camera2/params/MandatoryStreamCombination.html">MandatoryStreamCombination</a>.</p>
+ */
+ ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE = 19,
+
} acamera_metadata_enum_android_request_available_capabilities_t;
// ACAMERA_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP
@@ -9420,6 +9594,76 @@
} acamera_metadata_enum_android_scaler_multi_resolution_stream_supported_t;
+// ACAMERA_SCALER_AVAILABLE_STREAM_USE_CASES
+typedef enum acamera_metadata_enum_acamera_scaler_available_stream_use_cases {
+ /**
+ * <p>Default stream use case.</p>
+ * <p>This use case is the same as when the application doesn't set any use case for
+ * the stream. The camera device uses the properties of the output target, such as
+ * format, dataSpace, or surface class type, to optimize the image processing pipeline.</p>
+ */
+ ACAMERA_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT = 0x0,
+
+ /**
+ * <p>Live stream shown to the user.</p>
+ * <p>Optimized for performance and usability as a viewfinder, but not necessarily for
+ * image quality. The output is not meant to be persisted as saved images or video.</p>
+ * <p>No stall if android.control.<em> are set to FAST; may have stall if android.control.</em>
+ * are set to HIGH_QUALITY. This use case has the same behavior as the default
+ * SurfaceView and SurfaceTexture targets. Additionally, this use case can be used for
+ * in-app image analysis.</p>
+ */
+ ACAMERA_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW = 0x1,
+
+ /**
+ * <p>Still photo capture.</p>
+ * <p>Optimized for high-quality high-resolution capture, and not expected to maintain
+ * preview-like frame rates.</p>
+ * <p>The stream may have stalls regardless of whether ACAMERA_CONTROL_* is HIGH_QUALITY.
+ * This use case has the same behavior as the default JPEG and RAW related formats.</p>
+ */
+ ACAMERA_SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE = 0x2,
+
+ /**
+ * <p>Recording video clips.</p>
+ * <p>Optimized for high-quality video capture, including high-quality image stabilization
+ * if supported by the device and enabled by the application. As a result, may produce
+ * output frames with a substantial lag from real time, to allow for highest-quality
+ * stabilization or other processing. As such, such an output is not suitable for drawing
+ * to screen directly, and is expected to be persisted to disk or similar for later
+ * playback or processing. Only streams that set the VIDEO_RECORD use case are guaranteed
+ * to have video stabilization applied when the video stabilization control is set
+ * to ON, as opposed to PREVIEW_STABILIZATION.</p>
+ * <p>This use case has the same behavior as the default MediaRecorder and MediaCodec
+ * targets.</p>
+ */
+ ACAMERA_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD = 0x3,
+
+ /**
+ * <p>One single stream used for combined purposes of preview, video, and still capture.</p>
+ * <p>For such multi-purpose streams, the camera device aims to make the best tradeoff
+ * between the individual use cases. For example, the STILL_CAPTURE use case by itself
+ * may have stalls for achieving best image quality. But if combined with PREVIEW and
+ * VIDEO_RECORD, the camera device needs to trade off the additional image processing
+ * for speed so that preview and video recording aren't slowed down.</p>
+ * <p>Similarly, VIDEO_RECORD may produce frames with a substantial lag, but
+ * PREVIEW_VIDEO_STILL must have minimal output delay. This means that to enable video
+ * stabilization with this use case, the device must support and the app must select the
+ * PREVIEW_STABILIZATION mode for video stabilization.</p>
+ */
+ ACAMERA_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL = 0x4,
+
+ /**
+ * <p>Long-running video call optimized for both power efficienty and video quality.</p>
+ * <p>The camera sensor may run in a lower-resolution mode to reduce power consumption
+ * at the cost of some image and digital zoom quality. Unlike VIDEO_RECORD, VIDEO_CALL
+ * outputs are expected to work in dark conditions, so are usually accompanied with
+ * variable frame rate settings to allow sufficient exposure time in low light.</p>
+ */
+ ACAMERA_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL = 0x5,
+
+} acamera_metadata_enum_android_scaler_available_stream_use_cases_t;
+
// ACAMERA_SENSOR_REFERENCE_ILLUMINANT1
typedef enum acamera_metadata_enum_acamera_sensor_reference_illuminant1 {
@@ -10181,6 +10425,167 @@
+// ACAMERA_AUTOMOTIVE_LOCATION
+typedef enum acamera_metadata_enum_acamera_automotive_location {
+ /**
+ * <p>The camera device exists inside of the vehicle cabin.</p>
+ */
+ ACAMERA_AUTOMOTIVE_LOCATION_INTERIOR = 0,
+
+ /**
+ * <p>The camera exists outside of the vehicle body frame but not exactly on one of the
+ * exterior locations this enum defines. The applications should determine the exact
+ * location from ACAMERA_LENS_POSE_TRANSLATION.</p>
+ *
+ * @see ACAMERA_LENS_POSE_TRANSLATION
+ */
+ ACAMERA_AUTOMOTIVE_LOCATION_EXTERIOR_OTHER = 1,
+
+ /**
+ * <p>The camera device exists outside of the vehicle body frame and on its front side.</p>
+ */
+ ACAMERA_AUTOMOTIVE_LOCATION_EXTERIOR_FRONT = 2,
+
+ /**
+ * <p>The camera device exists outside of the vehicle body frame and on its rear side.</p>
+ */
+ ACAMERA_AUTOMOTIVE_LOCATION_EXTERIOR_REAR = 3,
+
+ /**
+ * <p>The camera device exists outside and on left side of the vehicle body frame.</p>
+ */
+ ACAMERA_AUTOMOTIVE_LOCATION_EXTERIOR_LEFT = 4,
+
+ /**
+ * <p>The camera device exists outside and on right side of the vehicle body frame.</p>
+ */
+ ACAMERA_AUTOMOTIVE_LOCATION_EXTERIOR_RIGHT = 5,
+
+ /**
+ * <p>The camera device exists on an extra vehicle, such as the trailer, but not exactly
+ * on one of front, rear, left, or right side. Applications should determine the exact
+ * location from ACAMERA_LENS_POSE_TRANSLATION.</p>
+ *
+ * @see ACAMERA_LENS_POSE_TRANSLATION
+ */
+ ACAMERA_AUTOMOTIVE_LOCATION_EXTRA_OTHER = 6,
+
+ /**
+ * <p>The camera device exists outside of the extra vehicle's body frame and on its front
+ * side.</p>
+ */
+ ACAMERA_AUTOMOTIVE_LOCATION_EXTRA_FRONT = 7,
+
+ /**
+ * <p>The camera device exists outside of the extra vehicle's body frame and on its rear
+ * side.</p>
+ */
+ ACAMERA_AUTOMOTIVE_LOCATION_EXTRA_REAR = 8,
+
+ /**
+ * <p>The camera device exists outside and on left side of the extra vehicle body.</p>
+ */
+ ACAMERA_AUTOMOTIVE_LOCATION_EXTRA_LEFT = 9,
+
+ /**
+ * <p>The camera device exists outside and on right side of the extra vehicle body.</p>
+ */
+ ACAMERA_AUTOMOTIVE_LOCATION_EXTRA_RIGHT = 10,
+
+} acamera_metadata_enum_android_automotive_location_t;
+
+
+// ACAMERA_AUTOMOTIVE_LENS_FACING
+typedef enum acamera_metadata_enum_acamera_automotive_lens_facing {
+ /**
+ * <p>The camera device faces the outside of the vehicle body frame but not exactly
+ * one of the exterior sides defined by this enum. Applications should determine
+ * the exact facing direction from ACAMERA_LENS_POSE_ROTATION and
+ * ACAMERA_LENS_POSE_TRANSLATION.</p>
+ *
+ * @see ACAMERA_LENS_POSE_ROTATION
+ * @see ACAMERA_LENS_POSE_TRANSLATION
+ */
+ ACAMERA_AUTOMOTIVE_LENS_FACING_EXTERIOR_OTHER = 0,
+
+ /**
+ * <p>The camera device faces the front of the vehicle body frame.</p>
+ */
+ ACAMERA_AUTOMOTIVE_LENS_FACING_EXTERIOR_FRONT = 1,
+
+ /**
+ * <p>The camera device faces the rear of the vehicle body frame.</p>
+ */
+ ACAMERA_AUTOMOTIVE_LENS_FACING_EXTERIOR_REAR = 2,
+
+ /**
+ * <p>The camera device faces the left side of the vehicle body frame.</p>
+ */
+ ACAMERA_AUTOMOTIVE_LENS_FACING_EXTERIOR_LEFT = 3,
+
+ /**
+ * <p>The camera device faces the right side of the vehicle body frame.</p>
+ */
+ ACAMERA_AUTOMOTIVE_LENS_FACING_EXTERIOR_RIGHT = 4,
+
+ /**
+ * <p>The camera device faces the inside of the vehicle body frame but not exactly
+ * one of seats described by this enum. Applications should determine the exact
+ * facing direction from ACAMERA_LENS_POSE_ROTATION and ACAMERA_LENS_POSE_TRANSLATION.</p>
+ *
+ * @see ACAMERA_LENS_POSE_ROTATION
+ * @see ACAMERA_LENS_POSE_TRANSLATION
+ */
+ ACAMERA_AUTOMOTIVE_LENS_FACING_INTERIOR_OTHER = 5,
+
+ /**
+ * <p>The camera device faces the left side seat of the first row.</p>
+ */
+ ACAMERA_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_LEFT = 6,
+
+ /**
+ * <p>The camera device faces the center seat of the first row.</p>
+ */
+ ACAMERA_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_CENTER = 7,
+
+ /**
+ * <p>The camera device faces the right seat of the first row.</p>
+ */
+ ACAMERA_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_RIGHT = 8,
+
+ /**
+ * <p>The camera device faces the left side seat of the second row.</p>
+ */
+ ACAMERA_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_LEFT = 9,
+
+ /**
+ * <p>The camera device faces the center seat of the second row.</p>
+ */
+ ACAMERA_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_CENTER = 10,
+
+ /**
+ * <p>The camera device faces the right side seat of the second row.</p>
+ */
+ ACAMERA_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_RIGHT = 11,
+
+ /**
+ * <p>The camera device faces the left side seat of the third row.</p>
+ */
+ ACAMERA_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_LEFT = 12,
+
+ /**
+ * <p>The camera device faces the center seat of the third row.</p>
+ */
+ ACAMERA_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_CENTER = 13,
+
+ /**
+ * <p>The camera device faces the right seat of the third row.</p>
+ */
+ ACAMERA_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_RIGHT = 14,
+
+} acamera_metadata_enum_android_automotive_lens_facing_t;
+
+
__END_DECLS
diff --git a/camera/ndk/libcamera2ndk.map.txt b/camera/ndk/libcamera2ndk.map.txt
index 2b630db..b3977ff 100644
--- a/camera/ndk/libcamera2ndk.map.txt
+++ b/camera/ndk/libcamera2ndk.map.txt
@@ -2,11 +2,15 @@
global:
ACameraCaptureSession_abortCaptures;
ACameraCaptureSession_capture;
+ ACameraCaptureSession_captureV2; # introduced=33
ACameraCaptureSession_logicalCamera_capture; # introduced=29
+ ACameraCaptureSession_logicalCamera_captureV2; # introduced=33
ACameraCaptureSession_close;
ACameraCaptureSession_getDevice;
ACameraCaptureSession_setRepeatingRequest;
+ ACameraCaptureSession_setRepeatingRequestV2; # introduced=33
ACameraCaptureSession_logicalCamera_setRepeatingRequest; # introduced=29
+ ACameraCaptureSession_logicalCamera_setRepeatingRequestV2; # introduced=33
ACameraCaptureSession_stopRepeating;
ACameraCaptureSession_updateSharedOutput; # introduced=28
ACameraDevice_close;
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
index 9f63099..4cc1292 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
@@ -29,8 +29,6 @@
#include "ACaptureRequest.h"
#include "utils.h"
-#include "ACameraCaptureSession.inc"
-
#define CHECK_TRANSACTION_AND_RET(remoteRet, status, callName) \
if (!remoteRet.isOk()) { \
ALOGE("%s: Transaction error during %s call %s", __FUNCTION__, callName, \
@@ -910,6 +908,7 @@
case kWhatOnError:
case kWhatSessionStateCb:
case kWhatCaptureStart:
+ case kWhatCaptureStart2:
case kWhatCaptureResult:
case kWhatLogicalCaptureResult:
case kWhatCaptureFail:
@@ -982,6 +981,7 @@
}
case kWhatSessionStateCb:
case kWhatCaptureStart:
+ case kWhatCaptureStart2:
case kWhatCaptureResult:
case kWhatLogicalCaptureResult:
case kWhatCaptureFail:
@@ -1002,6 +1002,7 @@
const char *id_cstr = mId.c_str();
switch (msg->what()) {
case kWhatCaptureStart:
+ case kWhatCaptureStart2:
case kWhatCaptureResult:
case kWhatLogicalCaptureResult:
case kWhatCaptureFail:
@@ -1053,6 +1054,35 @@
freeACaptureRequest(request);
break;
}
+ case kWhatCaptureStart2:
+ {
+ ACameraCaptureSession_captureCallback_startV2 onStart2;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onStart2);
+ if (!found) {
+ ALOGE("%s: Cannot find capture startV2 callback!", __FUNCTION__);
+ return;
+ }
+ if (onStart2 == nullptr) {
+ return;
+ }
+ int64_t timestamp;
+ found = msg->findInt64(kTimeStampKey, ×tamp);
+ if (!found) {
+ ALOGE("%s: Cannot find timestamp!", __FUNCTION__);
+ return;
+ }
+ int64_t frameNumber;
+ found = msg->findInt64(kFrameNumberKey, &frameNumber);
+ if (!found) {
+ ALOGE("%s: Cannot find frame number!", __FUNCTION__);
+ return;
+ }
+
+ ACaptureRequest* request = allocateACaptureRequest(requestSp, id_cstr);
+ (*onStart2)(context, session.get(), request, timestamp, frameNumber);
+ freeACaptureRequest(request);
+ break;
+ }
case kWhatCaptureResult:
{
ACameraCaptureSession_captureCallback_result onResult;
@@ -1281,6 +1311,7 @@
ACameraCaptureSession_captureCallbacks* cbs) :
mSession(session), mRequests(requests),
mIsRepeating(isRepeating),
+ mIs2Callback(false),
mIsLogicalCameraCallback(false) {
initCaptureCallbacks(cbs);
@@ -1297,6 +1328,7 @@
ACameraCaptureSession_logicalCamera_captureCallbacks* lcbs) :
mSession(session), mRequests(requests),
mIsRepeating(isRepeating),
+ mIs2Callback(false),
mIsLogicalCameraCallback(true) {
initCaptureCallbacks(lcbs);
@@ -1306,6 +1338,40 @@
}
}
+CameraDevice::CallbackHolder::CallbackHolder(
+ sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest> >& requests,
+ bool isRepeating,
+ ACameraCaptureSession_captureCallbacksV2* cbs) :
+ mSession(session), mRequests(requests),
+ mIsRepeating(isRepeating),
+ mIs2Callback(true),
+ mIsLogicalCameraCallback(false) {
+ initCaptureCallbacksV2(cbs);
+
+ if (cbs != nullptr) {
+ mOnCaptureCompleted = cbs->onCaptureCompleted;
+ mOnCaptureFailed = cbs->onCaptureFailed;
+ }
+}
+
+CameraDevice::CallbackHolder::CallbackHolder(
+ sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest> >& requests,
+ bool isRepeating,
+ ACameraCaptureSession_logicalCamera_captureCallbacksV2* lcbs) :
+ mSession(session), mRequests(requests),
+ mIsRepeating(isRepeating),
+ mIs2Callback(true),
+ mIsLogicalCameraCallback(true) {
+ initCaptureCallbacksV2(lcbs);
+
+ if (lcbs != nullptr) {
+ mOnLogicalCameraCaptureCompleted = lcbs->onLogicalCameraCaptureCompleted;
+ mOnLogicalCameraCaptureFailed = lcbs->onLogicalCameraCaptureFailed;
+ }
+}
+
void
CameraDevice::checkRepeatingSequenceCompleteLocked(
const int sequenceId, const int64_t lastFrameNumber) {
@@ -1542,11 +1608,14 @@
int32_t sequenceId = resultExtras.requestId;
int32_t burstId = resultExtras.burstId;
+ int64_t frameNumber = resultExtras.frameNumber;
auto it = dev->mSequenceCallbackMap.find(sequenceId);
if (it != dev->mSequenceCallbackMap.end()) {
CallbackHolder cbh = (*it).second;
ACameraCaptureSession_captureCallback_start onStart = cbh.mOnCaptureStarted;
+ ACameraCaptureSession_captureCallback_startV2 onStart2 = cbh.mOnCaptureStarted2;
+ bool v2Callback = cbh.mIs2Callback;
sp<ACameraCaptureSession> session = cbh.mSession;
if ((size_t) burstId >= cbh.mRequests.size()) {
ALOGE("%s: Error: request index %d out of bound (size %zu)",
@@ -1554,12 +1623,19 @@
dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
}
sp<CaptureRequest> request = cbh.mRequests[burstId];
- sp<AMessage> msg = new AMessage(kWhatCaptureStart, dev->mHandler);
+ sp<AMessage> msg = nullptr;
+ if (v2Callback) {
+ msg = new AMessage(kWhatCaptureStart2, dev->mHandler);
+ msg->setPointer(kCallbackFpKey, (void*) onStart2);
+ } else {
+ msg = new AMessage(kWhatCaptureStart, dev->mHandler);
+ msg->setPointer(kCallbackFpKey, (void*) onStart);
+ }
msg->setPointer(kContextKey, cbh.mContext);
msg->setObject(kSessionSpKey, session);
- msg->setPointer(kCallbackFpKey, (void*) onStart);
msg->setObject(kCaptureRequestKey, request);
msg->setInt64(kTimeStampKey, timestamp);
+ msg->setInt64(kFrameNumberKey, frameNumber);
dev->postSessionMsgAndCleanup(msg);
}
return ret;
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.h b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
index 0b6c7c8..c306206 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
@@ -245,6 +245,7 @@
kWhatSessionStateCb, // onReady, onActive
// Capture callbacks
kWhatCaptureStart, // onCaptureStarted
+ kWhatCaptureStart2, // onCaptureStarted2
kWhatCaptureResult, // onCaptureProgressed, onCaptureCompleted
kWhatLogicalCaptureResult, // onLogicalCameraCaptureCompleted
kWhatCaptureFail, // onCaptureFailed
@@ -309,11 +310,18 @@
const Vector<sp<CaptureRequest>>& requests,
bool isRepeating,
ACameraCaptureSession_logicalCamera_captureCallbacks* lcbs);
-
- template <class T>
- void initCaptureCallbacks(T* cbs) {
+ CallbackHolder(sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest> >& requests,
+ bool isRepeating,
+ ACameraCaptureSession_captureCallbacksV2* cbs);
+ CallbackHolder(sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest> >& requests,
+ bool isRepeating,
+ ACameraCaptureSession_logicalCamera_captureCallbacksV2* lcbs);
+ void clearCallbacks() {
mContext = nullptr;
mOnCaptureStarted = nullptr;
+ mOnCaptureStarted2 = nullptr;
mOnCaptureProgressed = nullptr;
mOnCaptureCompleted = nullptr;
mOnLogicalCameraCaptureCompleted = nullptr;
@@ -322,6 +330,24 @@
mOnCaptureSequenceCompleted = nullptr;
mOnCaptureSequenceAborted = nullptr;
mOnCaptureBufferLost = nullptr;
+ }
+
+ template <class T>
+ void initCaptureCallbacksV2(T* cbs) {
+ clearCallbacks();
+ if (cbs != nullptr) {
+ mContext = cbs->context;
+ mOnCaptureStarted2 = cbs->onCaptureStarted;
+ mOnCaptureProgressed = cbs->onCaptureProgressed;
+ mOnCaptureSequenceCompleted = cbs->onCaptureSequenceCompleted;
+ mOnCaptureSequenceAborted = cbs->onCaptureSequenceAborted;
+ mOnCaptureBufferLost = cbs->onCaptureBufferLost;
+ }
+ }
+
+ template <class T>
+ void initCaptureCallbacks(T* cbs) {
+ clearCallbacks();
if (cbs != nullptr) {
mContext = cbs->context;
mOnCaptureStarted = cbs->onCaptureStarted;
@@ -335,10 +361,12 @@
sp<ACameraCaptureSession> mSession;
Vector<sp<CaptureRequest>> mRequests;
const bool mIsRepeating;
+ const bool mIs2Callback;
const bool mIsLogicalCameraCallback;
void* mContext;
ACameraCaptureSession_captureCallback_start mOnCaptureStarted;
+ ACameraCaptureSession_captureCallback_startV2 mOnCaptureStarted2;
ACameraCaptureSession_captureCallback_result mOnCaptureProgressed;
ACameraCaptureSession_captureCallback_result mOnCaptureCompleted;
ACameraCaptureSession_logicalCamera_captureCallback_result mOnLogicalCameraCaptureCompleted;
diff --git a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
index ba14c5c..63cdb76 100644
--- a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
+++ b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
@@ -236,6 +236,11 @@
return ACameraCaptureSession_capture(mSession, &mCaptureCallbacks, 1, &mStillRequest,
&seqId);
}
+ int takePicture2() {
+ int seqId;
+ return ACameraCaptureSession_captureV2(mSession, &mCaptureCallbacksV2, 1,
+ &mStillRequest, &seqId);
+ }
int takeLogicalCameraPicture() {
int seqId;
@@ -243,15 +248,31 @@
1, &mStillRequest, &seqId);
}
+ int takeLogicalCameraPicture2() {
+ int seqId;
+ return ACameraCaptureSession_logicalCamera_captureV2(mSession,
+ &mLogicalCaptureCallbacksV2, 1, &mStillRequest, &seqId);
+ }
+
bool checkCallbacks(int pictureCount) {
std::lock_guard<std::mutex> lock(mMutex);
if (mCompletedCaptureCallbackCount != pictureCount) {
- ALOGE("Completed capture callaback count not as expected. expected %d actual %d",
+ ALOGE("Completed capture callback count not as expected. expected %d actual %d",
pictureCount, mCompletedCaptureCallbackCount);
return false;
}
return true;
}
+ bool checkCallbacksV2(int pictureCount) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mCaptureStartedCallbackCount != pictureCount) {
+ ALOGE("Capture started callback count not as expected. expected %d actual %d",
+ pictureCount, mCaptureStartedCallbackCount);
+ return false;
+ }
+ return true;
+ }
+
private:
ACameraDevice_StateCallbacks mDeviceCb{this, nullptr, nullptr};
@@ -276,6 +297,7 @@
const char* mCameraId;
ACameraManager* mCameraManager;
int mCompletedCaptureCallbackCount = 0;
+ int mCaptureStartedCallbackCount = 0;
std::mutex mMutex;
ACameraCaptureSession_captureCallbacks mCaptureCallbacks = {
// TODO: Add tests for other callbacks
@@ -293,8 +315,25 @@
nullptr, // onCaptureSequenceAborted
nullptr, // onCaptureBufferLost
};
+ ACameraCaptureSession_captureCallbacksV2 mCaptureCallbacksV2 = {
+ this, // context
+ [](void* ctx , ACameraCaptureSession *,const ACaptureRequest *, int64_t,
+ int64_t frameNumber ) {
+ CameraHelper *ch = static_cast<CameraHelper *>(ctx);
+ ASSERT_TRUE(frameNumber >= 0);
+ std::lock_guard<std::mutex> lock(ch->mMutex);
+ ch->mCaptureStartedCallbackCount++;
+ },
+ nullptr, // onCaptureProgressed
+ nullptr, // onCaptureCompleted
+ nullptr, // onCaptureFailed
+ nullptr, // onCaptureSequenceCompleted
+ nullptr, // onCaptureSequenceAborted
+ nullptr, // onCaptureBufferLost
+ };
std::vector<std::string> mPhysicalCameraIds;
+
ACameraCaptureSession_logicalCamera_captureCallbacks mLogicalCaptureCallbacks = {
// TODO: Add tests for other callbacks
this, // context
@@ -336,6 +375,23 @@
nullptr, // onCaptureSequenceAborted
nullptr, // onCaptureBufferLost
};
+ ACameraCaptureSession_logicalCamera_captureCallbacksV2 mLogicalCaptureCallbacksV2 = {
+ this, // context
+ [](void* ctx , ACameraCaptureSession *,const ACaptureRequest *, int64_t,
+ int64_t frameNumber) {
+ CameraHelper *ch = static_cast<CameraHelper *>(ctx);
+ ASSERT_TRUE(frameNumber >= 0);
+ std::lock_guard<std::mutex> lock(ch->mMutex);
+ ch->mCaptureStartedCallbackCount++;
+ },
+ nullptr, // onCaptureProgressed
+ nullptr, //onLogicalCaptureCompleted
+ nullptr, //onLogicalCpatureFailed
+ nullptr, // onCaptureSequenceCompleted
+ nullptr, // onCaptureSequenceAborted
+ nullptr, // onCaptureBufferLost
+ };
+
};
class ImageReaderTestCase {
@@ -570,7 +626,7 @@
}
bool takePictures(const char* id, uint64_t readerUsage, int readerMaxImages,
- bool readerAsync, int pictureCount) {
+ bool readerAsync, int pictureCount, bool v2 = false) {
int ret = 0;
ImageReaderTestCase testCase(
@@ -600,7 +656,11 @@
}
for (int i = 0; i < pictureCount; i++) {
- ret = cameraHelper.takePicture();
+ if (v2) {
+ ret = cameraHelper.takePicture2();
+ } else {
+ ret = cameraHelper.takePicture();
+ }
if (ret < 0) {
ALOGE("Unable to take picture");
return false;
@@ -617,7 +677,8 @@
}
}
return testCase.getAcquiredImageCount() == pictureCount &&
- cameraHelper.checkCallbacks(pictureCount);
+ v2 ? cameraHelper.checkCallbacksV2(pictureCount) :
+ cameraHelper.checkCallbacks(pictureCount);
}
bool testTakePicturesNative(const char* id) {
@@ -626,12 +687,14 @@
for (auto& readerMaxImages : {1, 4, 8}) {
for (auto& readerAsync : {true, false}) {
for (auto& pictureCount : {1, 4, 8}) {
- if (!takePictures(id, readerUsage, readerMaxImages,
- readerAsync, pictureCount)) {
- ALOGE("Test takePictures failed for test case usage=%" PRIu64
- ", maxImages=%d, async=%d, pictureCount=%d",
- readerUsage, readerMaxImages, readerAsync, pictureCount);
- return false;
+ for ( auto & v2 : {true, false}) {
+ if (!takePictures(id, readerUsage, readerMaxImages,
+ readerAsync, pictureCount, v2)) {
+ ALOGE("Test takePictures failed for test case usage=%" PRIu64
+ ", maxImages=%d, async=%d, pictureCount=%d",
+ readerUsage, readerMaxImages, readerAsync, pictureCount);
+ return false;
+ }
}
}
}
@@ -725,7 +788,7 @@
return;
}
- void testLogicalCameraPhysicalStream(bool usePhysicalSettings) {
+ void testLogicalCameraPhysicalStream(bool usePhysicalSettings, bool v2) {
const char* cameraId = nullptr;
ACameraMetadata* staticMetadata = nullptr;
std::vector<const char*> physicalCameraIds;
@@ -772,7 +835,12 @@
}
for (int i = 0; i < pictureCount; i++) {
- ret = cameraHelper.takeLogicalCameraPicture();
+ if (v2) {
+ ret = cameraHelper.takeLogicalCameraPicture2();
+ }
+ else {
+ ret = cameraHelper.takeLogicalCameraPicture();
+ }
ASSERT_EQ(ret, 0);
}
@@ -793,8 +861,11 @@
ALOGI("Testing window %p", testCase->getNativeWindow());
ASSERT_EQ(testCase->getAcquiredImageCount(), pictureCount);
}
-
- ASSERT_TRUE(cameraHelper.checkCallbacks(pictureCount));
+ if (v2) {
+ ASSERT_TRUE(cameraHelper.checkCallbacksV2(pictureCount));
+ } else {
+ ASSERT_TRUE(cameraHelper.checkCallbacks(pictureCount));
+ }
ACameraMetadata_free(staticMetadata);
}
@@ -834,8 +905,10 @@
}
TEST_F(AImageReaderVendorTest, LogicalCameraPhysicalStream) {
- testLogicalCameraPhysicalStream(false/*usePhysicalSettings*/);
- testLogicalCameraPhysicalStream(true/*usePhysicalSettings*/);
+ for (auto & v2 : {true, false}) {
+ testLogicalCameraPhysicalStream(false/*usePhysicalSettings*/, v2);
+ testLogicalCameraPhysicalStream(true/*usePhysicalSettings*/, v2);
+ }
}
} // namespace
diff --git a/cmds/stagefright/Android.bp b/cmds/stagefright/Android.bp
index c4783d3..e1fe07e 100644
--- a/cmds/stagefright/Android.bp
+++ b/cmds/stagefright/Android.bp
@@ -227,8 +227,6 @@
"rs-headers",
],
- include_dirs: ["frameworks/av/media/libstagefright"],
-
shared_libs: [
"libstagefright",
"liblog",
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index ec16bc2..9783855 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -70,6 +70,10 @@
using namespace android;
+namespace {
+ constexpr static int PIXEL_FORMAT_RGBA_1010102_AS_8888 = -HAL_PIXEL_FORMAT_RGBA_1010102;
+}
+
static long gNumRepetitions;
static long gMaxNumFrames; // 0 means decode all available.
static long gReproduceBug; // if not -1.
@@ -626,7 +630,14 @@
fprintf(stderr, " -m max-number-of-frames-to-decode in each pass\n");
fprintf(stderr, " -b bug to reproduce\n");
fprintf(stderr, " -i(nfo) dump codec info (profiles and color formats supported, details)\n");
- fprintf(stderr, " -t(humbnail) extract video thumbnail or album art\n");
+ fprintf(stderr, " -t(humbnail) extract video thumbnail or album art (/sdcard/out.jpg)\n");
+ fprintf(stderr, " -P(ixelFormat) pixel format to use for raw thumbnail "
+ "(/sdcard/out.raw)\n");
+ fprintf(stderr, " %d: RGBA_565\n", HAL_PIXEL_FORMAT_RGB_565);
+ fprintf(stderr, " %d: RGBA_8888\n", HAL_PIXEL_FORMAT_RGBA_8888);
+ fprintf(stderr, " %d: BGRA_8888\n", HAL_PIXEL_FORMAT_BGRA_8888);
+ fprintf(stderr, " %d: RGBA_1010102\n", HAL_PIXEL_FORMAT_RGBA_1010102);
+ fprintf(stderr, " %d: RGBA_1010102 as RGBA_8888\n", PIXEL_FORMAT_RGBA_1010102_AS_8888);
fprintf(stderr, " -s(oftware) prefer software codec\n");
fprintf(stderr, " -r(hardware) force to use hardware codec\n");
fprintf(stderr, " -o playback audio\n");
@@ -784,6 +795,7 @@
bool useSurfaceTexAlloc = false;
bool dumpStream = false;
bool dumpPCMStream = false;
+ int32_t pixelFormat = 0; // thumbnail pixel format
String8 dumpStreamFilename;
gNumRepetitions = 1;
gMaxNumFrames = 0;
@@ -797,7 +809,7 @@
sp<android::ALooper> looper;
int res;
- while ((res = getopt(argc, argv, "vhaqn:lm:b:itsrow:kN:xSTd:D:")) >= 0) {
+ while ((res = getopt(argc, argv, "vhaqn:lm:b:itsrow:kN:xSTd:D:P:")) >= 0) {
switch (res) {
case 'a':
{
@@ -838,6 +850,7 @@
break;
}
+ case 'P':
case 'm':
case 'n':
case 'b':
@@ -853,6 +866,8 @@
gNumRepetitions = x;
} else if (res == 'm') {
gMaxNumFrames = x;
+ } else if (res == 'P') {
+ pixelFormat = x;
} else {
CHECK_EQ(res, 'b');
gReproduceBug = x;
@@ -975,24 +990,71 @@
close(fd);
fd = -1;
+ uint32_t retrieverPixelFormat = HAL_PIXEL_FORMAT_RGB_565;
+ if (pixelFormat == PIXEL_FORMAT_RGBA_1010102_AS_8888) {
+ retrieverPixelFormat = HAL_PIXEL_FORMAT_RGBA_1010102;
+ } else if (pixelFormat) {
+ retrieverPixelFormat = pixelFormat;
+ }
sp<IMemory> mem =
retriever->getFrameAtTime(-1,
MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC,
- HAL_PIXEL_FORMAT_RGB_565,
- false /*metaOnly*/);
+ retrieverPixelFormat, false /*metaOnly*/);
if (mem != NULL) {
failed = false;
- printf("getFrameAtTime(%s) => OK\n", filename);
+ printf("getFrameAtTime(%s) format=%d => OK\n", filename, retrieverPixelFormat);
VideoFrame *frame = (VideoFrame *)mem->unsecurePointer();
- CHECK_EQ(writeJpegFile("/sdcard/out.jpg",
- frame->getFlattenedData(),
- frame->mWidth, frame->mHeight), 0);
+ if (pixelFormat) {
+ int bpp = 0;
+ switch (pixelFormat) {
+ case HAL_PIXEL_FORMAT_RGB_565:
+ bpp = 2;
+ break;
+ case PIXEL_FORMAT_RGBA_1010102_AS_8888:
+ // convert RGBA_1010102 to RGBA_8888
+ {
+ uint32_t *data = (uint32_t *)frame->getFlattenedData();
+ uint32_t *end = data + frame->mWidth * frame->mHeight;
+ for (; data < end; ++data) {
+ *data =
+ // pick out 8-bit R, G, B values and move them to the
+ // correct position
+ ( (*data & 0x3fc) >> 2) | // R
+ ( (*data & 0xff000) >> 4) | // G
+ ( (*data & 0x3fc00000) >> 6) | // B
+ // pick out 2-bit A and expand to 8-bits
+ (((*data & 0xc0000000) >> 6) * 0x55);
+ }
+ }
+
+ FALLTHROUGH_INTENDED;
+
+ case HAL_PIXEL_FORMAT_RGBA_1010102:
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ bpp = 4;
+ break;
+ }
+ if (bpp) {
+ FILE *out = fopen("/sdcard/out.raw", "wb");
+ fwrite(frame->getFlattenedData(), bpp * frame->mWidth, frame->mHeight, out);
+ fclose(out);
+
+ printf("write out %d x %d x %dbpp\n", frame->mWidth, frame->mHeight, bpp);
+ } else {
+ printf("unknown pixel format.\n");
+ }
+ } else {
+ CHECK_EQ(writeJpegFile("/sdcard/out.jpg",
+ frame->getFlattenedData(),
+ frame->mWidth, frame->mHeight), 0);
+ }
}
- {
+ if (!pixelFormat) {
mem = retriever->extractAlbumArt();
if (mem != NULL) {
diff --git a/drm/OWNERS b/drm/OWNERS
index e788754..090c021 100644
--- a/drm/OWNERS
+++ b/drm/OWNERS
@@ -1 +1,3 @@
jtinker@google.com
+kelzhan@google.com
+robertshih@google.com
diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp
index 71df58c..408d216 100644
--- a/drm/libmediadrm/Android.bp
+++ b/drm/libmediadrm/Android.bp
@@ -28,8 +28,13 @@
"DrmSessionManager.cpp",
"SharedLibrary.cpp",
"DrmHal.cpp",
+ "DrmHalHidl.cpp",
+ "DrmHalAidl.cpp",
"CryptoHal.cpp",
+ "CryptoHalHidl.cpp",
+ "CryptoHalAidl.cpp",
"DrmUtils.cpp",
+ "DrmHalListener.cpp",
],
local_include_dirs: [
@@ -63,10 +68,12 @@
"android.hardware.drm@1.4",
"libhidlallocatorutils",
"libhidlbase",
+ "android.hardware.drm-V1-ndk",
],
static_libs: [
"resourcemanager_aidl_interface-ndk",
+ "libaidlcommonsupport",
],
export_shared_lib_headers: [
@@ -162,10 +169,6 @@
"DrmMetricsConsumer.cpp",
],
- include_dirs: [
- "frameworks/av/media/libmedia/include"
- ],
-
shared_libs: [
"android.hardware.drm@1.0",
"android.hardware.drm@1.1",
@@ -181,5 +184,6 @@
header_libs: [
"libmediametrics_headers",
"libstagefright_foundation_headers",
+ "libmedia_headers",
],
}
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index e0db1c4..f95d527 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -16,389 +16,100 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "CryptoHal"
-#include <utils/Log.h>
-
-#include <android/hardware/drm/1.0/types.h>
-#include <android/hidl/manager/1.2/IServiceManager.h>
-#include <hidl/ServiceManagement.h>
-#include <hidlmemory/FrameworkUtils.h>
-#include <media/hardware/CryptoAPI.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AString.h>
-#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/MediaErrors.h>
#include <mediadrm/CryptoHal.h>
+#include <mediadrm/CryptoHalHidl.h>
+#include <mediadrm/CryptoHalAidl.h>
#include <mediadrm/DrmUtils.h>
-using drm::V1_0::BufferType;
-using drm::V1_0::DestinationBuffer;
-using drm::V1_0::ICryptoFactory;
-using drm::V1_0::ICryptoPlugin;
-using drm::V1_0::Mode;
-using drm::V1_0::Pattern;
-using drm::V1_0::SharedBuffer;
-using drm::V1_0::Status;
-using drm::V1_0::SubSample;
-
-using ::android::DrmUtils::toStatusT;
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_handle;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::HidlMemory;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::sp;
-
-typedef drm::V1_2::Status Status_V1_2;
-
namespace android {
-static hidl_vec<uint8_t> toHidlVec(const Vector<uint8_t> &vector) {
- hidl_vec<uint8_t> vec;
- vec.setToExternal(const_cast<uint8_t *>(vector.array()), vector.size());
- return vec;
+CryptoHal::CryptoHal() {
+ mCryptoHalAidl = sp<CryptoHalAidl>::make();
+ mCryptoHalHidl = sp<CryptoHalHidl>::make();
}
-static hidl_vec<uint8_t> toHidlVec(const void *ptr, size_t size) {
- hidl_vec<uint8_t> vec;
- vec.resize(size);
- memcpy(vec.data(), ptr, size);
- return vec;
-}
-
-static hidl_array<uint8_t, 16> toHidlArray16(const uint8_t *ptr) {
- if (!ptr) {
- return hidl_array<uint8_t, 16>();
- }
- return hidl_array<uint8_t, 16>(ptr);
-}
-
-
-static String8 toString8(hidl_string hString) {
- return String8(hString.c_str());
-}
-
-
-CryptoHal::CryptoHal()
- : mFactories(makeCryptoFactories()),
- mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT),
- mHeapSeqNum(0) {
-}
-
-CryptoHal::~CryptoHal() {
-}
-
-Vector<sp<ICryptoFactory>> CryptoHal::makeCryptoFactories() {
- Vector<sp<ICryptoFactory>> factories;
-
- auto manager = hardware::defaultServiceManager1_2();
- if (manager != NULL) {
- manager->listManifestByInterface(drm::V1_0::ICryptoFactory::descriptor,
- [&factories](const hidl_vec<hidl_string> ®istered) {
- for (const auto &instance : registered) {
- auto factory = drm::V1_0::ICryptoFactory::getService(instance);
- if (factory != NULL) {
- ALOGD("found drm@1.0 ICryptoFactory %s", instance.c_str());
- factories.push_back(factory);
- }
- }
- }
- );
- manager->listManifestByInterface(drm::V1_1::ICryptoFactory::descriptor,
- [&factories](const hidl_vec<hidl_string> ®istered) {
- for (const auto &instance : registered) {
- auto factory = drm::V1_1::ICryptoFactory::getService(instance);
- if (factory != NULL) {
- ALOGD("found drm@1.1 ICryptoFactory %s", instance.c_str());
- factories.push_back(factory);
- }
- }
- }
- );
- }
-
- if (factories.size() == 0) {
- // must be in passthrough mode, load the default passthrough service
- auto passthrough = ICryptoFactory::getService();
- if (passthrough != NULL) {
- ALOGI("makeCryptoFactories: using default passthrough crypto instance");
- factories.push_back(passthrough);
- } else {
- ALOGE("Failed to find any crypto factories");
- }
- }
- return factories;
-}
-
-sp<ICryptoPlugin> CryptoHal::makeCryptoPlugin(const sp<ICryptoFactory>& factory,
- const uint8_t uuid[16], const void *initData, size_t initDataSize) {
-
- sp<ICryptoPlugin> plugin;
- Return<void> hResult = factory->createPlugin(toHidlArray16(uuid),
- toHidlVec(initData, initDataSize),
- [&](Status status, const sp<ICryptoPlugin>& hPlugin) {
- if (status != Status::OK) {
- ALOGE("Failed to make crypto plugin");
- return;
- }
- plugin = hPlugin;
- }
- );
- if (!hResult.isOk()) {
- mInitCheck = DEAD_OBJECT;
- }
- return plugin;
-}
-
+CryptoHal::~CryptoHal() {}
status_t CryptoHal::initCheck() const {
- return mInitCheck;
+ if (mCryptoHalAidl->initCheck() == OK || mCryptoHalHidl->initCheck() == OK) return OK;
+ if (mCryptoHalAidl->initCheck() == NO_INIT || mCryptoHalHidl->initCheck() == NO_INIT)
+ return NO_INIT;
+ return mCryptoHalHidl->initCheck();
}
-
bool CryptoHal::isCryptoSchemeSupported(const uint8_t uuid[16]) {
- Mutex::Autolock autoLock(mLock);
-
- for (size_t i = 0; i < mFactories.size(); i++) {
- if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
- return true;
- }
- }
- return false;
+ return mCryptoHalAidl->isCryptoSchemeSupported(uuid) ||
+ mCryptoHalHidl->isCryptoSchemeSupported(uuid);
}
-status_t CryptoHal::createPlugin(const uint8_t uuid[16], const void *data,
- size_t size) {
- Mutex::Autolock autoLock(mLock);
-
- for (size_t i = 0; i < mFactories.size(); i++) {
- if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
- mPlugin = makeCryptoPlugin(mFactories[i], uuid, data, size);
- if (mPlugin != NULL) {
- mPluginV1_2 = drm::V1_2::ICryptoPlugin::castFrom(mPlugin);
- }
- }
- }
-
- if (mInitCheck == NO_INIT) {
- mInitCheck = mPlugin == NULL ? ERROR_UNSUPPORTED : OK;
- }
-
- return mInitCheck;
+status_t CryptoHal::createPlugin(const uint8_t uuid[16], const void* data, size_t size) {
+ if (mCryptoHalAidl->createPlugin(uuid, data, size) != OK)
+ return mCryptoHalHidl->createPlugin(uuid, data, size);
+ return OK;
}
status_t CryptoHal::destroyPlugin() {
- Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
- mPlugin.clear();
- mPluginV1_2.clear();
- return OK;
+ // This requires plugin to be created.
+ if (mCryptoHalAidl->initCheck() == OK) return mCryptoHalAidl->destroyPlugin();
+ return mCryptoHalHidl->destroyPlugin();
}
-bool CryptoHal::requiresSecureDecoderComponent(const char *mime) const {
- Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return false;
- }
-
- Return<bool> hResult = mPlugin->requiresSecureDecoderComponent(hidl_string(mime));
- if (!hResult.isOk()) {
- return false;
- }
- return hResult;
-}
-
-
-/**
- * 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.
- */
-int32_t CryptoHal::setHeapBase(const sp<HidlMemory>& heap) {
- if (heap == NULL || mHeapSeqNum < 0) {
- ALOGE("setHeapBase(): heap %p mHeapSeqNum %d", heap.get(), mHeapSeqNum);
- return -1;
- }
-
- Mutex::Autolock autoLock(mLock);
-
- int32_t seqNum = mHeapSeqNum++;
- uint32_t bufferId = static_cast<uint32_t>(seqNum);
- mHeapSizes.add(seqNum, heap->size());
- Return<void> hResult = mPlugin->setSharedBufferBase(*heap, bufferId);
- ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
- return seqNum;
-}
-
-void CryptoHal::clearHeapBase(int32_t seqNum) {
- Mutex::Autolock autoLock(mLock);
-
- /*
- * Clear the remote shared memory mapping by setting the shared
- * buffer base to a null hidl_memory.
- *
- * TODO: Add a releaseSharedBuffer method in a future DRM HAL
- * API version to make this explicit.
- */
- ssize_t index = mHeapSizes.indexOfKey(seqNum);
- if (index >= 0) {
- if (mPlugin != NULL) {
- uint32_t bufferId = static_cast<uint32_t>(seqNum);
- Return<void> hResult = mPlugin->setSharedBufferBase(hidl_memory(), bufferId);
- ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
- }
- mHeapSizes.removeItem(seqNum);
- }
-}
-
-status_t CryptoHal::checkSharedBuffer(const ::SharedBuffer &buffer) {
- int32_t seqNum = static_cast<int32_t>(buffer.bufferId);
- // memory must be in one of the heaps that have been set
- if (mHeapSizes.indexOfKey(seqNum) < 0) {
- return UNKNOWN_ERROR;
- }
-
- // memory must be within the address space of the heap
- size_t heapSize = mHeapSizes.valueFor(seqNum);
- if (heapSize < buffer.offset + buffer.size ||
- SIZE_MAX - buffer.offset < buffer.size) {
- android_errorWriteLog(0x534e4554, "76221123");
- return UNKNOWN_ERROR;
- }
-
- return OK;
-}
-
-ssize_t CryptoHal::decrypt(const uint8_t keyId[16], const uint8_t iv[16],
- CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
- const ::SharedBuffer &hSource, size_t offset,
- const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
- const ::DestinationBuffer &hDestination, AString *errorDetailMsg) {
- Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
- Mode hMode;
- switch(mode) {
- case CryptoPlugin::kMode_Unencrypted:
- hMode = Mode::UNENCRYPTED ;
- break;
- case CryptoPlugin::kMode_AES_CTR:
- hMode = Mode::AES_CTR;
- break;
- case CryptoPlugin::kMode_AES_WV:
- hMode = Mode::AES_CBC_CTS;
- break;
- case CryptoPlugin::kMode_AES_CBC:
- hMode = Mode::AES_CBC;
- break;
- default:
- return UNKNOWN_ERROR;
- }
-
- Pattern hPattern;
- hPattern.encryptBlocks = pattern.mEncryptBlocks;
- hPattern.skipBlocks = pattern.mSkipBlocks;
-
- std::vector<SubSample> stdSubSamples;
- for (size_t i = 0; i < numSubSamples; i++) {
- SubSample subSample;
- subSample.numBytesOfClearData = subSamples[i].mNumBytesOfClearData;
- subSample.numBytesOfEncryptedData = subSamples[i].mNumBytesOfEncryptedData;
- stdSubSamples.push_back(subSample);
- }
- auto hSubSamples = hidl_vec<SubSample>(stdSubSamples);
-
- bool secure;
- if (hDestination.type == BufferType::SHARED_MEMORY) {
- status_t status = checkSharedBuffer(hDestination.nonsecureMemory);
- if (status != OK) {
- return status;
- }
- secure = false;
- } else if (hDestination.type == BufferType::NATIVE_HANDLE) {
- secure = true;
- } else {
- android_errorWriteLog(0x534e4554, "70526702");
- return UNKNOWN_ERROR;
- }
-
- status_t status = checkSharedBuffer(hSource);
- if (status != OK) {
- return status;
- }
-
- status_t err = UNKNOWN_ERROR;
- uint32_t bytesWritten = 0;
-
- Return<void> hResult;
-
- mLock.unlock();
- if (mPluginV1_2 != NULL) {
- hResult = mPluginV1_2->decrypt_1_2(secure, toHidlArray16(keyId), toHidlArray16(iv),
- hMode, hPattern, hSubSamples, hSource, offset, hDestination,
- [&](Status_V1_2 status, uint32_t hBytesWritten, hidl_string hDetailedError) {
- if (status == Status_V1_2::OK) {
- bytesWritten = hBytesWritten;
- *errorDetailMsg = toString8(hDetailedError);
- }
- err = toStatusT(status);
- }
- );
- } else {
- hResult = mPlugin->decrypt(secure, toHidlArray16(keyId), toHidlArray16(iv),
- hMode, hPattern, hSubSamples, hSource, offset, hDestination,
- [&](Status status, uint32_t hBytesWritten, hidl_string hDetailedError) {
- if (status == Status::OK) {
- bytesWritten = hBytesWritten;
- *errorDetailMsg = toString8(hDetailedError);
- }
- err = toStatusT(status);
- }
- );
- }
-
- err = hResult.isOk() ? err : DEAD_OBJECT;
- if (err == OK) {
- return bytesWritten;
- }
- return err;
+bool CryptoHal::requiresSecureDecoderComponent(const char* mime) const {
+ // This requires plugin to be created.
+ if (mCryptoHalAidl->initCheck() == OK)
+ return mCryptoHalAidl->requiresSecureDecoderComponent(mime);
+ return mCryptoHalHidl->requiresSecureDecoderComponent(mime);
}
void CryptoHal::notifyResolution(uint32_t width, uint32_t height) {
- Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
+ // This requires plugin to be created.
+ if (mCryptoHalAidl->initCheck() == OK) {
+ mCryptoHalAidl->notifyResolution(width, height);
return;
}
- auto hResult = mPlugin->notifyResolution(width, height);
- ALOGE_IF(!hResult.isOk(), "notifyResolution txn failed %s", hResult.description().c_str());
+ mCryptoHalHidl->notifyResolution(width, height);
}
-status_t CryptoHal::setMediaDrmSession(const Vector<uint8_t> &sessionId) {
- Mutex::Autolock autoLock(mLock);
+status_t CryptoHal::setMediaDrmSession(const Vector<uint8_t>& sessionId) {
+ // This requires plugin to be created.
+ if (mCryptoHalAidl->initCheck() == OK) return mCryptoHalAidl->setMediaDrmSession(sessionId);
+ return mCryptoHalHidl->setMediaDrmSession(sessionId);
+}
- if (mInitCheck != OK) {
- return mInitCheck;
+ssize_t CryptoHal::decrypt(const uint8_t key[16], const uint8_t iv[16], CryptoPlugin::Mode mode,
+ const CryptoPlugin::Pattern& pattern, const ::SharedBuffer& source,
+ size_t offset, const CryptoPlugin::SubSample* subSamples,
+ size_t numSubSamples, const ::DestinationBuffer& destination,
+ AString* errorDetailMsg) {
+ // This requires plugin to be created.
+ if (mCryptoHalAidl->initCheck() == OK)
+ return mCryptoHalAidl->decrypt(key, iv, mode, pattern, source, offset, subSamples,
+ numSubSamples, destination, errorDetailMsg);
+ return mCryptoHalHidl->decrypt(key, iv, mode, pattern, source, offset, subSamples,
+ numSubSamples, destination, errorDetailMsg);
+}
+
+int32_t CryptoHal::setHeap(const sp<HidlMemory>& heap) {
+ // This requires plugin to be created.
+ if (mCryptoHalAidl->initCheck() == OK) return mCryptoHalAidl->setHeap(heap);
+ return mCryptoHalHidl->setHeap(heap);
+}
+
+void CryptoHal::unsetHeap(int32_t seqNum) {
+ // This requires plugin to be created.
+ if (mCryptoHalAidl->initCheck() == OK) {
+ mCryptoHalAidl->unsetHeap(seqNum);
+ return;
}
- auto err = mPlugin->setMediaDrmSession(toHidlVec(sessionId));
- return err.isOk() ? toStatusT(err) : DEAD_OBJECT;
+ mCryptoHalHidl->unsetHeap(seqNum);
}
-status_t CryptoHal::getLogMessages(Vector<drm::V1_4::LogMessage> &logs) const {
- Mutex::Autolock autoLock(mLock);
- return DrmUtils::GetLogMessages<drm::V1_4::ICryptoPlugin>(mPlugin, logs);
+status_t CryptoHal::getLogMessages(Vector<drm::V1_4::LogMessage>& logs) const {
+ // This requires plugin to be created.
+ if (mCryptoHalAidl->initCheck() == OK) return mCryptoHalAidl->getLogMessages(logs);
+ return mCryptoHalHidl->getLogMessages(logs);
}
-} // namespace android
+
+} // namespace android
\ No newline at end of file
diff --git a/drm/libmediadrm/CryptoHalAidl.cpp b/drm/libmediadrm/CryptoHalAidl.cpp
new file mode 100644
index 0000000..37091dc
--- /dev/null
+++ b/drm/libmediadrm/CryptoHalAidl.cpp
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2021 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 "CryptoHalAidl"
+
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_manager.h>
+#include <media/hardware/CryptoAPI.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/hexdump.h>
+#include <mediadrm/CryptoHalAidl.h>
+#include <mediadrm/DrmUtils.h>
+
+using ::aidl::android::hardware::drm::CryptoSchemes;
+using DestinationBufferAidl = ::aidl::android::hardware::drm::DestinationBuffer;
+using ::aidl::android::hardware::drm::Mode;
+using ::aidl::android::hardware::drm::Pattern;
+using SharedBufferAidl = ::aidl::android::hardware::drm::SharedBuffer;
+using ::aidl::android::hardware::drm::Status;
+using ::aidl::android::hardware::drm::SubSample;
+using ::aidl::android::hardware::drm::Uuid;
+using ::aidl::android::hardware::drm::SecurityLevel;
+using NativeHandleAidlCommon = ::aidl::android::hardware::common::NativeHandle;
+using ::aidl::android::hardware::drm::DecryptArgs;
+
+using ::android::sp;
+using ::android::DrmUtils::statusAidlToStatusT;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::HidlMemory;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+using ::aidl::android::hardware::drm::Uuid;
+// -------Hidl interface related-----------------
+// TODO: replace before removing hidl interface
+
+using BufferTypeHidl = ::android::hardware::drm::V1_0::BufferType;
+using SharedBufferHidl = ::android::hardware::drm::V1_0::SharedBuffer;
+using DestinationBufferHidl = ::android::hardware::drm::V1_0::DestinationBuffer;
+
+// -------Hidl interface related end-------------
+
+namespace android {
+
+template <typename Byte = uint8_t>
+static std::vector<Byte> toStdVec(const Vector<uint8_t>& vector) {
+ auto v = reinterpret_cast<const Byte*>(vector.array());
+ std::vector<Byte> vec(v, v + vector.size());
+ return vec;
+}
+
+// -------Hidl interface related-----------------
+// TODO: replace before removing hidl interface
+status_t CryptoHalAidl::checkSharedBuffer(const SharedBufferHidl& buffer) {
+ int32_t seqNum = static_cast<int32_t>(buffer.bufferId);
+ // memory must be in one of the heaps that have been set
+ if (mHeapSizes.indexOfKey(seqNum) < 0) {
+ return UNKNOWN_ERROR;
+ }
+
+ // memory must be within the address space of the heap
+ size_t heapSize = mHeapSizes.valueFor(seqNum);
+ if (heapSize < buffer.offset + buffer.size || SIZE_MAX - buffer.offset < buffer.size) {
+ android_errorWriteLog(0x534e4554, "76221123");
+ return UNKNOWN_ERROR;
+ }
+
+ return OK;
+}
+
+static SharedBufferAidl hidlSharedBufferToAidlSharedBuffer(const SharedBufferHidl& buffer) {
+ SharedBufferAidl aidlsb;
+ aidlsb.bufferId = buffer.bufferId;
+ aidlsb.offset = buffer.offset;
+ aidlsb.size = buffer.size;
+ return aidlsb;
+}
+
+static DestinationBufferAidl hidlDestinationBufferToAidlDestinationBuffer(
+ const DestinationBufferHidl& buffer) {
+ DestinationBufferAidl aidldb;
+ // skip negative convert check as count of enum elements are 2
+ switch(buffer.type) {
+ case BufferTypeHidl::SHARED_MEMORY:
+ aidldb.set<DestinationBufferAidl::Tag::nonsecureMemory>(
+ hidlSharedBufferToAidlSharedBuffer(buffer.nonsecureMemory));
+ break;
+ default:
+ auto handle = buffer.secureMemory.getNativeHandle();
+ if (handle) {
+ aidldb.set<DestinationBufferAidl::Tag::secureMemory>(
+ ::android::makeToAidl(handle));
+ } else {
+ NativeHandleAidlCommon emptyhandle;
+ aidldb.set<DestinationBufferAidl::Tag::secureMemory>(
+ std::move(emptyhandle));
+ }
+ break;
+ }
+
+ return aidldb;
+}
+
+static hidl_vec<uint8_t> toHidlVec(const void* ptr, size_t size) {
+ hidl_vec<uint8_t> vec;
+ vec.resize(size);
+ memcpy(vec.data(), ptr, size);
+ return vec;
+}
+
+static const Vector<uint8_t> toVector(const std::vector<uint8_t>& vec) {
+ Vector<uint8_t> vector;
+ vector.appendArray(vec.data(), vec.size());
+ return *const_cast<const Vector<uint8_t>*>(&vector);
+}
+
+static String8 toString8(const std::string& string) {
+ return String8(string.c_str());
+}
+
+static std::vector<uint8_t> toStdVec(const uint8_t* ptr, size_t n) {
+ if (!ptr) {
+ return std::vector<uint8_t>();
+ }
+ return std::vector<uint8_t>(ptr, ptr + n);
+}
+
+// -------Hidl interface related end--------------
+
+bool CryptoHalAidl::isCryptoSchemeSupportedInternal(const uint8_t uuid[16], int* factoryIdx) {
+ Uuid uuidAidl = DrmUtils::toAidlUuid(uuid);
+ for (size_t i = 0; i < mFactories.size(); i++) {
+ CryptoSchemes schemes{};
+ if (mFactories[i]->getSupportedCryptoSchemes(&schemes).isOk()) {
+ if (std::count(schemes.uuids.begin(), schemes.uuids.end(), uuidAidl)) {
+ if (factoryIdx != NULL) *factoryIdx = i;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+CryptoHalAidl::CryptoHalAidl()
+ : mFactories(DrmUtils::makeDrmFactoriesAidl()),
+ mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT),
+ mHeapSeqNum(0) {}
+
+CryptoHalAidl::~CryptoHalAidl() {}
+
+status_t CryptoHalAidl::initCheck() const {
+ return mInitCheck;
+}
+
+bool CryptoHalAidl::isCryptoSchemeSupported(const uint8_t uuid[16]) {
+ Mutex::Autolock autoLock(mLock);
+
+ return isCryptoSchemeSupportedInternal(uuid, NULL);
+}
+
+status_t CryptoHalAidl::createPlugin(const uint8_t uuid[16], const void* data, size_t size) {
+ Mutex::Autolock autoLock(mLock);
+
+ Uuid uuidAidl = DrmUtils::toAidlUuid(uuid);
+ std::vector<uint8_t> dataAidl = toStdVec(toVector(toHidlVec(data, size)));
+ int i = 0;
+ if (isCryptoSchemeSupportedInternal(uuid, &i)) {
+ mPlugin = makeCryptoPlugin(mFactories[i], uuidAidl, dataAidl);
+ }
+
+ if (mInitCheck == NO_INIT) {
+ mInitCheck = mPlugin == NULL ? ERROR_UNSUPPORTED : OK;
+ }
+
+ return mInitCheck;
+}
+
+std::shared_ptr<ICryptoPluginAidl> CryptoHalAidl::makeCryptoPlugin(
+ const std::shared_ptr<IDrmFactoryAidl>& factory, const Uuid& uuidAidl,
+ const std::vector<uint8_t> initData) {
+ std::shared_ptr<ICryptoPluginAidl> pluginAidl;
+ if (factory->createCryptoPlugin(uuidAidl, initData, &pluginAidl).isOk()) {
+ ALOGI("Create ICryptoPluginAidl. UUID:[%s]", uuidAidl.toString().c_str());
+ } else {
+ mInitCheck = DEAD_OBJECT;
+ ALOGE("Failed to create ICryptoPluginAidl. UUID:[%s]", uuidAidl.toString().c_str());
+ }
+
+ return pluginAidl;
+}
+
+status_t CryptoHalAidl::destroyPlugin() {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ mPlugin.reset();
+ return OK;
+}
+
+bool CryptoHalAidl::requiresSecureDecoderComponent(const char* mime) const {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return false;
+ }
+
+ std::string mimeStr = std::string(mime);
+ bool result;
+ if (!mPlugin->requiresSecureDecoderComponent(mimeStr, &result).isOk()) {
+ ALOGE("Failed to requiresSecureDecoderComponent. mime:[%s]", mime);
+ return false;
+ }
+
+ return result;
+}
+
+void CryptoHalAidl::notifyResolution(uint32_t width, uint32_t height) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return;
+ }
+
+ // Check negative width and height after type conversion
+ // Log error and return if any is negative
+ if ((int32_t)width < 0 || (int32_t)height < 0) {
+ ALOGE("Negative width: %d or height %d in notifyResolution", width, height);
+ return;
+ }
+
+ ::ndk::ScopedAStatus status = mPlugin->notifyResolution(width, height);
+ if (!status.isOk()) {
+ ALOGE("notifyResolution txn failed status code: %d", status.getServiceSpecificError());
+ }
+}
+
+status_t CryptoHalAidl::setMediaDrmSession(const Vector<uint8_t>& sessionId) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ auto err = mPlugin->setMediaDrmSession(toStdVec(sessionId));
+ return statusAidlToStatusT(err);
+}
+
+ssize_t CryptoHalAidl::decrypt(const uint8_t keyId[16], const uint8_t iv[16],
+ CryptoPlugin::Mode mode, const CryptoPlugin::Pattern& pattern,
+ const SharedBufferHidl& hSource, size_t offset,
+ const CryptoPlugin::SubSample* subSamples, size_t numSubSamples,
+ const DestinationBufferHidl& hDestination, AString* errorDetailMsg) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ Mode aMode;
+ switch (mode) {
+ case CryptoPlugin::kMode_Unencrypted:
+ aMode = Mode::UNENCRYPTED;
+ break;
+ case CryptoPlugin::kMode_AES_CTR:
+ aMode = Mode::AES_CTR;
+ break;
+ case CryptoPlugin::kMode_AES_WV:
+ aMode = Mode::AES_CBC_CTS;
+ break;
+ case CryptoPlugin::kMode_AES_CBC:
+ aMode = Mode::AES_CBC;
+ break;
+ default:
+ return UNKNOWN_ERROR;
+ }
+
+ Pattern aPattern;
+ aPattern.encryptBlocks = pattern.mEncryptBlocks;
+ aPattern.skipBlocks = pattern.mSkipBlocks;
+
+ std::vector<SubSample> stdSubSamples;
+ for (size_t i = 0; i < numSubSamples; i++) {
+ SubSample subSample;
+ subSample.numBytesOfClearData = subSamples[i].mNumBytesOfClearData;
+ subSample.numBytesOfEncryptedData = subSamples[i].mNumBytesOfEncryptedData;
+ stdSubSamples.push_back(subSample);
+ }
+
+ bool secure;
+ if (hDestination.type == BufferTypeHidl::SHARED_MEMORY) {
+ status_t status = checkSharedBuffer(hDestination.nonsecureMemory);
+ if (status != OK) {
+ return status;
+ }
+ secure = false;
+ } else if (hDestination.type == BufferTypeHidl::NATIVE_HANDLE) {
+ secure = true;
+ } else {
+ android_errorWriteLog(0x534e4554, "70526702");
+ return UNKNOWN_ERROR;
+ }
+
+ status_t status = checkSharedBuffer(hSource);
+ if (status != OK) {
+ return status;
+ }
+
+ status_t err = UNKNOWN_ERROR;
+ mLock.unlock();
+
+ std::vector<uint8_t> keyIdAidl(toStdVec(keyId, 16));
+ std::vector<uint8_t> ivAidl(toStdVec(iv, 16));
+
+ DecryptArgs args;
+ args.secure = secure;
+ args.keyId = keyIdAidl;
+ args.iv = ivAidl;
+ args.mode = aMode;
+ args.pattern = aPattern;
+ args.subSamples = std::move(stdSubSamples);
+ args.source = hidlSharedBufferToAidlSharedBuffer(hSource);
+ args.offset = offset;
+ args.destination = hidlDestinationBufferToAidlDestinationBuffer(hDestination);
+
+
+ int32_t result = 0;
+ ::ndk::ScopedAStatus statusAidl = mPlugin->decrypt(args, &result);
+
+ err = statusAidlToStatusT(statusAidl);
+ std::string msgStr(statusAidl.getMessage());
+ *errorDetailMsg = toString8(msgStr);
+ if (err != OK) {
+ ALOGE("Failed on decrypt, error message:%s, bytes written:%d", statusAidl.getMessage(),
+ result);
+ return err;
+ }
+
+ return result;
+}
+
+int32_t CryptoHalAidl::setHeap(const sp<HidlMemory>& heap) {
+ if (heap == NULL || mHeapSeqNum < 0) {
+ ALOGE("setHeap(): heap %p mHeapSeqNum %d", heap.get(), mHeapSeqNum);
+ return -1;
+ }
+
+ Mutex::Autolock autoLock(mLock);
+
+ int32_t seqNum = mHeapSeqNum++;
+ uint32_t bufferId = static_cast<uint32_t>(seqNum);
+ mHeapSizes.add(seqNum, heap->size());
+
+ SharedBufferAidl memAidl;
+ memAidl.handle = ::android::makeToAidl(heap->handle());
+ memAidl.size = heap->size();
+ memAidl.bufferId = bufferId;
+
+ auto status = mPlugin->setSharedBufferBase(memAidl);
+ ALOGE_IF(!status.isOk(),
+ "setSharedBufferBase(): remote call failed");
+ return seqNum;
+}
+
+void CryptoHalAidl::unsetHeap(int32_t seqNum) {
+ Mutex::Autolock autoLock(mLock);
+
+ /*
+ * Clear the remote shared memory mapping by setting the shared
+ * buffer base to a null hidl_memory.
+ *
+ * TODO: Add a releaseSharedBuffer method in a future DRM HAL
+ * API version to make this explicit.
+ */
+ ssize_t index = mHeapSizes.indexOfKey(seqNum);
+ if (index >= 0) {
+ if (mPlugin != NULL) {
+ uint32_t bufferId = static_cast<uint32_t>(seqNum);
+ SharedBufferAidl memAidl{};
+ memAidl.bufferId = bufferId;
+ auto status = mPlugin->setSharedBufferBase(memAidl);
+ ALOGE_IF(!status.isOk(),
+ "setSharedBufferBase(): remote call failed");
+ }
+ mHeapSizes.removeItem(seqNum);
+ }
+}
+
+status_t CryptoHalAidl::getLogMessages(Vector<drm::V1_4::LogMessage>& logs) const {
+ Mutex::Autolock autoLock(mLock);
+ // Need to convert logmessage
+
+ return DrmUtils::GetLogMessagesAidl<ICryptoPluginAidl>(mPlugin, logs);
+}
+} // namespace android
\ No newline at end of file
diff --git a/drm/libmediadrm/CryptoHalHidl.cpp b/drm/libmediadrm/CryptoHalHidl.cpp
new file mode 100644
index 0000000..cbb6ddf
--- /dev/null
+++ b/drm/libmediadrm/CryptoHalHidl.cpp
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) 2017 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 "CryptoHalHidl"
+#include <utils/Log.h>
+
+#include <android/hardware/drm/1.0/types.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <hidl/ServiceManagement.h>
+#include <hidlmemory/FrameworkUtils.h>
+#include <media/hardware/CryptoAPI.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/hexdump.h>
+#include <mediadrm/CryptoHalHidl.h>
+#include <mediadrm/DrmUtils.h>
+
+using drm::V1_0::BufferType;
+using drm::V1_0::DestinationBuffer;
+using drm::V1_0::ICryptoFactory;
+using drm::V1_0::ICryptoPlugin;
+using drm::V1_0::Mode;
+using drm::V1_0::Pattern;
+using drm::V1_0::SharedBuffer;
+using drm::V1_0::Status;
+using drm::V1_0::SubSample;
+
+using ::android::sp;
+using ::android::DrmUtils::toStatusT;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::HidlMemory;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+typedef drm::V1_2::Status Status_V1_2;
+
+namespace android {
+
+static hidl_vec<uint8_t> toHidlVec(const Vector<uint8_t>& vector) {
+ hidl_vec<uint8_t> vec;
+ vec.setToExternal(const_cast<uint8_t*>(vector.array()), vector.size());
+ return vec;
+}
+
+static hidl_vec<uint8_t> toHidlVec(const void* ptr, size_t size) {
+ hidl_vec<uint8_t> vec;
+ vec.resize(size);
+ memcpy(vec.data(), ptr, size);
+ return vec;
+}
+
+static hidl_array<uint8_t, 16> toHidlArray16(const uint8_t* ptr) {
+ if (!ptr) {
+ return hidl_array<uint8_t, 16>();
+ }
+ return hidl_array<uint8_t, 16>(ptr);
+}
+
+static String8 toString8(hidl_string hString) {
+ return String8(hString.c_str());
+}
+
+CryptoHalHidl::CryptoHalHidl()
+ : mFactories(makeCryptoFactories()),
+ mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT),
+ mHeapSeqNum(0) {}
+
+CryptoHalHidl::~CryptoHalHidl() {}
+
+Vector<sp<ICryptoFactory>> CryptoHalHidl::makeCryptoFactories() {
+ Vector<sp<ICryptoFactory>> factories;
+
+ auto manager = hardware::defaultServiceManager1_2();
+ if (manager != NULL) {
+ manager->listManifestByInterface(
+ drm::V1_0::ICryptoFactory::descriptor,
+ [&factories](const hidl_vec<hidl_string>& registered) {
+ for (const auto& instance : registered) {
+ auto factory = drm::V1_0::ICryptoFactory::getService(instance);
+ if (factory != NULL) {
+ ALOGD("found drm@1.0 ICryptoFactory %s", instance.c_str());
+ factories.push_back(factory);
+ }
+ }
+ });
+ manager->listManifestByInterface(
+ drm::V1_1::ICryptoFactory::descriptor,
+ [&factories](const hidl_vec<hidl_string>& registered) {
+ for (const auto& instance : registered) {
+ auto factory = drm::V1_1::ICryptoFactory::getService(instance);
+ if (factory != NULL) {
+ ALOGD("found drm@1.1 ICryptoFactory %s", instance.c_str());
+ factories.push_back(factory);
+ }
+ }
+ });
+ }
+
+ if (factories.size() == 0) {
+ // must be in passthrough mode, load the default passthrough service
+ auto passthrough = ICryptoFactory::getService();
+ if (passthrough != NULL) {
+ ALOGI("makeCryptoFactories: using default passthrough crypto instance");
+ factories.push_back(passthrough);
+ } else {
+ ALOGE("Failed to find any crypto factories");
+ }
+ }
+ return factories;
+}
+
+sp<ICryptoPlugin> CryptoHalHidl::makeCryptoPlugin(const sp<ICryptoFactory>& factory,
+ const uint8_t uuid[16], const void* initData,
+ size_t initDataSize) {
+ sp<ICryptoPlugin> plugin;
+ Return<void> hResult =
+ factory->createPlugin(toHidlArray16(uuid), toHidlVec(initData, initDataSize),
+ [&](Status status, const sp<ICryptoPlugin>& hPlugin) {
+ if (status != Status::OK) {
+ ALOGE("Failed to make crypto plugin");
+ return;
+ }
+ plugin = hPlugin;
+ });
+ if (!hResult.isOk()) {
+ mInitCheck = DEAD_OBJECT;
+ }
+ return plugin;
+}
+
+status_t CryptoHalHidl::initCheck() const {
+ return mInitCheck;
+}
+
+bool CryptoHalHidl::isCryptoSchemeSupported(const uint8_t uuid[16]) {
+ Mutex::Autolock autoLock(mLock);
+
+ for (size_t i = 0; i < mFactories.size(); i++) {
+ if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+status_t CryptoHalHidl::createPlugin(const uint8_t uuid[16], const void* data, size_t size) {
+ Mutex::Autolock autoLock(mLock);
+
+ for (size_t i = 0; i < mFactories.size(); i++) {
+ if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
+ mPlugin = makeCryptoPlugin(mFactories[i], uuid, data, size);
+ if (mPlugin != NULL) {
+ mPluginV1_2 = drm::V1_2::ICryptoPlugin::castFrom(mPlugin);
+ }
+ }
+ }
+
+ if (mInitCheck == NO_INIT) {
+ mInitCheck = mPlugin == NULL ? ERROR_UNSUPPORTED : OK;
+ }
+
+ return mInitCheck;
+}
+
+status_t CryptoHalHidl::destroyPlugin() {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ mPlugin.clear();
+ mPluginV1_2.clear();
+ return OK;
+}
+
+bool CryptoHalHidl::requiresSecureDecoderComponent(const char* mime) const {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return false;
+ }
+
+ Return<bool> hResult = mPlugin->requiresSecureDecoderComponent(hidl_string(mime));
+ if (!hResult.isOk()) {
+ return false;
+ }
+ return hResult;
+}
+
+/**
+ * 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.
+ */
+int32_t CryptoHalHidl::setHeapBase(const sp<HidlMemory>& heap) {
+ if (heap == NULL || mHeapSeqNum < 0) {
+ ALOGE("setHeapBase(): heap %p mHeapSeqNum %d", heap.get(), mHeapSeqNum);
+ return -1;
+ }
+
+ Mutex::Autolock autoLock(mLock);
+
+ int32_t seqNum = mHeapSeqNum++;
+ uint32_t bufferId = static_cast<uint32_t>(seqNum);
+ mHeapSizes.add(seqNum, heap->size());
+ Return<void> hResult = mPlugin->setSharedBufferBase(*heap, bufferId);
+ ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
+ return seqNum;
+}
+
+void CryptoHalHidl::clearHeapBase(int32_t seqNum) {
+ Mutex::Autolock autoLock(mLock);
+
+ /*
+ * Clear the remote shared memory mapping by setting the shared
+ * buffer base to a null hidl_memory.
+ *
+ * TODO: Add a releaseSharedBuffer method in a future DRM HAL
+ * API version to make this explicit.
+ */
+ ssize_t index = mHeapSizes.indexOfKey(seqNum);
+ if (index >= 0) {
+ if (mPlugin != NULL) {
+ uint32_t bufferId = static_cast<uint32_t>(seqNum);
+ Return<void> hResult = mPlugin->setSharedBufferBase(hidl_memory(), bufferId);
+ ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
+ }
+ mHeapSizes.removeItem(seqNum);
+ }
+}
+
+status_t CryptoHalHidl::checkSharedBuffer(const ::SharedBuffer& buffer) {
+ int32_t seqNum = static_cast<int32_t>(buffer.bufferId);
+ // memory must be in one of the heaps that have been set
+ if (mHeapSizes.indexOfKey(seqNum) < 0) {
+ return UNKNOWN_ERROR;
+ }
+
+ // memory must be within the address space of the heap
+ size_t heapSize = mHeapSizes.valueFor(seqNum);
+ if (heapSize < buffer.offset + buffer.size || SIZE_MAX - buffer.offset < buffer.size) {
+ android_errorWriteLog(0x534e4554, "76221123");
+ return UNKNOWN_ERROR;
+ }
+
+ return OK;
+}
+
+ssize_t CryptoHalHidl::decrypt(const uint8_t keyId[16], const uint8_t iv[16],
+ CryptoPlugin::Mode mode, const CryptoPlugin::Pattern& pattern,
+ const drm::V1_0::SharedBuffer& hSource, size_t offset,
+ const CryptoPlugin::SubSample* subSamples, size_t numSubSamples,
+ const drm::V1_0::DestinationBuffer& hDestination,
+ AString* errorDetailMsg) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ Mode hMode;
+ switch (mode) {
+ case CryptoPlugin::kMode_Unencrypted:
+ hMode = Mode::UNENCRYPTED;
+ break;
+ case CryptoPlugin::kMode_AES_CTR:
+ hMode = Mode::AES_CTR;
+ break;
+ case CryptoPlugin::kMode_AES_WV:
+ hMode = Mode::AES_CBC_CTS;
+ break;
+ case CryptoPlugin::kMode_AES_CBC:
+ hMode = Mode::AES_CBC;
+ break;
+ default:
+ return UNKNOWN_ERROR;
+ }
+
+ Pattern hPattern;
+ hPattern.encryptBlocks = pattern.mEncryptBlocks;
+ hPattern.skipBlocks = pattern.mSkipBlocks;
+
+ std::vector<SubSample> stdSubSamples;
+ for (size_t i = 0; i < numSubSamples; i++) {
+ SubSample subSample;
+ subSample.numBytesOfClearData = subSamples[i].mNumBytesOfClearData;
+ subSample.numBytesOfEncryptedData = subSamples[i].mNumBytesOfEncryptedData;
+ stdSubSamples.push_back(subSample);
+ }
+ auto hSubSamples = hidl_vec<SubSample>(stdSubSamples);
+
+ bool secure;
+ if (hDestination.type == BufferType::SHARED_MEMORY) {
+ status_t status = checkSharedBuffer(hDestination.nonsecureMemory);
+ if (status != OK) {
+ return status;
+ }
+ secure = false;
+ } else if (hDestination.type == BufferType::NATIVE_HANDLE) {
+ secure = true;
+ } else {
+ android_errorWriteLog(0x534e4554, "70526702");
+ return UNKNOWN_ERROR;
+ }
+
+ status_t status = checkSharedBuffer(hSource);
+ if (status != OK) {
+ return status;
+ }
+
+ status_t err = UNKNOWN_ERROR;
+ uint32_t bytesWritten = 0;
+
+ Return<void> hResult;
+
+ mLock.unlock();
+ if (mPluginV1_2 != NULL) {
+ hResult = mPluginV1_2->decrypt_1_2(
+ secure, toHidlArray16(keyId), toHidlArray16(iv), hMode, hPattern, hSubSamples,
+ hSource, offset, hDestination,
+ [&](Status_V1_2 status, uint32_t hBytesWritten, hidl_string hDetailedError) {
+ if (status == Status_V1_2::OK) {
+ bytesWritten = hBytesWritten;
+ *errorDetailMsg = toString8(hDetailedError);
+ }
+ err = toStatusT(status);
+ });
+ } else {
+ hResult = mPlugin->decrypt(
+ secure, toHidlArray16(keyId), toHidlArray16(iv), hMode, hPattern, hSubSamples,
+ hSource, offset, hDestination,
+ [&](Status status, uint32_t hBytesWritten, hidl_string hDetailedError) {
+ if (status == Status::OK) {
+ bytesWritten = hBytesWritten;
+ *errorDetailMsg = toString8(hDetailedError);
+ }
+ err = toStatusT(status);
+ });
+ }
+
+ err = hResult.isOk() ? err : DEAD_OBJECT;
+ if (err == OK) {
+ return bytesWritten;
+ }
+ return err;
+}
+
+void CryptoHalHidl::notifyResolution(uint32_t width, uint32_t height) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return;
+ }
+
+ auto hResult = mPlugin->notifyResolution(width, height);
+ ALOGE_IF(!hResult.isOk(), "notifyResolution txn failed %s", hResult.description().c_str());
+}
+
+status_t CryptoHalHidl::setMediaDrmSession(const Vector<uint8_t>& sessionId) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ auto err = mPlugin->setMediaDrmSession(toHidlVec(sessionId));
+ return err.isOk() ? toStatusT(err) : DEAD_OBJECT;
+}
+
+status_t CryptoHalHidl::getLogMessages(Vector<drm::V1_4::LogMessage>& logs) const {
+ Mutex::Autolock autoLock(mLock);
+ return DrmUtils::GetLogMessages<drm::V1_4::ICryptoPlugin>(mPlugin, logs);
+}
+} // namespace android
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 40d1e0c..aa40793 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -17,1557 +17,273 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "DrmHal"
-#include <aidl/android/media/BnResourceManagerClient.h>
-#include <android/binder_manager.h>
-#include <android/hardware/drm/1.2/types.h>
-#include <android/hidl/manager/1.2/IServiceManager.h>
-#include <hidl/ServiceManagement.h>
-#include <media/EventMetric.h>
-#include <media/MediaMetrics.h>
-#include <media/PluginMetricsReporting.h>
-#include <media/drm/DrmAPI.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AString.h>
-#include <media/stagefright/foundation/base64.h>
-#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/MediaErrors.h>
#include <mediadrm/DrmHal.h>
-#include <mediadrm/DrmSessionClientInterface.h>
-#include <mediadrm/DrmSessionManager.h>
-#include <mediadrm/IDrmMetricsConsumer.h>
+#include <mediadrm/DrmHalAidl.h>
+#include <mediadrm/DrmHalHidl.h>
#include <mediadrm/DrmUtils.h>
-#include <utils/Log.h>
-
-#include <iomanip>
-#include <vector>
-
-using drm::V1_0::KeyedVector;
-using drm::V1_0::KeyRequestType;
-using drm::V1_0::KeyType;
-using drm::V1_0::KeyValue;
-using drm::V1_0::SecureStop;
-using drm::V1_0::SecureStopId;
-using drm::V1_0::Status;
-using drm::V1_1::HdcpLevel;
-using drm::V1_1::SecureStopRelease;
-using drm::V1_1::SecurityLevel;
-using drm::V1_2::KeySetId;
-using drm::V1_2::KeyStatusType;
-using ::android::DrmUtils::toStatusT;
-using ::android::hardware::drm::V1_1::DrmMetricGroup;
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::os::PersistableBundle;
-using ::android::sp;
-
-typedef drm::V1_1::KeyRequestType KeyRequestType_V1_1;
-typedef drm::V1_2::Status Status_V1_2;
-typedef drm::V1_2::HdcpLevel HdcpLevel_V1_2;
-
-namespace {
-
-// This constant corresponds to the PROPERTY_DEVICE_UNIQUE_ID constant
-// in the MediaDrm API.
-constexpr char kPropertyDeviceUniqueId[] = "deviceUniqueId";
-constexpr char kEqualsSign[] = "=";
-
-template<typename T>
-std::string toBase64StringNoPad(const T* data, size_t size) {
- // Note that the base 64 conversion only works with arrays of single-byte
- // values. If the source is empty or is not an array of single-byte values,
- // return empty string.
- if (size == 0 || sizeof(data[0]) != 1) {
- return "";
- }
-
- android::AString outputString;
- encodeBase64(data, size, &outputString);
- // Remove trailing equals padding if it exists.
- while (outputString.size() > 0 && outputString.endsWith(kEqualsSign)) {
- outputString.erase(outputString.size() - 1, 1);
- }
-
- return std::string(outputString.c_str(), outputString.size());
-}
-
-} // anonymous namespace
namespace android {
-#define INIT_CHECK() {if (mInitCheck != OK) return mInitCheck;}
-
-static const Vector<uint8_t> toVector(const hidl_vec<uint8_t> &vec) {
- Vector<uint8_t> vector;
- vector.appendArray(vec.data(), vec.size());
- return *const_cast<const Vector<uint8_t> *>(&vector);
+DrmHal::DrmHal() {
+ mDrmHalHidl = sp<DrmHalHidl>::make();
+ mDrmHalAidl = sp<DrmHalAidl>::make();
}
-static hidl_vec<uint8_t> toHidlVec(const Vector<uint8_t> &vector) {
- hidl_vec<uint8_t> vec;
- vec.setToExternal(const_cast<uint8_t *>(vector.array()), vector.size());
- return vec;
-}
-
-static String8 toString8(const hidl_string &string) {
- return String8(string.c_str());
-}
-
-static hidl_string toHidlString(const String8& string) {
- return hidl_string(string.string());
-}
-
-static DrmPlugin::SecurityLevel toSecurityLevel(SecurityLevel level) {
- switch(level) {
- case SecurityLevel::SW_SECURE_CRYPTO:
- return DrmPlugin::kSecurityLevelSwSecureCrypto;
- case SecurityLevel::SW_SECURE_DECODE:
- return DrmPlugin::kSecurityLevelSwSecureDecode;
- case SecurityLevel::HW_SECURE_CRYPTO:
- return DrmPlugin::kSecurityLevelHwSecureCrypto;
- case SecurityLevel::HW_SECURE_DECODE:
- return DrmPlugin::kSecurityLevelHwSecureDecode;
- case SecurityLevel::HW_SECURE_ALL:
- return DrmPlugin::kSecurityLevelHwSecureAll;
- default:
- return DrmPlugin::kSecurityLevelUnknown;
- }
-}
-
-static SecurityLevel toHidlSecurityLevel(DrmPlugin::SecurityLevel level) {
- switch(level) {
- case DrmPlugin::kSecurityLevelSwSecureCrypto:
- return SecurityLevel::SW_SECURE_CRYPTO;
- case DrmPlugin::kSecurityLevelSwSecureDecode:
- return SecurityLevel::SW_SECURE_DECODE;
- case DrmPlugin::kSecurityLevelHwSecureCrypto:
- return SecurityLevel::HW_SECURE_CRYPTO;
- case DrmPlugin::kSecurityLevelHwSecureDecode:
- return SecurityLevel::HW_SECURE_DECODE;
- case DrmPlugin::kSecurityLevelHwSecureAll:
- return SecurityLevel::HW_SECURE_ALL;
- default:
- return SecurityLevel::UNKNOWN;
- }
-}
-
-static DrmPlugin::OfflineLicenseState toOfflineLicenseState(
- OfflineLicenseState licenseState) {
- switch(licenseState) {
- case OfflineLicenseState::USABLE:
- return DrmPlugin::kOfflineLicenseStateUsable;
- case OfflineLicenseState::INACTIVE:
- return DrmPlugin::kOfflineLicenseStateReleased;
- default:
- return DrmPlugin::kOfflineLicenseStateUnknown;
- }
-}
-
-static DrmPlugin::HdcpLevel toHdcpLevel(HdcpLevel_V1_2 level) {
- switch(level) {
- case HdcpLevel_V1_2::HDCP_NONE:
- return DrmPlugin::kHdcpNone;
- case HdcpLevel_V1_2::HDCP_V1:
- return DrmPlugin::kHdcpV1;
- case HdcpLevel_V1_2::HDCP_V2:
- return DrmPlugin::kHdcpV2;
- case HdcpLevel_V1_2::HDCP_V2_1:
- return DrmPlugin::kHdcpV2_1;
- case HdcpLevel_V1_2::HDCP_V2_2:
- return DrmPlugin::kHdcpV2_2;
- case HdcpLevel_V1_2::HDCP_V2_3:
- return DrmPlugin::kHdcpV2_3;
- case HdcpLevel_V1_2::HDCP_NO_OUTPUT:
- return DrmPlugin::kHdcpNoOutput;
- default:
- return DrmPlugin::kHdcpLevelUnknown;
- }
-}
-static ::KeyedVector toHidlKeyedVector(const KeyedVector<String8, String8>&
- keyedVector) {
- std::vector<KeyValue> stdKeyedVector;
- for (size_t i = 0; i < keyedVector.size(); i++) {
- KeyValue keyValue;
- keyValue.key = toHidlString(keyedVector.keyAt(i));
- keyValue.value = toHidlString(keyedVector.valueAt(i));
- stdKeyedVector.push_back(keyValue);
- }
- return ::KeyedVector(stdKeyedVector);
-}
-
-static KeyedVector<String8, String8> toKeyedVector(const ::KeyedVector&
- hKeyedVector) {
- KeyedVector<String8, String8> keyedVector;
- for (size_t i = 0; i < hKeyedVector.size(); i++) {
- keyedVector.add(toString8(hKeyedVector[i].key),
- toString8(hKeyedVector[i].value));
- }
- return keyedVector;
-}
-
-static List<Vector<uint8_t>> toSecureStops(const hidl_vec<SecureStop>&
- hSecureStops) {
- List<Vector<uint8_t>> secureStops;
- for (size_t i = 0; i < hSecureStops.size(); i++) {
- secureStops.push_back(toVector(hSecureStops[i].opaqueData));
- }
- return secureStops;
-}
-
-static List<Vector<uint8_t>> toSecureStopIds(const hidl_vec<SecureStopId>&
- hSecureStopIds) {
- List<Vector<uint8_t>> secureStopIds;
- for (size_t i = 0; i < hSecureStopIds.size(); i++) {
- secureStopIds.push_back(toVector(hSecureStopIds[i]));
- }
- return secureStopIds;
-}
-
-static List<Vector<uint8_t>> toKeySetIds(const hidl_vec<KeySetId>&
- hKeySetIds) {
- List<Vector<uint8_t>> keySetIds;
- for (size_t i = 0; i < hKeySetIds.size(); i++) {
- keySetIds.push_back(toVector(hKeySetIds[i]));
- }
- return keySetIds;
-}
-
-Mutex DrmHal::mLock;
-
-struct DrmHal::DrmSessionClient : public aidl::android::media::BnResourceManagerClient {
- explicit DrmSessionClient(DrmHal* drm, const Vector<uint8_t>& sessionId)
- : mSessionId(sessionId),
- mDrm(drm) {}
-
- ::ndk::ScopedAStatus reclaimResource(bool* _aidl_return) override;
- ::ndk::ScopedAStatus getName(::std::string* _aidl_return) override;
-
- const Vector<uint8_t> mSessionId;
-
- virtual ~DrmSessionClient();
-
-private:
- wp<DrmHal> mDrm;
-
- DISALLOW_EVIL_CONSTRUCTORS(DrmSessionClient);
-};
-
-::ndk::ScopedAStatus DrmHal::DrmSessionClient::reclaimResource(bool* _aidl_return) {
- auto sessionId = mSessionId;
- sp<DrmHal> drm = mDrm.promote();
- if (drm == NULL) {
- *_aidl_return = true;
- return ::ndk::ScopedAStatus::ok();
- }
- status_t err = drm->closeSession(sessionId);
- if (err != OK) {
- *_aidl_return = false;
- return ::ndk::ScopedAStatus::ok();
- }
- drm->sendEvent(EventType::SESSION_RECLAIMED,
- toHidlVec(sessionId), hidl_vec<uint8_t>());
- *_aidl_return = true;
- return ::ndk::ScopedAStatus::ok();
-}
-
-::ndk::ScopedAStatus DrmHal::DrmSessionClient::getName(::std::string* _aidl_return) {
- String8 name;
- sp<DrmHal> drm = mDrm.promote();
- if (drm == NULL) {
- name.append("<deleted>");
- } else if (drm->getPropertyStringInternal(String8("vendor"), name) != OK
- || name.isEmpty()) {
- name.append("<Get vendor failed or is empty>");
- }
- name.append("[");
- for (size_t i = 0; i < mSessionId.size(); ++i) {
- name.appendFormat("%02x", mSessionId[i]);
- }
- name.append("]");
- *_aidl_return = name;
- return ::ndk::ScopedAStatus::ok();
-}
-
-DrmHal::DrmSessionClient::~DrmSessionClient() {
- DrmSessionManager::Instance()->removeSession(mSessionId);
-}
-
-DrmHal::DrmHal()
- : mFactories(makeDrmFactories()),
- mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT) {
-}
-
-void DrmHal::closeOpenSessions() {
- Mutex::Autolock autoLock(mLock);
- auto openSessions = mOpenSessions;
- for (size_t i = 0; i < openSessions.size(); i++) {
- mLock.unlock();
- closeSession(openSessions[i]->mSessionId);
- mLock.lock();
- }
- mOpenSessions.clear();
-}
-
-DrmHal::~DrmHal() {
-}
-
-void DrmHal::cleanup() {
- closeOpenSessions();
-
- Mutex::Autolock autoLock(mLock);
- reportFrameworkMetrics(reportPluginMetrics());
-
- setListener(NULL);
- mInitCheck = NO_INIT;
- if (mPluginV1_2 != NULL) {
- if (!mPluginV1_2->setListener(NULL).isOk()) {
- mInitCheck = DEAD_OBJECT;
- }
- } else if (mPlugin != NULL) {
- if (!mPlugin->setListener(NULL).isOk()) {
- mInitCheck = DEAD_OBJECT;
- }
- }
- mPlugin.clear();
- mPluginV1_1.clear();
- mPluginV1_2.clear();
- mPluginV1_4.clear();
-}
-
-std::vector<sp<IDrmFactory>> DrmHal::makeDrmFactories() {
- static 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();
- if (passthrough != NULL) {
- DrmUtils::LOG2BI("makeDrmFactories: using default passthrough drm instance");
- factories.push_back(passthrough);
- } else {
- DrmUtils::LOG2BE("Failed to find any drm factories");
- }
- }
- return factories;
-}
-
-sp<IDrmPlugin> DrmHal::makeDrmPlugin(const sp<IDrmFactory>& factory,
- const uint8_t uuid[16], const String8& appPackageName) {
- mAppPackageName = appPackageName;
- mMetrics.SetAppPackageName(appPackageName);
- mMetrics.SetAppUid(AIBinder_getCallingUid());
-
- sp<IDrmPlugin> plugin;
- Return<void> hResult = factory->createPlugin(uuid, appPackageName.string(),
- [&](Status status, const sp<IDrmPlugin>& hPlugin) {
- if (status != Status::OK) {
- DrmUtils::LOG2BE(uuid, "Failed to make drm plugin: %d", status);
- return;
- }
- plugin = hPlugin;
- }
- );
-
- if (!hResult.isOk()) {
- DrmUtils::LOG2BE(uuid, "createPlugin remote call failed: %s",
- hResult.description().c_str());
- }
-
- return plugin;
-}
+DrmHal::~DrmHal() {}
status_t DrmHal::initCheck() const {
- return mInitCheck;
+ if (mDrmHalAidl->initCheck() == OK || mDrmHalHidl->initCheck() == OK) return OK;
+ if (mDrmHalAidl->initCheck() == NO_INIT || mDrmHalHidl->initCheck() == NO_INIT) return NO_INIT;
+ return mDrmHalHidl->initCheck();
}
-status_t DrmHal::setListener(const sp<IDrmClient>& listener)
-{
- Mutex::Autolock lock(mEventLock);
- mListener = listener;
- return NO_ERROR;
+status_t DrmHal::isCryptoSchemeSupported(const uint8_t uuid[16], const String8& mimeType,
+ DrmPlugin::SecurityLevel securityLevel, bool* result) {
+ status_t statusResult;
+ statusResult = mDrmHalAidl->isCryptoSchemeSupported(uuid, mimeType, securityLevel, result);
+ if (*result) return statusResult;
+ return mDrmHalHidl->isCryptoSchemeSupported(uuid, mimeType, securityLevel, result);
}
-Return<void> DrmHal::sendEvent(EventType hEventType,
- const hidl_vec<uint8_t>& sessionId, const hidl_vec<uint8_t>& data) {
- mMetrics.mEventCounter.Increment(hEventType);
-
- mEventLock.lock();
- sp<IDrmClient> listener = mListener;
- mEventLock.unlock();
-
- if (listener != NULL) {
- Mutex::Autolock lock(mNotifyLock);
- DrmPlugin::EventType eventType;
- switch(hEventType) {
- case EventType::PROVISION_REQUIRED:
- eventType = DrmPlugin::kDrmPluginEventProvisionRequired;
- break;
- case EventType::KEY_NEEDED:
- eventType = DrmPlugin::kDrmPluginEventKeyNeeded;
- break;
- case EventType::KEY_EXPIRED:
- eventType = DrmPlugin::kDrmPluginEventKeyExpired;
- break;
- case EventType::VENDOR_DEFINED:
- eventType = DrmPlugin::kDrmPluginEventVendorDefined;
- break;
- case EventType::SESSION_RECLAIMED:
- eventType = DrmPlugin::kDrmPluginEventSessionReclaimed;
- break;
- default:
- return Void();
- }
- listener->sendEvent(eventType, sessionId, data);
- }
- return Void();
-}
-
-Return<void> DrmHal::sendExpirationUpdate(const hidl_vec<uint8_t>& sessionId,
- int64_t expiryTimeInMS) {
-
- mEventLock.lock();
- sp<IDrmClient> listener = mListener;
- mEventLock.unlock();
-
- if (listener != NULL) {
- Mutex::Autolock lock(mNotifyLock);
- listener->sendExpirationUpdate(sessionId, expiryTimeInMS);
- }
- return Void();
-}
-
-Return<void> DrmHal::sendKeysChange(const hidl_vec<uint8_t>& sessionId,
- const hidl_vec<KeyStatus_V1_0>& keyStatusList_V1_0, bool hasNewUsableKey) {
- std::vector<KeyStatus> keyStatusVec;
- for (const auto &keyStatus_V1_0 : keyStatusList_V1_0) {
- keyStatusVec.push_back({keyStatus_V1_0.keyId,
- static_cast<KeyStatusType>(keyStatus_V1_0.type)});
- }
- hidl_vec<KeyStatus> keyStatusList_V1_2(keyStatusVec);
- return sendKeysChange_1_2(sessionId, keyStatusList_V1_2, hasNewUsableKey);
-}
-
-Return<void> DrmHal::sendKeysChange_1_2(const hidl_vec<uint8_t>& sessionId,
- const hidl_vec<KeyStatus>& hKeyStatusList, bool hasNewUsableKey) {
-
- mEventLock.lock();
- sp<IDrmClient> listener = mListener;
- mEventLock.unlock();
-
- if (listener != NULL) {
- std::vector<DrmKeyStatus> keyStatusList;
- size_t nKeys = hKeyStatusList.size();
- for (size_t i = 0; i < nKeys; ++i) {
- const KeyStatus &keyStatus = hKeyStatusList[i];
- uint32_t type;
- switch(keyStatus.type) {
- case KeyStatusType::USABLE:
- type = DrmPlugin::kKeyStatusType_Usable;
- break;
- case KeyStatusType::EXPIRED:
- type = DrmPlugin::kKeyStatusType_Expired;
- break;
- case KeyStatusType::OUTPUTNOTALLOWED:
- type = DrmPlugin::kKeyStatusType_OutputNotAllowed;
- break;
- case KeyStatusType::STATUSPENDING:
- type = DrmPlugin::kKeyStatusType_StatusPending;
- break;
- case KeyStatusType::USABLEINFUTURE:
- type = DrmPlugin::kKeyStatusType_UsableInFuture;
- break;
- case KeyStatusType::INTERNALERROR:
- default:
- type = DrmPlugin::kKeyStatusType_InternalError;
- break;
- }
- keyStatusList.push_back({type, keyStatus.keyId});
- mMetrics.mKeyStatusChangeCounter.Increment(keyStatus.type);
- }
-
- Mutex::Autolock lock(mNotifyLock);
- listener->sendKeysChange(sessionId, keyStatusList, hasNewUsableKey);
- } else {
- // There's no listener. But we still want to count the key change
- // events.
- size_t nKeys = hKeyStatusList.size();
- for (size_t i = 0; i < nKeys; i++) {
- mMetrics.mKeyStatusChangeCounter.Increment(hKeyStatusList[i].type);
- }
- }
-
- return Void();
-}
-
-Return<void> DrmHal::sendSessionLostState(
- const hidl_vec<uint8_t>& sessionId) {
-
- mEventLock.lock();
- sp<IDrmClient> listener = mListener;
- mEventLock.unlock();
-
- if (listener != NULL) {
- Mutex::Autolock lock(mNotifyLock);
- listener->sendSessionLostState(sessionId);
- }
- return Void();
-}
-
-status_t DrmHal::matchMimeTypeAndSecurityLevel(const sp<IDrmFactory> &factory,
- const uint8_t uuid[16],
- const String8 &mimeType,
- DrmPlugin::SecurityLevel level,
- bool *isSupported) {
- *isSupported = false;
-
- // handle default value cases
- if (level == DrmPlugin::kSecurityLevelUnknown) {
- if (mimeType == "") {
- // isCryptoSchemeSupported(uuid)
- *isSupported = true;
- } else {
- // isCryptoSchemeSupported(uuid, mimeType)
- *isSupported = factory->isContentTypeSupported(mimeType.string());
- }
- return OK;
- } else if (mimeType == "") {
- return BAD_VALUE;
- }
-
- sp<drm::V1_2::IDrmFactory> factoryV1_2 = drm::V1_2::IDrmFactory::castFrom(factory);
- if (factoryV1_2 == NULL) {
- return ERROR_UNSUPPORTED;
- } else {
- *isSupported = factoryV1_2->isCryptoSchemeSupported_1_2(uuid,
- mimeType.string(), toHidlSecurityLevel(level));
- return OK;
- }
-}
-
-status_t DrmHal::isCryptoSchemeSupported(const uint8_t uuid[16],
- const String8 &mimeType,
- DrmPlugin::SecurityLevel level,
- bool *isSupported) {
- Mutex::Autolock autoLock(mLock);
- *isSupported = false;
- for (ssize_t i = mFactories.size() - 1; i >= 0; i--) {
- if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
- return matchMimeTypeAndSecurityLevel(mFactories[i],
- uuid, mimeType, level, isSupported);
- }
- }
- return OK;
-}
-
-status_t DrmHal::createPlugin(const uint8_t uuid[16],
- const String8& appPackageName) {
- Mutex::Autolock autoLock(mLock);
-
- for (ssize_t i = mFactories.size() - 1; i >= 0; i--) {
- auto hResult = mFactories[i]->isCryptoSchemeSupported(uuid);
- if (hResult.isOk() && hResult) {
- auto plugin = makeDrmPlugin(mFactories[i], uuid, appPackageName);
- if (plugin != NULL) {
- mPlugin = plugin;
- mPluginV1_1 = drm::V1_1::IDrmPlugin::castFrom(mPlugin);
- mPluginV1_2 = drm::V1_2::IDrmPlugin::castFrom(mPlugin);
- mPluginV1_4 = drm::V1_4::IDrmPlugin::castFrom(mPlugin);
- break;
- }
- }
- }
-
- if (mPlugin == NULL) {
- DrmUtils::LOG2BE(uuid, "No supported hal instance found");
- mInitCheck = ERROR_UNSUPPORTED;
- } else {
- mInitCheck = OK;
- if (mPluginV1_2 != NULL) {
- if (!mPluginV1_2->setListener(this).isOk()) {
- mInitCheck = DEAD_OBJECT;
- }
- } else if (!mPlugin->setListener(this).isOk()) {
- mInitCheck = DEAD_OBJECT;
- }
- if (mInitCheck != OK) {
- mPlugin.clear();
- mPluginV1_1.clear();
- mPluginV1_2.clear();
- mPluginV1_4.clear();
- }
- }
-
-
- return mInitCheck;
+status_t DrmHal::createPlugin(const uint8_t uuid[16], const String8& appPackageName) {
+ status_t statusResult;
+ statusResult = mDrmHalAidl->createPlugin(uuid, appPackageName);
+ if (statusResult != OK) return mDrmHalHidl->createPlugin(uuid, appPackageName);
+ return statusResult;
}
status_t DrmHal::destroyPlugin() {
- cleanup();
- return OK;
+ status_t statusResult = mDrmHalAidl->destroyPlugin();
+ status_t statusResultHidl = mDrmHalHidl->destroyPlugin();
+ if (statusResult != OK) return statusResult;
+ return statusResultHidl;
}
-status_t DrmHal::openSession(DrmPlugin::SecurityLevel level,
- Vector<uint8_t> &sessionId) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- SecurityLevel hSecurityLevel = toHidlSecurityLevel(level);
- bool setSecurityLevel = true;
-
- if (level == DrmPlugin::kSecurityLevelMax) {
- setSecurityLevel = false;
- } else {
- if (hSecurityLevel == SecurityLevel::UNKNOWN) {
- return ERROR_DRM_CANNOT_HANDLE;
- }
- }
-
- status_t err = UNKNOWN_ERROR;
- bool retry = true;
- do {
- hidl_vec<uint8_t> hSessionId;
-
- Return<void> hResult;
- if (mPluginV1_1 == NULL || !setSecurityLevel) {
- hResult = mPlugin->openSession(
- [&](Status status,const hidl_vec<uint8_t>& id) {
- if (status == Status::OK) {
- sessionId = toVector(id);
- }
- err = toStatusT(status);
- }
- );
- } else {
- hResult = mPluginV1_1->openSession_1_1(hSecurityLevel,
- [&](Status status, const hidl_vec<uint8_t>& id) {
- if (status == Status::OK) {
- sessionId = toVector(id);
- }
- err = toStatusT(status);
- }
- );
- }
-
- if (!hResult.isOk()) {
- err = DEAD_OBJECT;
- }
-
- if (err == ERROR_DRM_RESOURCE_BUSY && retry) {
- mLock.unlock();
- // reclaimSession may call back to closeSession, since mLock is
- // shared between Drm instances, we should unlock here to avoid
- // deadlock.
- retry = DrmSessionManager::Instance()->reclaimSession(AIBinder_getCallingPid());
- mLock.lock();
- } else {
- retry = false;
- }
- } while (retry);
-
- if (err == OK) {
- std::shared_ptr<DrmSessionClient> client =
- ndk::SharedRefBase::make<DrmSessionClient>(this, sessionId);
- DrmSessionManager::Instance()->addSession(AIBinder_getCallingPid(),
- std::static_pointer_cast<IResourceManagerClient>(client), sessionId);
- mOpenSessions.push_back(client);
- mMetrics.SetSessionStart(sessionId);
- }
-
- mMetrics.mOpenSessionCounter.Increment(err);
- return err;
+status_t DrmHal::openSession(DrmPlugin::SecurityLevel securityLevel, Vector<uint8_t>& sessionId) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->openSession(securityLevel, sessionId);
+ return mDrmHalHidl->openSession(securityLevel, sessionId);
}
-status_t DrmHal::closeSession(Vector<uint8_t> const &sessionId) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- Return<Status> status = mPlugin->closeSession(toHidlVec(sessionId));
- if (status.isOk()) {
- if (status == Status::OK) {
- DrmSessionManager::Instance()->removeSession(sessionId);
- for (auto i = mOpenSessions.begin(); i != mOpenSessions.end(); i++) {
- if (isEqualSessionId((*i)->mSessionId, sessionId)) {
- mOpenSessions.erase(i);
- break;
- }
- }
- }
- status_t response = toStatusT(status);
- mMetrics.SetSessionEnd(sessionId);
- mMetrics.mCloseSessionCounter.Increment(response);
- return response;
- }
- mMetrics.mCloseSessionCounter.Increment(DEAD_OBJECT);
- return DEAD_OBJECT;
+status_t DrmHal::closeSession(Vector<uint8_t> const& sessionId) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->closeSession(sessionId);
+ return mDrmHalHidl->closeSession(sessionId);
}
-static DrmPlugin::KeyRequestType toKeyRequestType(
- KeyRequestType keyRequestType) {
- switch (keyRequestType) {
- case KeyRequestType::INITIAL:
- return DrmPlugin::kKeyRequestType_Initial;
- break;
- case KeyRequestType::RENEWAL:
- return DrmPlugin::kKeyRequestType_Renewal;
- break;
- case KeyRequestType::RELEASE:
- return DrmPlugin::kKeyRequestType_Release;
- break;
- default:
- return DrmPlugin::kKeyRequestType_Unknown;
- break;
- }
+status_t DrmHal::getKeyRequest(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& initData,
+ String8 const& mimeType, DrmPlugin::KeyType keyType,
+ KeyedVector<String8, String8> const& optionalParameters,
+ Vector<uint8_t>& request, String8& defaultUrl,
+ DrmPlugin::KeyRequestType* keyRequestType) {
+ if (mDrmHalAidl->initCheck() == OK)
+ return mDrmHalAidl->getKeyRequest(sessionId, initData, mimeType, keyType,
+ optionalParameters, request, defaultUrl, keyRequestType);
+ return mDrmHalHidl->getKeyRequest(sessionId, initData, mimeType, keyType, optionalParameters,
+ request, defaultUrl, keyRequestType);
}
-static DrmPlugin::KeyRequestType toKeyRequestType_1_1(
- KeyRequestType_V1_1 keyRequestType) {
- switch (keyRequestType) {
- case KeyRequestType_V1_1::NONE:
- return DrmPlugin::kKeyRequestType_None;
- break;
- case KeyRequestType_V1_1::UPDATE:
- return DrmPlugin::kKeyRequestType_Update;
- break;
- default:
- return toKeyRequestType(static_cast<KeyRequestType>(keyRequestType));
- break;
- }
+status_t DrmHal::provideKeyResponse(Vector<uint8_t> const& sessionId,
+ Vector<uint8_t> const& response, Vector<uint8_t>& keySetId) {
+ if (mDrmHalAidl->initCheck() == OK)
+ return mDrmHalAidl->provideKeyResponse(sessionId, response, keySetId);
+ return mDrmHalHidl->provideKeyResponse(sessionId, response, keySetId);
}
-status_t DrmHal::getKeyRequest(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &initData, String8 const &mimeType,
- DrmPlugin::KeyType keyType, KeyedVector<String8,
- String8> const &optionalParameters, Vector<uint8_t> &request,
- String8 &defaultUrl, DrmPlugin::KeyRequestType *keyRequestType) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
- EventTimer<status_t> keyRequestTimer(&mMetrics.mGetKeyRequestTimeUs);
-
- DrmSessionManager::Instance()->useSession(sessionId);
-
- KeyType hKeyType;
- if (keyType == DrmPlugin::kKeyType_Streaming) {
- hKeyType = KeyType::STREAMING;
- } else if (keyType == DrmPlugin::kKeyType_Offline) {
- hKeyType = KeyType::OFFLINE;
- } else if (keyType == DrmPlugin::kKeyType_Release) {
- hKeyType = KeyType::RELEASE;
- } else {
- keyRequestTimer.SetAttribute(BAD_VALUE);
- return BAD_VALUE;
- }
-
- ::KeyedVector hOptionalParameters = toHidlKeyedVector(optionalParameters);
-
- status_t err = UNKNOWN_ERROR;
- Return<void> hResult;
-
- if (mPluginV1_2 != NULL) {
- hResult = mPluginV1_2->getKeyRequest_1_2(
- toHidlVec(sessionId), toHidlVec(initData),
- toHidlString(mimeType), hKeyType, hOptionalParameters,
- [&](Status_V1_2 status, const hidl_vec<uint8_t>& hRequest,
- KeyRequestType_V1_1 hKeyRequestType,
- const hidl_string& hDefaultUrl) {
- if (status == Status_V1_2::OK) {
- request = toVector(hRequest);
- defaultUrl = toString8(hDefaultUrl);
- *keyRequestType = toKeyRequestType_1_1(hKeyRequestType);
- }
- err = toStatusT(status);
- });
- } else if (mPluginV1_1 != NULL) {
- hResult = mPluginV1_1->getKeyRequest_1_1(
- toHidlVec(sessionId), toHidlVec(initData),
- toHidlString(mimeType), hKeyType, hOptionalParameters,
- [&](Status status, const hidl_vec<uint8_t>& hRequest,
- KeyRequestType_V1_1 hKeyRequestType,
- const hidl_string& hDefaultUrl) {
- if (status == Status::OK) {
- request = toVector(hRequest);
- defaultUrl = toString8(hDefaultUrl);
- *keyRequestType = toKeyRequestType_1_1(hKeyRequestType);
- }
- err = toStatusT(status);
- });
- } else {
- hResult = mPlugin->getKeyRequest(
- toHidlVec(sessionId), toHidlVec(initData),
- toHidlString(mimeType), hKeyType, hOptionalParameters,
- [&](Status status, const hidl_vec<uint8_t>& hRequest,
- KeyRequestType hKeyRequestType,
- const hidl_string& hDefaultUrl) {
- if (status == Status::OK) {
- request = toVector(hRequest);
- defaultUrl = toString8(hDefaultUrl);
- *keyRequestType = toKeyRequestType(hKeyRequestType);
- }
- err = toStatusT(status);
- });
- }
-
- err = hResult.isOk() ? err : DEAD_OBJECT;
- keyRequestTimer.SetAttribute(err);
- return err;
+status_t DrmHal::removeKeys(Vector<uint8_t> const& keySetId) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->removeKeys(keySetId);
+ return mDrmHalHidl->removeKeys(keySetId);
}
-status_t DrmHal::provideKeyResponse(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &response, Vector<uint8_t> &keySetId) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
- EventTimer<status_t> keyResponseTimer(&mMetrics.mProvideKeyResponseTimeUs);
-
- DrmSessionManager::Instance()->useSession(sessionId);
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPlugin->provideKeyResponse(toHidlVec(sessionId),
- toHidlVec(response),
- [&](Status status, const hidl_vec<uint8_t>& hKeySetId) {
- if (status == Status::OK) {
- keySetId = toVector(hKeySetId);
- }
- err = toStatusT(status);
- }
- );
- err = hResult.isOk() ? err : DEAD_OBJECT;
- keyResponseTimer.SetAttribute(err);
- return err;
+status_t DrmHal::restoreKeys(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keySetId) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->restoreKeys(sessionId, keySetId);
+ return mDrmHalHidl->restoreKeys(sessionId, keySetId);
}
-status_t DrmHal::removeKeys(Vector<uint8_t> const &keySetId) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- Return<Status> status = mPlugin->removeKeys(toHidlVec(keySetId));
- return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+status_t DrmHal::queryKeyStatus(Vector<uint8_t> const& sessionId,
+ KeyedVector<String8, String8>& infoMap) const {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->queryKeyStatus(sessionId, infoMap);
+ return mDrmHalHidl->queryKeyStatus(sessionId, infoMap);
}
-status_t DrmHal::restoreKeys(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keySetId) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- DrmSessionManager::Instance()->useSession(sessionId);
-
- Return<Status> status = mPlugin->restoreKeys(toHidlVec(sessionId),
- toHidlVec(keySetId));
- return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+status_t DrmHal::getProvisionRequest(String8 const& certType, String8 const& certAuthority,
+ Vector<uint8_t>& request, String8& defaultUrl) {
+ if (mDrmHalAidl->initCheck() == OK)
+ return mDrmHalAidl->getProvisionRequest(certType, certAuthority, request, defaultUrl);
+ return mDrmHalHidl->getProvisionRequest(certType, certAuthority, request, defaultUrl);
}
-status_t DrmHal::queryKeyStatus(Vector<uint8_t> const &sessionId,
- KeyedVector<String8, String8> &infoMap) const {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- DrmSessionManager::Instance()->useSession(sessionId);
-
- ::KeyedVector hInfoMap;
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPlugin->queryKeyStatus(toHidlVec(sessionId),
- [&](Status status, const hidl_vec<KeyValue>& map) {
- if (status == Status::OK) {
- infoMap = toKeyedVector(map);
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::provideProvisionResponse(Vector<uint8_t> const& response,
+ Vector<uint8_t>& certificate,
+ Vector<uint8_t>& wrappedKey) {
+ if (mDrmHalAidl->initCheck() == OK)
+ return mDrmHalAidl->provideProvisionResponse(response, certificate, wrappedKey);
+ return mDrmHalHidl->provideProvisionResponse(response, certificate, wrappedKey);
}
-status_t DrmHal::getProvisionRequest(String8 const &certType,
- String8 const &certAuthority, Vector<uint8_t> &request,
- String8 &defaultUrl) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- status_t err = UNKNOWN_ERROR;
- Return<void> hResult;
-
- if (mPluginV1_2 != NULL) {
- hResult = mPluginV1_2->getProvisionRequest_1_2(
- toHidlString(certType), toHidlString(certAuthority),
- [&](Status_V1_2 status, const hidl_vec<uint8_t>& hRequest,
- const hidl_string& hDefaultUrl) {
- if (status == Status_V1_2::OK) {
- request = toVector(hRequest);
- defaultUrl = toString8(hDefaultUrl);
- }
- err = toStatusT(status);
- }
- );
- } else {
- hResult = mPlugin->getProvisionRequest(
- toHidlString(certType), toHidlString(certAuthority),
- [&](Status status, const hidl_vec<uint8_t>& hRequest,
- const hidl_string& hDefaultUrl) {
- if (status == Status::OK) {
- request = toVector(hRequest);
- defaultUrl = toString8(hDefaultUrl);
- }
- err = toStatusT(status);
- }
- );
- }
-
- err = hResult.isOk() ? err : DEAD_OBJECT;
- mMetrics.mGetProvisionRequestCounter.Increment(err);
- return err;
+status_t DrmHal::getSecureStops(List<Vector<uint8_t>>& secureStops) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->getSecureStops(secureStops);
+ return mDrmHalHidl->getSecureStops(secureStops);
}
-status_t DrmHal::provideProvisionResponse(Vector<uint8_t> const &response,
- Vector<uint8_t> &certificate, Vector<uint8_t> &wrappedKey) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPlugin->provideProvisionResponse(toHidlVec(response),
- [&](Status status, const hidl_vec<uint8_t>& hCertificate,
- const hidl_vec<uint8_t>& hWrappedKey) {
- if (status == Status::OK) {
- certificate = toVector(hCertificate);
- wrappedKey = toVector(hWrappedKey);
- }
- err = toStatusT(status);
- }
- );
-
- err = hResult.isOk() ? err : DEAD_OBJECT;
- mMetrics.mProvideProvisionResponseCounter.Increment(err);
- return err;
+status_t DrmHal::getSecureStopIds(List<Vector<uint8_t>>& secureStopIds) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->getSecureStopIds(secureStopIds);
+ return mDrmHalHidl->getSecureStopIds(secureStopIds);
}
-status_t DrmHal::getSecureStops(List<Vector<uint8_t>> &secureStops) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPlugin->getSecureStops(
- [&](Status status, const hidl_vec<SecureStop>& hSecureStops) {
- if (status == Status::OK) {
- secureStops = toSecureStops(hSecureStops);
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::getSecureStop(Vector<uint8_t> const& ssid, Vector<uint8_t>& secureStop) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->getSecureStop(ssid, secureStop);
+ return mDrmHalHidl->getSecureStop(ssid, secureStop);
}
-
-status_t DrmHal::getSecureStopIds(List<Vector<uint8_t>> &secureStopIds) {
- Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
- if (mPluginV1_1 == NULL) {
- return ERROR_DRM_CANNOT_HANDLE;
- }
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPluginV1_1->getSecureStopIds(
- [&](Status status, const hidl_vec<SecureStopId>& hSecureStopIds) {
- if (status == Status::OK) {
- secureStopIds = toSecureStopIds(hSecureStopIds);
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::releaseSecureStops(Vector<uint8_t> const& ssRelease) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->releaseSecureStops(ssRelease);
+ return mDrmHalHidl->releaseSecureStops(ssRelease);
}
-
-status_t DrmHal::getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPlugin->getSecureStop(toHidlVec(ssid),
- [&](Status status, const SecureStop& hSecureStop) {
- if (status == Status::OK) {
- secureStop = toVector(hSecureStop.opaqueData);
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
-}
-
-status_t DrmHal::releaseSecureStops(Vector<uint8_t> const &ssRelease) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- Return<Status> status(Status::ERROR_DRM_UNKNOWN);
- if (mPluginV1_1 != NULL) {
- SecureStopRelease secureStopRelease;
- secureStopRelease.opaqueData = toHidlVec(ssRelease);
- status = mPluginV1_1->releaseSecureStops(secureStopRelease);
- } else {
- status = mPlugin->releaseSecureStop(toHidlVec(ssRelease));
- }
- return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
-}
-
-status_t DrmHal::removeSecureStop(Vector<uint8_t> const &ssid) {
- Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
- if (mPluginV1_1 == NULL) {
- return ERROR_DRM_CANNOT_HANDLE;
- }
-
- Return<Status> status = mPluginV1_1->removeSecureStop(toHidlVec(ssid));
- return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+status_t DrmHal::removeSecureStop(Vector<uint8_t> const& ssid) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->removeSecureStop(ssid);
+ return mDrmHalHidl->removeSecureStop(ssid);
}
status_t DrmHal::removeAllSecureStops() {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- Return<Status> status(Status::ERROR_DRM_UNKNOWN);
- if (mPluginV1_1 != NULL) {
- status = mPluginV1_1->removeAllSecureStops();
- } else {
- status = mPlugin->releaseAllSecureStops();
- }
- return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->removeAllSecureStops();
+ return mDrmHalHidl->removeAllSecureStops();
}
-status_t DrmHal::getHdcpLevels(DrmPlugin::HdcpLevel *connected,
- DrmPlugin::HdcpLevel *max) const {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- if (connected == NULL || max == NULL) {
- return BAD_VALUE;
- }
- status_t err = UNKNOWN_ERROR;
-
- *connected = DrmPlugin::kHdcpLevelUnknown;
- *max = DrmPlugin::kHdcpLevelUnknown;
-
- Return<void> hResult;
- if (mPluginV1_2 != NULL) {
- hResult = mPluginV1_2->getHdcpLevels_1_2(
- [&](Status_V1_2 status, const HdcpLevel_V1_2& hConnected, const HdcpLevel_V1_2& hMax) {
- if (status == Status_V1_2::OK) {
- *connected = toHdcpLevel(hConnected);
- *max = toHdcpLevel(hMax);
- }
- err = toStatusT(status);
- });
- } else if (mPluginV1_1 != NULL) {
- hResult = mPluginV1_1->getHdcpLevels(
- [&](Status status, const HdcpLevel& hConnected, const HdcpLevel& hMax) {
- if (status == Status::OK) {
- *connected = toHdcpLevel(static_cast<HdcpLevel_V1_2>(hConnected));
- *max = toHdcpLevel(static_cast<HdcpLevel_V1_2>(hMax));
- }
- err = toStatusT(status);
- });
- } else {
- return ERROR_DRM_CANNOT_HANDLE;
- }
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::getHdcpLevels(DrmPlugin::HdcpLevel* connectedLevel,
+ DrmPlugin::HdcpLevel* maxLevel) const {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->getHdcpLevels(connectedLevel, maxLevel);
+ return mDrmHalHidl->getHdcpLevels(connectedLevel, maxLevel);
}
-status_t DrmHal::getNumberOfSessions(uint32_t *open, uint32_t *max) const {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- if (open == NULL || max == NULL) {
- return BAD_VALUE;
- }
- status_t err = UNKNOWN_ERROR;
-
- *open = 0;
- *max = 0;
-
- if (mPluginV1_1 == NULL) {
- return ERROR_DRM_CANNOT_HANDLE;
- }
-
- Return<void> hResult = mPluginV1_1->getNumberOfSessions(
- [&](Status status, uint32_t hOpen, uint32_t hMax) {
- if (status == Status::OK) {
- *open = hOpen;
- *max = hMax;
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::getNumberOfSessions(uint32_t* currentSessions, uint32_t* maxSessions) const {
+ if (mDrmHalAidl->initCheck() == OK)
+ return mDrmHalAidl->getNumberOfSessions(currentSessions, maxSessions);
+ return mDrmHalHidl->getNumberOfSessions(currentSessions, maxSessions);
}
-status_t DrmHal::getSecurityLevel(Vector<uint8_t> const &sessionId,
- DrmPlugin::SecurityLevel *level) const {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- if (level == NULL) {
- return BAD_VALUE;
- }
- status_t err = UNKNOWN_ERROR;
-
- if (mPluginV1_1 == NULL) {
- return ERROR_DRM_CANNOT_HANDLE;
- }
-
- *level = DrmPlugin::kSecurityLevelUnknown;
-
- Return<void> hResult = mPluginV1_1->getSecurityLevel(toHidlVec(sessionId),
- [&](Status status, SecurityLevel hLevel) {
- if (status == Status::OK) {
- *level = toSecurityLevel(hLevel);
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::getSecurityLevel(Vector<uint8_t> const& sessionId,
+ DrmPlugin::SecurityLevel* level) const {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->getSecurityLevel(sessionId, level);
+ return mDrmHalHidl->getSecurityLevel(sessionId, level);
}
-status_t DrmHal::getOfflineLicenseKeySetIds(List<Vector<uint8_t>> &keySetIds) const {
- Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
- if (mPluginV1_2 == NULL) {
- return ERROR_UNSUPPORTED;
- }
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPluginV1_2->getOfflineLicenseKeySetIds(
- [&](Status status, const hidl_vec<KeySetId>& hKeySetIds) {
- if (status == Status::OK) {
- keySetIds = toKeySetIds(hKeySetIds);
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::getOfflineLicenseKeySetIds(List<Vector<uint8_t>>& keySetIds) const {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->getOfflineLicenseKeySetIds(keySetIds);
+ return mDrmHalHidl->getOfflineLicenseKeySetIds(keySetIds);
}
-status_t DrmHal::removeOfflineLicense(Vector<uint8_t> const &keySetId) {
- Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
- if (mPluginV1_2 == NULL) {
- return ERROR_UNSUPPORTED;
- }
-
- Return<Status> status = mPluginV1_2->removeOfflineLicense(toHidlVec(keySetId));
- return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+status_t DrmHal::removeOfflineLicense(Vector<uint8_t> const& keySetId) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->removeOfflineLicense(keySetId);
+ return mDrmHalHidl->removeOfflineLicense(keySetId);
}
-status_t DrmHal::getOfflineLicenseState(Vector<uint8_t> const &keySetId,
- DrmPlugin::OfflineLicenseState *licenseState) const {
- Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
- if (mPluginV1_2 == NULL) {
- return ERROR_UNSUPPORTED;
- }
- *licenseState = DrmPlugin::kOfflineLicenseStateUnknown;
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPluginV1_2->getOfflineLicenseState(toHidlVec(keySetId),
- [&](Status status, OfflineLicenseState hLicenseState) {
- if (status == Status::OK) {
- *licenseState = toOfflineLicenseState(hLicenseState);
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::getOfflineLicenseState(Vector<uint8_t> const& keySetId,
+ DrmPlugin::OfflineLicenseState* licenseState) const {
+ if (mDrmHalAidl->initCheck() == OK)
+ return mDrmHalAidl->getOfflineLicenseState(keySetId, licenseState);
+ return mDrmHalHidl->getOfflineLicenseState(keySetId, licenseState);
}
-status_t DrmHal::getPropertyString(String8 const &name, String8 &value ) const {
- Mutex::Autolock autoLock(mLock);
- return getPropertyStringInternal(name, value);
+status_t DrmHal::getPropertyString(String8 const& name, String8& value) const {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->getPropertyString(name, value);
+ return mDrmHalHidl->getPropertyString(name, value);
}
-status_t DrmHal::getPropertyStringInternal(String8 const &name, String8 &value) const {
- // This function is internal to the class and should only be called while
- // mLock is already held.
- INIT_CHECK();
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPlugin->getPropertyString(toHidlString(name),
- [&](Status status, const hidl_string& hValue) {
- if (status == Status::OK) {
- value = toString8(hValue);
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::getPropertyByteArray(String8 const& name, Vector<uint8_t>& value) const {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->getPropertyByteArray(name, value);
+ return mDrmHalHidl->getPropertyByteArray(name, value);
}
-status_t DrmHal::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const {
- Mutex::Autolock autoLock(mLock);
- return getPropertyByteArrayInternal(name, value);
+status_t DrmHal::setPropertyString(String8 const& name, String8 const& value) const {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->setPropertyString(name, value);
+ return mDrmHalHidl->setPropertyString(name, value);
}
-status_t DrmHal::getPropertyByteArrayInternal(String8 const &name, Vector<uint8_t> &value ) const {
- // This function is internal to the class and should only be called while
- // mLock is already held.
- INIT_CHECK();
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPlugin->getPropertyByteArray(toHidlString(name),
- [&](Status status, const hidl_vec<uint8_t>& hValue) {
- if (status == Status::OK) {
- value = toVector(hValue);
- }
- err = toStatusT(status);
- }
- );
-
- err = hResult.isOk() ? err : DEAD_OBJECT;
- if (name == kPropertyDeviceUniqueId) {
- mMetrics.mGetDeviceUniqueIdCounter.Increment(err);
- }
- return err;
+status_t DrmHal::setPropertyByteArray(String8 const& name, Vector<uint8_t> const& value) const {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->setPropertyByteArray(name, value);
+ return mDrmHalHidl->setPropertyByteArray(name, value);
}
-status_t DrmHal::setPropertyString(String8 const &name, String8 const &value ) const {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- Return<Status> status = mPlugin->setPropertyString(toHidlString(name),
- toHidlString(value));
- return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+status_t DrmHal::getMetrics(const sp<IDrmMetricsConsumer>& consumer) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->getMetrics(consumer);
+ return mDrmHalHidl->getMetrics(consumer);
}
-status_t DrmHal::setPropertyByteArray(String8 const &name,
- Vector<uint8_t> const &value ) const {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- Return<Status> status = mPlugin->setPropertyByteArray(toHidlString(name),
- toHidlVec(value));
- return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+status_t DrmHal::setCipherAlgorithm(Vector<uint8_t> const& sessionId, String8 const& algorithm) {
+ if (mDrmHalAidl->initCheck() == OK)
+ return mDrmHalAidl->setCipherAlgorithm(sessionId, algorithm);
+ return mDrmHalHidl->setCipherAlgorithm(sessionId, algorithm);
}
-status_t DrmHal::getMetrics(const sp<IDrmMetricsConsumer> &consumer) {
- if (consumer == nullptr) {
- return UNEXPECTED_NULL;
- }
- consumer->consumeFrameworkMetrics(mMetrics);
-
- // Append vendor metrics if they are supported.
- if (mPluginV1_1 != NULL) {
- String8 vendor;
- String8 description;
- if (getPropertyStringInternal(String8("vendor"), vendor) != OK
- || vendor.isEmpty()) {
- ALOGE("Get vendor failed or is empty");
- vendor = "NONE";
- }
- if (getPropertyStringInternal(String8("description"), description) != OK
- || description.isEmpty()) {
- ALOGE("Get description failed or is empty.");
- description = "NONE";
- }
- vendor += ".";
- vendor += description;
-
- hidl_vec<DrmMetricGroup> pluginMetrics;
- status_t err = UNKNOWN_ERROR;
-
- Return<void> status = mPluginV1_1->getMetrics(
- [&](Status status, hidl_vec<DrmMetricGroup> pluginMetrics) {
- if (status != Status::OK) {
- ALOGV("Error getting plugin metrics: %d", status);
- } else {
- consumer->consumeHidlMetrics(vendor, pluginMetrics);
- }
- err = toStatusT(status);
- });
- return status.isOk() ? err : DEAD_OBJECT;
- }
-
- return OK;
+status_t DrmHal::setMacAlgorithm(Vector<uint8_t> const& sessionId, String8 const& algorithm) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->setMacAlgorithm(sessionId, algorithm);
+ return mDrmHalHidl->setMacAlgorithm(sessionId, algorithm);
}
-status_t DrmHal::setCipherAlgorithm(Vector<uint8_t> const &sessionId,
- String8 const &algorithm) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- DrmSessionManager::Instance()->useSession(sessionId);
-
- Return<Status> status = mPlugin->setCipherAlgorithm(toHidlVec(sessionId),
- toHidlString(algorithm));
- return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+status_t DrmHal::encrypt(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& input, Vector<uint8_t> const& iv,
+ Vector<uint8_t>& output) {
+ if (mDrmHalAidl->initCheck() == OK)
+ return mDrmHalAidl->encrypt(sessionId, keyId, input, iv, output);
+ return mDrmHalHidl->encrypt(sessionId, keyId, input, iv, output);
}
-status_t DrmHal::setMacAlgorithm(Vector<uint8_t> const &sessionId,
- String8 const &algorithm) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- DrmSessionManager::Instance()->useSession(sessionId);
-
- Return<Status> status = mPlugin->setMacAlgorithm(toHidlVec(sessionId),
- toHidlString(algorithm));
- return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+status_t DrmHal::decrypt(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& input, Vector<uint8_t> const& iv,
+ Vector<uint8_t>& output) {
+ if (mDrmHalAidl->initCheck() == OK)
+ return mDrmHalAidl->decrypt(sessionId, keyId, input, iv, output);
+ return mDrmHalHidl->decrypt(sessionId, keyId, input, iv, output);
}
-status_t DrmHal::encrypt(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId, Vector<uint8_t> const &input,
- Vector<uint8_t> const &iv, Vector<uint8_t> &output) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- DrmSessionManager::Instance()->useSession(sessionId);
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPlugin->encrypt(toHidlVec(sessionId),
- toHidlVec(keyId), toHidlVec(input), toHidlVec(iv),
- [&](Status status, const hidl_vec<uint8_t>& hOutput) {
- if (status == Status::OK) {
- output = toVector(hOutput);
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::sign(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& message, Vector<uint8_t>& signature) {
+ if (mDrmHalAidl->initCheck() == OK)
+ return mDrmHalAidl->sign(sessionId, keyId, message, signature);
+ return mDrmHalHidl->sign(sessionId, keyId, message, signature);
}
-status_t DrmHal::decrypt(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId, Vector<uint8_t> const &input,
- Vector<uint8_t> const &iv, Vector<uint8_t> &output) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- DrmSessionManager::Instance()->useSession(sessionId);
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPlugin->decrypt(toHidlVec(sessionId),
- toHidlVec(keyId), toHidlVec(input), toHidlVec(iv),
- [&](Status status, const hidl_vec<uint8_t>& hOutput) {
- if (status == Status::OK) {
- output = toVector(hOutput);
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::verify(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& message, Vector<uint8_t> const& signature,
+ bool& match) {
+ if (mDrmHalAidl->initCheck() == OK)
+ return mDrmHalAidl->verify(sessionId, keyId, message, signature, match);
+ return mDrmHalHidl->verify(sessionId, keyId, message, signature, match);
}
-status_t DrmHal::sign(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId, Vector<uint8_t> const &message,
- Vector<uint8_t> &signature) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- DrmSessionManager::Instance()->useSession(sessionId);
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPlugin->sign(toHidlVec(sessionId),
- toHidlVec(keyId), toHidlVec(message),
- [&](Status status, const hidl_vec<uint8_t>& hSignature) {
- if (status == Status::OK) {
- signature = toVector(hSignature);
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::signRSA(Vector<uint8_t> const& sessionId, String8 const& algorithm,
+ Vector<uint8_t> const& message, Vector<uint8_t> const& wrappedKey,
+ Vector<uint8_t>& signature) {
+ if (mDrmHalAidl->initCheck() == OK)
+ return mDrmHalAidl->signRSA(sessionId, algorithm, message, wrappedKey, signature);
+ return mDrmHalHidl->signRSA(sessionId, algorithm, message, wrappedKey, signature);
}
-status_t DrmHal::verify(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId, Vector<uint8_t> const &message,
- Vector<uint8_t> const &signature, bool &match) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- DrmSessionManager::Instance()->useSession(sessionId);
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPlugin->verify(toHidlVec(sessionId),toHidlVec(keyId),
- toHidlVec(message), toHidlVec(signature),
- [&](Status status, bool hMatch) {
- if (status == Status::OK) {
- match = hMatch;
- } else {
- match = false;
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::setListener(const sp<IDrmClient>& listener) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->setListener(listener);
+ return mDrmHalHidl->setListener(listener);
}
-status_t DrmHal::signRSA(Vector<uint8_t> const &sessionId,
- String8 const &algorithm, Vector<uint8_t> const &message,
- Vector<uint8_t> const &wrappedKey, Vector<uint8_t> &signature) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- DrmSessionManager::Instance()->useSession(sessionId);
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPlugin->signRSA(toHidlVec(sessionId),
- toHidlString(algorithm), toHidlVec(message), toHidlVec(wrappedKey),
- [&](Status status, const hidl_vec<uint8_t>& hSignature) {
- if (status == Status::OK) {
- signature = toVector(hSignature);
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::requiresSecureDecoder(const char* mime, bool* required) const {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->requiresSecureDecoder(mime, required);
+ return mDrmHalHidl->requiresSecureDecoder(mime, required);
}
-std::string DrmHal::reportFrameworkMetrics(const std::string& pluginMetrics) const
-{
- mediametrics_handle_t item(mediametrics_create("mediadrm"));
- mediametrics_setUid(item, mMetrics.GetAppUid());
- String8 vendor;
- String8 description;
- status_t result = getPropertyStringInternal(String8("vendor"), vendor);
- if (result != OK) {
- ALOGE("Failed to get vendor from drm plugin: %d", result);
- } else {
- mediametrics_setCString(item, "vendor", vendor.c_str());
- }
- result = getPropertyStringInternal(String8("description"), description);
- if (result != OK) {
- ALOGE("Failed to get description from drm plugin: %d", result);
- } else {
- mediametrics_setCString(item, "description", description.c_str());
- }
-
- std::string serializedMetrics;
- result = mMetrics.GetSerializedMetrics(&serializedMetrics);
- if (result != OK) {
- ALOGE("Failed to serialize framework metrics: %d", result);
- }
- std::string b64EncodedMetrics = toBase64StringNoPad(serializedMetrics.data(),
- serializedMetrics.size());
- if (!b64EncodedMetrics.empty()) {
- mediametrics_setCString(item, "serialized_metrics", b64EncodedMetrics.c_str());
- }
- if (!pluginMetrics.empty()) {
- mediametrics_setCString(item, "plugin_metrics", pluginMetrics.c_str());
- }
- if (!mediametrics_selfRecord(item)) {
- ALOGE("Failed to self record framework metrics");
- }
- mediametrics_delete(item);
- return serializedMetrics;
+status_t DrmHal::requiresSecureDecoder(const char* mime, DrmPlugin::SecurityLevel securityLevel,
+ bool* required) const {
+ if (mDrmHalAidl->initCheck() == OK)
+ return mDrmHalAidl->requiresSecureDecoder(mime, securityLevel, required);
+ return mDrmHalHidl->requiresSecureDecoder(mime, securityLevel, required);
}
-std::string DrmHal::reportPluginMetrics() const
-{
- Vector<uint8_t> metricsVector;
- String8 vendor;
- String8 description;
- std::string metricsString;
- if (getPropertyStringInternal(String8("vendor"), vendor) == OK &&
- getPropertyStringInternal(String8("description"), description) == OK &&
- getPropertyByteArrayInternal(String8("metrics"), metricsVector) == OK) {
- metricsString = toBase64StringNoPad(metricsVector.array(),
- metricsVector.size());
- status_t res = android::reportDrmPluginMetrics(metricsString, vendor,
- description, mMetrics.GetAppUid());
- if (res != OK) {
- ALOGE("Metrics were retrieved but could not be reported: %d", res);
- }
- }
- return metricsString;
+status_t DrmHal::setPlaybackId(Vector<uint8_t> const& sessionId, const char* playbackId) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->setPlaybackId(sessionId, playbackId);
+ return mDrmHalHidl->setPlaybackId(sessionId, playbackId);
}
-status_t DrmHal::requiresSecureDecoder(const char *mime, bool *required) const {
- Mutex::Autolock autoLock(mLock);
- if (mPluginV1_4 == NULL) {
- return false;
- }
- auto hResult = mPluginV1_4->requiresSecureDecoderDefault(hidl_string(mime));
- if (!hResult.isOk()) {
- DrmUtils::LOG2BE("requiresSecureDecoder txn failed: %s", hResult.description().c_str());
- return DEAD_OBJECT;
- }
- if (required) {
- *required = hResult;
- }
- return OK;
-}
-
-status_t DrmHal::requiresSecureDecoder(const char *mime, DrmPlugin::SecurityLevel securityLevel,
- bool *required) const {
- Mutex::Autolock autoLock(mLock);
- if (mPluginV1_4 == NULL) {
- return false;
- }
- auto hLevel = toHidlSecurityLevel(securityLevel);
- auto hResult = mPluginV1_4->requiresSecureDecoder(hidl_string(mime), hLevel);
- if (!hResult.isOk()) {
- DrmUtils::LOG2BE("requiresSecureDecoder txn failed: %s", hResult.description().c_str());
- return DEAD_OBJECT;
- }
- if (required) {
- *required = hResult;
- }
- return OK;
-}
-
-status_t DrmHal::setPlaybackId(Vector<uint8_t> const &sessionId, const char *playbackId) {
- Mutex::Autolock autoLock(mLock);
- if (mPluginV1_4 == NULL) {
- return ERROR_UNSUPPORTED;
- }
- auto err = mPluginV1_4->setPlaybackId(toHidlVec(sessionId), hidl_string(playbackId));
- return err.isOk() ? toStatusT(err) : DEAD_OBJECT;
-}
-
-status_t DrmHal::getLogMessages(Vector<drm::V1_4::LogMessage> &logs) const {
- Mutex::Autolock autoLock(mLock);
- return DrmUtils::GetLogMessages<drm::V1_4::IDrmPlugin>(mPlugin, logs);
+status_t DrmHal::getLogMessages(Vector<drm::V1_4::LogMessage>& logs) const {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->getLogMessages(logs);
+ return mDrmHalHidl->getLogMessages(logs);
}
} // namespace android
diff --git a/drm/libmediadrm/DrmHalAidl.cpp b/drm/libmediadrm/DrmHalAidl.cpp
new file mode 100644
index 0000000..dc6d23e
--- /dev/null
+++ b/drm/libmediadrm/DrmHalAidl.cpp
@@ -0,0 +1,1219 @@
+/*
+ * Copyright (C) 2021 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 "DrmHalAidl"
+
+#include <array>
+#include <algorithm>
+#include <android/binder_auto_utils.h>
+#include <android/binder_manager.h>
+#include <media/PluginMetricsReporting.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/base64.h>
+#include <media/stagefright/foundation/hexdump.h>
+#include <mediadrm/DrmHalAidl.h>
+#include <mediadrm/DrmSessionManager.h>
+#include <mediadrm/DrmUtils.h>
+
+using ::android::DrmUtils::statusAidlToStatusT;
+using ::aidl::android::hardware::drm::CryptoSchemes;
+using ::aidl::android::hardware::drm::DrmMetricNamedValue;
+using ::aidl::android::hardware::drm::DrmMetricValue;
+using ::aidl::android::hardware::drm::HdcpLevel;
+using ::aidl::android::hardware::drm::HdcpLevels;
+using ::aidl::android::hardware::drm::KeyRequest;
+using ::aidl::android::hardware::drm::KeyRequestType;
+using ::aidl::android::hardware::drm::KeySetId;
+using ::aidl::android::hardware::drm::KeyStatus;
+using ::aidl::android::hardware::drm::KeyStatusType;
+using ::aidl::android::hardware::drm::KeyType;
+using ::aidl::android::hardware::drm::KeyValue;
+using ::aidl::android::hardware::drm::NumberOfSessions;
+using ::aidl::android::hardware::drm::OfflineLicenseState;
+using ::aidl::android::hardware::drm::OpaqueData;
+using ::aidl::android::hardware::drm::ProvideProvisionResponseResult;
+using ::aidl::android::hardware::drm::ProvisionRequest;
+using ::aidl::android::hardware::drm::SecureStop;
+using ::aidl::android::hardware::drm::SecureStopId;
+using ::aidl::android::hardware::drm::SecurityLevel;
+using ::aidl::android::hardware::drm::Status;
+using ::aidl::android::hardware::drm::Uuid;
+using DrmMetricGroupAidl = ::aidl::android::hardware::drm::DrmMetricGroup;
+using DrmMetricGroupHidl = ::android::hardware::drm::V1_1::DrmMetricGroup;
+using DrmMetricAidl = ::aidl::android::hardware::drm::DrmMetric;
+using DrmMetricHidl = ::android::hardware::drm::V1_1::DrmMetricGroup::Metric;
+using ValueHidl = ::android::hardware::drm::V1_1::DrmMetricGroup::Value;
+using AttributeHidl = ::android::hardware::drm::V1_1::DrmMetricGroup::Attribute;
+using IDrmPluginAidl = ::aidl::android::hardware::drm::IDrmPlugin;
+using EventTypeAidl = ::aidl::android::hardware::drm::EventType;
+using ::android::hardware::hidl_vec;
+
+namespace {
+
+constexpr char kPropertyDeviceUniqueId[] = "deviceUniqueId";
+constexpr char kEqualsSign[] = "=";
+
+template <typename T>
+std::string toBase64StringNoPad(const T* data, size_t size) {
+ // Note that the base 64 conversion only works with arrays of single-byte
+ // values. If the source is empty or is not an array of single-byte values,
+ // return empty string.
+ if (size == 0 || sizeof(data[0]) != 1) {
+ return "";
+ }
+
+ android::AString outputString;
+ encodeBase64(data, size, &outputString);
+ // Remove trailing equals padding if it exists.
+ while (outputString.size() > 0 && outputString.endsWith(kEqualsSign)) {
+ outputString.erase(outputString.size() - 1, 1);
+ }
+
+ return std::string(outputString.c_str(), outputString.size());
+}
+
+} // anonymous namespace
+
+namespace android {
+
+#define INIT_CHECK() \
+ { \
+ if (mInitCheck != OK) return mInitCheck; \
+ }
+
+template <typename Byte = uint8_t>
+static std::vector<Byte> toStdVec(const Vector<uint8_t>& vector) {
+ auto v = reinterpret_cast<const Byte*>(vector.array());
+ std::vector<Byte> vec(v, v + vector.size());
+ return vec;
+}
+
+static const Vector<uint8_t> toVector(const std::vector<uint8_t>& vec) {
+ Vector<uint8_t> vector;
+ vector.appendArray(vec.data(), vec.size());
+ return *const_cast<const Vector<uint8_t>*>(&vector);
+}
+
+static String8 toString8(const std::string& string) {
+ return String8(string.c_str());
+}
+
+static std::string toStdString(const String8& string8) {
+ return std::string(string8.string());
+}
+
+static std::vector<KeyValue> toKeyValueVector(const KeyedVector<String8, String8>& keyedVector) {
+ std::vector<KeyValue> stdKeyedVector;
+ for (size_t i = 0; i < keyedVector.size(); i++) {
+ KeyValue keyValue;
+ keyValue.key = toStdString(keyedVector.keyAt(i));
+ keyValue.value = toStdString(keyedVector.valueAt(i));
+ stdKeyedVector.push_back(keyValue);
+ }
+ return stdKeyedVector;
+}
+
+static KeyedVector<String8, String8> toKeyedVector(const std::vector<KeyValue>& keyValueVec) {
+ KeyedVector<String8, String8> keyedVector;
+ for (size_t i = 0; i < keyValueVec.size(); i++) {
+ keyedVector.add(toString8(keyValueVec[i].key), toString8(keyValueVec[i].value));
+ }
+ return keyedVector;
+}
+
+static DrmPlugin::KeyRequestType toKeyRequestType(KeyRequestType keyRequestType) {
+ switch (keyRequestType) {
+ case KeyRequestType::INITIAL:
+ return DrmPlugin::kKeyRequestType_Initial;
+ break;
+ case KeyRequestType::RENEWAL:
+ return DrmPlugin::kKeyRequestType_Renewal;
+ break;
+ case KeyRequestType::RELEASE:
+ return DrmPlugin::kKeyRequestType_Release;
+ break;
+ case KeyRequestType::NONE:
+ return DrmPlugin::kKeyRequestType_None;
+ break;
+ case KeyRequestType::UPDATE:
+ return DrmPlugin::kKeyRequestType_Update;
+ break;
+ default:
+ return DrmPlugin::kKeyRequestType_Unknown;
+ break;
+ }
+}
+
+static List<Vector<uint8_t>> toSecureStops(const std::vector<SecureStop>& aSecureStops) {
+ List<Vector<uint8_t>> secureStops;
+ for (size_t i = 0; i < aSecureStops.size(); i++) {
+ secureStops.push_back(toVector(aSecureStops[i].opaqueData));
+ }
+ return secureStops;
+}
+
+static List<Vector<uint8_t>> toSecureStopIds(const std::vector<SecureStopId>& aSecureStopIds) {
+ List<Vector<uint8_t>> secureStopIds;
+ for (size_t i = 0; i < aSecureStopIds.size(); i++) {
+ secureStopIds.push_back(toVector(aSecureStopIds[i].secureStopId));
+ }
+ return secureStopIds;
+}
+
+static DrmPlugin::HdcpLevel toHdcpLevel(HdcpLevel level) {
+ switch (level) {
+ case HdcpLevel::HDCP_NONE:
+ return DrmPlugin::kHdcpNone;
+ case HdcpLevel::HDCP_V1:
+ return DrmPlugin::kHdcpV1;
+ case HdcpLevel::HDCP_V2:
+ return DrmPlugin::kHdcpV2;
+ case HdcpLevel::HDCP_V2_1:
+ return DrmPlugin::kHdcpV2_1;
+ case HdcpLevel::HDCP_V2_2:
+ return DrmPlugin::kHdcpV2_2;
+ case HdcpLevel::HDCP_V2_3:
+ return DrmPlugin::kHdcpV2_3;
+ case HdcpLevel::HDCP_NO_OUTPUT:
+ return DrmPlugin::kHdcpNoOutput;
+ default:
+ return DrmPlugin::kHdcpLevelUnknown;
+ }
+}
+
+static DrmPlugin::SecurityLevel toSecurityLevel(SecurityLevel level) {
+ switch (level) {
+ case SecurityLevel::SW_SECURE_CRYPTO:
+ return DrmPlugin::kSecurityLevelSwSecureCrypto;
+ case SecurityLevel::SW_SECURE_DECODE:
+ return DrmPlugin::kSecurityLevelSwSecureDecode;
+ case SecurityLevel::HW_SECURE_CRYPTO:
+ return DrmPlugin::kSecurityLevelHwSecureCrypto;
+ case SecurityLevel::HW_SECURE_DECODE:
+ return DrmPlugin::kSecurityLevelHwSecureDecode;
+ case SecurityLevel::HW_SECURE_ALL:
+ return DrmPlugin::kSecurityLevelHwSecureAll;
+ case SecurityLevel::DEFAULT:
+ return DrmPlugin::kSecurityLevelMax;
+ default:
+ return DrmPlugin::kSecurityLevelUnknown;
+ }
+}
+
+static SecurityLevel toAidlSecurityLevel(DrmPlugin::SecurityLevel level) {
+ switch (level) {
+ case DrmPlugin::kSecurityLevelSwSecureCrypto:
+ return SecurityLevel::SW_SECURE_CRYPTO;
+ case DrmPlugin::kSecurityLevelSwSecureDecode:
+ return SecurityLevel::SW_SECURE_DECODE;
+ case DrmPlugin::kSecurityLevelHwSecureCrypto:
+ return SecurityLevel::HW_SECURE_CRYPTO;
+ case DrmPlugin::kSecurityLevelHwSecureDecode:
+ return SecurityLevel::HW_SECURE_DECODE;
+ case DrmPlugin::kSecurityLevelHwSecureAll:
+ return SecurityLevel::HW_SECURE_ALL;
+ case DrmPlugin::kSecurityLevelMax:
+ return SecurityLevel::DEFAULT;
+ default:
+ return SecurityLevel::UNKNOWN;
+ }
+}
+
+static List<Vector<uint8_t>> toKeySetIds(const std::vector<KeySetId>& hKeySetIds) {
+ List<Vector<uint8_t>> keySetIds;
+ for (size_t i = 0; i < hKeySetIds.size(); i++) {
+ keySetIds.push_back(toVector(hKeySetIds[i].keySetId));
+ }
+ return keySetIds;
+}
+
+static hidl_vec<uint8_t> toHidlVec(const Vector<uint8_t>& vector) {
+ hidl_vec<uint8_t> vec;
+ vec.setToExternal(const_cast<uint8_t*>(vector.array()), vector.size());
+ return vec;
+}
+
+static DrmPlugin::OfflineLicenseState toOfflineLicenseState(OfflineLicenseState licenseState) {
+ switch (licenseState) {
+ case OfflineLicenseState::USABLE:
+ return DrmPlugin::kOfflineLicenseStateUsable;
+ case OfflineLicenseState::INACTIVE:
+ return DrmPlugin::kOfflineLicenseStateReleased;
+ default:
+ return DrmPlugin::kOfflineLicenseStateUnknown;
+ }
+}
+
+Mutex DrmHalAidl::mLock;
+
+static hidl_vec<DrmMetricGroupHidl> toDrmMetricGroupHidl(std::vector<DrmMetricGroupAidl> result) {
+ std::vector<DrmMetricGroupHidl> resultHidl;
+ for (auto r : result) {
+ DrmMetricGroupHidl re;
+ std::vector<DrmMetricHidl> tmpMetric;
+ for (auto m : r.metrics) {
+ DrmMetricHidl me;
+ me.name = m.name;
+ std::vector<AttributeHidl> aTmp;
+ for (auto attr : m.attributes) {
+ AttributeHidl attrHidl;
+ attrHidl.name = attr.name;
+
+ switch (attr.value.getTag()) {
+ case DrmMetricValue::Tag::int64Value:
+ attrHidl.type = DrmMetricGroupHidl::ValueType::INT64_TYPE;
+ attrHidl.int64Value = attr.value.get<DrmMetricValue::Tag::int64Value>();
+ break;
+ case DrmMetricValue::Tag::doubleValue:
+ attrHidl.type = DrmMetricGroupHidl::ValueType::DOUBLE_TYPE;
+ attrHidl.doubleValue = attr.value.get<DrmMetricValue::Tag::doubleValue>();
+ break;
+ case DrmMetricValue::Tag::stringValue:
+ attrHidl.type = DrmMetricGroupHidl::ValueType::STRING_TYPE;
+ attrHidl.stringValue = attr.value.get<DrmMetricValue::Tag::stringValue>();
+ break;
+ default:
+ break;
+ }
+
+ aTmp.push_back(attrHidl);
+ }
+
+ me.attributes = aTmp;
+
+ std::vector<ValueHidl> vTmp;
+ for (auto value : m.values) {
+ ValueHidl valueHidl;
+ valueHidl.componentName = value.name;
+ switch (value.value.getTag()) {
+ case DrmMetricValue::Tag::int64Value:
+ valueHidl.type = DrmMetricGroupHidl::ValueType::INT64_TYPE;
+ valueHidl.int64Value = value.value.get<DrmMetricValue::Tag::int64Value>();
+ break;
+ case DrmMetricValue::Tag::doubleValue:
+ valueHidl.type = DrmMetricGroupHidl::ValueType::DOUBLE_TYPE;
+ valueHidl.doubleValue = value.value.get<DrmMetricValue::Tag::doubleValue>();
+ break;
+ case DrmMetricValue::Tag::stringValue:
+ valueHidl.type = DrmMetricGroupHidl::ValueType::STRING_TYPE;
+ valueHidl.stringValue = value.value.get<DrmMetricValue::Tag::stringValue>();
+ break;
+ default:
+ break;
+ }
+
+ vTmp.push_back(valueHidl);
+ }
+
+ me.values = vTmp;
+ tmpMetric.push_back(me);
+ }
+
+ re.metrics = tmpMetric;
+ resultHidl.push_back(re);
+ }
+
+ return resultHidl;
+}
+
+// DrmSessionClient Definition
+
+struct DrmHalAidl::DrmSessionClient : public aidl::android::media::BnResourceManagerClient {
+ explicit DrmSessionClient(DrmHalAidl* drm, const Vector<uint8_t>& sessionId)
+ : mSessionId(sessionId), mDrm(drm) {}
+
+ ::ndk::ScopedAStatus reclaimResource(bool* _aidl_return) override;
+ ::ndk::ScopedAStatus getName(::std::string* _aidl_return) override;
+
+ const Vector<uint8_t> mSessionId;
+
+ virtual ~DrmSessionClient();
+
+ private:
+ wp<DrmHalAidl> mDrm;
+
+ DISALLOW_EVIL_CONSTRUCTORS(DrmSessionClient);
+};
+
+::ndk::ScopedAStatus DrmHalAidl::DrmSessionClient::reclaimResource(bool* _aidl_return) {
+ auto sessionId = mSessionId;
+ sp<DrmHalAidl> drm = mDrm.promote();
+ if (drm == NULL) {
+ *_aidl_return = true;
+ return ::ndk::ScopedAStatus::ok();
+ }
+ status_t err = drm->closeSession(sessionId);
+ if (err != OK) {
+ *_aidl_return = false;
+ return ::ndk::ScopedAStatus::ok();
+ }
+ drm->onEvent(EventTypeAidl::SESSION_RECLAIMED, toHidlVec(sessionId), hidl_vec<uint8_t>());
+ *_aidl_return = true;
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus DrmHalAidl::DrmSessionClient::getName(::std::string* _aidl_return) {
+ String8 name;
+ sp<DrmHalAidl> drm = mDrm.promote();
+ if (drm == NULL) {
+ name.append("<deleted>");
+ } else if (drm->getPropertyStringInternal(String8("vendor"), name) != OK || name.isEmpty()) {
+ name.append("<Get vendor failed or is empty>");
+ }
+ name.append("[");
+ for (size_t i = 0; i < mSessionId.size(); ++i) {
+ name.appendFormat("%02x", mSessionId[i]);
+ }
+ name.append("]");
+ *_aidl_return = name;
+ return ::ndk::ScopedAStatus::ok();
+}
+
+DrmHalAidl::DrmSessionClient::~DrmSessionClient() {
+ DrmSessionManager::Instance()->removeSession(mSessionId);
+}
+
+// DrmHalAidl methods
+DrmHalAidl::DrmHalAidl()
+ : mListener(::ndk::SharedRefBase::make<DrmHalListener>(&mMetrics)),
+ mFactories(DrmUtils::makeDrmFactoriesAidl()),
+ mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT) {}
+
+status_t DrmHalAidl::initCheck() const {
+ return mInitCheck;
+}
+
+DrmHalAidl::~DrmHalAidl() {}
+
+status_t DrmHalAidl::setListener(const sp<IDrmClient>& listener) {
+ mListener->setListener(listener);
+ return NO_ERROR;
+}
+
+status_t DrmHalAidl::isCryptoSchemeSupported(const uint8_t uuid[16], const String8& mimeType,
+ DrmPlugin::SecurityLevel level, bool* isSupported) {
+ Mutex::Autolock autoLock(mLock);
+ *isSupported = false;
+ Uuid uuidAidl = DrmUtils::toAidlUuid(uuid);
+ SecurityLevel levelAidl = toAidlSecurityLevel(level);
+ std::string mimeTypeStr = mimeType.string();
+
+ for (ssize_t i = mFactories.size() - 1; i >= 0; i--) {
+ CryptoSchemes schemes{};
+ auto err = mFactories[i]->getSupportedCryptoSchemes(&schemes);
+ if (!err.isOk() || !std::count(schemes.uuids.begin(), schemes.uuids.end(), uuidAidl)) {
+ continue;
+ }
+
+ if (levelAidl != SecurityLevel::DEFAULT && levelAidl != SecurityLevel::UNKNOWN) {
+ if (levelAidl > schemes.maxLevel || levelAidl < schemes.minLevel) {
+ continue;
+ }
+ }
+
+ if (!mimeTypeStr.empty()) {
+ if (!std::count(schemes.mimeTypes.begin(), schemes.mimeTypes.end(), mimeTypeStr)) {
+ continue;
+ }
+ }
+
+ *isSupported = true;
+ break;
+ }
+
+ return OK;
+}
+
+status_t DrmHalAidl::createPlugin(const uint8_t uuid[16], const String8& appPackageName) {
+ Mutex::Autolock autoLock(mLock);
+
+ Uuid uuidAidl = DrmUtils::toAidlUuid(uuid);
+ std::string appPackageNameAidl = toStdString(appPackageName);
+ std::shared_ptr<IDrmPluginAidl> pluginAidl;
+ mMetrics.SetAppPackageName(appPackageName);
+ mMetrics.SetAppUid(AIBinder_getCallingUid());
+ for (ssize_t i = mFactories.size() - 1; i >= 0; i--) {
+ ::ndk::ScopedAStatus status =
+ mFactories[i]->createDrmPlugin(uuidAidl, appPackageNameAidl, &pluginAidl);
+ if (status.isOk()) {
+ if (pluginAidl != NULL) {
+ mPlugin = pluginAidl;
+ break;
+ }
+ } else {
+ DrmUtils::LOG2BE(uuid, "Failed to make drm plugin: %d",
+ status.getServiceSpecificError());
+ }
+ }
+
+ if (mPlugin == NULL) {
+ DrmUtils::LOG2BE(uuid, "No supported hal instance found");
+ mInitCheck = ERROR_UNSUPPORTED;
+ } else {
+ mInitCheck = OK;
+ // Stored pointer mListener upcast to base BnDrmPluginListener
+ ::ndk::ScopedAStatus status = mPlugin
+ ->setListener(std::static_pointer_cast<BnDrmPluginListener>(mListener));
+ if (!status.isOk()) {
+ mInitCheck = DEAD_OBJECT;
+ ALOGE("setListener failed: ex %d svc err %d",
+ status.getExceptionCode(),
+ status.getServiceSpecificError());
+ }
+
+ if (mInitCheck != OK) {
+ mPlugin.reset();
+ }
+ }
+
+ return mInitCheck;
+}
+
+status_t DrmHalAidl::openSession(DrmPlugin::SecurityLevel level, Vector<uint8_t>& sessionId) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ SecurityLevel aSecurityLevel = toAidlSecurityLevel(level);
+
+ if (aSecurityLevel == SecurityLevel::UNKNOWN) {
+ return ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ status_t err = UNKNOWN_ERROR;
+ bool retry = true;
+ do {
+ std::vector<uint8_t> aSessionId;
+
+ ::ndk::ScopedAStatus status = mPlugin->openSession(aSecurityLevel, &aSessionId);
+ if (status.isOk()) sessionId = toVector(aSessionId);
+ err = statusAidlToStatusT(status);
+
+ if (err == ERROR_DRM_RESOURCE_BUSY && retry) {
+ mLock.unlock();
+ // reclaimSession may call back to closeSession, since mLock is
+ // shared between Drm instances, we should unlock here to avoid
+ // deadlock.
+ retry = DrmSessionManager::Instance()->reclaimSession(AIBinder_getCallingPid());
+ mLock.lock();
+ } else {
+ retry = false;
+ }
+ } while (retry);
+
+ if (err == OK) {
+ std::shared_ptr<DrmSessionClient> client =
+ ndk::SharedRefBase::make<DrmSessionClient>(this, sessionId);
+ DrmSessionManager::Instance()->addSession(
+ AIBinder_getCallingPid(), std::static_pointer_cast<IResourceManagerClient>(client),
+ sessionId);
+ mOpenSessions.push_back(client);
+ mMetrics.SetSessionStart(sessionId);
+ }
+
+ mMetrics.mOpenSessionCounter.Increment(err);
+ return err;
+}
+
+status_t DrmHalAidl::closeSession(Vector<uint8_t> const& sessionId) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ std::vector<uint8_t> sessionIdAidl = toStdVec(sessionId);
+ ::ndk::ScopedAStatus status = mPlugin->closeSession(sessionIdAidl);
+ status_t response = statusAidlToStatusT(status);
+ if (status.isOk()) {
+ DrmSessionManager::Instance()->removeSession(sessionId);
+ for (auto i = mOpenSessions.begin(); i != mOpenSessions.end(); i++) {
+ if (isEqualSessionId((*i)->mSessionId, sessionId)) {
+ mOpenSessions.erase(i);
+ break;
+ }
+ }
+
+ mMetrics.SetSessionEnd(sessionId);
+ }
+
+ mMetrics.mCloseSessionCounter.Increment(response);
+ return response;
+}
+
+status_t DrmHalAidl::getKeyRequest(Vector<uint8_t> const& sessionId,
+ Vector<uint8_t> const& initData, String8 const& mimeType,
+ DrmPlugin::KeyType keyType,
+ KeyedVector<String8, String8> const& optionalParameters,
+ Vector<uint8_t>& request, String8& defaultUrl,
+ DrmPlugin::KeyRequestType* keyRequestType) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+ EventTimer<status_t> keyRequestTimer(&mMetrics.mGetKeyRequestTimeUs);
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ KeyType aKeyType;
+ if (keyType == DrmPlugin::kKeyType_Streaming) {
+ aKeyType = KeyType::STREAMING;
+ } else if (keyType == DrmPlugin::kKeyType_Offline) {
+ aKeyType = KeyType::OFFLINE;
+ } else if (keyType == DrmPlugin::kKeyType_Release) {
+ aKeyType = KeyType::RELEASE;
+ } else {
+ keyRequestTimer.SetAttribute(BAD_VALUE);
+ return BAD_VALUE;
+ }
+
+ status_t err = UNKNOWN_ERROR;
+
+ std::vector<uint8_t> sessionIdAidl = toStdVec(sessionId);
+ std::vector<uint8_t> initDataAidl = toStdVec(initData);
+ KeyRequest keyRequest;
+
+ ::ndk::ScopedAStatus status =
+ mPlugin->getKeyRequest(sessionIdAidl, initDataAidl, toStdString(mimeType), aKeyType,
+ toKeyValueVector(optionalParameters), &keyRequest);
+ if (status.isOk()) {
+ request = toVector(keyRequest.request);
+ defaultUrl = toString8(keyRequest.defaultUrl);
+ *keyRequestType = toKeyRequestType(keyRequest.requestType);
+ }
+
+ err = statusAidlToStatusT(status);
+ keyRequestTimer.SetAttribute(err);
+ return err;
+}
+
+status_t DrmHalAidl::provideKeyResponse(Vector<uint8_t> const& sessionId,
+ Vector<uint8_t> const& response,
+ Vector<uint8_t>& keySetId) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+ EventTimer<status_t> keyResponseTimer(&mMetrics.mProvideKeyResponseTimeUs);
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ status_t err = UNKNOWN_ERROR;
+
+ std::vector<uint8_t> sessionIdAidl = toStdVec(sessionId);
+ std::vector<uint8_t> responseAidl = toStdVec(response);
+ KeySetId keySetIdsAidl;
+ ::ndk::ScopedAStatus status =
+ mPlugin->provideKeyResponse(sessionIdAidl, responseAidl, &keySetIdsAidl);
+
+ if (status.isOk()) keySetId = toVector(keySetIdsAidl.keySetId);
+ err = statusAidlToStatusT(status);
+ keyResponseTimer.SetAttribute(err);
+ return err;
+}
+
+status_t DrmHalAidl::removeKeys(Vector<uint8_t> const& keySetId) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ ::ndk::ScopedAStatus status = mPlugin->removeKeys(toStdVec(keySetId));
+ return statusAidlToStatusT(status);
+}
+
+status_t DrmHalAidl::restoreKeys(Vector<uint8_t> const& sessionId,
+ Vector<uint8_t> const& keySetId) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ KeySetId keySetIdsAidl;
+ keySetIdsAidl.keySetId = toStdVec(keySetId);
+ ::ndk::ScopedAStatus status = mPlugin->restoreKeys(toStdVec(sessionId), keySetIdsAidl);
+ return statusAidlToStatusT(status);
+}
+
+status_t DrmHalAidl::queryKeyStatus(Vector<uint8_t> const& sessionId,
+ KeyedVector<String8, String8>& infoMap) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ std::vector<KeyValue> infoMapAidl;
+ ::ndk::ScopedAStatus status = mPlugin->queryKeyStatus(toStdVec(sessionId), &infoMapAidl);
+
+ infoMap = toKeyedVector(infoMapAidl);
+
+ return statusAidlToStatusT(status);
+}
+
+status_t DrmHalAidl::getProvisionRequest(String8 const& certType, String8 const& certAuthority,
+ Vector<uint8_t>& request, String8& defaultUrl) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ status_t err = UNKNOWN_ERROR;
+
+ ProvisionRequest requestAidl;
+ ::ndk::ScopedAStatus status = mPlugin->getProvisionRequest(
+ toStdString(certType), toStdString(certAuthority), &requestAidl);
+
+ request = toVector(requestAidl.request);
+ defaultUrl = toString8(requestAidl.defaultUrl);
+
+ err = statusAidlToStatusT(status);
+ mMetrics.mGetProvisionRequestCounter.Increment(err);
+ return err;
+}
+
+status_t DrmHalAidl::provideProvisionResponse(Vector<uint8_t> const& response,
+ Vector<uint8_t>& certificate,
+ Vector<uint8_t>& wrappedKey) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ status_t err = UNKNOWN_ERROR;
+ ProvideProvisionResponseResult result;
+ ::ndk::ScopedAStatus status = mPlugin->provideProvisionResponse(toStdVec(response), &result);
+
+ certificate = toVector(result.certificate);
+ wrappedKey = toVector(result.wrappedKey);
+ err = statusAidlToStatusT(status);
+ mMetrics.mProvideProvisionResponseCounter.Increment(err);
+ return err;
+}
+
+status_t DrmHalAidl::getSecureStops(List<Vector<uint8_t>>& secureStops) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ std::vector<SecureStop> result;
+ ::ndk::ScopedAStatus status = mPlugin->getSecureStops(&result);
+
+ secureStops = toSecureStops(result);
+
+ return statusAidlToStatusT(status);
+}
+
+status_t DrmHalAidl::getSecureStopIds(List<Vector<uint8_t>>& secureStopIds) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ std::vector<SecureStopId> result;
+ ::ndk::ScopedAStatus status = mPlugin->getSecureStopIds(&result);
+
+ secureStopIds = toSecureStopIds(result);
+
+ return statusAidlToStatusT(status);
+}
+
+status_t DrmHalAidl::getSecureStop(Vector<uint8_t> const& ssid, Vector<uint8_t>& secureStop) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ SecureStopId ssidAidl;
+ ssidAidl.secureStopId = toStdVec(ssid);
+
+ SecureStop result;
+ ::ndk::ScopedAStatus status = mPlugin->getSecureStop(ssidAidl, &result);
+
+ secureStop = toVector(result.opaqueData);
+
+ return statusAidlToStatusT(status);
+}
+
+status_t DrmHalAidl::releaseSecureStops(Vector<uint8_t> const& ssRelease) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ OpaqueData ssId;
+ ssId.opaqueData = toStdVec(ssRelease);
+ ::ndk::ScopedAStatus status = mPlugin->releaseSecureStops(ssId);
+
+ return statusAidlToStatusT(status);
+}
+
+status_t DrmHalAidl::removeSecureStop(Vector<uint8_t> const& ssid) {
+ Mutex::Autolock autoLock(mLock);
+
+ INIT_CHECK();
+
+ SecureStopId ssidAidl;
+ ssidAidl.secureStopId = toStdVec(ssid);
+ ::ndk::ScopedAStatus status = mPlugin->removeSecureStop(ssidAidl);
+ return statusAidlToStatusT(status);
+}
+
+status_t DrmHalAidl::removeAllSecureStops() {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ ::ndk::ScopedAStatus status = mPlugin->releaseAllSecureStops();
+ return statusAidlToStatusT(status);
+}
+
+status_t DrmHalAidl::getHdcpLevels(DrmPlugin::HdcpLevel* connected,
+ DrmPlugin::HdcpLevel* max) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ if (connected == NULL || max == NULL) {
+ return BAD_VALUE;
+ }
+
+ *connected = DrmPlugin::kHdcpLevelUnknown;
+ *max = DrmPlugin::kHdcpLevelUnknown;
+
+ HdcpLevels lvlsAidl;
+ ::ndk::ScopedAStatus status = mPlugin->getHdcpLevels(&lvlsAidl);
+
+ *connected = toHdcpLevel(lvlsAidl.connectedLevel);
+ *max = toHdcpLevel(lvlsAidl.maxLevel);
+
+ return statusAidlToStatusT(status);
+}
+
+status_t DrmHalAidl::getNumberOfSessions(uint32_t* open, uint32_t* max) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ if (open == NULL || max == NULL) {
+ return BAD_VALUE;
+ }
+
+ *open = 0;
+ *max = 0;
+
+ NumberOfSessions result;
+ ::ndk::ScopedAStatus status = mPlugin->getNumberOfSessions(&result);
+
+ *open = result.currentSessions;
+ *max = result.maxSessions;
+
+ return statusAidlToStatusT(status);
+}
+
+status_t DrmHalAidl::getSecurityLevel(Vector<uint8_t> const& sessionId,
+ DrmPlugin::SecurityLevel* level) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ if (level == NULL) {
+ return BAD_VALUE;
+ }
+
+ *level = DrmPlugin::kSecurityLevelUnknown;
+
+ SecurityLevel result;
+ ::ndk::ScopedAStatus status = mPlugin->getSecurityLevel(toStdVec(sessionId), &result);
+
+ *level = toSecurityLevel(result);
+
+ return statusAidlToStatusT(status);
+}
+
+status_t DrmHalAidl::getOfflineLicenseKeySetIds(List<Vector<uint8_t>>& keySetIds) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ std::vector<KeySetId> result;
+ ::ndk::ScopedAStatus status = mPlugin->getOfflineLicenseKeySetIds(&result);
+
+ keySetIds = toKeySetIds(result);
+
+ return statusAidlToStatusT(status);
+}
+
+status_t DrmHalAidl::removeOfflineLicense(Vector<uint8_t> const& keySetId) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ KeySetId keySetIdAidl;
+ keySetIdAidl.keySetId = toStdVec(keySetId);
+ ::ndk::ScopedAStatus status = mPlugin->removeOfflineLicense(keySetIdAidl);
+ return statusAidlToStatusT(status);
+}
+
+status_t DrmHalAidl::getOfflineLicenseState(Vector<uint8_t> const& keySetId,
+ DrmPlugin::OfflineLicenseState* licenseState) const {
+ Mutex::Autolock autoLock(mLock);
+
+ INIT_CHECK();
+ *licenseState = DrmPlugin::kOfflineLicenseStateUnknown;
+
+ KeySetId keySetIdAidl;
+ keySetIdAidl.keySetId = toStdVec(keySetId);
+
+ OfflineLicenseState result;
+ ::ndk::ScopedAStatus status = mPlugin->getOfflineLicenseState(keySetIdAidl, &result);
+
+ *licenseState = toOfflineLicenseState(result);
+
+ return statusAidlToStatusT(status);
+}
+
+status_t DrmHalAidl::getPropertyString(String8 const& name, String8& value) const {
+ Mutex::Autolock autoLock(mLock);
+ return getPropertyStringInternal(name, value);
+}
+
+status_t DrmHalAidl::getPropertyStringInternal(String8 const& name, String8& value) const {
+ // This function is internal to the class and should only be called while
+ // mLock is already held.
+ INIT_CHECK();
+
+ std::string result;
+ ::ndk::ScopedAStatus status = mPlugin->getPropertyString(toStdString(name), &result);
+
+ value = toString8(result);
+
+ return statusAidlToStatusT(status);
+}
+
+status_t DrmHalAidl::getPropertyByteArray(String8 const& name, Vector<uint8_t>& value) const {
+ Mutex::Autolock autoLock(mLock);
+ return getPropertyByteArrayInternal(name, value);
+}
+
+status_t DrmHalAidl::getPropertyByteArrayInternal(String8 const& name,
+ Vector<uint8_t>& value) const {
+ // This function is internal to the class and should only be called while
+ // mLock is already held.
+ INIT_CHECK();
+
+ status_t err = UNKNOWN_ERROR;
+
+ std::vector<uint8_t> result;
+ ::ndk::ScopedAStatus status = mPlugin->getPropertyByteArray(toStdString(name), &result);
+
+ value = toVector(result);
+ err = statusAidlToStatusT(status);
+ if (name == kPropertyDeviceUniqueId) {
+ mMetrics.mGetDeviceUniqueIdCounter.Increment(err);
+ }
+ return err;
+}
+
+status_t DrmHalAidl::setPropertyString(String8 const& name, String8 const& value) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ ::ndk::ScopedAStatus status = mPlugin->setPropertyString(toStdString(name), toStdString(value));
+ return statusAidlToStatusT(status);
+}
+
+status_t DrmHalAidl::setPropertyByteArray(String8 const& name, Vector<uint8_t> const& value) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ ::ndk::ScopedAStatus status = mPlugin->setPropertyByteArray(toStdString(name), toStdVec(value));
+ return statusAidlToStatusT(status);
+}
+
+status_t DrmHalAidl::getMetrics(const sp<IDrmMetricsConsumer>& consumer) {
+ if (consumer == nullptr) {
+ return UNEXPECTED_NULL;
+ }
+ consumer->consumeFrameworkMetrics(mMetrics);
+
+ // Append vendor metrics if they are supported.
+
+ String8 vendor;
+ String8 description;
+ if (getPropertyStringInternal(String8("vendor"), vendor) != OK || vendor.isEmpty()) {
+ ALOGE("Get vendor failed or is empty");
+ vendor = "NONE";
+ }
+ if (getPropertyStringInternal(String8("description"), description) != OK ||
+ description.isEmpty()) {
+ ALOGE("Get description failed or is empty.");
+ description = "NONE";
+ }
+ vendor += ".";
+ vendor += description;
+
+ hidl_vec<DrmMetricGroupHidl> pluginMetrics;
+ status_t err = UNKNOWN_ERROR;
+
+ std::vector<DrmMetricGroupAidl> result;
+ ::ndk::ScopedAStatus status = mPlugin->getMetrics(&result);
+
+ if (status.isOk()) {
+ pluginMetrics = toDrmMetricGroupHidl(result);
+ consumer->consumeHidlMetrics(vendor, pluginMetrics);
+ }
+
+ err = statusAidlToStatusT(status);
+
+ return err;
+}
+
+status_t DrmHalAidl::setCipherAlgorithm(Vector<uint8_t> const& sessionId,
+ String8 const& algorithm) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ ::ndk::ScopedAStatus status =
+ mPlugin->setCipherAlgorithm(toStdVec(sessionId), toStdString(algorithm));
+ return statusAidlToStatusT(status);
+}
+
+status_t DrmHalAidl::setMacAlgorithm(Vector<uint8_t> const& sessionId, String8 const& algorithm) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ ::ndk::ScopedAStatus status =
+ mPlugin->setMacAlgorithm(toStdVec(sessionId), toStdString(algorithm));
+ return statusAidlToStatusT(status);
+}
+
+status_t DrmHalAidl::encrypt(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& input, Vector<uint8_t> const& iv,
+ Vector<uint8_t>& output) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ std::vector<uint8_t> result;
+ ::ndk::ScopedAStatus status = mPlugin->encrypt(toStdVec(sessionId), toStdVec(keyId),
+ toStdVec(input), toStdVec(iv), &result);
+
+ output = toVector(result);
+
+ return statusAidlToStatusT(status);
+}
+
+status_t DrmHalAidl::decrypt(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& input, Vector<uint8_t> const& iv,
+ Vector<uint8_t>& output) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ std::vector<uint8_t> result;
+ ::ndk::ScopedAStatus status = mPlugin->decrypt(toStdVec(sessionId), toStdVec(keyId),
+ toStdVec(input), toStdVec(iv), &result);
+
+ output = toVector(result);
+
+ return statusAidlToStatusT(status);
+}
+
+status_t DrmHalAidl::sign(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& message, Vector<uint8_t>& signature) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ std::vector<uint8_t> result;
+ ::ndk::ScopedAStatus status =
+ mPlugin->sign(toStdVec(sessionId), toStdVec(keyId), toStdVec(message), &result);
+
+ signature = toVector(result);
+
+ return statusAidlToStatusT(status);
+}
+
+status_t DrmHalAidl::verify(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& message, Vector<uint8_t> const& signature,
+ bool& match) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ ::ndk::ScopedAStatus status = mPlugin->verify(toStdVec(sessionId), toStdVec(keyId),
+ toStdVec(message), toStdVec(signature), &match);
+
+ return statusAidlToStatusT(status);
+}
+
+status_t DrmHalAidl::signRSA(Vector<uint8_t> const& sessionId, String8 const& algorithm,
+ Vector<uint8_t> const& message, Vector<uint8_t> const& wrappedKey,
+ Vector<uint8_t>& signature) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ std::vector<uint8_t> result;
+ ::ndk::ScopedAStatus status =
+ mPlugin->signRSA(toStdVec(sessionId), toStdString(algorithm), toStdVec(message),
+ toStdVec(wrappedKey), &result);
+
+ signature = toVector(result);
+
+ return statusAidlToStatusT(status);
+}
+
+status_t DrmHalAidl::requiresSecureDecoder(const char* mime, bool* required) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ std::string mimeAidl(mime);
+ ::ndk::ScopedAStatus status =
+ mPlugin->requiresSecureDecoder(mimeAidl, SecurityLevel::DEFAULT, required);
+ if (!status.isOk()) {
+ DrmUtils::LOG2BE("requiresSecureDecoder txn failed: %d", status.getServiceSpecificError());
+ return DEAD_OBJECT;
+ }
+
+ return OK;
+}
+
+status_t DrmHalAidl::requiresSecureDecoder(const char* mime, DrmPlugin::SecurityLevel securityLevel,
+ bool* required) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ auto aLevel = toAidlSecurityLevel(securityLevel);
+ std::string mimeAidl(mime);
+ ::ndk::ScopedAStatus status = mPlugin->requiresSecureDecoder(mimeAidl, aLevel, required);
+
+ status_t err = statusAidlToStatusT(status);
+ if (!status.isOk()) {
+ DrmUtils::LOG2BE("requiresSecureDecoder txn failed: %d", status.getServiceSpecificError());
+ }
+
+ return err;
+}
+
+status_t DrmHalAidl::setPlaybackId(Vector<uint8_t> const& sessionId, const char* playbackId) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+ std::string playbackIdAidl(playbackId);
+ ::ndk::ScopedAStatus status = mPlugin->setPlaybackId(toStdVec(sessionId), playbackIdAidl);
+ return statusAidlToStatusT(status);
+}
+
+status_t DrmHalAidl::getLogMessages(Vector<drm::V1_4::LogMessage>& logs) const {
+ Mutex::Autolock autoLock(mLock);
+ return DrmUtils::GetLogMessagesAidl<IDrmPluginAidl>(mPlugin, logs);
+}
+
+void DrmHalAidl::closeOpenSessions() {
+ Mutex::Autolock autoLock(mLock);
+ auto openSessions = mOpenSessions;
+ for (size_t i = 0; i < openSessions.size(); i++) {
+ mLock.unlock();
+ closeSession(openSessions[i]->mSessionId);
+ mLock.lock();
+ }
+ mOpenSessions.clear();
+}
+
+std::string DrmHalAidl::reportPluginMetrics() const {
+ Vector<uint8_t> metricsVector;
+ String8 vendor;
+ String8 description;
+ std::string metricsString;
+ if (getPropertyStringInternal(String8("vendor"), vendor) == OK &&
+ getPropertyStringInternal(String8("description"), description) == OK &&
+ getPropertyByteArrayInternal(String8("metrics"), metricsVector) == OK) {
+ metricsString = toBase64StringNoPad(metricsVector.array(), metricsVector.size());
+ status_t res = android::reportDrmPluginMetrics(metricsString, vendor, description,
+ mMetrics.GetAppUid());
+ if (res != OK) {
+ ALOGE("Metrics were retrieved but could not be reported: %d", res);
+ }
+ }
+ return metricsString;
+}
+
+std::string DrmHalAidl::reportFrameworkMetrics(const std::string& pluginMetrics) const {
+ mediametrics_handle_t item(mediametrics_create("mediadrm"));
+ mediametrics_setUid(item, mMetrics.GetAppUid());
+ String8 vendor;
+ String8 description;
+ status_t result = getPropertyStringInternal(String8("vendor"), vendor);
+ if (result != OK) {
+ ALOGE("Failed to get vendor from drm plugin: %d", result);
+ } else {
+ mediametrics_setCString(item, "vendor", vendor.c_str());
+ }
+ result = getPropertyStringInternal(String8("description"), description);
+ if (result != OK) {
+ ALOGE("Failed to get description from drm plugin: %d", result);
+ } else {
+ mediametrics_setCString(item, "description", description.c_str());
+ }
+
+ std::string serializedMetrics;
+ result = mMetrics.GetSerializedMetrics(&serializedMetrics);
+ if (result != OK) {
+ ALOGE("Failed to serialize framework metrics: %d", result);
+ }
+ std::string b64EncodedMetrics =
+ toBase64StringNoPad(serializedMetrics.data(), serializedMetrics.size());
+ if (!b64EncodedMetrics.empty()) {
+ mediametrics_setCString(item, "serialized_metrics", b64EncodedMetrics.c_str());
+ }
+ if (!pluginMetrics.empty()) {
+ mediametrics_setCString(item, "plugin_metrics", pluginMetrics.c_str());
+ }
+ if (!mediametrics_selfRecord(item)) {
+ ALOGE("Failed to self record framework metrics");
+ }
+ mediametrics_delete(item);
+ return serializedMetrics;
+}
+
+void DrmHalAidl::cleanup() {
+ closeOpenSessions();
+
+ Mutex::Autolock autoLock(mLock);
+ reportFrameworkMetrics(reportPluginMetrics());
+
+ setListener(NULL);
+ mInitCheck = NO_INIT;
+ if (mPlugin != NULL) {
+ if (!mPlugin->setListener(NULL).isOk()) {
+ mInitCheck = DEAD_OBJECT;
+ }
+ }
+
+ mPlugin.reset();
+}
+
+status_t DrmHalAidl::destroyPlugin() {
+ cleanup();
+ return OK;
+}
+
+::ndk::ScopedAStatus DrmHalAidl::onEvent(EventTypeAidl eventTypeAidl,
+ const std::vector<uint8_t>& sessionId,
+ const std::vector<uint8_t>& data) {
+ return mListener->onEvent(eventTypeAidl, sessionId, data);
+}
+
+::ndk::ScopedAStatus DrmHalAidl::onExpirationUpdate(const std::vector<uint8_t>& sessionId,
+ int64_t expiryTimeInMS) {
+ return mListener->onExpirationUpdate(sessionId, expiryTimeInMS);
+}
+
+::ndk::ScopedAStatus DrmHalAidl::onKeysChange(const std::vector<uint8_t>& sessionId,
+ const std::vector<KeyStatus>& keyStatusListAidl,
+ bool hasNewUsableKey) {
+ return mListener->onKeysChange(sessionId, keyStatusListAidl, hasNewUsableKey);
+}
+
+::ndk::ScopedAStatus DrmHalAidl::onSessionLostState(const std::vector<uint8_t>& sessionId) {
+ return mListener->onSessionLostState(sessionId);
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/drm/libmediadrm/DrmHalHidl.cpp b/drm/libmediadrm/DrmHalHidl.cpp
new file mode 100644
index 0000000..c83b52b
--- /dev/null
+++ b/drm/libmediadrm/DrmHalHidl.cpp
@@ -0,0 +1,1517 @@
+/*
+ * Copyright (C) 2021 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 "DrmHalHidl"
+
+#include <aidl/android/media/BnResourceManagerClient.h>
+#include <android/binder_manager.h>
+#include <android/hardware/drm/1.2/types.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <hidl/ServiceManagement.h>
+#include <media/EventMetric.h>
+#include <media/MediaMetrics.h>
+#include <media/PluginMetricsReporting.h>
+#include <media/drm/DrmAPI.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/base64.h>
+#include <media/stagefright/foundation/hexdump.h>
+#include <mediadrm/DrmHalHidl.h>
+#include <mediadrm/DrmSessionClientInterface.h>
+#include <mediadrm/DrmSessionManager.h>
+#include <mediadrm/DrmUtils.h>
+#include <mediadrm/IDrmMetricsConsumer.h>
+#include <utils/Log.h>
+
+#include <iomanip>
+#include <vector>
+
+using ::android::sp;
+using ::android::DrmUtils::toStatusT;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::drm::V1_1::DrmMetricGroup;
+using ::android::os::PersistableBundle;
+using drm::V1_0::KeyedVector;
+using drm::V1_0::KeyRequestType;
+using drm::V1_0::KeyType;
+using drm::V1_0::KeyValue;
+using drm::V1_0::SecureStop;
+using drm::V1_0::SecureStopId;
+using drm::V1_0::Status;
+using drm::V1_1::HdcpLevel;
+using drm::V1_1::SecureStopRelease;
+using drm::V1_1::SecurityLevel;
+using drm::V1_2::KeySetId;
+using drm::V1_2::KeyStatusType;
+
+typedef drm::V1_1::KeyRequestType KeyRequestType_V1_1;
+typedef drm::V1_2::Status Status_V1_2;
+typedef drm::V1_2::HdcpLevel HdcpLevel_V1_2;
+
+namespace {
+
+// This constant corresponds to the PROPERTY_DEVICE_UNIQUE_ID constant
+// in the MediaDrm API.
+constexpr char kPropertyDeviceUniqueId[] = "deviceUniqueId";
+constexpr char kEqualsSign[] = "=";
+
+template <typename T>
+std::string toBase64StringNoPad(const T* data, size_t size) {
+ // Note that the base 64 conversion only works with arrays of single-byte
+ // values. If the source is empty or is not an array of single-byte values,
+ // return empty string.
+ if (size == 0 || sizeof(data[0]) != 1) {
+ return "";
+ }
+
+ android::AString outputString;
+ encodeBase64(data, size, &outputString);
+ // Remove trailing equals padding if it exists.
+ while (outputString.size() > 0 && outputString.endsWith(kEqualsSign)) {
+ outputString.erase(outputString.size() - 1, 1);
+ }
+
+ return std::string(outputString.c_str(), outputString.size());
+}
+
+} // anonymous namespace
+
+namespace android {
+
+#define INIT_CHECK() \
+ { \
+ if (mInitCheck != OK) return mInitCheck; \
+ }
+
+static const Vector<uint8_t> toVector(const hidl_vec<uint8_t>& vec) {
+ Vector<uint8_t> vector;
+ vector.appendArray(vec.data(), vec.size());
+ return *const_cast<const Vector<uint8_t>*>(&vector);
+}
+
+static hidl_vec<uint8_t> toHidlVec(const Vector<uint8_t>& vector) {
+ hidl_vec<uint8_t> vec;
+ vec.setToExternal(const_cast<uint8_t*>(vector.array()), vector.size());
+ return vec;
+}
+
+static String8 toString8(const hidl_string& string) {
+ return String8(string.c_str());
+}
+
+static hidl_string toHidlString(const String8& string) {
+ return hidl_string(string.string());
+}
+
+static DrmPlugin::SecurityLevel toSecurityLevel(SecurityLevel level) {
+ switch (level) {
+ case SecurityLevel::SW_SECURE_CRYPTO:
+ return DrmPlugin::kSecurityLevelSwSecureCrypto;
+ case SecurityLevel::SW_SECURE_DECODE:
+ return DrmPlugin::kSecurityLevelSwSecureDecode;
+ case SecurityLevel::HW_SECURE_CRYPTO:
+ return DrmPlugin::kSecurityLevelHwSecureCrypto;
+ case SecurityLevel::HW_SECURE_DECODE:
+ return DrmPlugin::kSecurityLevelHwSecureDecode;
+ case SecurityLevel::HW_SECURE_ALL:
+ return DrmPlugin::kSecurityLevelHwSecureAll;
+ default:
+ return DrmPlugin::kSecurityLevelUnknown;
+ }
+}
+
+static SecurityLevel toHidlSecurityLevel(DrmPlugin::SecurityLevel level) {
+ switch (level) {
+ case DrmPlugin::kSecurityLevelSwSecureCrypto:
+ return SecurityLevel::SW_SECURE_CRYPTO;
+ case DrmPlugin::kSecurityLevelSwSecureDecode:
+ return SecurityLevel::SW_SECURE_DECODE;
+ case DrmPlugin::kSecurityLevelHwSecureCrypto:
+ return SecurityLevel::HW_SECURE_CRYPTO;
+ case DrmPlugin::kSecurityLevelHwSecureDecode:
+ return SecurityLevel::HW_SECURE_DECODE;
+ case DrmPlugin::kSecurityLevelHwSecureAll:
+ return SecurityLevel::HW_SECURE_ALL;
+ default:
+ return SecurityLevel::UNKNOWN;
+ }
+}
+
+static DrmPlugin::OfflineLicenseState toOfflineLicenseState(OfflineLicenseState licenseState) {
+ switch (licenseState) {
+ case OfflineLicenseState::USABLE:
+ return DrmPlugin::kOfflineLicenseStateUsable;
+ case OfflineLicenseState::INACTIVE:
+ return DrmPlugin::kOfflineLicenseStateReleased;
+ default:
+ return DrmPlugin::kOfflineLicenseStateUnknown;
+ }
+}
+
+static DrmPlugin::HdcpLevel toHdcpLevel(HdcpLevel_V1_2 level) {
+ switch (level) {
+ case HdcpLevel_V1_2::HDCP_NONE:
+ return DrmPlugin::kHdcpNone;
+ case HdcpLevel_V1_2::HDCP_V1:
+ return DrmPlugin::kHdcpV1;
+ case HdcpLevel_V1_2::HDCP_V2:
+ return DrmPlugin::kHdcpV2;
+ case HdcpLevel_V1_2::HDCP_V2_1:
+ return DrmPlugin::kHdcpV2_1;
+ case HdcpLevel_V1_2::HDCP_V2_2:
+ return DrmPlugin::kHdcpV2_2;
+ case HdcpLevel_V1_2::HDCP_V2_3:
+ return DrmPlugin::kHdcpV2_3;
+ case HdcpLevel_V1_2::HDCP_NO_OUTPUT:
+ return DrmPlugin::kHdcpNoOutput;
+ default:
+ return DrmPlugin::kHdcpLevelUnknown;
+ }
+}
+static ::KeyedVector toHidlKeyedVector(const KeyedVector<String8, String8>& keyedVector) {
+ std::vector<KeyValue> stdKeyedVector;
+ for (size_t i = 0; i < keyedVector.size(); i++) {
+ KeyValue keyValue;
+ keyValue.key = toHidlString(keyedVector.keyAt(i));
+ keyValue.value = toHidlString(keyedVector.valueAt(i));
+ stdKeyedVector.push_back(keyValue);
+ }
+ return ::KeyedVector(stdKeyedVector);
+}
+
+static KeyedVector<String8, String8> toKeyedVector(const ::KeyedVector& hKeyedVector) {
+ KeyedVector<String8, String8> keyedVector;
+ for (size_t i = 0; i < hKeyedVector.size(); i++) {
+ keyedVector.add(toString8(hKeyedVector[i].key), toString8(hKeyedVector[i].value));
+ }
+ return keyedVector;
+}
+
+static List<Vector<uint8_t>> toSecureStops(const hidl_vec<SecureStop>& hSecureStops) {
+ List<Vector<uint8_t>> secureStops;
+ for (size_t i = 0; i < hSecureStops.size(); i++) {
+ secureStops.push_back(toVector(hSecureStops[i].opaqueData));
+ }
+ return secureStops;
+}
+
+static List<Vector<uint8_t>> toSecureStopIds(const hidl_vec<SecureStopId>& hSecureStopIds) {
+ List<Vector<uint8_t>> secureStopIds;
+ for (size_t i = 0; i < hSecureStopIds.size(); i++) {
+ secureStopIds.push_back(toVector(hSecureStopIds[i]));
+ }
+ return secureStopIds;
+}
+
+static List<Vector<uint8_t>> toKeySetIds(const hidl_vec<KeySetId>& hKeySetIds) {
+ List<Vector<uint8_t>> keySetIds;
+ for (size_t i = 0; i < hKeySetIds.size(); i++) {
+ keySetIds.push_back(toVector(hKeySetIds[i]));
+ }
+ return keySetIds;
+}
+
+Mutex DrmHalHidl::mLock;
+
+struct DrmHalHidl::DrmSessionClient : public aidl::android::media::BnResourceManagerClient {
+ explicit DrmSessionClient(DrmHalHidl* drm, const Vector<uint8_t>& sessionId)
+ : mSessionId(sessionId), mDrm(drm) {}
+
+ ::ndk::ScopedAStatus reclaimResource(bool* _aidl_return) override;
+ ::ndk::ScopedAStatus getName(::std::string* _aidl_return) override;
+
+ const Vector<uint8_t> mSessionId;
+
+ virtual ~DrmSessionClient();
+
+ private:
+ wp<DrmHalHidl> mDrm;
+
+ DISALLOW_EVIL_CONSTRUCTORS(DrmSessionClient);
+};
+
+::ndk::ScopedAStatus DrmHalHidl::DrmSessionClient::reclaimResource(bool* _aidl_return) {
+ auto sessionId = mSessionId;
+ sp<DrmHalHidl> drm = mDrm.promote();
+ if (drm == NULL) {
+ *_aidl_return = true;
+ return ::ndk::ScopedAStatus::ok();
+ }
+ status_t err = drm->closeSession(sessionId);
+ if (err != OK) {
+ *_aidl_return = false;
+ return ::ndk::ScopedAStatus::ok();
+ }
+ drm->sendEvent(EventType::SESSION_RECLAIMED, toHidlVec(sessionId), hidl_vec<uint8_t>());
+ *_aidl_return = true;
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus DrmHalHidl::DrmSessionClient::getName(::std::string* _aidl_return) {
+ String8 name;
+ sp<DrmHalHidl> drm = mDrm.promote();
+ if (drm == NULL) {
+ name.append("<deleted>");
+ } else if (drm->getPropertyStringInternal(String8("vendor"), name) != OK || name.isEmpty()) {
+ name.append("<Get vendor failed or is empty>");
+ }
+ name.append("[");
+ for (size_t i = 0; i < mSessionId.size(); ++i) {
+ name.appendFormat("%02x", mSessionId[i]);
+ }
+ name.append("]");
+ *_aidl_return = name;
+ return ::ndk::ScopedAStatus::ok();
+}
+
+DrmHalHidl::DrmSessionClient::~DrmSessionClient() {
+ DrmSessionManager::Instance()->removeSession(mSessionId);
+}
+
+DrmHalHidl::DrmHalHidl()
+ : mFactories(makeDrmFactories()),
+ mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT) {}
+
+void DrmHalHidl::closeOpenSessions() {
+ Mutex::Autolock autoLock(mLock);
+ auto openSessions = mOpenSessions;
+ for (size_t i = 0; i < openSessions.size(); i++) {
+ mLock.unlock();
+ closeSession(openSessions[i]->mSessionId);
+ mLock.lock();
+ }
+ mOpenSessions.clear();
+}
+
+DrmHalHidl::~DrmHalHidl() {}
+
+void DrmHalHidl::cleanup() {
+ closeOpenSessions();
+
+ Mutex::Autolock autoLock(mLock);
+ reportFrameworkMetrics(reportPluginMetrics());
+
+ setListener(NULL);
+ mInitCheck = NO_INIT;
+ if (mPluginV1_2 != NULL) {
+ if (!mPluginV1_2->setListener(NULL).isOk()) {
+ mInitCheck = DEAD_OBJECT;
+ }
+ } else if (mPlugin != NULL) {
+ if (!mPlugin->setListener(NULL).isOk()) {
+ mInitCheck = DEAD_OBJECT;
+ }
+ }
+ mPlugin.clear();
+ mPluginV1_1.clear();
+ mPluginV1_2.clear();
+ mPluginV1_4.clear();
+}
+
+std::vector<sp<IDrmFactory>> DrmHalHidl::makeDrmFactories() {
+ static std::vector<sp<IDrmFactory>> factories(DrmUtils::MakeDrmFactories());
+ if (factories.size() == 0) {
+ DrmUtils::LOG2BI("No hidl drm factories found");
+ // could be in passthrough mode, load the default passthrough service
+ auto passthrough = IDrmFactory::getService();
+ if (passthrough != NULL) {
+ DrmUtils::LOG2BI("makeDrmFactories: using default passthrough drm instance");
+ factories.push_back(passthrough);
+ } else {
+ DrmUtils::LOG2BE("Failed to find passthrough drm factories");
+ }
+ }
+ return factories;
+}
+
+sp<IDrmPlugin> DrmHalHidl::makeDrmPlugin(const sp<IDrmFactory>& factory, const uint8_t uuid[16],
+ const String8& appPackageName) {
+ mAppPackageName = appPackageName;
+ mMetrics.SetAppPackageName(appPackageName);
+ mMetrics.SetAppUid(AIBinder_getCallingUid());
+
+ sp<IDrmPlugin> plugin;
+ Return<void> hResult = factory->createPlugin(
+ uuid, appPackageName.string(), [&](Status status, const sp<IDrmPlugin>& hPlugin) {
+ if (status != Status::OK) {
+ DrmUtils::LOG2BE(uuid, "Failed to make drm plugin: %d", status);
+ return;
+ }
+ plugin = hPlugin;
+ });
+
+ if (!hResult.isOk()) {
+ DrmUtils::LOG2BE(uuid, "createPlugin remote call failed: %s",
+ hResult.description().c_str());
+ }
+
+ return plugin;
+}
+
+status_t DrmHalHidl::initCheck() const {
+ return mInitCheck;
+}
+
+status_t DrmHalHidl::setListener(const sp<IDrmClient>& listener) {
+ Mutex::Autolock lock(mEventLock);
+ mListener = listener;
+ return NO_ERROR;
+}
+
+Return<void> DrmHalHidl::sendEvent(EventType hEventType, const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<uint8_t>& data) {
+ mMetrics.mEventCounter.Increment((uint32_t)hEventType);
+
+ mEventLock.lock();
+ sp<IDrmClient> listener = mListener;
+ mEventLock.unlock();
+
+ if (listener != NULL) {
+ Mutex::Autolock lock(mNotifyLock);
+ DrmPlugin::EventType eventType;
+ switch (hEventType) {
+ case EventType::PROVISION_REQUIRED:
+ eventType = DrmPlugin::kDrmPluginEventProvisionRequired;
+ break;
+ case EventType::KEY_NEEDED:
+ eventType = DrmPlugin::kDrmPluginEventKeyNeeded;
+ break;
+ case EventType::KEY_EXPIRED:
+ eventType = DrmPlugin::kDrmPluginEventKeyExpired;
+ break;
+ case EventType::VENDOR_DEFINED:
+ eventType = DrmPlugin::kDrmPluginEventVendorDefined;
+ break;
+ case EventType::SESSION_RECLAIMED:
+ eventType = DrmPlugin::kDrmPluginEventSessionReclaimed;
+ break;
+ default:
+ return Void();
+ }
+ listener->sendEvent(eventType, sessionId, data);
+ }
+ return Void();
+}
+
+Return<void> DrmHalHidl::sendExpirationUpdate(const hidl_vec<uint8_t>& sessionId,
+ int64_t expiryTimeInMS) {
+ mEventLock.lock();
+ sp<IDrmClient> listener = mListener;
+ mEventLock.unlock();
+
+ if (listener != NULL) {
+ Mutex::Autolock lock(mNotifyLock);
+ listener->sendExpirationUpdate(sessionId, expiryTimeInMS);
+ }
+ return Void();
+}
+
+Return<void> DrmHalHidl::sendKeysChange(const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<KeyStatus_V1_0>& keyStatusList_V1_0,
+ bool hasNewUsableKey) {
+ std::vector<KeyStatus> keyStatusVec;
+ for (const auto& keyStatus_V1_0 : keyStatusList_V1_0) {
+ keyStatusVec.push_back(
+ {keyStatus_V1_0.keyId, static_cast<KeyStatusType>(keyStatus_V1_0.type)});
+ }
+ hidl_vec<KeyStatus> keyStatusList_V1_2(keyStatusVec);
+ return sendKeysChange_1_2(sessionId, keyStatusList_V1_2, hasNewUsableKey);
+}
+
+Return<void> DrmHalHidl::sendKeysChange_1_2(const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<KeyStatus>& hKeyStatusList,
+ bool hasNewUsableKey) {
+ mEventLock.lock();
+ sp<IDrmClient> listener = mListener;
+ mEventLock.unlock();
+
+ if (listener != NULL) {
+ std::vector<DrmKeyStatus> keyStatusList;
+ size_t nKeys = hKeyStatusList.size();
+ for (size_t i = 0; i < nKeys; ++i) {
+ const KeyStatus& keyStatus = hKeyStatusList[i];
+ uint32_t type;
+ switch (keyStatus.type) {
+ case KeyStatusType::USABLE:
+ type = DrmPlugin::kKeyStatusType_Usable;
+ break;
+ case KeyStatusType::EXPIRED:
+ type = DrmPlugin::kKeyStatusType_Expired;
+ break;
+ case KeyStatusType::OUTPUTNOTALLOWED:
+ type = DrmPlugin::kKeyStatusType_OutputNotAllowed;
+ break;
+ case KeyStatusType::STATUSPENDING:
+ type = DrmPlugin::kKeyStatusType_StatusPending;
+ break;
+ case KeyStatusType::USABLEINFUTURE:
+ type = DrmPlugin::kKeyStatusType_UsableInFuture;
+ break;
+ case KeyStatusType::INTERNALERROR:
+ default:
+ type = DrmPlugin::kKeyStatusType_InternalError;
+ break;
+ }
+ keyStatusList.push_back({type, keyStatus.keyId});
+ mMetrics.mKeyStatusChangeCounter.Increment((uint32_t)keyStatus.type);
+ }
+
+ Mutex::Autolock lock(mNotifyLock);
+ listener->sendKeysChange(sessionId, keyStatusList, hasNewUsableKey);
+ } else {
+ // There's no listener. But we still want to count the key change
+ // events.
+ size_t nKeys = hKeyStatusList.size();
+ for (size_t i = 0; i < nKeys; i++) {
+ mMetrics.mKeyStatusChangeCounter.Increment((uint32_t)hKeyStatusList[i].type);
+ }
+ }
+
+ return Void();
+}
+
+Return<void> DrmHalHidl::sendSessionLostState(const hidl_vec<uint8_t>& sessionId) {
+ mEventLock.lock();
+ sp<IDrmClient> listener = mListener;
+ mEventLock.unlock();
+
+ if (listener != NULL) {
+ Mutex::Autolock lock(mNotifyLock);
+ listener->sendSessionLostState(sessionId);
+ }
+ return Void();
+}
+
+status_t DrmHalHidl::matchMimeTypeAndSecurityLevel(const sp<IDrmFactory>& factory,
+ const uint8_t uuid[16], const String8& mimeType,
+ DrmPlugin::SecurityLevel level,
+ bool* isSupported) {
+ *isSupported = false;
+
+ // handle default value cases
+ if (level == DrmPlugin::kSecurityLevelUnknown) {
+ if (mimeType == "") {
+ // isCryptoSchemeSupported(uuid)
+ *isSupported = true;
+ } else {
+ // isCryptoSchemeSupported(uuid, mimeType)
+ *isSupported = factory->isContentTypeSupported(mimeType.string());
+ }
+ return OK;
+ } else if (mimeType == "") {
+ return BAD_VALUE;
+ }
+
+ sp<drm::V1_2::IDrmFactory> factoryV1_2 = drm::V1_2::IDrmFactory::castFrom(factory);
+ if (factoryV1_2 == NULL) {
+ return ERROR_UNSUPPORTED;
+ } else {
+ *isSupported = factoryV1_2->isCryptoSchemeSupported_1_2(uuid, mimeType.string(),
+ toHidlSecurityLevel(level));
+ return OK;
+ }
+}
+
+status_t DrmHalHidl::isCryptoSchemeSupported(const uint8_t uuid[16], const String8& mimeType,
+ DrmPlugin::SecurityLevel level, bool* isSupported) {
+ Mutex::Autolock autoLock(mLock);
+ *isSupported = false;
+ for (ssize_t i = mFactories.size() - 1; i >= 0; i--) {
+ if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
+ return matchMimeTypeAndSecurityLevel(mFactories[i], uuid, mimeType, level, isSupported);
+ }
+ }
+ return OK;
+}
+
+status_t DrmHalHidl::createPlugin(const uint8_t uuid[16], const String8& appPackageName) {
+ Mutex::Autolock autoLock(mLock);
+
+ for (ssize_t i = mFactories.size() - 1; i >= 0; i--) {
+ auto hResult = mFactories[i]->isCryptoSchemeSupported(uuid);
+ if (hResult.isOk() && hResult) {
+ auto plugin = makeDrmPlugin(mFactories[i], uuid, appPackageName);
+ if (plugin != NULL) {
+ mPlugin = plugin;
+ mPluginV1_1 = drm::V1_1::IDrmPlugin::castFrom(mPlugin);
+ mPluginV1_2 = drm::V1_2::IDrmPlugin::castFrom(mPlugin);
+ mPluginV1_4 = drm::V1_4::IDrmPlugin::castFrom(mPlugin);
+ break;
+ }
+ }
+ }
+
+ if (mPlugin == NULL) {
+ DrmUtils::LOG2BE(uuid, "No supported hal instance found");
+ mInitCheck = ERROR_UNSUPPORTED;
+ } else {
+ mInitCheck = OK;
+ if (mPluginV1_2 != NULL) {
+ if (!mPluginV1_2->setListener(this).isOk()) {
+ mInitCheck = DEAD_OBJECT;
+ }
+ } else if (!mPlugin->setListener(this).isOk()) {
+ mInitCheck = DEAD_OBJECT;
+ }
+ if (mInitCheck != OK) {
+ mPlugin.clear();
+ mPluginV1_1.clear();
+ mPluginV1_2.clear();
+ mPluginV1_4.clear();
+ }
+ }
+
+ return mInitCheck;
+}
+
+status_t DrmHalHidl::destroyPlugin() {
+ cleanup();
+ return OK;
+}
+
+status_t DrmHalHidl::openSession(DrmPlugin::SecurityLevel level, Vector<uint8_t>& sessionId) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ SecurityLevel hSecurityLevel = toHidlSecurityLevel(level);
+ bool setSecurityLevel = true;
+
+ if (level == DrmPlugin::kSecurityLevelMax) {
+ setSecurityLevel = false;
+ } else {
+ if (hSecurityLevel == SecurityLevel::UNKNOWN) {
+ return ERROR_DRM_CANNOT_HANDLE;
+ }
+ }
+
+ status_t err = UNKNOWN_ERROR;
+ bool retry = true;
+ do {
+ hidl_vec<uint8_t> hSessionId;
+
+ Return<void> hResult;
+ if (mPluginV1_1 == NULL || !setSecurityLevel) {
+ hResult = mPlugin->openSession([&](Status status, const hidl_vec<uint8_t>& id) {
+ if (status == Status::OK) {
+ sessionId = toVector(id);
+ }
+ err = toStatusT(status);
+ });
+ } else {
+ hResult = mPluginV1_1->openSession_1_1(hSecurityLevel,
+ [&](Status status, const hidl_vec<uint8_t>& id) {
+ if (status == Status::OK) {
+ sessionId = toVector(id);
+ }
+ err = toStatusT(status);
+ });
+ }
+
+ if (!hResult.isOk()) {
+ err = DEAD_OBJECT;
+ }
+
+ if (err == ERROR_DRM_RESOURCE_BUSY && retry) {
+ mLock.unlock();
+ // reclaimSession may call back to closeSession, since mLock is
+ // shared between Drm instances, we should unlock here to avoid
+ // deadlock.
+ retry = DrmSessionManager::Instance()->reclaimSession(AIBinder_getCallingPid());
+ mLock.lock();
+ } else {
+ retry = false;
+ }
+ } while (retry);
+
+ if (err == OK) {
+ std::shared_ptr<DrmSessionClient> client =
+ ndk::SharedRefBase::make<DrmSessionClient>(this, sessionId);
+ DrmSessionManager::Instance()->addSession(
+ AIBinder_getCallingPid(), std::static_pointer_cast<IResourceManagerClient>(client),
+ sessionId);
+ mOpenSessions.push_back(client);
+ mMetrics.SetSessionStart(sessionId);
+ }
+
+ mMetrics.mOpenSessionCounter.Increment(err);
+ return err;
+}
+
+status_t DrmHalHidl::closeSession(Vector<uint8_t> const& sessionId) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ Return<Status> status = mPlugin->closeSession(toHidlVec(sessionId));
+ if (status.isOk()) {
+ if (status == Status::OK) {
+ DrmSessionManager::Instance()->removeSession(sessionId);
+ for (auto i = mOpenSessions.begin(); i != mOpenSessions.end(); i++) {
+ if (isEqualSessionId((*i)->mSessionId, sessionId)) {
+ mOpenSessions.erase(i);
+ break;
+ }
+ }
+ }
+ status_t response = toStatusT(status);
+ mMetrics.SetSessionEnd(sessionId);
+ mMetrics.mCloseSessionCounter.Increment(response);
+ return response;
+ }
+ mMetrics.mCloseSessionCounter.Increment(DEAD_OBJECT);
+ return DEAD_OBJECT;
+}
+
+static DrmPlugin::KeyRequestType toKeyRequestType(KeyRequestType keyRequestType) {
+ switch (keyRequestType) {
+ case KeyRequestType::INITIAL:
+ return DrmPlugin::kKeyRequestType_Initial;
+ break;
+ case KeyRequestType::RENEWAL:
+ return DrmPlugin::kKeyRequestType_Renewal;
+ break;
+ case KeyRequestType::RELEASE:
+ return DrmPlugin::kKeyRequestType_Release;
+ break;
+ default:
+ return DrmPlugin::kKeyRequestType_Unknown;
+ break;
+ }
+}
+
+static DrmPlugin::KeyRequestType toKeyRequestType_1_1(KeyRequestType_V1_1 keyRequestType) {
+ switch (keyRequestType) {
+ case KeyRequestType_V1_1::NONE:
+ return DrmPlugin::kKeyRequestType_None;
+ break;
+ case KeyRequestType_V1_1::UPDATE:
+ return DrmPlugin::kKeyRequestType_Update;
+ break;
+ default:
+ return toKeyRequestType(static_cast<KeyRequestType>(keyRequestType));
+ break;
+ }
+}
+
+status_t DrmHalHidl::getKeyRequest(Vector<uint8_t> const& sessionId,
+ Vector<uint8_t> const& initData, String8 const& mimeType,
+ DrmPlugin::KeyType keyType,
+ KeyedVector<String8, String8> const& optionalParameters,
+ Vector<uint8_t>& request, String8& defaultUrl,
+ DrmPlugin::KeyRequestType* keyRequestType) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+ EventTimer<status_t> keyRequestTimer(&mMetrics.mGetKeyRequestTimeUs);
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ KeyType hKeyType;
+ if (keyType == DrmPlugin::kKeyType_Streaming) {
+ hKeyType = KeyType::STREAMING;
+ } else if (keyType == DrmPlugin::kKeyType_Offline) {
+ hKeyType = KeyType::OFFLINE;
+ } else if (keyType == DrmPlugin::kKeyType_Release) {
+ hKeyType = KeyType::RELEASE;
+ } else {
+ keyRequestTimer.SetAttribute(BAD_VALUE);
+ return BAD_VALUE;
+ }
+
+ ::KeyedVector hOptionalParameters = toHidlKeyedVector(optionalParameters);
+
+ status_t err = UNKNOWN_ERROR;
+ Return<void> hResult;
+
+ if (mPluginV1_2 != NULL) {
+ hResult = mPluginV1_2->getKeyRequest_1_2(
+ toHidlVec(sessionId), toHidlVec(initData), toHidlString(mimeType), hKeyType,
+ hOptionalParameters,
+ [&](Status_V1_2 status, const hidl_vec<uint8_t>& hRequest,
+ KeyRequestType_V1_1 hKeyRequestType, const hidl_string& hDefaultUrl) {
+ if (status == Status_V1_2::OK) {
+ request = toVector(hRequest);
+ defaultUrl = toString8(hDefaultUrl);
+ *keyRequestType = toKeyRequestType_1_1(hKeyRequestType);
+ }
+ err = toStatusT(status);
+ });
+ } else if (mPluginV1_1 != NULL) {
+ hResult = mPluginV1_1->getKeyRequest_1_1(
+ toHidlVec(sessionId), toHidlVec(initData), toHidlString(mimeType), hKeyType,
+ hOptionalParameters,
+ [&](Status status, const hidl_vec<uint8_t>& hRequest,
+ KeyRequestType_V1_1 hKeyRequestType, const hidl_string& hDefaultUrl) {
+ if (status == Status::OK) {
+ request = toVector(hRequest);
+ defaultUrl = toString8(hDefaultUrl);
+ *keyRequestType = toKeyRequestType_1_1(hKeyRequestType);
+ }
+ err = toStatusT(status);
+ });
+ } else {
+ hResult = mPlugin->getKeyRequest(
+ toHidlVec(sessionId), toHidlVec(initData), toHidlString(mimeType), hKeyType,
+ hOptionalParameters,
+ [&](Status status, const hidl_vec<uint8_t>& hRequest,
+ KeyRequestType hKeyRequestType, const hidl_string& hDefaultUrl) {
+ if (status == Status::OK) {
+ request = toVector(hRequest);
+ defaultUrl = toString8(hDefaultUrl);
+ *keyRequestType = toKeyRequestType(hKeyRequestType);
+ }
+ err = toStatusT(status);
+ });
+ }
+
+ err = hResult.isOk() ? err : DEAD_OBJECT;
+ keyRequestTimer.SetAttribute(err);
+ return err;
+}
+
+status_t DrmHalHidl::provideKeyResponse(Vector<uint8_t> const& sessionId,
+ Vector<uint8_t> const& response,
+ Vector<uint8_t>& keySetId) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+ EventTimer<status_t> keyResponseTimer(&mMetrics.mProvideKeyResponseTimeUs);
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult =
+ mPlugin->provideKeyResponse(toHidlVec(sessionId), toHidlVec(response),
+ [&](Status status, const hidl_vec<uint8_t>& hKeySetId) {
+ if (status == Status::OK) {
+ keySetId = toVector(hKeySetId);
+ }
+ err = toStatusT(status);
+ });
+ err = hResult.isOk() ? err : DEAD_OBJECT;
+ keyResponseTimer.SetAttribute(err);
+ return err;
+}
+
+status_t DrmHalHidl::removeKeys(Vector<uint8_t> const& keySetId) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ Return<Status> status = mPlugin->removeKeys(toHidlVec(keySetId));
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::restoreKeys(Vector<uint8_t> const& sessionId,
+ Vector<uint8_t> const& keySetId) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ Return<Status> status = mPlugin->restoreKeys(toHidlVec(sessionId), toHidlVec(keySetId));
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::queryKeyStatus(Vector<uint8_t> const& sessionId,
+ KeyedVector<String8, String8>& infoMap) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ ::KeyedVector hInfoMap;
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult = mPlugin->queryKeyStatus(
+ toHidlVec(sessionId), [&](Status status, const hidl_vec<KeyValue>& map) {
+ if (status == Status::OK) {
+ infoMap = toKeyedVector(map);
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::getProvisionRequest(String8 const& certType, String8 const& certAuthority,
+ Vector<uint8_t>& request, String8& defaultUrl) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ status_t err = UNKNOWN_ERROR;
+ Return<void> hResult;
+
+ if (mPluginV1_2 != NULL) {
+ hResult = mPluginV1_2->getProvisionRequest_1_2(
+ toHidlString(certType), toHidlString(certAuthority),
+ [&](Status_V1_2 status, const hidl_vec<uint8_t>& hRequest,
+ const hidl_string& hDefaultUrl) {
+ if (status == Status_V1_2::OK) {
+ request = toVector(hRequest);
+ defaultUrl = toString8(hDefaultUrl);
+ }
+ err = toStatusT(status);
+ });
+ } else {
+ hResult = mPlugin->getProvisionRequest(toHidlString(certType), toHidlString(certAuthority),
+ [&](Status status, const hidl_vec<uint8_t>& hRequest,
+ const hidl_string& hDefaultUrl) {
+ if (status == Status::OK) {
+ request = toVector(hRequest);
+ defaultUrl = toString8(hDefaultUrl);
+ }
+ err = toStatusT(status);
+ });
+ }
+
+ err = hResult.isOk() ? err : DEAD_OBJECT;
+ mMetrics.mGetProvisionRequestCounter.Increment(err);
+ return err;
+}
+
+status_t DrmHalHidl::provideProvisionResponse(Vector<uint8_t> const& response,
+ Vector<uint8_t>& certificate,
+ Vector<uint8_t>& wrappedKey) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult = mPlugin->provideProvisionResponse(
+ toHidlVec(response), [&](Status status, const hidl_vec<uint8_t>& hCertificate,
+ const hidl_vec<uint8_t>& hWrappedKey) {
+ if (status == Status::OK) {
+ certificate = toVector(hCertificate);
+ wrappedKey = toVector(hWrappedKey);
+ }
+ err = toStatusT(status);
+ });
+
+ err = hResult.isOk() ? err : DEAD_OBJECT;
+ mMetrics.mProvideProvisionResponseCounter.Increment(err);
+ return err;
+}
+
+status_t DrmHalHidl::getSecureStops(List<Vector<uint8_t>>& secureStops) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult =
+ mPlugin->getSecureStops([&](Status status, const hidl_vec<SecureStop>& hSecureStops) {
+ if (status == Status::OK) {
+ secureStops = toSecureStops(hSecureStops);
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::getSecureStopIds(List<Vector<uint8_t>>& secureStopIds) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ if (mPluginV1_1 == NULL) {
+ return ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult = mPluginV1_1->getSecureStopIds(
+ [&](Status status, const hidl_vec<SecureStopId>& hSecureStopIds) {
+ if (status == Status::OK) {
+ secureStopIds = toSecureStopIds(hSecureStopIds);
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::getSecureStop(Vector<uint8_t> const& ssid, Vector<uint8_t>& secureStop) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult = mPlugin->getSecureStop(
+ toHidlVec(ssid), [&](Status status, const SecureStop& hSecureStop) {
+ if (status == Status::OK) {
+ secureStop = toVector(hSecureStop.opaqueData);
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::releaseSecureStops(Vector<uint8_t> const& ssRelease) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ Return<Status> status(Status::ERROR_DRM_UNKNOWN);
+ if (mPluginV1_1 != NULL) {
+ SecureStopRelease secureStopRelease;
+ secureStopRelease.opaqueData = toHidlVec(ssRelease);
+ status = mPluginV1_1->releaseSecureStops(secureStopRelease);
+ } else {
+ status = mPlugin->releaseSecureStop(toHidlVec(ssRelease));
+ }
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::removeSecureStop(Vector<uint8_t> const& ssid) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ if (mPluginV1_1 == NULL) {
+ return ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ Return<Status> status = mPluginV1_1->removeSecureStop(toHidlVec(ssid));
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::removeAllSecureStops() {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ Return<Status> status(Status::ERROR_DRM_UNKNOWN);
+ if (mPluginV1_1 != NULL) {
+ status = mPluginV1_1->removeAllSecureStops();
+ } else {
+ status = mPlugin->releaseAllSecureStops();
+ }
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::getHdcpLevels(DrmPlugin::HdcpLevel* connected,
+ DrmPlugin::HdcpLevel* max) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ if (connected == NULL || max == NULL) {
+ return BAD_VALUE;
+ }
+ status_t err = UNKNOWN_ERROR;
+
+ *connected = DrmPlugin::kHdcpLevelUnknown;
+ *max = DrmPlugin::kHdcpLevelUnknown;
+
+ Return<void> hResult;
+ if (mPluginV1_2 != NULL) {
+ hResult = mPluginV1_2->getHdcpLevels_1_2([&](Status_V1_2 status,
+ const HdcpLevel_V1_2& hConnected,
+ const HdcpLevel_V1_2& hMax) {
+ if (status == Status_V1_2::OK) {
+ *connected = toHdcpLevel(hConnected);
+ *max = toHdcpLevel(hMax);
+ }
+ err = toStatusT(status);
+ });
+ } else if (mPluginV1_1 != NULL) {
+ hResult = mPluginV1_1->getHdcpLevels(
+ [&](Status status, const HdcpLevel& hConnected, const HdcpLevel& hMax) {
+ if (status == Status::OK) {
+ *connected = toHdcpLevel(static_cast<HdcpLevel_V1_2>(hConnected));
+ *max = toHdcpLevel(static_cast<HdcpLevel_V1_2>(hMax));
+ }
+ err = toStatusT(status);
+ });
+ } else {
+ return ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::getNumberOfSessions(uint32_t* open, uint32_t* max) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ if (open == NULL || max == NULL) {
+ return BAD_VALUE;
+ }
+ status_t err = UNKNOWN_ERROR;
+
+ *open = 0;
+ *max = 0;
+
+ if (mPluginV1_1 == NULL) {
+ return ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ Return<void> hResult =
+ mPluginV1_1->getNumberOfSessions([&](Status status, uint32_t hOpen, uint32_t hMax) {
+ if (status == Status::OK) {
+ *open = hOpen;
+ *max = hMax;
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::getSecurityLevel(Vector<uint8_t> const& sessionId,
+ DrmPlugin::SecurityLevel* level) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ if (level == NULL) {
+ return BAD_VALUE;
+ }
+ status_t err = UNKNOWN_ERROR;
+
+ if (mPluginV1_1 == NULL) {
+ return ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ *level = DrmPlugin::kSecurityLevelUnknown;
+
+ Return<void> hResult = mPluginV1_1->getSecurityLevel(toHidlVec(sessionId),
+ [&](Status status, SecurityLevel hLevel) {
+ if (status == Status::OK) {
+ *level = toSecurityLevel(hLevel);
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::getOfflineLicenseKeySetIds(List<Vector<uint8_t>>& keySetIds) const {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ if (mPluginV1_2 == NULL) {
+ return ERROR_UNSUPPORTED;
+ }
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult = mPluginV1_2->getOfflineLicenseKeySetIds(
+ [&](Status status, const hidl_vec<KeySetId>& hKeySetIds) {
+ if (status == Status::OK) {
+ keySetIds = toKeySetIds(hKeySetIds);
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::removeOfflineLicense(Vector<uint8_t> const& keySetId) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ if (mPluginV1_2 == NULL) {
+ return ERROR_UNSUPPORTED;
+ }
+
+ Return<Status> status = mPluginV1_2->removeOfflineLicense(toHidlVec(keySetId));
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::getOfflineLicenseState(Vector<uint8_t> const& keySetId,
+ DrmPlugin::OfflineLicenseState* licenseState) const {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ if (mPluginV1_2 == NULL) {
+ return ERROR_UNSUPPORTED;
+ }
+ *licenseState = DrmPlugin::kOfflineLicenseStateUnknown;
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult = mPluginV1_2->getOfflineLicenseState(
+ toHidlVec(keySetId), [&](Status status, OfflineLicenseState hLicenseState) {
+ if (status == Status::OK) {
+ *licenseState = toOfflineLicenseState(hLicenseState);
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::getPropertyString(String8 const& name, String8& value) const {
+ Mutex::Autolock autoLock(mLock);
+ return getPropertyStringInternal(name, value);
+}
+
+status_t DrmHalHidl::getPropertyStringInternal(String8 const& name, String8& value) const {
+ // This function is internal to the class and should only be called while
+ // mLock is already held.
+ INIT_CHECK();
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult = mPlugin->getPropertyString(
+ toHidlString(name), [&](Status status, const hidl_string& hValue) {
+ if (status == Status::OK) {
+ value = toString8(hValue);
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::getPropertyByteArray(String8 const& name, Vector<uint8_t>& value) const {
+ Mutex::Autolock autoLock(mLock);
+ return getPropertyByteArrayInternal(name, value);
+}
+
+status_t DrmHalHidl::getPropertyByteArrayInternal(String8 const& name,
+ Vector<uint8_t>& value) const {
+ // This function is internal to the class and should only be called while
+ // mLock is already held.
+ INIT_CHECK();
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult = mPlugin->getPropertyByteArray(
+ toHidlString(name), [&](Status status, const hidl_vec<uint8_t>& hValue) {
+ if (status == Status::OK) {
+ value = toVector(hValue);
+ }
+ err = toStatusT(status);
+ });
+
+ err = hResult.isOk() ? err : DEAD_OBJECT;
+ if (name == kPropertyDeviceUniqueId) {
+ mMetrics.mGetDeviceUniqueIdCounter.Increment(err);
+ }
+ return err;
+}
+
+status_t DrmHalHidl::setPropertyString(String8 const& name, String8 const& value) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ Return<Status> status = mPlugin->setPropertyString(toHidlString(name), toHidlString(value));
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::setPropertyByteArray(String8 const& name, Vector<uint8_t> const& value) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ Return<Status> status = mPlugin->setPropertyByteArray(toHidlString(name), toHidlVec(value));
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::getMetrics(const sp<IDrmMetricsConsumer>& consumer) {
+ if (consumer == nullptr) {
+ return UNEXPECTED_NULL;
+ }
+ consumer->consumeFrameworkMetrics(mMetrics);
+
+ // Append vendor metrics if they are supported.
+ if (mPluginV1_1 != NULL) {
+ String8 vendor;
+ String8 description;
+ if (getPropertyStringInternal(String8("vendor"), vendor) != OK || vendor.isEmpty()) {
+ ALOGE("Get vendor failed or is empty");
+ vendor = "NONE";
+ }
+ if (getPropertyStringInternal(String8("description"), description) != OK ||
+ description.isEmpty()) {
+ ALOGE("Get description failed or is empty.");
+ description = "NONE";
+ }
+ vendor += ".";
+ vendor += description;
+
+ hidl_vec<DrmMetricGroup> pluginMetrics;
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> status =
+ mPluginV1_1->getMetrics([&](Status status, hidl_vec<DrmMetricGroup> pluginMetrics) {
+ if (status != Status::OK) {
+ ALOGV("Error getting plugin metrics: %d", status);
+ } else {
+ consumer->consumeHidlMetrics(vendor, pluginMetrics);
+ }
+ err = toStatusT(status);
+ });
+ return status.isOk() ? err : DEAD_OBJECT;
+ }
+
+ return OK;
+}
+
+status_t DrmHalHidl::setCipherAlgorithm(Vector<uint8_t> const& sessionId,
+ String8 const& algorithm) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ Return<Status> status =
+ mPlugin->setCipherAlgorithm(toHidlVec(sessionId), toHidlString(algorithm));
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::setMacAlgorithm(Vector<uint8_t> const& sessionId, String8 const& algorithm) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ Return<Status> status = mPlugin->setMacAlgorithm(toHidlVec(sessionId), toHidlString(algorithm));
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::encrypt(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& input, Vector<uint8_t> const& iv,
+ Vector<uint8_t>& output) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult =
+ mPlugin->encrypt(toHidlVec(sessionId), toHidlVec(keyId), toHidlVec(input),
+ toHidlVec(iv), [&](Status status, const hidl_vec<uint8_t>& hOutput) {
+ if (status == Status::OK) {
+ output = toVector(hOutput);
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::decrypt(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& input, Vector<uint8_t> const& iv,
+ Vector<uint8_t>& output) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult =
+ mPlugin->decrypt(toHidlVec(sessionId), toHidlVec(keyId), toHidlVec(input),
+ toHidlVec(iv), [&](Status status, const hidl_vec<uint8_t>& hOutput) {
+ if (status == Status::OK) {
+ output = toVector(hOutput);
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::sign(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& message, Vector<uint8_t>& signature) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult = mPlugin->sign(toHidlVec(sessionId), toHidlVec(keyId), toHidlVec(message),
+ [&](Status status, const hidl_vec<uint8_t>& hSignature) {
+ if (status == Status::OK) {
+ signature = toVector(hSignature);
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::verify(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& message, Vector<uint8_t> const& signature,
+ bool& match) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult =
+ mPlugin->verify(toHidlVec(sessionId), toHidlVec(keyId), toHidlVec(message),
+ toHidlVec(signature), [&](Status status, bool hMatch) {
+ if (status == Status::OK) {
+ match = hMatch;
+ } else {
+ match = false;
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::signRSA(Vector<uint8_t> const& sessionId, String8 const& algorithm,
+ Vector<uint8_t> const& message, Vector<uint8_t> const& wrappedKey,
+ Vector<uint8_t>& signature) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult = mPlugin->signRSA(
+ toHidlVec(sessionId), toHidlString(algorithm), toHidlVec(message),
+ toHidlVec(wrappedKey), [&](Status status, const hidl_vec<uint8_t>& hSignature) {
+ if (status == Status::OK) {
+ signature = toVector(hSignature);
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+std::string DrmHalHidl::reportFrameworkMetrics(const std::string& pluginMetrics) const {
+ mediametrics_handle_t item(mediametrics_create("mediadrm"));
+ mediametrics_setUid(item, mMetrics.GetAppUid());
+ String8 vendor;
+ String8 description;
+ status_t result = getPropertyStringInternal(String8("vendor"), vendor);
+ if (result != OK) {
+ ALOGE("Failed to get vendor from drm plugin: %d", result);
+ } else {
+ mediametrics_setCString(item, "vendor", vendor.c_str());
+ }
+ result = getPropertyStringInternal(String8("description"), description);
+ if (result != OK) {
+ ALOGE("Failed to get description from drm plugin: %d", result);
+ } else {
+ mediametrics_setCString(item, "description", description.c_str());
+ }
+
+ std::string serializedMetrics;
+ result = mMetrics.GetSerializedMetrics(&serializedMetrics);
+ if (result != OK) {
+ ALOGE("Failed to serialize framework metrics: %d", result);
+ }
+ std::string b64EncodedMetrics =
+ toBase64StringNoPad(serializedMetrics.data(), serializedMetrics.size());
+ if (!b64EncodedMetrics.empty()) {
+ mediametrics_setCString(item, "serialized_metrics", b64EncodedMetrics.c_str());
+ }
+ if (!pluginMetrics.empty()) {
+ mediametrics_setCString(item, "plugin_metrics", pluginMetrics.c_str());
+ }
+ if (!mediametrics_selfRecord(item)) {
+ ALOGE("Failed to self record framework metrics");
+ }
+ mediametrics_delete(item);
+ return serializedMetrics;
+}
+
+std::string DrmHalHidl::reportPluginMetrics() const {
+ Vector<uint8_t> metricsVector;
+ String8 vendor;
+ String8 description;
+ std::string metricsString;
+ if (getPropertyStringInternal(String8("vendor"), vendor) == OK &&
+ getPropertyStringInternal(String8("description"), description) == OK &&
+ getPropertyByteArrayInternal(String8("metrics"), metricsVector) == OK) {
+ metricsString = toBase64StringNoPad(metricsVector.array(), metricsVector.size());
+ status_t res = android::reportDrmPluginMetrics(metricsString, vendor, description,
+ mMetrics.GetAppUid());
+ if (res != OK) {
+ ALOGE("Metrics were retrieved but could not be reported: %d", res);
+ }
+ }
+ return metricsString;
+}
+
+status_t DrmHalHidl::requiresSecureDecoder(const char* mime, bool* required) const {
+ Mutex::Autolock autoLock(mLock);
+ if (mPluginV1_4 == NULL) {
+ return false;
+ }
+ auto hResult = mPluginV1_4->requiresSecureDecoderDefault(hidl_string(mime));
+ if (!hResult.isOk()) {
+ DrmUtils::LOG2BE("requiresSecureDecoder txn failed: %s", hResult.description().c_str());
+ return DEAD_OBJECT;
+ }
+ if (required) {
+ *required = hResult;
+ }
+ return OK;
+}
+
+status_t DrmHalHidl::requiresSecureDecoder(const char* mime, DrmPlugin::SecurityLevel securityLevel,
+ bool* required) const {
+ Mutex::Autolock autoLock(mLock);
+ if (mPluginV1_4 == NULL) {
+ return false;
+ }
+ auto hLevel = toHidlSecurityLevel(securityLevel);
+ auto hResult = mPluginV1_4->requiresSecureDecoder(hidl_string(mime), hLevel);
+ if (!hResult.isOk()) {
+ DrmUtils::LOG2BE("requiresSecureDecoder txn failed: %s", hResult.description().c_str());
+ return DEAD_OBJECT;
+ }
+ if (required) {
+ *required = hResult;
+ }
+ return OK;
+}
+
+status_t DrmHalHidl::setPlaybackId(Vector<uint8_t> const& sessionId, const char* playbackId) {
+ Mutex::Autolock autoLock(mLock);
+ if (mPluginV1_4 == NULL) {
+ return ERROR_UNSUPPORTED;
+ }
+ auto err = mPluginV1_4->setPlaybackId(toHidlVec(sessionId), hidl_string(playbackId));
+ return err.isOk() ? toStatusT(err) : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::getLogMessages(Vector<drm::V1_4::LogMessage>& logs) const {
+ Mutex::Autolock autoLock(mLock);
+ return DrmUtils::GetLogMessages<drm::V1_4::IDrmPlugin>(mPlugin, logs);
+}
+
+} // namespace android
diff --git a/drm/libmediadrm/DrmHalListener.cpp b/drm/libmediadrm/DrmHalListener.cpp
new file mode 100644
index 0000000..cfcf475
--- /dev/null
+++ b/drm/libmediadrm/DrmHalListener.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2022 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 "DrmHalListener"
+
+#include <mediadrm/DrmHalListener.h>
+
+using ::aidl::android::hardware::drm::KeyStatusType;
+using ::android::hardware::hidl_vec;
+
+namespace android {
+
+static const Vector<uint8_t> toVector(const std::vector<uint8_t>& vec) {
+ Vector<uint8_t> vector;
+ vector.appendArray(vec.data(), vec.size());
+ return *const_cast<const Vector<uint8_t>*>(&vector);
+}
+
+template <typename T = uint8_t>
+static hidl_vec<T> toHidlVec(const Vector<T>& vector) {
+ hidl_vec<T> vec;
+ vec.setToExternal(const_cast<T*>(vector.array()), vector.size());
+ return vec;
+}
+
+DrmHalListener::DrmHalListener(MediaDrmMetrics* metrics)
+ : mMetrics(metrics) {}
+
+DrmHalListener::~DrmHalListener() {}
+
+void DrmHalListener::setListener(sp<IDrmClient> listener) {
+ Mutex::Autolock lock(mEventLock);
+ mListener = listener;
+}
+
+::ndk::ScopedAStatus DrmHalListener::onEvent(EventTypeAidl eventTypeAidl,
+ const std::vector<uint8_t>& sessionId,
+ const std::vector<uint8_t>& data) {
+ mMetrics->mEventCounter.Increment((uint32_t)eventTypeAidl);
+
+ mEventLock.lock();
+ sp<IDrmClient> listener = mListener;
+ mEventLock.unlock();
+
+ if (listener != NULL) {
+ Mutex::Autolock lock(mNotifyLock);
+ DrmPlugin::EventType eventType;
+ switch (eventTypeAidl) {
+ case EventTypeAidl::PROVISION_REQUIRED:
+ eventType = DrmPlugin::kDrmPluginEventProvisionRequired;
+ break;
+ case EventTypeAidl::KEY_NEEDED:
+ eventType = DrmPlugin::kDrmPluginEventKeyNeeded;
+ break;
+ case EventTypeAidl::KEY_EXPIRED:
+ eventType = DrmPlugin::kDrmPluginEventKeyExpired;
+ break;
+ case EventTypeAidl::VENDOR_DEFINED:
+ eventType = DrmPlugin::kDrmPluginEventVendorDefined;
+ break;
+ case EventTypeAidl::SESSION_RECLAIMED:
+ eventType = DrmPlugin::kDrmPluginEventSessionReclaimed;
+ break;
+ default:
+ return ::ndk::ScopedAStatus::ok();
+ }
+
+ listener->sendEvent(eventType, toHidlVec(toVector(sessionId)), toHidlVec(toVector(data)));
+ }
+
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus DrmHalListener::onExpirationUpdate(const std::vector<uint8_t>& sessionId,
+ int64_t expiryTimeInMS) {
+ mEventLock.lock();
+ sp<IDrmClient> listener = mListener;
+ mEventLock.unlock();
+
+ if (listener != NULL) {
+ Mutex::Autolock lock(mNotifyLock);
+ listener->sendExpirationUpdate(toHidlVec(toVector(sessionId)), expiryTimeInMS);
+ }
+
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus DrmHalListener::onKeysChange(const std::vector<uint8_t>& sessionId,
+ const std::vector<KeyStatusAidl>& keyStatusListAidl,
+ bool hasNewUsableKey) {
+ mEventLock.lock();
+ sp<IDrmClient> listener = mListener;
+ mEventLock.unlock();
+
+ if (listener != NULL) {
+ std::vector<DrmKeyStatus> keyStatusList;
+ size_t nKeys = keyStatusListAidl.size();
+ for (size_t i = 0; i < nKeys; ++i) {
+ const KeyStatusAidl keyStatus = keyStatusListAidl[i];
+ uint32_t type;
+ switch (keyStatus.type) {
+ case KeyStatusType::USABLE:
+ type = DrmPlugin::kKeyStatusType_Usable;
+ break;
+ case KeyStatusType::EXPIRED:
+ type = DrmPlugin::kKeyStatusType_Expired;
+ break;
+ case KeyStatusType::OUTPUT_NOT_ALLOWED:
+ type = DrmPlugin::kKeyStatusType_OutputNotAllowed;
+ break;
+ case KeyStatusType::STATUS_PENDING:
+ type = DrmPlugin::kKeyStatusType_StatusPending;
+ break;
+ case KeyStatusType::USABLE_IN_FUTURE:
+ type = DrmPlugin::kKeyStatusType_UsableInFuture;
+ break;
+ case KeyStatusType::INTERNAL_ERROR:
+ default:
+ type = DrmPlugin::kKeyStatusType_InternalError;
+ break;
+ }
+ keyStatusList.push_back({type, toHidlVec(toVector(keyStatus.keyId))});
+ mMetrics->mKeyStatusChangeCounter.Increment((uint32_t)keyStatus.type);
+ }
+
+ Mutex::Autolock lock(mNotifyLock);
+ listener->sendKeysChange(toHidlVec(toVector(sessionId)), keyStatusList, hasNewUsableKey);
+ }
+ else {
+ // There's no listener. But we still want to count the key change
+ // events.
+ size_t nKeys = keyStatusListAidl.size();
+
+ for (size_t i = 0; i < nKeys; i++) {
+ mMetrics->mKeyStatusChangeCounter.Increment((uint32_t)keyStatusListAidl[i].type);
+ }
+ }
+
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus DrmHalListener::onSessionLostState(const std::vector<uint8_t>& sessionId) {
+ ::ndk::ScopedAStatus _aidl_status;
+ mEventLock.lock();
+ sp<IDrmClient> listener = mListener;
+ mEventLock.unlock();
+
+ if (listener != NULL) {
+ Mutex::Autolock lock(mNotifyLock);
+ listener->sendSessionLostState(toHidlVec(toVector(sessionId)));
+ }
+
+ return ::ndk::ScopedAStatus::ok();
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/drm/libmediadrm/DrmMetrics.cpp b/drm/libmediadrm/DrmMetrics.cpp
index 996fd19..77b5343 100644
--- a/drm/libmediadrm/DrmMetrics.cpp
+++ b/drm/libmediadrm/DrmMetrics.cpp
@@ -123,20 +123,19 @@
});
mKeyStatusChangeCounter.ExportValues(
- [&](const KeyStatusType key_status_type, const int64_t value) {
+ [&](const uint32_t key_status_type, const int64_t value) {
DrmFrameworkMetrics::Counter *counter =
metrics.add_key_status_change_counter();
counter->set_count(value);
- counter->mutable_attributes()->set_key_status_type(
- (uint32_t)key_status_type);
+ counter->mutable_attributes()->set_key_status_type(key_status_type);
});
mEventCounter.ExportValues(
- [&](const EventType event_type, const int64_t value) {
+ [&](const uint32_t event_type, const int64_t value) {
DrmFrameworkMetrics::Counter *counter =
metrics.add_event_callback_counter();
counter->set_count(value);
- counter->mutable_attributes()->set_event_type((uint32_t)event_type);
+ counter->mutable_attributes()->set_event_type(event_type);
});
mGetDeviceUniqueIdCounter.ExportValues(
diff --git a/drm/libmediadrm/DrmMetricsConsumer.cpp b/drm/libmediadrm/DrmMetricsConsumer.cpp
index 5f0b26e..c06f09b 100644
--- a/drm/libmediadrm/DrmMetricsConsumer.cpp
+++ b/drm/libmediadrm/DrmMetricsConsumer.cpp
@@ -32,26 +32,24 @@
namespace {
-template <typename T> std::string GetAttributeName(T type);
-
-template <> std::string GetAttributeName<KeyStatusType>(KeyStatusType type) {
- static const char *type_names[] = {"USABLE", "EXPIRED",
+std::string GetAttributeName(const std::string &typeName, uint32_t attribute) {
+ if (typeName == "KeyStatusChange") {
+ static const char *type_names[] = {"USABLE", "EXPIRED",
"OUTPUT_NOT_ALLOWED", "STATUS_PENDING",
"INTERNAL_ERROR", "USABLE_IN_FUTURE"};
- if (((size_t)type) >= arraysize(type_names)) {
- return "UNKNOWN_TYPE";
+ if (attribute >= arraysize(type_names)) {
+ return "UNKNOWN_TYPE";
+ }
+ return type_names[attribute];
}
- 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)) {
+ if (attribute >= arraysize(type_names)) {
return "UNKNOWN_TYPE";
}
- return type_names[(size_t)type];
+ return type_names[attribute];
}
template <typename T>
@@ -87,14 +85,14 @@
template <typename T>
void ExportCounterMetricWithAttributeNames(
- const android::CounterMetric<T> &counter, PersistableBundle *metrics) {
+ const android::CounterMetric<T> &counter, const std::string &typeName, PersistableBundle *metrics) {
if (!metrics) {
ALOGE("metrics was unexpectedly null.");
return;
}
- counter.ExportValues([&](const T &attribute, const int64_t value) {
+ counter.ExportValues([&](const uint32_t attribute, const int64_t value) {
std::string name = counter.metric_name() + "." +
- GetAttributeName(attribute) + ".count";
+ GetAttributeName(typeName, attribute) + ".count";
metrics->putLong(android::String16(name.c_str()), value);
});
}
@@ -196,8 +194,8 @@
ExportEventMetric(metrics.mProvideKeyResponseTimeUs, mBundle);
ExportCounterMetric(metrics.mGetProvisionRequestCounter, mBundle);
ExportCounterMetric(metrics.mProvideProvisionResponseCounter, mBundle);
- ExportCounterMetricWithAttributeNames(metrics.mKeyStatusChangeCounter, mBundle);
- ExportCounterMetricWithAttributeNames(metrics.mEventCounter, mBundle);
+ ExportCounterMetricWithAttributeNames(metrics.mKeyStatusChangeCounter, "KeyStatusChange", mBundle);
+ ExportCounterMetricWithAttributeNames(metrics.mEventCounter, "Event", mBundle);
ExportCounterMetric(metrics.mGetDeviceUniqueIdCounter, mBundle);
ExportSessionLifespans(metrics.GetSessionLifespans(), mBundle);
return android::OK;
diff --git a/drm/libmediadrm/DrmUtils.cpp b/drm/libmediadrm/DrmUtils.cpp
index 0b117a3..731755b 100644
--- a/drm/libmediadrm/DrmUtils.cpp
+++ b/drm/libmediadrm/DrmUtils.cpp
@@ -17,6 +17,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "DrmUtils"
+#include <android/binder_manager.h>
#include <android/hardware/drm/1.0/ICryptoFactory.h>
#include <android/hardware/drm/1.0/ICryptoPlugin.h>
#include <android/hardware/drm/1.0/IDrmFactory.h>
@@ -32,10 +33,10 @@
#include <android/hidl/manager/1.2/IServiceManager.h>
#include <hidl/HidlSupport.h>
+#include <cutils/properties.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/String16.h>
-#include <cutils/properties.h>
#include <mediadrm/CryptoHal.h>
#include <mediadrm/DrmHal.h>
@@ -57,10 +58,10 @@
namespace {
-template<typename Hal>
-Hal *MakeObject(status_t *pstatus) {
+template <typename Hal>
+Hal* MakeObject(status_t* pstatus) {
status_t err = OK;
- status_t &status = pstatus ? *pstatus : err;
+ status_t& status = pstatus ? *pstatus : err;
auto obj = new Hal();
status = obj->initCheck();
if (status != OK && status != NO_INIT) {
@@ -70,43 +71,44 @@
}
template <typename Hal, typename V, typename M>
-void MakeHidlFactories(const uint8_t uuid[16], V &factories, M& instances) {
+void MakeHidlFactories(const uint8_t uuid[16], V& factories, M& instances) {
sp<HServiceManager> serviceManager = HServiceManager::getService();
if (serviceManager == nullptr) {
LOG2BE("Failed to get service manager");
return;
}
- serviceManager->listManifestByInterface(Hal::descriptor, [&](const hidl_vec<hidl_string> ®istered) {
- for (const auto &instance : registered) {
- auto factory = Hal::getService(instance);
- if (factory != nullptr) {
- instances[instance.c_str()] = Hal::descriptor;
- if (!uuid) {
- factories.push_back(factory);
- continue;
+ serviceManager->listManifestByInterface(
+ Hal::descriptor, [&](const hidl_vec<hidl_string>& registered) {
+ for (const auto& instance : registered) {
+ auto factory = Hal::getService(instance);
+ if (factory != nullptr) {
+ instances[instance.c_str()] = Hal::descriptor;
+ if (!uuid) {
+ factories.push_back(factory);
+ continue;
+ }
+ auto supported = factory->isCryptoSchemeSupported(uuid);
+ if (!supported.isOk()) {
+ LOG2BE(uuid, "isCryptoSchemeSupported txn failed: %s",
+ supported.description().c_str());
+ continue;
+ }
+ if (supported) {
+ factories.push_back(factory);
+ }
+ }
}
- auto supported = factory->isCryptoSchemeSupported(uuid);
- if (!supported.isOk()) {
- LOG2BE(uuid, "isCryptoSchemeSupported txn failed: %s",
- supported.description().c_str());
- continue;
- }
- if (supported) {
- factories.push_back(factory);
- }
- }
- }
- });
+ });
}
template <typename Hal, typename V>
-void MakeHidlFactories(const uint8_t uuid[16], V &factories) {
+void MakeHidlFactories(const uint8_t uuid[16], V& factories) {
std::map<std::string, std::string> instances;
MakeHidlFactories<Hal>(uuid, factories, instances);
}
-hidl_vec<uint8_t> toHidlVec(const void *ptr, size_t size) {
+hidl_vec<uint8_t> toHidlVec(const void* ptr, size_t size) {
hidl_vec<uint8_t> vec(size);
if (ptr != nullptr) {
memcpy(vec.data(), ptr, size);
@@ -114,19 +116,19 @@
return vec;
}
-hidl_array<uint8_t, 16> toHidlArray16(const uint8_t *ptr) {
+hidl_array<uint8_t, 16> toHidlArray16(const uint8_t* ptr) {
if (ptr == nullptr) {
return hidl_array<uint8_t, 16>();
}
return hidl_array<uint8_t, 16>(ptr);
}
-sp<::V1_0::IDrmPlugin> MakeDrmPlugin(const sp<::V1_0::IDrmFactory> &factory,
- const uint8_t uuid[16], const char *appPackageName) {
+sp<::V1_0::IDrmPlugin> MakeDrmPlugin(const sp<::V1_0::IDrmFactory>& factory, const uint8_t uuid[16],
+ const char* appPackageName) {
sp<::V1_0::IDrmPlugin> plugin;
auto err = factory->createPlugin(
toHidlArray16(uuid), hidl_string(appPackageName),
- [&](::V1_0::Status status, const sp<::V1_0::IDrmPlugin> &hPlugin) {
+ [&](::V1_0::Status status, const sp<::V1_0::IDrmPlugin>& hPlugin) {
if (status != ::V1_0::Status::OK) {
LOG2BE(uuid, "MakeDrmPlugin failed: %d", status);
return;
@@ -141,13 +143,13 @@
}
}
-sp<::V1_0::ICryptoPlugin> MakeCryptoPlugin(const sp<::V1_0::ICryptoFactory> &factory,
- const uint8_t uuid[16], const void *initData,
+sp<::V1_0::ICryptoPlugin> MakeCryptoPlugin(const sp<::V1_0::ICryptoFactory>& factory,
+ const uint8_t uuid[16], const void* initData,
size_t initDataSize) {
sp<::V1_0::ICryptoPlugin> plugin;
auto err = factory->createPlugin(
toHidlArray16(uuid), toHidlVec(initData, initDataSize),
- [&](::V1_0::Status status, const sp<::V1_0::ICryptoPlugin> &hPlugin) {
+ [&](::V1_0::Status status, const sp<::V1_0::ICryptoPlugin>& hPlugin) {
if (status != ::V1_0::Status::OK) {
LOG2BE(uuid, "MakeCryptoPlugin failed: %d", status);
return;
@@ -162,17 +164,38 @@
}
}
-} // namespace
+} // namespace
bool UseDrmService() {
return property_get_bool("mediadrm.use_mediadrmserver", true);
}
-sp<IDrm> MakeDrm(status_t *pstatus) {
+std::vector<std::shared_ptr<IDrmFactoryAidl>> makeDrmFactoriesAidl() {
+ std::vector<std::shared_ptr<IDrmFactoryAidl>> factories;
+ AServiceManager_forEachDeclaredInstance(
+ IDrmFactoryAidl::descriptor, static_cast<void*>(&factories),
+ [](const char* instance, void* context) {
+ auto fullName = std::string(IDrmFactoryAidl::descriptor) + "/" + std::string(instance);
+ auto factory = IDrmFactoryAidl::fromBinder(
+ ::ndk::SpAIBinder(AServiceManager_getService(fullName.c_str())));
+ if (factory == nullptr) {
+ ALOGE("not found IDrmFactory. Instance name:[%s]", fullName.c_str());
+ return;
+ }
+
+ ALOGI("found IDrmFactory. Instance name:[%s]", fullName.c_str());
+ static_cast<std::vector<std::shared_ptr<IDrmFactoryAidl>>*>(context)->emplace_back(
+ factory);
+ });
+
+ return factories;
+}
+
+sp<IDrm> MakeDrm(status_t* pstatus) {
return MakeObject<DrmHal>(pstatus);
}
-sp<ICrypto> MakeCrypto(status_t *pstatus) {
+sp<ICrypto> MakeCrypto(status_t* pstatus) {
return MakeObject<CryptoHal>(pstatus);
}
@@ -191,9 +214,9 @@
}
std::vector<sp<::V1_0::IDrmPlugin>> MakeDrmPlugins(const uint8_t uuid[16],
- const char *appPackageName) {
+ const char* appPackageName) {
std::vector<sp<::V1_0::IDrmPlugin>> plugins;
- for (const auto &factory : MakeDrmFactories(uuid)) {
+ for (const auto& factory : MakeDrmFactories(uuid)) {
plugins.push_back(MakeDrmPlugin(factory, uuid, appPackageName));
}
return plugins;
@@ -209,10 +232,11 @@
return cryptoFactories;
}
-std::vector<sp<ICryptoPlugin>> MakeCryptoPlugins(const uint8_t uuid[16], const void *initData,
- size_t initDataSize) {
- std::vector<sp<ICryptoPlugin>> plugins;
- for (const auto &factory : MakeCryptoFactories(uuid)) {
+std::vector<sp<::V1_0::ICryptoPlugin>> MakeCryptoPlugins(const uint8_t uuid[16],
+ const void* initData,
+ size_t initDataSize) {
+ std::vector<sp<::V1_0::ICryptoPlugin>> plugins;
+ for (const auto& factory : MakeCryptoFactories(uuid)) {
plugins.push_back(MakeCryptoPlugin(factory, uuid, initData, initDataSize));
}
return plugins;
@@ -220,90 +244,90 @@
status_t toStatusT_1_4(::V1_4::Status status) {
switch (status) {
- case ::V1_4::Status::OK:
- return OK;
- case ::V1_4::Status::BAD_VALUE:
- return BAD_VALUE;
- case ::V1_4::Status::ERROR_DRM_CANNOT_HANDLE:
- return ERROR_DRM_CANNOT_HANDLE;
- case ::V1_4::Status::ERROR_DRM_DECRYPT:
- return ERROR_DRM_DECRYPT;
- case ::V1_4::Status::ERROR_DRM_DEVICE_REVOKED:
- return ERROR_DRM_DEVICE_REVOKED;
- case ::V1_4::Status::ERROR_DRM_FRAME_TOO_LARGE:
- return ERROR_DRM_FRAME_TOO_LARGE;
- case ::V1_4::Status::ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
- return ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION;
- case ::V1_4::Status::ERROR_DRM_INSUFFICIENT_SECURITY:
- return ERROR_DRM_INSUFFICIENT_SECURITY;
- case ::V1_4::Status::ERROR_DRM_INVALID_STATE:
- return ERROR_DRM_INVALID_STATE;
- case ::V1_4::Status::ERROR_DRM_LICENSE_EXPIRED:
- return ERROR_DRM_LICENSE_EXPIRED;
- case ::V1_4::Status::ERROR_DRM_NO_LICENSE:
- return ERROR_DRM_NO_LICENSE;
- case ::V1_4::Status::ERROR_DRM_NOT_PROVISIONED:
- return ERROR_DRM_NOT_PROVISIONED;
- case ::V1_4::Status::ERROR_DRM_RESOURCE_BUSY:
- return ERROR_DRM_RESOURCE_BUSY;
- case ::V1_4::Status::ERROR_DRM_RESOURCE_CONTENTION:
- return ERROR_DRM_RESOURCE_CONTENTION;
- case ::V1_4::Status::ERROR_DRM_SESSION_LOST_STATE:
- return ERROR_DRM_SESSION_LOST_STATE;
- case ::V1_4::Status::ERROR_DRM_SESSION_NOT_OPENED:
- return ERROR_DRM_SESSION_NOT_OPENED;
+ case ::V1_4::Status::OK:
+ return OK;
+ case ::V1_4::Status::BAD_VALUE:
+ return BAD_VALUE;
+ case ::V1_4::Status::ERROR_DRM_CANNOT_HANDLE:
+ return ERROR_DRM_CANNOT_HANDLE;
+ case ::V1_4::Status::ERROR_DRM_DECRYPT:
+ return ERROR_DRM_DECRYPT;
+ case ::V1_4::Status::ERROR_DRM_DEVICE_REVOKED:
+ return ERROR_DRM_DEVICE_REVOKED;
+ case ::V1_4::Status::ERROR_DRM_FRAME_TOO_LARGE:
+ return ERROR_DRM_FRAME_TOO_LARGE;
+ case ::V1_4::Status::ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
+ return ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION;
+ case ::V1_4::Status::ERROR_DRM_INSUFFICIENT_SECURITY:
+ return ERROR_DRM_INSUFFICIENT_SECURITY;
+ case ::V1_4::Status::ERROR_DRM_INVALID_STATE:
+ return ERROR_DRM_INVALID_STATE;
+ case ::V1_4::Status::ERROR_DRM_LICENSE_EXPIRED:
+ return ERROR_DRM_LICENSE_EXPIRED;
+ case ::V1_4::Status::ERROR_DRM_NO_LICENSE:
+ return ERROR_DRM_NO_LICENSE;
+ case ::V1_4::Status::ERROR_DRM_NOT_PROVISIONED:
+ return ERROR_DRM_NOT_PROVISIONED;
+ case ::V1_4::Status::ERROR_DRM_RESOURCE_BUSY:
+ return ERROR_DRM_RESOURCE_BUSY;
+ case ::V1_4::Status::ERROR_DRM_RESOURCE_CONTENTION:
+ return ERROR_DRM_RESOURCE_CONTENTION;
+ case ::V1_4::Status::ERROR_DRM_SESSION_LOST_STATE:
+ return ERROR_DRM_SESSION_LOST_STATE;
+ case ::V1_4::Status::ERROR_DRM_SESSION_NOT_OPENED:
+ return ERROR_DRM_SESSION_NOT_OPENED;
- // New in S / drm@1.4:
- case ::V1_4::Status::CANNOT_DECRYPT_ZERO_SUBSAMPLES:
- return ERROR_DRM_ZERO_SUBSAMPLES;
- case ::V1_4::Status::CRYPTO_LIBRARY_ERROR:
- return ERROR_DRM_CRYPTO_LIBRARY;
- case ::V1_4::Status::GENERAL_OEM_ERROR:
- return ERROR_DRM_GENERIC_OEM;
- case ::V1_4::Status::GENERAL_PLUGIN_ERROR:
- return ERROR_DRM_GENERIC_PLUGIN;
- case ::V1_4::Status::INIT_DATA_INVALID:
- return ERROR_DRM_INIT_DATA;
- case ::V1_4::Status::KEY_NOT_LOADED:
- return ERROR_DRM_KEY_NOT_LOADED;
- case ::V1_4::Status::LICENSE_PARSE_ERROR:
- return ERROR_DRM_LICENSE_PARSE;
- case ::V1_4::Status::LICENSE_POLICY_ERROR:
- return ERROR_DRM_LICENSE_POLICY;
- case ::V1_4::Status::LICENSE_RELEASE_ERROR:
- return ERROR_DRM_LICENSE_RELEASE;
- case ::V1_4::Status::LICENSE_REQUEST_REJECTED:
- return ERROR_DRM_LICENSE_REQUEST_REJECTED;
- case ::V1_4::Status::LICENSE_RESTORE_ERROR:
- return ERROR_DRM_LICENSE_RESTORE;
- case ::V1_4::Status::LICENSE_STATE_ERROR:
- return ERROR_DRM_LICENSE_STATE;
- case ::V1_4::Status::MALFORMED_CERTIFICATE:
- return ERROR_DRM_CERTIFICATE_MALFORMED;
- case ::V1_4::Status::MEDIA_FRAMEWORK_ERROR:
- return ERROR_DRM_MEDIA_FRAMEWORK;
- case ::V1_4::Status::MISSING_CERTIFICATE:
- return ERROR_DRM_CERTIFICATE_MISSING;
- case ::V1_4::Status::PROVISIONING_CERTIFICATE_ERROR:
- return ERROR_DRM_PROVISIONING_CERTIFICATE;
- case ::V1_4::Status::PROVISIONING_CONFIGURATION_ERROR:
- return ERROR_DRM_PROVISIONING_CONFIG;
- case ::V1_4::Status::PROVISIONING_PARSE_ERROR:
- return ERROR_DRM_PROVISIONING_PARSE;
- case ::V1_4::Status::PROVISIONING_REQUEST_REJECTED:
- return ERROR_DRM_PROVISIONING_REQUEST_REJECTED;
- case ::V1_4::Status::RETRYABLE_PROVISIONING_ERROR:
- return ERROR_DRM_PROVISIONING_RETRY;
- case ::V1_4::Status::SECURE_STOP_RELEASE_ERROR:
- return ERROR_DRM_SECURE_STOP_RELEASE;
- case ::V1_4::Status::STORAGE_READ_FAILURE:
- return ERROR_DRM_STORAGE_READ;
- case ::V1_4::Status::STORAGE_WRITE_FAILURE:
- return ERROR_DRM_STORAGE_WRITE;
+ // New in S / drm@1.4:
+ case ::V1_4::Status::CANNOT_DECRYPT_ZERO_SUBSAMPLES:
+ return ERROR_DRM_ZERO_SUBSAMPLES;
+ case ::V1_4::Status::CRYPTO_LIBRARY_ERROR:
+ return ERROR_DRM_CRYPTO_LIBRARY;
+ case ::V1_4::Status::GENERAL_OEM_ERROR:
+ return ERROR_DRM_GENERIC_OEM;
+ case ::V1_4::Status::GENERAL_PLUGIN_ERROR:
+ return ERROR_DRM_GENERIC_PLUGIN;
+ case ::V1_4::Status::INIT_DATA_INVALID:
+ return ERROR_DRM_INIT_DATA;
+ case ::V1_4::Status::KEY_NOT_LOADED:
+ return ERROR_DRM_KEY_NOT_LOADED;
+ case ::V1_4::Status::LICENSE_PARSE_ERROR:
+ return ERROR_DRM_LICENSE_PARSE;
+ case ::V1_4::Status::LICENSE_POLICY_ERROR:
+ return ERROR_DRM_LICENSE_POLICY;
+ case ::V1_4::Status::LICENSE_RELEASE_ERROR:
+ return ERROR_DRM_LICENSE_RELEASE;
+ case ::V1_4::Status::LICENSE_REQUEST_REJECTED:
+ return ERROR_DRM_LICENSE_REQUEST_REJECTED;
+ case ::V1_4::Status::LICENSE_RESTORE_ERROR:
+ return ERROR_DRM_LICENSE_RESTORE;
+ case ::V1_4::Status::LICENSE_STATE_ERROR:
+ return ERROR_DRM_LICENSE_STATE;
+ case ::V1_4::Status::MALFORMED_CERTIFICATE:
+ return ERROR_DRM_CERTIFICATE_MALFORMED;
+ case ::V1_4::Status::MEDIA_FRAMEWORK_ERROR:
+ return ERROR_DRM_MEDIA_FRAMEWORK;
+ case ::V1_4::Status::MISSING_CERTIFICATE:
+ return ERROR_DRM_CERTIFICATE_MISSING;
+ case ::V1_4::Status::PROVISIONING_CERTIFICATE_ERROR:
+ return ERROR_DRM_PROVISIONING_CERTIFICATE;
+ case ::V1_4::Status::PROVISIONING_CONFIGURATION_ERROR:
+ return ERROR_DRM_PROVISIONING_CONFIG;
+ case ::V1_4::Status::PROVISIONING_PARSE_ERROR:
+ return ERROR_DRM_PROVISIONING_PARSE;
+ case ::V1_4::Status::PROVISIONING_REQUEST_REJECTED:
+ return ERROR_DRM_PROVISIONING_REQUEST_REJECTED;
+ case ::V1_4::Status::RETRYABLE_PROVISIONING_ERROR:
+ return ERROR_DRM_PROVISIONING_RETRY;
+ case ::V1_4::Status::SECURE_STOP_RELEASE_ERROR:
+ return ERROR_DRM_SECURE_STOP_RELEASE;
+ case ::V1_4::Status::STORAGE_READ_FAILURE:
+ return ERROR_DRM_STORAGE_READ;
+ case ::V1_4::Status::STORAGE_WRITE_FAILURE:
+ return ERROR_DRM_STORAGE_WRITE;
- case ::V1_4::Status::ERROR_DRM_UNKNOWN:
- default:
- return ERROR_DRM_UNKNOWN;
+ case ::V1_4::Status::ERROR_DRM_UNKNOWN:
+ default:
+ return ERROR_DRM_UNKNOWN;
}
return ERROR_DRM_UNKNOWN;
}
@@ -312,20 +336,34 @@
char logPriorityToChar(::V1_4::LogPriority priority) {
char p = 'U';
switch (priority) {
- case ::V1_4::LogPriority::VERBOSE: p = 'V'; break;
- case ::V1_4::LogPriority::DEBUG: p = 'D'; break;
- case ::V1_4::LogPriority::INFO: p = 'I'; break;
- case ::V1_4::LogPriority::WARN: p = 'W'; break;
- case ::V1_4::LogPriority::ERROR: p = 'E'; break;
- case ::V1_4::LogPriority::FATAL: p = 'F'; break;
- default: p = 'U'; break;
+ case ::V1_4::LogPriority::VERBOSE:
+ p = 'V';
+ break;
+ case ::V1_4::LogPriority::DEBUG:
+ p = 'D';
+ break;
+ case ::V1_4::LogPriority::INFO:
+ p = 'I';
+ break;
+ case ::V1_4::LogPriority::WARN:
+ p = 'W';
+ break;
+ case ::V1_4::LogPriority::ERROR:
+ p = 'E';
+ break;
+ case ::V1_4::LogPriority::FATAL:
+ p = 'F';
+ break;
+ default:
+ p = 'U';
+ break;
}
return p;
}
} // namespace
-std::string GetExceptionMessage(status_t err, const char *msg,
- const Vector<::V1_4::LogMessage> &logs) {
+std::string GetExceptionMessage(status_t err, const char* msg,
+ const Vector<::V1_4::LogMessage>& logs) {
std::string ruler("==============================");
std::string header("Beginning of DRM Plugin Log");
std::string footer("End of DRM Plugin Log");
@@ -355,7 +393,7 @@
return msg8.c_str();
}
-void LogBuffer::addLog(const ::V1_4::LogMessage &log) {
+void LogBuffer::addLog(const ::V1_4::LogMessage& log) {
std::unique_lock<std::mutex> lock(mMutex);
mBuffer.push_back(log);
while (mBuffer.size() > MAX_CAPACITY) {
diff --git a/drm/libmediadrm/fuzzer/Android.bp b/drm/libmediadrm/fuzzer/Android.bp
index 49bbad4..a85e3cf 100644
--- a/drm/libmediadrm/fuzzer/Android.bp
+++ b/drm/libmediadrm/fuzzer/Android.bp
@@ -36,6 +36,7 @@
"libmediadrm",
"liblog",
"resourcemanager_aidl_interface-ndk",
+ "libaidlcommonsupport",
],
header_libs: [
"libmedia_headers",
@@ -59,6 +60,7 @@
"android.hardware.drm@1.4",
"libhidlallocatorutils",
"libhidlbase",
+ "android.hardware.drm-V1-ndk",
],
fuzz_config: {
cc: [
diff --git a/drm/libmediadrm/fuzzer/mediadrm_fuzzer.cpp b/drm/libmediadrm/fuzzer/mediadrm_fuzzer.cpp
index 8df0477..eabd41f 100644
--- a/drm/libmediadrm/fuzzer/mediadrm_fuzzer.cpp
+++ b/drm/libmediadrm/fuzzer/mediadrm_fuzzer.cpp
@@ -24,6 +24,8 @@
#include <mediadrm/DrmHal.h>
#include <utils/String8.h>
#include "fuzzer/FuzzedDataProvider.h"
+#include <binder/PersistableBundle.h>
+#include <android/hardware/drm/1.0/types.h>
#define AES_BLOCK_SIZE 16
#define UNUSED_PARAM __attribute__((unused))
@@ -33,6 +35,7 @@
using android::hardware::fromHeap;
using ::android::os::PersistableBundle;
using drm::V1_0::BufferType;
+using ::android::hardware::drm::V1_0::DestinationBuffer;
enum {
INVALID_UUID = 0,
diff --git a/drm/libmediadrm/include/mediadrm/CryptoHal.h b/drm/libmediadrm/include/mediadrm/CryptoHal.h
index 5fd39e6..32a6741 100644
--- a/drm/libmediadrm/include/mediadrm/CryptoHal.h
+++ b/drm/libmediadrm/include/mediadrm/CryptoHal.h
@@ -15,25 +15,12 @@
*/
#ifndef CRYPTO_HAL_H_
-
#define CRYPTO_HAL_H_
-#include <android/hardware/drm/1.0/ICryptoFactory.h>
-#include <android/hardware/drm/1.0/ICryptoPlugin.h>
-#include <android/hardware/drm/1.1/ICryptoFactory.h>
-#include <android/hardware/drm/1.2/ICryptoPlugin.h>
-#include <android/hardware/drm/1.4/ICryptoPlugin.h>
-
#include <mediadrm/ICrypto.h>
#include <utils/KeyedVector.h>
#include <utils/threads.h>
-namespace drm = ::android::hardware::drm;
-using drm::V1_0::ICryptoFactory;
-using drm::V1_0::ICryptoPlugin;
-using drm::V1_0::SharedBuffer;
-using drm::V1_0::DestinationBuffer;
-
using ::android::hardware::HidlMemory;
class IMemoryHeap;
@@ -43,67 +30,30 @@
struct CryptoHal : public ICrypto {
CryptoHal();
virtual ~CryptoHal();
-
virtual status_t initCheck() const;
-
virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]);
-
virtual status_t createPlugin(
const uint8_t uuid[16], const void *data, size_t size);
-
virtual status_t destroyPlugin();
-
virtual bool requiresSecureDecoderComponent(
const char *mime) const;
-
virtual void notifyResolution(uint32_t width, uint32_t height);
-
virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId);
-
virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16],
CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
- const ::SharedBuffer &source, size_t offset,
+ const drm::V1_0::SharedBuffer &source, size_t offset,
const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
- const ::DestinationBuffer &destination,
+ const drm::V1_0::DestinationBuffer &destination,
AString *errorDetailMsg);
-
- virtual int32_t setHeap(const sp<HidlMemory>& heap) {
- return setHeapBase(heap);
- }
- virtual void unsetHeap(int32_t seqNum) { clearHeapBase(seqNum); }
-
+ virtual int32_t setHeap(const sp<HidlMemory>& heap);
+ virtual void unsetHeap(int32_t seqNum);
virtual status_t getLogMessages(Vector<drm::V1_4::LogMessage> &logs) const;
-
private:
- mutable Mutex mLock;
-
- const Vector<sp<ICryptoFactory>> mFactories;
- sp<ICryptoPlugin> mPlugin;
- sp<drm::V1_2::ICryptoPlugin> mPluginV1_2;
-
- /**
- * mInitCheck is:
- * NO_INIT if a plugin hasn't been created yet
- * ERROR_UNSUPPORTED if a plugin can't be created for the uuid
- * OK after a plugin has been created and mPlugin is valid
- */
- status_t mInitCheck;
-
- KeyedVector<int32_t, size_t> mHeapSizes;
- int32_t mHeapSeqNum;
-
- Vector<sp<ICryptoFactory>> makeCryptoFactories();
- sp<ICryptoPlugin> makeCryptoPlugin(const sp<ICryptoFactory>& factory,
- const uint8_t uuid[16], const void *initData, size_t size);
-
- int32_t setHeapBase(const sp<HidlMemory>& heap);
- void clearHeapBase(int32_t seqNum);
-
- status_t checkSharedBuffer(const ::SharedBuffer& buffer);
-
+ sp<ICrypto> mCryptoHalHidl;
+ sp<ICrypto> mCryptoHalAidl;
DISALLOW_EVIL_CONSTRUCTORS(CryptoHal);
};
} // namespace android
-#endif // CRYPTO_HAL_H_
+#endif // CRYPTO_HAL_H_
\ No newline at end of file
diff --git a/drm/libmediadrm/include/mediadrm/CryptoHalAidl.h b/drm/libmediadrm/include/mediadrm/CryptoHalAidl.h
new file mode 100644
index 0000000..50878a6
--- /dev/null
+++ b/drm/libmediadrm/include/mediadrm/CryptoHalAidl.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2021 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 CRYPTO_HAL_AIDL_H_
+#define CRYPTO_HAL_AIDL_H_
+
+#include <aidl/android/hardware/drm/ICryptoPlugin.h>
+#include <aidl/android/hardware/drm/IDrmFactory.h>
+#include <mediadrm/ICrypto.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+
+using IDrmFactoryAidl = ::aidl::android::hardware::drm::IDrmFactory;
+using ICryptoPluginAidl = ::aidl::android::hardware::drm::ICryptoPlugin;
+using ::aidl::android::hardware::drm::Uuid;
+
+// -------Hidl interface related-----------------
+// TODO: replace before removing hidl interface
+using ::android::hardware::drm::V1_0::DestinationBuffer;
+using ::android::hardware::drm::V1_0::SharedBuffer;
+
+using ::android::hardware::HidlMemory;
+
+// -------Hidl interface related end-------------
+
+class IMemoryHeap;
+
+namespace android {
+
+struct CryptoHalAidl : public ICrypto {
+ CryptoHalAidl();
+ virtual ~CryptoHalAidl();
+ virtual status_t initCheck() const;
+ virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]);
+ virtual status_t createPlugin(const uint8_t uuid[16], const void* data, size_t size);
+ virtual status_t destroyPlugin();
+ virtual bool requiresSecureDecoderComponent(const char* mime) const;
+ virtual void notifyResolution(uint32_t width, uint32_t height);
+ virtual status_t setMediaDrmSession(const Vector<uint8_t>& sessionId);
+ virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16], CryptoPlugin::Mode mode,
+ const CryptoPlugin::Pattern& pattern, const ::SharedBuffer& source,
+ size_t offset, const CryptoPlugin::SubSample* subSamples,
+ size_t numSubSamples, const ::DestinationBuffer& destination,
+ AString* errorDetailMsg);
+ virtual int32_t setHeap(const sp<HidlMemory>& heap);
+ virtual void unsetHeap(int32_t seqNum);
+ virtual status_t getLogMessages(Vector<drm::V1_4::LogMessage>& logs) const;
+
+ private:
+ mutable Mutex mLock;
+
+ const std::vector<std::shared_ptr<IDrmFactoryAidl>> mFactories;
+ std::shared_ptr<ICryptoPluginAidl> mPlugin;
+
+ /**
+ * mInitCheck is:
+ * NO_INIT if a plugin hasn't been created yet
+ * ERROR_UNSUPPORTED if a plugin can't be created for the uuid
+ * OK after a plugin has been created and mPlugin is valid
+ */
+ status_t mInitCheck;
+
+ KeyedVector<int32_t, size_t> mHeapSizes;
+ int32_t mHeapSeqNum;
+
+ std::shared_ptr<ICryptoPluginAidl> makeCryptoPlugin(
+ const std::shared_ptr<IDrmFactoryAidl>& factory, const Uuid& uuidAidl,
+ const std::vector<uint8_t> initData);
+
+ status_t checkSharedBuffer(const ::SharedBuffer& buffer);
+ bool isCryptoSchemeSupportedInternal(const uint8_t uuid[16], int* factoryIdx);
+
+ DISALLOW_EVIL_CONSTRUCTORS(CryptoHalAidl);
+};
+
+} // namespace android
+
+#endif // CRYPTO_HAL_AIDL_H_
diff --git a/drm/libmediadrm/include/mediadrm/CryptoHalHidl.h b/drm/libmediadrm/include/mediadrm/CryptoHalHidl.h
new file mode 100644
index 0000000..6db1e89
--- /dev/null
+++ b/drm/libmediadrm/include/mediadrm/CryptoHalHidl.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2021 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 CRYPTO_HAL_HIDL_H_
+#define CRYPTO_HAL_HIDL_H_
+
+#include <android/hardware/drm/1.0/ICryptoFactory.h>
+#include <android/hardware/drm/1.0/ICryptoPlugin.h>
+#include <android/hardware/drm/1.1/ICryptoFactory.h>
+#include <android/hardware/drm/1.2/ICryptoPlugin.h>
+#include <android/hardware/drm/1.4/ICryptoPlugin.h>
+
+#include <mediadrm/ICrypto.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+
+namespace drm = ::android::hardware::drm;
+using drm::V1_0::ICryptoFactory;
+using drm::V1_0::ICryptoPlugin;
+using drm::V1_0::SharedBuffer;
+using drm::V1_0::DestinationBuffer;
+
+using ::android::hardware::HidlMemory;
+
+class IMemoryHeap;
+
+namespace android {
+
+struct CryptoHalHidl : public ICrypto {
+ CryptoHalHidl();
+ virtual ~CryptoHalHidl();
+
+ virtual status_t initCheck() const;
+
+ virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]);
+
+ virtual status_t createPlugin(
+ const uint8_t uuid[16], const void *data, size_t size);
+
+ virtual status_t destroyPlugin();
+
+ virtual bool requiresSecureDecoderComponent(
+ const char *mime) const;
+
+ virtual void notifyResolution(uint32_t width, uint32_t height);
+
+ virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId);
+
+ virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16],
+ CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
+ const ::SharedBuffer &source, size_t offset,
+ const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
+ const ::DestinationBuffer &destination,
+ AString *errorDetailMsg);
+
+ virtual int32_t setHeap(const sp<HidlMemory>& heap) {
+ return setHeapBase(heap);
+ }
+ virtual void unsetHeap(int32_t seqNum) { clearHeapBase(seqNum); }
+
+ virtual status_t getLogMessages(Vector<drm::V1_4::LogMessage> &logs) const;
+
+private:
+ mutable Mutex mLock;
+
+ const Vector<sp<ICryptoFactory>> mFactories;
+ sp<ICryptoPlugin> mPlugin;
+ sp<drm::V1_2::ICryptoPlugin> mPluginV1_2;
+
+ /**
+ * mInitCheck is:
+ * NO_INIT if a plugin hasn't been created yet
+ * ERROR_UNSUPPORTED if a plugin can't be created for the uuid
+ * OK after a plugin has been created and mPlugin is valid
+ */
+ status_t mInitCheck;
+
+ KeyedVector<int32_t, size_t> mHeapSizes;
+ int32_t mHeapSeqNum;
+
+ Vector<sp<ICryptoFactory>> makeCryptoFactories();
+ sp<ICryptoPlugin> makeCryptoPlugin(const sp<ICryptoFactory>& factory,
+ const uint8_t uuid[16], const void *initData, size_t size);
+
+ int32_t setHeapBase(const sp<HidlMemory>& heap);
+ void clearHeapBase(int32_t seqNum);
+
+ status_t checkSharedBuffer(const ::SharedBuffer& buffer);
+
+ DISALLOW_EVIL_CONSTRUCTORS(CryptoHalHidl);
+};
+
+} // namespace android
+
+#endif // CRYPTO_HAL_H_
diff --git a/drm/libmediadrm/include/mediadrm/DrmHal.h b/drm/libmediadrm/include/mediadrm/DrmHal.h
index 7eb1dec..f5e75ac 100644
--- a/drm/libmediadrm/include/mediadrm/DrmHal.h
+++ b/drm/libmediadrm/include/mediadrm/DrmHal.h
@@ -14,77 +14,27 @@
* limitations under the License.
*/
-#ifndef DRM_HAL_H_
-
-#define DRM_HAL_H_
-
-#include <android/hardware/drm/1.0/IDrmFactory.h>
-#include <android/hardware/drm/1.0/IDrmPlugin.h>
-#include <android/hardware/drm/1.1/IDrmFactory.h>
-#include <android/hardware/drm/1.1/IDrmPlugin.h>
-#include <android/hardware/drm/1.2/IDrmFactory.h>
-#include <android/hardware/drm/1.2/IDrmPlugin.h>
-#include <android/hardware/drm/1.2/IDrmPluginListener.h>
-#include <android/hardware/drm/1.4/IDrmPlugin.h>
-#include <android/hardware/drm/1.4/types.h>
-
-#include <media/drm/DrmAPI.h>
-#include <mediadrm/DrmMetrics.h>
-#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;
-using drm::V1_0::EventType;
-using drm::V1_0::IDrmFactory;
-using drm::V1_0::IDrmPlugin;
-using drm::V1_0::IDrmPluginListener;
-using drm::V1_1::SecurityLevel;
-using drm::V1_2::KeyStatus;
-using drm::V1_2::OfflineLicenseState;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-
-typedef drm::V1_2::IDrmPluginListener IDrmPluginListener_V1_2;
-typedef drm::V1_0::KeyStatus KeyStatus_V1_0;
+#ifndef DRM_HAL_H_
+#define DRM_HAL_H_
namespace android {
-struct DrmSessionClientInterface;
-
-inline bool operator==(const Vector<uint8_t> &l, const Vector<uint8_t> &r) {
- if (l.size() != r.size()) return false;
- return memcmp(l.array(), r.array(), l.size()) == 0;
-}
-
-struct DrmHal : public IDrm,
- public IDrmPluginListener_V1_2 {
-
- struct DrmSessionClient;
-
+struct DrmHal : public IDrm {
DrmHal();
virtual ~DrmHal();
-
virtual status_t initCheck() const;
-
virtual status_t isCryptoSchemeSupported(const uint8_t uuid[16],
- const String8& mimeType,
- DrmPlugin::SecurityLevel level,
- bool *isSupported);
-
+ const String8 &mimeType,
+ DrmPlugin::SecurityLevel securityLevel,
+ bool *result);
virtual status_t createPlugin(const uint8_t uuid[16],
const String8 &appPackageName);
-
virtual status_t destroyPlugin();
-
- virtual status_t openSession(DrmPlugin::SecurityLevel level,
+ virtual status_t openSession(DrmPlugin::SecurityLevel securityLevel,
Vector<uint8_t> &sessionId);
-
virtual status_t closeSession(Vector<uint8_t> const &sessionId);
-
virtual status_t
getKeyRequest(Vector<uint8_t> const &sessionId,
Vector<uint8_t> const &initData,
@@ -92,168 +42,88 @@
KeyedVector<String8, String8> const &optionalParameters,
Vector<uint8_t> &request, String8 &defaultUrl,
DrmPlugin::KeyRequestType *keyRequestType);
-
virtual status_t provideKeyResponse(Vector<uint8_t> const &sessionId,
Vector<uint8_t> const &response,
Vector<uint8_t> &keySetId);
-
virtual status_t removeKeys(Vector<uint8_t> const &keySetId);
-
virtual status_t restoreKeys(Vector<uint8_t> const &sessionId,
Vector<uint8_t> const &keySetId);
-
virtual status_t queryKeyStatus(Vector<uint8_t> const &sessionId,
KeyedVector<String8, String8> &infoMap) const;
-
virtual status_t getProvisionRequest(String8 const &certType,
String8 const &certAuthority,
Vector<uint8_t> &request,
- String8 &defaulUrl);
-
+ String8 &defaultUrl);
virtual status_t provideProvisionResponse(Vector<uint8_t> const &response,
Vector<uint8_t> &certificate,
Vector<uint8_t> &wrappedKey);
-
virtual status_t getSecureStops(List<Vector<uint8_t>> &secureStops);
virtual status_t getSecureStopIds(List<Vector<uint8_t>> &secureStopIds);
virtual status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop);
-
virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease);
virtual status_t removeSecureStop(Vector<uint8_t> const &ssid);
virtual status_t removeAllSecureStops();
-
virtual status_t getHdcpLevels(DrmPlugin::HdcpLevel *connectedLevel,
DrmPlugin::HdcpLevel *maxLevel) const;
virtual status_t getNumberOfSessions(uint32_t *currentSessions,
uint32_t *maxSessions) const;
virtual status_t getSecurityLevel(Vector<uint8_t> const &sessionId,
DrmPlugin::SecurityLevel *level) const;
-
virtual status_t getOfflineLicenseKeySetIds(List<Vector<uint8_t>> &keySetIds) const;
virtual status_t removeOfflineLicense(Vector<uint8_t> const &keySetId);
virtual status_t getOfflineLicenseState(Vector<uint8_t> const &keySetId,
DrmPlugin::OfflineLicenseState *licenseState) const;
-
- virtual status_t getPropertyString(String8 const &name, String8 &value ) const;
+ virtual status_t getPropertyString(String8 const &name, String8 &value) const;
virtual status_t getPropertyByteArray(String8 const &name,
- Vector<uint8_t> &value ) const;
- virtual status_t setPropertyString(String8 const &name, String8 const &value ) const;
+ Vector<uint8_t> &value) const;
+ virtual status_t setPropertyString(String8 const &name,
+ String8 const &value ) const;
virtual status_t setPropertyByteArray(String8 const &name,
- Vector<uint8_t> const &value ) const;
+ Vector<uint8_t> const &value) const;
virtual status_t getMetrics(const sp<IDrmMetricsConsumer> &consumer);
-
virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
String8 const &algorithm);
-
virtual status_t setMacAlgorithm(Vector<uint8_t> const &sessionId,
String8 const &algorithm);
-
virtual status_t encrypt(Vector<uint8_t> const &sessionId,
Vector<uint8_t> const &keyId,
Vector<uint8_t> const &input,
Vector<uint8_t> const &iv,
Vector<uint8_t> &output);
-
virtual status_t decrypt(Vector<uint8_t> const &sessionId,
Vector<uint8_t> const &keyId,
Vector<uint8_t> const &input,
Vector<uint8_t> const &iv,
Vector<uint8_t> &output);
-
virtual status_t sign(Vector<uint8_t> const &sessionId,
Vector<uint8_t> const &keyId,
Vector<uint8_t> const &message,
Vector<uint8_t> &signature);
-
virtual status_t verify(Vector<uint8_t> const &sessionId,
Vector<uint8_t> const &keyId,
Vector<uint8_t> const &message,
Vector<uint8_t> const &signature,
bool &match);
-
virtual status_t signRSA(Vector<uint8_t> const &sessionId,
String8 const &algorithm,
Vector<uint8_t> const &message,
Vector<uint8_t> const &wrappedKey,
Vector<uint8_t> &signature);
-
virtual status_t setListener(const sp<IDrmClient>& listener);
-
virtual status_t requiresSecureDecoder(const char *mime, bool *required) const;
-
virtual status_t requiresSecureDecoder(const char *mime, DrmPlugin::SecurityLevel securityLevel,
bool *required) const;
-
virtual status_t setPlaybackId(
Vector<uint8_t> const &sessionId,
const char *playbackId);
-
virtual status_t getLogMessages(Vector<drm::V1_4::LogMessage> &logs) const;
- // Methods of IDrmPluginListener
- Return<void> sendEvent(EventType eventType,
- const hidl_vec<uint8_t>& sessionId, const hidl_vec<uint8_t>& data);
-
- Return<void> sendExpirationUpdate(const hidl_vec<uint8_t>& sessionId,
- int64_t expiryTimeInMS);
-
- Return<void> sendKeysChange(const hidl_vec<uint8_t>& sessionId,
- const hidl_vec<KeyStatus_V1_0>& keyStatusList, bool hasNewUsableKey);
-
- Return<void> sendKeysChange_1_2(const hidl_vec<uint8_t>& sessionId,
- const hidl_vec<KeyStatus>& keyStatusList, bool hasNewUsableKey);
-
- Return<void> sendSessionLostState(const hidl_vec<uint8_t>& sessionId);
-
private:
- static Mutex mLock;
-
- sp<IDrmClient> mListener;
- mutable Mutex mEventLock;
- mutable Mutex mNotifyLock;
-
- const std::vector<sp<IDrmFactory>> mFactories;
- sp<IDrmPlugin> mPlugin;
- sp<drm::V1_1::IDrmPlugin> mPluginV1_1;
- sp<drm::V1_2::IDrmPlugin> mPluginV1_2;
- sp<drm::V1_4::IDrmPlugin> mPluginV1_4;
- String8 mAppPackageName;
-
- // Mutable to allow modification within GetPropertyByteArray.
- mutable MediaDrmMetrics mMetrics;
-
- std::vector<std::shared_ptr<DrmSessionClient>> mOpenSessions;
- void closeOpenSessions();
- void cleanup();
-
- /**
- * mInitCheck is:
- * NO_INIT if a plugin hasn't been created yet
- * ERROR_UNSUPPORTED if a plugin can't be created for the uuid
- * OK after a plugin has been created and mPlugin is valid
- */
- status_t mInitCheck;
-
- std::vector<sp<IDrmFactory>> makeDrmFactories();
- sp<IDrmPlugin> makeDrmPlugin(const sp<IDrmFactory>& factory,
- const uint8_t uuid[16], const String8& appPackageName);
-
- void writeByteArray(Parcel &obj, const hidl_vec<uint8_t>& array);
-
- std::string reportPluginMetrics() const;
- std::string reportFrameworkMetrics(const std::string& pluginMetrics) const;
- status_t getPropertyStringInternal(String8 const &name, String8 &value) const;
- status_t getPropertyByteArrayInternal(String8 const &name,
- Vector<uint8_t> &value) const;
- status_t matchMimeTypeAndSecurityLevel(const sp<IDrmFactory> &factory,
- const uint8_t uuid[16],
- const String8 &mimeType,
- DrmPlugin::SecurityLevel level,
- bool *isSupported);
-
+ sp<IDrm> mDrmHalHidl;
+ sp<IDrm> mDrmHalAidl;
DISALLOW_EVIL_CONSTRUCTORS(DrmHal);
};
-} // namespace android
+} // namespace android
-#endif // DRM_HAL_H_
+#endif // DRM_HAL_H_
\ No newline at end of file
diff --git a/drm/libmediadrm/include/mediadrm/DrmHalAidl.h b/drm/libmediadrm/include/mediadrm/DrmHalAidl.h
new file mode 100644
index 0000000..e35140e
--- /dev/null
+++ b/drm/libmediadrm/include/mediadrm/DrmHalAidl.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DRM_HAL_AIDL_H_
+#define DRM_HAL_AIDL_H_
+
+#include <memory>
+#include <aidl/android/hardware/drm/BnDrmPluginListener.h>
+#include <aidl/android/hardware/drm/IDrmFactory.h>
+#include <aidl/android/hardware/drm/IDrmPlugin.h>
+#include <aidl/android/media/BnResourceManagerClient.h>
+#include <mediadrm/DrmMetrics.h>
+#include <mediadrm/DrmSessionManager.h>
+#include <mediadrm/DrmHalListener.h>
+#include <mediadrm/IDrm.h>
+
+using IDrmPluginAidl = ::aidl::android::hardware::drm::IDrmPlugin;
+using IDrmFactoryAidl = ::aidl::android::hardware::drm::IDrmFactory;
+using EventTypeAidl = ::aidl::android::hardware::drm::EventType;
+using KeyStatusAidl = ::aidl::android::hardware::drm::KeyStatus;
+using ::aidl::android::hardware::drm::Uuid;
+
+namespace android {
+struct DrmHalAidl : public IDrm{
+ struct DrmSessionClient;
+ DrmHalAidl();
+ virtual ~DrmHalAidl();
+ virtual status_t initCheck() const;
+ virtual status_t isCryptoSchemeSupported(const uint8_t uuid[16], const String8& mimeType,
+ DrmPlugin::SecurityLevel securityLevel, bool* result);
+ virtual status_t createPlugin(const uint8_t uuid[16], const String8& appPackageName);
+ virtual status_t destroyPlugin();
+ virtual status_t openSession(DrmPlugin::SecurityLevel securityLevel,
+ Vector<uint8_t>& sessionId);
+ virtual status_t closeSession(Vector<uint8_t> const& sessionId);
+ virtual status_t getKeyRequest(Vector<uint8_t> const& sessionId,
+ Vector<uint8_t> const& initData, String8 const& mimeType,
+ DrmPlugin::KeyType keyType,
+ KeyedVector<String8, String8> const& optionalParameters,
+ Vector<uint8_t>& request, String8& defaultUrl,
+ DrmPlugin::KeyRequestType* keyRequestType);
+ virtual status_t provideKeyResponse(Vector<uint8_t> const& sessionId,
+ Vector<uint8_t> const& response, Vector<uint8_t>& keySetId);
+ virtual status_t removeKeys(Vector<uint8_t> const& keySetId);
+ virtual status_t restoreKeys(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keySetId);
+ virtual status_t queryKeyStatus(Vector<uint8_t> const& sessionId,
+ KeyedVector<String8, String8>& infoMap) const;
+ virtual status_t getProvisionRequest(String8 const& certType, String8 const& certAuthority,
+ Vector<uint8_t>& request, String8& defaultUrl);
+ virtual status_t provideProvisionResponse(Vector<uint8_t> const& response,
+ Vector<uint8_t>& certificate,
+ Vector<uint8_t>& wrappedKey);
+ virtual status_t getSecureStops(List<Vector<uint8_t>>& secureStops);
+ virtual status_t getSecureStopIds(List<Vector<uint8_t>>& secureStopIds);
+ virtual status_t getSecureStop(Vector<uint8_t> const& ssid, Vector<uint8_t>& secureStop);
+ virtual status_t releaseSecureStops(Vector<uint8_t> const& ssRelease);
+ virtual status_t removeSecureStop(Vector<uint8_t> const& ssid);
+ virtual status_t removeAllSecureStops();
+ virtual status_t getHdcpLevels(DrmPlugin::HdcpLevel* connectedLevel,
+ DrmPlugin::HdcpLevel* maxLevel) const;
+ virtual status_t getNumberOfSessions(uint32_t* currentSessions, uint32_t* maxSessions) const;
+ virtual status_t getSecurityLevel(Vector<uint8_t> const& sessionId,
+ DrmPlugin::SecurityLevel* level) const;
+ virtual status_t getOfflineLicenseKeySetIds(List<Vector<uint8_t>>& keySetIds) const;
+ virtual status_t removeOfflineLicense(Vector<uint8_t> const& keySetId);
+ virtual status_t getOfflineLicenseState(Vector<uint8_t> const& keySetId,
+ DrmPlugin::OfflineLicenseState* licenseState) const;
+ virtual status_t getPropertyString(String8 const& name, String8& value) const;
+ virtual status_t getPropertyByteArray(String8 const& name, Vector<uint8_t>& value) const;
+ 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(const sp<IDrmMetricsConsumer>& consumer);
+ virtual status_t setCipherAlgorithm(Vector<uint8_t> const& sessionId, String8 const& algorithm);
+ virtual status_t setMacAlgorithm(Vector<uint8_t> const& sessionId, String8 const& algorithm);
+ virtual status_t encrypt(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& input, Vector<uint8_t> const& iv,
+ Vector<uint8_t>& output);
+ virtual status_t decrypt(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& input, Vector<uint8_t> const& iv,
+ Vector<uint8_t>& output);
+ virtual status_t sign(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& message, Vector<uint8_t>& signature);
+ virtual status_t verify(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& message, Vector<uint8_t> const& signature,
+ bool& match);
+ virtual status_t signRSA(Vector<uint8_t> const& sessionId, String8 const& algorithm,
+ Vector<uint8_t> const& message, Vector<uint8_t> const& wrappedKey,
+ Vector<uint8_t>& signature);
+ virtual status_t setListener(const sp<IDrmClient>& listener);
+ virtual status_t requiresSecureDecoder(const char* mime, bool* required) const;
+ virtual status_t requiresSecureDecoder(const char* mime, DrmPlugin::SecurityLevel securityLevel,
+ bool* required) const;
+ virtual status_t setPlaybackId(Vector<uint8_t> const& sessionId, const char* playbackId);
+ virtual status_t getLogMessages(Vector<drm::V1_4::LogMessage>& logs) const;
+
+ ::ndk::ScopedAStatus onEvent(EventTypeAidl in_eventType,
+ const std::vector<uint8_t>& in_sessionId,
+ const std::vector<uint8_t>& in_data);
+ ::ndk::ScopedAStatus onExpirationUpdate(const std::vector<uint8_t>& in_sessionId,
+ int64_t in_expiryTimeInMS);
+ ::ndk::ScopedAStatus onKeysChange(const std::vector<uint8_t>& in_sessionId,
+ const std::vector<KeyStatusAidl>& in_keyStatusList,
+ bool in_hasNewUsableKey);
+ ::ndk::ScopedAStatus onSessionLostState(const std::vector<uint8_t>& in_sessionId);
+ private:
+ static Mutex mLock;
+ mutable MediaDrmMetrics mMetrics;
+ std::shared_ptr<DrmHalListener> mListener;
+ const std::vector<std::shared_ptr<IDrmFactoryAidl>> mFactories;
+ std::shared_ptr<IDrmPluginAidl> mPlugin;
+ status_t mInitCheck;
+ std::vector<std::shared_ptr<DrmSessionClient>> mOpenSessions;
+ void cleanup();
+ void closeOpenSessions();
+ std::string reportPluginMetrics() const;
+ std::string reportFrameworkMetrics(const std::string& pluginMetrics) const;
+ status_t getPropertyStringInternal(String8 const& name, String8& value) const;
+ status_t getPropertyByteArrayInternal(String8 const& name, Vector<uint8_t>& value) const;
+ DISALLOW_EVIL_CONSTRUCTORS(DrmHalAidl);
+};
+
+} // namespace android
+
+#endif // DRM_HAL_AIDL_H_
\ No newline at end of file
diff --git a/drm/libmediadrm/include/mediadrm/DrmHalHidl.h b/drm/libmediadrm/include/mediadrm/DrmHalHidl.h
new file mode 100644
index 0000000..94ef285
--- /dev/null
+++ b/drm/libmediadrm/include/mediadrm/DrmHalHidl.h
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DRM_HAL_HIDL_H_
+#define DRM_HAL_HIDL_H_
+
+#include <android/hardware/drm/1.2/IDrmFactory.h>
+#include <android/hardware/drm/1.2/IDrmPlugin.h>
+#include <android/hardware/drm/1.2/IDrmPluginListener.h>
+#include <android/hardware/drm/1.4/IDrmPlugin.h>
+#include <android/hardware/drm/1.4/types.h>
+
+#include <media/drm/DrmAPI.h>
+#include <mediadrm/DrmMetrics.h>
+#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;
+using drm::V1_0::EventType;
+using drm::V1_0::IDrmFactory;
+using drm::V1_0::IDrmPlugin;
+using drm::V1_0::IDrmPluginListener;
+using drm::V1_1::SecurityLevel;
+using drm::V1_2::KeyStatus;
+using drm::V1_2::OfflineLicenseState;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+typedef drm::V1_2::IDrmPluginListener IDrmPluginListener_V1_2;
+typedef drm::V1_0::KeyStatus KeyStatus_V1_0;
+
+namespace android {
+
+struct DrmSessionClientInterface;
+
+inline bool operator==(const Vector<uint8_t> &l, const Vector<uint8_t> &r) {
+ if (l.size() != r.size()) return false;
+ return memcmp(l.array(), r.array(), l.size()) == 0;
+}
+
+struct DrmHalHidl : public IDrm,
+ public IDrmPluginListener_V1_2 {
+
+ struct DrmSessionClient;
+
+ DrmHalHidl();
+ virtual ~DrmHalHidl();
+
+ virtual status_t initCheck() const;
+
+ virtual status_t isCryptoSchemeSupported(const uint8_t uuid[16],
+ const String8& mimeType,
+ DrmPlugin::SecurityLevel level,
+ bool *isSupported);
+
+ virtual status_t createPlugin(const uint8_t uuid[16],
+ const String8 &appPackageName);
+
+ virtual status_t destroyPlugin();
+
+ virtual status_t openSession(DrmPlugin::SecurityLevel level,
+ Vector<uint8_t> &sessionId);
+
+ virtual status_t closeSession(Vector<uint8_t> const &sessionId);
+
+ virtual status_t
+ getKeyRequest(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &initData,
+ String8 const &mimeType, DrmPlugin::KeyType keyType,
+ KeyedVector<String8, String8> const &optionalParameters,
+ Vector<uint8_t> &request, String8 &defaultUrl,
+ DrmPlugin::KeyRequestType *keyRequestType);
+
+ virtual status_t provideKeyResponse(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &response,
+ Vector<uint8_t> &keySetId);
+
+ virtual status_t removeKeys(Vector<uint8_t> const &keySetId);
+
+ virtual status_t restoreKeys(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keySetId);
+
+ virtual status_t queryKeyStatus(Vector<uint8_t> const &sessionId,
+ KeyedVector<String8, String8> &infoMap) const;
+
+ virtual status_t getProvisionRequest(String8 const &certType,
+ String8 const &certAuthority,
+ Vector<uint8_t> &request,
+ String8 &defaultUrl);
+
+ virtual status_t provideProvisionResponse(Vector<uint8_t> const &response,
+ Vector<uint8_t> &certificate,
+ Vector<uint8_t> &wrappedKey);
+
+ virtual status_t getSecureStops(List<Vector<uint8_t>> &secureStops);
+ virtual status_t getSecureStopIds(List<Vector<uint8_t>> &secureStopIds);
+ virtual status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop);
+
+ virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease);
+ virtual status_t removeSecureStop(Vector<uint8_t> const &ssid);
+ virtual status_t removeAllSecureStops();
+
+ virtual status_t getHdcpLevels(DrmPlugin::HdcpLevel *connectedLevel,
+ DrmPlugin::HdcpLevel *maxLevel) const;
+ virtual status_t getNumberOfSessions(uint32_t *currentSessions,
+ uint32_t *maxSessions) const;
+ virtual status_t getSecurityLevel(Vector<uint8_t> const &sessionId,
+ DrmPlugin::SecurityLevel *level) const;
+
+ virtual status_t getOfflineLicenseKeySetIds(List<Vector<uint8_t>> &keySetIds) const;
+ virtual status_t removeOfflineLicense(Vector<uint8_t> const &keySetId);
+ virtual status_t getOfflineLicenseState(Vector<uint8_t> const &keySetId,
+ DrmPlugin::OfflineLicenseState *licenseState) const;
+
+ virtual status_t getPropertyString(String8 const &name, String8 &value ) const;
+ virtual status_t getPropertyByteArray(String8 const &name,
+ Vector<uint8_t> &value ) const;
+ 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(const sp<IDrmMetricsConsumer> &consumer);
+
+ virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
+ String8 const &algorithm);
+
+ virtual status_t setMacAlgorithm(Vector<uint8_t> const &sessionId,
+ String8 const &algorithm);
+
+ virtual status_t encrypt(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &input,
+ Vector<uint8_t> const &iv,
+ Vector<uint8_t> &output);
+
+ virtual status_t decrypt(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &input,
+ Vector<uint8_t> const &iv,
+ Vector<uint8_t> &output);
+
+ virtual status_t sign(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &message,
+ Vector<uint8_t> &signature);
+
+ virtual status_t verify(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &message,
+ Vector<uint8_t> const &signature,
+ bool &match);
+
+ virtual status_t signRSA(Vector<uint8_t> const &sessionId,
+ String8 const &algorithm,
+ Vector<uint8_t> const &message,
+ Vector<uint8_t> const &wrappedKey,
+ Vector<uint8_t> &signature);
+
+ virtual status_t setListener(const sp<IDrmClient>& listener);
+
+ virtual status_t requiresSecureDecoder(const char *mime, bool *required) const;
+
+ virtual status_t requiresSecureDecoder(const char *mime, DrmPlugin::SecurityLevel securityLevel,
+ bool *required) const;
+
+ virtual status_t setPlaybackId(
+ Vector<uint8_t> const &sessionId,
+ const char *playbackId);
+
+ virtual status_t getLogMessages(Vector<drm::V1_4::LogMessage> &logs) const;
+
+ // Methods of IDrmPluginListener
+ Return<void> sendEvent(EventType eventType,
+ const hidl_vec<uint8_t>& sessionId, const hidl_vec<uint8_t>& data);
+
+ Return<void> sendExpirationUpdate(const hidl_vec<uint8_t>& sessionId,
+ int64_t expiryTimeInMS);
+
+ Return<void> sendKeysChange(const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<KeyStatus_V1_0>& keyStatusList, bool hasNewUsableKey);
+
+ Return<void> sendKeysChange_1_2(const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<KeyStatus>& keyStatusList, bool hasNewUsableKey);
+
+ Return<void> sendSessionLostState(const hidl_vec<uint8_t>& sessionId);
+
+private:
+ static Mutex mLock;
+
+ sp<IDrmClient> mListener;
+ mutable Mutex mEventLock;
+ mutable Mutex mNotifyLock;
+
+ const std::vector<sp<IDrmFactory>> mFactories;
+ sp<IDrmPlugin> mPlugin;
+ sp<drm::V1_1::IDrmPlugin> mPluginV1_1;
+ sp<drm::V1_2::IDrmPlugin> mPluginV1_2;
+ sp<drm::V1_4::IDrmPlugin> mPluginV1_4;
+ String8 mAppPackageName;
+
+ // Mutable to allow modification within GetPropertyByteArray.
+ mutable MediaDrmMetrics mMetrics;
+
+ std::vector<std::shared_ptr<DrmSessionClient>> mOpenSessions;
+ void closeOpenSessions();
+ void cleanup();
+
+ /**
+ * mInitCheck is:
+ * NO_INIT if a plugin hasn't been created yet
+ * ERROR_UNSUPPORTED if a plugin can't be created for the uuid
+ * OK after a plugin has been created and mPlugin is valid
+ */
+ status_t mInitCheck;
+
+ std::vector<sp<IDrmFactory>> makeDrmFactories();
+ sp<IDrmPlugin> makeDrmPlugin(const sp<IDrmFactory>& factory,
+ const uint8_t uuid[16], const String8& appPackageName);
+
+ void writeByteArray(Parcel &obj, const hidl_vec<uint8_t>& array);
+
+ std::string reportPluginMetrics() const;
+ std::string reportFrameworkMetrics(const std::string& pluginMetrics) const;
+ status_t getPropertyStringInternal(String8 const &name, String8 &value) const;
+ status_t getPropertyByteArrayInternal(String8 const &name,
+ Vector<uint8_t> &value) const;
+ status_t matchMimeTypeAndSecurityLevel(const sp<IDrmFactory> &factory,
+ const uint8_t uuid[16],
+ const String8 &mimeType,
+ DrmPlugin::SecurityLevel level,
+ bool *isSupported);
+
+ DISALLOW_EVIL_CONSTRUCTORS(DrmHalHidl);
+};
+
+} // namespace android
+
+#endif // DRM_HAL_HIDL_H_
diff --git a/drm/libmediadrm/include/mediadrm/DrmHalListener.h b/drm/libmediadrm/include/mediadrm/DrmHalListener.h
new file mode 100644
index 0000000..22361ad
--- /dev/null
+++ b/drm/libmediadrm/include/mediadrm/DrmHalListener.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DRM_HAL_LISTENER_H_
+#define DRM_HAL_LISTENER_H_
+
+#include <aidl/android/hardware/drm/BnDrmPluginListener.h>
+#include <mediadrm/DrmMetrics.h>
+#include <mediadrm/IDrmClient.h>
+
+using EventTypeAidl = ::aidl::android::hardware::drm::EventType;
+using KeyStatusAidl = ::aidl::android::hardware::drm::KeyStatus;
+using aidl::android::hardware::drm::BnDrmPluginListener;
+
+namespace android {
+struct DrmHalListener : public BnDrmPluginListener {
+ explicit DrmHalListener(MediaDrmMetrics* mMetrics);
+ ~DrmHalListener();
+ ::ndk::ScopedAStatus onEvent(EventTypeAidl in_eventType,
+ const std::vector<uint8_t>& in_sessionId,
+ const std::vector<uint8_t>& in_data);
+ ::ndk::ScopedAStatus onExpirationUpdate(const std::vector<uint8_t>& in_sessionId,
+ int64_t in_expiryTimeInMS);
+ ::ndk::ScopedAStatus onKeysChange(const std::vector<uint8_t>& in_sessionId,
+ const std::vector<KeyStatusAidl>& in_keyStatusList,
+ bool in_hasNewUsableKey);
+ ::ndk::ScopedAStatus onSessionLostState(const std::vector<uint8_t>& in_sessionId);
+ void setListener(sp<IDrmClient> listener);
+private:
+ mutable MediaDrmMetrics* mMetrics;
+ sp<IDrmClient> mListener;
+ mutable Mutex mEventLock;
+ mutable Mutex mNotifyLock;
+};
+} // namespace android
+
+#endif // DRM_HAL_LISTENER_H_
\ No newline at end of file
diff --git a/drm/libmediadrm/include/mediadrm/DrmMetrics.h b/drm/libmediadrm/include/mediadrm/DrmMetrics.h
index 100b8f7..e1775c7 100644
--- a/drm/libmediadrm/include/mediadrm/DrmMetrics.h
+++ b/drm/libmediadrm/include/mediadrm/DrmMetrics.h
@@ -50,12 +50,10 @@
CounterMetric<status_t> mGetProvisionRequestCounter;
// Count of provideProvisionResponse calls.
CounterMetric<status_t> mProvideProvisionResponseCounter;
-
// Count of key status events broken out by status type.
- CounterMetric<::android::hardware::drm::V1_2::KeyStatusType>
- mKeyStatusChangeCounter;
+ CounterMetric<uint32_t> mKeyStatusChangeCounter;
// Count of events broken out by event type
- CounterMetric<::android::hardware::drm::V1_0::EventType> mEventCounter;
+ CounterMetric<uint32_t> mEventCounter;
// Count getPropertyByteArray calls to retrieve the device unique id.
CounterMetric<status_t> mGetDeviceUniqueIdCounter;
diff --git a/drm/libmediadrm/interface/mediadrm/DrmUtils.h b/drm/libmediadrm/interface/mediadrm/DrmUtils.h
index ec0b878..66fe488 100644
--- a/drm/libmediadrm/interface/mediadrm/DrmUtils.h
+++ b/drm/libmediadrm/interface/mediadrm/DrmUtils.h
@@ -38,12 +38,20 @@
#include <mutex>
#include <string>
#include <vector>
-
+#include <aidl/android/hardware/drm/LogMessage.h>
+#include <aidl/android/hardware/drm/Status.h>
+#include <aidl/android/hardware/drm/IDrmFactory.h>
using namespace ::android::hardware::drm;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
+using ::aidl::android::hardware::drm::LogPriority;
+using ::aidl::android::hardware::drm::LogMessage;
+using ::aidl::android::hardware::drm::Uuid;
+using StatusAidl = ::aidl::android::hardware::drm::Status;
+using IDrmFactoryAidl = ::aidl::android::hardware::drm::IDrmFactory;
+
namespace android {
struct ICrypto;
@@ -155,6 +163,14 @@
obj.writeInt32(hasNewUsableKey);
}
+inline Uuid toAidlUuid(const uint8_t uuid[16]) {
+ Uuid uuidAidl;
+ for (int i = 0; i < 16; ++i) uuidAidl.uuid[i] = uuid[i];
+ return uuidAidl;
+}
+
+std::vector<std::shared_ptr<IDrmFactoryAidl>> makeDrmFactoriesAidl();
+
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],
@@ -180,6 +196,138 @@
return toStatusT_1_4(err);
}
+inline status_t statusAidlToStatusT(::ndk::ScopedAStatus &statusAidl) {
+ if (statusAidl.isOk()) return OK;
+ if (statusAidl.getExceptionCode() != EX_SERVICE_SPECIFIC) return DEAD_OBJECT;
+ auto status = static_cast<StatusAidl>(statusAidl.getServiceSpecificError());
+ switch (status) {
+ case StatusAidl::OK:
+ return OK;
+ case StatusAidl::BAD_VALUE:
+ return BAD_VALUE;
+ case StatusAidl::ERROR_DRM_CANNOT_HANDLE:
+ return ERROR_DRM_CANNOT_HANDLE;
+ case StatusAidl::ERROR_DRM_DECRYPT:
+ return ERROR_DRM_DECRYPT;
+ case StatusAidl::ERROR_DRM_DEVICE_REVOKED:
+ return ERROR_DRM_DEVICE_REVOKED;
+ case StatusAidl::ERROR_DRM_FRAME_TOO_LARGE:
+ return ERROR_DRM_FRAME_TOO_LARGE;
+ case StatusAidl::ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
+ return ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION;
+ case StatusAidl::ERROR_DRM_INSUFFICIENT_SECURITY:
+ return ERROR_DRM_INSUFFICIENT_SECURITY;
+ case StatusAidl::ERROR_DRM_INVALID_STATE:
+ return ERROR_DRM_INVALID_STATE;
+ case StatusAidl::ERROR_DRM_LICENSE_EXPIRED:
+ return ERROR_DRM_LICENSE_EXPIRED;
+ case StatusAidl::ERROR_DRM_NO_LICENSE:
+ return ERROR_DRM_NO_LICENSE;
+ case StatusAidl::ERROR_DRM_NOT_PROVISIONED:
+ return ERROR_DRM_NOT_PROVISIONED;
+ case StatusAidl::ERROR_DRM_RESOURCE_BUSY:
+ return ERROR_DRM_RESOURCE_BUSY;
+ case StatusAidl::ERROR_DRM_RESOURCE_CONTENTION:
+ return ERROR_DRM_RESOURCE_CONTENTION;
+ case StatusAidl::ERROR_DRM_SESSION_LOST_STATE:
+ return ERROR_DRM_SESSION_LOST_STATE;
+ case StatusAidl::ERROR_DRM_SESSION_NOT_OPENED:
+ return ERROR_DRM_SESSION_NOT_OPENED;
+
+ // New in S / drm@1.4:
+ case StatusAidl::CANNOT_DECRYPT_ZERO_SUBSAMPLES:
+ return ERROR_DRM_ZERO_SUBSAMPLES;
+ case StatusAidl::CRYPTO_LIBRARY_ERROR:
+ return ERROR_DRM_CRYPTO_LIBRARY;
+ case StatusAidl::GENERAL_OEM_ERROR:
+ return ERROR_DRM_GENERIC_OEM;
+ case StatusAidl::GENERAL_PLUGIN_ERROR:
+ return ERROR_DRM_GENERIC_PLUGIN;
+ case StatusAidl::INIT_DATA_INVALID:
+ return ERROR_DRM_INIT_DATA;
+ case StatusAidl::KEY_NOT_LOADED:
+ return ERROR_DRM_KEY_NOT_LOADED;
+ case StatusAidl::LICENSE_PARSE_ERROR:
+ return ERROR_DRM_LICENSE_PARSE;
+ case StatusAidl::LICENSE_POLICY_ERROR:
+ return ERROR_DRM_LICENSE_POLICY;
+ case StatusAidl::LICENSE_RELEASE_ERROR:
+ return ERROR_DRM_LICENSE_RELEASE;
+ case StatusAidl::LICENSE_REQUEST_REJECTED:
+ return ERROR_DRM_LICENSE_REQUEST_REJECTED;
+ case StatusAidl::LICENSE_RESTORE_ERROR:
+ return ERROR_DRM_LICENSE_RESTORE;
+ case StatusAidl::LICENSE_STATE_ERROR:
+ return ERROR_DRM_LICENSE_STATE;
+ case StatusAidl::MALFORMED_CERTIFICATE:
+ return ERROR_DRM_CERTIFICATE_MALFORMED;
+ case StatusAidl::MEDIA_FRAMEWORK_ERROR:
+ return ERROR_DRM_MEDIA_FRAMEWORK;
+ case StatusAidl::MISSING_CERTIFICATE:
+ return ERROR_DRM_CERTIFICATE_MISSING;
+ case StatusAidl::PROVISIONING_CERTIFICATE_ERROR:
+ return ERROR_DRM_PROVISIONING_CERTIFICATE;
+ case StatusAidl::PROVISIONING_CONFIGURATION_ERROR:
+ return ERROR_DRM_PROVISIONING_CONFIG;
+ case StatusAidl::PROVISIONING_PARSE_ERROR:
+ return ERROR_DRM_PROVISIONING_PARSE;
+ case StatusAidl::PROVISIONING_REQUEST_REJECTED:
+ return ERROR_DRM_PROVISIONING_REQUEST_REJECTED;
+ case StatusAidl::RETRYABLE_PROVISIONING_ERROR:
+ return ERROR_DRM_PROVISIONING_RETRY;
+ case StatusAidl::SECURE_STOP_RELEASE_ERROR:
+ return ERROR_DRM_SECURE_STOP_RELEASE;
+ case StatusAidl::STORAGE_READ_FAILURE:
+ return ERROR_DRM_STORAGE_READ;
+ case StatusAidl::STORAGE_WRITE_FAILURE:
+ return ERROR_DRM_STORAGE_WRITE;
+
+ case StatusAidl::ERROR_DRM_UNKNOWN:
+ default:
+ return ERROR_DRM_UNKNOWN;
+ }
+ return ERROR_DRM_UNKNOWN;
+}
+
+template<typename T, typename U>
+status_t GetLogMessagesAidl(const std::shared_ptr<U> &obj, Vector<::V1_4::LogMessage> &logs) {
+ std::shared_ptr<T> plugin = obj;
+ if (obj == NULL) {
+ LOG2BW("%s obj is null", U::descriptor);
+ } else if (plugin == NULL) {
+ LOG2BW("Cannot cast %s obj to %s plugin", U::descriptor, T::descriptor);
+ }
+
+ std::vector<LogMessage> pluginLogsAidl;
+ if (plugin != NULL) {
+ if(!plugin->getLogMessages(&pluginLogsAidl).isOk()) {
+ LOG2BW("%s::getLogMessages remote call failed", T::descriptor);
+ }
+ }
+
+ std::vector<::V1_4::LogMessage> pluginLogs;
+ for (LogMessage log : pluginLogsAidl) {
+ ::V1_4::LogMessage logHidl;
+ logHidl.timeMs = log.timeMs;
+ // skip negative convert check as count of enum elements is 7
+ logHidl.priority = static_cast<::V1_4::LogPriority>((int32_t)log.priority);
+ logHidl.message = log.message;
+ pluginLogs.push_back(logHidl);
+ }
+
+ auto allLogs(gLogBuf.getLogs());
+ LOG2BD("framework logs size %zu; plugin logs size %zu",
+ allLogs.size(), pluginLogs.size());
+ std::copy(pluginLogs.begin(), pluginLogs.end(), std::back_inserter(allLogs));
+ std::sort(allLogs.begin(), allLogs.end(),
+ [](const ::V1_4::LogMessage &a, const ::V1_4::LogMessage &b) {
+ return a.timeMs < b.timeMs;
+ });
+
+ logs.appendVector(allLogs);
+ return OK;
+}
+
template<typename T, typename U>
status_t GetLogMessages(const sp<U> &obj, Vector<::V1_4::LogMessage> &logs) {
sp<T> plugin = T::castFrom(obj);
diff --git a/drm/libmediadrm/tests/DrmMetrics_test.cpp b/drm/libmediadrm/tests/DrmMetrics_test.cpp
index f362d60..237a88b 100644
--- a/drm/libmediadrm/tests/DrmMetrics_test.cpp
+++ b/drm/libmediadrm/tests/DrmMetrics_test.cpp
@@ -83,8 +83,8 @@
metrics.mProvideProvisionResponseCounter.Increment(OK);
metrics.mGetDeviceUniqueIdCounter.Increment(OK);
- metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::USABLE);
- metrics.mEventCounter.Increment(EventType::PROVISION_REQUIRED);
+ metrics.mKeyStatusChangeCounter.Increment((uint32_t)KeyStatusType::USABLE);
+ metrics.mEventCounter.Increment((uint32_t)EventType::PROVISION_REQUIRED);
PersistableBundle bundle;
DrmMetricsConsumer consumer(&bundle);
@@ -151,16 +151,16 @@
metrics.mGetDeviceUniqueIdCounter.Increment(OK);
metrics.mGetDeviceUniqueIdCounter.Increment(UNEXPECTED_NULL);
- metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::USABLE);
- metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::EXPIRED);
- metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::OUTPUTNOTALLOWED);
- metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::STATUSPENDING);
- metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::INTERNALERROR);
- metrics.mEventCounter.Increment(EventType::PROVISION_REQUIRED);
- metrics.mEventCounter.Increment(EventType::KEY_NEEDED);
- metrics.mEventCounter.Increment(EventType::KEY_EXPIRED);
- metrics.mEventCounter.Increment(EventType::VENDOR_DEFINED);
- metrics.mEventCounter.Increment(EventType::SESSION_RECLAIMED);
+ metrics.mKeyStatusChangeCounter.Increment((uint32_t)KeyStatusType::USABLE);
+ metrics.mKeyStatusChangeCounter.Increment((uint32_t)KeyStatusType::EXPIRED);
+ metrics.mKeyStatusChangeCounter.Increment((uint32_t)KeyStatusType::OUTPUTNOTALLOWED);
+ metrics.mKeyStatusChangeCounter.Increment((uint32_t)KeyStatusType::STATUSPENDING);
+ metrics.mKeyStatusChangeCounter.Increment((uint32_t)KeyStatusType::INTERNALERROR);
+ metrics.mEventCounter.Increment((uint32_t)EventType::PROVISION_REQUIRED);
+ metrics.mEventCounter.Increment((uint32_t)EventType::KEY_NEEDED);
+ metrics.mEventCounter.Increment((uint32_t)EventType::KEY_EXPIRED);
+ metrics.mEventCounter.Increment((uint32_t)EventType::VENDOR_DEFINED);
+ metrics.mEventCounter.Increment((uint32_t)EventType::SESSION_RECLAIMED);
android::Vector<uint8_t> sessionId1;
sessionId1.push_back(1);
@@ -284,16 +284,16 @@
metrics.mGetDeviceUniqueIdCounter.Increment(OK);
metrics.mGetDeviceUniqueIdCounter.Increment(UNEXPECTED_NULL);
- metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::USABLE);
- metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::EXPIRED);
- metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::OUTPUTNOTALLOWED);
- metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::STATUSPENDING);
- metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::INTERNALERROR);
- metrics.mEventCounter.Increment(EventType::PROVISION_REQUIRED);
- metrics.mEventCounter.Increment(EventType::KEY_NEEDED);
- metrics.mEventCounter.Increment(EventType::KEY_EXPIRED);
- metrics.mEventCounter.Increment(EventType::VENDOR_DEFINED);
- metrics.mEventCounter.Increment(EventType::SESSION_RECLAIMED);
+ metrics.mKeyStatusChangeCounter.Increment((uint32_t)KeyStatusType::USABLE);
+ metrics.mKeyStatusChangeCounter.Increment((uint32_t)KeyStatusType::EXPIRED);
+ metrics.mKeyStatusChangeCounter.Increment((uint32_t)KeyStatusType::OUTPUTNOTALLOWED);
+ metrics.mKeyStatusChangeCounter.Increment((uint32_t)KeyStatusType::STATUSPENDING);
+ metrics.mKeyStatusChangeCounter.Increment((uint32_t)KeyStatusType::INTERNALERROR);
+ metrics.mEventCounter.Increment((uint32_t)EventType::PROVISION_REQUIRED);
+ metrics.mEventCounter.Increment((uint32_t)EventType::KEY_NEEDED);
+ metrics.mEventCounter.Increment((uint32_t)EventType::KEY_EXPIRED);
+ metrics.mEventCounter.Increment((uint32_t)EventType::VENDOR_DEFINED);
+ metrics.mEventCounter.Increment((uint32_t)EventType::SESSION_RECLAIMED);
std::string serializedMetrics;
ASSERT_EQ(OK, metrics.GetSerializedMetrics(&serializedMetrics));
diff --git a/drm/mediadrm/plugins/clearkey/aidl/Android.bp b/drm/mediadrm/plugins/clearkey/aidl/Android.bp
new file mode 100644
index 0000000..2d1f741
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/Android.bp
@@ -0,0 +1,71 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_av_license"],
+}
+
+cc_defaults {
+ name: "aidl_clearkey_service_defaults",
+ vendor: true,
+
+ srcs: [
+ "CreatePluginFactories.cpp",
+ "CryptoPlugin.cpp",
+ "DrmFactory.cpp",
+ "DrmPlugin.cpp",
+ ],
+
+ relative_install_path: "hw",
+
+ cflags: ["-Wall", "-Werror", "-Wthread-safety"],
+
+ include_dirs: ["frameworks/av/include"],
+
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "libcrypto",
+ "liblog",
+ "libprotobuf-cpp-lite",
+ "libutils",
+ "android.hardware.drm-V1-ndk",
+ ],
+
+ static_libs: [
+ "android.hardware.common-V2-ndk",
+ "libclearkeybase",
+ ],
+
+ local_include_dirs: ["include"],
+
+ sanitize: {
+ integer_overflow: true,
+ },
+}
+
+cc_binary {
+ name: "android.hardware.drm-service.clearkey",
+ defaults: ["aidl_clearkey_service_defaults"],
+ srcs: ["Service.cpp"],
+ init_rc: ["android.hardware.drm-service.clearkey.rc"],
+ vintf_fragments: ["android.hardware.drm-service.clearkey.xml"],
+}
+
+cc_binary {
+ name: "android.hardware.drm-service-lazy.clearkey",
+ defaults: ["aidl_clearkey_service_defaults"],
+ overrides: ["android.hardware.drm-service.clearkey"],
+ srcs: ["ServiceLazy.cpp"],
+ init_rc: ["android.hardware.drm-service-lazy.clearkey.rc"],
+ vintf_fragments: ["android.hardware.drm-service.clearkey.xml"],
+}
+
+phony {
+ name: "android.hardware.drm@latest-service.clearkey",
+ required: [
+ "android.hardware.drm-service.clearkey",
+ ],
+}
diff --git a/drm/mediadrm/plugins/clearkey/aidl/CreatePluginFactories.cpp b/drm/mediadrm/plugins/clearkey/aidl/CreatePluginFactories.cpp
new file mode 100644
index 0000000..4e6fe3a
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/CreatePluginFactories.cpp
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+#include "CreatePluginFactories.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace drm {
+namespace clearkey {
+
+std::shared_ptr<DrmFactory> createDrmFactory() {
+ return ::ndk::SharedRefBase::make<DrmFactory>();
+}
+
+} // namespace clearkey
+} // namespace drm
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/drm/mediadrm/plugins/clearkey/aidl/CryptoPlugin.cpp b/drm/mediadrm/plugins/clearkey/aidl/CryptoPlugin.cpp
new file mode 100644
index 0000000..651d8f5
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/CryptoPlugin.cpp
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2021 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 "clearkey-CryptoPlugin"
+
+#include <utils/Log.h>
+#include <cerrno>
+#include <cstring>
+
+#include "CryptoPlugin.h"
+#include "SessionLibrary.h"
+#include "AidlUtils.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace drm {
+namespace clearkey {
+
+using ::aidl::android::hardware::drm::Status;
+
+::ndk::ScopedAStatus CryptoPlugin::decrypt(const DecryptArgs& in_args, int32_t* _aidl_return) {
+ const char* detailedError = "";
+
+ *_aidl_return = 0;
+ if (in_args.secure) {
+ detailedError = "secure decryption is not supported with ClearKey";
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE, detailedError);
+ }
+
+ std::lock_guard<std::mutex> shared_buffer_lock(mSharedBufferLock);
+ if (mSharedBufferMap.find(in_args.source.bufferId) == mSharedBufferMap.end()) {
+ detailedError = "source decrypt buffer base not set";
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE, detailedError);
+ }
+
+ const auto NON_SECURE = DestinationBuffer::Tag::nonsecureMemory;
+ if (in_args.destination.getTag() != NON_SECURE) {
+ detailedError = "destination type not supported";
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE, detailedError);
+ }
+
+ const SharedBuffer& destBuffer = in_args.destination.get<NON_SECURE>();
+ if (mSharedBufferMap.find(destBuffer.bufferId) == mSharedBufferMap.end()) {
+ detailedError = "destination decrypt buffer base not set";
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE, detailedError);
+ }
+
+ auto src = mSharedBufferMap[in_args.source.bufferId];
+ if (src->mBase == nullptr) {
+ detailedError = "source is a nullptr";
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE, detailedError);
+ }
+
+ size_t totalSize = 0;
+ if (__builtin_add_overflow(in_args.source.offset, in_args.offset, &totalSize) ||
+ __builtin_add_overflow(totalSize, in_args.source.size, &totalSize) ||
+ totalSize > src->mSize) {
+ android_errorWriteLog(0x534e4554, "176496160");
+ detailedError = "invalid buffer size";
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE, detailedError);
+ }
+
+ // destination type must be non-secure shared memory
+ auto dest = mSharedBufferMap[destBuffer.bufferId];
+ if (dest->mBase == nullptr) {
+ detailedError = "destination is a nullptr";
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE, detailedError);
+ }
+
+ totalSize = 0;
+ if (__builtin_add_overflow(destBuffer.offset, destBuffer.size, &totalSize) ||
+ totalSize > dest->mSize) {
+ android_errorWriteLog(0x534e4554, "176444622");
+ detailedError = "invalid buffer size";
+ return toNdkScopedAStatus(Status::ERROR_DRM_FRAME_TOO_LARGE, detailedError);
+ }
+
+ // Calculate the output buffer size and determine if any subsamples are
+ // encrypted.
+ uint8_t* srcPtr = src->mBase + in_args.source.offset + in_args.offset;
+ uint8_t* destPtr = dest->mBase + destBuffer.offset;
+ size_t destSize = 0;
+ size_t srcSize = 0;
+ bool haveEncryptedSubsamples = false;
+ for (size_t i = 0; i < in_args.subSamples.size(); i++) {
+ const SubSample& subSample = in_args.subSamples[i];
+ if (__builtin_add_overflow(destSize, subSample.numBytesOfClearData, &destSize) ||
+ __builtin_add_overflow(srcSize, subSample.numBytesOfClearData, &srcSize)) {
+ detailedError = "subsample clear size overflow";
+ return toNdkScopedAStatus(Status::ERROR_DRM_FRAME_TOO_LARGE, detailedError);
+ }
+ if (__builtin_add_overflow(destSize, subSample.numBytesOfEncryptedData, &destSize) ||
+ __builtin_add_overflow(srcSize, subSample.numBytesOfEncryptedData, &srcSize)) {
+ detailedError = "subsample encrypted size overflow";
+ return toNdkScopedAStatus(Status::ERROR_DRM_FRAME_TOO_LARGE, detailedError);
+ }
+ if (subSample.numBytesOfEncryptedData > 0) {
+ haveEncryptedSubsamples = true;
+ }
+ }
+
+ if (destSize > destBuffer.size || srcSize > in_args.source.size) {
+ detailedError = "subsample sum too large";
+ return toNdkScopedAStatus(Status::ERROR_DRM_FRAME_TOO_LARGE, detailedError);
+ }
+
+ if (in_args.mode == Mode::UNENCRYPTED) {
+ if (haveEncryptedSubsamples) {
+ detailedError = "Encrypted subsamples found in allegedly unencrypted data.";
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE, detailedError);
+ }
+
+ size_t offset = 0;
+ for (size_t i = 0; i < in_args.subSamples.size(); ++i) {
+ const SubSample& subSample = in_args.subSamples[i];
+ if (subSample.numBytesOfClearData != 0) {
+ memcpy(reinterpret_cast<uint8_t*>(destPtr) + offset,
+ reinterpret_cast<const uint8_t*>(srcPtr) + offset,
+ subSample.numBytesOfClearData);
+ offset += subSample.numBytesOfClearData;
+ }
+ }
+
+ *_aidl_return = static_cast<ssize_t>(offset);
+ return toNdkScopedAStatus(Status::OK);
+ } else if (in_args.mode == Mode::AES_CTR) {
+ size_t bytesDecrypted{};
+ std::vector<int32_t> clearDataLengths;
+ std::vector<int32_t> encryptedDataLengths;
+ for (auto ss : in_args.subSamples) {
+ clearDataLengths.push_back(ss.numBytesOfClearData);
+ encryptedDataLengths.push_back(ss.numBytesOfEncryptedData);
+ }
+ auto res =
+ mSession->decrypt(in_args.keyId.data(), in_args.iv.data(),
+ srcPtr, static_cast<uint8_t*>(destPtr),
+ clearDataLengths, encryptedDataLengths,
+ &bytesDecrypted);
+ if (res == clearkeydrm::OK) {
+ *_aidl_return = static_cast<ssize_t>(bytesDecrypted);
+ return toNdkScopedAStatus(Status::OK);
+ } else {
+ *_aidl_return = 0;
+ detailedError = "Decryption Error";
+ return toNdkScopedAStatus(static_cast<Status>(res), detailedError);
+ }
+ } else {
+ *_aidl_return = 0;
+ detailedError = "selected encryption mode is not supported by the ClearKey DRM Plugin";
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE, detailedError);
+ }
+}
+
+::ndk::ScopedAStatus CryptoPlugin::getLogMessages(
+ std::vector<::aidl::android::hardware::drm::LogMessage>* _aidl_return) {
+ using std::chrono::duration_cast;
+ using std::chrono::milliseconds;
+ using std::chrono::system_clock;
+
+ auto timeMillis = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
+
+ std::vector<::aidl::android::hardware::drm::LogMessage> logs = {
+ {timeMillis, ::aidl::android::hardware::drm::LogPriority::ERROR,
+ std::string("Not implemented")}};
+ *_aidl_return = logs;
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus CryptoPlugin::notifyResolution(int32_t in_width, int32_t in_height) {
+ UNUSED(in_width);
+ UNUSED(in_height);
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus CryptoPlugin::requiresSecureDecoderComponent(const std::string& in_mime,
+ bool* _aidl_return) {
+ UNUSED(in_mime);
+ *_aidl_return = false;
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus CryptoPlugin::setMediaDrmSession(const std::vector<uint8_t>& in_sessionId) {
+ Status status = Status::OK;
+ if (!in_sessionId.size()) {
+ mSession = nullptr;
+ } else {
+ mSession = SessionLibrary::get()->findSession(in_sessionId);
+ if (!mSession.get()) {
+ status = Status::ERROR_DRM_SESSION_NOT_OPENED;
+ }
+ }
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus CryptoPlugin::setSharedBufferBase(const SharedBuffer& in_base) {
+ std::lock_guard<std::mutex> shared_buffer_lock(mSharedBufferLock);
+ mSharedBufferMap[in_base.bufferId] = std::make_shared<SharedBufferBase>(in_base);
+ return ::ndk::ScopedAStatus::ok();
+}
+
+SharedBufferBase::SharedBufferBase(const SharedBuffer& mem)
+ : mBase(nullptr),
+ mSize(mem.size) {
+ if (mem.handle.fds.empty()) {
+ return;
+ }
+ auto fd = mem.handle.fds[0].get();
+ auto addr = mmap(nullptr, mem.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (addr == MAP_FAILED) {
+ ALOGE("mmap err: fd %d; errno %s", fd, strerror(errno));
+ } else {
+ mBase = static_cast<uint8_t*>(addr);
+ }
+}
+
+SharedBufferBase::~SharedBufferBase() {
+ if (munmap(mBase, mSize)) {
+ ALOGE("munmap err: base %p; errno %s",
+ mBase, strerror(errno));
+ }
+}
+} // namespace clearkey
+} // namespace drm
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/drm/mediadrm/plugins/clearkey/aidl/DrmFactory.cpp b/drm/mediadrm/plugins/clearkey/aidl/DrmFactory.cpp
new file mode 100644
index 0000000..bef05ec
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/DrmFactory.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2021 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 "clearkey-DrmFactory"
+
+#include <utils/Log.h>
+
+#include "DrmFactory.h"
+
+#include "ClearKeyUUID.h"
+#include "CryptoPlugin.h"
+#include "DrmPlugin.h"
+#include "MimeTypeStdStr.h"
+#include "SessionLibrary.h"
+#include "AidlUtils.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace drm {
+namespace clearkey {
+
+using std::string;
+using std::vector;
+
+using ::aidl::android::hardware::drm::SecurityLevel;
+using ::aidl::android::hardware::drm::Status;
+using ::aidl::android::hardware::drm::Uuid;
+
+::ndk::ScopedAStatus DrmFactory::createDrmPlugin(
+ const Uuid& in_uuid, const string& in_appPackageName,
+ std::shared_ptr<::aidl::android::hardware::drm::IDrmPlugin>* _aidl_return) {
+ UNUSED(in_appPackageName);
+
+ if (!isClearKeyUUID(in_uuid.uuid.data())) {
+ ALOGE("Clearkey Drm HAL: failed to create drm plugin, "
+ "invalid crypto scheme");
+ *_aidl_return = nullptr;
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ std::shared_ptr<DrmPlugin> plugin =
+ ::ndk::SharedRefBase::make<DrmPlugin>(SessionLibrary::get());
+ *_aidl_return = plugin;
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmFactory::createCryptoPlugin(
+ const Uuid& in_uuid, const std::vector<uint8_t>& in_initData,
+ std::shared_ptr<::aidl::android::hardware::drm::ICryptoPlugin>* _aidl_return) {
+ if (!isClearKeyUUID(in_uuid.uuid.data())) {
+ ALOGE("Clearkey Drm HAL: failed to create crypto plugin, "
+ "invalid crypto scheme");
+ *_aidl_return = nullptr;
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ std::shared_ptr<CryptoPlugin> plugin = ::ndk::SharedRefBase::make<CryptoPlugin>(in_initData);
+ Status status = plugin->getInitStatus();
+ if (status != Status::OK) {
+ plugin.reset();
+ plugin = nullptr;
+ }
+ *_aidl_return = plugin;
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmFactory::getSupportedCryptoSchemes(CryptoSchemes* _aidl_return) {
+ CryptoSchemes schemes{};
+ for (const auto& uuid : ::aidl::android::hardware::drm::clearkey::getSupportedCryptoSchemes()) {
+ schemes.uuids.push_back({uuid});
+ }
+ schemes.minLevel = SecurityLevel::SW_SECURE_CRYPTO;
+ schemes.maxLevel = SecurityLevel::SW_SECURE_CRYPTO;
+ schemes.mimeTypes = {kIsoBmffVideoMimeType, kIsoBmffAudioMimeType, kCencInitDataFormat,
+ kWebmVideoMimeType, kWebmAudioMimeType, kWebmInitDataFormat};
+ *_aidl_return = schemes;
+ return ndk::ScopedAStatus::ok();
+}
+
+binder_status_t DrmFactory::dump(int fd, const char** args, uint32_t numArgs) {
+ UNUSED(args);
+ UNUSED(numArgs);
+
+ if (fd < 0) {
+ ALOGE("%s: negative fd", __FUNCTION__);
+ return STATUS_BAD_VALUE;
+ }
+
+ uint32_t currentSessions = SessionLibrary::get()->numOpenSessions();
+ dprintf(fd, "current open sessions: %u\n", currentSessions);
+
+ return STATUS_OK;
+}
+
+} // namespace clearkey
+} // namespace drm
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/drm/mediadrm/plugins/clearkey/aidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/aidl/DrmPlugin.cpp
new file mode 100644
index 0000000..7331ded
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/DrmPlugin.cpp
@@ -0,0 +1,1025 @@
+/*
+ * Copyright (C) 2021 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 "clearkey-DrmPlugin"
+
+#include <aidl/android/hardware/drm/DrmMetric.h>
+#include <utils/Log.h>
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <chrono>
+#include <set>
+
+#include "AidlUtils.h"
+#include "ClearKeyDrmProperties.h"
+#include "DrmPlugin.h"
+#include "Session.h"
+#include "Utils.h"
+
+namespace {
+const std::string kKeySetIdPrefix("ckid");
+const int kKeySetIdLength = 16;
+const int kSecureStopIdStart = 100;
+const std::string kOfflineLicense("\"type\":\"persistent-license\"");
+const std::string kStreaming("Streaming");
+const std::string kTemporaryLicense("\"type\":\"temporary\"");
+const std::string kTrue("True");
+
+const std::string kQueryKeyLicenseType("LicenseType");
+// Value: "Streaming" or "Offline"
+const std::string kQueryKeyPlayAllowed("PlayAllowed");
+// Value: "True" or "False"
+const std::string kQueryKeyRenewAllowed("RenewAllowed");
+// Value: "True" or "False"
+
+const int kSecureStopIdSize = 10;
+
+std::vector<uint8_t> uint32ToVector(uint32_t value) {
+ // 10 bytes to display max value 4294967295 + one byte null terminator
+ char buffer[kSecureStopIdSize];
+ memset(buffer, 0, kSecureStopIdSize);
+ snprintf(buffer, kSecureStopIdSize, "%" PRIu32, value);
+ return std::vector<uint8_t>(buffer, buffer + sizeof(buffer));
+}
+
+}; // unnamed namespace
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace drm {
+namespace clearkey {
+
+using ::android::Mutex;
+
+DrmPlugin::DrmPlugin(SessionLibrary* sessionLibrary)
+ : mSessionLibrary(sessionLibrary),
+ mOpenSessionOkCount(0),
+ mCloseSessionOkCount(0),
+ mCloseSessionNotOpenedCount(0),
+ mNextSecureStopId(kSecureStopIdStart),
+ mMockError(Status::OK) {
+ mPlayPolicy.clear();
+ initProperties();
+ mSecureStops.clear();
+ mReleaseKeysMap.clear();
+ std::srand(std::time(nullptr));
+}
+
+void DrmPlugin::initProperties() {
+ mStringProperties.clear();
+ mStringProperties[kVendorKey] = kVendorValue;
+ mStringProperties[kVersionKey] = kVersionValue;
+ mStringProperties[kPluginDescriptionKey] = kPluginDescriptionValue;
+ mStringProperties[kAlgorithmsKey] = kAlgorithmsValue;
+ mStringProperties[kListenerTestSupportKey] = kListenerTestSupportValue;
+ mStringProperties[kDrmErrorTestKey] = kDrmErrorTestValue;
+
+ std::vector<uint8_t> valueVector;
+ valueVector.clear();
+ valueVector.insert(valueVector.end(), kTestDeviceIdData,
+ kTestDeviceIdData + sizeof(kTestDeviceIdData) / sizeof(uint8_t));
+ mByteArrayProperties[kDeviceIdKey] = valueVector;
+
+ valueVector.clear();
+ valueVector.insert(valueVector.end(), kMetricsData,
+ kMetricsData + sizeof(kMetricsData) / sizeof(uint8_t));
+ mByteArrayProperties[kMetricsKey] = valueVector;
+}
+
+// The secure stop in ClearKey implementation is not installed securely.
+// This function merely creates a test environment for testing secure stops APIs.
+// The content in this secure stop is implementation dependent, the clearkey
+// secureStop does not serve as a reference implementation.
+void DrmPlugin::installSecureStop(const std::vector<uint8_t>& sessionId) {
+ ::android::Mutex::Autolock lock(mSecureStopLock);
+
+ ClearkeySecureStop clearkeySecureStop;
+ clearkeySecureStop.id = uint32ToVector(++mNextSecureStopId);
+ clearkeySecureStop.data.assign(sessionId.begin(), sessionId.end());
+
+ mSecureStops.insert(std::pair<std::vector<uint8_t>, ClearkeySecureStop>(clearkeySecureStop.id,
+ clearkeySecureStop));
+}
+
+::ndk::ScopedAStatus DrmPlugin::closeSession(const std::vector<uint8_t>& in_sessionId) {
+ if (in_sessionId.size() == 0) {
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ ::android::sp<Session> session = mSessionLibrary->findSession(in_sessionId);
+ if (session.get()) {
+ mSessionLibrary->destroySession(session);
+ if (session->getMockError() != clearkeydrm::OK) {
+ sendSessionLostState(in_sessionId);
+ return toNdkScopedAStatus(Status::ERROR_DRM_INVALID_STATE);
+ }
+ mCloseSessionOkCount++;
+ return toNdkScopedAStatus(Status::OK);
+ }
+ mCloseSessionNotOpenedCount++;
+ return toNdkScopedAStatus(Status::ERROR_DRM_SESSION_NOT_OPENED);
+}
+
+::ndk::ScopedAStatus DrmPlugin::decrypt(const std::vector<uint8_t>& in_sessionId,
+ const std::vector<uint8_t>& in_keyId,
+ const std::vector<uint8_t>& in_input,
+ const std::vector<uint8_t>& in_iv,
+ std::vector<uint8_t>* _aidl_return) {
+ *_aidl_return = {};
+ if (in_sessionId.size() == 0 || in_keyId.size() == 0 || in_input.size() == 0 ||
+ in_iv.size() == 0) {
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+}
+
+::ndk::ScopedAStatus DrmPlugin::encrypt(const std::vector<uint8_t>& in_sessionId,
+ const std::vector<uint8_t>& in_keyId,
+ const std::vector<uint8_t>& in_input,
+ const std::vector<uint8_t>& in_iv,
+ std::vector<uint8_t>* _aidl_return) {
+ *_aidl_return = {};
+ if (in_sessionId.size() == 0 || in_keyId.size() == 0 || in_input.size() == 0 ||
+ in_iv.size() == 0) {
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getHdcpLevels(
+ ::aidl::android::hardware::drm::HdcpLevels* _aidl_return) {
+ _aidl_return->connectedLevel = HdcpLevel::HDCP_NONE;
+ _aidl_return->maxLevel = HdcpLevel::HDCP_NO_OUTPUT;
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getKeyRequest(
+ const std::vector<uint8_t>& in_scope, const std::vector<uint8_t>& in_initData,
+ const std::string& in_mimeType, ::aidl::android::hardware::drm::KeyType in_keyType,
+ const std::vector<::aidl::android::hardware::drm::KeyValue>& in_optionalParameters,
+ ::aidl::android::hardware::drm::KeyRequest* _aidl_return) {
+ UNUSED(in_optionalParameters);
+
+ KeyRequestType keyRequestType = KeyRequestType::UNKNOWN;
+ std::string defaultUrl("https://default.url");
+
+ _aidl_return->request = {};
+ _aidl_return->requestType = keyRequestType;
+ _aidl_return->defaultUrl = defaultUrl;
+
+ if (in_scope.size() == 0 ||
+ (in_keyType != KeyType::STREAMING && in_keyType != KeyType::OFFLINE &&
+ in_keyType != KeyType::RELEASE)) {
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ const std::vector<uint8_t> scopeId = in_scope;
+ ::android::sp<Session> session;
+ std::set<KeyType> init_types{KeyType::STREAMING, KeyType::OFFLINE};
+ if (init_types.count(in_keyType)) {
+ std::vector<uint8_t> sessionId(scopeId.begin(), scopeId.end());
+ session = mSessionLibrary->findSession(sessionId);
+ if (!session.get()) {
+ return toNdkScopedAStatus(Status::ERROR_DRM_SESSION_NOT_OPENED);
+ } else if (session->getMockError() != clearkeydrm::OK) {
+ return toNdkScopedAStatus(session->getMockError());
+ }
+ keyRequestType = KeyRequestType::INITIAL;
+ }
+
+ std::vector<uint8_t> request = {};
+ auto keyType = static_cast<CdmKeyType>(in_keyType);
+ auto status = session->getKeyRequest(in_initData, in_mimeType, keyType, &request);
+
+ if (in_keyType == KeyType::RELEASE) {
+ std::vector<uint8_t> keySetId(scopeId.begin(), scopeId.end());
+ std::string requestString(request.begin(), request.end());
+ if (requestString.find(kOfflineLicense) != std::string::npos) {
+ std::string emptyResponse;
+ std::string keySetIdString(keySetId.begin(), keySetId.end());
+ if (!mFileHandle.StoreLicense(keySetIdString, DeviceFiles::kLicenseStateReleasing,
+ emptyResponse)) {
+ ALOGE("Problem releasing offline license");
+ return toNdkScopedAStatus(Status::ERROR_DRM_UNKNOWN);
+ }
+ if (mReleaseKeysMap.find(keySetIdString) == mReleaseKeysMap.end()) {
+ ::android::sp<Session> session = mSessionLibrary->createSession();
+ mReleaseKeysMap[keySetIdString] = session->sessionId();
+ } else {
+ ALOGI("key is in use, ignore release request");
+ }
+ } else {
+ ALOGE("Offline license not found, nothing to release");
+ }
+ keyRequestType = KeyRequestType::RELEASE;
+ }
+ _aidl_return->request = request;
+ _aidl_return->requestType = keyRequestType;
+ _aidl_return->defaultUrl = defaultUrl;
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getLogMessages(
+ std::vector<::aidl::android::hardware::drm::LogMessage>* _aidl_return) {
+ using std::chrono::duration_cast;
+ using std::chrono::milliseconds;
+ using std::chrono::system_clock;
+
+ auto timeMillis = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
+
+ std::vector<::aidl::android::hardware::drm::LogMessage> logs = {
+ {timeMillis, ::aidl::android::hardware::drm::LogPriority::ERROR,
+ std::string("Not implemented")}};
+ *_aidl_return = logs;
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getMetrics(
+ std::vector<::aidl::android::hardware::drm::DrmMetricGroup>* _aidl_return) {
+ // Set the open session count metric.
+ DrmMetricNamedValue openSessionOkAttribute = {"status", static_cast<int64_t>(Status::OK)};
+ DrmMetricNamedValue openSessionMetricValue = {"count", mOpenSessionOkCount};
+ DrmMetric openSessionMetric = {
+ "open_session", {openSessionOkAttribute}, {openSessionMetricValue}};
+
+ // Set the close session count metric.
+ DrmMetricNamedValue closeSessionOkAttribute = {"status", static_cast<int64_t>(Status::OK)};
+ DrmMetricNamedValue closeSessionMetricValue = {"count", mCloseSessionOkCount};
+ DrmMetric closeSessionMetric = {
+ "close_session", {closeSessionOkAttribute}, {closeSessionMetricValue}};
+
+ // Set the close session, not opened metric.
+ DrmMetricNamedValue closeSessionNotOpenedAttribute = {"status",
+ static_cast<int64_t>(Status::ERROR_DRM_SESSION_NOT_OPENED)};
+ DrmMetricNamedValue closeSessionNotOpenedMetricValue = {"count", mCloseSessionNotOpenedCount};
+ DrmMetric closeSessionNotOpenedMetric = {
+ "close_session", {closeSessionNotOpenedAttribute}, {closeSessionNotOpenedMetricValue}};
+
+ // Set the setPlaybackId metric.
+ std::vector<DrmMetricNamedValue> sids = {};
+ std::vector<DrmMetricNamedValue> playbackIds = {};
+ for (const auto& [key, value] : mPlaybackId) {
+ std::string sid(key.begin(), key.end());
+ DrmMetricNamedValue sessionIdAttribute = {"sid", sid};
+ sids.push_back(sessionIdAttribute);
+
+ DrmMetricNamedValue playbackIdMetricValue = {"playbackId", value};
+ playbackIds.push_back(playbackIdMetricValue);
+ }
+ DrmMetric setPlaybackIdMetric = {"set_playback_id", sids, playbackIds};
+
+ DrmMetricGroup metrics = {{openSessionMetric, closeSessionMetric, closeSessionNotOpenedMetric,
+ setPlaybackIdMetric}};
+
+ *_aidl_return = {metrics};
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getNumberOfSessions(
+ ::aidl::android::hardware::drm::NumberOfSessions* _aidl_return) {
+ _aidl_return->currentSessions = mSessionLibrary->numOpenSessions();
+ _aidl_return->maxSessions = 10;
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getOfflineLicenseKeySetIds(
+ std::vector<::aidl::android::hardware::drm::KeySetId>* _aidl_return) {
+ std::vector<std::string> licenseNames = mFileHandle.ListLicenses();
+ std::vector<KeySetId> keySetIds = {};
+ if (mMockError != Status::OK) {
+ *_aidl_return = keySetIds;
+ return toNdkScopedAStatus(toMockStatus(mMockError));
+ }
+ for (const auto& name : licenseNames) {
+ std::vector<uint8_t> keySetId(name.begin(), name.end());
+ KeySetId id = {};
+ id.keySetId = keySetId;
+ keySetIds.push_back(id);
+ }
+ *_aidl_return = keySetIds;
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getOfflineLicenseState(
+ const ::aidl::android::hardware::drm::KeySetId& in_keySetId,
+ ::aidl::android::hardware::drm::OfflineLicenseState* _aidl_return) {
+ std::string licenseName(in_keySetId.keySetId.begin(), in_keySetId.keySetId.end());
+ DeviceFiles::LicenseState state;
+ std::string license;
+ OfflineLicenseState licenseState = OfflineLicenseState::UNKNOWN;
+ Status status = Status::OK;
+ if (mMockError != Status::OK) {
+ *_aidl_return = licenseState;
+ return toNdkScopedAStatus(toMockStatus(mMockError));
+ } else if (mFileHandle.RetrieveLicense(licenseName, &state, &license)) {
+ switch (state) {
+ case DeviceFiles::kLicenseStateActive:
+ licenseState = OfflineLicenseState::USABLE;
+ break;
+ case DeviceFiles::kLicenseStateReleasing:
+ licenseState = OfflineLicenseState::INACTIVE;
+ break;
+ case DeviceFiles::kLicenseStateUnknown:
+ licenseState = OfflineLicenseState::UNKNOWN;
+ break;
+ }
+ } else {
+ status = Status::BAD_VALUE;
+ }
+ *_aidl_return = licenseState;
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getPropertyByteArray(const std::string& in_propertyName,
+ std::vector<uint8_t>* _aidl_return) {
+ std::map<std::string, std::vector<uint8_t>>::iterator itr =
+ mByteArrayProperties.find(std::string(in_propertyName.c_str()));
+ Status status = Status::OK;
+ if (itr != mByteArrayProperties.end()) {
+ *_aidl_return = itr->second;
+ } else {
+ ALOGE("App requested unknown property: %s", in_propertyName.c_str());
+ status = Status::BAD_VALUE;
+ *_aidl_return = {};
+ }
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getPropertyString(const std::string& in_propertyName,
+ std::string* _aidl_return) {
+ std::string name(in_propertyName.c_str());
+ std::string value;
+ Status status = Status::OK;
+
+ if (name == kVendorKey) {
+ value = mStringProperties[kVendorKey];
+ } else if (name == kVersionKey) {
+ value = mStringProperties[kVersionKey];
+ } else if (name == kPluginDescriptionKey) {
+ value = mStringProperties[kPluginDescriptionKey];
+ } else if (name == kAlgorithmsKey) {
+ value = mStringProperties[kAlgorithmsKey];
+ } else if (name == kListenerTestSupportKey) {
+ value = mStringProperties[kListenerTestSupportKey];
+ } else if (name == kDrmErrorTestKey) {
+ value = mStringProperties[kDrmErrorTestKey];
+ } else {
+ ALOGE("App requested unknown string property %s", name.c_str());
+ status = Status::ERROR_DRM_CANNOT_HANDLE;
+ }
+ *_aidl_return = value;
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getProvisionRequest(
+ const std::string& in_certificateType, const std::string& in_certificateAuthority,
+ ::aidl::android::hardware::drm::ProvisionRequest* _aidl_return) {
+ UNUSED(in_certificateType);
+ UNUSED(in_certificateAuthority);
+ _aidl_return->request = {};
+ _aidl_return->defaultUrl = {};
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getSecureStop(
+ const ::aidl::android::hardware::drm::SecureStopId& in_secureStopId,
+ ::aidl::android::hardware::drm::SecureStop* _aidl_return) {
+ std::vector<uint8_t> stop = {};
+
+ mSecureStopLock.lock();
+ auto itr = mSecureStops.find(in_secureStopId.secureStopId);
+ if (itr != mSecureStops.end()) {
+ ClearkeySecureStop clearkeyStop = itr->second;
+ stop.insert(stop.end(), clearkeyStop.id.begin(), clearkeyStop.id.end());
+ stop.insert(stop.end(), clearkeyStop.data.begin(), clearkeyStop.data.end());
+ }
+ mSecureStopLock.unlock();
+
+ SecureStop secureStop = {};
+ Status status = Status::OK;
+ if (!stop.empty()) {
+ secureStop.opaqueData = stop;
+ } else {
+ status = Status::BAD_VALUE;
+ }
+ *_aidl_return = secureStop;
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getSecureStopIds(
+ std::vector<::aidl::android::hardware::drm::SecureStopId>* _aidl_return) {
+ mSecureStopLock.lock();
+ std::vector<::aidl::android::hardware::drm::SecureStopId> ids;
+ for (auto itr = mSecureStops.begin(); itr != mSecureStops.end(); ++itr) {
+ SecureStopId id;
+ id.secureStopId = itr->first;
+ ids.push_back(id);
+ }
+ mSecureStopLock.unlock();
+
+ *_aidl_return = ids;
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getSecureStops(
+ std::vector<::aidl::android::hardware::drm::SecureStop>* _aidl_return) {
+ mSecureStopLock.lock();
+ std::vector<::aidl::android::hardware::drm::SecureStop> stops;
+ for (auto itr = mSecureStops.begin(); itr != mSecureStops.end(); ++itr) {
+ ClearkeySecureStop clearkeyStop = itr->second;
+ std::vector<uint8_t> stop{};
+ stop.insert(stop.end(), clearkeyStop.id.begin(), clearkeyStop.id.end());
+ stop.insert(stop.end(), clearkeyStop.data.begin(), clearkeyStop.data.end());
+
+ SecureStop secureStop;
+ secureStop.opaqueData = stop;
+ stops.push_back(secureStop);
+ }
+ mSecureStopLock.unlock();
+
+ *_aidl_return = stops;
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getSecurityLevel(
+ const std::vector<uint8_t>& in_sessionId,
+ ::aidl::android::hardware::drm::SecurityLevel* _aidl_return) {
+ if (in_sessionId.size() == 0) {
+ *_aidl_return = ::aidl::android::hardware::drm::SecurityLevel::UNKNOWN;
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ std::vector<uint8_t> sid = in_sessionId;
+ ::android::sp<Session> session = mSessionLibrary->findSession(sid);
+ if (!session.get()) {
+ *_aidl_return = SecurityLevel::UNKNOWN;
+ return toNdkScopedAStatus(Status::ERROR_DRM_SESSION_NOT_OPENED);
+ }
+
+ std::map<std::vector<uint8_t>, ::aidl::android::hardware::drm::SecurityLevel>::iterator itr =
+ mSecurityLevel.find(sid);
+ if (itr == mSecurityLevel.end()) {
+ ALOGE("Session id not found");
+ *_aidl_return = SecurityLevel::UNKNOWN;
+ return toNdkScopedAStatus(Status::ERROR_DRM_INVALID_STATE);
+ }
+
+ *_aidl_return = SecurityLevel::SW_SECURE_CRYPTO;
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmPlugin::openSession(
+ ::aidl::android::hardware::drm::SecurityLevel in_securityLevel,
+ std::vector<uint8_t>* _aidl_return) {
+ ::android::sp<Session> session = mSessionLibrary->createSession();
+ processMockError(session);
+ std::vector<uint8_t> sessionId = session->sessionId();
+
+ Status status = setSecurityLevel(sessionId, in_securityLevel);
+ if (status == Status::OK) {
+ mOpenSessionOkCount++;
+ } else {
+ mSessionLibrary->destroySession(session);
+ sessionId.clear();
+ }
+ *_aidl_return = sessionId;
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmPlugin::provideKeyResponse(
+ const std::vector<uint8_t>& in_scope, const std::vector<uint8_t>& in_response,
+ ::aidl::android::hardware::drm::KeySetId* _aidl_return) {
+ if (in_scope.size() == 0 || in_response.size() == 0) {
+ // Returns empty keySetId
+ *_aidl_return = {};
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ std::string responseString(reinterpret_cast<const char*>(in_response.data()),
+ in_response.size());
+ const std::vector<uint8_t> scopeId = in_scope;
+ std::vector<uint8_t> sessionId = {};
+ std::string keySetId;
+
+ bool isOfflineLicense = responseString.find(kOfflineLicense) != std::string::npos;
+ if (scopeId.size() < kKeySetIdPrefix.size()) {
+ android_errorWriteLog(0x534e4554, "144507096");
+ *_aidl_return = {};
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+ }
+ bool isRelease = (memcmp(scopeId.data(), kKeySetIdPrefix.data(), kKeySetIdPrefix.size()) == 0);
+ if (isRelease) {
+ keySetId.assign(scopeId.begin(), scopeId.end());
+
+ auto iter = mReleaseKeysMap.find(std::string(keySetId.begin(), keySetId.end()));
+ if (iter != mReleaseKeysMap.end()) {
+ sessionId.assign(iter->second.begin(), iter->second.end());
+ }
+ } else {
+ sessionId.assign(scopeId.begin(), scopeId.end());
+ // non offline license returns empty keySetId
+ keySetId.clear();
+ }
+
+ ::android::sp<Session> session = mSessionLibrary->findSession(sessionId);
+ if (!session.get()) {
+ *_aidl_return = {};
+ return toNdkScopedAStatus(Status::ERROR_DRM_SESSION_NOT_OPENED);
+ }
+ setPlayPolicy();
+
+ auto res = session->provideKeyResponse(in_response);
+ if (res == clearkeydrm::OK) {
+ if (isOfflineLicense) {
+ if (isRelease) {
+ mFileHandle.DeleteLicense(keySetId);
+ mSessionLibrary->destroySession(session);
+ } else {
+ if (!makeKeySetId(&keySetId)) {
+ *_aidl_return = {};
+ return toNdkScopedAStatus(Status::ERROR_DRM_UNKNOWN);
+ }
+
+ bool ok = mFileHandle.StoreLicense(
+ keySetId, DeviceFiles::kLicenseStateActive,
+ std::string(in_response.begin(), in_response.end()));
+ if (!ok) {
+ ALOGE("Failed to store offline license");
+ }
+ }
+ }
+
+ // Test calling AMediaDrm listeners.
+ sendEvent(EventType::VENDOR_DEFINED, sessionId, sessionId);
+
+ sendExpirationUpdate(sessionId, 100);
+
+ std::vector<KeyStatus> keysStatus = {};
+ KeyStatus keyStatus;
+
+ std::vector<uint8_t> keyId1 = {0xA, 0xB, 0xC};
+ keyStatus.keyId = keyId1;
+ keyStatus.type = KeyStatusType::USABLE;
+ keysStatus.push_back(keyStatus);
+
+ std::vector<uint8_t> keyId2 = {0xD, 0xE, 0xF};
+ keyStatus.keyId = keyId2;
+ keyStatus.type = KeyStatusType::EXPIRED;
+ keysStatus.push_back(keyStatus);
+
+ std::vector<uint8_t> keyId3 = {0x0, 0x1, 0x2};
+ keyStatus.keyId = keyId3;
+ keyStatus.type = KeyStatusType::USABLE_IN_FUTURE;
+ keysStatus.push_back(keyStatus);
+
+ sendKeysChange(sessionId, keysStatus, true);
+
+ installSecureStop(sessionId);
+ } else {
+ ALOGE("provideKeyResponse returns error=%d", res);
+ }
+
+ std::vector<uint8_t> keySetIdVec(keySetId.begin(), keySetId.end());
+ _aidl_return->keySetId = keySetIdVec;
+ return toNdkScopedAStatus(res);
+}
+
+::ndk::ScopedAStatus DrmPlugin::provideProvisionResponse(
+ const std::vector<uint8_t>& in_response,
+ ::aidl::android::hardware::drm::ProvideProvisionResponseResult* _aidl_return) {
+ Status status = Status::ERROR_DRM_CANNOT_HANDLE;
+ _aidl_return->certificate = {};
+ _aidl_return->wrappedKey = {};
+ if (in_response.size() == 0) {
+ status = Status::BAD_VALUE;
+ }
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmPlugin::queryKeyStatus(
+ const std::vector<uint8_t>& in_sessionId,
+ std::vector<::aidl::android::hardware::drm::KeyValue>* _aidl_return) {
+ if (in_sessionId.size() == 0) {
+ // Returns empty key status KeyValue pair
+ *_aidl_return = {};
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ std::vector<KeyValue> infoMap = {};
+ mPlayPolicyLock.lock();
+ KeyValue keyValuePair;
+ for (size_t i = 0; i < mPlayPolicy.size(); ++i) {
+ keyValuePair.key = mPlayPolicy[i].key;
+ keyValuePair.value = mPlayPolicy[i].value;
+ infoMap.push_back(keyValuePair);
+ }
+ mPlayPolicyLock.unlock();
+ *_aidl_return = infoMap;
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmPlugin::releaseAllSecureStops() {
+ Status status = Status::OK;
+ const auto res = removeAllSecureStops();
+ if (!res.isOk() && res.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+ status = static_cast<Status>(res.getServiceSpecificError());
+ }
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmPlugin::releaseSecureStop(
+ const ::aidl::android::hardware::drm::SecureStopId& in_secureStopId) {
+ Status status = Status::OK;
+ const auto res = removeSecureStop(in_secureStopId);
+ if (!res.isOk() && res.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+ status = static_cast<Status>(res.getServiceSpecificError());
+ }
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmPlugin::releaseSecureStops(
+ const ::aidl::android::hardware::drm::OpaqueData& in_ssRelease) {
+ // OpaqueData starts with 4 byte decimal integer string
+ const size_t kFourBytesOffset = 4;
+ if (in_ssRelease.opaqueData.size() < kFourBytesOffset) {
+ ALOGE("Invalid secureStopRelease length");
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ Status status = Status::OK;
+ std::vector<uint8_t> input = in_ssRelease.opaqueData;
+
+ if (input.size() < kSecureStopIdSize + kFourBytesOffset) {
+ // The minimum size of secure stop has to contain
+ // a 4 bytes count and one secureStop id
+ ALOGE("Total size of secureStops is too short");
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ // The format of opaqueData is shared between the server
+ // and the drm service. The clearkey implementation consists of:
+ // count - number of secure stops
+ // list of fixed length secure stops
+ size_t countBufferSize = sizeof(uint32_t);
+ if (input.size() < countBufferSize) {
+ // SafetyNet logging
+ android_errorWriteLog(0x534e4554, "144766455");
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+ uint32_t count = 0;
+ sscanf(reinterpret_cast<char*>(input.data()), "%04" PRIu32, &count);
+
+ // Avoid divide by 0 below.
+ if (count == 0) {
+ ALOGE("Invalid 0 secureStop count");
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ // Computes the fixed length secureStop size
+ size_t secureStopSize = (input.size() - kFourBytesOffset) / count;
+ if (secureStopSize < kSecureStopIdSize) {
+ // A valid secureStop contains the id plus data
+ ALOGE("Invalid secureStop size");
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+ uint8_t* buffer = new uint8_t[secureStopSize];
+ size_t offset = kFourBytesOffset; // skip the count
+ for (size_t i = 0; i < count; ++i, offset += secureStopSize) {
+ memcpy(buffer, input.data() + offset, secureStopSize);
+
+ // A secureStop contains id+data, we only use the id for removal
+ std::vector<uint8_t> id(buffer, buffer + kSecureStopIdSize);
+ ::aidl::android::hardware::drm::SecureStopId secureStopId{id};
+ const auto res = removeSecureStop(secureStopId);
+ if (!res.isOk() && res.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+ status = static_cast<Status>(res.getServiceSpecificError());
+ }
+ if (Status::OK != status) break;
+ }
+
+ delete[] buffer;
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmPlugin::removeAllSecureStops() {
+ Mutex::Autolock lock(mSecureStopLock);
+
+ mSecureStops.clear();
+ mNextSecureStopId = kSecureStopIdStart;
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmPlugin::removeKeys(const std::vector<uint8_t>& in_sessionId) {
+ Status status = Status::ERROR_DRM_CANNOT_HANDLE;
+ if (in_sessionId.size() == 0) {
+ status = Status::BAD_VALUE;
+ }
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmPlugin::removeOfflineLicense(
+ const ::aidl::android::hardware::drm::KeySetId& in_keySetId) {
+ if (mMockError != Status::OK) {
+ return toNdkScopedAStatus(toMockStatus(mMockError));
+ }
+ Status status = Status::BAD_VALUE;
+ std::string licenseName(in_keySetId.keySetId.begin(), in_keySetId.keySetId.end());
+ if (mFileHandle.DeleteLicense(licenseName)) {
+ status = Status::OK;
+ }
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmPlugin::removeSecureStop(
+ const ::aidl::android::hardware::drm::SecureStopId& in_secureStopId) {
+ Mutex::Autolock lock(mSecureStopLock);
+
+ Status status = Status::OK;
+ if (1 != mSecureStops.erase(in_secureStopId.secureStopId)) {
+ status = Status::BAD_VALUE;
+ }
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmPlugin::requiresSecureDecoder(
+ const std::string& in_mime, ::aidl::android::hardware::drm::SecurityLevel in_level,
+ bool* _aidl_return) {
+ UNUSED(in_mime);
+ UNUSED(in_level);
+ *_aidl_return = false;
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus DrmPlugin::restoreKeys(
+ const std::vector<uint8_t>& in_sessionId,
+ const ::aidl::android::hardware::drm::KeySetId& in_keySetId) {
+ if (in_sessionId.size() == 0 || in_keySetId.keySetId.size() == 0) {
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ DeviceFiles::LicenseState licenseState;
+ std::string offlineLicense;
+ if (!mFileHandle.RetrieveLicense(
+ std::string(in_keySetId.keySetId.begin(), in_keySetId.keySetId.end()),
+ &licenseState, &offlineLicense)) {
+ ALOGE("Failed to restore offline license");
+ return toNdkScopedAStatus(Status::ERROR_DRM_NO_LICENSE);
+ }
+
+ if (DeviceFiles::kLicenseStateUnknown == licenseState ||
+ DeviceFiles::kLicenseStateReleasing == licenseState) {
+ ALOGE("Invalid license state=%d", licenseState);
+ return toNdkScopedAStatus(Status::ERROR_DRM_NO_LICENSE);
+ }
+
+ ::android::sp<Session> session = mSessionLibrary->findSession(in_sessionId);
+ if (!session.get()) {
+ return toNdkScopedAStatus(Status::ERROR_DRM_SESSION_NOT_OPENED);
+ }
+ auto res = session->provideKeyResponse(
+ std::vector<uint8_t>(offlineLicense.begin(), offlineLicense.end()));
+ if (res != clearkeydrm::OK) {
+ ALOGE("Failed to restore keys");
+ }
+ return toNdkScopedAStatus(res);
+}
+
+void DrmPlugin::sendEvent(::aidl::android::hardware::drm::EventType in_eventType,
+ const std::vector<uint8_t>& in_sessionId,
+ const std::vector<uint8_t>& in_data) {
+ if (mListener != nullptr) {
+ mListener->onEvent(in_eventType, in_sessionId, in_data);
+ } else {
+ ALOGE("Null event listener, event not sent");
+ }
+ return;
+}
+
+void DrmPlugin::sendExpirationUpdate(const std::vector<uint8_t>& in_sessionId,
+ int64_t in_expiryTimeInMS) {
+ if (mListener != nullptr) {
+ mListener->onExpirationUpdate(in_sessionId, in_expiryTimeInMS);
+ } else {
+ ALOGE("Null event listener, event not sent");
+ }
+ return;
+}
+
+void DrmPlugin::sendKeysChange(
+ const std::vector<uint8_t>& in_sessionId,
+ const std::vector<::aidl::android::hardware::drm::KeyStatus>& in_keyStatusList,
+ bool in_hasNewUsableKey) {
+ if (mListener != nullptr) {
+ mListener->onKeysChange(in_sessionId, in_keyStatusList, in_hasNewUsableKey);
+ } else {
+ ALOGE("Null event listener, event not sent");
+ }
+ return;
+}
+
+void DrmPlugin::sendSessionLostState(const std::vector<uint8_t>& in_sessionId) {
+ if (mListener != nullptr) {
+ mListener->onSessionLostState(in_sessionId);
+ }
+ return;
+}
+
+::ndk::ScopedAStatus DrmPlugin::setCipherAlgorithm(const std::vector<uint8_t>& /*in_sessionId*/,
+ const std::string& /*in_algorithm*/) {
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+}
+
+::ndk::ScopedAStatus DrmPlugin::setListener(
+ const std::shared_ptr<
+ ::aidl::android::hardware::drm::IDrmPluginListener>& in_listener) {
+ mListener = in_listener;
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmPlugin::setMacAlgorithm(const std::vector<uint8_t>& /*in_sessionId*/,
+ const std::string& /*in_algorithm*/) {
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+}
+
+::ndk::ScopedAStatus DrmPlugin::setPlaybackId(const std::vector<uint8_t>& in_sessionId,
+ const std::string& in_playbackId) {
+ if (in_sessionId.size() == 0) {
+ ALOGE("Invalid empty session id");
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ std::vector<uint8_t> sid = in_sessionId;
+ mPlaybackId[sid] = in_playbackId;
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmPlugin::setPropertyByteArray(const std::string& in_propertyName,
+ const std::vector<uint8_t>& in_value) {
+ if (in_propertyName == kDeviceIdKey) {
+ ALOGD("Cannot set immutable property: %s", in_propertyName.c_str());
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ } else if (in_propertyName == kClientIdKey) {
+ mByteArrayProperties[kClientIdKey] = in_value;
+ return toNdkScopedAStatus(Status::OK);
+ }
+
+ // Setting of undefined properties is not supported
+ ALOGE("Failed to set property byte array, key=%s", in_propertyName.c_str());
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+}
+
+::ndk::ScopedAStatus DrmPlugin::setPropertyString(const std::string& in_propertyName,
+ const std::string& in_value) {
+ std::string immutableKeys;
+ immutableKeys.append(kAlgorithmsKey + ",");
+ immutableKeys.append(kPluginDescriptionKey + ",");
+ immutableKeys.append(kVendorKey + ",");
+ immutableKeys.append(kVersionKey + ",");
+
+ std::string key = std::string(in_propertyName.c_str());
+ if (immutableKeys.find(key) != std::string::npos) {
+ ALOGD("Cannot set immutable property: %s", key.c_str());
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ std::map<std::string, std::string>::iterator itr = mStringProperties.find(key);
+ if (itr == mStringProperties.end()) {
+ ALOGE("Cannot set undefined property string, key=%s", key.c_str());
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ if (in_propertyName == kDrmErrorTestKey) {
+ if (in_value == kResourceContentionValue) {
+ mMockError = Status::ERROR_DRM_RESOURCE_CONTENTION;
+ } else if (in_value == kLostStateValue) {
+ mMockError = Status::ERROR_DRM_SESSION_LOST_STATE;
+ } else if (in_value == kFrameTooLargeValue) {
+ mMockError = Status::ERROR_DRM_FRAME_TOO_LARGE;
+ } else if (in_value == kInvalidStateValue) {
+ mMockError = Status::ERROR_DRM_INVALID_STATE;
+ } else {
+ mMockError = Status::ERROR_DRM_UNKNOWN;
+ }
+ }
+
+ mStringProperties[key] = std::string(in_value.c_str());
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmPlugin::sign(const std::vector<uint8_t>& /*in_sessionId*/,
+ const std::vector<uint8_t>& /*in_keyId*/,
+ const std::vector<uint8_t>& /*in_message*/,
+ std::vector<uint8_t>* _aidl_return) {
+ *_aidl_return = {};
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+}
+
+::ndk::ScopedAStatus DrmPlugin::signRSA(const std::vector<uint8_t>& /*in_sessionId*/,
+ const std::string& /*in_algorithm*/,
+ const std::vector<uint8_t>& /*in_message*/,
+ const std::vector<uint8_t>& /*in_wrappedkey*/,
+ std::vector<uint8_t>* _aidl_return) {
+ *_aidl_return = {};
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+}
+
+::ndk::ScopedAStatus DrmPlugin::verify(const std::vector<uint8_t>& /*in_sessionId*/,
+ const std::vector<uint8_t>& /*in_keyId*/,
+ const std::vector<uint8_t>& /*in_message*/,
+ const std::vector<uint8_t>& /*in_signature*/,
+ bool* _aidl_return) {
+ *_aidl_return = false;
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+}
+
+// Private methods below.
+void DrmPlugin::setPlayPolicy() {
+ ::android::Mutex::Autolock lock(mPlayPolicyLock);
+ mPlayPolicy.clear();
+
+ KeyValue policy;
+ policy.key = kQueryKeyLicenseType;
+ policy.value = kStreaming;
+ mPlayPolicy.push_back(policy);
+
+ policy.key = kQueryKeyPlayAllowed;
+ policy.value = kTrue;
+ mPlayPolicy.push_back(policy);
+
+ policy.key = kQueryKeyRenewAllowed;
+ mPlayPolicy.push_back(policy);
+}
+
+bool DrmPlugin::makeKeySetId(std::string* keySetId) {
+ if (!keySetId) {
+ ALOGE("keySetId destination not provided");
+ return false;
+ }
+ std::vector<uint8_t> ksid(kKeySetIdPrefix.begin(), kKeySetIdPrefix.end());
+ ksid.resize(kKeySetIdLength);
+ std::vector<uint8_t> randomData((kKeySetIdLength - kKeySetIdPrefix.size()) / 2, 0);
+
+ while (keySetId->empty()) {
+ for (auto itr = randomData.begin(); itr != randomData.end(); ++itr) {
+ *itr = std::rand() % 0xff;
+ }
+ auto id = reinterpret_cast<const uint8_t*>(randomData.data());
+ *keySetId = kKeySetIdPrefix + ::android::ByteArrayToHexString(id, randomData.size());
+ if (mFileHandle.LicenseExists(*keySetId)) {
+ // collision, regenerate
+ ALOGV("Retry generating KeySetId");
+ keySetId->clear();
+ }
+ }
+ return true;
+}
+
+Status DrmPlugin::setSecurityLevel(const std::vector<uint8_t>& sessionId, SecurityLevel level) {
+ if (sessionId.size() == 0) {
+ ALOGE("Invalid empty session id");
+ return Status::BAD_VALUE;
+ }
+
+ if (level != SecurityLevel::DEFAULT && level != SecurityLevel::SW_SECURE_CRYPTO) {
+ ALOGE("Cannot set security level > max");
+ return Status::ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ std::vector<uint8_t> sid = sessionId;
+ ::android::sp<Session> session = mSessionLibrary->findSession(sid);
+ if (!session.get()) {
+ return Status::ERROR_DRM_SESSION_NOT_OPENED;
+ }
+
+ std::map<std::vector<uint8_t>, SecurityLevel>::iterator itr = mSecurityLevel.find(sid);
+ if (itr != mSecurityLevel.end()) {
+ mSecurityLevel[sid] = level;
+ } else {
+ if (!mSecurityLevel.insert(std::pair<std::vector<uint8_t>, SecurityLevel>(sid, level))
+ .second) {
+ ALOGE("Failed to set security level");
+ return Status::ERROR_DRM_INVALID_STATE;
+ }
+ }
+ return Status::OK;
+}
+
+} // namespace clearkey
+} // namespace drm
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/drm/mediadrm/plugins/clearkey/aidl/Service.cpp b/drm/mediadrm/plugins/clearkey/aidl/Service.cpp
new file mode 100644
index 0000000..0b07864
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/Service.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021 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 1
+#define LOG_TAG "clearkey-main"
+
+#include "CreatePluginFactories.h"
+
+#include <android-base/logging.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using ::android::base::InitLogging;
+using ::android::base::LogdLogger;
+
+using ::aidl::android::hardware::drm::clearkey::createDrmFactory;
+using ::aidl::android::hardware::drm::clearkey::DrmFactory;
+
+int main(int /*argc*/, char* argv[]) {
+ InitLogging(argv, LogdLogger());
+ ::android::base::SetMinimumLogSeverity(::android::base::VERBOSE);
+ ABinderProcess_setThreadPoolMaxThreadCount(8);
+
+ std::shared_ptr<DrmFactory> drmFactory = createDrmFactory();
+ const std::string drmInstance = std::string() + DrmFactory::descriptor + "/clearkey";
+ binder_status_t status =
+ AServiceManager_addService(drmFactory->asBinder().get(), drmInstance.c_str());
+ CHECK(status == STATUS_OK);
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reached
+}
diff --git a/drm/mediadrm/plugins/clearkey/aidl/ServiceLazy.cpp b/drm/mediadrm/plugins/clearkey/aidl/ServiceLazy.cpp
new file mode 100644
index 0000000..c3a33bb
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/ServiceLazy.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021 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 1
+#define LOG_TAG "clearkey-main"
+
+#include "CreatePluginFactories.h"
+
+#include <android-base/logging.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using ::android::base::InitLogging;
+using ::android::base::LogdLogger;
+
+using ::aidl::android::hardware::drm::clearkey::createDrmFactory;
+using ::aidl::android::hardware::drm::clearkey::DrmFactory;
+
+int main(int /*argc*/, char* argv[]) {
+ InitLogging(argv, LogdLogger());
+ ::android::base::SetMinimumLogSeverity(::android::base::VERBOSE);
+ ABinderProcess_setThreadPoolMaxThreadCount(8);
+
+ std::shared_ptr<DrmFactory> drmFactory = createDrmFactory();
+ const std::string drmInstance = std::string() + DrmFactory::descriptor + "/clearkey";
+ binder_status_t status =
+ AServiceManager_registerLazyService(drmFactory->asBinder().get(), drmInstance.c_str());
+ CHECK(status == STATUS_OK);
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reached
+}
diff --git a/drm/mediadrm/plugins/clearkey/aidl/android.hardware.drm-service-lazy.clearkey.rc b/drm/mediadrm/plugins/clearkey/aidl/android.hardware.drm-service-lazy.clearkey.rc
new file mode 100644
index 0000000..019c726
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/android.hardware.drm-service-lazy.clearkey.rc
@@ -0,0 +1,9 @@
+service vendor.drm-clearkey-service /vendor/bin/hw/android.hardware.drm-service.clearkey
+ disabled
+ class hal
+ user media
+ group mediadrm drmrpc
+ ioprio rt 4
+ task_profiles ProcessCapacityHigh
+ interface aidl android.hardware.drm.IDrmFactory/clearkey
+ interface aidl android.hardware.drm.ICryptoFactory/clearkey
diff --git a/drm/mediadrm/plugins/clearkey/aidl/android.hardware.drm-service.clearkey.rc b/drm/mediadrm/plugins/clearkey/aidl/android.hardware.drm-service.clearkey.rc
new file mode 100644
index 0000000..e9252cd
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/android.hardware.drm-service.clearkey.rc
@@ -0,0 +1,7 @@
+service vendor.drm-clearkey-service /vendor/bin/hw/android.hardware.drm-service.clearkey
+ class hal
+ user media
+ group mediadrm drmrpc
+ ioprio rt 4
+ task_profiles ProcessCapacityHigh
+ interface aidl android.hardware.drm.IDrmFactory/clearkey
diff --git a/drm/mediadrm/plugins/clearkey/aidl/android.hardware.drm-service.clearkey.xml b/drm/mediadrm/plugins/clearkey/aidl/android.hardware.drm-service.clearkey.xml
new file mode 100644
index 0000000..ac3e922
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/android.hardware.drm-service.clearkey.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.drm</name>
+ <version>1</version>
+ <fqname>IDrmFactory/clearkey</fqname>
+ </hal>
+</manifest>
diff --git a/drm/mediadrm/plugins/clearkey/aidl/include/AidlUtils.h b/drm/mediadrm/plugins/clearkey/aidl/include/AidlUtils.h
new file mode 100644
index 0000000..9257b17
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/include/AidlUtils.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2021 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 <string>
+#include <vector>
+
+#include <android/binder_auto_utils.h>
+#include "aidl/android/hardware/drm/Status.h"
+#include "ClearKeyTypes.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace drm {
+namespace clearkey {
+
+inline ::aidl::android::hardware::drm::Status toMockStatus(
+ ::aidl::android::hardware::drm::Status status) {
+ switch (status) {
+ case ::aidl::android::hardware::drm::Status::ERROR_DRM_INSUFFICIENT_SECURITY:
+ case ::aidl::android::hardware::drm::Status::ERROR_DRM_FRAME_TOO_LARGE:
+ case ::aidl::android::hardware::drm::Status::ERROR_DRM_SESSION_LOST_STATE:
+ return ::aidl::android::hardware::drm::Status::ERROR_DRM_UNKNOWN;
+ default:
+ return status;
+ }
+}
+
+inline ::ndk::ScopedAStatus toNdkScopedAStatus(::aidl::android::hardware::drm::Status status,
+ const char* msg = nullptr) {
+ if (Status::OK == status) {
+ return ::ndk::ScopedAStatus::ok();
+ } else {
+ auto err = static_cast<int32_t>(status);
+ if (msg) {
+ return ::ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(err, msg);
+ } else {
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(err);
+ }
+ }
+}
+
+inline ::ndk::ScopedAStatus toNdkScopedAStatus(clearkeydrm::CdmResponseType res) {
+ return toNdkScopedAStatus(static_cast<::aidl::android::hardware::drm::Status>(res));
+}
+
+#define UNUSED(x) (void)(x);
+
+} // namespace clearkey
+} // namespace drm
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/drm/mediadrm/plugins/clearkey/aidl/include/CreatePluginFactories.h b/drm/mediadrm/plugins/clearkey/aidl/include/CreatePluginFactories.h
new file mode 100644
index 0000000..e2afcf5
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/include/CreatePluginFactories.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 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 "DrmFactory.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace drm {
+namespace clearkey {
+
+std::shared_ptr<DrmFactory> createDrmFactory();
+
+} // namespace clearkey
+} // namespace drm
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/drm/mediadrm/plugins/clearkey/aidl/include/CryptoPlugin.h b/drm/mediadrm/plugins/clearkey/aidl/include/CryptoPlugin.h
new file mode 100644
index 0000000..60dbf77
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/include/CryptoPlugin.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2021 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 <aidl/android/hardware/drm/BnCryptoPlugin.h>
+#include <aidl/android/hardware/drm/Status.h>
+
+#include <aidl/android/hardware/common/Ashmem.h>
+
+#include <android/binder_auto_utils.h>
+
+#include <memory>
+#include <mutex>
+
+#include "ClearKeyTypes.h"
+#include "Session.h"
+
+namespace {
+static const size_t KEY_ID_SIZE = 16;
+static const size_t KEY_IV_SIZE = 16;
+} // namespace
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace drm {
+namespace clearkey {
+
+using namespace clearkeydrm;
+using ::aidl::android::hardware::drm::DecryptArgs;
+using ::aidl::android::hardware::drm::Status;
+
+struct SharedBufferBase {
+ uint8_t* mBase;
+ int64_t mSize;
+ SharedBufferBase(const ::aidl::android::hardware::drm::SharedBuffer& mem);
+ ~SharedBufferBase();
+};
+
+struct CryptoPlugin : public BnCryptoPlugin {
+ explicit CryptoPlugin(const std::vector<uint8_t>& sessionId) {
+ const auto res = setMediaDrmSession(sessionId);
+ mInitStatus = Status::OK;
+ if (!res.isOk() && res.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+ mInitStatus = static_cast<Status>(res.getServiceSpecificError());
+ }
+ }
+ virtual ~CryptoPlugin() {}
+
+ ::ndk::ScopedAStatus decrypt(const DecryptArgs& in_args, int32_t* _aidl_return) override;
+
+ ::ndk::ScopedAStatus getLogMessages(
+ std::vector<::aidl::android::hardware::drm::LogMessage>* _aidl_return) override;
+
+ ::ndk::ScopedAStatus notifyResolution(int32_t in_width, int32_t in_height) override;
+
+ ::ndk::ScopedAStatus requiresSecureDecoderComponent(const std::string& in_mime,
+ bool* _aidl_return) override;
+
+ ::ndk::ScopedAStatus setMediaDrmSession(const std::vector<uint8_t>& in_sessionId) override;
+
+ ::ndk::ScopedAStatus setSharedBufferBase(
+ const ::aidl::android::hardware::drm::SharedBuffer& in_base) override;
+
+ ::aidl::android::hardware::drm::Status getInitStatus() const { return mInitStatus; }
+
+ private:
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(CryptoPlugin);
+
+ std::mutex mSharedBufferLock;
+ std::map<uint32_t, std::shared_ptr<SharedBufferBase>> mSharedBufferMap
+ GUARDED_BY(mSharedBufferLock);
+ ::android::sp<Session> mSession;
+ ::aidl::android::hardware::drm::Status mInitStatus;
+};
+
+} // namespace clearkey
+} // namespace drm
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/drm/mediadrm/plugins/clearkey/aidl/include/DrmFactory.h b/drm/mediadrm/plugins/clearkey/aidl/include/DrmFactory.h
new file mode 100644
index 0000000..1239aa4
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/include/DrmFactory.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2021 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 <aidl/android/hardware/drm/BnDrmFactory.h>
+#include <aidl/android/hardware/drm/IDrmFactory.h>
+#include <aidl/android/hardware/drm/IDrmPlugin.h>
+#include <aidl/android/hardware/drm/ICryptoPlugin.h>
+
+#include <string>
+#include <vector>
+
+#include "ClearKeyTypes.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace drm {
+namespace clearkey {
+
+struct DrmFactory : public BnDrmFactory {
+ DrmFactory() {}
+ virtual ~DrmFactory() {}
+
+ ::ndk::ScopedAStatus createDrmPlugin(
+ const ::aidl::android::hardware::drm::Uuid& in_uuid,
+ const std::string& in_appPackageName,
+ std::shared_ptr<::aidl::android::hardware::drm::IDrmPlugin>* _aidl_return) override;
+
+ ::ndk::ScopedAStatus createCryptoPlugin(
+ const ::aidl::android::hardware::drm::Uuid& in_uuid,
+ const std::vector<uint8_t>& in_initData,
+ std::shared_ptr<::aidl::android::hardware::drm::ICryptoPlugin>* _aidl_return) override;
+
+ ::ndk::ScopedAStatus getSupportedCryptoSchemes(
+ ::aidl::android::hardware::drm::CryptoSchemes* _aidl_return) override;
+
+ binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
+
+
+ private:
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(DrmFactory);
+};
+
+} // namespace clearkey
+} // namespace drm
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/drm/mediadrm/plugins/clearkey/aidl/include/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/aidl/include/DrmPlugin.h
new file mode 100644
index 0000000..25c05f0
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/include/DrmPlugin.h
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2021 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 <aidl/android/hardware/drm/BnDrmPlugin.h>
+#include <aidl/android/hardware/drm/IDrmPluginListener.h>
+#include <aidl/android/hardware/drm/Status.h>
+
+#include <stdio.h>
+#include <map>
+
+#include <utils/List.h>
+
+#include "DeviceFiles.h"
+#include "SessionLibrary.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace drm {
+namespace clearkey {
+
+using namespace clearkeydrm;
+using ::aidl::android::hardware::drm::KeyType;
+using ::aidl::android::hardware::drm::Status;
+
+struct DrmPlugin : public BnDrmPlugin {
+ public:
+ explicit DrmPlugin(SessionLibrary* sessionLibrary);
+ virtual ~DrmPlugin() { mFileHandle.DeleteAllLicenses(); }
+
+ ::ndk::ScopedAStatus closeSession(const std::vector<uint8_t>& in_sessionId) override;
+ ::ndk::ScopedAStatus decrypt(const std::vector<uint8_t>& in_sessionId,
+ const std::vector<uint8_t>& in_keyId,
+ const std::vector<uint8_t>& in_input,
+ const std::vector<uint8_t>& in_iv,
+ std::vector<uint8_t>* _aidl_return) override;
+ ::ndk::ScopedAStatus encrypt(const std::vector<uint8_t>& in_sessionId,
+ const std::vector<uint8_t>& in_keyId,
+ const std::vector<uint8_t>& in_input,
+ const std::vector<uint8_t>& in_iv,
+ std::vector<uint8_t>* _aidl_return) override;
+ ::ndk::ScopedAStatus getHdcpLevels(
+ ::aidl::android::hardware::drm::HdcpLevels* _aidl_return) override;
+ ::ndk::ScopedAStatus getKeyRequest(
+ const std::vector<uint8_t>& in_scope, const std::vector<uint8_t>& in_initData,
+ const std::string& in_mimeType, ::aidl::android::hardware::drm::KeyType in_keyType,
+ const std::vector<::aidl::android::hardware::drm::KeyValue>& in_optionalParameters,
+ ::aidl::android::hardware::drm::KeyRequest* _aidl_return) override;
+ ::ndk::ScopedAStatus getLogMessages(
+ std::vector<::aidl::android::hardware::drm::LogMessage>* _aidl_return) override;
+
+ ::ndk::ScopedAStatus getMetrics(
+ std::vector<::aidl::android::hardware::drm::DrmMetricGroup>* _aidl_return) override;
+ ::ndk::ScopedAStatus getNumberOfSessions(
+ ::aidl::android::hardware::drm::NumberOfSessions* _aidl_return) override;
+ ::ndk::ScopedAStatus getOfflineLicenseKeySetIds(
+ std::vector<::aidl::android::hardware::drm::KeySetId>* _aidl_return) override;
+ ::ndk::ScopedAStatus getOfflineLicenseState(
+ const ::aidl::android::hardware::drm::KeySetId& in_keySetId,
+ ::aidl::android::hardware::drm::OfflineLicenseState* _aidl_return) override;
+ ::ndk::ScopedAStatus getPropertyByteArray(const std::string& in_propertyName,
+ std::vector<uint8_t>* _aidl_return) override;
+ ::ndk::ScopedAStatus getPropertyString(const std::string& in_propertyName,
+ std::string* _aidl_return) override;
+ ::ndk::ScopedAStatus getProvisionRequest(
+ const std::string& in_certificateType, const std::string& in_certificateAuthority,
+ ::aidl::android::hardware::drm::ProvisionRequest* _aidl_return) override;
+ ::ndk::ScopedAStatus getSecureStop(
+ const ::aidl::android::hardware::drm::SecureStopId& in_secureStopId,
+ ::aidl::android::hardware::drm::SecureStop* _aidl_return) override;
+ ::ndk::ScopedAStatus getSecureStopIds(
+ std::vector<::aidl::android::hardware::drm::SecureStopId>* _aidl_return) override;
+ ::ndk::ScopedAStatus getSecureStops(
+ std::vector<::aidl::android::hardware::drm::SecureStop>* _aidl_return) override;
+ ::ndk::ScopedAStatus getSecurityLevel(
+ const std::vector<uint8_t>& in_sessionId,
+ ::aidl::android::hardware::drm::SecurityLevel* _aidl_return) override;
+ ::ndk::ScopedAStatus openSession(::aidl::android::hardware::drm::SecurityLevel in_securityLevel,
+ std::vector<uint8_t>* _aidl_return) override;
+ ::ndk::ScopedAStatus provideKeyResponse(
+ const std::vector<uint8_t>& in_scope, const std::vector<uint8_t>& in_response,
+ ::aidl::android::hardware::drm::KeySetId* _aidl_return) override;
+ ::ndk::ScopedAStatus provideProvisionResponse(
+ const std::vector<uint8_t>& in_response,
+ ::aidl::android::hardware::drm::ProvideProvisionResponseResult* _aidl_return) override;
+ ::ndk::ScopedAStatus queryKeyStatus(
+ const std::vector<uint8_t>& in_sessionId,
+ std::vector<::aidl::android::hardware::drm::KeyValue>* _aidl_return) override;
+ ::ndk::ScopedAStatus releaseAllSecureStops() override;
+ ::ndk::ScopedAStatus releaseSecureStop(
+ const ::aidl::android::hardware::drm::SecureStopId& in_secureStopId) override;
+ ::ndk::ScopedAStatus releaseSecureStops(
+ const ::aidl::android::hardware::drm::OpaqueData& in_ssRelease) override;
+ ::ndk::ScopedAStatus removeAllSecureStops() override;
+ ::ndk::ScopedAStatus removeKeys(const std::vector<uint8_t>& in_sessionId) override;
+ ::ndk::ScopedAStatus removeOfflineLicense(
+ const ::aidl::android::hardware::drm::KeySetId& in_keySetId) override;
+ ::ndk::ScopedAStatus removeSecureStop(
+ const ::aidl::android::hardware::drm::SecureStopId& in_secureStopId) override;
+ ::ndk::ScopedAStatus requiresSecureDecoder(
+ const std::string& in_mime, ::aidl::android::hardware::drm::SecurityLevel in_level,
+ bool* _aidl_return) override;
+ ::ndk::ScopedAStatus restoreKeys(
+ const std::vector<uint8_t>& in_sessionId,
+ const ::aidl::android::hardware::drm::KeySetId& in_keySetId) override;
+ ::ndk::ScopedAStatus setCipherAlgorithm(const std::vector<uint8_t>& in_sessionId,
+ const std::string& in_algorithm) override;
+ ::ndk::ScopedAStatus setListener(
+ // const ::android::sp<::aidl::android::hardware::drm::IDrmPluginListener>&
+ // in_listener)
+ const std::shared_ptr<IDrmPluginListener>& in_listener) override;
+ ::ndk::ScopedAStatus setMacAlgorithm(const std::vector<uint8_t>& in_sessionId,
+ const std::string& in_algorithm) override;
+ ::ndk::ScopedAStatus setPlaybackId(const std::vector<uint8_t>& in_sessionId,
+ const std::string& in_playbackId) override;
+ ::ndk::ScopedAStatus setPropertyByteArray(const std::string& in_propertyName,
+ const std::vector<uint8_t>& in_value) override;
+ ::ndk::ScopedAStatus setPropertyString(const std::string& in_propertyName,
+ const std::string& in_value) override;
+ ::ndk::ScopedAStatus sign(const std::vector<uint8_t>& in_sessionId,
+ const std::vector<uint8_t>& in_keyId,
+ const std::vector<uint8_t>& in_message,
+ std::vector<uint8_t>* _aidl_return) override;
+ ::ndk::ScopedAStatus signRSA(const std::vector<uint8_t>& in_sessionId,
+ const std::string& in_algorithm,
+ const std::vector<uint8_t>& in_message,
+ const std::vector<uint8_t>& in_wrappedkey,
+ std::vector<uint8_t>* _aidl_return) override;
+ ::ndk::ScopedAStatus verify(const std::vector<uint8_t>& in_sessionId,
+ const std::vector<uint8_t>& in_keyId,
+ const std::vector<uint8_t>& in_message,
+ const std::vector<uint8_t>& in_signature,
+ bool* _aidl_return) override;
+
+ private:
+ void initProperties();
+ void installSecureStop(const std::vector<uint8_t>& sessionId);
+ bool makeKeySetId(std::string* keySetId);
+ void setPlayPolicy();
+
+ void sendEvent(::aidl::android::hardware::drm::EventType in_eventType,
+ const std::vector<uint8_t>& in_sessionId,
+ const std::vector<uint8_t>& in_data);
+ void sendExpirationUpdate(const std::vector<uint8_t>& in_sessionId,
+ int64_t in_expiryTimeInMS);
+ void sendKeysChange(
+ const std::vector<uint8_t>& in_sessionId,
+ const std::vector<::aidl::android::hardware::drm::KeyStatus>& in_keyStatusList,
+ bool in_hasNewUsableKey);
+ void sendSessionLostState(const std::vector<uint8_t>& in_sessionId);
+
+ Status setSecurityLevel(const std::vector<uint8_t>& sessionId, SecurityLevel level);
+
+ Status getKeyRequestCommon(const std::vector<uint8_t>& scope,
+ const std::vector<uint8_t>& initData, const std::string& mimeType,
+ KeyType keyType, const std::vector<KeyValue>& optionalParameters,
+ std::vector<uint8_t>* request, KeyRequestType* getKeyRequestType,
+ std::string* defaultUrl);
+
+ struct ClearkeySecureStop {
+ std::vector<uint8_t> id;
+ std::vector<uint8_t> data;
+ };
+
+ std::map<std::vector<uint8_t>, ClearkeySecureStop> mSecureStops;
+ std::vector<KeyValue> mPlayPolicy;
+ std::map<std::string, std::string> mStringProperties;
+ std::map<std::string, std::vector<uint8_t>> mByteArrayProperties;
+ std::map<std::string, std::vector<uint8_t>> mReleaseKeysMap;
+ std::map<std::vector<uint8_t>, std::string> mPlaybackId;
+ std::map<std::vector<uint8_t>, SecurityLevel> mSecurityLevel;
+ ::std::shared_ptr<IDrmPluginListener> mListener;
+ SessionLibrary* mSessionLibrary;
+ int64_t mOpenSessionOkCount;
+ int64_t mCloseSessionOkCount;
+ int64_t mCloseSessionNotOpenedCount;
+ uint32_t mNextSecureStopId;
+ ::android::Mutex mPlayPolicyLock;
+
+ // set by property to mock error scenarios
+ Status mMockError;
+
+ void processMockError(const ::android::sp<Session>& session) {
+ session->setMockError(static_cast<CdmResponseType>(mMockError));
+ mMockError = Status::OK;
+ }
+
+ DeviceFiles mFileHandle;
+ ::android::Mutex mSecureStopLock;
+
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN_AND_NEW(DrmPlugin);
+};
+
+} // namespace clearkey
+} // namespace drm
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/drm/mediadrm/plugins/clearkey/common/AesCtrDecryptor.cpp b/drm/mediadrm/plugins/clearkey/common/AesCtrDecryptor.cpp
new file mode 100644
index 0000000..0b97820
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/AesCtrDecryptor.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2021 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 "clearkey-AesDecryptor"
+
+#include <utils/Log.h>
+
+#include <openssl/aes.h>
+
+#include "AesCtrDecryptor.h"
+#include "ClearKeyTypes.h"
+
+namespace clearkeydrm {
+
+static const size_t kBlockBitCount = kBlockSize * 8;
+
+CdmResponseType AesCtrDecryptor::decrypt(const std::vector<uint8_t>& key, const Iv iv,
+ const uint8_t* source, uint8_t* destination,
+ const std::vector<int32_t>& clearDataLengths,
+ const std::vector<int32_t>& encryptedDataLengths,
+ size_t* bytesDecryptedOut) {
+
+ if (key.size() != kBlockSize || clearDataLengths.size() != encryptedDataLengths.size()) {
+ android_errorWriteLog(0x534e4554, "63982768");
+ return clearkeydrm::ERROR_DECRYPT;
+ }
+
+ uint32_t blockOffset = 0;
+ uint8_t previousEncryptedCounter[kBlockSize];
+ memset(previousEncryptedCounter, 0, kBlockSize);
+
+ size_t offset = 0;
+ AES_KEY opensslKey;
+ AES_set_encrypt_key(key.data(), kBlockBitCount, &opensslKey);
+ Iv opensslIv;
+ memcpy(opensslIv, iv, sizeof(opensslIv));
+
+ for (size_t i = 0; i < clearDataLengths.size(); ++i) {
+ int32_t numBytesOfClearData = clearDataLengths[i];
+ if (numBytesOfClearData > 0) {
+ memcpy(destination + offset, source + offset, numBytesOfClearData);
+ offset += numBytesOfClearData;
+ }
+
+ int32_t numBytesOfEncryptedData = encryptedDataLengths[i];
+ if (numBytesOfEncryptedData > 0) {
+ AES_ctr128_encrypt(source + offset, destination + offset,
+ numBytesOfEncryptedData, &opensslKey, opensslIv,
+ previousEncryptedCounter, &blockOffset);
+ offset += numBytesOfEncryptedData;
+ }
+ }
+
+ *bytesDecryptedOut = offset;
+ return clearkeydrm::OK;
+}
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/Android.bp b/drm/mediadrm/plugins/clearkey/common/Android.bp
index 7ed8b88..a6a5b28 100644
--- a/drm/mediadrm/plugins/clearkey/common/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/common/Android.bp
@@ -44,3 +44,56 @@
integer_overflow: true,
},
}
+
+cc_library_static {
+ name: "libclearkeydevicefiles-protos.common",
+ vendor: true,
+
+ proto: {
+ export_proto_headers: true,
+ type: "lite",
+ },
+ srcs: ["protos/DeviceFiles.proto"],
+}
+
+cc_library_static {
+ name: "libclearkeybase",
+ vendor: true,
+
+ srcs: [
+ "AesCtrDecryptor.cpp",
+ "Base64.cpp",
+ "Buffer.cpp",
+ "ClearKeyUUID.cpp",
+ "DeviceFiles.cpp",
+ "InitDataParser.cpp",
+ "JsonWebKey.cpp",
+ "MemoryFileSystem.cpp",
+ "Session.cpp",
+ "SessionLibrary.cpp",
+ "Utils.cpp",
+ ],
+
+ cflags: ["-Wall", "-Werror"],
+
+ include_dirs: ["frameworks/av/include"],
+
+ shared_libs: [
+ "libutils",
+ "libcrypto",
+ ],
+
+ whole_static_libs: [
+ "libjsmn",
+ "libclearkeydevicefiles-protos.common",
+ ],
+
+ export_include_dirs: [
+ "include",
+ "include/clearkeydrm",
+ ],
+
+ sanitize: {
+ integer_overflow: true,
+ },
+}
diff --git a/drm/mediadrm/plugins/clearkey/common/Base64.cpp b/drm/mediadrm/plugins/clearkey/common/Base64.cpp
new file mode 100644
index 0000000..6499793
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/Base64.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2021 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 "clearkey-Base64"
+
+#include "Base64.h"
+
+#include <string>
+
+namespace clearkeydrm {
+
+::android::sp<Buffer> decodeBase64(const std::string& s) {
+ size_t n = s.size();
+
+ if ((n % 4) != 0) {
+ return nullptr;
+ }
+
+ size_t padding = 0;
+ if (n >= 1 && s.c_str()[n - 1] == '=') {
+ padding = 1;
+
+ if (n >= 2 && s.c_str()[n - 2] == '=') {
+ padding = 2;
+
+ if (n >= 3 && s.c_str()[n - 3] == '=') {
+ padding = 3;
+ }
+ }
+ }
+
+ // We divide first to avoid overflow. It's OK to do this because we
+ // already made sure that n % 4 == 0.
+ size_t outLen = (n / 4) * 3 - padding;
+
+ ::android::sp<Buffer> buffer = new Buffer(outLen);
+ uint8_t* out = buffer->data();
+ if (out == nullptr || buffer->size() < outLen) {
+ return nullptr;
+ }
+
+ size_t j = 0;
+ uint32_t accum = 0;
+ for (size_t i = 0; i < n; ++i) {
+ char c = s.c_str()[i];
+ unsigned value;
+ if (c >= 'A' && c <= 'Z') {
+ value = c - 'A';
+ } else if (c >= 'a' && c <= 'z') {
+ value = 26 + c - 'a';
+ } else if (c >= '0' && c <= '9') {
+ value = 52 + c - '0';
+ } else if (c == '+' || c == '-') {
+ value = 62;
+ } else if (c == '/' || c == '_') {
+ value = 63;
+ } else if (c != '=') {
+ return nullptr;
+ } else {
+ if (i < n - padding) {
+ return nullptr;
+ }
+
+ value = 0;
+ }
+
+ accum = (accum << 6) | value;
+
+ if (((i + 1) % 4) == 0) {
+ if (j < outLen) {
+ out[j++] = (accum >> 16);
+ }
+ if (j < outLen) {
+ out[j++] = (accum >> 8) & 0xff;
+ }
+ if (j < outLen) {
+ out[j++] = accum & 0xff;
+ }
+
+ accum = 0;
+ }
+ }
+
+ return buffer;
+}
+
+static char encode6Bit(unsigned x) {
+ if (x <= 25) {
+ return 'A' + x;
+ } else if (x <= 51) {
+ return 'a' + x - 26;
+ } else if (x <= 61) {
+ return '0' + x - 52;
+ } else if (x == 62) {
+ return '+';
+ } else {
+ return '/';
+ }
+}
+
+void encodeBase64(const void* _data, size_t size, std::string* out) {
+ out->clear();
+
+ const uint8_t* data = (const uint8_t*)_data;
+
+ size_t i;
+ for (i = 0; i < (size / 3) * 3; i += 3) {
+ uint8_t x1 = data[i];
+ uint8_t x2 = data[i + 1];
+ uint8_t x3 = data[i + 2];
+
+ out->push_back(encode6Bit(x1 >> 2));
+ out->push_back(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f));
+ out->push_back(encode6Bit((x2 << 2 | x3 >> 6) & 0x3f));
+ out->push_back(encode6Bit(x3 & 0x3f));
+ }
+ switch (size % 3) {
+ case 0:
+ break;
+ case 2: {
+ uint8_t x1 = data[i];
+ uint8_t x2 = data[i + 1];
+ out->push_back(encode6Bit(x1 >> 2));
+ out->push_back(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f));
+ out->push_back(encode6Bit((x2 << 2) & 0x3f));
+ out->push_back('=');
+ break;
+ }
+ default: {
+ uint8_t x1 = data[i];
+ out->push_back(encode6Bit(x1 >> 2));
+ out->push_back(encode6Bit((x1 << 4) & 0x3f));
+ out->append("==");
+ break;
+ }
+ }
+}
+
+void encodeBase64Url(const void* _data, size_t size, std::string* out) {
+ encodeBase64(_data, size, out);
+
+ if ((std::string::npos != out->find("+")) || (std::string::npos != out->find("/"))) {
+ size_t outLen = out->size();
+ char* base64url = new char[outLen];
+ for (size_t i = 0; i < outLen; ++i) {
+ if (out->c_str()[i] == '+')
+ base64url[i] = '-';
+ else if (out->c_str()[i] == '/')
+ base64url[i] = '_';
+ else
+ base64url[i] = out->c_str()[i];
+ }
+
+ out->assign(base64url, outLen);
+ delete[] base64url;
+ }
+}
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/Buffer.cpp b/drm/mediadrm/plugins/clearkey/common/Buffer.cpp
new file mode 100644
index 0000000..1671598
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/Buffer.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 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 "Buffer.h"
+
+namespace clearkeydrm {
+
+Buffer::Buffer(size_t capacity) : mRangeOffset(0), mOwnsData(true) {
+ mData = malloc(capacity);
+ if (mData == nullptr) {
+ mCapacity = 0;
+ mRangeLength = 0;
+ } else {
+ mCapacity = capacity;
+ mRangeLength = capacity;
+ }
+}
+
+Buffer::~Buffer() {
+ if (mOwnsData) {
+ if (mData != nullptr) {
+ free(mData);
+ mData = nullptr;
+ }
+ }
+}
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/DeviceFiles.cpp b/drm/mediadrm/plugins/clearkey/common/DeviceFiles.cpp
new file mode 100644
index 0000000..2299249
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/DeviceFiles.cpp
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2021 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 <utils/Log.h>
+
+#include <sys/stat.h>
+#include <string>
+
+#include "DeviceFiles.h"
+#include "protos/DeviceFiles.pb.h"
+
+#include <openssl/sha.h>
+
+// Protobuf generated classes.
+using clearkeydrm::HashedFile;
+using clearkeydrm::License;
+using clearkeydrm::License_LicenseState_ACTIVE;
+using clearkeydrm::License_LicenseState_RELEASING;
+using clearkeydrm::OfflineFile;
+
+namespace {
+const char kLicenseFileNameExt[] = ".lic";
+
+bool Hash(const std::string& data, std::string* hash) {
+ if (!hash) return false;
+
+ hash->resize(SHA256_DIGEST_LENGTH);
+
+ const unsigned char* input = reinterpret_cast<const unsigned char*>(data.data());
+ unsigned char* output = reinterpret_cast<unsigned char*>(&(*hash)[0]);
+ SHA256(input, data.size(), output);
+ return true;
+}
+
+} // namespace
+
+namespace clearkeydrm {
+
+bool DeviceFiles::StoreLicense(const std::string& keySetId, LicenseState state,
+ const std::string& licenseResponse) {
+ OfflineFile file;
+ file.set_type(OfflineFile::LICENSE);
+ file.set_version(OfflineFile::VERSION_1);
+
+ License* license = file.mutable_license();
+ switch (state) {
+ case kLicenseStateActive:
+ license->set_state(License_LicenseState_ACTIVE);
+ license->set_license(licenseResponse);
+ break;
+ case kLicenseStateReleasing:
+ license->set_state(License_LicenseState_RELEASING);
+ license->set_license(licenseResponse);
+ break;
+ default:
+ ALOGW("StoreLicense: Unknown license state: %u", state);
+ return false;
+ }
+
+ std::string serializedFile;
+ file.SerializeToString(&serializedFile);
+
+ return StoreFileWithHash(keySetId + kLicenseFileNameExt, serializedFile);
+}
+
+bool DeviceFiles::StoreFileWithHash(const std::string& fileName,
+ const std::string& serializedFile) {
+ std::string hash;
+ if (!Hash(serializedFile, &hash)) {
+ ALOGE("StoreFileWithHash: Failed to compute hash");
+ return false;
+ }
+
+ HashedFile hashFile;
+ hashFile.set_file(serializedFile);
+ hashFile.set_hash(hash);
+
+ std::string serializedHashFile;
+ hashFile.SerializeToString(&serializedHashFile);
+
+ return StoreFileRaw(fileName, serializedHashFile);
+}
+
+bool DeviceFiles::StoreFileRaw(const std::string& fileName, const std::string& serializedHashFile) {
+ MemoryFileSystem::MemoryFile memFile;
+ memFile.setFileName(fileName);
+ memFile.setContent(serializedHashFile);
+ memFile.setFileSize(serializedHashFile.size());
+ size_t len = mFileHandle.Write(fileName, memFile);
+
+ if (len != static_cast<size_t>(serializedHashFile.size())) {
+ ALOGE("StoreFileRaw: Failed to write %s", fileName.c_str());
+ ALOGD("StoreFileRaw: expected=%zd, actual=%zu", serializedHashFile.size(), len);
+ return false;
+ }
+
+ ALOGD("StoreFileRaw: wrote %zu bytes to %s", serializedHashFile.size(), fileName.c_str());
+ return true;
+}
+
+bool DeviceFiles::RetrieveLicense(const std::string& keySetId, LicenseState* state,
+ std::string* offlineLicense) {
+ OfflineFile file;
+ if (!RetrieveHashedFile(keySetId + kLicenseFileNameExt, &file)) {
+ return false;
+ }
+
+ if (file.type() != OfflineFile::LICENSE) {
+ ALOGE("RetrieveLicense: Invalid file type");
+ return false;
+ }
+
+ if (file.version() != OfflineFile::VERSION_1) {
+ ALOGE("RetrieveLicense: Invalid file version");
+ return false;
+ }
+
+ if (!file.has_license()) {
+ ALOGE("RetrieveLicense: License not present");
+ return false;
+ }
+
+ License license = file.license();
+ switch (license.state()) {
+ case License_LicenseState_ACTIVE:
+ *state = kLicenseStateActive;
+ break;
+ case License_LicenseState_RELEASING:
+ *state = kLicenseStateReleasing;
+ break;
+ default:
+ ALOGW("RetrieveLicense: Unrecognized license state: %u", kLicenseStateUnknown);
+ *state = kLicenseStateUnknown;
+ break;
+ }
+ *offlineLicense = license.license();
+ return true;
+}
+
+bool DeviceFiles::DeleteLicense(const std::string& keySetId) {
+ return mFileHandle.RemoveFile(keySetId + kLicenseFileNameExt);
+}
+
+bool DeviceFiles::DeleteAllLicenses() {
+ return mFileHandle.RemoveAllFiles();
+}
+
+bool DeviceFiles::LicenseExists(const std::string& keySetId) {
+ return mFileHandle.FileExists(keySetId + kLicenseFileNameExt);
+}
+
+std::vector<std::string> DeviceFiles::ListLicenses() const {
+ std::vector<std::string> licenses = mFileHandle.ListFiles();
+ for (size_t i = 0; i < licenses.size(); i++) {
+ std::string& license = licenses[i];
+ license = license.substr(0, license.size() - strlen(kLicenseFileNameExt));
+ }
+ return licenses;
+}
+
+bool DeviceFiles::RetrieveHashedFile(const std::string& fileName, OfflineFile* deSerializedFile) {
+ if (!deSerializedFile) {
+ ALOGE("RetrieveHashedFile: invalid file parameter");
+ return false;
+ }
+
+ if (!FileExists(fileName)) {
+ ALOGE("RetrieveHashedFile: %s does not exist", fileName.c_str());
+ return false;
+ }
+
+ ssize_t bytes = GetFileSize(fileName);
+ if (bytes <= 0) {
+ ALOGE("RetrieveHashedFile: invalid file size: %s", fileName.c_str());
+ // Remove the corrupted file so the caller will not get the same error
+ // when trying to access the file repeatedly, causing the system to stall.
+ RemoveFile(fileName);
+ return false;
+ }
+
+ std::string serializedHashFile;
+ serializedHashFile.resize(bytes);
+ bytes = mFileHandle.Read(fileName, &serializedHashFile);
+
+ if (bytes != static_cast<ssize_t>(serializedHashFile.size())) {
+ ALOGE("RetrieveHashedFile: Failed to read from %s", fileName.c_str());
+ ALOGV("RetrieveHashedFile: expected: %zd, actual: %zd", serializedHashFile.size(), bytes);
+ // Remove the corrupted file so the caller will not get the same error
+ // when trying to access the file repeatedly, causing the system to stall.
+ RemoveFile(fileName);
+ return false;
+ }
+
+ ALOGV("RetrieveHashedFile: read %zd from %s", bytes, fileName.c_str());
+
+ HashedFile hashFile;
+ if (!hashFile.ParseFromString(serializedHashFile)) {
+ ALOGE("RetrieveHashedFile: Unable to parse hash file");
+ // Remove corrupt file.
+ RemoveFile(fileName);
+ return false;
+ }
+
+ std::string hash;
+ if (!Hash(hashFile.file(), &hash)) {
+ ALOGE("RetrieveHashedFile: Hash computation failed");
+ return false;
+ }
+
+ if (hash != hashFile.hash()) {
+ ALOGE("RetrieveHashedFile: Hash mismatch");
+ // Remove corrupt file.
+ RemoveFile(fileName);
+ return false;
+ }
+
+ if (!deSerializedFile->ParseFromString(hashFile.file())) {
+ ALOGE("RetrieveHashedFile: Unable to parse file");
+ // Remove corrupt file.
+ RemoveFile(fileName);
+ return false;
+ }
+
+ return true;
+}
+
+bool DeviceFiles::FileExists(const std::string& fileName) const {
+ return mFileHandle.FileExists(fileName);
+}
+
+bool DeviceFiles::RemoveFile(const std::string& fileName) {
+ return mFileHandle.RemoveFile(fileName);
+}
+
+ssize_t DeviceFiles::GetFileSize(const std::string& fileName) const {
+ return mFileHandle.GetFileSize(fileName);
+}
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/InitDataParser.cpp b/drm/mediadrm/plugins/clearkey/common/InitDataParser.cpp
new file mode 100644
index 0000000..fc839e9
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/InitDataParser.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2021 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 "clearkey-InitDataParser"
+
+#include <algorithm>
+#include <arpa/inet.h>
+#include <utils/Log.h>
+
+#include "InitDataParser.h"
+
+#include "Base64.h"
+
+#include "ClearKeyUUID.h"
+#include "MimeType.h"
+
+namespace {
+const size_t kKeyIdSize = 16;
+const size_t kSystemIdSize = 16;
+} // namespace
+
+namespace clearkeydrm {
+
+std::vector<uint8_t> StrToVector(const std::string& str) {
+ std::vector<uint8_t> vec(str.begin(), str.end());
+ return vec;
+}
+
+CdmResponseType InitDataParser::parse(const std::vector<uint8_t>& initData,
+ const std::string& mimeType,
+ CdmKeyType keyType,
+ std::vector<uint8_t>* licenseRequest) {
+ // Build a list of the key IDs
+ std::vector<const uint8_t*> keyIds;
+
+ if (mimeType == kIsoBmffVideoMimeType.c_str() || mimeType == kIsoBmffAudioMimeType.c_str() ||
+ mimeType == kCencInitDataFormat.c_str()) {
+ auto res = parsePssh(initData, &keyIds);
+ if (res != clearkeydrm::OK) {
+ return res;
+ }
+ } else if (mimeType == kWebmVideoMimeType.c_str() || mimeType == kWebmAudioMimeType.c_str() ||
+ mimeType == kWebmInitDataFormat.c_str()) {
+ // WebM "init data" is just a single key ID
+ if (initData.size() != kKeyIdSize) {
+ return clearkeydrm::ERROR_CANNOT_HANDLE;
+ }
+ keyIds.push_back(initData.data());
+ } else {
+ return clearkeydrm::ERROR_CANNOT_HANDLE;
+ }
+
+ if (keyType == clearkeydrm::KEY_TYPE_RELEASE) {
+ // restore key
+ }
+
+ // Build the request
+ std::string requestJson = generateRequest(keyType, keyIds);
+ std::vector<uint8_t> requestJsonVec = StrToVector(requestJson);
+
+ licenseRequest->clear();
+ licenseRequest->insert(licenseRequest->end(), requestJsonVec.begin(), requestJsonVec.end());
+ return clearkeydrm::OK;
+}
+
+CdmResponseType InitDataParser::parsePssh(const std::vector<uint8_t>& initData,
+ std::vector<const uint8_t*>* keyIds) {
+ // Description of PSSH format:
+ // https://w3c.github.io/encrypted-media/format-registry/initdata/cenc.html
+ size_t readPosition = 0;
+
+ uint32_t expectedSize = initData.size();
+ const char psshIdentifier[4] = {'p', 's', 's', 'h'};
+ const uint8_t psshVersion1[4] = {1, 0, 0, 0};
+ uint32_t keyIdCount = 0;
+ size_t headerSize = sizeof(expectedSize) + sizeof(psshIdentifier) + sizeof(psshVersion1) +
+ kSystemIdSize + sizeof(keyIdCount);
+ if (initData.size() < headerSize) {
+ return clearkeydrm::ERROR_CANNOT_HANDLE;
+ }
+
+ // Validate size field
+ expectedSize = htonl(expectedSize);
+ if (memcmp(&initData[readPosition], &expectedSize, sizeof(expectedSize)) != 0) {
+ return clearkeydrm::ERROR_CANNOT_HANDLE;
+ }
+ readPosition += sizeof(expectedSize);
+
+ // Validate PSSH box identifier
+ if (memcmp(&initData[readPosition], psshIdentifier, sizeof(psshIdentifier)) != 0) {
+ return clearkeydrm::ERROR_CANNOT_HANDLE;
+ }
+ readPosition += sizeof(psshIdentifier);
+
+ // Validate EME version number
+ if (memcmp(&initData[readPosition], psshVersion1, sizeof(psshVersion1)) != 0) {
+ return clearkeydrm::ERROR_CANNOT_HANDLE;
+ }
+ readPosition += sizeof(psshVersion1);
+
+ // Validate system ID
+ if (!isClearKeyUUID(&initData[readPosition])) {
+ return clearkeydrm::ERROR_CANNOT_HANDLE;
+ }
+ readPosition += kSystemIdSize;
+
+ // Read key ID count
+ memcpy(&keyIdCount, &initData[readPosition], sizeof(keyIdCount));
+ keyIdCount = ntohl(keyIdCount);
+ readPosition += sizeof(keyIdCount);
+
+ uint64_t psshSize = 0;
+ if (__builtin_mul_overflow(keyIdCount, kKeyIdSize, &psshSize) ||
+ __builtin_add_overflow(readPosition, psshSize, &psshSize) ||
+ psshSize != initData.size() - sizeof(uint32_t) /* DataSize(0) */) {
+ return clearkeydrm::ERROR_CANNOT_HANDLE;
+ }
+
+ // Calculate the key ID offsets
+ for (uint32_t i = 0; i < keyIdCount; ++i) {
+ size_t keyIdPosition = readPosition + (i * kKeyIdSize);
+ keyIds->push_back(&initData[keyIdPosition]);
+ }
+ return clearkeydrm::OK;
+}
+
+std::string InitDataParser::generateRequest(CdmKeyType keyType,
+ const std::vector<const uint8_t*>& keyIds) {
+ const std::string kRequestPrefix("{\"kids\":[");
+ const std::string kTemporarySession("],\"type\":\"temporary\"}");
+ const std::string kPersistentSession("],\"type\":\"persistent-license\"}");
+
+ std::string request(kRequestPrefix);
+ std::string encodedId;
+ for (size_t i = 0; i < keyIds.size(); ++i) {
+ encodedId.clear();
+ encodeBase64Url(keyIds[i], kKeyIdSize, &encodedId);
+ if (i != 0) {
+ request.append(",");
+ }
+ request.push_back('\"');
+ request.append(encodedId);
+ request.push_back('\"');
+ }
+ if (keyType == clearkeydrm::KEY_TYPE_STREAMING) {
+ request.append(kTemporarySession);
+ } else if (keyType == clearkeydrm::KEY_TYPE_OFFLINE ||
+ keyType == clearkeydrm::KEY_TYPE_RELEASE) {
+ request.append(kPersistentSession);
+ }
+
+ // Android's Base64 encoder produces padding. EME forbids padding.
+ const char kBase64Padding = '=';
+ request.erase(std::remove(request.begin(), request.end(), kBase64Padding), request.end());
+
+ return request;
+}
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/JsonWebKey.cpp b/drm/mediadrm/plugins/clearkey/common/JsonWebKey.cpp
new file mode 100644
index 0000000..ddbc594
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/JsonWebKey.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2021 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 "clearkey-JsonWebKey"
+
+#include <utils/Log.h>
+
+#include "JsonWebKey.h"
+
+#include "Base64.h"
+
+namespace {
+const std::string kBase64Padding("=");
+const std::string kKeysTag("keys");
+const std::string kKeyTypeTag("kty");
+const std::string kKeyTag("k");
+const std::string kKeyIdTag("kid");
+const std::string kMediaSessionType("type");
+const std::string kPersistentLicenseSession("persistent-license");
+const std::string kSymmetricKeyValue("oct");
+const std::string kTemporaryLicenseSession("temporary");
+} // namespace
+
+namespace clearkeydrm {
+
+JsonWebKey::JsonWebKey() {}
+
+JsonWebKey::~JsonWebKey() {}
+
+/*
+ * Parses a JSON Web Key Set string, initializes a KeyMap with key id:key
+ * pairs from the JSON Web Key Set. Both key ids and keys are base64url
+ * encoded. The KeyMap contains base64url decoded key id:key pairs.
+ *
+ * @return Returns false for errors, true for success.
+ */
+bool JsonWebKey::extractKeysFromJsonWebKeySet(const std::string& jsonWebKeySet, KeyMap* keys) {
+ keys->clear();
+
+ if (!parseJsonWebKeySet(jsonWebKeySet, &mJsonObjects)) {
+ return false;
+ }
+
+ // mJsonObjects[0] contains the entire JSON Web Key Set, including
+ // all the base64 encoded keys. Each key is also stored separately as
+ // a JSON object in mJsonObjects[1..n] where n is the total
+ // number of keys in the set.
+ if (mJsonObjects.size() == 0 || !isJsonWebKeySet(mJsonObjects[0])) {
+ return false;
+ }
+
+ std::string encodedKey, encodedKeyId;
+ std::vector<uint8_t> decodedKey, decodedKeyId;
+
+ // mJsonObjects[1] contains the first JSON Web Key in the set
+ for (size_t i = 1; i < mJsonObjects.size(); ++i) {
+ encodedKeyId.clear();
+ encodedKey.clear();
+
+ if (!parseJsonObject(mJsonObjects[i], &mTokens)) return false;
+
+ if (findKey(mJsonObjects[i], &encodedKeyId, &encodedKey)) {
+ if (encodedKeyId.empty() || encodedKey.empty()) {
+ ALOGE("Must have both key id and key in the JsonWebKey set.");
+ continue;
+ }
+
+ if (!decodeBase64String(encodedKeyId, &decodedKeyId)) {
+ ALOGE("Failed to decode key id(%s)", encodedKeyId.c_str());
+ continue;
+ }
+
+ if (!decodeBase64String(encodedKey, &decodedKey)) {
+ ALOGE("Failed to decode key(%s)", encodedKey.c_str());
+ continue;
+ }
+
+ keys->insert(std::pair<std::vector<uint8_t>, std::vector<uint8_t>>(decodedKeyId,
+ decodedKey));
+ }
+ }
+ return true;
+}
+
+bool JsonWebKey::decodeBase64String(const std::string& encodedText,
+ std::vector<uint8_t>* decodedText) {
+ decodedText->clear();
+
+ // encodedText should not contain padding characters as per EME spec.
+ if (encodedText.find(kBase64Padding) != std::string::npos) {
+ return false;
+ }
+
+ // Since decodeBase64() requires padding characters,
+ // add them so length of encodedText is exactly a multiple of 4.
+ int remainder = encodedText.length() % 4;
+ std::string paddedText(encodedText);
+ if (remainder > 0) {
+ for (int i = 0; i < 4 - remainder; ++i) {
+ paddedText.append(kBase64Padding);
+ }
+ }
+
+ ::android::sp<Buffer> buffer = decodeBase64(paddedText);
+ if (buffer == nullptr) {
+ ALOGE("Malformed base64 encoded content found.");
+ return false;
+ }
+
+ decodedText->insert(decodedText->end(), buffer->base(), buffer->base() + buffer->size());
+ return true;
+}
+
+bool JsonWebKey::findKey(const std::string& jsonObject, std::string* keyId,
+ std::string* encodedKey) {
+ std::string key, value;
+
+ // Only allow symmetric key, i.e. "kty":"oct" pair.
+ if (jsonObject.find(kKeyTypeTag) != std::string::npos) {
+ findValue(kKeyTypeTag, &value);
+ if (0 != value.compare(kSymmetricKeyValue)) return false;
+ }
+
+ if (jsonObject.find(kKeyIdTag) != std::string::npos) {
+ findValue(kKeyIdTag, keyId);
+ }
+
+ if (jsonObject.find(kKeyTag) != std::string::npos) {
+ findValue(kKeyTag, encodedKey);
+ }
+ return true;
+}
+
+void JsonWebKey::findValue(const std::string& key, std::string* value) {
+ value->clear();
+ const char* valueToken;
+ for (std::vector<std::string>::const_iterator nextToken = mTokens.begin();
+ nextToken != mTokens.end(); ++nextToken) {
+ if (0 == (*nextToken).compare(key)) {
+ if (nextToken + 1 == mTokens.end()) break;
+ valueToken = (*(nextToken + 1)).c_str();
+ value->assign(valueToken);
+ nextToken++;
+ break;
+ }
+ }
+}
+
+bool JsonWebKey::isJsonWebKeySet(const std::string& jsonObject) const {
+ if (jsonObject.find(kKeysTag) == std::string::npos) {
+ ALOGE("JSON Web Key does not contain keys.");
+ return false;
+ }
+ return true;
+}
+
+/*
+ * Parses a JSON objects string and initializes a vector of tokens.
+ *
+ * @return Returns false for errors, true for success.
+ */
+bool JsonWebKey::parseJsonObject(const std::string& jsonObject, std::vector<std::string>* tokens) {
+ jsmn_parser parser;
+
+ jsmn_init(&parser);
+ int numTokens = jsmn_parse(&parser, jsonObject.c_str(), jsonObject.size(), nullptr, 0);
+ if (numTokens < 0) {
+ ALOGE("Parser returns error code=%d", numTokens);
+ return false;
+ }
+
+ unsigned int jsmnTokensSize = numTokens * sizeof(jsmntok_t);
+ mJsmnTokens.clear();
+ mJsmnTokens.resize(jsmnTokensSize);
+
+ jsmn_init(&parser);
+ int status = jsmn_parse(&parser, jsonObject.c_str(), jsonObject.size(), mJsmnTokens.data(),
+ numTokens);
+ if (status < 0) {
+ ALOGE("Parser returns error code=%d", status);
+ return false;
+ }
+
+ tokens->clear();
+ std::string token;
+ const char* pjs;
+ for (int j = 0; j < numTokens; ++j) {
+ pjs = jsonObject.c_str() + mJsmnTokens[j].start;
+ if (mJsmnTokens[j].type == JSMN_STRING || mJsmnTokens[j].type == JSMN_PRIMITIVE) {
+ token.assign(pjs, mJsmnTokens[j].end - mJsmnTokens[j].start);
+ tokens->push_back(token);
+ }
+ }
+ return true;
+}
+
+/*
+ * Parses JSON Web Key Set string and initializes a vector of JSON objects.
+ *
+ * @return Returns false for errors, true for success.
+ */
+bool JsonWebKey::parseJsonWebKeySet(const std::string& jsonWebKeySet,
+ std::vector<std::string>* jsonObjects) {
+ if (jsonWebKeySet.empty()) {
+ ALOGE("Empty JSON Web Key");
+ return false;
+ }
+
+ // The jsmn parser only supports unicode encoding.
+ jsmn_parser parser;
+
+ // Computes number of tokens. A token marks the type, offset in
+ // the original string.
+ jsmn_init(&parser);
+ int numTokens = jsmn_parse(&parser, jsonWebKeySet.c_str(), jsonWebKeySet.size(), nullptr, 0);
+ if (numTokens < 0) {
+ ALOGE("Parser returns error code=%d", numTokens);
+ return false;
+ }
+
+ unsigned int jsmnTokensSize = numTokens * sizeof(jsmntok_t);
+ mJsmnTokens.resize(jsmnTokensSize);
+
+ jsmn_init(&parser);
+ int status = jsmn_parse(&parser, jsonWebKeySet.c_str(), jsonWebKeySet.size(),
+ mJsmnTokens.data(), numTokens);
+ if (status < 0) {
+ ALOGE("Parser returns error code=%d", status);
+ return false;
+ }
+
+ std::string token;
+ const char* pjs;
+ for (int i = 0; i < numTokens; ++i) {
+ pjs = jsonWebKeySet.c_str() + mJsmnTokens[i].start;
+ if (mJsmnTokens[i].type == JSMN_OBJECT) {
+ token.assign(pjs, mJsmnTokens[i].end - mJsmnTokens[i].start);
+ jsonObjects->push_back(token);
+ }
+ }
+ return true;
+}
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/MemoryFileSystem.cpp b/drm/mediadrm/plugins/clearkey/common/MemoryFileSystem.cpp
new file mode 100644
index 0000000..1045458
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/MemoryFileSystem.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2021 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 <utils/Log.h>
+#include <string>
+#include <vector>
+
+#include "MemoryFileSystem.h"
+
+namespace clearkeydrm {
+
+std::string MemoryFileSystem::GetFileName(const std::string& path) {
+ size_t index = path.find_last_of('/');
+ if (index != std::string::npos) {
+ return path.substr(index + 1);
+ } else {
+ return path;
+ }
+}
+
+bool MemoryFileSystem::FileExists(const std::string& fileName) const {
+ auto result = mMemoryFileSystem.find(fileName);
+ return result != mMemoryFileSystem.end();
+}
+
+ssize_t MemoryFileSystem::GetFileSize(const std::string& fileName) const {
+ auto result = mMemoryFileSystem.find(fileName);
+ if (result != mMemoryFileSystem.end()) {
+ return static_cast<ssize_t>(result->second.getFileSize());
+ } else {
+ ALOGE("Failed to get size for %s", fileName.c_str());
+ return -1;
+ }
+}
+
+std::vector<std::string> MemoryFileSystem::ListFiles() const {
+ std::vector<std::string> list;
+ for (const auto& filename : mMemoryFileSystem) {
+ list.push_back(filename.first);
+ }
+ return list;
+}
+
+size_t MemoryFileSystem::Read(const std::string& path, std::string* buffer) {
+ std::string key = GetFileName(path);
+ auto result = mMemoryFileSystem.find(key);
+ if (result != mMemoryFileSystem.end()) {
+ std::string serializedHashFile = result->second.getContent();
+ buffer->assign(serializedHashFile);
+ return buffer->size();
+ } else {
+ ALOGE("Failed to read from %s", path.c_str());
+ return -1;
+ }
+}
+
+size_t MemoryFileSystem::Write(const std::string& path, const MemoryFile& memoryFile) {
+ std::string key = GetFileName(path);
+ auto result = mMemoryFileSystem.find(key);
+ if (result != mMemoryFileSystem.end()) {
+ mMemoryFileSystem.erase(key);
+ }
+ mMemoryFileSystem.insert(std::pair<std::string, MemoryFile>(key, memoryFile));
+ return memoryFile.getFileSize();
+}
+
+bool MemoryFileSystem::RemoveFile(const std::string& fileName) {
+ auto result = mMemoryFileSystem.find(fileName);
+ if (result != mMemoryFileSystem.end()) {
+ mMemoryFileSystem.erase(result);
+ return true;
+ } else {
+ ALOGE("Cannot find license to remove: %s", fileName.c_str());
+ return false;
+ }
+}
+
+bool MemoryFileSystem::RemoveAllFiles() {
+ mMemoryFileSystem.clear();
+ return mMemoryFileSystem.empty();
+}
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/Session.cpp b/drm/mediadrm/plugins/clearkey/common/Session.cpp
new file mode 100644
index 0000000..d7fd13a
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/Session.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2021 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 "clearkey-Session"
+
+#include <utils/Log.h>
+
+#include "Session.h"
+
+#include "AesCtrDecryptor.h"
+#include "InitDataParser.h"
+#include "JsonWebKey.h"
+
+namespace clearkeydrm {
+
+using ::android::Mutex;
+using ::android::sp;
+
+CdmResponseType Session::getKeyRequest(const std::vector<uint8_t>& initData,
+ const std::string& mimeType,
+ CdmKeyType keyType,
+ std::vector<uint8_t>* keyRequest) const {
+ InitDataParser parser;
+ return parser.parse(initData, mimeType, keyType, keyRequest);
+}
+
+CdmResponseType Session::provideKeyResponse(const std::vector<uint8_t>& response) {
+ std::string responseString(reinterpret_cast<const char*>(response.data()), response.size());
+ KeyMap keys;
+
+ Mutex::Autolock lock(mMapLock);
+ JsonWebKey parser;
+ if (parser.extractKeysFromJsonWebKeySet(responseString, &keys)) {
+ for (auto& key : keys) {
+ std::string first(key.first.begin(), key.first.end());
+ std::string second(key.second.begin(), key.second.end());
+ mKeyMap.insert(
+ std::pair<std::vector<uint8_t>, std::vector<uint8_t>>(key.first, key.second));
+ }
+ return clearkeydrm::OK;
+ } else {
+ return clearkeydrm::ERROR_UNKNOWN;
+ }
+}
+
+CdmResponseType Session::decrypt(const KeyId keyId, const Iv iv,
+ const uint8_t* srcPtr, uint8_t* destPtr,
+ const std::vector<int32_t>& clearDataLengths,
+ const std::vector<int32_t>& encryptedDataLengths,
+ size_t* bytesDecryptedOut) {
+ Mutex::Autolock lock(mMapLock);
+
+ if (getMockError() != clearkeydrm::OK) {
+ return getMockError();
+ }
+
+ std::vector<uint8_t> keyIdVector;
+ keyIdVector.clear();
+ keyIdVector.insert(keyIdVector.end(), keyId, keyId + kBlockSize);
+ std::map<std::vector<uint8_t>, std::vector<uint8_t>>::iterator itr;
+ itr = mKeyMap.find(keyIdVector);
+ if (itr == mKeyMap.end()) {
+ return clearkeydrm::ERROR_NO_LICENSE;
+ }
+
+ clearkeydrm::AesCtrDecryptor decryptor;
+ auto status = decryptor.decrypt(itr->second /*key*/, iv, srcPtr, destPtr,
+ clearDataLengths,
+ encryptedDataLengths,
+ bytesDecryptedOut);
+ return status;
+}
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/SessionLibrary.cpp b/drm/mediadrm/plugins/clearkey/common/SessionLibrary.cpp
new file mode 100644
index 0000000..6b2ff38
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/SessionLibrary.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2021 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 "clearkey-SessionLibrary"
+
+#include <utils/Log.h>
+
+#include "SessionLibrary.h"
+
+namespace clearkeydrm {
+
+using ::android::Mutex;
+using ::android::sp;
+
+Mutex SessionLibrary::sSingletonLock;
+SessionLibrary* SessionLibrary::sSingleton = NULL;
+
+SessionLibrary* SessionLibrary::get() {
+ Mutex::Autolock lock(sSingletonLock);
+
+ if (sSingleton == NULL) {
+ ALOGD("Instantiating Session Library Singleton.");
+ sSingleton = new SessionLibrary();
+ }
+
+ return sSingleton;
+}
+
+sp<Session> SessionLibrary::createSession() {
+ Mutex::Autolock lock(mSessionsLock);
+
+ char sessionIdRaw[16];
+ snprintf(sessionIdRaw, sizeof(sessionIdRaw), "%u", mNextSessionId);
+
+ mNextSessionId += 1;
+
+ std::vector<uint8_t> sessionId;
+ sessionId.insert(sessionId.end(), sessionIdRaw,
+ sessionIdRaw + sizeof(sessionIdRaw) / sizeof(uint8_t));
+
+ mSessions.insert(
+ std::pair<std::vector<uint8_t>, sp<Session>>(sessionId, new Session(sessionId)));
+ std::map<std::vector<uint8_t>, sp<Session>>::iterator itr = mSessions.find(sessionId);
+ if (itr != mSessions.end()) {
+ return itr->second;
+ } else {
+ return nullptr;
+ }
+}
+
+sp<Session> SessionLibrary::findSession(const std::vector<uint8_t>& sessionId) {
+ Mutex::Autolock lock(mSessionsLock);
+ std::map<std::vector<uint8_t>, sp<Session>>::iterator itr = mSessions.find(sessionId);
+ if (itr != mSessions.end()) {
+ return itr->second;
+ } else {
+ return nullptr;
+ }
+}
+
+void SessionLibrary::destroySession(const sp<Session>& session) {
+ Mutex::Autolock lock(mSessionsLock);
+ mSessions.erase(session->sessionId());
+}
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/include/ClearKeyUUID.h b/drm/mediadrm/plugins/clearkey/common/include/ClearKeyUUID.h
index fe10fba..8911024 100644
--- a/drm/mediadrm/plugins/clearkey/common/include/ClearKeyUUID.h
+++ b/drm/mediadrm/plugins/clearkey/common/include/ClearKeyUUID.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -13,9 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-#ifndef CLEARKEY_UUID_H_
-#define CLEARKEY_UUID_H_
+#pragma once
#include <array>
#include <cstdint>
@@ -27,6 +25,4 @@
std::vector<std::array<uint8_t, 16>> getSupportedCryptoSchemes();
-} // namespace clearkeydrm
-
-#endif // CLEARKEY_UUID_H_
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/AesCtrDecryptor.h b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/AesCtrDecryptor.h
new file mode 100644
index 0000000..dbf3098
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/AesCtrDecryptor.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 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 <cstdint>
+
+#include "ClearKeyTypes.h"
+
+namespace clearkeydrm {
+
+class AesCtrDecryptor {
+ public:
+ AesCtrDecryptor() {}
+
+ CdmResponseType decrypt(const std::vector<uint8_t>& key, const Iv iv, const uint8_t* source,
+ uint8_t* destination,
+ const std::vector<int32_t>& clearDataLengths,
+ const std::vector<int32_t>& encryptedDataLengths,
+ size_t* bytesDecryptedOut);
+
+ private:
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(AesCtrDecryptor);
+};
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/Base64.h b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/Base64.h
new file mode 100644
index 0000000..075d247
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/Base64.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 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 "Buffer.h"
+
+namespace clearkeydrm {
+
+struct Buffer;
+
+::android::sp<Buffer> decodeBase64(const std::string& s);
+
+void encodeBase64(const void* data, size_t size, std::string* out);
+
+void encodeBase64Url(const void* data, size_t size, std::string* out);
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/Buffer.h b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/Buffer.h
new file mode 100644
index 0000000..d41c4f3
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/Buffer.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 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 <utils/RefBase.h>
+
+#include "ClearKeyTypes.h"
+
+namespace clearkeydrm {
+struct Buffer : public ::android::RefBase {
+ explicit Buffer(size_t capacity);
+
+ uint8_t* base() { return reinterpret_cast<uint8_t*>(mData); }
+ uint8_t* data() { return reinterpret_cast<uint8_t*>(mData) + mRangeOffset; }
+ size_t capacity() const { return mCapacity; }
+ size_t size() const { return mRangeLength; }
+ size_t offset() const { return mRangeOffset; }
+
+ protected:
+ virtual ~Buffer();
+
+ private:
+ void* mData;
+ size_t mCapacity;
+ size_t mRangeOffset;
+ size_t mRangeLength;
+
+ bool mOwnsData;
+
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(Buffer);
+};
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/ClearKeyDrmProperties.h b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/ClearKeyDrmProperties.h
new file mode 100644
index 0000000..9a22633
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/ClearKeyDrmProperties.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 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 <string>
+
+namespace clearkeydrm {
+static const std::string kVendorKey("vendor");
+static const std::string kVendorValue("Google");
+static const std::string kVersionKey("version");
+static const std::string kVersionValue("1.2");
+static const std::string kPluginDescriptionKey("description");
+static const std::string kPluginDescriptionValue("ClearKey CDM");
+static const std::string kAlgorithmsKey("algorithms");
+static const std::string kAlgorithmsValue("");
+static const std::string kListenerTestSupportKey("listenerTestSupport");
+static const std::string kListenerTestSupportValue("true");
+static const std::string kDrmErrorTestKey("drmErrorTest");
+static const std::string kDrmErrorTestValue("");
+static const std::string kResourceContentionValue("resourceContention");
+static const std::string kLostStateValue("lostState");
+static const std::string kFrameTooLargeValue("frameTooLarge");
+static const std::string kInvalidStateValue("invalidState");
+
+static const std::string kDeviceIdKey("deviceId");
+static const uint8_t kTestDeviceIdData[] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+ 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
+
+// settable byte array property
+static const std::string kClientIdKey("clientId");
+
+// TODO stub out metrics for nw
+static const std::string kMetricsKey("metrics");
+static const uint8_t kMetricsData[] = {0};
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/ClearKeyTypes.h b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/ClearKeyTypes.h
new file mode 100644
index 0000000..0cc9511
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/ClearKeyTypes.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2021 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 <cstdint>
+#include <map>
+#include <vector>
+
+namespace clearkeydrm {
+
+const uint8_t kBlockSize = 16; // AES_BLOCK_SIZE;
+typedef uint8_t KeyId[kBlockSize];
+typedef uint8_t Iv[kBlockSize];
+
+typedef std::map<std::vector<uint8_t>, std::vector<uint8_t>> KeyMap;
+
+#define CLEARKEY_DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ TypeName(const TypeName&) = delete; \
+ void operator=(const TypeName&) = delete;
+
+#define CLEARKEY_DISALLOW_COPY_AND_ASSIGN_AND_NEW(TypeName) \
+ TypeName() = delete; \
+ TypeName(const TypeName&) = delete; \
+ void operator=(const TypeName&) = delete;
+
+enum CdmResponseType : int32_t {
+ OK = 0,
+ ERROR_NO_LICENSE = 1,
+ ERROR_SESSION_NOT_OPENED = 3,
+ ERROR_CANNOT_HANDLE = 4,
+ ERROR_INVALID_STATE = 5,
+ BAD_VALUE = 6,
+ ERROR_DECRYPT = 11,
+ ERROR_UNKNOWN = 12,
+ ERROR_INSUFFICIENT_SECURITY = 13,
+ ERROR_FRAME_TOO_LARGE = 14,
+ ERROR_SESSION_LOST_STATE = 15,
+ ERROR_RESOURCE_CONTENTION = 16,
+};
+
+enum CdmKeyType : int32_t {
+ KEY_TYPE_OFFLINE = 0,
+ KEY_TYPE_STREAMING = 1,
+ KEY_TYPE_RELEASE = 2,
+};
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/DeviceFiles.h b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/DeviceFiles.h
new file mode 100644
index 0000000..5698441
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/DeviceFiles.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2021 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 <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "ClearKeyTypes.h"
+#include "MemoryFileSystem.h"
+
+namespace clearkeydrm {
+class OfflineFile;
+class DeviceFiles {
+ public:
+ typedef enum {
+ kLicenseStateUnknown,
+ kLicenseStateActive,
+ kLicenseStateReleasing,
+ } LicenseState;
+
+ DeviceFiles(){};
+ virtual ~DeviceFiles(){};
+
+ virtual bool StoreLicense(const std::string& keySetId, LicenseState state,
+ const std::string& keyResponse);
+
+ virtual bool RetrieveLicense(const std::string& key_set_id, LicenseState* state,
+ std::string* offlineLicense);
+
+ virtual bool LicenseExists(const std::string& keySetId);
+
+ virtual std::vector<std::string> ListLicenses() const;
+
+ virtual bool DeleteLicense(const std::string& keySetId);
+
+ virtual bool DeleteAllLicenses();
+
+ private:
+ bool FileExists(const std::string& path) const;
+ ssize_t GetFileSize(const std::string& fileName) const;
+ bool RemoveFile(const std::string& fileName);
+
+ bool RetrieveHashedFile(
+ const std::string& fileName,
+ OfflineFile* deSerializedFile);
+ bool StoreFileRaw(const std::string& fileName, const std::string& serializedFile);
+ bool StoreFileWithHash(const std::string& fileName, const std::string& serializedFile);
+
+ MemoryFileSystem mFileHandle;
+
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(DeviceFiles);
+};
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/InitDataParser.h b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/InitDataParser.h
new file mode 100644
index 0000000..8ecc8e3
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/InitDataParser.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 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 "ClearKeyTypes.h"
+
+namespace clearkeydrm {
+
+class InitDataParser {
+ public:
+ InitDataParser() {}
+
+ CdmResponseType parse(const std::vector<uint8_t>& initData, const std::string& mimeType,
+ CdmKeyType keyType, std::vector<uint8_t>* licenseRequest);
+
+ private:
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(InitDataParser);
+
+ CdmResponseType parsePssh(const std::vector<uint8_t>& initData,
+ std::vector<const uint8_t*>* keyIds);
+
+ std::string generateRequest(CdmKeyType keyType, const std::vector<const uint8_t*>& keyIds);
+};
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/JsonWebKey.h b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/JsonWebKey.h
new file mode 100644
index 0000000..6681553
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/JsonWebKey.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 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 <string>
+#include <vector>
+
+#include "jsmn.h"
+#include "ClearKeyTypes.h"
+
+namespace clearkeydrm {
+
+class JsonWebKey {
+ public:
+ JsonWebKey();
+ virtual ~JsonWebKey();
+
+ bool extractKeysFromJsonWebKeySet(const std::string& jsonWebKeySet, KeyMap* keys);
+
+ private:
+ std::vector<jsmntok_t> mJsmnTokens;
+ std::vector<std::string> mJsonObjects;
+ std::vector<std::string> mTokens;
+
+ bool decodeBase64String(const std::string& encodedText, std::vector<uint8_t>* decodedText);
+ bool findKey(const std::string& jsonObject, std::string* keyId, std::string* encodedKey);
+ void findValue(const std::string& key, std::string* value);
+ bool isJsonWebKeySet(const std::string& jsonObject) const;
+ bool parseJsonObject(const std::string& jsonObject, std::vector<std::string>* tokens);
+ bool parseJsonWebKeySet(const std::string& jsonWebKeySet,
+ std::vector<std::string>* jsonObjects);
+
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(JsonWebKey);
+};
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/MemoryFileSystem.h b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/MemoryFileSystem.h
new file mode 100644
index 0000000..5642a0f
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/MemoryFileSystem.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2021 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 <map>
+#include <string>
+
+#include "ClearKeyTypes.h"
+
+namespace clearkeydrm {
+
+// Using android file system requires clearkey plugin to update
+// its sepolicy. However, we are unable to update sepolicy for
+// older vendor partitions. To provide backward compatibility,
+// clearkey plugin implements a very simple file system in memory.
+// This memory file system does not support directory structure.
+class MemoryFileSystem {
+ public:
+ struct MemoryFile {
+ std::string fileName; // excludes path
+ std::string content;
+ size_t fileSize;
+
+ std::string getContent() const { return content; }
+ size_t getFileSize() const { return fileSize; }
+ void setContent(const std::string& file) { content = file; }
+ void setFileName(const std::string& name) { fileName = name; }
+ void setFileSize(size_t size) {
+ content.resize(size);
+ fileSize = size;
+ }
+ };
+
+ MemoryFileSystem(){};
+ virtual ~MemoryFileSystem(){};
+
+ bool FileExists(const std::string& fileName) const;
+ ssize_t GetFileSize(const std::string& fileName) const;
+ std::vector<std::string> ListFiles() const;
+ size_t Read(const std::string& pathName, std::string* buffer);
+ bool RemoveAllFiles();
+ bool RemoveFile(const std::string& fileName);
+ size_t Write(const std::string& pathName, const MemoryFile& memoryFile);
+
+ private:
+ // License file name is made up of a unique keySetId, therefore,
+ // the filename can be used as the key to locate licenses in the
+ // memory file system.
+ std::map<std::string, MemoryFile> mMemoryFileSystem;
+
+ std::string GetFileName(const std::string& path);
+
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(MemoryFileSystem);
+};
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/MimeTypeStdStr.h b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/MimeTypeStdStr.h
new file mode 100644
index 0000000..dea2974
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/MimeTypeStdStr.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2021 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 <string>
+
+namespace {
+const std::string kCencInitDataFormat("cenc");
+const std::string kIsoBmffAudioMimeType("audio/mp4");
+const std::string kIsoBmffVideoMimeType("video/mp4");
+const std::string kWebmInitDataFormat("webm");
+const std::string kWebmAudioMimeType("audio/webm");
+const std::string kWebmVideoMimeType("video/webm");
+} // namespace
diff --git a/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/Session.h b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/Session.h
new file mode 100644
index 0000000..e2d4e32
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/Session.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2021 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 <utils/Mutex.h>
+#include <utils/RefBase.h>
+
+#include <cstdint>
+#include <vector>
+
+#include "ClearKeyTypes.h"
+
+namespace clearkeydrm {
+
+class Session : public ::android::RefBase {
+ public:
+ explicit Session(const std::vector<uint8_t>& sessionId)
+ : mSessionId(sessionId), mMockError(clearkeydrm::OK) {}
+ virtual ~Session() {}
+
+ const std::vector<uint8_t>& sessionId() const { return mSessionId; }
+
+ CdmResponseType getKeyRequest(const std::vector<uint8_t>& initDataType,
+ const std::string& mimeType,
+ CdmKeyType keyType,
+ std::vector<uint8_t>* keyRequest) const;
+
+ CdmResponseType provideKeyResponse(const std::vector<uint8_t>& response);
+
+ CdmResponseType decrypt(const KeyId keyId, const Iv iv, const uint8_t* srcPtr, uint8_t* dstPtr,
+ const std::vector<int32_t>& clearDataLengths,
+ const std::vector<int32_t>& encryptedDataLengths,
+ size_t* bytesDecryptedOut);
+
+ void setMockError(CdmResponseType error) { mMockError = error; }
+ CdmResponseType getMockError() const { return mMockError; }
+
+ private:
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(Session);
+
+ const std::vector<uint8_t> mSessionId;
+ KeyMap mKeyMap;
+ ::android::Mutex mMapLock;
+
+ // For mocking error return scenarios
+ CdmResponseType mMockError;
+};
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/SessionLibrary.h b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/SessionLibrary.h
new file mode 100644
index 0000000..17d4a22
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/SessionLibrary.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 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 <utils/Mutex.h>
+#include <utils/RefBase.h>
+
+#include "ClearKeyTypes.h"
+#include "Session.h"
+
+namespace clearkeydrm {
+
+class SessionLibrary {
+ public:
+ static SessionLibrary* get();
+
+ ::android::sp<Session> createSession();
+
+ ::android::sp<Session> findSession(const std::vector<uint8_t>& sessionId);
+
+ void destroySession(const ::android::sp<Session>& session);
+
+ size_t numOpenSessions() const { return mSessions.size(); }
+
+ private:
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(SessionLibrary);
+
+ SessionLibrary() : mNextSessionId(1) {}
+
+ static ::android::Mutex sSingletonLock;
+ static SessionLibrary* sSingleton;
+
+ ::android::Mutex mSessionsLock;
+ uint32_t mNextSessionId;
+ std::map<std::vector<uint8_t>, ::android::sp<Session>> mSessions;
+};
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/protos/DeviceFiles.proto b/drm/mediadrm/plugins/clearkey/common/protos/DeviceFiles.proto
new file mode 100644
index 0000000..2d98656
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/protos/DeviceFiles.proto
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+syntax = "proto2";
+
+package clearkeydrm;
+
+// need this if we are using libprotobuf-cpp-2.3.0-lite
+option optimize_for = LITE_RUNTIME;
+
+message License {
+ enum LicenseState {
+ ACTIVE = 1;
+ RELEASING = 2;
+ }
+
+ optional LicenseState state = 1;
+ optional bytes license = 2;
+}
+
+message OfflineFile {
+ enum FileType {
+ LICENSE = 1;
+ }
+
+ enum FileVersion {
+ VERSION_1 = 1;
+ }
+
+ optional FileType type = 1;
+ optional FileVersion version = 2 [default = VERSION_1];
+ optional License license = 3;
+
+}
+
+message HashedFile {
+ optional bytes file = 1;
+ // A raw (not hex-encoded) SHA256, taken over the bytes of 'file'.
+ optional bytes hash = 2;
+}
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index bd6db55..a1e1702 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -55,6 +55,7 @@
// for audio_track_cblk_t::mState, to match TrackBase.h
static inline constexpr int CBLK_STATE_IDLE = 0;
+static inline constexpr int CBLK_STATE_ACTIVE = 6;
static inline constexpr int CBLK_STATE_PAUSING = 7;
/**
diff --git a/media/audioserver/Android.bp b/media/audioserver/Android.bp
index 0b44700..828d861 100644
--- a/media/audioserver/Android.bp
+++ b/media/audioserver/Android.bp
@@ -21,6 +21,7 @@
header_libs: [
"libaudiohal_headers",
+ "libmedia_headers",
"libmediametrics_headers",
],
@@ -51,7 +52,6 @@
"frameworks/av/media/libaaudio/include",
"frameworks/av/media/libaaudio/src",
"frameworks/av/media/libaaudio/src/binding",
- "frameworks/av/media/libmedia/include",
"frameworks/av/services/audioflinger",
"frameworks/av/services/audiopolicy",
"frameworks/av/services/audiopolicy/common/include",
diff --git a/media/bufferpool/2.0/Android.bp b/media/bufferpool/2.0/Android.bp
index 0d1fe27..930b026 100644
--- a/media/bufferpool/2.0/Android.bp
+++ b/media/bufferpool/2.0/Android.bp
@@ -40,6 +40,12 @@
defaults: ["libstagefright_bufferpool@2.0-default"],
vendor_available: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ "test_com.android.media.swcodec",
+ ],
+
// TODO: b/147147992
double_loadable: true,
cflags: [
diff --git a/media/codec2/components/aom/Android.bp b/media/codec2/components/aom/Android.bp
index cb9837f..a2a79d5 100644
--- a/media/codec2/components/aom/Android.bp
+++ b/media/codec2/components/aom/Android.bp
@@ -22,8 +22,4 @@
srcs: ["C2SoftAomDec.cpp"],
static_libs: ["libaom"],
-
- include_dirs: [
- "external/libaom/",
- ],
}
diff --git a/media/codec2/components/avc/Android.bp b/media/codec2/components/avc/Android.bp
index 0be1bed..7f82486 100644
--- a/media/codec2/components/avc/Android.bp
+++ b/media/codec2/components/avc/Android.bp
@@ -18,11 +18,6 @@
static_libs: ["libavcdec"],
srcs: ["C2SoftAvcDec.cpp"],
-
- include_dirs: [
- "external/libavc/decoder",
- "external/libavc/common",
- ],
}
cc_library {
@@ -37,11 +32,6 @@
srcs: ["C2SoftAvcEnc.cpp"],
- include_dirs: [
- "external/libavc/encoder",
- "external/libavc/common",
- ],
-
cflags: [
"-Wno-unused-variable",
],
diff --git a/media/codec2/components/base/Android.bp b/media/codec2/components/base/Android.bp
index 160e250..f1669fd 100644
--- a/media/codec2/components/base/Android.bp
+++ b/media/codec2/components/base/Android.bp
@@ -34,6 +34,12 @@
"libstagefright_foundation", // for Mutexed
],
+ min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
+
sanitize: {
misc_undefined: [
"unsigned-integer-overflow",
@@ -75,6 +81,12 @@
],
ldflags: ["-Wl,-Bsymbolic"],
+
+ min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
}
// public dependency for software codec implementation
diff --git a/media/codec2/components/base/SimpleC2Component.cpp b/media/codec2/components/base/SimpleC2Component.cpp
index 99ff450..434246f 100644
--- a/media/codec2/components/base/SimpleC2Component.cpp
+++ b/media/codec2/components/base/SimpleC2Component.cpp
@@ -763,6 +763,43 @@
return hasQueuedWork;
}
+int SimpleC2Component::getHalPixelFormatForBitDepth10(bool allowRGBA1010102) {
+ // Save supported hal pixel formats for bit depth of 10, the first time this is called
+ if (!mBitDepth10HalPixelFormats.size()) {
+ std::vector<int> halPixelFormats;
+ // TODO(b/178229371) Enable HAL_PIXEL_FORMAT_YCBCR_P010 once framework supports it
+ // halPixelFormats.push_back(HAL_PIXEL_FORMAT_YCBCR_P010);
+
+ // since allowRGBA1010102 can chance in each call, but mBitDepth10HalPixelFormats
+ // is populated only once, allowRGBA1010102 is not considered at this stage.
+ halPixelFormats.push_back(HAL_PIXEL_FORMAT_RGBA_1010102);
+
+ for (int halPixelFormat : halPixelFormats) {
+ std::shared_ptr<C2GraphicBlock> block;
+
+ uint32_t gpuConsumerFlags = halPixelFormat == HAL_PIXEL_FORMAT_RGBA_1010102
+ ? C2AndroidMemoryUsage::HW_TEXTURE_READ
+ : 0;
+ C2MemoryUsage usage = {C2MemoryUsage::CPU_READ | gpuConsumerFlags,
+ C2MemoryUsage::CPU_WRITE};
+ // TODO(b/214411172) Use AHardwareBuffer_isSupported once it supports P010
+ c2_status_t status =
+ mOutputBlockPool->fetchGraphicBlock(320, 240, halPixelFormat, usage, &block);
+ if (status == C2_OK) {
+ mBitDepth10HalPixelFormats.push_back(halPixelFormat);
+ }
+ }
+ // Add YV12 in the end as a fall-back option
+ mBitDepth10HalPixelFormats.push_back(HAL_PIXEL_FORMAT_YV12);
+ }
+ // When RGBA1010102 is not allowed and if the first supported hal pixel is format is
+ // HAL_PIXEL_FORMAT_RGBA_1010102, then return HAL_PIXEL_FORMAT_YV12
+ if (!allowRGBA1010102 && mBitDepth10HalPixelFormats[0] == HAL_PIXEL_FORMAT_RGBA_1010102) {
+ return HAL_PIXEL_FORMAT_YV12;
+ }
+ // Return the first entry from supported formats
+ return mBitDepth10HalPixelFormats[0];
+}
std::shared_ptr<C2Buffer> SimpleC2Component::createLinearBuffer(
const std::shared_ptr<C2LinearBlock> &block, size_t offset, size_t size) {
return C2Buffer::CreateLinearBuffer(block->share(offset, size, ::C2Fence()));
diff --git a/media/codec2/components/base/include/SimpleC2Component.h b/media/codec2/components/base/include/SimpleC2Component.h
index 3b4e212..d244f45 100644
--- a/media/codec2/components/base/include/SimpleC2Component.h
+++ b/media/codec2/components/base/include/SimpleC2Component.h
@@ -167,6 +167,7 @@
static constexpr uint32_t NO_DRAIN = ~0u;
C2ReadView mDummyReadView;
+ int getHalPixelFormatForBitDepth10(bool allowRGBA1010102);
private:
const std::shared_ptr<C2ComponentInterface> mIntf;
@@ -250,6 +251,7 @@
class BlockingBlockPool;
std::shared_ptr<BlockingBlockPool> mOutputBlockPool;
+ std::vector<int> mBitDepth10HalPixelFormats;
SimpleC2Component() = delete;
};
diff --git a/media/codec2/components/cmds/Android.bp b/media/codec2/components/cmds/Android.bp
index d6ffd12..2a11c01 100644
--- a/media/codec2/components/cmds/Android.bp
+++ b/media/codec2/components/cmds/Android.bp
@@ -15,9 +15,6 @@
"codec2.cpp",
],
- include_dirs: [
- ],
-
header_libs: [
"libmediadrm_headers",
],
diff --git a/media/codec2/components/gav1/Android.bp b/media/codec2/components/gav1/Android.bp
index 7692d37..162339f 100644
--- a/media/codec2/components/gav1/Android.bp
+++ b/media/codec2/components/gav1/Android.bp
@@ -22,4 +22,10 @@
srcs: ["C2SoftGav1Dec.cpp"],
static_libs: ["libgav1"],
+
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
+
}
diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.cpp b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
index ff6080d..2ed8541 100644
--- a/media/codec2/components/gav1/C2SoftGav1Dec.cpp
+++ b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
@@ -32,6 +32,8 @@
// codecname set and passed in as a compile flag from Android.bp
constexpr char COMPONENT_NAME[] = CODECNAME;
+constexpr size_t kMinInputBufferSize = 2 * 1024 * 1024;
+
class C2SoftGav1Dec::IntfImpl : public SimpleInterface<void>::BaseParams {
public:
explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
@@ -110,8 +112,7 @@
.build());
addParameter(DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
- .withDefault(new C2StreamMaxBufferSizeInfo::input(
- 0u, 320 * 240 * 3 / 4))
+ .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, kMinInputBufferSize))
.withFields({
C2F(mMaxInputSize, value).any(),
})
@@ -227,9 +228,9 @@
bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input> &me,
const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
(void)mayBlock;
- // assume compression ratio of 2
- me.set().value =
- (((maxSize.v.width + 63) / 64) * ((maxSize.v.height + 63) / 64) * 3072);
+ // assume compression ratio of 2, but enforce a floor
+ me.set().value = c2_max((((maxSize.v.width + 63) / 64)
+ * ((maxSize.v.height + 63) / 64) * 3072), kMinInputBufferSize);
return C2R::Ok();
}
@@ -334,7 +335,6 @@
std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
mIntf(intfImpl),
mCodecCtx(nullptr) {
- mIsFormatR10G10B10A2Supported = IsFormatR10G10B10A2SupportedForLegacyRendering();
gettimeofday(&mTimeStart, nullptr);
gettimeofday(&mTimeEnd, nullptr);
}
@@ -632,25 +632,20 @@
IntfImpl::Lock lock = mIntf->lock();
std::shared_ptr<C2StreamColorAspectsInfo::output> codedColorAspects =
mIntf->getColorAspects_l();
-
+ bool allowRGBA1010102 = false;
if (codedColorAspects->primaries == C2Color::PRIMARIES_BT2020 &&
codedColorAspects->matrix == C2Color::MATRIX_BT2020 &&
codedColorAspects->transfer == C2Color::TRANSFER_ST2084) {
- if (buffer->image_format != libgav1::kImageFormatYuv420) {
+ allowRGBA1010102 = true;
+ }
+ format = getHalPixelFormatForBitDepth10(allowRGBA1010102);
+ if ((format == HAL_PIXEL_FORMAT_RGBA_1010102) &&
+ (buffer->image_format != libgav1::kImageFormatYuv420)) {
ALOGE("Only YUV420 output is supported when targeting RGBA_1010102");
- mSignalledError = true;
- work->result = C2_OMITTED;
- work->workletsProcessed = 1u;
- return false;
- }
- // TODO (b/201787956) For devices that do not support HAL_PIXEL_FORMAT_RGBA_1010102,
- // HAL_PIXEL_FORMAT_YV12 is used as a temporary work around.
- if (!mIsFormatR10G10B10A2Supported) {
- ALOGE("HAL_PIXEL_FORMAT_RGBA_1010102 isn't supported");
- format = HAL_PIXEL_FORMAT_YV12;
- } else {
- format = HAL_PIXEL_FORMAT_RGBA_1010102;
- }
+ mSignalledError = true;
+ work->result = C2_OMITTED;
+ work->workletsProcessed = 1u;
+ return false;
}
}
C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.h b/media/codec2/components/gav1/C2SoftGav1Dec.h
index f82992d..134fa0d 100644
--- a/media/codec2/components/gav1/C2SoftGav1Dec.h
+++ b/media/codec2/components/gav1/C2SoftGav1Dec.h
@@ -82,7 +82,6 @@
struct timeval mTimeStart; // Time at the start of decode()
struct timeval mTimeEnd; // Time at the end of decode()
- bool mIsFormatR10G10B10A2Supported;
bool initDecoder();
void getVuiParams(const libgav1::DecoderBuffer *buffer);
diff --git a/media/codec2/components/hevc/C2SoftHevcDec.cpp b/media/codec2/components/hevc/C2SoftHevcDec.cpp
index 5f5b2ef..2a6adca 100644
--- a/media/codec2/components/hevc/C2SoftHevcDec.cpp
+++ b/media/codec2/components/hevc/C2SoftHevcDec.cpp
@@ -34,6 +34,7 @@
constexpr char COMPONENT_NAME[] = "c2.android.hevc.decoder";
constexpr uint32_t kDefaultOutputDelay = 8;
constexpr uint32_t kMaxOutputDelay = 16;
+constexpr size_t kMinInputBufferSize = 2 * 1024 * 1024;
} // namespace
class C2SoftHevcDec::IntfImpl : public SimpleInterface<void>::BaseParams {
@@ -108,7 +109,7 @@
addParameter(
DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
- .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, 320 * 240 * 3 / 4))
+ .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, kMinInputBufferSize))
.withFields({
C2F(mMaxInputSize, value).any(),
})
@@ -220,8 +221,9 @@
static C2R MaxInputSizeSetter(bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input> &me,
const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
(void)mayBlock;
- // assume compression ratio of 2
- me.set().value = (((maxSize.v.width + 63) / 64) * ((maxSize.v.height + 63) / 64) * 3072);
+ // assume compression ratio of 2, but enforce a floor
+ me.set().value = c2_max((((maxSize.v.width + 63) / 64)
+ * ((maxSize.v.height + 63) / 64) * 3072), kMinInputBufferSize);
return C2R::Ok();
}
diff --git a/media/codec2/components/mpeg2/Android.bp b/media/codec2/components/mpeg2/Android.bp
index daa10ae..a58044c 100644
--- a/media/codec2/components/mpeg2/Android.bp
+++ b/media/codec2/components/mpeg2/Android.bp
@@ -17,9 +17,4 @@
srcs: ["C2SoftMpeg2Dec.cpp"],
static_libs: ["libmpeg2dec"],
-
- include_dirs: [
- "external/libmpeg2/decoder",
- "external/libmpeg2/common",
- ],
}
diff --git a/media/codec2/components/tests/Android.bp b/media/codec2/components/tests/Android.bp
index 3c68eee..be2abf2 100644
--- a/media/codec2/components/tests/Android.bp
+++ b/media/codec2/components/tests/Android.bp
@@ -9,44 +9,13 @@
cc_defaults {
name: "C2SoftCodecTest-defaults",
+ defaults: [ "libcodec2-static-defaults" ],
gtest: true,
host_supported: false,
srcs: [
"C2SoftCodecTest.cpp",
],
- static_libs: [
- "liblog",
- "libion",
- "libfmq",
- "libbase",
- "libutils",
- "libcutils",
- "libcodec2",
- "libhidlbase",
- "libdmabufheap",
- "libcodec2_vndk",
- "libnativewindow",
- "libcodec2_soft_common",
- "libsfplugin_ccodec_utils",
- "libstagefright_foundation",
- "libstagefright_bufferpool@2.0.1",
- "android.hardware.graphics.mapper@2.0",
- "android.hardware.graphics.mapper@3.0",
- "android.hardware.media.bufferpool@2.0",
- "android.hardware.graphics.allocator@2.0",
- "android.hardware.graphics.allocator@3.0",
- "android.hardware.graphics.bufferqueue@2.0",
- ],
-
- shared_libs: [
- "libui",
- "libdl",
- "libhardware",
- "libvndksupport",
- "libprocessgroup",
- ],
-
cflags: [
"-Wall",
"-Werror",
diff --git a/media/codec2/components/vpx/C2SoftVpxDec.cpp b/media/codec2/components/vpx/C2SoftVpxDec.cpp
index 0a27821..5fc89be 100644
--- a/media/codec2/components/vpx/C2SoftVpxDec.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxDec.cpp
@@ -352,7 +352,6 @@
mCodecCtx(nullptr),
mCoreCount(1),
mQueue(new Mutexed<ConversionQueue>) {
- mIsFormatR10G10B10A2Supported = IsFormatR10G10B10A2SupportedForLegacyRendering();
}
C2SoftVpxDec::~C2SoftVpxDec() {
@@ -683,19 +682,13 @@
if (img->fmt == VPX_IMG_FMT_I42016) {
IntfImpl::Lock lock = mIntf->lock();
std::shared_ptr<C2StreamColorAspectsTuning::output> defaultColorAspects = mIntf->getDefaultColorAspects_l();
-
+ bool allowRGBA1010102 = false;
if (defaultColorAspects->primaries == C2Color::PRIMARIES_BT2020 &&
defaultColorAspects->matrix == C2Color::MATRIX_BT2020 &&
defaultColorAspects->transfer == C2Color::TRANSFER_ST2084) {
- // TODO (b/201787956) For devices that do not support HAL_PIXEL_FORMAT_RGBA_1010102,
- // HAL_PIXEL_FORMAT_YV12 is used as a temporary work around.
- if (!mIsFormatR10G10B10A2Supported) {
- ALOGE("HAL_PIXEL_FORMAT_RGBA_1010102 isn't supported");
- format = HAL_PIXEL_FORMAT_YV12;
- } else {
- format = HAL_PIXEL_FORMAT_RGBA_1010102;
- }
+ allowRGBA1010102 = true;
}
+ format = getHalPixelFormatForBitDepth10(allowRGBA1010102);
}
C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 16), mHeight, format, usage, &block);
diff --git a/media/codec2/components/vpx/C2SoftVpxDec.h b/media/codec2/components/vpx/C2SoftVpxDec.h
index ade162d..2065165 100644
--- a/media/codec2/components/vpx/C2SoftVpxDec.h
+++ b/media/codec2/components/vpx/C2SoftVpxDec.h
@@ -80,7 +80,7 @@
};
std::shared_ptr<Mutexed<ConversionQueue>> mQueue;
std::vector<sp<ConverterThread>> mConverterThreads;
- bool mIsFormatR10G10B10A2Supported;
+
status_t initDecoder();
status_t destroyDecoder();
void finishWork(uint64_t index, const std::unique_ptr<C2Work> &work,
diff --git a/media/codec2/core/Android.bp b/media/codec2/core/Android.bp
index 64999b7..7d5740b 100644
--- a/media/codec2/core/Android.bp
+++ b/media/codec2/core/Android.bp
@@ -11,6 +11,10 @@
name: "libcodec2_headers",
vendor_available: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
export_include_dirs: ["include"],
}
@@ -18,6 +22,10 @@
name: "libcodec2",
vendor_available: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
vndk: {
enabled: true,
},
diff --git a/media/codec2/core/include/C2Config.h b/media/codec2/core/include/C2Config.h
index feaa98c..70e742c 100644
--- a/media/codec2/core/include/C2Config.h
+++ b/media/codec2/core/include/C2Config.h
@@ -59,6 +59,7 @@
enum drc_compression_mode_t : int32_t; ///< DRC compression mode
enum drc_effect_type_t : int32_t; ///< DRC effect type
enum drc_album_mode_t : int32_t; ///< DRC album mode
+ enum hdr_dynamic_metadata_type_t : uint32_t; ///< HDR dynamic metadata type
enum intra_refresh_mode_t : uint32_t; ///< intra refresh modes
enum level_t : uint32_t; ///< coding level
enum ordinal_key_t : uint32_t; ///< work ordering keys
@@ -189,10 +190,13 @@
kParamIndexPictureTypeMask,
kParamIndexPictureType,
+ // deprecated
kParamIndexHdr10PlusMetadata,
kParamIndexPictureQuantization,
+ kParamIndexHdrDynamicMetadata,
+
/* ------------------------------------ video components ------------------------------------ */
kParamIndexFrameRate = C2_PARAM_INDEX_VIDEO_PARAM_START,
@@ -270,6 +274,9 @@
// encoding quality requirements
kParamIndexEncodingQualityLevel, // encoders, enum
+
+ // encoding statistics, average block qp of a frame
+ kParamIndexAverageBlockQuantization, // int32
};
}
@@ -680,6 +687,9 @@
LEVEL_DV_MAIN_UHD_30, ///< Dolby Vision main tier uhd30
LEVEL_DV_MAIN_UHD_48, ///< Dolby Vision main tier uhd48
LEVEL_DV_MAIN_UHD_60, ///< Dolby Vision main tier uhd60
+ LEVEL_DV_MAIN_UHD_120, ///< Dolby Vision main tier uhd120
+ LEVEL_DV_MAIN_8K_30, ///< Dolby Vision main tier 8k30
+ LEVEL_DV_MAIN_8K_60, ///< Dolby Vision main tier 8k60
LEVEL_DV_HIGH_HD_24 = _C2_PL_DV_BASE + 0x100, ///< Dolby Vision high tier hd24
LEVEL_DV_HIGH_HD_30, ///< Dolby Vision high tier hd30
@@ -690,6 +700,9 @@
LEVEL_DV_HIGH_UHD_30, ///< Dolby Vision high tier uhd30
LEVEL_DV_HIGH_UHD_48, ///< Dolby Vision high tier uhd48
LEVEL_DV_HIGH_UHD_60, ///< Dolby Vision high tier uhd60
+ LEVEL_DV_HIGH_UHD_120, ///< Dolby Vision high tier uhd120
+ LEVEL_DV_HIGH_8K_30, ///< Dolby Vision high tier 8k30
+ LEVEL_DV_HIGH_8K_60, ///< Dolby Vision high tier 8k60
// AV1 levels
LEVEL_AV1_2 = _C2_PL_AV1_BASE , ///< AV1 Level 2
@@ -1602,16 +1615,54 @@
C2FIELD(maxFall, "max-fall")
};
typedef C2StreamParam<C2Info, C2HdrStaticMetadataStruct, kParamIndexHdrStaticMetadata>
- C2StreamHdrStaticInfo;
+ C2StreamHdrStaticMetadataInfo;
+typedef C2StreamParam<C2Info, C2HdrStaticMetadataStruct, kParamIndexHdrStaticMetadata>
+ C2StreamHdrStaticInfo; // deprecated
constexpr char C2_PARAMKEY_HDR_STATIC_INFO[] = "raw.hdr-static-info";
/**
* HDR10+ Metadata Info.
+ *
+ * Deprecated. Use C2StreamHdrDynamicMetadataInfo with
+ * HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40
*/
typedef C2StreamParam<C2Info, C2BlobValue, kParamIndexHdr10PlusMetadata>
- C2StreamHdr10PlusInfo;
-constexpr char C2_PARAMKEY_INPUT_HDR10_PLUS_INFO[] = "input.hdr10-plus-info";
-constexpr char C2_PARAMKEY_OUTPUT_HDR10_PLUS_INFO[] = "output.hdr10-plus-info";
+ C2StreamHdr10PlusInfo; // deprecated
+constexpr char C2_PARAMKEY_INPUT_HDR10_PLUS_INFO[] = "input.hdr10-plus-info"; // deprecated
+constexpr char C2_PARAMKEY_OUTPUT_HDR10_PLUS_INFO[] = "output.hdr10-plus-info"; // deprecated
+
+/**
+ * HDR dynamic metadata types
+ */
+C2ENUM(C2Config::hdr_dynamic_metadata_type_t, uint32_t,
+ HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_10, ///< SMPTE ST 2094-10
+ HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40, ///< SMPTE ST 2094-40
+)
+
+struct C2HdrDynamicMetadataStruct {
+ inline C2HdrDynamicMetadataStruct() { memset(this, 0, sizeof(*this)); }
+
+ inline C2HdrDynamicMetadataStruct(
+ size_t flexCount, C2Config::hdr_dynamic_metadata_type_t type)
+ : type_(type) {
+ memset(data, 0, flexCount);
+ }
+
+ C2Config::hdr_dynamic_metadata_type_t type_;
+ uint8_t data[];
+
+ DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(HdrDynamicMetadata, data)
+ C2FIELD(type_, "type")
+ C2FIELD(data, "data")
+};
+
+/**
+ * Dynamic HDR Metadata Info.
+ */
+typedef C2StreamParam<C2Info, C2HdrDynamicMetadataStruct, kParamIndexHdrDynamicMetadata>
+ C2StreamHdrDynamicMetadataInfo;
+constexpr char C2_PARAMKEY_INPUT_HDR_DYNAMIC_INFO[] = "input.hdr-dynamic-info";
+constexpr char C2_PARAMKEY_OUTPUT_HDR_DYNAMIC_INFO[] = "output.hdr-dynamic-info";
/* ------------------------------------ block-based coding ----------------------------------- */
@@ -2411,6 +2462,17 @@
S_HANDHELD = 1 // corresponds to VMAF=70
);
+/**
+ * Video Encoding Statistics Export
+ */
+
+/**
+ * Average block QP exported from video encoder.
+ */
+typedef C2StreamParam<C2Info, C2SimpleValueStruct<int32_t>, kParamIndexAverageBlockQuantization>
+ C2AndroidStreamAverageBlockQuantizationInfo;
+constexpr char C2_PARAMKEY_AVERAGE_QP[] = "coded.average-qp";
+
/// @}
#endif // C2CONFIG_H_
diff --git a/media/codec2/fuzzer/Android.bp b/media/codec2/fuzzer/Android.bp
index bd1fac6..3adc212 100644
--- a/media/codec2/fuzzer/Android.bp
+++ b/media/codec2/fuzzer/Android.bp
@@ -28,43 +28,12 @@
cc_defaults {
name: "C2Fuzzer-defaults",
+ defaults: [ "libcodec2-static-defaults" ],
+
srcs: [
"C2Fuzzer.cpp",
],
- static_libs: [
- "liblog",
- "libion",
- "libfmq",
- "libbase",
- "libutils",
- "libcutils",
- "libcodec2",
- "libhidlbase",
- "libdmabufheap",
- "libcodec2_vndk",
- "libnativewindow",
- "libcodec2_soft_common",
- "libsfplugin_ccodec_utils",
- "libstagefright_foundation",
- "libstagefright_bufferpool@2.0.1",
- "android.hardware.graphics.mapper@2.0",
- "android.hardware.graphics.mapper@3.0",
- "android.hardware.media.bufferpool@2.0",
- "android.hardware.graphics.allocator@2.0",
- "android.hardware.graphics.allocator@3.0",
- "android.hardware.graphics.bufferqueue@2.0",
- ],
-
- shared_libs: [
- "libui",
- "libdl",
- "libbinder",
- "libhardware",
- "libvndksupport",
- "libprocessgroup",
- ],
-
cflags: [
"-Wall",
"-Werror",
diff --git a/media/codec2/hidl/1.0/utils/Android.bp b/media/codec2/hidl/1.0/utils/Android.bp
index 122aacd..db7874d 100644
--- a/media/codec2/hidl/1.0/utils/Android.bp
+++ b/media/codec2/hidl/1.0/utils/Android.bp
@@ -57,6 +57,10 @@
name: "libcodec2_hidl@1.0",
vendor_available: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
defaults: ["hidl_defaults"],
diff --git a/media/codec2/hidl/1.1/utils/Android.bp b/media/codec2/hidl/1.1/utils/Android.bp
index 0eeedb6..ed77a15 100644
--- a/media/codec2/hidl/1.1/utils/Android.bp
+++ b/media/codec2/hidl/1.1/utils/Android.bp
@@ -67,6 +67,11 @@
name: "libcodec2_hidl@1.1",
vendor_available: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
+
defaults: ["hidl_defaults"],
diff --git a/media/codec2/sfplugin/Android.bp b/media/codec2/sfplugin/Android.bp
index 2bc748f..feeddb5 100644
--- a/media/codec2/sfplugin/Android.bp
+++ b/media/codec2/sfplugin/Android.bp
@@ -42,12 +42,14 @@
"android.hardware.drm@1.0",
"android.hardware.media.c2@1.0",
"android.hardware.media.omx@1.0",
+ "android.hardware.graphics.mapper@4.0",
"libbase",
"libbinder",
"libcodec2",
"libcodec2_client",
"libcodec2_vndk",
"libcutils",
+ "libgralloctypes",
"libgui",
"libhidlallocatorutils",
"libhidlbase",
diff --git a/media/codec2/sfplugin/C2OMXNode.cpp b/media/codec2/sfplugin/C2OMXNode.cpp
index c049187..ed7d69c 100644
--- a/media/codec2/sfplugin/C2OMXNode.cpp
+++ b/media/codec2/sfplugin/C2OMXNode.cpp
@@ -42,6 +42,7 @@
#include "utils/Codec2Mapper.h"
#include "C2OMXNode.h"
+#include "Codec2Buffer.h"
namespace android {
@@ -466,6 +467,18 @@
new Buffer2D(block->share(
C2Rect(block->width(), block->height()), ::C2Fence())));
work->input.buffers.push_back(c2Buffer);
+ std::shared_ptr<C2StreamHdrStaticInfo::input> staticInfo;
+ std::shared_ptr<C2StreamHdrDynamicMetadataInfo::input> dynamicInfo;
+ GetHdrMetadataFromGralloc4Handle(
+ block->handle(),
+ &staticInfo,
+ &dynamicInfo);
+ if (staticInfo && *staticInfo) {
+ c2Buffer->setInfo(staticInfo);
+ }
+ if (dynamicInfo && *dynamicInfo) {
+ c2Buffer->setInfo(dynamicInfo);
+ }
}
work->worklets.clear();
work->worklets.emplace_back(new C2Worklet);
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 5389339..5df28f0 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -1018,29 +1018,31 @@
} else {
pixelFormatInfo = nullptr;
}
- std::optional<uint32_t> flexPixelFormat{};
- std::optional<uint32_t> flexPlanarPixelFormat{};
- std::optional<uint32_t> flexSemiPlanarPixelFormat{};
+ // bit depth -> format
+ std::map<uint32_t, uint32_t> flexPixelFormat;
+ std::map<uint32_t, uint32_t> flexPlanarPixelFormat;
+ std::map<uint32_t, uint32_t> flexSemiPlanarPixelFormat;
if (pixelFormatInfo && *pixelFormatInfo) {
for (size_t i = 0; i < pixelFormatInfo->flexCount(); ++i) {
const C2FlexiblePixelFormatDescriptorStruct &desc =
pixelFormatInfo->m.values[i];
- if (desc.bitDepth != 8
- || desc.subsampling != C2Color::YUV_420
+ if (desc.subsampling != C2Color::YUV_420
// TODO(b/180076105): some device report wrong layout
// || desc.layout == C2Color::INTERLEAVED_PACKED
// || desc.layout == C2Color::INTERLEAVED_ALIGNED
|| desc.layout == C2Color::UNKNOWN_LAYOUT) {
continue;
}
- if (!flexPixelFormat) {
- flexPixelFormat = desc.pixelFormat;
+ if (flexPixelFormat.count(desc.bitDepth) == 0) {
+ flexPixelFormat.emplace(desc.bitDepth, desc.pixelFormat);
}
- if (desc.layout == C2Color::PLANAR_PACKED && !flexPlanarPixelFormat) {
- flexPlanarPixelFormat = desc.pixelFormat;
+ if (desc.layout == C2Color::PLANAR_PACKED
+ && flexPlanarPixelFormat.count(desc.bitDepth) == 0) {
+ flexPlanarPixelFormat.emplace(desc.bitDepth, desc.pixelFormat);
}
- if (desc.layout == C2Color::SEMIPLANAR_PACKED && !flexSemiPlanarPixelFormat) {
- flexSemiPlanarPixelFormat = desc.pixelFormat;
+ if (desc.layout == C2Color::SEMIPLANAR_PACKED
+ && flexSemiPlanarPixelFormat.count(desc.bitDepth) == 0) {
+ flexSemiPlanarPixelFormat.emplace(desc.bitDepth, desc.pixelFormat);
}
}
}
@@ -1050,7 +1052,7 @@
if (!(config->mDomain & Config::IS_ENCODER)) {
if (surface == nullptr) {
const char *prefix = "";
- if (flexSemiPlanarPixelFormat) {
+ if (flexSemiPlanarPixelFormat.count(8) != 0) {
format = COLOR_FormatYUV420SemiPlanar;
prefix = "semi-";
} else {
@@ -1067,17 +1069,34 @@
if ((config->mDomain & Config::IS_ENCODER) || !surface) {
switch (format) {
case COLOR_FormatYUV420Flexible:
- format = flexPixelFormat.value_or(COLOR_FormatYUV420Planar);
+ format = COLOR_FormatYUV420Planar;
+ if (flexPixelFormat.count(8) != 0) {
+ format = flexPixelFormat[8];
+ }
break;
case COLOR_FormatYUV420Planar:
case COLOR_FormatYUV420PackedPlanar:
- format = flexPlanarPixelFormat.value_or(
- flexPixelFormat.value_or(format));
+ if (flexPlanarPixelFormat.count(8) != 0) {
+ format = flexPlanarPixelFormat[8];
+ } else if (flexPixelFormat.count(8) != 0) {
+ format = flexPixelFormat[8];
+ }
break;
case COLOR_FormatYUV420SemiPlanar:
case COLOR_FormatYUV420PackedSemiPlanar:
- format = flexSemiPlanarPixelFormat.value_or(
- flexPixelFormat.value_or(format));
+ if (flexSemiPlanarPixelFormat.count(8) != 0) {
+ format = flexSemiPlanarPixelFormat[8];
+ } else if (flexPixelFormat.count(8) != 0) {
+ format = flexPixelFormat[8];
+ }
+ break;
+ case COLOR_FormatYUVP010:
+ format = COLOR_FormatYUVP010;
+ if (flexSemiPlanarPixelFormat.count(10) != 0) {
+ format = flexSemiPlanarPixelFormat[10];
+ } else if (flexPixelFormat.count(10) != 0) {
+ format = flexPixelFormat[10];
+ }
break;
default:
// No-op
@@ -1443,6 +1462,27 @@
config->mOutputFormat->setInt32("android._tunneled", 1);
}
+ // Convert an encoding statistics level to corresponding encoding statistics
+ // kinds
+ int32_t encodingStatisticsLevel = VIDEO_ENCODING_STATISTICS_LEVEL_NONE;
+ if ((config->mDomain & Config::IS_ENCODER)
+ && (config->mDomain & Config::IS_VIDEO)
+ && msg->findInt32(KEY_VIDEO_ENCODING_STATISTICS_LEVEL, &encodingStatisticsLevel)) {
+ // Higher level include all the enc stats belong to lower level.
+ switch (encodingStatisticsLevel) {
+ // case VIDEO_ENCODING_STATISTICS_LEVEL_2: // reserved for the future level 2
+ // with more enc stat kinds
+ // Future extended encoding statistics for the level 2 should be added here
+ case VIDEO_ENCODING_STATISTICS_LEVEL_1:
+ config->subscribeToConfigUpdate(comp,
+ {kParamIndexAverageBlockQuantization, kParamIndexPictureType});
+ break;
+ case VIDEO_ENCODING_STATISTICS_LEVEL_NONE:
+ break;
+ }
+ }
+ ALOGD("encoding statistics level = %d", encodingStatisticsLevel);
+
ALOGD("setup formats input: %s",
config->mInputFormat->debugString().c_str());
ALOGD("setup formats output: %s",
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 0de0b77..99aa593 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -840,6 +840,35 @@
hdr10PlusInfo.reset();
}
+ // HDR dynamic info
+ std::shared_ptr<const C2StreamHdrDynamicMetadataInfo::output> hdrDynamicInfo =
+ std::static_pointer_cast<const C2StreamHdrDynamicMetadataInfo::output>(
+ c2Buffer->getInfo(C2StreamHdrDynamicMetadataInfo::output::PARAM_TYPE));
+ // TODO: make this sticky & enable unset
+ if (hdrDynamicInfo && hdrDynamicInfo->flexCount() == 0) {
+ hdrDynamicInfo.reset();
+ }
+
+ if (hdr10PlusInfo) {
+ // C2StreamHdr10PlusInfo is deprecated; components should use
+ // C2StreamHdrDynamicMetadataInfo
+ // TODO: #metric
+ if (hdrDynamicInfo) {
+ // It is unexpected that C2StreamHdr10PlusInfo and
+ // C2StreamHdrDynamicMetadataInfo is both present.
+ // C2StreamHdrDynamicMetadataInfo takes priority.
+ // TODO: #metric
+ } else {
+ std::shared_ptr<C2StreamHdrDynamicMetadataInfo::output> info =
+ C2StreamHdrDynamicMetadataInfo::output::AllocShared(
+ hdr10PlusInfo->flexCount(),
+ 0u,
+ C2Config::HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40);
+ memcpy(info->m.data, hdr10PlusInfo->m.value, hdr10PlusInfo->flexCount());
+ hdrDynamicInfo = info;
+ }
+ }
+
std::vector<C2ConstGraphicBlock> blocks = c2Buffer->data().graphicBlocks();
if (blocks.size() != 1u) {
ALOGD("[%s] expected 1 graphic block, but got %zu", mName, blocks.size());
@@ -859,7 +888,7 @@
videoScalingMode,
transform,
Fence::NO_FENCE, 0);
- if (hdrStaticInfo || hdr10PlusInfo) {
+ if (hdrStaticInfo || hdrDynamicInfo) {
HdrMetadata hdr;
if (hdrStaticInfo) {
// If mastering max and min luminance fields are 0, do not use them.
@@ -896,13 +925,16 @@
hdr.cta8613 = cta861_meta;
}
}
- if (hdr10PlusInfo) {
+ if (hdrDynamicInfo
+ && hdrDynamicInfo->m.type_ == C2Config::HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40) {
hdr.validTypes |= HdrMetadata::HDR10PLUS;
hdr.hdr10plus.assign(
- hdr10PlusInfo->m.value,
- hdr10PlusInfo->m.value + hdr10PlusInfo->flexCount());
+ hdrDynamicInfo->m.data,
+ hdrDynamicInfo->m.data + hdrDynamicInfo->flexCount());
}
qbi.setHdrMetadata(hdr);
+
+ SetHdrMetadataToGralloc4Handle(hdrStaticInfo, hdrDynamicInfo, block.handle());
}
// we don't have dirty regions
qbi.setSurfaceDamage(Region::INVALID_REGION);
diff --git a/media/codec2/sfplugin/CCodecConfig.cpp b/media/codec2/sfplugin/CCodecConfig.cpp
index 03418d9..dd37c4b 100644
--- a/media/codec2/sfplugin/CCodecConfig.cpp
+++ b/media/codec2/sfplugin/CCodecConfig.cpp
@@ -899,6 +899,9 @@
add(ConfigMapper(KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT, C2_PARAMKEY_MAX_CHANNEL_COUNT, "value")
.limitTo(D::AUDIO & (D::CONFIG | D::PARAM | D::READ)));
+ add(ConfigMapper(KEY_MAX_OUTPUT_CHANNEL_COUNT, C2_PARAMKEY_MAX_CHANNEL_COUNT, "value")
+ .limitTo(D::AUDIO & (D::CONFIG | D::PARAM | D::READ)));
+
add(ConfigMapper(KEY_AAC_SBR_MODE, C2_PARAMKEY_AAC_SBR_MODE, "value")
.limitTo(D::AUDIO & D::ENCODER & (D::CONFIG | D::PARAM | D::READ))
.withMapper([](C2Value v) -> C2Value {
@@ -953,6 +956,12 @@
return value == 0 ? C2_FALSE : C2_TRUE;
}));
+ add(ConfigMapper(KEY_VIDEO_QP_AVERAGE, C2_PARAMKEY_AVERAGE_QP, "value")
+ .limitTo(D::ENCODER & D::VIDEO & D::READ));
+
+ add(ConfigMapper(KEY_PICTURE_TYPE, C2_PARAMKEY_PICTURE_TYPE, "value")
+ .limitTo(D::ENCODER & D::VIDEO & D::READ));
+
/* still to do
constexpr char KEY_PUSH_BLANK_BUFFERS_ON_STOP[] = "push-blank-buffers-on-shutdown";
diff --git a/media/codec2/sfplugin/CCodecConfig.h b/media/codec2/sfplugin/CCodecConfig.h
index 417b773..88e6239 100644
--- a/media/codec2/sfplugin/CCodecConfig.h
+++ b/media/codec2/sfplugin/CCodecConfig.h
@@ -363,11 +363,6 @@
const std::vector<std::string> &names,
c2_blocking_t blocking = C2_DONT_BLOCK);
-private:
-
- /// initializes the standard MediaCodec to Codec 2.0 params mapping
- void initializeStandardParams();
-
/// Adds indices to the subscribed indices, and updated subscription to component
/// \param blocking blocking mode to use with the component
status_t subscribeToConfigUpdate(
@@ -375,6 +370,11 @@
const std::vector<C2Param::Index> &indices,
c2_blocking_t blocking = C2_DONT_BLOCK);
+private:
+
+ /// initializes the standard MediaCodec to Codec 2.0 params mapping
+ void initializeStandardParams();
+
/// Gets SDK format from codec 2.0 reflected configuration
/// \param domain input/output bitmask
sp<AMessage> getFormatForDomain(
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 4070478..2d3c70a 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -18,9 +18,14 @@
#define LOG_TAG "Codec2Buffer"
#include <utils/Log.h>
+#include <aidl/android/hardware/graphics/common/Cta861_3.h>
+#include <aidl/android/hardware/graphics/common/Smpte2086.h>
#include <android-base/properties.h>
#include <android/hardware/cas/native/1.0/types.h>
#include <android/hardware/drm/1.0/types.h>
+#include <android/hardware/graphics/common/1.2/types.h>
+#include <android/hardware/graphics/mapper/4.0/IMapper.h>
+#include <gralloctypes/Gralloc4.h>
#include <hidlmemory/FrameworkUtils.h>
#include <media/hardware/HardwareAPI.h>
#include <media/stagefright/CodecBase.h>
@@ -358,21 +363,22 @@
break;
case COLOR_FormatYUVP010:
+ // stride is in bytes
mediaImage->mPlane[mediaImage->Y].mOffset = 0;
mediaImage->mPlane[mediaImage->Y].mColInc = 2;
- mediaImage->mPlane[mediaImage->Y].mRowInc = stride * 2;
+ mediaImage->mPlane[mediaImage->Y].mRowInc = stride;
mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
- mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride * 2;
+ mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride;
mediaImage->mPlane[mediaImage->U].mColInc = 4;
- mediaImage->mPlane[mediaImage->U].mRowInc = stride * 2;
+ mediaImage->mPlane[mediaImage->U].mRowInc = stride;
mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
- mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride * 2 + 2;
+ mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride + 2;
mediaImage->mPlane[mediaImage->V].mColInc = 4;
- mediaImage->mPlane[mediaImage->V].mRowInc = stride * 2;
+ mediaImage->mPlane[mediaImage->V].mRowInc = stride;
mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
if (tryWrapping) {
@@ -533,8 +539,8 @@
mInitCheck = BAD_VALUE;
return;
}
- bufferSize += stride * vStride
- / plane.rowSampling / plane.colSampling * divUp(mAllocatedDepth, 8u);
+ // stride is in bytes
+ bufferSize += stride * vStride / plane.rowSampling / plane.colSampling;
}
mBackBufferSize = bufferSize;
@@ -787,8 +793,14 @@
ALOGD("format had no width / height");
return nullptr;
}
- // NOTE: we currently only support YUV420 formats for byte-buffer mode.
- sp<ABuffer> aBuffer(alloc(align(width, 16) * align(height, 16) * 3 / 2));
+ int32_t colorFormat = COLOR_FormatYUV420Flexible;
+ int32_t bpp = 12; // 8(Y) + 2(U) + 2(V)
+ if (format->findInt32(KEY_COLOR_FORMAT, &colorFormat)) {
+ if (colorFormat == COLOR_FormatYUVP010) {
+ bpp = 24; // 16(Y) + 4(U) + 4(V)
+ }
+ }
+ sp<ABuffer> aBuffer(alloc(align(width, 16) * align(height, 16) * bpp / 8));
return new ConstGraphicBlockBuffer(
format,
aBuffer,
@@ -941,4 +953,218 @@
return const_cast<native_handle_t *>(mBlock->handle());
}
+using ::aidl::android::hardware::graphics::common::Cta861_3;
+using ::aidl::android::hardware::graphics::common::Smpte2086;
+
+using ::android::gralloc4::MetadataType_Cta861_3;
+using ::android::gralloc4::MetadataType_Smpte2086;
+using ::android::gralloc4::MetadataType_Smpte2094_40;
+
+using ::android::hardware::Return;
+using ::android::hardware::hidl_vec;
+
+using Error4 = ::android::hardware::graphics::mapper::V4_0::Error;
+using IMapper4 = ::android::hardware::graphics::mapper::V4_0::IMapper;
+
+namespace {
+
+sp<IMapper4> GetMapper4() {
+ static sp<IMapper4> sMapper = IMapper4::getService();
+ return sMapper;
+}
+
+class NativeHandleDeleter {
+public:
+ explicit NativeHandleDeleter(native_handle_t *handle) : mHandle(handle) {}
+ ~NativeHandleDeleter() {
+ if (mHandle) {
+ native_handle_delete(mHandle);
+ }
+ }
+private:
+ native_handle_t *mHandle;
+};
+
+} // namspace
+
+c2_status_t GetHdrMetadataFromGralloc4Handle(
+ const C2Handle *const handle,
+ std::shared_ptr<C2StreamHdrStaticMetadataInfo::input> *staticInfo,
+ std::shared_ptr<C2StreamHdrDynamicMetadataInfo::input> *dynamicInfo) {
+ c2_status_t err = C2_OK;
+ native_handle_t *nativeHandle = UnwrapNativeCodec2GrallocHandle(handle);
+ if (nativeHandle == nullptr) {
+ // Nothing to do
+ return err;
+ }
+ // TRICKY: UnwrapNativeCodec2GrallocHandle creates a new handle but
+ // does not clone the fds. Thus we need to delete the handle
+ // without closing it when going out of scope.
+ // NativeHandle cannot solve this problem, as it would close and
+ // delete the handle, while we need delete only.
+ NativeHandleDeleter nhd(nativeHandle);
+ sp<IMapper4> mapper = GetMapper4();
+ if (!mapper) {
+ // Gralloc4 not supported; nothing to do
+ return err;
+ }
+ Error4 mapperErr = Error4::NONE;
+ if (staticInfo) {
+ staticInfo->reset(new C2StreamHdrStaticMetadataInfo::input(0u));
+ memset(&(*staticInfo)->mastering, 0, sizeof((*staticInfo)->mastering));
+ (*staticInfo)->maxCll = 0;
+ (*staticInfo)->maxFall = 0;
+ IMapper4::get_cb cb = [&mapperErr, staticInfo](Error4 err, const hidl_vec<uint8_t> &vec) {
+ mapperErr = err;
+ if (err != Error4::NONE) {
+ return;
+ }
+
+ std::optional<Smpte2086> smpte2086;
+ gralloc4::decodeSmpte2086(vec, &smpte2086);
+ if (smpte2086) {
+ (*staticInfo)->mastering.red.x = smpte2086->primaryRed.x;
+ (*staticInfo)->mastering.red.y = smpte2086->primaryRed.y;
+ (*staticInfo)->mastering.green.x = smpte2086->primaryGreen.x;
+ (*staticInfo)->mastering.green.y = smpte2086->primaryGreen.y;
+ (*staticInfo)->mastering.blue.x = smpte2086->primaryBlue.x;
+ (*staticInfo)->mastering.blue.y = smpte2086->primaryBlue.y;
+ (*staticInfo)->mastering.white.x = smpte2086->whitePoint.x;
+ (*staticInfo)->mastering.white.y = smpte2086->whitePoint.y;
+
+ (*staticInfo)->mastering.maxLuminance = smpte2086->maxLuminance;
+ (*staticInfo)->mastering.minLuminance = smpte2086->minLuminance;
+ } else {
+ mapperErr = Error4::BAD_VALUE;
+ }
+ };
+ Return<void> ret = mapper->get(nativeHandle, MetadataType_Smpte2086, cb);
+ if (!ret.isOk()) {
+ err = C2_REFUSED;
+ } else if (mapperErr != Error4::NONE) {
+ err = C2_CORRUPTED;
+ }
+ cb = [&mapperErr, staticInfo](Error4 err, const hidl_vec<uint8_t> &vec) {
+ mapperErr = err;
+ if (err != Error4::NONE) {
+ return;
+ }
+
+ std::optional<Cta861_3> cta861_3;
+ gralloc4::decodeCta861_3(vec, &cta861_3);
+ if (cta861_3) {
+ (*staticInfo)->maxCll = cta861_3->maxContentLightLevel;
+ (*staticInfo)->maxFall = cta861_3->maxFrameAverageLightLevel;
+ } else {
+ mapperErr = Error4::BAD_VALUE;
+ }
+ };
+ ret = mapper->get(nativeHandle, MetadataType_Cta861_3, cb);
+ if (!ret.isOk()) {
+ err = C2_REFUSED;
+ } else if (mapperErr != Error4::NONE) {
+ err = C2_CORRUPTED;
+ }
+ }
+ if (dynamicInfo) {
+ dynamicInfo->reset();
+ IMapper4::get_cb cb = [&mapperErr, dynamicInfo](Error4 err, const hidl_vec<uint8_t> &vec) {
+ mapperErr = err;
+ if (err != Error4::NONE) {
+ return;
+ }
+ if (!dynamicInfo) {
+ return;
+ }
+ *dynamicInfo = C2StreamHdrDynamicMetadataInfo::input::AllocShared(
+ vec.size(), 0u, C2Config::HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40);
+ memcpy((*dynamicInfo)->m.data, vec.data(), vec.size());
+ };
+ Return<void> ret = mapper->get(nativeHandle, MetadataType_Smpte2094_40, cb);
+ if (!ret.isOk() || mapperErr != Error4::NONE) {
+ dynamicInfo->reset();
+ }
+ }
+
+ return err;
+}
+
+c2_status_t SetHdrMetadataToGralloc4Handle(
+ const std::shared_ptr<const C2StreamHdrStaticMetadataInfo::output> &staticInfo,
+ const std::shared_ptr<const C2StreamHdrDynamicMetadataInfo::output> &dynamicInfo,
+ const C2Handle *const handle) {
+ c2_status_t err = C2_OK;
+ native_handle_t *nativeHandle = UnwrapNativeCodec2GrallocHandle(handle);
+ if (nativeHandle == nullptr) {
+ // Nothing to do
+ return err;
+ }
+ // TRICKY: UnwrapNativeCodec2GrallocHandle creates a new handle but
+ // does not clone the fds. Thus we need to delete the handle
+ // without closing it when going out of scope.
+ NativeHandleDeleter nhd(nativeHandle);
+ sp<IMapper4> mapper = GetMapper4();
+ if (!mapper) {
+ // Gralloc4 not supported; nothing to do
+ return err;
+ }
+ if (staticInfo && *staticInfo) {
+ std::optional<Smpte2086> smpte2086 = Smpte2086{
+ {staticInfo->mastering.red.x, staticInfo->mastering.red.y},
+ {staticInfo->mastering.green.x, staticInfo->mastering.green.y},
+ {staticInfo->mastering.blue.x, staticInfo->mastering.blue.y},
+ {staticInfo->mastering.white.x, staticInfo->mastering.white.y},
+ staticInfo->mastering.maxLuminance,
+ staticInfo->mastering.minLuminance,
+ };
+ hidl_vec<uint8_t> vec;
+ if (gralloc4::encodeSmpte2086(smpte2086, &vec) == OK) {
+ Return<Error4> ret = mapper->set(nativeHandle, MetadataType_Smpte2086, vec);
+ if (!ret.isOk()) {
+ err = C2_REFUSED;
+ } else if (ret != Error4::NONE) {
+ err = C2_CORRUPTED;
+ }
+ }
+ std::optional<Cta861_3> cta861_3 = Cta861_3{
+ staticInfo->maxCll,
+ staticInfo->maxFall,
+ };
+ if (gralloc4::encodeCta861_3(cta861_3, &vec) == OK) {
+ Return<Error4> ret = mapper->set(nativeHandle, MetadataType_Cta861_3, vec);
+ if (!ret.isOk()) {
+ err = C2_REFUSED;
+ } else if (ret != Error4::NONE) {
+ err = C2_CORRUPTED;
+ }
+ }
+ }
+ if (dynamicInfo && *dynamicInfo) {
+ hidl_vec<uint8_t> vec;
+ vec.resize(dynamicInfo->flexCount());
+ memcpy(vec.data(), dynamicInfo->m.data, dynamicInfo->flexCount());
+ std::optional<IMapper4::MetadataType> metadataType;
+ switch (dynamicInfo->m.type_) {
+ case C2Config::HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_10:
+ // TODO
+ break;
+ case C2Config::HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40:
+ metadataType = MetadataType_Smpte2094_40;
+ break;
+ }
+ if (metadataType) {
+ Return<Error4> ret = mapper->set(nativeHandle, *metadataType, vec);
+ if (!ret.isOk()) {
+ err = C2_REFUSED;
+ } else if (ret != Error4::NONE) {
+ err = C2_CORRUPTED;
+ }
+ } else {
+ err = C2_BAD_VALUE;
+ }
+ }
+
+ return err;
+}
+
} // namespace android
diff --git a/media/codec2/sfplugin/Codec2Buffer.h b/media/codec2/sfplugin/Codec2Buffer.h
index dc788cd..b02b042 100644
--- a/media/codec2/sfplugin/Codec2Buffer.h
+++ b/media/codec2/sfplugin/Codec2Buffer.h
@@ -19,6 +19,7 @@
#define CODEC2_BUFFER_H_
#include <C2Buffer.h>
+#include <C2Config.h>
#include <binder/IMemory.h>
#include <media/hardware/VideoAPI.h>
@@ -391,6 +392,36 @@
int32_t mHeapSeqNum;
};
+/**
+ * Get HDR metadata from Gralloc4 handle.
+ *
+ * \param[in] handle handle of the allocation
+ * \param[out] staticInfo HDR static info to be filled. Ignored if null;
+ * if |handle| is invalid or does not contain the metadata,
+ * the shared_ptr is reset.
+ * \param[out] dynamicInfo HDR dynamic info to be filled. Ignored if null;
+ * if |handle| is invalid or does not contain the metadata,
+ * the shared_ptr is reset.
+ * \return C2_OK if successful
+ */
+c2_status_t GetHdrMetadataFromGralloc4Handle(
+ const C2Handle *const handle,
+ std::shared_ptr<C2StreamHdrStaticMetadataInfo::input> *staticInfo,
+ std::shared_ptr<C2StreamHdrDynamicMetadataInfo::input> *dynamicInfo);
+
+/**
+ * Set HDR metadata to Gralloc4 handle.
+ *
+ * \param[in] staticInfo HDR static info to set. Ignored if null or invalid.
+ * \param[in] dynamicInfo HDR dynamic info to set. Ignored if null or invalid.
+ * \param[out] handle handle of the allocation.
+ * \return C2_OK if successful
+ */
+c2_status_t SetHdrMetadataToGralloc4Handle(
+ const std::shared_ptr<const C2StreamHdrStaticMetadataInfo::output> &staticInfo,
+ const std::shared_ptr<const C2StreamHdrDynamicMetadataInfo::output> &dynamicInfo,
+ const C2Handle *const handle);
+
} // namespace android
#endif // CODEC2_BUFFER_H_
diff --git a/media/codec2/sfplugin/Codec2InfoBuilder.cpp b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
index 67d7ed2..63bd64b 100644
--- a/media/codec2/sfplugin/Codec2InfoBuilder.cpp
+++ b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
@@ -54,6 +54,9 @@
using Traits = C2Component::Traits;
+// HAL pixel format -> framework color format
+typedef std::map<uint32_t, int32_t> PixelFormatMap;
+
namespace /* unnamed */ {
bool hasPrefix(const std::string& s, const char* prefix) {
@@ -67,6 +70,26 @@
s.compare(s.size() - suffixLen, suffixLen, suffix) == 0;
}
+std::optional<int32_t> findFrameworkColorFormat(
+ const C2FlexiblePixelFormatDescriptorStruct &desc) {
+ switch (desc.bitDepth) {
+ case 8u:
+ if (desc.layout == C2Color::PLANAR_PACKED
+ || desc.layout == C2Color::SEMIPLANAR_PACKED) {
+ return COLOR_FormatYUV420Flexible;
+ }
+ break;
+ case 10u:
+ if (desc.layout == C2Color::SEMIPLANAR_PACKED) {
+ return COLOR_FormatYUVP010;
+ }
+ break;
+ default:
+ break;
+ }
+ return std::nullopt;
+}
+
// returns true if component advertised supported profile level(s)
bool addSupportedProfileLevels(
std::shared_ptr<Codec2Client::Interface> intf,
@@ -211,27 +234,69 @@
void addSupportedColorFormats(
std::shared_ptr<Codec2Client::Interface> intf,
MediaCodecInfo::CapabilitiesWriter *caps,
- const Traits& trait, const std::string &mediaType) {
- (void)intf;
-
+ const Traits& trait, const std::string &mediaType,
+ const PixelFormatMap &pixelFormatMap) {
// TODO: get this from intf() as well, but how do we map them to
// MediaCodec color formats?
bool encoder = trait.kind == C2Component::KIND_ENCODER;
if (mediaType.find("video") != std::string::npos
|| mediaType.find("image") != std::string::npos) {
+
+ std::vector<C2FieldSupportedValuesQuery> query;
+ if (encoder) {
+ C2StreamPixelFormatInfo::input pixelFormat;
+ query.push_back(C2FieldSupportedValuesQuery::Possible(
+ C2ParamField::Make(pixelFormat, pixelFormat.value)));
+ } else {
+ C2StreamPixelFormatInfo::output pixelFormat;
+ query.push_back(C2FieldSupportedValuesQuery::Possible(
+ C2ParamField::Make(pixelFormat, pixelFormat.value)));
+ }
+ std::list<int32_t> supportedColorFormats;
+ if (intf->querySupportedValues(query, C2_DONT_BLOCK) == C2_OK) {
+ if (query[0].status == C2_OK) {
+ const C2FieldSupportedValues &fsv = query[0].values;
+ if (fsv.type == C2FieldSupportedValues::VALUES) {
+ for (C2Value::Primitive value : fsv.values) {
+ auto it = pixelFormatMap.find(value.u32);
+ if (it != pixelFormatMap.end()) {
+ auto it2 = std::find(
+ supportedColorFormats.begin(),
+ supportedColorFormats.end(),
+ it->second);
+ if (it2 == supportedColorFormats.end()) {
+ supportedColorFormats.push_back(it->second);
+ }
+ }
+ }
+ }
+ }
+ }
+ auto addDefaultColorFormat = [caps, &supportedColorFormats](int32_t colorFormat) {
+ caps->addColorFormat(colorFormat);
+ auto it = std::find(
+ supportedColorFormats.begin(), supportedColorFormats.end(), colorFormat);
+ if (it != supportedColorFormats.end()) {
+ supportedColorFormats.erase(it);
+ }
+ };
+
// vendor video codecs prefer opaque format
if (trait.name.find("android") == std::string::npos) {
- caps->addColorFormat(COLOR_FormatSurface);
+ addDefaultColorFormat(COLOR_FormatSurface);
}
- caps->addColorFormat(COLOR_FormatYUV420Flexible);
- caps->addColorFormat(COLOR_FormatYUV420Planar);
- caps->addColorFormat(COLOR_FormatYUV420SemiPlanar);
- caps->addColorFormat(COLOR_FormatYUV420PackedPlanar);
- caps->addColorFormat(COLOR_FormatYUV420PackedSemiPlanar);
+ addDefaultColorFormat(COLOR_FormatYUV420Flexible);
+ addDefaultColorFormat(COLOR_FormatYUV420Planar);
+ addDefaultColorFormat(COLOR_FormatYUV420SemiPlanar);
+ addDefaultColorFormat(COLOR_FormatYUV420PackedPlanar);
+ addDefaultColorFormat(COLOR_FormatYUV420PackedSemiPlanar);
// framework video encoders must support surface format, though it is unclear
// that they will be able to map it if it is opaque
if (encoder && trait.name.find("android") != std::string::npos) {
- caps->addColorFormat(COLOR_FormatSurface);
+ addDefaultColorFormat(COLOR_FormatSurface);
+ }
+ for (int32_t colorFormat : supportedColorFormats) {
+ caps->addColorFormat(colorFormat);
}
}
}
@@ -423,6 +488,7 @@
}
}
+ std::map<std::string, PixelFormatMap> nameToPixelFormatMap;
for (const Traits& trait : traits) {
C2Component::rank_t rank = trait.rank;
@@ -436,8 +502,9 @@
nameAndAliases.insert(nameAndAliases.begin(), trait.name);
for (const std::string &nameOrAlias : nameAndAliases) {
bool isAlias = trait.name != nameOrAlias;
+ std::shared_ptr<Codec2Client> client;
std::shared_ptr<Codec2Client::Interface> intf =
- Codec2Client::CreateInterfaceByName(nameOrAlias.c_str());
+ Codec2Client::CreateInterfaceByName(nameOrAlias.c_str(), &client);
if (!intf) {
ALOGD("could not create interface for %s'%s'",
isAlias ? "alias " : "",
@@ -631,7 +698,40 @@
caps->addProfileLevel(VP8ProfileMain, VP8Level_Version0);
}
}
- addSupportedColorFormats(intf, caps.get(), trait, mediaType);
+
+ auto it = nameToPixelFormatMap.find(client->getServiceName());
+ if (it == nameToPixelFormatMap.end()) {
+ it = nameToPixelFormatMap.try_emplace(client->getServiceName()).first;
+ PixelFormatMap &pixelFormatMap = it->second;
+ pixelFormatMap[HAL_PIXEL_FORMAT_YCBCR_420_888] = COLOR_FormatYUV420Flexible;
+ pixelFormatMap[HAL_PIXEL_FORMAT_YCBCR_P010] = COLOR_FormatYUVP010;
+ pixelFormatMap[HAL_PIXEL_FORMAT_RGBA_1010102] = COLOR_Format32bitABGR2101010;
+ pixelFormatMap[HAL_PIXEL_FORMAT_RGBA_FP16] = COLOR_Format64bitABGRFloat;
+
+ std::shared_ptr<C2StoreFlexiblePixelFormatDescriptorsInfo> pixelFormatInfo;
+ std::vector<std::unique_ptr<C2Param>> heapParams;
+ if (client->query(
+ {},
+ {C2StoreFlexiblePixelFormatDescriptorsInfo::PARAM_TYPE},
+ C2_MAY_BLOCK,
+ &heapParams) == C2_OK
+ && heapParams.size() == 1u) {
+ pixelFormatInfo.reset(C2StoreFlexiblePixelFormatDescriptorsInfo::From(
+ heapParams[0].release()));
+ }
+ if (pixelFormatInfo && *pixelFormatInfo) {
+ for (size_t i = 0; i < pixelFormatInfo->flexCount(); ++i) {
+ C2FlexiblePixelFormatDescriptorStruct &desc =
+ pixelFormatInfo->m.values[i];
+ std::optional<int32_t> colorFormat = findFrameworkColorFormat(desc);
+ if (colorFormat) {
+ pixelFormatMap[desc.pixelFormat] = *colorFormat;
+ }
+ }
+ }
+ }
+ addSupportedColorFormats(
+ intf, caps.get(), trait, mediaType, it->second);
}
}
}
diff --git a/media/codec2/sfplugin/utils/Android.bp b/media/codec2/sfplugin/utils/Android.bp
index 2f4d6b1..674921e 100644
--- a/media/codec2/sfplugin/utils/Android.bp
+++ b/media/codec2/sfplugin/utils/Android.bp
@@ -11,6 +11,8 @@
name: "libsfplugin_ccodec_utils",
vendor_available: true,
min_sdk_version: "29",
+ apex_available: [ "//apex_available:platform", "com.android.media.swcodec", ],
+
double_loadable: true,
srcs: [
diff --git a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
index 2213001..bff9db5 100644
--- a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
+++ b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
@@ -88,7 +88,7 @@
uint32_t planeW = img->mWidth / plane.colSampling;
uint32_t planeH = img->mHeight / plane.rowSampling;
- bool canCopyByRow = (plane.colInc == 1) && (img->mPlane[i].mColInc == 1);
+ bool canCopyByRow = (plane.colInc == bpp) && (img->mPlane[i].mColInc == bpp);
bool canCopyByPlane = canCopyByRow && (plane.rowInc == img->mPlane[i].mRowInc);
if (canCopyByPlane) {
MemCopier<ToMediaImage, 0>::copy(imgRow, viewRow, plane.rowInc * planeH);
@@ -118,22 +118,6 @@
} // namespace
-bool IsFormatR10G10B10A2SupportedForLegacyRendering() {
- const AHardwareBuffer_Desc desc = {
- .width = 320,
- .height = 240,
- .format = AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM,
- .layers = 1,
- .usage = AHARDWAREBUFFER_USAGE_CPU_READ_RARELY | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN |
- AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE,
- .stride = 0,
- .rfu0 = 0,
- .rfu1 = 0,
- };
-
- return AHardwareBuffer_isSupported(&desc);
-}
-
status_t ImageCopy(uint8_t *imgBase, const MediaImage2 *img, const C2GraphicView &view) {
if (view.crop().width != img->mWidth || view.crop().height != img->mHeight) {
return BAD_VALUE;
diff --git a/media/codec2/sfplugin/utils/Codec2BufferUtils.h b/media/codec2/sfplugin/utils/Codec2BufferUtils.h
index c4651a4..9fa642d 100644
--- a/media/codec2/sfplugin/utils/Codec2BufferUtils.h
+++ b/media/codec2/sfplugin/utils/Codec2BufferUtils.h
@@ -27,11 +27,6 @@
namespace android {
/**
- * Check if R10G10B10A2 is supported in legacy rendering path that involves GPU
- */
-bool IsFormatR10G10B10A2SupportedForLegacyRendering();
-
-/**
* Converts an RGB view to planar YUV 420 media image.
*
* \param dstY pointer to media image buffer
diff --git a/media/codec2/sfplugin/utils/Codec2Mapper.cpp b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
index f557830..93f29ca 100644
--- a/media/codec2/sfplugin/utils/Codec2Mapper.cpp
+++ b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
@@ -18,6 +18,9 @@
#define LOG_TAG "Codec2Mapper"
#include <utils/Log.h>
+#include <map>
+#include <optional>
+
#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/SurfaceUtils.h>
#include <media/stagefright/foundation/ALookup.h>
@@ -167,6 +170,9 @@
{ C2Config::LEVEL_DV_MAIN_UHD_30, DolbyVisionLevelUhd30 },
{ C2Config::LEVEL_DV_MAIN_UHD_48, DolbyVisionLevelUhd48 },
{ C2Config::LEVEL_DV_MAIN_UHD_60, DolbyVisionLevelUhd60 },
+ { C2Config::LEVEL_DV_MAIN_UHD_120, DolbyVisionLevelUhd120 },
+ { C2Config::LEVEL_DV_MAIN_8K_30, DolbyVisionLevel8k30 },
+ { C2Config::LEVEL_DV_MAIN_8K_60, DolbyVisionLevel8k60 },
// high tiers are not yet supported on android, for now map them to main tier
{ C2Config::LEVEL_DV_HIGH_HD_24, DolbyVisionLevelHd24 },
@@ -178,6 +184,9 @@
{ C2Config::LEVEL_DV_HIGH_UHD_30, DolbyVisionLevelUhd30 },
{ C2Config::LEVEL_DV_HIGH_UHD_48, DolbyVisionLevelUhd48 },
{ C2Config::LEVEL_DV_HIGH_UHD_60, DolbyVisionLevelUhd60 },
+ { C2Config::LEVEL_DV_HIGH_UHD_120, DolbyVisionLevelUhd120 },
+ { C2Config::LEVEL_DV_HIGH_8K_30, DolbyVisionLevel8k30 },
+ { C2Config::LEVEL_DV_HIGH_8K_60, DolbyVisionLevel8k60 },
};
ALookup<C2Config::profile_t, int32_t> sDolbyVisionProfiles = {
@@ -402,6 +411,30 @@
{ C2Config::PROFILE_AV1_0, AV1ProfileMain10HDR10Plus },
};
+// HAL_PIXEL_FORMAT_* -> COLOR_Format*
+ALookup<uint32_t, int32_t> sPixelFormats = {
+ { HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, COLOR_FormatSurface },
+
+ // YCBCR_420_888 maps to YUV420Flexible and vice versa
+ { HAL_PIXEL_FORMAT_YCBCR_420_888, COLOR_FormatYUV420Flexible },
+
+ // Fallback matches for YCBCR_420_888
+ { HAL_PIXEL_FORMAT_YCBCR_420_888, COLOR_FormatYUV420Planar },
+ { HAL_PIXEL_FORMAT_YCBCR_420_888, COLOR_FormatYUV420SemiPlanar },
+ { HAL_PIXEL_FORMAT_YCBCR_420_888, COLOR_FormatYUV420PackedPlanar },
+ { HAL_PIXEL_FORMAT_YCBCR_420_888, COLOR_FormatYUV420PackedSemiPlanar },
+
+ // Fallback matches for YUV420Flexible
+ { HAL_PIXEL_FORMAT_YCRCB_420_SP, COLOR_FormatYUV420Flexible },
+ { HAL_PIXEL_FORMAT_YV12, COLOR_FormatYUV420Flexible },
+
+ { HAL_PIXEL_FORMAT_YCBCR_422_SP, COLOR_FormatYUV422PackedSemiPlanar },
+ { HAL_PIXEL_FORMAT_YCBCR_422_I, COLOR_FormatYUV422PackedPlanar },
+ { HAL_PIXEL_FORMAT_YCBCR_P010, COLOR_FormatYUVP010 },
+ { HAL_PIXEL_FORMAT_RGBA_1010102, COLOR_Format32bitABGR2101010 },
+ { HAL_PIXEL_FORMAT_RGBA_FP16, COLOR_Format64bitABGRFloat },
+};
+
/**
* A helper that passes through vendor extension profile and level values.
*/
@@ -975,41 +1008,19 @@
// static
bool C2Mapper::mapPixelFormatFrameworkToCodec(
int32_t frameworkValue, uint32_t *c2Value) {
- switch (frameworkValue) {
- case COLOR_FormatSurface:
- *c2Value = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
- return true;
- case COLOR_FormatYUV420Flexible:
- case COLOR_FormatYUV420Planar:
- case COLOR_FormatYUV420SemiPlanar:
- case COLOR_FormatYUV420PackedPlanar:
- case COLOR_FormatYUV420PackedSemiPlanar:
- *c2Value = HAL_PIXEL_FORMAT_YCBCR_420_888;
- return true;
- default:
- // Passthrough
- *c2Value = uint32_t(frameworkValue);
- return true;
+ if (!sPixelFormats.map(frameworkValue, c2Value)) {
+ // passthrough if not mapped
+ *c2Value = uint32_t(frameworkValue);
}
+ return true;
}
// static
bool C2Mapper::mapPixelFormatCodecToFramework(
uint32_t c2Value, int32_t *frameworkValue) {
- switch (c2Value) {
- case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
- *frameworkValue = COLOR_FormatSurface;
- return true;
- case HAL_PIXEL_FORMAT_YCBCR_422_SP:
- case HAL_PIXEL_FORMAT_YCRCB_420_SP:
- case HAL_PIXEL_FORMAT_YCBCR_422_I:
- case HAL_PIXEL_FORMAT_YCBCR_420_888:
- case HAL_PIXEL_FORMAT_YV12:
- *frameworkValue = COLOR_FormatYUV420Flexible;
- return true;
- default:
- // Passthrough
- *frameworkValue = int32_t(c2Value);
- return true;
+ if (!sPixelFormats.map(c2Value, frameworkValue)) {
+ // passthrough if not mapped
+ *frameworkValue = int32_t(c2Value);
}
+ return true;
}
diff --git a/media/codec2/tests/Android.bp b/media/codec2/tests/Android.bp
index b858fa5..9c3ba4d 100644
--- a/media/codec2/tests/Android.bp
+++ b/media/codec2/tests/Android.bp
@@ -15,12 +15,9 @@
"C2Param_test.cpp",
],
- include_dirs: [
- "frameworks/av/media/codec2/vndk/include",
- ],
-
header_libs: [
"libcodec2_headers",
+ "libcodec2_vndk_headers",
],
// param tests must not depend on any codec2 libraries as all params should be templated
@@ -47,9 +44,6 @@
"vndk/C2BufferTest.cpp",
],
- include_dirs: [
- ],
-
shared_libs: [
"libcodec2",
"libcodec2_vndk",
diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp
index be81c84..598500d 100644
--- a/media/codec2/vndk/Android.bp
+++ b/media/codec2/vndk/Android.bp
@@ -18,6 +18,25 @@
vendor_available: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
+
+}
+
+cc_library_headers {
+ name: "libcodec2_vndk_headers",
+ vendor_available: true,
+ min_sdk_version: "29",
+
+ export_include_dirs: [
+ "include",
+ ],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
}
// !!!DO NOT DEPEND ON THIS SHARED LIBRARY DIRECTLY!!!
@@ -28,6 +47,11 @@
min_sdk_version: "29",
// TODO: b/147147883
double_loadable: true,
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
+
srcs: [
"C2AllocatorBlob.cpp",
@@ -73,11 +97,12 @@
"libbase",
"libcutils",
"libdl",
+ "libdmabufheap",
+ "libfmq",
+ "libgralloctypes",
"libhardware",
"libhidlbase",
"libion",
- "libdmabufheap",
- "libfmq",
"liblog",
"libnativewindow",
"libstagefright_foundation",
@@ -92,6 +117,44 @@
],
}
+// public dependency for statically linking to libcodec2_vndk for unit tests
+cc_defaults {
+ name: "libcodec2-static-defaults",
+
+ static_libs: [
+ "liblog",
+ "libion",
+ "libfmq",
+ "libbase",
+ "libutils",
+ "libcutils",
+ "libcodec2",
+ "libhidlbase",
+ "libdmabufheap",
+ "libcodec2_vndk",
+ "libnativewindow",
+ "libcodec2_soft_common",
+ "libsfplugin_ccodec_utils",
+ "libstagefright_foundation",
+ "libstagefright_bufferpool@2.0.1",
+ "libgralloctypes",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.media.bufferpool@2.0",
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.allocator@3.0",
+ "android.hardware.graphics.bufferqueue@2.0",
+ ],
+
+ shared_libs: [
+ "libui",
+ "libdl",
+ "libhardware",
+ "libvndksupport",
+ "libprocessgroup",
+ ],
+}
+
// public dependency for implementing Codec 2 components
cc_defaults {
name: "libcodec2-impl-defaults",
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index 6a7f19c..b5200a5 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -20,8 +20,10 @@
#include <mutex>
+#include <aidl/android/hardware/graphics/common/PlaneLayoutComponentType.h>
#include <android/hardware/graphics/common/1.2/types.h>
#include <cutils/native_handle.h>
+#include <gralloctypes/Gralloc4.h>
#include <hardware/gralloc.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/GraphicBufferMapper.h>
@@ -29,6 +31,7 @@
#include <C2AllocatorGralloc.h>
#include <C2Buffer.h>
+#include <C2Debug.h>
#include <C2PlatformSupport.h>
using ::android::hardware::hidl_handle;
@@ -230,8 +233,89 @@
}
};
+static
+c2_status_t Gralloc4Mapper_lock(native_handle_t *handle, uint64_t usage, const Rect& bounds,
+ C2PlanarLayout *layout, uint8_t **addr) {
+ GraphicBufferMapper &mapper = GraphicBufferMapper::get();
+
+ std::vector<ui::PlaneLayout> planes;
+ // this method is only supported on Gralloc 4 or later
+ status_t err = mapper.getPlaneLayouts(handle, &planes);
+ if (err != NO_ERROR || planes.empty()) {
+ return C2_CANNOT_DO;
+ }
+
+ uint8_t *pointer = nullptr;
+ err = mapper.lock(handle, usage, bounds, (void **)&pointer, nullptr, nullptr);
+ if (err != NO_ERROR || pointer == nullptr) {
+ return C2_CORRUPTED;
+ }
+
+ using aidl::android::hardware::graphics::common::PlaneLayoutComponentType;
+ using aidl::android::hardware::graphics::common::PlaneLayoutComponent;
+
+ layout->type = C2PlanarLayout::TYPE_YUV;
+ layout->numPlanes = 0;
+ layout->rootPlanes = 0;
+
+ for (const ui::PlaneLayout &plane : planes) {
+ layout->rootPlanes++;
+ uint32_t lastOffsetInBits = 0;
+ uint32_t rootIx = 0;
+
+ for (const PlaneLayoutComponent &component : plane.components) {
+ if (!gralloc4::isStandardPlaneLayoutComponentType(component.type)) {
+ return C2_CANNOT_DO;
+ }
+
+ uint32_t rightShiftBits = component.offsetInBits - lastOffsetInBits;
+ uint32_t allocatedDepthInBits = component.sizeInBits + rightShiftBits;
+ C2PlanarLayout::plane_index_t planeId;
+ C2PlaneInfo::channel_t channel;
+
+ switch (static_cast<PlaneLayoutComponentType>(component.type.value)) {
+ case PlaneLayoutComponentType::Y:
+ planeId = C2PlanarLayout::PLANE_Y;
+ channel = C2PlaneInfo::CHANNEL_Y;
+ break;
+ case PlaneLayoutComponentType::CB:
+ planeId = C2PlanarLayout::PLANE_U;
+ channel = C2PlaneInfo::CHANNEL_CB;
+ break;
+ case PlaneLayoutComponentType::CR:
+ planeId = C2PlanarLayout::PLANE_V;
+ channel = C2PlaneInfo::CHANNEL_CR;
+ break;
+ default:
+ return C2_CORRUPTED;
+ }
+
+ addr[planeId] = pointer + plane.offsetInBytes + (component.offsetInBits / 8);
+ layout->planes[planeId] = {
+ channel, // channel
+ static_cast<int32_t>(plane.sampleIncrementInBits / 8), // colInc
+ static_cast<int32_t>(plane.strideInBytes), // rowInc
+ static_cast<uint32_t>(plane.horizontalSubsampling), // mColSampling
+ static_cast<uint32_t>(plane.verticalSubsampling), // mRowSampling
+ allocatedDepthInBits, // allocatedDepth (bits)
+ static_cast<uint32_t>(component.sizeInBits), // bitDepth (bits)
+ rightShiftBits, // rightShift (bits)
+ C2PlaneInfo::NATIVE, // endianness
+ rootIx, // rootIx
+ static_cast<uint32_t>(component.offsetInBits / 8), // offset (bytes)
+ };
+
+ layout->numPlanes++;
+ lastOffsetInBits = component.offsetInBits + component.sizeInBits;
+ rootIx++;
+ }
+ }
+ return C2_OK;
+}
+
} // unnamed namespace
+
native_handle_t *UnwrapNativeCodec2GrallocHandle(const C2Handle *const handle) {
return C2HandleGralloc::UnwrapNativeHandle(handle);
}
@@ -385,6 +469,10 @@
mBuffer, mWidth, mHeight, mFormat, mGrallocUsage,
mStride, generation, igbp_id, igbp_slot);
}
+
+ // 'NATIVE' on Android means LITTLE_ENDIAN
+ constexpr C2PlaneInfo::endianness_t kEndianness = C2PlaneInfo::NATIVE;
+
switch (mFormat) {
case static_cast<uint32_t>(PixelFormat4::RGBA_1010102): {
// TRICKY: this is used for media as YUV444 in the case when it is queued directly to a
@@ -646,7 +734,7 @@
16, // allocatedDepth
10, // bitDepth
6, // rightShift
- C2PlaneInfo::LITTLE_END, // endianness
+ kEndianness, // endianness
C2PlanarLayout::PLANE_Y, // rootIx
0, // offset
};
@@ -659,7 +747,7 @@
16, // allocatedDepth
10, // bitDepth
6, // rightShift
- C2PlaneInfo::LITTLE_END, // endianness
+ kEndianness, // endianness
C2PlanarLayout::PLANE_U, // rootIx
0, // offset
};
@@ -672,7 +760,7 @@
16, // allocatedDepth
10, // bitDepth
6, // rightShift
- C2PlaneInfo::LITTLE_END, // endianness
+ kEndianness, // endianness
C2PlanarLayout::PLANE_U, // rootIx
2, // offset
};
@@ -680,9 +768,15 @@
}
default: {
- // We don't know what it is, but let's try to lock it.
+ // We don't know what it is, let's try to lock it with gralloc4
android_ycbcr ycbcrLayout;
+ c2_status_t status = Gralloc4Mapper_lock(
+ const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, layout, addr);
+ if (status == C2_OK) {
+ break;
+ }
+ // fallback to lockYCbCr
status_t err = GraphicBufferMapper::get().lockYCbCr(
const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, &ycbcrLayout);
if (err == OK && ycbcrLayout.y && ycbcrLayout.cb && ycbcrLayout.cr
diff --git a/media/codecs/amrnb/common/Android.bp b/media/codecs/amrnb/common/Android.bp
index bae65f3..0bc6ed2 100644
--- a/media/codecs/amrnb/common/Android.bp
+++ b/media/codecs/amrnb/common/Android.bp
@@ -22,6 +22,10 @@
vendor_available: true,
host_supported: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
srcs: [
"src/add.cpp",
diff --git a/media/codecs/amrnb/dec/Android.bp b/media/codecs/amrnb/dec/Android.bp
index 1083b82..70741d2 100644
--- a/media/codecs/amrnb/dec/Android.bp
+++ b/media/codecs/amrnb/dec/Android.bp
@@ -35,6 +35,10 @@
vendor_available: true,
host_supported: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
srcs: [
"src/a_refl.cpp",
diff --git a/media/codecs/amrnb/enc/Android.bp b/media/codecs/amrnb/enc/Android.bp
index 9e947e9..3c6566e 100644
--- a/media/codecs/amrnb/enc/Android.bp
+++ b/media/codecs/amrnb/enc/Android.bp
@@ -34,6 +34,10 @@
name: "libstagefright_amrnbenc",
vendor_available: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
srcs: [
"src/amrencode.cpp",
diff --git a/media/codecs/amrwb/dec/Android.bp b/media/codecs/amrwb/dec/Android.bp
index 228ea80..f16b0fe 100644
--- a/media/codecs/amrwb/dec/Android.bp
+++ b/media/codecs/amrwb/dec/Android.bp
@@ -35,6 +35,10 @@
vendor_available: true,
host_supported: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
srcs: [
"src/agc2_amr_wb.cpp",
diff --git a/media/codecs/amrwb/enc/Android.bp b/media/codecs/amrwb/enc/Android.bp
index d945531..8780136 100644
--- a/media/codecs/amrwb/enc/Android.bp
+++ b/media/codecs/amrwb/enc/Android.bp
@@ -21,6 +21,10 @@
name: "libstagefright_amrwbenc",
vendor_available: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
srcs: [
"src/autocorr.c",
diff --git a/media/codecs/mp3dec/Android.bp b/media/codecs/mp3dec/Android.bp
index 1ab0511..6659ea5 100644
--- a/media/codecs/mp3dec/Android.bp
+++ b/media/codecs/mp3dec/Android.bp
@@ -47,6 +47,10 @@
name: "libstagefright_mp3dec",
vendor_available: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
host_supported:true,
srcs: [
diff --git a/media/extractors/Android.bp b/media/extractors/Android.bp
index 66585da..f654ecd 100644
--- a/media/extractors/Android.bp
+++ b/media/extractors/Android.bp
@@ -28,13 +28,15 @@
"liblog",
],
- // extractors are supposed to work on Q(29)
+ // extractors are expected to run on Q(29)
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ ],
relative_install_path: "extractors",
- compile_multilib: "first",
-
cflags: [
"-Werror",
"-Wall",
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 8836c47..fb935b6 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -1127,10 +1127,10 @@
void *data;
size_t size;
- if (AMediaFormat_getBuffer(mLastTrack->meta, AMEDIAFORMAT_KEY_CSD_2,
+ if (AMediaFormat_getBuffer(mLastTrack->meta, AMEDIAFORMAT_KEY_CSD_0,
&data, &size)
- && size >= 5) {
- const uint8_t *ptr = (const uint8_t *)data;
+ && size >= 24) {
+ const uint8_t *ptr = (const uint8_t *)data + (size - 24);
const uint8_t profile = ptr[2] >> 1;
const uint8_t bl_compatibility_id = (ptr[4]) >> 4;
bool create_two_tracks = false;
@@ -1147,13 +1147,15 @@
track_b->timescale = mLastTrack->timescale;
track_b->sampleTable = mLastTrack->sampleTable;
- track_b->includes_expensive_metadata = mLastTrack->includes_expensive_metadata;
+ track_b->includes_expensive_metadata =
+ mLastTrack->includes_expensive_metadata;
track_b->skipTrack = mLastTrack->skipTrack;
track_b->elst_needs_processing = mLastTrack->elst_needs_processing;
track_b->elst_media_time = mLastTrack->elst_media_time;
track_b->elst_segment_duration = mLastTrack->elst_segment_duration;
track_b->elst_shift_start_ticks = mLastTrack->elst_shift_start_ticks;
- track_b->elst_initial_empty_edit_ticks = mLastTrack->elst_initial_empty_edit_ticks;
+ track_b->elst_initial_empty_edit_ticks =
+ mLastTrack->elst_initial_empty_edit_ticks;
track_b->subsample_encryption = mLastTrack->subsample_encryption;
track_b->mTx3gBuffer = mLastTrack->mTx3gBuffer;
@@ -1166,11 +1168,11 @@
mLastTrack->next = track_b;
track_b->next = NULL;
- // we want to remove the csd-2 key from the metadata, but
+ // we want to remove the csd-0 key from the metadata, but
// don't have an AMediaFormat_* function to do so. Settle
- // for replacing this csd-2 with an empty csd-2.
+ // for replacing this csd-0 with an empty csd-0.
uint8_t emptybuffer[8] = {};
- AMediaFormat_setBuffer(track_b->meta, AMEDIAFORMAT_KEY_CSD_2,
+ AMediaFormat_setBuffer(track_b->meta, AMEDIAFORMAT_KEY_CSD_0,
emptybuffer, 0);
if (4 == profile || 7 == profile || 8 == profile ) {
@@ -1182,6 +1184,8 @@
} else if (10 == profile) {
AMediaFormat_setString(track_b->meta,
AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_AV1);
+ AMediaFormat_setBuffer(track_b->meta, AMEDIAFORMAT_KEY_CSD_0,
+ data, size - 24);
} // Should never get to else part
mLastTrack = track_b;
@@ -2591,9 +2595,11 @@
*offset += chunk_size;
break;
}
- case FOURCC("dvcC"):
- case FOURCC("dvvC"): {
+ case FOURCC("dvcC"):
+ case FOURCC("dvvC"):
+ case FOURCC("dvwC"):
+ {
if (chunk_data_size != 24) {
return ERROR_MALFORMED;
}
@@ -2612,14 +2618,29 @@
if (mLastTrack == NULL)
return ERROR_MALFORMED;
- AMediaFormat_setBuffer(mLastTrack->meta, AMEDIAFORMAT_KEY_CSD_2,
- buffer.get(), chunk_data_size);
+ void *data = nullptr;
+ size_t size = 0;
+ if (AMediaFormat_getBuffer(mLastTrack->meta, AMEDIAFORMAT_KEY_CSD_0, &data, &size)) {
+ //if csd-0 is already present, then append dvcc
+ auto csd0_dvcc = heapbuffer<uint8_t>(size + chunk_data_size);
+
+ memcpy(csd0_dvcc.get(), data, size);
+ memcpy(csd0_dvcc.get() + size, buffer.get(), chunk_data_size);
+
+ AMediaFormat_setBuffer(mLastTrack->meta, AMEDIAFORMAT_KEY_CSD_0,
+ csd0_dvcc.get(), size + chunk_data_size);
+ } else {
+ //if not set csd-0 directly
+ AMediaFormat_setBuffer(mLastTrack->meta, AMEDIAFORMAT_KEY_CSD_0,
+ buffer.get(), chunk_data_size);
+ }
AMediaFormat_setString(mLastTrack->meta, AMEDIAFORMAT_KEY_MIME,
MEDIA_MIMETYPE_VIDEO_DOLBY_VISION);
*offset += chunk_size;
break;
}
+
case FOURCC("d263"):
{
*offset += chunk_size;
@@ -4458,7 +4479,6 @@
if (!AMediaFormat_getString(track->meta, AMEDIAFORMAT_KEY_MIME, &mime)) {
return NULL;
}
-
sp<ItemTable> itemTable;
if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
void *data;
@@ -4491,14 +4511,14 @@
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
void *data;
size_t size;
- if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_2, &data, &size)) {
+ if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_0, &data, &size)
+ || size < 24) {
return NULL;
}
- const uint8_t *ptr = (const uint8_t *)data;
-
+ const uint8_t *ptr = (const uint8_t *)data + (size - 24);
// dv_major.dv_minor Should be 1.0 or 2.1
- if (size != 24 || ((ptr[0] != 1 || ptr[1] != 0) && (ptr[0] != 2 || ptr[1] != 1))) {
+ if ((ptr[0] != 1 || ptr[1] != 0) && (ptr[0] != 2 || ptr[1] != 1)) {
return NULL;
}
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AV1)
@@ -4576,7 +4596,7 @@
return ERROR_MALFORMED;
}
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
- if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_2, &data, &size)) {
+ if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_0, &data, &size)) {
return ERROR_MALFORMED;
}
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AV1)) {
@@ -5152,11 +5172,11 @@
ALOGV("%s DolbyVision stream detected", __FUNCTION__);
void *data;
size_t size;
- CHECK(AMediaFormat_getBuffer(format, AMEDIAFORMAT_KEY_CSD_2, &data, &size));
+ CHECK(AMediaFormat_getBuffer(format, AMEDIAFORMAT_KEY_CSD_0, &data, &size));
- const uint8_t *ptr = (const uint8_t *)data;
+ const uint8_t *ptr = (const uint8_t *)data + (size - 24);
- CHECK(size == 24);
+ CHECK(size >= 24);
// dv_major.dv_minor Should be 1.0 or 2.1
CHECK(!((ptr[0] != 1 || ptr[1] != 0) && (ptr[0] != 2 || ptr[1] != 1)));
diff --git a/media/extractors/mpeg2/MPEG2PSExtractor.cpp b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
index d431b05..afd28ef 100644
--- a/media/extractors/mpeg2/MPEG2PSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
@@ -20,9 +20,6 @@
#include "MPEG2PSExtractor.h"
-#include <AnotherPacketSource.h>
-#include <ESQueue.h>
-
#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -33,6 +30,8 @@
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
+#include <mpeg2ts/AnotherPacketSource.h>
+#include <mpeg2ts/ESQueue.h>
#include <utils/String8.h>
#include <inttypes.h>
diff --git a/media/extractors/mpeg2/MPEG2TSExtractor.cpp b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
index 2e68809..9a3cd92 100644
--- a/media/extractors/mpeg2/MPEG2TSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
@@ -35,10 +35,9 @@
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
+#include <mpeg2ts/AnotherPacketSource.h>
#include <utils/String8.h>
-#include <AnotherPacketSource.h>
-
#include <hidl/HybridInterface.h>
#include <android/hardware/cas/1.0/ICas.h>
diff --git a/media/extractors/mpeg2/include/MPEG2TSExtractor.h b/media/extractors/mpeg2/include/MPEG2TSExtractor.h
index fd77b08..0e3e484 100644
--- a/media/extractors/mpeg2/include/MPEG2TSExtractor.h
+++ b/media/extractors/mpeg2/include/MPEG2TSExtractor.h
@@ -23,12 +23,11 @@
#include <media/MediaExtractorPluginApi.h>
#include <media/MediaExtractorPluginHelper.h>
#include <media/stagefright/MetaDataBase.h>
+#include <mpeg2ts/ATSParser.h>
#include <utils/threads.h>
#include <utils/KeyedVector.h>
#include <utils/Vector.h>
-#include <ATSParser.h>
-
namespace android {
struct AMessage;
diff --git a/media/libaaudio/examples/utils/AAudioSimplePlayer.h b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
index 7daac20..956b3cd 100644
--- a/media/libaaudio/examples/utils/AAudioSimplePlayer.h
+++ b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
@@ -40,6 +40,31 @@
int64_t nanoseconds;
} Timestamp;
+static constexpr int32_t kWorkloadScaler = 500;
+
+// Linear congruential random number generator.
+static uint32_t s_random16() {
+ static uint32_t seed = 1234;
+ seed = ((seed * 31421) + 6927) & 0x0FFFF;
+ return seed;
+}
+
+/**
+ * The random number generator is good for burning CPU because the compiler cannot
+ * easily optimize away the computation.
+ * @param workload number of times to execute the loop
+ * @return a white noise value between -1.0 and +1.0
+ */
+static float s_burnCPU(int32_t workload) {
+ uint32_t random = 0;
+ for (int32_t i = 0; i < workload; i++) {
+ for (int32_t j = 0; j < 10; j++) {
+ random = random ^ s_random16();
+ }
+ }
+ return (random - 32768) * (1.0 / 32768);
+}
+
/**
* Simple wrapper for AAudio that opens an output stream either in callback or blocking write mode.
*/
@@ -268,11 +293,13 @@
int32_t timestampCount = 0; // in timestamps
int32_t sampleRate = 48000;
int32_t prefixToneFrames = 0;
+ double workload = 0.0;
bool sweepSetup = false;
int scheduler = 0;
bool schedulerChecked = false;
int32_t hangTimeMSec = 0;
+ int cpuAffinity = -1;
AAudioSimplePlayer simplePlayer;
int32_t callbackCount = 0;
@@ -304,6 +331,14 @@
} SineThreadedData_t;
+int setCpuAffinity(int cpuIndex) {
+cpu_set_t cpu_set;
+ CPU_ZERO(&cpu_set);
+ CPU_SET(cpuIndex, &cpu_set);
+ int err = sched_setaffinity((pid_t) 0, sizeof(cpu_set_t), &cpu_set);
+ return err == 0 ? 0 : -errno;
+}
+
// Callback function that fills the audio output buffer.
aaudio_data_callback_result_t SimplePlayerDataCallbackProc(
AAudioStream *stream,
@@ -319,6 +354,10 @@
}
SineThreadedData_t *sineData = (SineThreadedData_t *) userData;
+ if (sineData->cpuAffinity >= 0) {
+ setCpuAffinity(sineData->cpuAffinity);
+ sineData->cpuAffinity = -1;
+ }
// Play an initial high tone so we can tell whether the beginning was truncated.
if (!sineData->sweepSetup && sineData->framesTotal >= sineData->prefixToneFrames) {
sineData->setupSineSweeps();
@@ -398,6 +437,8 @@
return AAUDIO_CALLBACK_RESULT_STOP;
}
+ s_burnCPU((int32_t)(sineData->workload * kWorkloadScaler * numFrames));
+
sineData->callbackCount++;
sineData->framesTotal += numFrames;
return AAUDIO_CALLBACK_RESULT_CONTINUE;
diff --git a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
index cdc987b..400fc7c 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
@@ -31,10 +31,10 @@
#include "AAudioSimplePlayer.h"
#include "AAudioArgsParser.h"
-#define APP_VERSION "0.1.8"
+#define APP_VERSION "0.2.1"
-constexpr int32_t kDefaultHangTimeMSec = 10;
-
+static constexpr int32_t kDefaultHangTimeMSec = 10;
+static constexpr int32_t kWorkPeriodSeconds = 6;
/**
* Open stream, play some sine waves, then close the stream.
*
@@ -44,7 +44,11 @@
static aaudio_result_t testOpenPlayClose(AAudioArgsParser &argParser,
int32_t loopCount,
int32_t prefixToneMsec,
- int32_t hangTimeMSec)
+ int32_t hangTimeMSec,
+ int cpuAffinity,
+ double lowWorkLoad,
+ double highWorkLoad,
+ int32_t workPeriodSeconds)
{
SineThreadedData_t myData;
AAudioSimplePlayer &player = myData.simplePlayer;
@@ -57,6 +61,7 @@
myData.schedulerChecked = false;
myData.callbackCount = 0;
myData.hangTimeMSec = hangTimeMSec; // test AAudioStream_getXRunCount()
+ myData.cpuAffinity = cpuAffinity;
result = player.open(argParser,
SimplePlayerDataCallbackProc,
@@ -111,8 +116,8 @@
}
// Play a sine wave in the background.
- printf("Sleep for %d seconds while audio plays in a callback thread. %d of %d\n",
- argParser.getDurationSeconds(), (loopIndex + 1), loopCount);
+ printf("Monitor for %d seconds while audio plays in a callback thread. %d of %d, %d\n",
+ argParser.getDurationSeconds(), (loopIndex + 1), loopCount, workPeriodSeconds);
startedAtNanos = getNanoseconds(CLOCK_MONOTONIC);
for (int second = 0; second < durationSeconds; second++) {
// Sleep a while. Wake up early if there is an error, for example a DISCONNECT.
@@ -123,13 +128,17 @@
const int32_t framesWritten = (int32_t) AAudioStream_getFramesWritten(player.getStream());
const int32_t framesRead = (int32_t) AAudioStream_getFramesRead(player.getStream());
const int32_t xruns = AAudioStream_getXRunCount(player.getStream());
+ myData.workload = ((second % (2 * workPeriodSeconds)) < workPeriodSeconds)
+ ? lowWorkLoad : highWorkLoad;
printf(" waker result = %d, at %6d millis"
- ", second = %3d, frames written %8d - read %8d = %8d, underruns = %d\n",
+ ", second = %3d, frames written %8d - read %8d = %8d"
+ ", work = %5.1f, underruns = %d\n",
result, (int) millis,
second,
framesWritten,
framesRead,
framesWritten - framesRead,
+ myData.workload,
xruns);
if (result != AAUDIO_OK) {
disconnected = (result == AAUDIO_ERROR_DISCONNECTED);
@@ -220,6 +229,11 @@
AAudioArgsParser::usage();
printf(" -l{count} loopCount start/stop, every other one is silent\n");
printf(" -t{msec} play a high pitched tone at the beginning\n");
+ printf(" -w{workload} set base workload, default 0.0\n");
+ printf(" -W{workload} alternate between this higher workload and base workload\n");
+ printf(" -Z{duration} number of seconds to spend at each workload, default = %d\n",
+ kWorkPeriodSeconds);
+ printf(" -a{cpu} set CPU affinity, default none\n");
printf(" -h{msec} force periodic underruns by hanging in callback\n");
printf(" If no value specified then %d used.\n",
kDefaultHangTimeMSec);
@@ -232,6 +246,10 @@
int32_t loopCount = 1;
int32_t prefixToneMsec = 0;
int32_t hangTimeMSec = 0;
+ int cpuAffinity = -1;
+ double lowWorkLoad = 0.0;
+ double highWorkLoad = -1.0;
+ int32_t workPeriodSeconds = kWorkPeriodSeconds;
// Make printf print immediately so that debug info is not stuck
// in a buffer if we hang or crash.
@@ -247,6 +265,9 @@
if (arg[0] == '-') {
char option = arg[1];
switch (option) {
+ case 'a':
+ cpuAffinity = atoi(&arg[2]);
+ break;
case 'l':
loopCount = atoi(&arg[2]);
break;
@@ -258,6 +279,15 @@
? atoi(&arg[2])
: kDefaultHangTimeMSec;
break;
+ case 'w':
+ lowWorkLoad = atof(&arg[2]);
+ break;
+ case 'W':
+ highWorkLoad = atof(&arg[2]);
+ break;
+ case 'Z':
+ workPeriodSeconds = atoi(&arg[2]);
+ break;
default:
usage();
exit(EXIT_FAILURE);
@@ -271,9 +301,21 @@
}
}
+ if (highWorkLoad > 0) {
+ if (highWorkLoad < lowWorkLoad) {
+ printf("ERROR - -W%f workload lower than -w%f workload", highWorkLoad, lowWorkLoad);
+ return EXIT_FAILURE;
+ }
+ } else {
+ highWorkLoad = lowWorkLoad; // high not specified so use low
+ }
+
// Keep looping until we can complete the test without disconnecting.
while((result = testOpenPlayClose(argParser, loopCount,
- prefixToneMsec, hangTimeMSec))
+ prefixToneMsec, hangTimeMSec,
+ cpuAffinity,
+ lowWorkLoad, highWorkLoad,
+ workPeriodSeconds))
== AAUDIO_ERROR_DISCONNECTED);
return (result) ? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/media/libaaudio/fuzzer/libaaudio_fuzzer.cpp b/media/libaaudio/fuzzer/libaaudio_fuzzer.cpp
index 1167bb0..0233ee1 100644
--- a/media/libaaudio/fuzzer/libaaudio_fuzzer.cpp
+++ b/media/libaaudio/fuzzer/libaaudio_fuzzer.cpp
@@ -202,7 +202,7 @@
int32_t framesPerBurst = AAudioStream_getFramesPerBurst(mAaudioStream);
uint8_t numberOfBursts = fdp.ConsumeIntegral<uint8_t>();
- int32_t maxInputFrames = numberOfBursts * framesPerBurst;
+ int32_t maxFrames = numberOfBursts * framesPerBurst;
int32_t requestedBufferSize =
fdp.ConsumeIntegral<uint16_t>() * framesPerBurst;
AAudioStream_setBufferSizeInFrames(mAaudioStream, requestedBufferSize);
@@ -218,26 +218,24 @@
int32_t count = fdp.ConsumeIntegral<int32_t>();
direction = AAudioStream_getDirection(mAaudioStream);
- framesPerDataCallback = AAudioStream_getFramesPerDataCallback(mAaudioStream);
if (actualFormat == AAUDIO_FORMAT_PCM_I16) {
- std::vector<int16_t> inputShortData(maxInputFrames * actualChannelCount,
- 0x0);
- if (direction == AAUDIO_DIRECTION_INPUT) {
- AAudioStream_read(mAaudioStream, inputShortData.data(),
- framesPerDataCallback, count * kNanosPerMillisecond);
+ std::vector<int16_t> inputShortData(maxFrames * actualChannelCount, 0x0);
+ if (direction == AAUDIO_DIRECTION_INPUT) {
+ AAudioStream_read(mAaudioStream, inputShortData.data(), maxFrames,
+ count * kNanosPerMillisecond);
} else if (direction == AAUDIO_DIRECTION_OUTPUT) {
- AAudioStream_write(mAaudioStream, inputShortData.data(),
- framesPerDataCallback, count * kNanosPerMillisecond);
+ AAudioStream_write(mAaudioStream, inputShortData.data(), maxFrames,
+ count * kNanosPerMillisecond);
}
} else if (actualFormat == AAUDIO_FORMAT_PCM_FLOAT) {
- std::vector<float> inputFloatData(maxInputFrames * actualChannelCount, 0x0);
- if (direction == AAUDIO_DIRECTION_INPUT) {
- AAudioStream_read(mAaudioStream, inputFloatData.data(),
- framesPerDataCallback, count * kNanosPerMillisecond);
+ std::vector<float> inputFloatData(maxFrames * actualChannelCount, 0x0);
+ if (direction == AAUDIO_DIRECTION_INPUT) {
+ AAudioStream_read(mAaudioStream, inputFloatData.data(), maxFrames,
+ count * kNanosPerMillisecond);
} else if (direction == AAUDIO_DIRECTION_OUTPUT) {
- AAudioStream_write(mAaudioStream, inputFloatData.data(),
- framesPerDataCallback, count * kNanosPerMillisecond);
+ AAudioStream_write(mAaudioStream, inputFloatData.data(), maxFrames,
+ count * kNanosPerMillisecond);
}
}
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 2be3d65..a100aa9 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -321,9 +321,8 @@
mFramesPerDataCallback);
ALOGI("usage = %6d, contentType = %d, inputPreset = %d, allowedCapturePolicy = %d",
getUsage(), getContentType(), getInputPreset(), getAllowedCapturePolicy());
- ALOGI("privacy sensitive = %s", isPrivacySensitive() ? "true" : "false");
- ALOGI("opPackageName = %s", !getOpPackageName().has_value() ?
- "(null)" : getOpPackageName().value().c_str());
- ALOGI("attributionTag = %s", !getAttributionTag().has_value() ?
- "(null)" : getAttributionTag().value().c_str());
+ ALOGI("privacy sensitive = %s, opPackageName = %s, attributionTag = %s",
+ isPrivacySensitive() ? "true" : "false",
+ !getOpPackageName().has_value() ? "(null)" : getOpPackageName().value().c_str(),
+ !getAttributionTag().has_value() ? "(null)" : getAttributionTag().value().c_str());
}
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 988d097..ed31ec9 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -532,7 +532,7 @@
case AAUDIO_STREAM_STATE_STARTED:
result = mAudioRecord->getPosition(&position);
if (result == OK) {
- mFramesWritten.update32(position);
+ mFramesWritten.update32((int32_t)position);
}
break;
case AAUDIO_STREAM_STATE_STOPPING:
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 17a6d0c..6f1dc92 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -508,7 +508,7 @@
case AAUDIO_STREAM_STATE_PAUSED:
result = mAudioTrack->getPosition(&position);
if (result == OK) {
- mFramesRead.update32(position);
+ mFramesRead.update32((int32_t)position);
}
break;
default:
diff --git a/media/libaaudio/src/utility/MonotonicCounter.h b/media/libaaudio/src/utility/MonotonicCounter.h
index 313ccbd..51eb69b 100644
--- a/media/libaaudio/src/utility/MonotonicCounter.h
+++ b/media/libaaudio/src/utility/MonotonicCounter.h
@@ -41,7 +41,12 @@
}
/**
- * advance the current value to match the counter
+ * Advance the current value to match the counter.
+ *
+ * Note that it will take several million years for the 64-bit
+ * counters to wrap around.
+ * So we do not use __builtin_sub_overflow.
+ * We want to know if overflow happens because of a bug.
*/
void catchUpTo(int64_t counter) {
if ((counter - mCounter64) > 0) {
@@ -74,7 +79,8 @@
* @return current value of the 64-bit counter
*/
int64_t update32(int32_t counter32) {
- int32_t delta = counter32 - mCounter32;
+ int32_t delta;
+ __builtin_sub_overflow(counter32, mCounter32, &delta);
// protect against the mCounter64 going backwards
if (delta > 0) {
mCounter64 += delta;
@@ -108,5 +114,4 @@
int32_t mCounter32 = 0;
};
-
#endif //UTILITY_MONOTONIC_COUNTER_H
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index ea00a5a..4b45909 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -13,6 +13,11 @@
"-Wall",
"-Werror",
],
+
+ sanitize: {
+ integer_overflow: true,
+ misc_undefined: ["bounds"],
+ },
}
cc_test {
@@ -146,6 +151,18 @@
],
}
+cc_test {
+ name: "test_monotonic_counter",
+ defaults: ["libaaudio_tests_defaults"],
+ srcs: ["test_monotonic_counter.cpp"],
+ shared_libs: [
+ "libaaudio_internal",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+}
+
cc_binary {
name: "test_return_stop",
defaults: ["libaaudio_tests_defaults"],
diff --git a/media/libaaudio/tests/test_monotonic_counter.cpp b/media/libaaudio/tests/test_monotonic_counter.cpp
new file mode 100644
index 0000000..5cbbaf7
--- /dev/null
+++ b/media/libaaudio/tests/test_monotonic_counter.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2022 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.
+ */
+
+/*
+ * Test MonotonicCounter
+ */
+
+#include <iostream>
+
+#include <gtest/gtest.h>
+
+#include "utility/MonotonicCounter.h"
+
+TEST(test_monotonic_counter, builtin_wrap) {
+ int32_t x = 0x7FFFFFF0;
+ int32_t y = 0x80000010;
+ int32_t delta;
+ // delta = y - x; // This would cause a numeric overflow!
+ __builtin_sub_overflow(y, x, &delta);
+ ASSERT_EQ(0x20, delta);
+}
+
+// test updating past some overflow points
+TEST(test_monotonic_counter, mono_counter_update32_wrap) {
+ MonotonicCounter counter;
+ ASSERT_EQ(0, counter.get());
+
+ static constexpr uint32_t x = (uint32_t) 0x7FFFFFF0;
+ counter.update32(x);
+ ASSERT_EQ((int64_t)0x7FFFFFF0, counter.get());
+
+ static constexpr uint32_t y = (uint32_t) 0x80000010;
+ counter.update32(y);
+ ASSERT_EQ((int64_t)0x80000010, counter.get());
+
+ counter.update32(0);
+ ASSERT_EQ((int64_t)0x100000000, counter.get());
+}
+
+TEST(test_monotonic_counter, mono_counter_roundup) {
+ MonotonicCounter counter;
+ static constexpr uint32_t x = 2345;
+ counter.update32(x);
+ ASSERT_EQ((int64_t)x, counter.get());
+
+ counter.roundUp64(100);
+ ASSERT_EQ((int64_t)2400, counter.get());
+}
+
+TEST(test_monotonic_counter, mono_counter_catchup) {
+ MonotonicCounter counter;
+ counter.update32(7654);
+ counter.catchUpTo(5000); // already past 5000 so no change
+ ASSERT_EQ((int64_t)7654, counter.get());
+ counter.catchUpTo(9876); // jumps
+ ASSERT_EQ((int64_t)9876, counter.get());
+}
+
+TEST(test_monotonic_counter, mono_counter_increment) {
+ MonotonicCounter counter;
+ counter.update32(1000);
+ counter.increment(-234); // will not go backwards
+ ASSERT_EQ((int64_t)1000, counter.get());
+ counter.increment(96); // advances
+ ASSERT_EQ((int64_t)1096, counter.get());
+}
+
+TEST(test_monotonic_counter, mono_counter_reset) {
+ MonotonicCounter counter;
+ counter.update32(1000);
+ // Counter is monotonic and should not go backwards.
+ counter.update32(500); // No change because 32-bit counter is already past 1000.
+ ASSERT_EQ((int64_t)1000, counter.get());
+
+ counter.reset32();
+ counter.update32(500);
+ ASSERT_EQ((int64_t)1500, counter.get());
+}
diff --git a/media/libaudioclient/AidlConversion.cpp b/media/libaudioclient/AidlConversion.cpp
index 323e002..11724e0 100644
--- a/media/libaudioclient/AidlConversion.cpp
+++ b/media/libaudioclient/AidlConversion.cpp
@@ -601,6 +601,11 @@
AudioDeviceType::OUT_SPEAKER,
AudioDeviceDescription::CONNECTION_BT_LE())
},
+ {
+ AUDIO_DEVICE_OUT_BLE_BROADCAST, make_AudioDeviceDescription(
+ AudioDeviceType::OUT_BROADCAST,
+ AudioDeviceDescription::CONNECTION_BT_LE())
+ },
// AUDIO_DEVICE_IN_AMBIENT and IN_COMMUNICATION are removed since they were deprecated.
{
AUDIO_DEVICE_IN_BUILTIN_MIC, make_AudioDeviceDescription(
@@ -1434,6 +1439,8 @@
return AUDIO_INPUT_FLAG_HW_AV_SYNC;
case AudioInputFlags::DIRECT:
return AUDIO_INPUT_FLAG_DIRECT;
+ case AudioInputFlags::ULTRASOUND:
+ return AUDIO_INPUT_FLAG_ULTRASOUND;
}
return unexpected(BAD_VALUE);
}
@@ -1459,6 +1466,8 @@
return AudioInputFlags::HW_AV_SYNC;
case AUDIO_INPUT_FLAG_DIRECT:
return AudioInputFlags::DIRECT;
+ case AUDIO_INPUT_FLAG_ULTRASOUND:
+ return AudioInputFlags::ULTRASOUND;
}
return unexpected(BAD_VALUE);
}
@@ -1498,6 +1507,10 @@
return AUDIO_OUTPUT_FLAG_INCALL_MUSIC;
case AudioOutputFlags::GAPLESS_OFFLOAD:
return AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD;
+ case AudioOutputFlags::ULTRASOUND:
+ return AUDIO_OUTPUT_FLAG_ULTRASOUND;
+ case AudioOutputFlags::SPATIALIZER:
+ return AUDIO_OUTPUT_FLAG_SPATIALIZER;
}
return unexpected(BAD_VALUE);
}
@@ -1539,6 +1552,10 @@
return AudioOutputFlags::INCALL_MUSIC;
case AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD:
return AudioOutputFlags::GAPLESS_OFFLOAD;
+ case AUDIO_OUTPUT_FLAG_ULTRASOUND:
+ return AudioOutputFlags::ULTRASOUND;
+ case AUDIO_OUTPUT_FLAG_SPATIALIZER:
+ return AudioOutputFlags::SPATIALIZER;
}
return unexpected(BAD_VALUE);
}
@@ -1744,6 +1761,8 @@
return AUDIO_SOURCE_UNPROCESSED;
case AudioSource::VOICE_PERFORMANCE:
return AUDIO_SOURCE_VOICE_PERFORMANCE;
+ case AudioSource::ULTRASOUND:
+ return AUDIO_SOURCE_ULTRASOUND;
case AudioSource::ECHO_REFERENCE:
return AUDIO_SOURCE_ECHO_REFERENCE;
case AudioSource::FM_TUNER:
@@ -1781,6 +1800,8 @@
return AudioSource::UNPROCESSED;
case AUDIO_SOURCE_VOICE_PERFORMANCE:
return AudioSource::VOICE_PERFORMANCE;
+ case AUDIO_SOURCE_ULTRASOUND:
+ return AudioSource::ULTRASOUND;
case AUDIO_SOURCE_ECHO_REFERENCE:
return AudioSource::ECHO_REFERENCE;
case AUDIO_SOURCE_FM_TUNER:
@@ -2141,6 +2162,8 @@
return AUDIO_CONTENT_TYPE_MOVIE;
case AudioContentType::SONIFICATION:
return AUDIO_CONTENT_TYPE_SONIFICATION;
+ case AudioContentType::ULTRASOUND:
+ return AUDIO_CONTENT_TYPE_ULTRASOUND;
}
return unexpected(BAD_VALUE);
}
@@ -2158,6 +2181,8 @@
return AudioContentType::MOVIE;
case AUDIO_CONTENT_TYPE_SONIFICATION:
return AudioContentType::SONIFICATION;
+ case AUDIO_CONTENT_TYPE_ULTRASOUND:
+ return AudioContentType::ULTRASOUND;
}
return unexpected(BAD_VALUE);
}
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 9733cb3..e890e97 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -11,6 +11,10 @@
name: "libaudioclient_headers",
vendor_available: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ ],
host_supported: true,
header_libs: [
@@ -41,7 +45,7 @@
},
}
-cc_library_shared {
+cc_library {
name: "libaudiopolicy",
srcs: [
"AudioAttributes.cpp",
@@ -199,9 +203,11 @@
],
header_libs: [
"libbase_headers",
+ "liberror_headers",
],
export_header_lib_headers: [
"libbase_headers",
+ "liberror_headers",
],
apex_available: [
"//apex_available:platform",
diff --git a/media/libaudioclient/AudioEffect.cpp b/media/libaudioclient/AudioEffect.cpp
index 62f863d..7b273ec 100644
--- a/media/libaudioclient/AudioEffect.cpp
+++ b/media/libaudioclient/AudioEffect.cpp
@@ -61,8 +61,7 @@
status_t AudioEffect::set(const effect_uuid_t *type,
const effect_uuid_t *uuid,
int32_t priority,
- effect_callback_t cbf,
- void* user,
+ const wp<IAudioEffectCallback>& callback,
audio_session_t sessionId,
audio_io_handle_t io,
const AudioDeviceTypeAddr& device,
@@ -73,7 +72,7 @@
sp<IMemory> cblk;
int enabled;
- ALOGV("set %p mUserData: %p uuid: %p timeLow %08x", this, user, type, type ? type->timeLow : 0);
+ ALOGV("set %p uuid: %p timeLow %08x", this, type, type ? type->timeLow : 0);
if (mIEffect != 0) {
ALOGW("Effect already in use");
@@ -96,9 +95,8 @@
}
mProbe = probe;
mPriority = priority;
- mCbf = cbf;
- mUserData = user;
mSessionId = sessionId;
+ mCallback = callback;
memset(&mDescriptor, 0, sizeof(effect_descriptor_t));
mDescriptor.type = *(type != NULL ? type : EFFECT_UUID_NULL);
@@ -128,6 +126,9 @@
mStatus = audioFlinger->createEffect(request, &response);
if (mStatus == OK) {
+ if (response.alreadyExists) {
+ mStatus = ALREADY_EXISTS;
+ }
mId = response.id;
enabled = response.enabled;
iEffect = response.effect;
@@ -184,11 +185,60 @@
return mStatus;
}
+namespace {
+class LegacyCallbackWrapper : public AudioEffect::IAudioEffectCallback {
+ public:
+ LegacyCallbackWrapper(AudioEffect::legacy_callback_t callback, void* user):
+ mCallback(callback), mUser(user) {}
+ private:
+ void onControlStatusChanged(bool isGranted) override {
+ mCallback(AudioEffect::EVENT_CONTROL_STATUS_CHANGED, mUser, &isGranted);
+ }
+
+ void onEnableStatusChanged(bool isEnabled) override {
+ mCallback(AudioEffect::EVENT_ENABLE_STATUS_CHANGED, mUser, &isEnabled);
+ }
+
+ void onParameterChanged(std::vector<uint8_t> param) override {
+ mCallback(AudioEffect::EVENT_PARAMETER_CHANGED, mUser, param.data());
+ }
+
+ void onError(status_t errorCode) override {
+ mCallback(AudioEffect::EVENT_ERROR, mUser, &errorCode);
+ }
+
+ void onFramesProcessed(int32_t framesProcessed) override {
+ mCallback(AudioEffect::EVENT_FRAMES_PROCESSED, mUser, &framesProcessed);
+ }
+
+ const AudioEffect::legacy_callback_t mCallback;
+ void* const mUser;
+};
+} // namespace
+
+status_t AudioEffect::set(const effect_uuid_t *type,
+ const effect_uuid_t *uuid,
+ int32_t priority,
+ legacy_callback_t cbf,
+ void* user,
+ audio_session_t sessionId,
+ audio_io_handle_t io,
+ const AudioDeviceTypeAddr& device,
+ bool probe,
+ bool notifyFramesProcessed)
+{
+ if (cbf != nullptr) {
+ mLegacyWrapper = sp<LegacyCallbackWrapper>::make(cbf, user);
+ } else if (user != nullptr) {
+ LOG_ALWAYS_FATAL("%s: User provided without callback", __func__);
+ }
+ return set(type, uuid, priority, mLegacyWrapper, sessionId, io, device, probe,
+ notifyFramesProcessed);
+}
status_t AudioEffect::set(const char *typeStr,
const char *uuidStr,
int32_t priority,
- effect_callback_t cbf,
- void* user,
+ const wp<IAudioEffectCallback>& callback,
audio_session_t sessionId,
audio_io_handle_t io,
const AudioDeviceTypeAddr& device,
@@ -210,11 +260,29 @@
pUuid = &uuid;
}
- return set(pType, pUuid, priority, cbf, user, sessionId, io,
+ return set(pType, pUuid, priority, callback, sessionId, io,
device, probe, notifyFramesProcessed);
}
-
+status_t AudioEffect::set(const char *typeStr,
+ const char *uuidStr,
+ int32_t priority,
+ legacy_callback_t cbf,
+ void* user,
+ audio_session_t sessionId,
+ audio_io_handle_t io,
+ const AudioDeviceTypeAddr& device,
+ bool probe,
+ bool notifyFramesProcessed)
+{
+ if (cbf != nullptr) {
+ mLegacyWrapper = sp<LegacyCallbackWrapper>::make(cbf, user);
+ } else if (user != nullptr) {
+ LOG_ALWAYS_FATAL("%s: User provided without callback", __func__);
+ }
+ return set(typeStr, uuidStr, priority, mLegacyWrapper, sessionId, io, device, probe,
+ notifyFramesProcessed);
+}
AudioEffect::~AudioEffect()
{
ALOGV("Destructor %p", this);
@@ -468,9 +536,9 @@
{
ALOGW("IEffect died");
mStatus = DEAD_OBJECT;
- if (mCbf != NULL) {
- status_t status = DEAD_OBJECT;
- mCbf(EVENT_ERROR, mUserData, &status);
+ auto cb = mCallback.promote();
+ if (cb != nullptr) {
+ cb->onError(mStatus);
}
mIEffect.clear();
}
@@ -479,8 +547,8 @@
void AudioEffect::controlStatusChanged(bool controlGranted)
{
- ALOGV("controlStatusChanged %p control %d callback %p mUserData %p", this, controlGranted, mCbf,
- mUserData);
+ auto cb = mCallback.promote();
+ ALOGV("controlStatusChanged %p control %d callback %p", this, controlGranted, cb.get());
if (controlGranted) {
if (mStatus == ALREADY_EXISTS) {
mStatus = NO_ERROR;
@@ -490,18 +558,19 @@
mStatus = ALREADY_EXISTS;
}
}
- if (mCbf != NULL) {
- mCbf(EVENT_CONTROL_STATUS_CHANGED, mUserData, &controlGranted);
+ if (cb != nullptr) {
+ cb->onControlStatusChanged(controlGranted);
}
}
void AudioEffect::enableStatusChanged(bool enabled)
{
- ALOGV("enableStatusChanged %p enabled %d mCbf %p", this, enabled, mCbf);
+ auto cb = mCallback.promote();
+ ALOGV("enableStatusChanged %p enabled %d mCallback %p", this, enabled, cb.get());
if (mStatus == ALREADY_EXISTS) {
mEnabled = enabled;
- if (mCbf != NULL) {
- mCbf(EVENT_ENABLE_STATUS_CHANGED, mUserData, &enabled);
+ if (cb != nullptr) {
+ cb->onEnableStatusChanged(enabled);
}
}
}
@@ -513,19 +582,20 @@
if (cmdData.empty() || replyData.empty()) {
return;
}
-
- if (mCbf != NULL && cmdCode == EFFECT_CMD_SET_PARAM) {
+ auto cb = mCallback.promote();
+ if (cb != nullptr && cmdCode == EFFECT_CMD_SET_PARAM) {
std::vector<uint8_t> cmdDataCopy(cmdData);
effect_param_t* cmd = reinterpret_cast<effect_param_t *>(cmdDataCopy.data());
cmd->status = *reinterpret_cast<const int32_t *>(replyData.data());
- mCbf(EVENT_PARAMETER_CHANGED, mUserData, cmd);
+ cb->onParameterChanged(std::move(cmdDataCopy));
}
}
void AudioEffect::framesProcessed(int32_t frames)
{
- if (mCbf != NULL) {
- mCbf(EVENT_FRAMES_PROCESSED, mUserData, &frames);
+ auto cb = mCallback.promote();
+ if (cb != nullptr) {
+ cb->onFramesProcessed(frames);
}
}
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 0c37fb5..2f8845f 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -69,8 +69,9 @@
// We double the size of input buffer for ping pong use of record buffer.
// Assumes audio_is_linear_pcm(format)
- if ((*frameCount = (size * 2) / (audio_channel_count_from_in_mask(channelMask) *
- audio_bytes_per_sample(format))) == 0) {
+ const auto sampleSize = audio_channel_count_from_in_mask(channelMask) *
+ audio_bytes_per_sample(format);
+ if (sampleSize == 0 || ((*frameCount = (size * 2) / sampleSize) == 0)) {
ALOGE("%s(): Unsupported configuration: sampleRate %u, format %#x, channelMask %#x",
__func__, sampleRate, format, channelMask);
return BAD_VALUE;
@@ -357,6 +358,12 @@
if (format == AUDIO_FORMAT_DEFAULT) {
format = AUDIO_FORMAT_PCM_16_BIT;
}
+ if (!audio_is_linear_pcm(format)) {
+ // Compressed capture requires direct
+ flags = (audio_input_flags_t) (flags | AUDIO_INPUT_FLAG_DIRECT);
+ ALOGI("%s(): Format %#x is not linear pcm. Setting DIRECT, using flags %#x", __func__,
+ format, flags);
+ }
mFormat = format;
mChannelMask = channelMask;
mSessionId = sessionId;
@@ -396,9 +403,8 @@
goto error;
}
- // AudioFlinger capture only supports linear PCM
- if (!audio_is_valid_format(mFormat) || !audio_is_linear_pcm(mFormat)) {
- errorMessage = StringPrintf("%s: Format %#x is not linear pcm", __func__, mFormat);
+ if (!audio_is_valid_format(mFormat)) {
+ errorMessage = StringPrintf("%s: Format %#x is not valid", __func__, mFormat);
status = BAD_VALUE;
goto error;
}
@@ -718,6 +724,11 @@
if (status == OK) {
timestamp->mPosition[ExtendedTimestamp::LOCATION_CLIENT] = mFramesRead;
timestamp->mTimeNs[ExtendedTimestamp::LOCATION_CLIENT] = 0;
+ if (!audio_is_linear_pcm(mFormat)) {
+ // Don't do retrograde corrections or server offset if track is
+ // compressed
+ return OK;
+ }
// server side frame offset in case AudioRecord has been restored.
for (int i = ExtendedTimestamp::LOCATION_SERVER;
i < ExtendedTimestamp::LOCATION_MAX; ++i) {
@@ -1184,7 +1195,13 @@
if (status == DEAD_OBJECT) {
// re-create track, unless someone else has already done so
if (newSequence == oldSequence) {
- status = restoreRecord_l("obtainBuffer");
+ if (!audio_is_linear_pcm(mFormat)) {
+ // If compressed capture, don't attempt to restore the track.
+ // Return a DEAD_OBJECT error and let the caller recreate.
+ tryCounter = 0;
+ } else {
+ status = restoreRecord_l("obtainBuffer");
+ }
if (status != NO_ERROR) {
buffer.mFrameCount = 0;
buffer.mRaw = NULL;
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index b3c82787..32c77c7 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -834,33 +834,18 @@
aps->onNewAudioModulesAvailable();
}
-status_t AudioSystem::setDeviceConnectionState(audio_devices_t device,
- audio_policy_dev_state_t state,
- const char* device_address,
- const char* device_name,
+status_t AudioSystem::setDeviceConnectionState(audio_policy_dev_state_t state,
+ const android::media::audio::common::AudioPort& port,
audio_format_t encodedFormat) {
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
- const char* address = "";
- const char* name = "";
if (aps == 0) return PERMISSION_DENIED;
- if (device_address != NULL) {
- address = device_address;
- }
- if (device_name != NULL) {
- name = device_name;
- }
-
- AudioDevice deviceAidl = VALUE_OR_RETURN_STATUS(
- legacy2aidl_audio_device_AudioDevice(device, address));
-
return statusTFromBinderStatus(
aps->setDeviceConnectionState(
- deviceAidl,
VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_policy_dev_state_t_AudioPolicyDeviceState(state)),
- name,
+ port,
VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_format_t_AudioFormatDescription(encodedFormat))));
}
@@ -1926,20 +1911,22 @@
aps->setSurroundFormatEnabled(audioFormatAidl, enabled));
}
-status_t AudioSystem::setAssistantUid(uid_t uid) {
+status_t AudioSystem::setAssistantServicesUids(const std::vector<uid_t>& uids) {
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
- int32_t uidAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(uid));
- return statusTFromBinderStatus(aps->setAssistantUid(uidAidl));
+ std::vector<int32_t> uidsAidl = VALUE_OR_RETURN_STATUS(
+ convertContainer<std::vector<int32_t>>(uids, legacy2aidl_uid_t_int32_t));
+ return statusTFromBinderStatus(aps->setAssistantServicesUids(uidsAidl));
}
-status_t AudioSystem::setHotwordDetectionServiceUid(uid_t uid) {
+status_t AudioSystem::setActiveAssistantServicesUids(const std::vector<uid_t>& activeUids) {
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
- int32_t uidAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(uid));
- return statusTFromBinderStatus(aps->setHotwordDetectionServiceUid(uidAidl));
+ std::vector<int32_t> activeUidsAidl = VALUE_OR_RETURN_STATUS(
+ convertContainer<std::vector<int32_t>>(activeUids, legacy2aidl_uid_t_int32_t));
+ return statusTFromBinderStatus(aps->setActiveAssistantServicesUids(activeUidsAidl));
}
status_t AudioSystem::setA11yServicesUids(const std::vector<uid_t>& uids) {
@@ -1972,6 +1959,19 @@
return result.value_or(false);
}
+bool AudioSystem::isUltrasoundSupported() {
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return false;
+
+ auto result = [&]() -> ConversionResult<bool> {
+ bool retVal;
+ RETURN_IF_ERROR(
+ statusTFromBinderStatus(aps->isUltrasoundSupported(&retVal)));
+ return retVal;
+ }();
+ return result.value_or(false);
+}
+
status_t AudioSystem::getHwOffloadFormatsSupportedForBluetoothMedia(
audio_devices_t device, std::vector<audio_format_t>* formats) {
if (formats == nullptr) {
@@ -2314,6 +2314,28 @@
return NO_ERROR;
}
+status_t AudioSystem::getDirectProfilesForAttributes(const audio_attributes_t* attr,
+ std::vector<audio_profile>* audioProfiles) {
+ if (attr == nullptr) {
+ return BAD_VALUE;
+ }
+
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) {
+ return PERMISSION_DENIED;
+ }
+
+ media::AudioAttributesInternal attrAidl = VALUE_OR_RETURN_STATUS(
+ legacy2aidl_audio_attributes_t_AudioAttributesInternal(*attr));
+
+ std::vector<media::audio::common::AudioProfile> audioProfilesAidl;
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
+ aps->getDirectProfilesForAttributes(attrAidl, &audioProfilesAidl)));
+ *audioProfiles = VALUE_OR_RETURN_STATUS(convertContainer<std::vector<audio_profile>>(
+ audioProfilesAidl, aidl2legacy_AudioProfile_audio_profile, false /*isInput*/));
+
+ return NO_ERROR;
+}
class CaptureStateListenerImpl : public media::BnCaptureStateListener,
public IBinder::DeathRecipient {
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 919d6d2..bceca2d 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -537,6 +537,8 @@
float maxRequiredSpeed,
audio_port_handle_t selectedDeviceId)
{
+ LOG_ALWAYS_FATAL_IF(mInitialized, "%s: should not be called twice", __func__);
+ mInitialized = true;
status_t status;
uint32_t channelCount;
pid_t callingPid;
@@ -1120,8 +1122,16 @@
{
using namespace std::chrono_literals;
+ // We use atomic access here for state variables - these are used as hints
+ // to ensure we have ramped down audio.
+ const int priorState = mProxy->getState();
+ const uint32_t priorPosition = mProxy->getPosition().unsignedValue();
+
pause();
+ // Only if we were previously active, do we wait to ramp down the audio.
+ if (priorState != CBLK_STATE_ACTIVE) return true;
+
AutoMutex lock(mLock);
// offload and direct tracks do not wait because pause volume ramp is handled by hardware.
if (isOffloadedOrDirect_l()) return true;
@@ -1129,16 +1139,25 @@
// Wait for the track state to be anything besides pausing.
// This ensures that the volume has ramped down.
constexpr auto SLEEP_INTERVAL_MS = 10ms;
+ constexpr auto POSITION_TIMEOUT_MS = 40ms; // don't wait longer than this for position change.
auto begin = std::chrono::steady_clock::now();
while (true) {
- // wait for state to change
+ // Wait for state and position to change.
+ // After pause() the server state should be PAUSING, but that may immediately
+ // convert to PAUSED by prepareTracks before data is read into the mixer.
+ // Hence we check that the state is not PAUSING and that the server position
+ // has advanced to be a more reliable estimate that the volume ramp has completed.
const int state = mProxy->getState();
+ const uint32_t position = mProxy->getPosition().unsignedValue();
mLock.unlock(); // only local variables accessed until lock.
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - begin);
- if (state != CBLK_STATE_PAUSING) {
- ALOGV("%s: success state:%d after %lld ms", __func__, state, elapsed.count());
+ if (state != CBLK_STATE_PAUSING &&
+ (elapsed >= POSITION_TIMEOUT_MS || position != priorPosition)) {
+ ALOGV("%s: success state:%d, position:%u after %lld ms"
+ " (prior state:%d prior position:%u)",
+ __func__, state, position, elapsed.count(), priorState, priorPosition);
return true;
}
std::chrono::milliseconds remaining = timeout - elapsed;
@@ -1574,12 +1593,12 @@
status_t AudioTrack::setMarkerPosition(uint32_t marker)
{
+ AutoMutex lock(mLock);
// The only purpose of setting marker position is to get a callback
- if (!mCallback.promote() || isOffloadedOrDirect()) {
+ if (!mCallback.promote() || isOffloadedOrDirect_l()) {
return INVALID_OPERATION;
}
- AutoMutex lock(mLock);
mMarkerPosition = marker;
mMarkerReached = false;
@@ -1607,12 +1626,12 @@
status_t AudioTrack::setPositionUpdatePeriod(uint32_t updatePeriod)
{
+ AutoMutex lock(mLock);
// The only purpose of setting position update period is to get a callback
- if (!mCallback.promote() || isOffloadedOrDirect()) {
+ if (!mCallback.promote() || isOffloadedOrDirect_l()) {
return INVALID_OPERATION;
}
- AutoMutex lock(mLock);
mNewPosition = updateAndGetPosition_l() + updatePeriod;
mUpdatePeriod = updatePeriod;
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 88e7396..292d92f 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -803,6 +803,12 @@
return result.value_or(0);
}
+status_t AudioFlingerClientAdapter::setDeviceConnectedState(
+ const struct audio_port_v7 *port, bool connected) {
+ media::AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
+ legacy2aidl_audio_port_v7_AudioPort(*port));
+ return statusTFromBinderStatus(mDelegate->setDeviceConnectedState(aidlPort, connected));
+}
////////////////////////////////////////////////////////////////////////////////////////////////////
// AudioFlingerServerAdapter
@@ -1292,4 +1298,10 @@
return Status::ok();
}
+Status AudioFlingerServerAdapter::setDeviceConnectedState(
+ const media::AudioPort& port, bool connected) {
+ audio_port_v7 portLegacy = VALUE_OR_RETURN_BINDER(aidl2legacy_AudioPort_audio_port_v7(port));
+ return Status::fromStatusT(mDelegate->setDeviceConnectedState(&portLegacy, connected));
+}
+
} // namespace android
diff --git a/media/libaudioclient/PolicyAidlConversion.cpp b/media/libaudioclient/PolicyAidlConversion.cpp
index fd94568..520f09c 100644
--- a/media/libaudioclient/PolicyAidlConversion.cpp
+++ b/media/libaudioclient/PolicyAidlConversion.cpp
@@ -27,16 +27,6 @@
using base::unexpected;
using media::audio::common::AudioDeviceAddress;
-ConversionResult<volume_group_t>
-aidl2legacy_int32_t_volume_group_t(int32_t aidl) {
- return convertReinterpret<volume_group_t>(aidl);
-}
-
-ConversionResult<int32_t>
-legacy2aidl_volume_group_t_int32_t(volume_group_t legacy) {
- return convertReinterpret<int32_t>(legacy);
-}
-
ConversionResult<uint32_t>
aidl2legacy_AudioMixType_uint32_t(media::AudioMixType aidl) {
switch (aidl) {
diff --git a/media/libaudioclient/aidl/android/media/CreateEffectResponse.aidl b/media/libaudioclient/aidl/android/media/CreateEffectResponse.aidl
index 0aa640a..e2755dd 100644
--- a/media/libaudioclient/aidl/android/media/CreateEffectResponse.aidl
+++ b/media/libaudioclient/aidl/android/media/CreateEffectResponse.aidl
@@ -29,4 +29,5 @@
boolean enabled;
@nullable IEffect effect;
EffectDescriptor desc;
+ boolean alreadyExists;
}
diff --git a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
index c55c66e..6afe023 100644
--- a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
@@ -225,4 +225,6 @@
int getAAudioMixerBurstCount();
int getAAudioHardwareBurstMinUsec();
+
+ void setDeviceConnectedState(in AudioPort devicePort, boolean connected);
}
diff --git a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
index 7895ae3..de0f75b 100644
--- a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
@@ -48,7 +48,9 @@
import android.media.audio.common.AudioDeviceDescription;
import android.media.audio.common.AudioFormatDescription;
import android.media.audio.common.AudioMode;
+import android.media.audio.common.AudioProfile;
import android.media.audio.common.AudioOffloadInfo;
+import android.media.audio.common.AudioPort;
import android.media.audio.common.AudioSource;
import android.media.audio.common.AudioStreamType;
import android.media.audio.common.AudioUsage;
@@ -63,9 +65,8 @@
interface IAudioPolicyService {
oneway void onNewAudioModulesAvailable();
- void setDeviceConnectionState(in AudioDevice device,
- in AudioPolicyDeviceState state,
- @utf8InCpp String deviceName,
+ void setDeviceConnectionState(in AudioPolicyDeviceState state,
+ in android.media.audio.common.AudioPort port,
in AudioFormatDescription encodedFormat);
AudioPolicyDeviceState getDeviceConnectionState(in AudioDevice device);
@@ -301,9 +302,9 @@
void setSurroundFormatEnabled(in AudioFormatDescription audioFormat, boolean enabled);
- void setAssistantUid(int /* uid_t */ uid);
+ void setAssistantServicesUids(in int[] /* uid_t[] */ uids);
- void setHotwordDetectionServiceUid(int /* uid_t */ uid);
+ void setActiveAssistantServicesUids(in int[] /* uid_t[] */ activeUids);
void setA11yServicesUids(in int[] /* uid_t[] */ uids);
@@ -311,6 +312,8 @@
boolean isHapticPlaybackSupported();
+ boolean isUltrasoundSupported();
+
AudioProductStrategy[] listAudioProductStrategies();
int /* product_strategy_t */ getProductStrategyFromAudioAttributes(in AudioAttributesEx aa,
boolean fallbackOnDefault);
@@ -381,6 +384,12 @@
/**
* Query how the direct playback is currently supported on the device.
*/
- AudioDirectMode getDirectPlaybackSupport(in AudioAttributesInternal attr,
+ AudioDirectMode getDirectPlaybackSupport(in AudioAttributesInternal attr,
in AudioConfig config);
+
+ /**
+ * Query audio profiles available for direct playback on the current output device(s)
+ * for the specified audio attributes.
+ */
+ AudioProfile[] getDirectProfilesForAttributes(in AudioAttributesInternal attr);
}
diff --git a/media/libaudioclient/aidl/android/media/SpatializationMode.aidl b/media/libaudioclient/aidl/android/media/SpatializationMode.aidl
index 5d8fd93..eaaff37 100644
--- a/media/libaudioclient/aidl/android/media/SpatializationMode.aidl
+++ b/media/libaudioclient/aidl/android/media/SpatializationMode.aidl
@@ -24,7 +24,7 @@
@Backing(type="byte")
enum SpatializationMode {
/** The spatializer supports binaural mode (over headphones type devices). */
- SPATIALIZATER_BINAURAL = 0,
+ SPATIALIZER_BINAURAL = 0,
/** The spatializer supports transaural mode (over speaker type devices). */
- SPATIALIZATER_TRANSAURAL = 1,
+ SPATIALIZER_TRANSAURAL = 1,
}
diff --git a/media/libaudioclient/fuzzer/audioflinger_fuzzer.cpp b/media/libaudioclient/fuzzer/audioflinger_fuzzer.cpp
index 169a6a7..036e72e 100644
--- a/media/libaudioclient/fuzzer/audioflinger_fuzzer.cpp
+++ b/media/libaudioclient/fuzzer/audioflinger_fuzzer.cpp
@@ -315,7 +315,7 @@
attributionSource.packageName = std::string(mFdp.ConsumeRandomLengthString().c_str());
attributionSource.token = sp<BBinder>::make();
sp<AudioRecord> record = new AudioRecord(attributionSource);
- record->set(AUDIO_SOURCE_DEFAULT, sampleRate, format, channelMask, frameCount, nullptr, nullptr,
+ record->set(AUDIO_SOURCE_DEFAULT, sampleRate, format, channelMask, frameCount, nullptr,
notificationFrames, false, sessionId,
fast ? AudioRecord::TRANSFER_CALLBACK : AudioRecord::TRANSFER_DEFAULT, flags,
getuid(), getpid(), &attributes, AUDIO_PORT_HANDLE_NONE);
diff --git a/media/libaudioclient/include/media/AidlConversionUtil.h b/media/libaudioclient/include/media/AidlConversionUtil.h
index dfabd55..820b7cb 100644
--- a/media/libaudioclient/include/media/AidlConversionUtil.h
+++ b/media/libaudioclient/include/media/AidlConversionUtil.h
@@ -20,45 +20,13 @@
#include <type_traits>
#include <utility>
-#include <android-base/expected.h>
#include <binder/Status.h>
+#include <error/Result.h>
namespace android {
template <typename T>
-using ConversionResult = base::expected<T, status_t>;
-
-// Convenience macros for working with ConversionResult, useful for writing converted for aggregate
-// types.
-
-#define VALUE_OR_RETURN(result) \
- ({ \
- auto _tmp = (result); \
- if (!_tmp.ok()) return base::unexpected(_tmp.error()); \
- std::move(_tmp.value()); \
- })
-
-#define RETURN_IF_ERROR(result) \
- if (status_t _tmp = (result); _tmp != OK) return base::unexpected(_tmp);
-
-#define RETURN_STATUS_IF_ERROR(result) \
- if (status_t _tmp = (result); _tmp != OK) return _tmp;
-
-#define VALUE_OR_RETURN_STATUS(x) \
- ({ \
- auto _tmp = (x); \
- if (!_tmp.ok()) return _tmp.error(); \
- std::move(_tmp.value()); \
- })
-
-#define VALUE_OR_FATAL(result) \
- ({ \
- auto _tmp = (result); \
- LOG_ALWAYS_FATAL_IF(!_tmp.ok(), \
- "Function: %s Line: %d Failed result (%d)",\
- __FUNCTION__, __LINE__, _tmp.error()); \
- std::move(_tmp.value()); \
- })
+using ConversionResult = error::Result<T>;
/**
* A generic template to safely cast between integral types, respecting limits of the destination
@@ -109,6 +77,26 @@
}
/**
+ * A generic template that helps convert containers of convertible types, using iterators.
+ * Uses a limit as maximum conversion items.
+ */
+template<typename InputIterator, typename OutputIterator, typename Func>
+status_t convertRangeWithLimit(InputIterator start,
+ InputIterator end,
+ OutputIterator out,
+ const Func& itemConversion,
+ const size_t limit) {
+ InputIterator last = end;
+ if (end - start > limit) {
+ last = start + limit;
+ }
+ for (InputIterator iter = start; (iter != last); ++iter, ++out) {
+ *out = VALUE_OR_RETURN_STATUS(itemConversion(*iter));
+ }
+ return OK;
+}
+
+/**
* A generic template that helps convert containers of convertible types.
*/
template<typename OutputContainer, typename InputContainer, typename Func>
@@ -123,6 +111,21 @@
}
/**
+ * A generic template that helps convert containers of convertible types
+ * using an item conversion function with an additional parameter.
+ */
+template<typename OutputContainer, typename InputContainer, typename Func, typename Parameter>
+ConversionResult<OutputContainer>
+convertContainer(const InputContainer& input, const Func& itemConversion, const Parameter& param) {
+ OutputContainer output;
+ auto ins = std::inserter(output, output.begin());
+ for (const auto& item : input) {
+ *ins = VALUE_OR_RETURN(itemConversion(item, param));
+ }
+ return output;
+}
+
+/**
* A generic template that helps to "zip" two input containers of the same size
* into a single vector of converted types. The conversion function must
* thus accept two arguments.
diff --git a/media/libaudioclient/include/media/AudioEffect.h b/media/libaudioclient/include/media/AudioEffect.h
index ee262f3..56884a3 100644
--- a/media/libaudioclient/include/media/AudioEffect.h
+++ b/media/libaudioclient/include/media/AudioEffect.h
@@ -277,7 +277,7 @@
static status_t removeStreamDefaultEffect(audio_unique_id_t id);
/*
- * Events used by callback function (effect_callback_t).
+ * Events used by callback function (legacy_callback_t).
*/
enum event_type {
EVENT_CONTROL_STATUS_CHANGED = 0,
@@ -287,6 +287,47 @@
EVENT_FRAMES_PROCESSED = 4,
};
+ class IAudioEffectCallback : public virtual RefBase {
+ friend AudioEffect;
+ protected:
+ /* The event is received when an application loses or
+ * gains the control of the effect engine. Loss of control happens
+ * if another application requests the use of the engine by creating an AudioEffect for
+ * the same effect type but with a higher priority. Control is returned when the
+ * application having the control deletes its AudioEffect object.
+ * @param isGranted: True if control has been granted. False if stolen.
+ */
+ virtual void onControlStatusChanged([[maybe_unused]] bool isGranted) {}
+
+ /* The event is received by all applications not having the
+ * control of the effect engine when the effect is enabled or disabled.
+ * @param isEnabled: True if enabled. False if disabled.
+ */
+ virtual void onEnableStatusChanged([[maybe_unused]] bool isEnabled) {}
+
+ /* The event is received by all applications not having the
+ * control of the effect engine when an effect parameter is changed.
+ * @param param: A vector containing the raw bytes of a effect_param_type containing
+ * raw data representing a param type, value pair.
+ */
+ // TODO pass an AIDL parcel instead of effect_param_type
+ virtual void onParameterChanged([[maybe_unused]] std::vector<uint8_t> param) {}
+
+ /* The event is received when the binder connection to the mediaserver
+ * is no longer valid. Typically the server has been killed.
+ * @param errorCode: A code representing the type of error.
+ */
+ virtual void onError([[maybe_unused]] status_t errorCode) {}
+
+
+ /* The event is received when the audio server has processed a block of
+ * data.
+ * @param framesProcessed: The number of frames the audio server has
+ * processed.
+ */
+ virtual void onFramesProcessed([[maybe_unused]] int32_t framesProcessed) {}
+ };
+
/* Callback function notifying client application of a change in effect engine state or
* configuration.
* An effect engine can be shared by several applications but only one has the control
@@ -315,7 +356,7 @@
* - EVENT_ERROR: status_t indicating the error (DEAD_OBJECT when media server dies).
*/
- typedef void (*effect_callback_t)(int32_t event, void* user, void *info);
+ typedef void (*legacy_callback_t)(int32_t event, void* user, void *info);
/* Constructor.
@@ -360,7 +401,7 @@
* priority: requested priority for effect control: the priority level corresponds to the
* value of priority parameter: negative values indicate lower priorities, positive values
* higher priorities, 0 being the normal priority.
- * cbf: optional callback function (see effect_callback_t)
+ * cbf: optional callback function (see legacy_callback_t)
* user: pointer to context for use by the callback receiver.
* sessionId: audio session this effect is associated to.
* If equal to AUDIO_SESSION_OUTPUT_MIX, the effect will be global to
@@ -383,10 +424,20 @@
* - NO_INIT: audio flinger or audio hardware not initialized
*/
status_t set(const effect_uuid_t *type,
- const effect_uuid_t *uuid = NULL,
+ const effect_uuid_t *uuid = nullptr,
int32_t priority = 0,
- effect_callback_t cbf = NULL,
- void* user = NULL,
+ const wp<IAudioEffectCallback>& callback = nullptr,
+ audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX,
+ audio_io_handle_t io = AUDIO_IO_HANDLE_NONE,
+ const AudioDeviceTypeAddr& device = {},
+ bool probe = false,
+ bool notifyFramesProcessed = false);
+
+ status_t set(const effect_uuid_t *type,
+ const effect_uuid_t *uuid,
+ int32_t priority,
+ legacy_callback_t cbf,
+ void* user,
audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX,
audio_io_handle_t io = AUDIO_IO_HANDLE_NONE,
const AudioDeviceTypeAddr& device = {},
@@ -396,10 +447,21 @@
* Same as above but with type and uuid specified by character strings.
*/
status_t set(const char *typeStr,
- const char *uuidStr = NULL,
+ const char *uuidStr = nullptr,
int32_t priority = 0,
- effect_callback_t cbf = NULL,
- void* user = NULL,
+ const wp<IAudioEffectCallback>& callback = nullptr,
+ audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX,
+ audio_io_handle_t io = AUDIO_IO_HANDLE_NONE,
+ const AudioDeviceTypeAddr& device = {},
+ bool probe = false,
+ bool notifyFramesProcessed = false);
+
+
+ status_t set(const char *typeStr,
+ const char *uuidStr,
+ int32_t priority,
+ legacy_callback_t cbf,
+ void* user,
audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX,
audio_io_handle_t io = AUDIO_IO_HANDLE_NONE,
const AudioDeviceTypeAddr& device = {},
@@ -535,18 +597,19 @@
protected:
android::content::AttributionSourceState mClientAttributionSource; // source for app op checks.
- bool mEnabled = false; // enable state
- audio_session_t mSessionId = AUDIO_SESSION_OUTPUT_MIX; // audio session ID
- int32_t mPriority = 0; // priority for effect control
- status_t mStatus = NO_INIT; // effect status
- bool mProbe = false; // effect created in probe mode: all commands
- // are no ops because mIEffect is NULL
- effect_callback_t mCbf = nullptr; // callback function for status, control and
- // parameter changes notifications
- void* mUserData = nullptr;// client context for callback function
- effect_descriptor_t mDescriptor = {}; // effect descriptor
- int32_t mId = -1; // system wide unique effect engine instance ID
- Mutex mLock; // Mutex for mEnabled access
+ bool mEnabled = false; // enable state
+ audio_session_t mSessionId = AUDIO_SESSION_OUTPUT_MIX; // audio session ID
+ int32_t mPriority = 0; // priority for effect control
+ status_t mStatus = NO_INIT; // effect status
+ bool mProbe = false; // effect created in probe mode: all commands
+ // are no ops because mIEffect is nullptr
+
+ wp<IAudioEffectCallback> mCallback = nullptr; // callback interface for status, control and
+ // parameter changes notifications
+ sp<IAudioEffectCallback> mLegacyWrapper = nullptr;
+ effect_descriptor_t mDescriptor = {}; // effect descriptor
+ int32_t mId = -1; // system wide unique effect engine instance ID
+ Mutex mLock; // Mutex for mEnabled access
// IEffectClient
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 11eb070..baefee3 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -30,6 +30,7 @@
#include <android/media/ISpatializer.h>
#include <android/media/audio/common/AudioMMapPolicyInfo.h>
#include <android/media/audio/common/AudioMMapPolicyType.h>
+#include <android/media/audio/common/AudioPort.h>
#include <media/AidlConversionUtil.h>
#include <media/AudioContainers.h>
#include <media/AudioDeviceTypeAddr.h>
@@ -263,8 +264,8 @@
// IAudioPolicyService interface (see AudioPolicyInterface for method descriptions)
//
static void onNewAudioModulesAvailable();
- static status_t setDeviceConnectionState(audio_devices_t device, audio_policy_dev_state_t state,
- const char *device_address, const char *device_name,
+ static status_t setDeviceConnectionState(audio_policy_dev_state_t state,
+ const android::media::audio::common::AudioPort& port,
audio_format_t encodedFormat);
static audio_policy_dev_state_t getDeviceConnectionState(audio_devices_t device,
const char *device_address);
@@ -437,13 +438,16 @@
audio_format_t *surroundFormats);
static status_t setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled);
- static status_t setAssistantUid(uid_t uid);
- static status_t setHotwordDetectionServiceUid(uid_t uid);
+ static status_t setAssistantServicesUids(const std::vector<uid_t>& uids);
+ static status_t setActiveAssistantServicesUids(const std::vector<uid_t>& activeUids);
+
static status_t setA11yServicesUids(const std::vector<uid_t>& uids);
static status_t setCurrentImeUid(uid_t uid);
static bool isHapticPlaybackSupported();
+ static bool isUltrasoundSupported();
+
static status_t listAudioProductStrategies(AudioProductStrategyVector &strategies);
static status_t getProductStrategyFromAudioAttributes(
const AudioAttributes &aa, product_strategy_t &productStrategy,
@@ -550,6 +554,16 @@
audio_direct_mode_t *directMode);
+ /**
+ * Query which direct audio profiles are available for the specified audio attributes.
+ * @param attr audio attributes describing the playback use case
+ * @param audioProfiles out: a vector of audio profiles
+ * @return NO_ERROR in case of success, DEAD_OBJECT, NO_INIT, BAD_VALUE, PERMISSION_DENIED
+ * in case of error.
+ */
+ static status_t getDirectProfilesForAttributes(const audio_attributes_t* attr,
+ std::vector<audio_profile>* audioProfiles);
+
// A listener for capture state changes.
class CaptureStateListener : public virtual RefBase {
public:
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index d777124..1708cc7 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -1350,6 +1350,7 @@
sp<IAudioTrackCallback> mLegacyCallbackWrapper; // wrapper for legacy callback interface
// for notification APIs
+ bool mInitialized = false; // Set after track is initialized
// next 2 fields are const after constructor or set()
uint32_t mNotificationFramesReq; // requested number of frames between each
// notification callback,
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index b4ee4dc..e047378 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -358,6 +358,8 @@
virtual int32_t getAAudioMixerBurstCount() = 0;
virtual int32_t getAAudioHardwareBurstMinUsec() = 0;
+
+ virtual status_t setDeviceConnectedState(const struct audio_port_v7 *port, bool connected) = 0;
};
/**
@@ -454,14 +456,12 @@
status_t setVibratorInfos(const std::vector<media::AudioVibratorInfo>& vibratorInfos) override;
status_t updateSecondaryOutputs(
const TrackSecondaryOutputsMap& trackSecondaryOutputs) override;
-
status_t getMmapPolicyInfos(
media::audio::common::AudioMMapPolicyType policyType,
std::vector<media::audio::common::AudioMMapPolicyInfo> *policyInfos) override;
-
int32_t getAAudioMixerBurstCount() override;
-
int32_t getAAudioHardwareBurstMinUsec() override;
+ status_t setDeviceConnectedState(const struct audio_port_v7 *port, bool connected) override;
private:
const sp<media::IAudioFlingerService> mDelegate;
@@ -550,6 +550,7 @@
GET_MMAP_POLICY_INFOS = media::BnAudioFlingerService::TRANSACTION_getMmapPolicyInfos,
GET_AAUDIO_MIXER_BURST_COUNT = media::BnAudioFlingerService::TRANSACTION_getAAudioMixerBurstCount,
GET_AAUDIO_HARDWARE_BURST_MIN_USEC = media::BnAudioFlingerService::TRANSACTION_getAAudioHardwareBurstMinUsec,
+ SET_DEVICE_CONNECTED_STATE = media::BnAudioFlingerService::TRANSACTION_setDeviceConnectedState,
};
/**
@@ -669,6 +670,7 @@
std::vector<media::audio::common::AudioMMapPolicyInfo> *_aidl_return) override;
Status getAAudioMixerBurstCount(int32_t* _aidl_return) override;
Status getAAudioHardwareBurstMinUsec(int32_t* _aidl_return) override;
+ Status setDeviceConnectedState(const media::AudioPort& port, bool connected) override;
private:
const sp<AudioFlingerServerAdapter::Delegate> mDelegate;
diff --git a/media/libaudioclient/include/media/PolicyAidlConversion.h b/media/libaudioclient/include/media/PolicyAidlConversion.h
index 2296fdb..54e778e 100644
--- a/media/libaudioclient/include/media/PolicyAidlConversion.h
+++ b/media/libaudioclient/include/media/PolicyAidlConversion.h
@@ -37,11 +37,6 @@
namespace android {
-ConversionResult<volume_group_t>
-aidl2legacy_int32_t_volume_group_t(int32_t aidl);
-ConversionResult<int32_t>
-legacy2aidl_volume_group_t_int32_t(volume_group_t legacy);
-
ConversionResult<product_strategy_t>
aidl2legacy_int32_t_product_strategy_t(int32_t aidl);
ConversionResult<int32_t>
diff --git a/media/libaudioclient/tests/test_create_audiorecord.cpp b/media/libaudioclient/tests/test_create_audiorecord.cpp
index 1cbcb71..2e0883b 100644
--- a/media/libaudioclient/tests/test_create_audiorecord.cpp
+++ b/media/libaudioclient/tests/test_create_audiorecord.cpp
@@ -98,14 +98,14 @@
attributes.source = inputSource;
sp<AudioRecord> record = new AudioRecord(attributionSource);
+ const auto emptyCallback = sp<AudioRecord::IAudioRecordCallback>::make();
record->set(AUDIO_SOURCE_DEFAULT,
sampleRate,
format,
channelMask,
frameCount,
- fast ? callback : nullptr,
- nullptr,
+ fast ? emptyCallback : nullptr,
notificationFrames,
false,
sessionId,
diff --git a/media/libaudioclient/tests/test_create_audiotrack.cpp b/media/libaudioclient/tests/test_create_audiotrack.cpp
index cf9b925..e7231d3 100644
--- a/media/libaudioclient/tests/test_create_audiotrack.cpp
+++ b/media/libaudioclient/tests/test_create_audiotrack.cpp
@@ -19,6 +19,7 @@
#include <string.h>
#include <unistd.h>
+#include <android/content/AttributionSourceState.h>
#include <binder/MemoryBase.h>
#include <binder/MemoryDealer.h>
#include <binder/MemoryHeapBase.h>
@@ -108,17 +109,15 @@
memset(&attributes, 0, sizeof(attributes));
attributes.content_type = contentType;
attributes.usage = usage;
-
sp<AudioTrack> track = new AudioTrack();
-
+ const auto emptyCallback = sp<AudioTrack::IAudioTrackCallback>::make();
track->set(AUDIO_STREAM_DEFAULT,
sampleRate,
format,
channelMask,
frameCount,
flags,
- (fast || offload) ? callback : nullptr,
- nullptr,
+ (fast || offload) ? emptyCallback : nullptr,
notificationFrames,
sharedBuffer,
false,
@@ -126,8 +125,7 @@
((fast && sharedBuffer == 0) || offload) ?
AudioTrack::TRANSFER_CALLBACK : AudioTrack::TRANSFER_DEFAULT,
offload ? &offloadInfo : nullptr,
- getuid(),
- getpid(),
+ AttributionSourceState(),
&attributes,
false,
1.0f,
diff --git a/media/libaudioclient/tests/test_create_utils.cpp b/media/libaudioclient/tests/test_create_utils.cpp
index 8aa1f13..caf5227 100644
--- a/media/libaudioclient/tests/test_create_utils.cpp
+++ b/media/libaudioclient/tests/test_create_utils.cpp
@@ -68,10 +68,6 @@
return true;
}
-void callback(int event __unused, void* user __unused, void *info __unused)
-{
-}
-
int main(int argc, char **argv, test_func_t testFunc)
{
FILE *inputFile = nullptr;
diff --git a/media/libaudioclient/tests/test_create_utils.h b/media/libaudioclient/tests/test_create_utils.h
index 2ad646e..9a6f9fa 100644
--- a/media/libaudioclient/tests/test_create_utils.h
+++ b/media/libaudioclient/tests/test_create_utils.h
@@ -31,7 +31,6 @@
bool checkVersion(FILE *inputFile, const char *version);
-void callback(int event, void* user, void *info);
typedef int (*test_func_t)(FILE *inputFile, int outputFileFd);
diff --git a/media/libaudiofoundation/Android.bp b/media/libaudiofoundation/Android.bp
index 727b86f..159f898 100644
--- a/media/libaudiofoundation/Android.bp
+++ b/media/libaudiofoundation/Android.bp
@@ -11,6 +11,10 @@
name: "libaudiofoundation_headers",
vendor_available: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ ],
export_include_dirs: ["include"],
header_libs: [
diff --git a/media/libaudiofoundation/AudioProfile.cpp b/media/libaudiofoundation/AudioProfile.cpp
index 9a67bb7..734fa9c 100644
--- a/media/libaudiofoundation/AudioProfile.cpp
+++ b/media/libaudiofoundation/AudioProfile.cpp
@@ -154,6 +154,26 @@
ConversionResult<AudioProfile::Aidl>
AudioProfile::toParcelable(bool isInput) const {
+ media::audio::common::AudioProfile parcelable = VALUE_OR_RETURN(toCommonParcelable(isInput));
+ media::AudioProfileSys parcelableSys;
+ parcelableSys.isDynamicFormat = mIsDynamicFormat;
+ parcelableSys.isDynamicChannels = mIsDynamicChannels;
+ parcelableSys.isDynamicRate = mIsDynamicRate;
+ return std::make_pair(parcelable, parcelableSys);
+}
+
+ConversionResult<sp<AudioProfile>> AudioProfile::fromParcelable(
+ const AudioProfile::Aidl& aidl, bool isInput) {
+ sp<AudioProfile> legacy = VALUE_OR_RETURN(fromCommonParcelable(aidl.first, isInput));
+ const auto& parcelableSys = aidl.second;
+ legacy->mIsDynamicFormat = parcelableSys.isDynamicFormat;
+ legacy->mIsDynamicChannels = parcelableSys.isDynamicChannels;
+ legacy->mIsDynamicRate = parcelableSys.isDynamicRate;
+ return legacy;
+}
+
+ConversionResult<media::audio::common::AudioProfile>
+AudioProfile::toCommonParcelable(bool isInput) const {
media::audio::common::AudioProfile parcelable;
parcelable.name = mName;
parcelable.format = VALUE_OR_RETURN(
@@ -164,44 +184,35 @@
// of using 'legacy2aidl_audio_profile_AudioProfile' from AidlConversion.
parcelable.channelMasks = VALUE_OR_RETURN(
convertContainer<std::vector<AudioChannelLayout>>(
- mChannelMasks,
- [isInput](audio_channel_mask_t m) {
- return legacy2aidl_audio_channel_mask_t_AudioChannelLayout(m, isInput);
- }));
+ mChannelMasks,
+ [isInput](audio_channel_mask_t m) {
+ return legacy2aidl_audio_channel_mask_t_AudioChannelLayout(m, isInput);
+ }));
parcelable.sampleRates = VALUE_OR_RETURN(
convertContainer<std::vector<int32_t>>(mSamplingRates,
convertIntegral<int32_t, uint32_t>));
parcelable.encapsulationType = VALUE_OR_RETURN(
legacy2aidl_audio_encapsulation_type_t_AudioEncapsulationType(mEncapsulationType));
- media::AudioProfileSys parcelableSys;
- parcelableSys.isDynamicFormat = mIsDynamicFormat;
- parcelableSys.isDynamicChannels = mIsDynamicChannels;
- parcelableSys.isDynamicRate = mIsDynamicRate;
- return std::make_pair(parcelable, parcelableSys);
+ return parcelable;
}
-ConversionResult<sp<AudioProfile>> AudioProfile::fromParcelable(
- const AudioProfile::Aidl& aidl, bool isInput) {
+ConversionResult<sp<AudioProfile>> AudioProfile::fromCommonParcelable(
+ const media::audio::common::AudioProfile& aidl, bool isInput) {
sp<AudioProfile> legacy = new AudioProfile();
- const auto& parcelable = aidl.first;
- legacy->mName = parcelable.name;
+ legacy->mName = aidl.name;
legacy->mFormat = VALUE_OR_RETURN(
- aidl2legacy_AudioFormatDescription_audio_format_t(parcelable.format));
+ aidl2legacy_AudioFormatDescription_audio_format_t(aidl.format));
legacy->mChannelMasks = VALUE_OR_RETURN(
- convertContainer<ChannelMaskSet>(parcelable.channelMasks,
- [isInput](const AudioChannelLayout& l) {
- return aidl2legacy_AudioChannelLayout_audio_channel_mask_t(l, isInput);
- }));
+ convertContainer<ChannelMaskSet>(aidl.channelMasks,
+ [isInput](const AudioChannelLayout& l) {
+ return aidl2legacy_AudioChannelLayout_audio_channel_mask_t(l, isInput);
+ }));
legacy->mSamplingRates = VALUE_OR_RETURN(
- convertContainer<SampleRateSet>(parcelable.sampleRates,
+ convertContainer<SampleRateSet>(aidl.sampleRates,
convertIntegral<uint32_t, int32_t>));
legacy->mEncapsulationType = VALUE_OR_RETURN(
aidl2legacy_AudioEncapsulationType_audio_encapsulation_type_t(
- parcelable.encapsulationType));
- const auto& parcelableSys = aidl.second;
- legacy->mIsDynamicFormat = parcelableSys.isDynamicFormat;
- legacy->mIsDynamicChannels = parcelableSys.isDynamicChannels;
- legacy->mIsDynamicRate = parcelableSys.isDynamicRate;
+ aidl.encapsulationType));
return legacy;
}
@@ -215,6 +226,16 @@
return legacy->toParcelable(isInput);
}
+ConversionResult<sp<AudioProfile>>
+aidl2legacy_AudioProfile_common(const media::audio::common::AudioProfile& aidl, bool isInput) {
+ return AudioProfile::fromCommonParcelable(aidl, isInput);
+}
+
+ConversionResult<media::audio::common::AudioProfile>
+legacy2aidl_AudioProfile_common(const sp<AudioProfile>& legacy, bool isInput) {
+ return legacy->toCommonParcelable(isInput);
+}
+
ssize_t AudioProfileVector::add(const sp<AudioProfile> &profile)
{
ssize_t index = size();
diff --git a/media/libaudiofoundation/include/media/AudioProfile.h b/media/libaudiofoundation/include/media/AudioProfile.h
index d7cddb7..c3a0fb2 100644
--- a/media/libaudiofoundation/include/media/AudioProfile.h
+++ b/media/libaudiofoundation/include/media/AudioProfile.h
@@ -85,6 +85,11 @@
static ConversionResult<sp<AudioProfile>> fromParcelable(
const Aidl& aidl, bool isInput);
+ ConversionResult<media::audio::common::AudioProfile>
+ toCommonParcelable(bool isInput) const;
+ static ConversionResult<sp<AudioProfile>> fromCommonParcelable(
+ const media::audio::common::AudioProfile& aidl, bool isInput);
+
private:
std::string mName;
@@ -108,6 +113,11 @@
ConversionResult<AudioProfile::Aidl>
legacy2aidl_AudioProfile(const sp<AudioProfile>& legacy, bool isInput);
+ConversionResult<sp<AudioProfile>>
+aidl2legacy_AudioProfile_common(const media::audio::common::AudioProfile& aidl, bool isInput);
+ConversionResult<media::audio::common::AudioProfile>
+legacy2aidl_AudioProfile_common(const sp<AudioProfile>& legacy, bool isInput);
+
class AudioProfileVector : public std::vector<sp<AudioProfile>>
{
public:
diff --git a/media/libaudiohal/Android.bp b/media/libaudiohal/Android.bp
index 5fe74f9..5f63e8d 100644
--- a/media/libaudiohal/Android.bp
+++ b/media/libaudiohal/Android.bp
@@ -27,6 +27,7 @@
"libaudiohal@5.0",
"libaudiohal@6.0",
"libaudiohal@7.0",
+ "libaudiohal@7.1",
],
shared_libs: [
diff --git a/media/libaudiohal/FactoryHalHidl.cpp b/media/libaudiohal/FactoryHalHidl.cpp
index c19d2c2..804edcc 100644
--- a/media/libaudiohal/FactoryHalHidl.cpp
+++ b/media/libaudiohal/FactoryHalHidl.cpp
@@ -31,6 +31,7 @@
/** Supported HAL versions, in order of preference.
*/
const char* sAudioHALVersions[] = {
+ "7.1",
"7.0",
"6.0",
"5.0",
diff --git a/media/libaudiohal/impl/Android.bp b/media/libaudiohal/impl/Android.bp
index d6576f5..dd435fe 100644
--- a/media/libaudiohal/impl/Android.bp
+++ b/media/libaudiohal/impl/Android.bp
@@ -7,22 +7,29 @@
default_applicable_licenses: ["frameworks_av_license"],
}
+filegroup {
+ name: "audio_core_hal_client_sources",
+ srcs: [
+ "DeviceHalHidl.cpp",
+ "DevicesFactoryHalHidl.cpp",
+ "StreamHalHidl.cpp",
+ ],
+}
+
+filegroup {
+ name: "audio_effect_hal_client_sources",
+ srcs: [
+ "EffectBufferHalHidl.cpp",
+ "EffectHalHidl.cpp",
+ "EffectsFactoryHalHidl.cpp",
+ ],
+}
+
cc_defaults {
name: "libaudiohal_default",
srcs: [
- "DeviceHalLocal.cpp",
- "DevicesFactoryHalHybrid.cpp",
- "DevicesFactoryHalLocal.cpp",
- "StreamHalLocal.cpp",
-
"ConversionHelperHidl.cpp",
- "DeviceHalHidl.cpp",
- "DevicesFactoryHalHidl.cpp",
- "EffectBufferHalHidl.cpp",
- "EffectHalHidl.cpp",
- "EffectsFactoryHalHidl.cpp",
- "StreamHalHidl.cpp",
],
cflags: [
@@ -66,6 +73,10 @@
cc_library_shared {
name: "libaudiohal@4.0",
defaults: ["libaudiohal_default"],
+ srcs: [
+ ":audio_core_hal_client_sources",
+ ":audio_effect_hal_client_sources",
+ ],
shared_libs: [
"android.hardware.audio.common@4.0",
"android.hardware.audio.common@4.0-util",
@@ -84,6 +95,10 @@
cc_library_shared {
name: "libaudiohal@5.0",
defaults: ["libaudiohal_default"],
+ srcs: [
+ ":audio_core_hal_client_sources",
+ ":audio_effect_hal_client_sources",
+ ],
shared_libs: [
"android.hardware.audio.common@5.0",
"android.hardware.audio.common@5.0-util",
@@ -102,6 +117,10 @@
cc_library_shared {
name: "libaudiohal@6.0",
defaults: ["libaudiohal_default"],
+ srcs: [
+ ":audio_core_hal_client_sources",
+ ":audio_effect_hal_client_sources",
+ ],
shared_libs: [
"android.hardware.audio.common@6.0",
"android.hardware.audio.common@6.0-util",
@@ -120,6 +139,10 @@
cc_library_shared {
name: "libaudiohal@7.0",
defaults: ["libaudiohal_default"],
+ srcs: [
+ ":audio_core_hal_client_sources",
+ ":audio_effect_hal_client_sources",
+ ],
shared_libs: [
"android.hardware.audio.common@7.0",
"android.hardware.audio.common@7.0-util",
@@ -134,3 +157,25 @@
"-include common/all-versions/VersionMacro.h",
]
}
+
+cc_library_shared {
+ name: "libaudiohal@7.1",
+ defaults: ["libaudiohal_default"],
+ srcs: [
+ ":audio_core_hal_client_sources",
+ ],
+ shared_libs: [
+ "android.hardware.audio.common@7.0",
+ "android.hardware.audio.common@7.1-util",
+ "android.hardware.audio@7.0",
+ "android.hardware.audio@7.1",
+ "android.hardware.audio@7.1-util",
+ ],
+ cflags: [
+ "-DMAJOR_VERSION=7",
+ "-DMINOR_VERSION=1",
+ "-DCOMMON_TYPES_MINOR_VERSION=0",
+ "-DCORE_TYPES_MINOR_VERSION=0",
+ "-include common/all-versions/VersionMacro.h",
+ ]
+}
diff --git a/media/libaudiohal/impl/ConversionHelperHidl.cpp b/media/libaudiohal/impl/ConversionHelperHidl.cpp
index 0503698..1d34814 100644
--- a/media/libaudiohal/impl/ConversionHelperHidl.cpp
+++ b/media/libaudiohal/impl/ConversionHelperHidl.cpp
@@ -24,10 +24,9 @@
#include "ConversionHelperHidl.h"
namespace android {
-namespace CPP_VERSION {
-using namespace ::android::hardware::audio::common::CPP_VERSION;
-using namespace ::android::hardware::audio::CPP_VERSION;
+using namespace ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION;
+using namespace ::android::hardware::audio::CORE_TYPES_CPP_VERSION;
// static
status_t ConversionHelperHidl::keysFromHal(const String8& keys, hidl_vec<hidl_string> *hidlKeys) {
@@ -129,5 +128,4 @@
ALOGE("%s %p %s: %s (from rpc)", mClassName, this, funcName, description);
}
-} // namespace CPP_VERSION
} // namespace android
diff --git a/media/libaudiohal/impl/ConversionHelperHidl.h b/media/libaudiohal/impl/ConversionHelperHidl.h
index 2909013..9368551 100644
--- a/media/libaudiohal/impl/ConversionHelperHidl.h
+++ b/media/libaudiohal/impl/ConversionHelperHidl.h
@@ -17,22 +17,21 @@
#ifndef ANDROID_HARDWARE_CONVERSION_HELPER_HIDL_H
#define ANDROID_HARDWARE_CONVERSION_HELPER_HIDL_H
-#include PATH(android/hardware/audio/FILE_VERSION/types.h)
+#include PATH(android/hardware/audio/CORE_TYPES_FILE_VERSION/types.h)
#include <hidl/HidlSupport.h>
#include <system/audio.h>
#include <utils/String8.h>
#include <utils/String16.h>
#include <utils/Vector.h>
-using ::android::hardware::audio::CPP_VERSION::ParameterValue;
-using CoreResult = ::android::hardware::audio::CPP_VERSION::Result;
+using ::android::hardware::audio::CORE_TYPES_CPP_VERSION::ParameterValue;
+using CoreResult = ::android::hardware::audio::CORE_TYPES_CPP_VERSION::Result;
using ::android::hardware::Return;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
namespace android {
-namespace CPP_VERSION {
class ConversionHelperHidl {
protected:
@@ -85,7 +84,6 @@
void emitError(const char* funcName, const char* description);
};
-} // namespace CPP_VERSION
} // namespace android
#endif // ANDROID_HARDWARE_CONVERSION_HELPER_HIDL_H
diff --git a/media/libaudiohal/impl/DeviceHalHidl.cpp b/media/libaudiohal/impl/DeviceHalHidl.cpp
index 47acb19..16863e4 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalHidl.cpp
@@ -31,27 +31,40 @@
#include <util/CoreUtils.h>
#include "DeviceHalHidl.h"
-#include "EffectHalHidl.h"
#include "ParameterUtils.h"
#include "StreamHalHidl.h"
-using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils;
+using ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::implementation::HidlUtils;
using ::android::hardware::audio::common::utils::EnumBitfield;
-using ::android::hardware::audio::CPP_VERSION::implementation::CoreUtils;
+using ::android::hardware::audio::CORE_TYPES_CPP_VERSION::implementation::CoreUtils;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
namespace android {
-namespace CPP_VERSION {
-using namespace ::android::hardware::audio::common::CPP_VERSION;
-using namespace ::android::hardware::audio::CPP_VERSION;
+using namespace ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION;
+using namespace ::android::hardware::audio::CORE_TYPES_CPP_VERSION;
-using EffectHalHidl = ::android::effect::CPP_VERSION::EffectHalHidl;
+DeviceHalHidl::DeviceHalHidl(const sp<::android::hardware::audio::CPP_VERSION::IDevice>& device)
+ : ConversionHelperHidl("Device"), mDevice(device) {
+}
-DeviceHalHidl::DeviceHalHidl(const sp<IDevice>& device)
- : ConversionHelperHidl("Device"), mDevice(device),
- mPrimaryDevice(IPrimaryDevice::castFrom(device)) {
+DeviceHalHidl::DeviceHalHidl(
+ const sp<::android::hardware::audio::CPP_VERSION::IPrimaryDevice>& device)
+ : ConversionHelperHidl("Device"),
+#if MAJOR_VERSION <= 6 || (MAJOR_VERSION == 7 && MINOR_VERSION == 0)
+ mDevice(device),
+#endif
+ mPrimaryDevice(device) {
+#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
+ auto getDeviceRet = mPrimaryDevice->getDevice();
+ if (getDeviceRet.isOk()) {
+ mDevice = getDeviceRet;
+ } else {
+ ALOGE("Call to IPrimaryDevice.getDevice has failed: %s",
+ getDeviceRet.description().c_str());
+ }
+#endif
}
DeviceHalHidl::~DeviceHalHidl() {
@@ -205,17 +218,32 @@
status != OK) {
return status;
}
+
+#if !(MAJOR_VERSION == 7 && MINOR_VERSION == 1)
+ //TODO: b/193496180 use spatializer flag at audio HAL when available
+ if ((flags & AUDIO_OUTPUT_FLAG_SPATIALIZER) != 0) {
+ flags = (audio_output_flags_t)(flags & ~AUDIO_OUTPUT_FLAG_SPATIALIZER);
+ flags = (audio_output_flags_t)
+ (flags | AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_DEEP_BUFFER);
+ }
+#endif
+
CoreUtils::AudioOutputFlags hidlFlags;
if (status_t status = CoreUtils::audioOutputFlagsFromHal(flags, &hidlFlags); status != OK) {
return status;
}
Result retval = Result::NOT_INITIALIZED;
+#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
+ Return<void> ret = mDevice->openOutputStream_7_1(
+#else
Return<void> ret = mDevice->openOutputStream(
+#endif
handle, hidlDevice, hidlConfig, hidlFlags,
#if MAJOR_VERSION >= 4
{} /* metadata */,
#endif
- [&](Result r, const sp<IStreamOut>& result, const AudioConfig& suggestedConfig) {
+ [&](Result r, const sp<::android::hardware::audio::CPP_VERSION::IStreamOut>& result,
+ const AudioConfig& suggestedConfig) {
retval = r;
if (retval == Result::OK) {
*outStream = new StreamOutHalHidl(result);
@@ -285,7 +313,9 @@
#endif
Return<void> ret = mDevice->openInputStream(
handle, hidlDevice, hidlConfig, hidlFlags, sinkMetadata,
- [&](Result r, const sp<IStreamIn>& result, const AudioConfig& suggestedConfig) {
+ [&](Result r,
+ const sp<::android::hardware::audio::CORE_TYPES_CPP_VERSION::IStreamIn>& result,
+ const AudioConfig& suggestedConfig) {
retval = r;
if (retval == Result::OK) {
*inStream = new StreamInHalHidl(result);
@@ -433,8 +463,7 @@
audio_port_handle_t device, sp<EffectHalInterface> effect) {
if (mDevice == 0) return NO_INIT;
return processReturn("addDeviceEffect", mDevice->addDeviceEffect(
- static_cast<AudioPortHandle>(device),
- static_cast<EffectHalHidl*>(effect.get())->effectId()));
+ static_cast<AudioPortHandle>(device), effect->effectId()));
}
#else
status_t DeviceHalHidl::addDeviceEffect(
@@ -448,8 +477,7 @@
audio_port_handle_t device, sp<EffectHalInterface> effect) {
if (mDevice == 0) return NO_INIT;
return processReturn("removeDeviceEffect", mDevice->removeDeviceEffect(
- static_cast<AudioPortHandle>(device),
- static_cast<EffectHalHidl*>(effect.get())->effectId()));
+ static_cast<AudioPortHandle>(device), effect->effectId()));
}
#else
status_t DeviceHalHidl::removeDeviceEffect(
@@ -458,6 +486,44 @@
}
#endif
+status_t DeviceHalHidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
+ if (mDevice == 0) return NO_INIT;
+#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
+ if (supportsSetConnectedState7_1) {
+ AudioPort hidlPort;
+ if (status_t result = HidlUtils::audioPortFromHal(*port, &hidlPort); result != NO_ERROR) {
+ return result;
+ }
+ Return<Result> ret = mDevice->setConnectedState_7_1(hidlPort, connected);
+ if (!ret.isOk() || ret != Result::NOT_SUPPORTED) {
+ return processReturn("setConnectedState_7_1", ret);
+ } else if (ret == Result::OK) {
+ return NO_ERROR;
+ }
+ supportsSetConnectedState7_1 = false;
+ }
+#endif
+ DeviceAddress hidlAddress;
+ if (status_t result = CoreUtils::deviceAddressFromHal(
+ port->ext.device.type, port->ext.device.address, &hidlAddress);
+ result != NO_ERROR) {
+ return result;
+ }
+ return processReturn("setConnectedState", mDevice->setConnectedState(hidlAddress, connected));
+}
+
+error::Result<audio_hw_sync_t> DeviceHalHidl::getHwAvSync() {
+ if (mDevice == 0) return NO_INIT;
+ audio_hw_sync_t value;
+ Result result;
+ Return<void> ret = mDevice->getHwAvSync([&value, &result](Result r, audio_hw_sync_t v) {
+ value = v;
+ result = r;
+ });
+ RETURN_IF_ERROR(processReturn("getHwAvSync", ret, result));
+ return value;
+}
+
status_t DeviceHalHidl::dump(int fd, const Vector<String16>& args) {
if (mDevice == 0) return NO_INIT;
native_handle_t* hidlHandle = native_handle_create(1, 0);
@@ -481,5 +547,4 @@
return processReturn("dump", ret);
}
-} // namespace CPP_VERSION
} // namespace android
diff --git a/media/libaudiohal/impl/DeviceHalHidl.h b/media/libaudiohal/impl/DeviceHalHidl.h
index 9fd0ac0..8a97a55 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.h
+++ b/media/libaudiohal/impl/DeviceHalHidl.h
@@ -20,15 +20,11 @@
#include PATH(android/hardware/audio/FILE_VERSION/IDevice.h)
#include PATH(android/hardware/audio/FILE_VERSION/IPrimaryDevice.h)
#include <media/audiohal/DeviceHalInterface.h>
+#include <media/audiohal/EffectHalInterface.h>
#include "ConversionHelperHidl.h"
-using ::android::hardware::audio::CPP_VERSION::IDevice;
-using ::android::hardware::audio::CPP_VERSION::IPrimaryDevice;
-using ::android::hardware::Return;
-
namespace android {
-namespace CPP_VERSION {
class DeviceHalHidl : public DeviceHalInterface, public ConversionHelperHidl
{
@@ -136,15 +132,23 @@
return INVALID_OPERATION;
}
+ status_t setConnectedState(const struct audio_port_v7 *port, bool connected) override;
+
+ error::Result<audio_hw_sync_t> getHwAvSync() override;
+
status_t dump(int fd, const Vector<String16>& args) override;
private:
friend class DevicesFactoryHalHidl;
- sp<IDevice> mDevice;
- sp<IPrimaryDevice> mPrimaryDevice; // Null if it's not a primary device.
+ sp<::android::hardware::audio::CPP_VERSION::IDevice> mDevice;
+ // Null if it's not a primary device.
+ sp<::android::hardware::audio::CPP_VERSION::IPrimaryDevice> mPrimaryDevice;
+ bool supportsSetConnectedState7_1 = true;
// Can not be constructed directly by clients.
- explicit DeviceHalHidl(const sp<IDevice>& device);
+ explicit DeviceHalHidl(const sp<::android::hardware::audio::CPP_VERSION::IDevice>& device);
+ explicit DeviceHalHidl(
+ const sp<::android::hardware::audio::CPP_VERSION::IPrimaryDevice>& device);
// The destructor automatically closes the device.
virtual ~DeviceHalHidl();
@@ -152,7 +156,6 @@
template <typename HalPort> status_t getAudioPortImpl(HalPort *port);
};
-} // namespace CPP_VERSION
} // namespace android
#endif // ANDROID_HARDWARE_DEVICE_HAL_HIDL_H
diff --git a/media/libaudiohal/impl/DeviceHalLocal.cpp b/media/libaudiohal/impl/DeviceHalLocal.cpp
deleted file mode 100644
index e0304af..0000000
--- a/media/libaudiohal/impl/DeviceHalLocal.cpp
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright (C) 2016 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 "DeviceHalLocal"
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-
-#include "DeviceHalLocal.h"
-#include "StreamHalLocal.h"
-
-namespace android {
-namespace CPP_VERSION {
-
-DeviceHalLocal::DeviceHalLocal(audio_hw_device_t *dev)
- : mDev(dev) {
-}
-
-DeviceHalLocal::~DeviceHalLocal() {
- int status = audio_hw_device_close(mDev);
- ALOGW_IF(status, "Error closing audio hw device %p: %s", mDev, strerror(-status));
- mDev = 0;
-}
-
-status_t DeviceHalLocal::getSupportedDevices(uint32_t *devices) {
- if (mDev->get_supported_devices == NULL) return INVALID_OPERATION;
- *devices = mDev->get_supported_devices(mDev);
- return OK;
-}
-
-status_t DeviceHalLocal::initCheck() {
- return mDev->init_check(mDev);
-}
-
-status_t DeviceHalLocal::setVoiceVolume(float volume) {
- return mDev->set_voice_volume(mDev, volume);
-}
-
-status_t DeviceHalLocal::setMasterVolume(float volume) {
- if (mDev->set_master_volume == NULL) return INVALID_OPERATION;
- return mDev->set_master_volume(mDev, volume);
-}
-
-status_t DeviceHalLocal::getMasterVolume(float *volume) {
- if (mDev->get_master_volume == NULL) return INVALID_OPERATION;
- return mDev->get_master_volume(mDev, volume);
-}
-
-status_t DeviceHalLocal::setMode(audio_mode_t mode) {
- return mDev->set_mode(mDev, mode);
-}
-
-status_t DeviceHalLocal::setMicMute(bool state) {
- return mDev->set_mic_mute(mDev, state);
-}
-
-status_t DeviceHalLocal::getMicMute(bool *state) {
- return mDev->get_mic_mute(mDev, state);
-}
-
-status_t DeviceHalLocal::setMasterMute(bool state) {
- if (mDev->set_master_mute == NULL) return INVALID_OPERATION;
- return mDev->set_master_mute(mDev, state);
-}
-
-status_t DeviceHalLocal::getMasterMute(bool *state) {
- if (mDev->get_master_mute == NULL) return INVALID_OPERATION;
- return mDev->get_master_mute(mDev, state);
-}
-
-status_t DeviceHalLocal::setParameters(const String8& kvPairs) {
- return mDev->set_parameters(mDev, kvPairs.string());
-}
-
-status_t DeviceHalLocal::getParameters(const String8& keys, String8 *values) {
- char *halValues = mDev->get_parameters(mDev, keys.string());
- if (halValues != NULL) {
- values->setTo(halValues);
- free(halValues);
- } else {
- values->clear();
- }
- return OK;
-}
-
-status_t DeviceHalLocal::getInputBufferSize(
- const struct audio_config *config, size_t *size) {
- *size = mDev->get_input_buffer_size(mDev, config);
- return OK;
-}
-
-status_t DeviceHalLocal::openOutputStream(
- audio_io_handle_t handle,
- audio_devices_t deviceType,
- audio_output_flags_t flags,
- struct audio_config *config,
- const char *address,
- sp<StreamOutHalInterface> *outStream) {
- audio_stream_out_t *halStream;
- ALOGV("open_output_stream handle: %d devices: %x flags: %#x"
- "srate: %d format %#x channels %x address %s",
- handle, deviceType, flags,
- config->sample_rate, config->format, config->channel_mask,
- address);
- int openResut = mDev->open_output_stream(
- mDev, handle, deviceType, flags, config, &halStream, address);
- if (openResut == OK) {
- *outStream = new StreamOutHalLocal(halStream, this);
- }
- ALOGV("open_output_stream status %d stream %p", openResut, halStream);
- return openResut;
-}
-
-status_t DeviceHalLocal::openInputStream(
- audio_io_handle_t handle,
- audio_devices_t devices,
- struct audio_config *config,
- audio_input_flags_t flags,
- const char *address,
- audio_source_t source,
- audio_devices_t /*outputDevice*/,
- const char */*outputDeviceAddress*/,
- sp<StreamInHalInterface> *inStream) {
- audio_stream_in_t *halStream;
- ALOGV("open_input_stream handle: %d devices: %x flags: %#x "
- "srate: %d format %#x channels %x address %s source %d",
- handle, devices, flags,
- config->sample_rate, config->format, config->channel_mask,
- address, source);
- int openResult = mDev->open_input_stream(
- mDev, handle, devices, config, &halStream, flags, address, source);
- if (openResult == OK) {
- *inStream = new StreamInHalLocal(halStream, this);
- }
- ALOGV("open_input_stream status %d stream %p", openResult, inStream);
- return openResult;
-}
-
-status_t DeviceHalLocal::supportsAudioPatches(bool *supportsPatches) {
- *supportsPatches = version() >= AUDIO_DEVICE_API_VERSION_3_0;
- return OK;
-}
-
-status_t DeviceHalLocal::createAudioPatch(
- unsigned int num_sources,
- const struct audio_port_config *sources,
- unsigned int num_sinks,
- const struct audio_port_config *sinks,
- audio_patch_handle_t *patch) {
- if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
- return mDev->create_audio_patch(
- mDev, num_sources, sources, num_sinks, sinks, patch);
- } else {
- return INVALID_OPERATION;
- }
-}
-
-status_t DeviceHalLocal::releaseAudioPatch(audio_patch_handle_t patch) {
- if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
- return mDev->release_audio_patch(mDev, patch);
- } else {
- return INVALID_OPERATION;
- }
-}
-
-status_t DeviceHalLocal::getAudioPort(struct audio_port *port) {
- return mDev->get_audio_port(mDev, port);
-}
-
-status_t DeviceHalLocal::getAudioPort(struct audio_port_v7 *port) {
-#if MAJOR_VERSION >= 7
- if (version() >= AUDIO_DEVICE_API_VERSION_3_2) {
- // get_audio_port_v7 is mandatory if legacy HAL support this API version.
- return mDev->get_audio_port_v7(mDev, port);
- }
-#endif
- struct audio_port audioPort = {};
- audio_populate_audio_port(port, &audioPort);
- status_t status = getAudioPort(&audioPort);
- if (status == NO_ERROR) {
- audio_populate_audio_port_v7(&audioPort, port);
- }
- return status;
-}
-
-status_t DeviceHalLocal::setAudioPortConfig(const struct audio_port_config *config) {
- if (version() >= AUDIO_DEVICE_API_VERSION_3_0)
- return mDev->set_audio_port_config(mDev, config);
- else
- return INVALID_OPERATION;
-}
-
-#if MAJOR_VERSION == 2
-status_t DeviceHalLocal::getMicrophones(
- std::vector<media::MicrophoneInfo> *microphones __unused) {
- return INVALID_OPERATION;
-}
-#elif MAJOR_VERSION >= 4
-status_t DeviceHalLocal::getMicrophones(std::vector<media::MicrophoneInfo> *microphones) {
- if (mDev->get_microphones == NULL) return INVALID_OPERATION;
- size_t actual_mics = AUDIO_MICROPHONE_MAX_COUNT;
- audio_microphone_characteristic_t mic_array[AUDIO_MICROPHONE_MAX_COUNT];
- status_t status = mDev->get_microphones(mDev, &mic_array[0], &actual_mics);
- for (size_t i = 0; i < actual_mics; i++) {
- media::MicrophoneInfo microphoneInfo = media::MicrophoneInfo(mic_array[i]);
- microphones->push_back(microphoneInfo);
- }
- return status;
-}
-#endif
-
-// Local HAL implementation does not support effects
-status_t DeviceHalLocal::addDeviceEffect(
- audio_port_handle_t device __unused, sp<EffectHalInterface> effect __unused) {
- return INVALID_OPERATION;
-}
-
-status_t DeviceHalLocal::removeDeviceEffect(
- audio_port_handle_t device __unused, sp<EffectHalInterface> effect __unused) {
- return INVALID_OPERATION;
-}
-
-status_t DeviceHalLocal::dump(int fd, const Vector<String16>& /* args */) {
- return mDev->dump(mDev, fd);
-}
-
-void DeviceHalLocal::closeOutputStream(struct audio_stream_out *stream_out) {
- mDev->close_output_stream(mDev, stream_out);
-}
-
-void DeviceHalLocal::closeInputStream(struct audio_stream_in *stream_in) {
- mDev->close_input_stream(mDev, stream_in);
-}
-
-} // namespace CPP_VERSION
-} // namespace android
diff --git a/media/libaudiohal/impl/DeviceHalLocal.h b/media/libaudiohal/impl/DeviceHalLocal.h
deleted file mode 100644
index ee1d2c5..0000000
--- a/media/libaudiohal/impl/DeviceHalLocal.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2016 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_HARDWARE_DEVICE_HAL_LOCAL_H
-#define ANDROID_HARDWARE_DEVICE_HAL_LOCAL_H
-
-#include <hardware/audio.h>
-#include <media/audiohal/DeviceHalInterface.h>
-
-namespace android {
-namespace CPP_VERSION {
-
-class DeviceHalLocal : public DeviceHalInterface
-{
- public:
- // Sets the value of 'devices' to a bitmask of 1 or more values of audio_devices_t.
- virtual status_t getSupportedDevices(uint32_t *devices);
-
- // Check to see if the audio hardware interface has been initialized.
- virtual status_t initCheck();
-
- // Set the audio volume of a voice call. Range is between 0.0 and 1.0.
- virtual status_t setVoiceVolume(float volume);
-
- // Set the audio volume for all audio activities other than voice call.
- virtual status_t setMasterVolume(float volume);
-
- // Get the current master volume value for the HAL.
- virtual status_t getMasterVolume(float *volume);
-
- // Called when the audio mode changes.
- virtual status_t setMode(audio_mode_t mode);
-
- // Muting control.
- virtual status_t setMicMute(bool state);
- virtual status_t getMicMute(bool *state);
- virtual status_t setMasterMute(bool state);
- virtual status_t getMasterMute(bool *state);
-
- // Set global audio parameters.
- virtual status_t setParameters(const String8& kvPairs);
-
- // Get global audio parameters.
- virtual status_t getParameters(const String8& keys, String8 *values);
-
- // Returns audio input buffer size according to parameters passed.
- virtual status_t getInputBufferSize(const struct audio_config *config,
- size_t *size);
-
- // Creates and opens the audio hardware output stream. The stream is closed
- // by releasing all references to the returned object.
- virtual status_t openOutputStream(
- audio_io_handle_t handle,
- audio_devices_t devices,
- audio_output_flags_t flags,
- struct audio_config *config,
- const char *address,
- sp<StreamOutHalInterface> *outStream);
-
- // Creates and opens the audio hardware input stream. The stream is closed
- // by releasing all references to the returned object.
- virtual status_t openInputStream(
- audio_io_handle_t handle,
- audio_devices_t devices,
- struct audio_config *config,
- audio_input_flags_t flags,
- const char *address,
- audio_source_t source,
- audio_devices_t outputDevice,
- const char *outputDeviceAddress,
- sp<StreamInHalInterface> *inStream);
-
- // Returns whether createAudioPatch and releaseAudioPatch operations are supported.
- virtual status_t supportsAudioPatches(bool *supportsPatches);
-
- // Creates an audio patch between several source and sink ports.
- virtual status_t createAudioPatch(
- unsigned int num_sources,
- const struct audio_port_config *sources,
- unsigned int num_sinks,
- const struct audio_port_config *sinks,
- audio_patch_handle_t *patch);
-
- // Releases an audio patch.
- virtual status_t releaseAudioPatch(audio_patch_handle_t patch);
-
- // Fills the list of supported attributes for a given audio port.
- virtual status_t getAudioPort(struct audio_port *port);
-
- // Fills the list of supported attributes for a given audio port.
- virtual status_t getAudioPort(struct audio_port_v7 *port);
-
- // Set audio port configuration.
- virtual status_t setAudioPortConfig(const struct audio_port_config *config);
-
- // List microphones
- virtual status_t getMicrophones(std::vector<media::MicrophoneInfo> *microphones);
-
- status_t addDeviceEffect(audio_port_handle_t device, sp<EffectHalInterface> effect) override;
- status_t removeDeviceEffect(audio_port_handle_t device, sp<EffectHalInterface> effect) override;
-
- status_t getMmapPolicyInfos(
- media::audio::common::AudioMMapPolicyType policyType __unused,
- std::vector<media::audio::common::AudioMMapPolicyInfo> *policyInfos __unused) override {
- // This function will only be available on AIDL HAL.
- return INVALID_OPERATION;
- }
-
- int32_t getAAudioMixerBurstCount() override {
- // This function will only be available on AIDL HAL.
- return INVALID_OPERATION;
- }
-
- int32_t getAAudioHardwareBurstMinUsec() override {
- // This function will only be available on AIDL HAL.
- return INVALID_OPERATION;
- }
-
- status_t dump(int fd, const Vector<String16>& args) override;
-
- void closeOutputStream(struct audio_stream_out *stream_out);
- void closeInputStream(struct audio_stream_in *stream_in);
-
- uint32_t version() const { return mDev->common.version; }
-
- private:
- audio_hw_device_t *mDev;
-
- friend class DevicesFactoryHalLocal;
-
- // Can not be constructed directly by clients.
- explicit DeviceHalLocal(audio_hw_device_t *dev);
-
- // The destructor automatically closes the device.
- virtual ~DeviceHalLocal();
-};
-
-} // namespace CPP_VERSION
-} // namespace android
-
-#endif // ANDROID_HARDWARE_DEVICE_HAL_LOCAL_H
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp b/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
index 1c0eacb..8f3c907 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
+++ b/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
@@ -31,14 +31,13 @@
#include "DevicesFactoryHalHidl.h"
using ::android::hardware::audio::CPP_VERSION::IDevice;
-using ::android::hardware::audio::CPP_VERSION::Result;
+using ::android::hardware::audio::CORE_TYPES_CPP_VERSION::Result;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hidl::manager::V1_0::IServiceManager;
using ::android::hidl::manager::V1_0::IServiceNotification;
namespace android {
-namespace CPP_VERSION {
class ServiceNotificationListener : public IServiceNotification {
public:
@@ -115,14 +114,37 @@
if (status != OK) return status;
Result retval = Result::NOT_INITIALIZED;
for (const auto& factory : factories) {
- Return<void> ret = factory->openDevice(
- hidlId,
- [&](Result r, const sp<IDevice>& result) {
- retval = r;
- if (retval == Result::OK) {
- *device = new DeviceHalHidl(result);
- }
- });
+ Return<void> ret;
+ if (strcmp(name, AUDIO_HARDWARE_MODULE_ID_PRIMARY) == 0) {
+ // In V7.1 it's not possible to cast IDevice back to IPrimaryDevice,
+ // thus openPrimaryDevice must be used.
+#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
+ ret = factory->openPrimaryDevice_7_1(
+#else
+ ret = factory->openPrimaryDevice(
+#endif
+ [&](Result r,
+ const sp<::android::hardware::audio::CPP_VERSION::IPrimaryDevice>& result) {
+ retval = r;
+ if (retval == Result::OK) {
+ *device = new DeviceHalHidl(result);
+ }
+ });
+ } else {
+#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
+ ret = factory->openDevice_7_1(
+#else
+ ret = factory->openDevice(
+#endif
+ hidlId,
+ [&](Result r,
+ const sp<::android::hardware::audio::CPP_VERSION::IDevice>& result) {
+ retval = r;
+ if (retval == Result::OK) {
+ *device = new DeviceHalHidl(result);
+ }
+ });
+ }
if (!ret.isOk()) return FAILED_TRANSACTION;
switch (retval) {
// Device was found and was initialized successfully.
@@ -178,7 +200,8 @@
return NO_ERROR;
}
-void DevicesFactoryHalHidl::addDeviceFactory(sp<IDevicesFactory> factory, bool needToNotify) {
+void DevicesFactoryHalHidl::addDeviceFactory(
+ sp<::android::hardware::audio::CPP_VERSION::IDevicesFactory> factory, bool needToNotify) {
// It is assumed that the DevicesFactoryHalInterface instance is owned
// by AudioFlinger and thus have the same lifespan.
factory->linkToDeath(HalDeathHandler::getInstance(), 0 /*cookie*/);
@@ -198,10 +221,16 @@
}
}
-std::vector<sp<IDevicesFactory>> DevicesFactoryHalHidl::copyDeviceFactories() {
+std::vector<sp<::android::hardware::audio::CPP_VERSION::IDevicesFactory>>
+ DevicesFactoryHalHidl::copyDeviceFactories() {
std::lock_guard<std::mutex> lock(mLock);
return mDeviceFactories;
}
-} // namespace CPP_VERSION
+// Main entry-point to the shared library.
+extern "C" __attribute__((visibility("default"))) void* createIDevicesFactory() {
+ auto service = hardware::audio::CPP_VERSION::IDevicesFactory::getService();
+ return service ? new DevicesFactoryHalHidl(service) : nullptr;
+}
+
} // namespace android
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHidl.h b/media/libaudiohal/impl/DevicesFactoryHalHidl.h
index b46259b..ffd229d 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHidl.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalHidl.h
@@ -30,7 +30,6 @@
using ::android::hardware::audio::CPP_VERSION::IDevicesFactory;
namespace android {
-namespace CPP_VERSION {
class DevicesFactoryHalHidl : public DevicesFactoryHalInterface
{
@@ -61,7 +60,6 @@
virtual ~DevicesFactoryHalHidl() = default;
};
-} // namespace CPP_VERSION
} // namespace android
#endif // ANDROID_HARDWARE_DEVICES_FACTORY_HAL_HIDL_H
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp b/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp
deleted file mode 100644
index cde8d85..0000000
--- a/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2017 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 "DevicesFactoryHalHybrid"
-//#define LOG_NDEBUG 0
-
-#include "DevicesFactoryHalHidl.h"
-#include "DevicesFactoryHalHybrid.h"
-#include "DevicesFactoryHalLocal.h"
-
-namespace android {
-namespace CPP_VERSION {
-
-DevicesFactoryHalHybrid::DevicesFactoryHalHybrid(sp<IDevicesFactory> hidlFactory)
- : mLocalFactory(new DevicesFactoryHalLocal()),
- mHidlFactory(new DevicesFactoryHalHidl(hidlFactory)) {
-}
-
-status_t DevicesFactoryHalHybrid::openDevice(const char *name, sp<DeviceHalInterface> *device) {
- if (mHidlFactory != 0 && strcmp(AUDIO_HARDWARE_MODULE_ID_A2DP, name) != 0 &&
- strcmp(AUDIO_HARDWARE_MODULE_ID_HEARING_AID, name) != 0) {
- return mHidlFactory->openDevice(name, device);
- }
- return mLocalFactory->openDevice(name, device);
-}
-
-status_t DevicesFactoryHalHybrid::getHalPids(std::vector<pid_t> *pids) {
- if (mHidlFactory != 0) {
- return mHidlFactory->getHalPids(pids);
- }
- return INVALID_OPERATION;
-}
-
-status_t DevicesFactoryHalHybrid::setCallbackOnce(sp<DevicesFactoryHalCallback> callback) {
- if (mHidlFactory) {
- return mHidlFactory->setCallbackOnce(callback);
- }
- return INVALID_OPERATION;
-}
-
-} // namespace CPP_VERSION
-
-extern "C" __attribute__((visibility("default"))) void* createIDevicesFactory() {
- auto service = hardware::audio::CPP_VERSION::IDevicesFactory::getService();
- return service ? new CPP_VERSION::DevicesFactoryHalHybrid(service) : nullptr;
-}
-
-} // namespace android
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHybrid.h b/media/libaudiohal/impl/DevicesFactoryHalHybrid.h
deleted file mode 100644
index 5baefa4b..0000000
--- a/media/libaudiohal/impl/DevicesFactoryHalHybrid.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2017 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_HARDWARE_DEVICES_FACTORY_HAL_HYBRID_H
-#define ANDROID_HARDWARE_DEVICES_FACTORY_HAL_HYBRID_H
-
-#include PATH(android/hardware/audio/FILE_VERSION/IDevicesFactory.h)
-#include <media/audiohal/DevicesFactoryHalInterface.h>
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-
-using ::android::hardware::audio::CPP_VERSION::IDevicesFactory;
-
-namespace android {
-namespace CPP_VERSION {
-
-class DevicesFactoryHalHybrid : public DevicesFactoryHalInterface
-{
- public:
- DevicesFactoryHalHybrid(sp<IDevicesFactory> hidlFactory);
-
- // Opens a device with the specified name. To close the device, it is
- // necessary to release references to the returned object.
- virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device);
-
- status_t getHalPids(std::vector<pid_t> *pids) override;
-
- status_t setCallbackOnce(sp<DevicesFactoryHalCallback> callback) override;
-
- float getHalVersion() const override {
- return MAJOR_VERSION + (float)MINOR_VERSION / 10;
- }
-
- private:
- sp<DevicesFactoryHalInterface> mLocalFactory;
- sp<DevicesFactoryHalInterface> mHidlFactory;
-};
-
-} // namespace CPP_VERSION
-} // namespace android
-
-#endif // ANDROID_HARDWARE_DEVICES_FACTORY_HAL_HYBRID_H
diff --git a/media/libaudiohal/impl/DevicesFactoryHalLocal.cpp b/media/libaudiohal/impl/DevicesFactoryHalLocal.cpp
deleted file mode 100644
index af67ff5..0000000
--- a/media/libaudiohal/impl/DevicesFactoryHalLocal.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2016 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 "DevicesFactoryHalLocal"
-//#define LOG_NDEBUG 0
-
-#include <string.h>
-
-#include <hardware/audio.h>
-#include <utils/Log.h>
-
-#include "DeviceHalLocal.h"
-#include "DevicesFactoryHalLocal.h"
-
-namespace android {
-namespace CPP_VERSION {
-
-static status_t load_audio_interface(const char *if_name, audio_hw_device_t **dev)
-{
- const hw_module_t *mod;
- int rc;
-
- rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod);
- if (rc) {
- ALOGE("%s couldn't load audio hw module %s.%s (%s)", __func__,
- AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));
- goto out;
- }
- rc = audio_hw_device_open(mod, dev);
- if (rc) {
- ALOGE("%s couldn't open audio hw device in %s.%s (%s)", __func__,
- AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));
- goto out;
- }
- if ((*dev)->common.version < AUDIO_DEVICE_API_VERSION_MIN) {
- ALOGE("%s wrong audio hw device version %04x", __func__, (*dev)->common.version);
- rc = BAD_VALUE;
- audio_hw_device_close(*dev);
- goto out;
- }
- return OK;
-
-out:
- *dev = NULL;
- return rc;
-}
-
-status_t DevicesFactoryHalLocal::openDevice(const char *name, sp<DeviceHalInterface> *device) {
- audio_hw_device_t *dev;
- status_t rc = load_audio_interface(name, &dev);
- if (rc == OK) {
- *device = new DeviceHalLocal(dev);
- }
- return rc;
-}
-
-} // namespace CPP_VERSION
-} // namespace android
diff --git a/media/libaudiohal/impl/DevicesFactoryHalLocal.h b/media/libaudiohal/impl/DevicesFactoryHalLocal.h
deleted file mode 100644
index d2b9104..0000000
--- a/media/libaudiohal/impl/DevicesFactoryHalLocal.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2016 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_HARDWARE_DEVICES_FACTORY_HAL_LOCAL_H
-#define ANDROID_HARDWARE_DEVICES_FACTORY_HAL_LOCAL_H
-
-#include <media/audiohal/DevicesFactoryHalInterface.h>
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-
-#include "DeviceHalLocal.h"
-
-namespace android {
-namespace CPP_VERSION {
-
-class DevicesFactoryHalLocal : public DevicesFactoryHalInterface
-{
- public:
- // Opens a device with the specified name. To close the device, it is
- // necessary to release references to the returned object.
- virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device);
-
- status_t getHalPids(std::vector<pid_t> *pids __unused) override {
- return INVALID_OPERATION;
- }
-
- status_t setCallbackOnce(sp<DevicesFactoryHalCallback> callback __unused) override {
- return INVALID_OPERATION;
- }
-
- float getHalVersion() const override {
- return MAJOR_VERSION + (float)MINOR_VERSION / 10;
- }
-
- private:
- friend class DevicesFactoryHalHybrid;
-
- // Can not be constructed directly by clients.
- DevicesFactoryHalLocal() {}
-
- virtual ~DevicesFactoryHalLocal() {}
-};
-
-} // namespace CPP_VERSION
-} // namespace android
-
-#endif // ANDROID_HARDWARE_DEVICES_FACTORY_HAL_LOCAL_H
diff --git a/media/libaudiohal/impl/EffectBufferHalHidl.cpp b/media/libaudiohal/impl/EffectBufferHalHidl.cpp
index 5367972..65297af 100644
--- a/media/libaudiohal/impl/EffectBufferHalHidl.cpp
+++ b/media/libaudiohal/impl/EffectBufferHalHidl.cpp
@@ -31,7 +31,6 @@
namespace android {
namespace effect {
-namespace CPP_VERSION {
// static
uint64_t EffectBufferHalHidl::makeUniqueId() {
@@ -144,5 +143,4 @@
}
} // namespace effect
-} // namespace CPP_VERSION
} // namespace android
diff --git a/media/libaudiohal/impl/EffectBufferHalHidl.h b/media/libaudiohal/impl/EffectBufferHalHidl.h
index 4826813..a9df68b 100644
--- a/media/libaudiohal/impl/EffectBufferHalHidl.h
+++ b/media/libaudiohal/impl/EffectBufferHalHidl.h
@@ -28,7 +28,6 @@
namespace android {
namespace effect {
-namespace CPP_VERSION {
using namespace ::android::hardware::audio::effect::CPP_VERSION;
@@ -74,7 +73,6 @@
status_t init();
};
-} // namespace CPP_VERSION
} // namespace effect
} // namespace android
diff --git a/media/libaudiohal/impl/EffectHalHidl.cpp b/media/libaudiohal/impl/EffectHalHidl.cpp
index 51ad146..1bb1e5f 100644
--- a/media/libaudiohal/impl/EffectHalHidl.cpp
+++ b/media/libaudiohal/impl/EffectHalHidl.cpp
@@ -36,7 +36,6 @@
namespace android {
namespace effect {
-namespace CPP_VERSION {
using namespace ::android::hardware::audio::common::CPP_VERSION;
using namespace ::android::hardware::audio::effect::CPP_VERSION;
@@ -310,6 +309,5 @@
return result;
}
-} // namespace CPP_VERSION
} // namespace effect
} // namespace android
diff --git a/media/libaudiohal/impl/EffectHalHidl.h b/media/libaudiohal/impl/EffectHalHidl.h
index 8e46638..07745db 100644
--- a/media/libaudiohal/impl/EffectHalHidl.h
+++ b/media/libaudiohal/impl/EffectHalHidl.h
@@ -28,7 +28,6 @@
namespace android {
namespace effect {
-namespace CPP_VERSION {
using namespace ::android::hardware::audio::effect::CPP_VERSION;
@@ -63,7 +62,7 @@
virtual status_t dump(int fd);
- uint64_t effectId() const { return mEffectId; }
+ virtual uint64_t effectId() const { return mEffectId; }
private:
friend class EffectsFactoryHalHidl;
@@ -96,7 +95,6 @@
status_t setProcessBuffers();
};
-} // namespace CPP_VERSION
} // namespace effect
} // namespace android
diff --git a/media/libaudiohal/impl/EffectsFactoryHalHidl.cpp b/media/libaudiohal/impl/EffectsFactoryHalHidl.cpp
index ffe0d72..90954b2 100644
--- a/media/libaudiohal/impl/EffectsFactoryHalHidl.cpp
+++ b/media/libaudiohal/impl/EffectsFactoryHalHidl.cpp
@@ -33,7 +33,6 @@
namespace android {
namespace effect {
-namespace CPP_VERSION {
using namespace ::android::hardware::audio::common::CPP_VERSION;
using namespace ::android::hardware::audio::effect::CPP_VERSION;
@@ -204,12 +203,11 @@
return EffectBufferHalHidl::mirror(external, size, buffer);
}
-} // namespace CPP_VERSION
} // namespace effect
extern "C" __attribute__((visibility("default"))) void* createIEffectsFactory() {
auto service = hardware::audio::effect::CPP_VERSION::IEffectsFactory::getService();
- return service ? new effect::CPP_VERSION::EffectsFactoryHalHidl(service) : nullptr;
+ return service ? new effect::EffectsFactoryHalHidl(service) : nullptr;
}
} // namespace android
diff --git a/media/libaudiohal/impl/EffectsFactoryHalHidl.h b/media/libaudiohal/impl/EffectsFactoryHalHidl.h
index ff26d9f..7491133 100644
--- a/media/libaudiohal/impl/EffectsFactoryHalHidl.h
+++ b/media/libaudiohal/impl/EffectsFactoryHalHidl.h
@@ -24,10 +24,9 @@
namespace android {
namespace effect {
-namespace CPP_VERSION {
using ::android::hardware::hidl_vec;
-using ::android::CPP_VERSION::ConversionHelperHidl;
+using ::android::ConversionHelperHidl;
using namespace ::android::hardware::audio::effect::CPP_VERSION;
class EffectsFactoryHalHidl : public EffectsFactoryHalInterface, public ConversionHelperHidl
@@ -70,7 +69,6 @@
status_t queryAllDescriptors();
};
-} // namespace CPP_VERSION
} // namespace effect
} // namespace android
diff --git a/media/libaudiohal/impl/ParameterUtils.h b/media/libaudiohal/impl/ParameterUtils.h
index 9cab72e..b5dcb9d 100644
--- a/media/libaudiohal/impl/ParameterUtils.h
+++ b/media/libaudiohal/impl/ParameterUtils.h
@@ -16,17 +16,16 @@
#pragma once
-#include PATH(android/hardware/audio/FILE_VERSION/types.h)
+#include PATH(android/hardware/audio/CORE_TYPES_FILE_VERSION/types.h)
#include <hidl/HidlSupport.h>
-using ::android::hardware::audio::CPP_VERSION::ParameterValue;
-using ::android::hardware::audio::CPP_VERSION::Result;
+using ::android::hardware::audio::CORE_TYPES_CPP_VERSION::ParameterValue;
+using ::android::hardware::audio::CORE_TYPES_CPP_VERSION::Result;
using ::android::hardware::Return;
using ::android::hardware::hidl_vec;
using ::android::hardware::hidl_string;
namespace android {
-namespace CPP_VERSION {
namespace utils {
#if MAJOR_VERSION == 2
@@ -56,5 +55,4 @@
#endif
} // namespace utils
-} // namespace CPP_VERSION
} // namespace android
diff --git a/media/libaudiohal/impl/StreamHalHidl.cpp b/media/libaudiohal/impl/StreamHalHidl.cpp
index e63aded..8ba0f72 100644
--- a/media/libaudiohal/impl/StreamHalHidl.cpp
+++ b/media/libaudiohal/impl/StreamHalHidl.cpp
@@ -20,32 +20,30 @@
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <hwbinder/IPCThreadState.h>
#include <media/AudioParameter.h>
+#include <mediautils/memory.h>
#include <mediautils/SchedulingPolicyService.h>
#include <utils/Log.h>
-#include PATH(android/hardware/audio/FILE_VERSION/IStreamOutCallback.h)
+#include PATH(android/hardware/audio/CORE_TYPES_FILE_VERSION/IStreamOutCallback.h)
#include <HidlUtils.h>
#include <util/CoreUtils.h>
#include "DeviceHalHidl.h"
-#include "EffectHalHidl.h"
#include "ParameterUtils.h"
#include "StreamHalHidl.h"
-using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils;
-using ::android::hardware::audio::CPP_VERSION::implementation::CoreUtils;
+using ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::implementation::HidlUtils;
+using ::android::hardware::audio::CORE_TYPES_CPP_VERSION::implementation::CoreUtils;
using ::android::hardware::MQDescriptorSync;
using ::android::hardware::Return;
using ::android::hardware::Void;
namespace android {
-namespace CPP_VERSION {
-using EffectHalHidl = ::android::effect::CPP_VERSION::EffectHalHidl;
-using ReadCommand = ::android::hardware::audio::CPP_VERSION::IStreamIn::ReadCommand;
+using ReadCommand = ::android::hardware::audio::CORE_TYPES_CPP_VERSION::IStreamIn::ReadCommand;
-using namespace ::android::hardware::audio::common::CPP_VERSION;
-using namespace ::android::hardware::audio::CPP_VERSION;
+using namespace ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION;
+using namespace ::android::hardware::audio::CORE_TYPES_CPP_VERSION;
StreamHalHidl::StreamHalHidl(IStream *stream)
: ConversionHelperHidl("Stream"),
@@ -137,14 +135,12 @@
status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
if (!mStream) return NO_INIT;
- return processReturn("addEffect", mStream->addEffect(
- static_cast<EffectHalHidl*>(effect.get())->effectId()));
+ return processReturn("addEffect", mStream->addEffect(effect->effectId()));
}
status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
if (!mStream) return NO_INIT;
- return processReturn("removeEffect", mStream->removeEffect(
- static_cast<EffectHalHidl*>(effect.get())->effectId()));
+ return processReturn("removeEffect", mStream->removeEffect(effect->effectId()));
}
status_t StreamHalHidl::standby() {
@@ -276,6 +272,32 @@
return err == 0;
}
+status_t StreamHalHidl::legacyCreateAudioPatch(const struct audio_port_config& port,
+ std::optional<audio_source_t> source,
+ audio_devices_t type) {
+ LOG_ALWAYS_FATAL_IF(port.type != AUDIO_PORT_TYPE_DEVICE, "port type must be device");
+ unique_malloced_ptr<char> address;
+ if (strcmp(port.ext.device.address, "") != 0) {
+ // FIXME: we only support address on first sink with HAL version < 3.0
+ address.reset(
+ audio_device_address_to_parameter(port.ext.device.type, port.ext.device.address));
+ } else {
+ address.reset((char*)calloc(1, 1));
+ }
+ AudioParameter param = AudioParameter(String8(address.get()));
+ param.addInt(String8(AudioParameter::keyRouting), (int)type);
+ if (source.has_value()) {
+ param.addInt(String8(AudioParameter::keyInputSource), (int)source.value());
+ }
+ return setParameters(param.toString());
+}
+
+status_t StreamHalHidl::legacyReleaseAudioPatch() {
+ AudioParameter param;
+ param.addInt(String8(AudioParameter::keyRouting), 0);
+ return setParameters(param.toString());
+}
+
namespace {
/* Notes on callback ownership.
@@ -328,7 +350,8 @@
} // namespace
-StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
+StreamOutHalHidl::StreamOutHalHidl(
+ const sp<::android::hardware::audio::CPP_VERSION::IStreamOut>& stream)
: StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
}
@@ -644,7 +667,11 @@
#elif MAJOR_VERSION >= 4
status_t StreamOutHalHidl::updateSourceMetadata(
const StreamOutHalInterface::SourceMetadata& sourceMetadata) {
- CPP_VERSION::SourceMetadata hidlMetadata;
+#if MAJOR_VERSION == 4
+ ::android::hardware::audio::CORE_TYPES_CPP_VERSION::SourceMetadata hidlMetadata;
+#else
+ ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::SourceMetadata hidlMetadata;
+#endif
if (status_t status = CoreUtils::sourceMetadataFromHalV7(
sourceMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
status != OK) {
@@ -686,6 +713,7 @@
// Codec format callback is supported starting from audio HAL V6.0
return INVALID_OPERATION;
}
+
#else
status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode) {
@@ -755,7 +783,7 @@
static_cast<TimestretchFallbackMode>(playbackRate.mFallbackMode)}));
}
-#include PATH(android/hardware/audio/FILE_VERSION/IStreamOutEventCallback.h)
+#include PATH(android/hardware/audio/CORE_TYPES_FILE_VERSION/IStreamOutEventCallback.h)
namespace {
@@ -791,6 +819,84 @@
}
#endif
+#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
+using hardware::audio::V7_1::LatencyMode;
+
+status_t StreamOutHalHidl::setLatencyMode(audio_latency_mode_t mode) {
+ if (mStream == 0) return NO_INIT;
+ return processReturn(
+ "setLatencyMode", mStream->setLatencyMode(static_cast<LatencyMode>(mode)));
+};
+
+status_t StreamOutHalHidl::getRecommendedLatencyModes(std::vector<audio_latency_mode_t> *modes) {
+ if (!mStream) return NO_INIT;
+ Result retval;
+ Return<void> ret = mStream->getRecommendedLatencyModes(
+ [&](Result r, hidl_vec<LatencyMode> hidlModes) {
+ retval = r;
+ for (size_t i = 0; i < hidlModes.size(); i++) {
+ modes->push_back(static_cast<audio_latency_mode_t>(hidlModes[i]));
+ }
+ });
+ return processReturn("getRecommendedLatencyModes", ret, retval);
+};
+
+#include PATH(android/hardware/audio/FILE_VERSION/IStreamOutLatencyModeCallback.h)
+
+using hardware::audio::V7_1::IStreamOutLatencyModeCallback;
+
+namespace {
+struct StreamOutLatencyModeCallback : public IStreamOutLatencyModeCallback {
+ StreamOutLatencyModeCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
+
+ // IStreamOutLatencyModeCallback implementation
+ Return<void> onRecommendedLatencyModeChanged(const hidl_vec<LatencyMode>& hidlModes) override {
+ sp<StreamOutHalHidl> stream = mStream.promote();
+ if (stream != nullptr) {
+ std::vector<audio_latency_mode_t> modes;
+ for (size_t i = 0; i < hidlModes.size(); i++) {
+ modes.push_back(static_cast<audio_latency_mode_t>(hidlModes[i]));
+ }
+ stream->onRecommendedLatencyModeChanged(modes);
+ }
+ return Void();
+ }
+
+ private:
+ wp<StreamOutHalHidl> mStream;
+};
+} // namespace
+
+status_t StreamOutHalHidl::setLatencyModeCallback(
+ const sp<StreamOutHalInterfaceLatencyModeCallback>& callback) {
+
+ if (mStream == nullptr) return NO_INIT;
+ mLatencyModeCallback = callback;
+ status_t status = processReturn(
+ "setLatencyModeCallback",
+ mStream->setLatencyModeCallback(
+ callback.get() == nullptr ? nullptr : new StreamOutLatencyModeCallback(this)));
+ return status;
+};
+
+#else
+
+status_t StreamOutHalHidl::setLatencyMode(audio_latency_mode_t mode __unused) {
+ return INVALID_OPERATION;
+};
+
+status_t StreamOutHalHidl::getRecommendedLatencyModes(
+ std::vector<audio_latency_mode_t> *modes __unused) {
+ return INVALID_OPERATION;
+};
+
+status_t StreamOutHalHidl::setLatencyModeCallback(
+ const sp<StreamOutHalInterfaceLatencyModeCallback>& callback __unused) {
+ return INVALID_OPERATION;
+};
+
+#endif
+
void StreamOutHalHidl::onWriteReady() {
sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
if (callback == 0) return;
@@ -819,8 +925,21 @@
callback->onCodecFormatChanged(metadataBs);
}
+void StreamOutHalHidl::onRecommendedLatencyModeChanged(
+ const std::vector<audio_latency_mode_t>& modes) {
+ sp<StreamOutHalInterfaceLatencyModeCallback> callback = mLatencyModeCallback.load().promote();
+ if (callback == nullptr) return;
+ callback->onRecommendedLatencyModeChanged(modes);
+}
-StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
+status_t StreamOutHalHidl::exit() {
+ // FIXME this is using hard-coded strings but in the future, this functionality will be
+ // converted to use audio HAL extensions required to support tunneling
+ return setParameters(String8("exiting=1"));
+}
+
+StreamInHalHidl::StreamInHalHidl(
+ const sp<::android::hardware::audio::CORE_TYPES_CPP_VERSION::IStreamIn>& stream)
: StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
}
@@ -1033,7 +1152,11 @@
status_t StreamInHalHidl::updateSinkMetadata(const
StreamInHalInterface::SinkMetadata& sinkMetadata) {
- CPP_VERSION::SinkMetadata hidlMetadata;
+#if MAJOR_VERSION == 4
+ ::android::hardware::audio::CORE_TYPES_CPP_VERSION::SinkMetadata hidlMetadata;
+#else
+ ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::SinkMetadata hidlMetadata;
+#endif
if (status_t status = CoreUtils::sinkMetadataFromHalV7(
sinkMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
status != OK) {
@@ -1068,5 +1191,4 @@
}
#endif
-} // namespace CPP_VERSION
} // namespace android
diff --git a/media/libaudiohal/impl/StreamHalHidl.h b/media/libaudiohal/impl/StreamHalHidl.h
index 6f5dd04..4e80e88 100644
--- a/media/libaudiohal/impl/StreamHalHidl.h
+++ b/media/libaudiohal/impl/StreamHalHidl.h
@@ -19,30 +19,29 @@
#include <atomic>
-#include PATH(android/hardware/audio/FILE_VERSION/IStream.h)
-#include PATH(android/hardware/audio/FILE_VERSION/IStreamIn.h)
+#include PATH(android/hardware/audio/CORE_TYPES_FILE_VERSION/IStream.h)
+#include PATH(android/hardware/audio/CORE_TYPES_FILE_VERSION/IStreamIn.h)
#include PATH(android/hardware/audio/FILE_VERSION/IStreamOut.h)
#include <fmq/EventFlag.h>
#include <fmq/MessageQueue.h>
+#include <media/audiohal/EffectHalInterface.h>
#include <media/audiohal/StreamHalInterface.h>
#include <mediautils/Synchronization.h>
#include "ConversionHelperHidl.h"
#include "StreamPowerLog.h"
-using ::android::hardware::audio::CPP_VERSION::IStream;
-using ::android::hardware::audio::CPP_VERSION::IStreamIn;
-using ::android::hardware::audio::CPP_VERSION::IStreamOut;
+using ::android::hardware::audio::CORE_TYPES_CPP_VERSION::IStream;
using ::android::hardware::EventFlag;
using ::android::hardware::MessageQueue;
using ::android::hardware::Return;
-using ReadParameters = ::android::hardware::audio::CPP_VERSION::IStreamIn::ReadParameters;
-using ReadStatus = ::android::hardware::audio::CPP_VERSION::IStreamIn::ReadStatus;
+using ReadParameters =
+ ::android::hardware::audio::CORE_TYPES_CPP_VERSION::IStreamIn::ReadParameters;
+using ReadStatus = ::android::hardware::audio::CORE_TYPES_CPP_VERSION::IStreamIn::ReadStatus;
using WriteCommand = ::android::hardware::audio::CPP_VERSION::IStreamOut::WriteCommand;
using WriteStatus = ::android::hardware::audio::CPP_VERSION::IStreamOut::WriteStatus;
namespace android {
-namespace CPP_VERSION {
class DeviceHalHidl;
@@ -90,6 +89,12 @@
// (must match the priority of the audioflinger's thread that calls 'read' / 'write')
virtual status_t setHalThreadPriority(int priority);
+ status_t legacyCreateAudioPatch(const struct audio_port_config& port,
+ std::optional<audio_source_t> source,
+ audio_devices_t type) override;
+
+ status_t legacyReleaseAudioPatch() override;
+
protected:
// Subclasses can not be constructed directly by clients.
explicit StreamHalHidl(IStream *stream);
@@ -191,6 +196,15 @@
// Methods used by StreamCodecFormatCallback (HIDL).
void onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs);
+ status_t setLatencyMode(audio_latency_mode_t mode) override;
+ status_t getRecommendedLatencyModes(std::vector<audio_latency_mode_t> *modes) override;
+ status_t setLatencyModeCallback(
+ const sp<StreamOutHalInterfaceLatencyModeCallback>& callback) override;
+
+ void onRecommendedLatencyModeChanged(const std::vector<audio_latency_mode_t>& modes);
+
+ status_t exit() override;
+
private:
friend class DeviceHalHidl;
typedef MessageQueue<WriteCommand, hardware::kSynchronizedReadWrite> CommandMQ;
@@ -199,7 +213,9 @@
mediautils::atomic_wp<StreamOutHalInterfaceCallback> mCallback;
mediautils::atomic_wp<StreamOutHalInterfaceEventCallback> mEventCallback;
- const sp<IStreamOut> mStream;
+ mediautils::atomic_wp<StreamOutHalInterfaceLatencyModeCallback> mLatencyModeCallback;
+
+ const sp<::android::hardware::audio::CPP_VERSION::IStreamOut> mStream;
std::unique_ptr<CommandMQ> mCommandMQ;
std::unique_ptr<DataMQ> mDataMQ;
std::unique_ptr<StatusMQ> mStatusMQ;
@@ -207,7 +223,7 @@
EventFlag* mEfGroup;
// Can not be constructed directly by clients.
- StreamOutHalHidl(const sp<IStreamOut>& stream);
+ StreamOutHalHidl(const sp<::android::hardware::audio::CPP_VERSION::IStreamOut>& stream);
virtual ~StreamOutHalHidl();
@@ -255,7 +271,7 @@
typedef MessageQueue<uint8_t, hardware::kSynchronizedReadWrite> DataMQ;
typedef MessageQueue<ReadStatus, hardware::kSynchronizedReadWrite> StatusMQ;
- const sp<IStreamIn> mStream;
+ const sp<::android::hardware::audio::CORE_TYPES_CPP_VERSION::IStreamIn> mStream;
std::unique_ptr<CommandMQ> mCommandMQ;
std::unique_ptr<DataMQ> mDataMQ;
std::unique_ptr<StatusMQ> mStatusMQ;
@@ -263,7 +279,8 @@
EventFlag* mEfGroup;
// Can not be constructed directly by clients.
- StreamInHalHidl(const sp<IStreamIn>& stream);
+ StreamInHalHidl(
+ const sp<::android::hardware::audio::CORE_TYPES_CPP_VERSION::IStreamIn>& stream);
virtual ~StreamInHalHidl();
@@ -273,7 +290,6 @@
status_t prepareForReading(size_t bufferSize);
};
-} // namespace CPP_VERSION
} // namespace android
#endif // ANDROID_HARDWARE_STREAM_HAL_HIDL_H
diff --git a/media/libaudiohal/impl/StreamHalLocal.cpp b/media/libaudiohal/impl/StreamHalLocal.cpp
deleted file mode 100644
index 11fac61..0000000
--- a/media/libaudiohal/impl/StreamHalLocal.cpp
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
- * Copyright (C) 2016 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 "StreamHalLocal"
-//#define LOG_NDEBUG 0
-
-#include <audio_utils/Metadata.h>
-#include <hardware/audio.h>
-#include <media/AudioParameter.h>
-#include <utils/Log.h>
-
-#include "DeviceHalLocal.h"
-#include "ParameterUtils.h"
-#include "StreamHalLocal.h"
-
-namespace android {
-namespace CPP_VERSION {
-
-StreamHalLocal::StreamHalLocal(audio_stream_t *stream, sp<DeviceHalLocal> device)
- : mDevice(device),
- mStream(stream) {
- // Instrument audio signal power logging.
- // Note: This assumes channel mask, format, and sample rate do not change after creation.
- if (mStream != nullptr /* && mStreamPowerLog.isUserDebugOrEngBuild() */) {
- mStreamPowerLog.init(mStream->get_sample_rate(mStream),
- mStream->get_channels(mStream),
- mStream->get_format(mStream));
- }
-}
-
-StreamHalLocal::~StreamHalLocal() {
- mStream = 0;
- mDevice.clear();
-}
-
-status_t StreamHalLocal::getBufferSize(size_t *size) {
- *size = mStream->get_buffer_size(mStream);
- return OK;
-}
-
-status_t StreamHalLocal::getAudioProperties(audio_config_base_t *configBase) {
- configBase->sample_rate = mStream->get_sample_rate(mStream);
- configBase->channel_mask = mStream->get_channels(mStream);
- configBase->format = mStream->get_format(mStream);
- return OK;
-}
-
-status_t StreamHalLocal::setParameters(const String8& kvPairs) {
- return mStream->set_parameters(mStream, kvPairs.string());
-}
-
-status_t StreamHalLocal::getParameters(const String8& keys, String8 *values) {
- char *halValues = mStream->get_parameters(mStream, keys.string());
- if (halValues != NULL) {
- values->setTo(halValues);
- free(halValues);
- } else {
- values->clear();
- }
- return OK;
-}
-
-status_t StreamHalLocal::addEffect(sp<EffectHalInterface>) {
- LOG_ALWAYS_FATAL("Local streams can not have effects");
- return INVALID_OPERATION;
-}
-
-status_t StreamHalLocal::removeEffect(sp<EffectHalInterface>) {
- LOG_ALWAYS_FATAL("Local streams can not have effects");
- return INVALID_OPERATION;
-}
-
-status_t StreamHalLocal::standby() {
- return mStream->standby(mStream);
-}
-
-status_t StreamHalLocal::dump(int fd, const Vector<String16>& args) {
- (void) args;
- status_t status = mStream->dump(mStream, fd);
- mStreamPowerLog.dump(fd);
- return status;
-}
-
-status_t StreamHalLocal::setHalThreadPriority(int) {
- // Don't need to do anything as local hal is executed by audioflinger directly
- // on the same thread.
- return OK;
-}
-
-StreamOutHalLocal::StreamOutHalLocal(audio_stream_out_t *stream, sp<DeviceHalLocal> device)
- : StreamHalLocal(&stream->common, device), mStream(stream) {
-}
-
-StreamOutHalLocal::~StreamOutHalLocal() {
- mCallback.clear();
- mDevice->closeOutputStream(mStream);
- mStream = 0;
-}
-
-status_t StreamOutHalLocal::getFrameSize(size_t *size) {
- *size = audio_stream_out_frame_size(mStream);
- return OK;
-}
-
-status_t StreamOutHalLocal::getLatency(uint32_t *latency) {
- *latency = mStream->get_latency(mStream);
- return OK;
-}
-
-status_t StreamOutHalLocal::setVolume(float left, float right) {
- if (mStream->set_volume == NULL) return INVALID_OPERATION;
- return mStream->set_volume(mStream, left, right);
-}
-
-status_t StreamOutHalLocal::selectPresentation(int presentationId, int programId) {
- AudioParameter param;
- param.addInt(String8(AudioParameter::keyPresentationId), presentationId);
- param.addInt(String8(AudioParameter::keyProgramId), programId);
- return setParameters(param.toString());
-}
-
-status_t StreamOutHalLocal::write(const void *buffer, size_t bytes, size_t *written) {
- ssize_t writeResult = mStream->write(mStream, buffer, bytes);
- if (writeResult > 0) {
- *written = writeResult;
- mStreamPowerLog.log(buffer, *written);
- return OK;
- } else {
- *written = 0;
- return writeResult;
- }
-}
-
-status_t StreamOutHalLocal::getRenderPosition(uint32_t *dspFrames) {
- return mStream->get_render_position(mStream, dspFrames);
-}
-
-status_t StreamOutHalLocal::getNextWriteTimestamp(int64_t *timestamp) {
- if (mStream->get_next_write_timestamp == NULL) return INVALID_OPERATION;
- return mStream->get_next_write_timestamp(mStream, timestamp);
-}
-
-status_t StreamOutHalLocal::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
- if (mStream->set_callback == NULL) return INVALID_OPERATION;
- status_t result = mStream->set_callback(mStream, StreamOutHalLocal::asyncCallback, this);
- if (result == OK) {
- mCallback = callback;
- }
- return result;
-}
-
-// static
-int StreamOutHalLocal::asyncCallback(stream_callback_event_t event, void*, void *cookie) {
- // We act as if we gave a wp<StreamOutHalLocal> to HAL. This way we should handle
- // correctly the case when the callback is invoked while StreamOutHalLocal's destructor is
- // already running, because the destructor is invoked after the refcount has been atomically
- // decremented.
- wp<StreamOutHalLocal> weakSelf(static_cast<StreamOutHalLocal*>(cookie));
- sp<StreamOutHalLocal> self = weakSelf.promote();
- if (self == 0) return 0;
- sp<StreamOutHalInterfaceCallback> callback = self->mCallback.promote();
- if (callback == 0) return 0;
- ALOGV("asyncCallback() event %d", event);
- switch (event) {
- case STREAM_CBK_EVENT_WRITE_READY:
- callback->onWriteReady();
- break;
- case STREAM_CBK_EVENT_DRAIN_READY:
- callback->onDrainReady();
- break;
- case STREAM_CBK_EVENT_ERROR:
- callback->onError();
- break;
- default:
- ALOGW("asyncCallback() unknown event %d", event);
- break;
- }
- return 0;
-}
-
-status_t StreamOutHalLocal::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
- *supportsPause = mStream->pause != NULL;
- *supportsResume = mStream->resume != NULL;
- return OK;
-}
-
-status_t StreamOutHalLocal::pause() {
- if (mStream->pause == NULL) return INVALID_OPERATION;
- return mStream->pause(mStream);
-}
-
-status_t StreamOutHalLocal::resume() {
- if (mStream->resume == NULL) return INVALID_OPERATION;
- return mStream->resume(mStream);
-}
-
-status_t StreamOutHalLocal::supportsDrain(bool *supportsDrain) {
- *supportsDrain = mStream->drain != NULL;
- return OK;
-}
-
-status_t StreamOutHalLocal::drain(bool earlyNotify) {
- if (mStream->drain == NULL) return INVALID_OPERATION;
- return mStream->drain(mStream, earlyNotify ? AUDIO_DRAIN_EARLY_NOTIFY : AUDIO_DRAIN_ALL);
-}
-
-status_t StreamOutHalLocal::flush() {
- if (mStream->flush == NULL) return INVALID_OPERATION;
- return mStream->flush(mStream);
-}
-
-status_t StreamOutHalLocal::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
- if (mStream->get_presentation_position == NULL) return INVALID_OPERATION;
- return mStream->get_presentation_position(mStream, frames, timestamp);
-}
-
-void StreamOutHalLocal::doUpdateSourceMetadata(const SourceMetadata& sourceMetadata) {
- std::vector<playback_track_metadata> halTracks;
- halTracks.reserve(sourceMetadata.tracks.size());
- for (auto& metadata : sourceMetadata.tracks) {
- playback_track_metadata halTrackMetadata;
- playback_track_metadata_from_v7(&halTrackMetadata, &metadata);
- halTracks.push_back(halTrackMetadata);
- }
- const source_metadata_t halMetadata = {
- .track_count = halTracks.size(),
- .tracks = halTracks.data(),
- };
- mStream->update_source_metadata(mStream, &halMetadata);
-}
-
-#if MAJOR_VERSION >= 7
-void StreamOutHalLocal::doUpdateSourceMetadataV7(const SourceMetadata& sourceMetadata) {
- const source_metadata_v7_t metadata {
- .track_count = sourceMetadata.tracks.size(),
- // const cast is fine as it is in a const structure
- .tracks = const_cast<playback_track_metadata_v7*>(sourceMetadata.tracks.data()),
- };
- mStream->update_source_metadata_v7(mStream, &metadata);
-}
-#endif
-
-status_t StreamOutHalLocal::updateSourceMetadata(const SourceMetadata& sourceMetadata) {
-#if MAJOR_VERSION < 7
- if (mStream->update_source_metadata == nullptr) {
- return INVALID_OPERATION;
- }
- doUpdateSourceMetadata(sourceMetadata);
-#else
- if (mDevice->version() < AUDIO_DEVICE_API_VERSION_3_2) {
- if (mStream->update_source_metadata == nullptr) {
- return INVALID_OPERATION;
- }
- doUpdateSourceMetadata(sourceMetadata);
- } else {
- if (mStream->update_source_metadata_v7 == nullptr) {
- return INVALID_OPERATION;
- }
- doUpdateSourceMetadataV7(sourceMetadata);
- }
-#endif
- return OK;
-}
-
-
-status_t StreamOutHalLocal::start() {
- if (mStream->start == NULL) return INVALID_OPERATION;
- return mStream->start(mStream);
-}
-
-status_t StreamOutHalLocal::stop() {
- if (mStream->stop == NULL) return INVALID_OPERATION;
- return mStream->stop(mStream);
-}
-
-status_t StreamOutHalLocal::createMmapBuffer(int32_t minSizeFrames,
- struct audio_mmap_buffer_info *info) {
- if (mStream->create_mmap_buffer == NULL) return INVALID_OPERATION;
- return mStream->create_mmap_buffer(mStream, minSizeFrames, info);
-}
-
-status_t StreamOutHalLocal::getMmapPosition(struct audio_mmap_position *position) {
- if (mStream->get_mmap_position == NULL) return INVALID_OPERATION;
- return mStream->get_mmap_position(mStream, position);
-}
-
-status_t StreamOutHalLocal::getDualMonoMode(audio_dual_mono_mode_t* mode) {
- if (mStream->get_dual_mono_mode == nullptr) return INVALID_OPERATION;
- return mStream->get_dual_mono_mode(mStream, mode);
-}
-
-status_t StreamOutHalLocal::setDualMonoMode(audio_dual_mono_mode_t mode) {
- if (mStream->set_dual_mono_mode == nullptr) return INVALID_OPERATION;
- return mStream->set_dual_mono_mode(mStream, mode);
-}
-
-status_t StreamOutHalLocal::getAudioDescriptionMixLevel(float* leveldB) {
- if (mStream->get_audio_description_mix_level == nullptr) return INVALID_OPERATION;
- return mStream->get_audio_description_mix_level(mStream, leveldB);
-}
-
-status_t StreamOutHalLocal::setAudioDescriptionMixLevel(float leveldB) {
- if (mStream->set_audio_description_mix_level == nullptr) return INVALID_OPERATION;
- return mStream->set_audio_description_mix_level(mStream, leveldB);
-}
-
-status_t StreamOutHalLocal::getPlaybackRateParameters(audio_playback_rate_t* playbackRate) {
- if (mStream->get_playback_rate_parameters == nullptr) return INVALID_OPERATION;
- return mStream->get_playback_rate_parameters(mStream, playbackRate);
-}
-
-status_t StreamOutHalLocal::setPlaybackRateParameters(const audio_playback_rate_t& playbackRate) {
- if (mStream->set_playback_rate_parameters == nullptr) return INVALID_OPERATION;
- return mStream->set_playback_rate_parameters(mStream, &playbackRate);
-}
-
-status_t StreamOutHalLocal::setEventCallback(
- const sp<StreamOutHalInterfaceEventCallback>& callback) {
- if (mStream->set_event_callback == nullptr) {
- return INVALID_OPERATION;
- }
- stream_event_callback_t asyncCallback =
- callback == nullptr ? nullptr : StreamOutHalLocal::asyncEventCallback;
- status_t result = mStream->set_event_callback(mStream, asyncCallback, this);
- if (result == OK) {
- mEventCallback = callback;
- }
- return result;
-}
-
-// static
-int StreamOutHalLocal::asyncEventCallback(
- stream_event_callback_type_t event, void *param, void *cookie) {
- // We act as if we gave a wp<StreamOutHalLocal> to HAL. This way we should handle
- // correctly the case when the callback is invoked while StreamOutHalLocal's destructor is
- // already running, because the destructor is invoked after the refcount has been atomically
- // decremented.
- wp<StreamOutHalLocal> weakSelf(static_cast<StreamOutHalLocal*>(cookie));
- sp<StreamOutHalLocal> self = weakSelf.promote();
- if (self == nullptr) return 0;
- sp<StreamOutHalInterfaceEventCallback> callback = self->mEventCallback.promote();
- if (callback.get() == nullptr) return 0;
- switch (event) {
- case STREAM_EVENT_CBK_TYPE_CODEC_FORMAT_CHANGED:
- // void* param is the byte string buffer from byte_string_from_audio_metadata().
- // As the byte string buffer may have embedded zeroes, we cannot use strlen()
- callback->onCodecFormatChanged(std::basic_string<uint8_t>(
- (const uint8_t*)param,
- audio_utils::metadata::dataByteStringLen((const uint8_t*)param)));
- break;
- default:
- ALOGW("%s unknown event %d", __func__, event);
- break;
- }
- return 0;
-}
-
-StreamInHalLocal::StreamInHalLocal(audio_stream_in_t *stream, sp<DeviceHalLocal> device)
- : StreamHalLocal(&stream->common, device), mStream(stream) {
-}
-
-StreamInHalLocal::~StreamInHalLocal() {
- mDevice->closeInputStream(mStream);
- mStream = 0;
-}
-
-status_t StreamInHalLocal::getFrameSize(size_t *size) {
- *size = audio_stream_in_frame_size(mStream);
- return OK;
-}
-
-status_t StreamInHalLocal::setGain(float gain) {
- return mStream->set_gain(mStream, gain);
-}
-
-status_t StreamInHalLocal::read(void *buffer, size_t bytes, size_t *read) {
- ssize_t readResult = mStream->read(mStream, buffer, bytes);
- if (readResult > 0) {
- *read = readResult;
- mStreamPowerLog.log( buffer, *read);
- return OK;
- } else {
- *read = 0;
- return readResult;
- }
-}
-
-status_t StreamInHalLocal::getInputFramesLost(uint32_t *framesLost) {
- *framesLost = mStream->get_input_frames_lost(mStream);
- return OK;
-}
-
-status_t StreamInHalLocal::getCapturePosition(int64_t *frames, int64_t *time) {
- if (mStream->get_capture_position == NULL) return INVALID_OPERATION;
- return mStream->get_capture_position(mStream, frames, time);
-}
-
-void StreamInHalLocal::doUpdateSinkMetadata(const SinkMetadata& sinkMetadata) {
- std::vector<record_track_metadata> halTracks;
- halTracks.reserve(sinkMetadata.tracks.size());
- for (auto& metadata : sinkMetadata.tracks) {
- record_track_metadata halTrackMetadata;
- record_track_metadata_from_v7(&halTrackMetadata, &metadata);
- halTracks.push_back(halTrackMetadata);
- }
- const sink_metadata_t halMetadata = {
- .track_count = halTracks.size(),
- .tracks = halTracks.data(),
- };
- mStream->update_sink_metadata(mStream, &halMetadata);
-}
-
-#if MAJOR_VERSION >= 7
-void StreamInHalLocal::doUpdateSinkMetadataV7(const SinkMetadata& sinkMetadata) {
- const sink_metadata_v7_t halMetadata {
- .track_count = sinkMetadata.tracks.size(),
- // const cast is fine as it is in a const structure
- .tracks = const_cast<record_track_metadata_v7*>(sinkMetadata.tracks.data()),
- };
- mStream->update_sink_metadata_v7(mStream, &halMetadata);
-}
-#endif
-
-status_t StreamInHalLocal::updateSinkMetadata(const SinkMetadata& sinkMetadata) {
-#if MAJOR_VERSION < 7
- if (mStream->update_sink_metadata == nullptr) {
- return INVALID_OPERATION; // not supported by the HAL
- }
- doUpdateSinkMetadata(sinkMetadata);
-#else
- if (mDevice->version() < AUDIO_DEVICE_API_VERSION_3_2) {
- if (mStream->update_sink_metadata == nullptr) {
- return INVALID_OPERATION; // not supported by the HAL
- }
- doUpdateSinkMetadata(sinkMetadata);
- } else {
- if (mStream->update_sink_metadata_v7 == nullptr) {
- return INVALID_OPERATION; // not supported by the HAL
- }
- doUpdateSinkMetadataV7(sinkMetadata);
- }
-#endif
- return OK;
-}
-
-status_t StreamInHalLocal::start() {
- if (mStream->start == NULL) return INVALID_OPERATION;
- return mStream->start(mStream);
-}
-
-status_t StreamInHalLocal::stop() {
- if (mStream->stop == NULL) return INVALID_OPERATION;
- return mStream->stop(mStream);
-}
-
-status_t StreamInHalLocal::createMmapBuffer(int32_t minSizeFrames,
- struct audio_mmap_buffer_info *info) {
- if (mStream->create_mmap_buffer == NULL) return INVALID_OPERATION;
- return mStream->create_mmap_buffer(mStream, minSizeFrames, info);
-}
-
-status_t StreamInHalLocal::getMmapPosition(struct audio_mmap_position *position) {
- if (mStream->get_mmap_position == NULL) return INVALID_OPERATION;
- return mStream->get_mmap_position(mStream, position);
-}
-
-#if MAJOR_VERSION == 2
-status_t StreamInHalLocal::getActiveMicrophones(
- std::vector<media::MicrophoneInfo> *microphones __unused) {
- return INVALID_OPERATION;
-}
-#elif MAJOR_VERSION >= 4
-status_t StreamInHalLocal::getActiveMicrophones(std::vector<media::MicrophoneInfo> *microphones) {
- if (mStream->get_active_microphones == NULL) return INVALID_OPERATION;
- size_t actual_mics = AUDIO_MICROPHONE_MAX_COUNT;
- audio_microphone_characteristic_t mic_array[AUDIO_MICROPHONE_MAX_COUNT];
- status_t status = mStream->get_active_microphones(mStream, &mic_array[0], &actual_mics);
- for (size_t i = 0; i < actual_mics; i++) {
- media::MicrophoneInfo microphoneInfo = media::MicrophoneInfo(mic_array[i]);
- microphones->push_back(microphoneInfo);
- }
- return status;
-}
-#endif
-
-#if MAJOR_VERSION < 5
-status_t StreamInHalLocal::setPreferredMicrophoneDirection(
- audio_microphone_direction_t direction __unused) {
- return INVALID_OPERATION;
-}
-
-status_t StreamInHalLocal::setPreferredMicrophoneFieldDimension(float zoom __unused) {
- return INVALID_OPERATION;
-}
-#else
-status_t StreamInHalLocal::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
- if (mStream->set_microphone_direction == NULL) return INVALID_OPERATION;
- return mStream->set_microphone_direction(mStream, direction);
-}
-
-status_t StreamInHalLocal::setPreferredMicrophoneFieldDimension(float zoom) {
- if (mStream->set_microphone_field_dimension == NULL) return INVALID_OPERATION;
- return mStream->set_microphone_field_dimension(mStream, zoom);
-
-}
-#endif
-
-} // namespace CPP_VERSION
-} // namespace android
-
-
diff --git a/media/libaudiohal/impl/StreamHalLocal.h b/media/libaudiohal/impl/StreamHalLocal.h
deleted file mode 100644
index 493c521..0000000
--- a/media/libaudiohal/impl/StreamHalLocal.h
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright (C) 2016 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_HARDWARE_STREAM_HAL_LOCAL_H
-#define ANDROID_HARDWARE_STREAM_HAL_LOCAL_H
-
-#include <media/audiohal/StreamHalInterface.h>
-#include "StreamPowerLog.h"
-
-namespace android {
-namespace CPP_VERSION {
-
-class DeviceHalLocal;
-
-class StreamHalLocal : public virtual StreamHalInterface
-{
- public:
- // Return size of input/output buffer in bytes for this stream - eg. 4800.
- virtual status_t getBufferSize(size_t *size);
-
- // Return the base configuration of the stream:
- // - channel mask;
- // - format - e.g. AUDIO_FORMAT_PCM_16_BIT;
- // - sampling rate in Hz - eg. 44100.
- virtual status_t getAudioProperties(audio_config_base_t *configBase);
-
- // Set audio stream parameters.
- virtual status_t setParameters(const String8& kvPairs);
-
- // Get audio stream parameters.
- virtual status_t getParameters(const String8& keys, String8 *values);
-
- // Add or remove the effect on the stream.
- virtual status_t addEffect(sp<EffectHalInterface> effect);
- virtual status_t removeEffect(sp<EffectHalInterface> effect);
-
- // Put the audio hardware input/output into standby mode.
- virtual status_t standby();
-
- virtual status_t dump(int fd, const Vector<String16>& args) override;
-
- // Start a stream operating in mmap mode.
- virtual status_t start() = 0;
-
- // Stop a stream operating in mmap mode.
- virtual status_t stop() = 0;
-
- // Retrieve information on the data buffer in mmap mode.
- virtual status_t createMmapBuffer(int32_t minSizeFrames,
- struct audio_mmap_buffer_info *info) = 0;
-
- // Get current read/write position in the mmap buffer
- virtual status_t getMmapPosition(struct audio_mmap_position *position) = 0;
-
- // Set the priority of the thread that interacts with the HAL
- // (must match the priority of the audioflinger's thread that calls 'read' / 'write')
- virtual status_t setHalThreadPriority(int priority);
-
- protected:
- // Subclasses can not be constructed directly by clients.
- StreamHalLocal(audio_stream_t *stream, sp<DeviceHalLocal> device);
-
- // The destructor automatically closes the stream.
- virtual ~StreamHalLocal();
-
- sp<DeviceHalLocal> mDevice;
-
- // mStreamPowerLog is used for audio signal power logging.
- StreamPowerLog mStreamPowerLog;
-
- private:
- audio_stream_t *mStream;
-};
-
-class StreamOutHalLocal : public StreamOutHalInterface, public StreamHalLocal {
- public:
- // Return the frame size (number of bytes per sample) of a stream.
- virtual status_t getFrameSize(size_t *size);
-
- // Return the audio hardware driver estimated latency in milliseconds.
- virtual status_t getLatency(uint32_t *latency);
-
- // Use this method in situations where audio mixing is done in the hardware.
- virtual status_t setVolume(float left, float right);
-
- // Selects the audio presentation (if available).
- virtual status_t selectPresentation(int presentationId, int programId);
-
- // Write audio buffer to driver.
- virtual status_t write(const void *buffer, size_t bytes, size_t *written);
-
- // Return the number of audio frames written by the audio dsp to DAC since
- // the output has exited standby.
- virtual status_t getRenderPosition(uint32_t *dspFrames);
-
- // Get the local time at which the next write to the audio driver will be presented.
- virtual status_t getNextWriteTimestamp(int64_t *timestamp);
-
- // Set the callback for notifying completion of non-blocking write and drain.
- virtual status_t setCallback(wp<StreamOutHalInterfaceCallback> callback);
-
- // Returns whether pause and resume operations are supported.
- virtual status_t supportsPauseAndResume(bool *supportsPause, bool *supportsResume);
-
- // Notifies to the audio driver to resume playback following a pause.
- virtual status_t pause();
-
- // Notifies to the audio driver to resume playback following a pause.
- virtual status_t resume();
-
- // Returns whether drain operation is supported.
- virtual status_t supportsDrain(bool *supportsDrain);
-
- // Requests notification when data buffered by the driver/hardware has been played.
- virtual status_t drain(bool earlyNotify);
-
- // Notifies to the audio driver to flush the queued data.
- virtual status_t flush();
-
- // Return a recent count of the number of audio frames presented to an external observer.
- virtual status_t getPresentationPosition(uint64_t *frames, struct timespec *timestamp);
-
- // Start a stream operating in mmap mode.
- virtual status_t start();
-
- // Stop a stream operating in mmap mode.
- virtual status_t stop();
-
- // Retrieve information on the data buffer in mmap mode.
- virtual status_t createMmapBuffer(int32_t minSizeFrames,
- struct audio_mmap_buffer_info *info);
-
- // Get current read/write position in the mmap buffer
- virtual status_t getMmapPosition(struct audio_mmap_position *position);
-
- // Called when the metadata of the stream's source has been changed.
- status_t updateSourceMetadata(const SourceMetadata& sourceMetadata) override;
-
- // Returns the Dual Mono mode presentation setting.
- status_t getDualMonoMode(audio_dual_mono_mode_t* mode) override;
-
- // Sets the Dual Mono mode presentation on the output device.
- status_t setDualMonoMode(audio_dual_mono_mode_t mode) override;
-
- // Returns the Audio Description Mix level in dB.
- status_t getAudioDescriptionMixLevel(float* leveldB) override;
-
- // Sets the Audio Description Mix level in dB.
- status_t setAudioDescriptionMixLevel(float leveldB) override;
-
- // Retrieves current playback rate parameters.
- status_t getPlaybackRateParameters(audio_playback_rate_t* playbackRate) override;
-
- // Sets the playback rate parameters that control playback behavior.
- status_t setPlaybackRateParameters(const audio_playback_rate_t& playbackRate) override;
-
- status_t setEventCallback(const sp<StreamOutHalInterfaceEventCallback>& callback) override;
-
- private:
- audio_stream_out_t *mStream;
- wp<StreamOutHalInterfaceCallback> mCallback;
- wp<StreamOutHalInterfaceEventCallback> mEventCallback;
-
- friend class DeviceHalLocal;
-
- // Can not be constructed directly by clients.
- StreamOutHalLocal(audio_stream_out_t *stream, sp<DeviceHalLocal> device);
-
- virtual ~StreamOutHalLocal();
-
- static int asyncCallback(stream_callback_event_t event, void *param, void *cookie);
-
- static int asyncEventCallback(stream_event_callback_type_t event, void *param, void *cookie);
-
- void doUpdateSourceMetadataV7(const SourceMetadata& sourceMetadata);
- void doUpdateSourceMetadata(const SourceMetadata& sourceMetadata);
-};
-
-class StreamInHalLocal : public StreamInHalInterface, public StreamHalLocal {
- public:
- // Return the frame size (number of bytes per sample) of a stream.
- virtual status_t getFrameSize(size_t *size);
-
- // Set the input gain for the audio driver.
- virtual status_t setGain(float gain);
-
- // Read audio buffer in from driver.
- virtual status_t read(void *buffer, size_t bytes, size_t *read);
-
- // Return the amount of input frames lost in the audio driver.
- virtual status_t getInputFramesLost(uint32_t *framesLost);
-
- // Return a recent count of the number of audio frames received and
- // the clock time associated with that frame count.
- virtual status_t getCapturePosition(int64_t *frames, int64_t *time);
-
- // Start a stream operating in mmap mode.
- virtual status_t start();
-
- // Stop a stream operating in mmap mode.
- virtual status_t stop();
-
- // Retrieve information on the data buffer in mmap mode.
- virtual status_t createMmapBuffer(int32_t minSizeFrames,
- struct audio_mmap_buffer_info *info);
-
- // Get current read/write position in the mmap buffer
- virtual status_t getMmapPosition(struct audio_mmap_position *position);
-
- // Get active microphones
- virtual status_t getActiveMicrophones(std::vector<media::MicrophoneInfo> *microphones);
-
- // Sets microphone direction (for processing)
- virtual status_t setPreferredMicrophoneDirection(audio_microphone_direction_t direction);
-
- // Sets microphone zoom (for processing)
- virtual status_t setPreferredMicrophoneFieldDimension(float zoom);
-
- // Called when the metadata of the stream's sink has been changed.
- status_t updateSinkMetadata(const SinkMetadata& sinkMetadata) override;
-
- private:
- audio_stream_in_t *mStream;
-
- friend class DeviceHalLocal;
-
- // Can not be constructed directly by clients.
- StreamInHalLocal(audio_stream_in_t *stream, sp<DeviceHalLocal> device);
-
- virtual ~StreamInHalLocal();
-
- void doUpdateSinkMetadata(const SinkMetadata& sinkMetadata);
- void doUpdateSinkMetadataV7(const SinkMetadata& sinkMetadata);
-};
-
-} // namespace CPP_VERSION
-} // namespace android
-
-#endif // ANDROID_HARDWARE_STREAM_HAL_LOCAL_H
diff --git a/media/libaudiohal/impl/StreamPowerLog.h b/media/libaudiohal/impl/StreamPowerLog.h
index f6a554b..c08ee47 100644
--- a/media/libaudiohal/impl/StreamPowerLog.h
+++ b/media/libaudiohal/impl/StreamPowerLog.h
@@ -24,7 +24,6 @@
#include <system/audio.h>
namespace android {
-namespace CPP_VERSION {
class StreamPowerLog {
public:
@@ -99,7 +98,6 @@
size_t mFrameSize;
};
-} // namespace CPP_VERSION
} // namespace android
#endif // ANDROID_HARDWARE_STREAM_POWER_LOG_H
diff --git a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
index 70c3199..d27ad4c 100644
--- a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
@@ -19,6 +19,7 @@
#include <android/media/audio/common/AudioMMapPolicyInfo.h>
#include <android/media/audio/common/AudioMMapPolicyType.h>
+#include <error/Result.h>
#include <media/audiohal/EffectHalInterface.h>
#include <media/MicrophoneInfo.h>
#include <system/audio.h>
@@ -128,6 +129,11 @@
virtual int32_t getAAudioMixerBurstCount() = 0;
virtual int32_t getAAudioHardwareBurstMinUsec() = 0;
+ // Update the connection status of an external device.
+ virtual status_t setConnectedState(const struct audio_port_v7 *port, bool connected) = 0;
+
+ virtual error::Result<audio_hw_sync_t> getHwAvSync() = 0;
+
virtual status_t dump(int fd, const Vector<String16>& args) = 0;
protected:
diff --git a/media/libaudiohal/include/media/audiohal/EffectHalInterface.h b/media/libaudiohal/include/media/audiohal/EffectHalInterface.h
index 03165bd..2969c92 100644
--- a/media/libaudiohal/include/media/audiohal/EffectHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/EffectHalInterface.h
@@ -57,6 +57,9 @@
virtual status_t dump(int fd) = 0;
+ // Unique effect ID to use with the core HAL.
+ virtual uint64_t effectId() const = 0;
+
protected:
// Subclasses can not be constructed directly by clients.
EffectHalInterface() {}
diff --git a/media/libaudiohal/include/media/audiohal/StreamHalInterface.h b/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
index 2b5b2db..1d52b7d 100644
--- a/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
@@ -89,6 +89,12 @@
// (must match the priority of the audioflinger's thread that calls 'read' / 'write')
virtual status_t setHalThreadPriority(int priority) = 0;
+ virtual status_t legacyCreateAudioPatch(const struct audio_port_config& port,
+ std::optional<audio_source_t> source,
+ audio_devices_t type) = 0;
+
+ virtual status_t legacyReleaseAudioPatch() = 0;
+
protected:
// Subclasses can not be constructed directly by clients.
StreamHalInterface() {}
@@ -117,6 +123,18 @@
virtual ~StreamOutHalInterfaceEventCallback() {}
};
+class StreamOutHalInterfaceLatencyModeCallback : public virtual RefBase {
+public:
+ /**
+ * Called with the new list of supported latency modes when a change occurs.
+ */
+ virtual void onRecommendedLatencyModeChanged(std::vector<audio_latency_mode_t> modes) = 0;
+
+protected:
+ StreamOutHalInterfaceLatencyModeCallback() {}
+ virtual ~StreamOutHalInterfaceLatencyModeCallback() {}
+};
+
class StreamOutHalInterface : public virtual StreamHalInterface {
public:
// Return the audio hardware driver estimated latency in milliseconds.
@@ -194,6 +212,47 @@
virtual status_t setEventCallback(const sp<StreamOutHalInterfaceEventCallback>& callback) = 0;
+ /**
+ * Indicates the requested latency mode for this output stream.
+ *
+ * The requested mode can be one of the modes returned by
+ * getRecommendedLatencyModes() API.
+ *
+ * @param mode the requested latency mode.
+ * @return operation completion status.
+ */
+ virtual status_t setLatencyMode(audio_latency_mode_t mode) = 0;
+
+ /**
+ * Indicates which latency modes are currently supported on this output stream.
+ * If the transport protocol (e.g Bluetooth A2DP) used by this output stream to reach
+ * the output device supports variable latency modes, the HAL indicates which
+ * modes are currently supported.
+ * The framework can then call setLatencyMode() with one of the supported modes to select
+ * the desired operation mode.
+ *
+ * @param modes currrently supported latency modes.
+ * @return operation completion status.
+ */
+ virtual status_t getRecommendedLatencyModes(std::vector<audio_latency_mode_t> *modes) = 0;
+
+ /**
+ * Set the callback interface for notifying changes in supported latency modes.
+ *
+ * Calling this method with a null pointer will result in releasing
+ * the callback.
+ *
+ * @param callback the registered callback or null to unregister.
+ * @return operation completion status.
+ */
+ virtual status_t setLatencyModeCallback(
+ const sp<StreamOutHalInterfaceLatencyModeCallback>& callback) = 0;
+
+ /**
+ * Signal the end of audio output, interrupting an ongoing 'write' operation.
+ */
+ virtual status_t exit() = 0;
+
protected:
virtual ~StreamOutHalInterface() {}
};
diff --git a/media/libeffects/downmix/Android.bp b/media/libeffects/downmix/Android.bp
index b26d028..abe622d 100644
--- a/media/libeffects/downmix/Android.bp
+++ b/media/libeffects/downmix/Android.bp
@@ -24,6 +24,10 @@
vendor: true,
srcs: ["EffectDownmix.cpp"],
+ export_include_dirs: [
+ ".",
+ ],
+
shared_libs: [
"libaudioutils",
"libcutils",
diff --git a/media/libeffects/downmix/tests/Android.bp b/media/libeffects/downmix/tests/Android.bp
index 4940117..392a6fa 100644
--- a/media/libeffects/downmix/tests/Android.bp
+++ b/media/libeffects/downmix/tests/Android.bp
@@ -18,9 +18,6 @@
gtest: true,
host_supported: true,
vendor: true,
- include_dirs: [
- "frameworks/av/media/libeffects/downmix",
- ],
header_libs: [
"libaudioeffects",
],
@@ -51,9 +48,6 @@
name:"downmixtest",
host_supported: false,
proprietary: true,
- include_dirs: [
- "frameworks/av/media/libeffects/downmix",
- ],
header_libs: [
"libaudioeffects",
diff --git a/media/libeffects/lvm/benchmarks/Android.bp b/media/libeffects/lvm/benchmarks/Android.bp
index 8a25b85..c21c5f2 100644
--- a/media/libeffects/lvm/benchmarks/Android.bp
+++ b/media/libeffects/lvm/benchmarks/Android.bp
@@ -29,9 +29,6 @@
name: "reverb_benchmark",
vendor: true,
host_supported: true,
- include_dirs: [
- "frameworks/av/media/libeffects/lvm/wrapper/Reverb",
- ],
srcs: ["reverb_benchmark.cpp"],
static_libs: [
"libreverb",
diff --git a/media/libeffects/lvm/tests/Android.bp b/media/libeffects/lvm/tests/Android.bp
index 9939ed1..7d7f8b9 100644
--- a/media/libeffects/lvm/tests/Android.bp
+++ b/media/libeffects/lvm/tests/Android.bp
@@ -18,10 +18,6 @@
"EffectReverbTest.cpp",
"EffectTestHelper.cpp",
],
- include_dirs: [
- "frameworks/av/media/libeffects/lvm/lib/Common/lib",
- "frameworks/av/media/libeffects/lvm/wrapper/Reverb",
- ],
static_libs: [
"libaudioutils",
"libreverb",
@@ -108,10 +104,6 @@
proprietary: true,
gtest: false,
- include_dirs: [
- "frameworks/av/media/libeffects/lvm/wrapper/Reverb",
- ],
-
header_libs: [
"libaudioeffects",
],
diff --git a/media/libeffects/lvm/wrapper/Android.bp b/media/libeffects/lvm/wrapper/Android.bp
index e169e3c..1287514 100644
--- a/media/libeffects/lvm/wrapper/Android.bp
+++ b/media/libeffects/lvm/wrapper/Android.bp
@@ -89,6 +89,8 @@
local_include_dirs: ["Reverb"],
+ export_include_dirs: ["Reverb"],
+
header_libs: [
"libhardware_headers",
"libaudioeffects",
diff --git a/media/liberror/Android.bp b/media/liberror/Android.bp
new file mode 100644
index 0000000..f54d354
--- /dev/null
+++ b/media/liberror/Android.bp
@@ -0,0 +1,67 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_av_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_av_license"],
+}
+
+cc_library_headers {
+ name: "libexpectedutils_headers",
+ host_supported: true,
+ vendor_available: true,
+ min_sdk_version: "29",
+ export_include_dirs: [
+ "include",
+ ],
+ header_libs: [
+ "libbase_headers",
+ "libutils_headers",
+ ],
+ export_header_lib_headers: [
+ "libbase_headers",
+ "libutils_headers",
+ ],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.bluetooth",
+ "com.android.media",
+ "com.android.media.swcodec",
+ ],
+}
+
+cc_test_host {
+ name: "libexpectedutils_test",
+ srcs: [
+ "expected_utils_test.cpp",
+ ],
+ shared_libs: [
+ "liblog",
+ ],
+ header_libs: [
+ "libexpectedutils_headers",
+ ],
+}
+
+cc_library_headers {
+ name: "liberror_headers",
+ host_supported: true,
+ vendor_available: true,
+ min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.bluetooth",
+ "com.android.media",
+ "com.android.media.swcodec",
+ ],
+ export_include_dirs: [
+ "include",
+ ],
+ header_libs: [
+ "libexpectedutils_headers",
+ ],
+ export_header_lib_headers: [
+ "libexpectedutils_headers",
+ ],
+}
diff --git a/media/liberror/expected_utils_test.cpp b/media/liberror/expected_utils_test.cpp
new file mode 100644
index 0000000..252210a
--- /dev/null
+++ b/media/liberror/expected_utils_test.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2021 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 <error/expected_utils.h>
+#include <gtest/gtest.h>
+
+#define LOG_TAG "Result-test"
+
+namespace android {
+namespace foo {
+
+class Value {
+ public:
+ explicit Value(int i) : mInt(i) {}
+ Value(const Value&) = delete;
+ Value(Value&&) = default;
+
+ operator int() const { return mInt; }
+
+ private:
+ const int mInt;
+};
+
+class Status {
+ public:
+ explicit Status(int i) : mInt(i) {}
+ Status(const Status&) = delete;
+ Status(Status&&) = default;
+
+ operator int() const { return mInt; }
+
+ private:
+ const int mInt;
+};
+
+bool errorIsOk(const Status& e) {
+ return e == 0;
+}
+
+std::string errorToString(const Status& e) {
+ std::ostringstream str;
+ str << e;
+ return str.str();
+}
+
+using Result = base::expected<Value, Status>;
+
+} // namespace foo
+
+namespace {
+
+using foo::Result;
+using foo::Status;
+using foo::Value;
+
+TEST(Result, ValueOrReturnSuccess) {
+ Result result = []() -> Result {
+ Value intermediate = VALUE_OR_RETURN(Result(Value(3)));
+ return Value(intermediate + 1);
+ }();
+ ASSERT_TRUE(result.ok());
+ EXPECT_EQ(4, result.value());
+}
+
+TEST(Result, ValueOrReturnFailure) {
+ Result result = []() -> Result {
+ Value intermediate = VALUE_OR_RETURN(Result(base::unexpected(Status(2))));
+ return Value(intermediate + 1);
+ }();
+ ASSERT_FALSE(result.ok());
+ EXPECT_EQ(2, result.error());
+}
+
+TEST(Result, ValueOrReturnStatusSuccess) {
+ Status status = []() -> Status {
+ Value intermediate = VALUE_OR_RETURN_STATUS(Result(Value(3)));
+ (void) intermediate;
+ return Status(0);
+ }();
+ EXPECT_EQ(0, status);
+}
+
+TEST(Result, ValueOrReturnStatusFailure) {
+ Status status = []() -> Status {
+ Value intermediate = VALUE_OR_RETURN_STATUS(Result(base::unexpected(Status(1))));
+ (void) intermediate;
+ return Status(0);
+ }();
+ EXPECT_EQ(1, status);
+}
+
+TEST(Result, ReturnIfErrorSuccess) {
+ Result result = []() -> Result {
+ RETURN_IF_ERROR(Status(0));
+ return Value(5);
+ }();
+ ASSERT_TRUE(result.ok());
+ EXPECT_EQ(5, result.value());
+}
+
+TEST(Result, ReturnIfErrorFailure) {
+ Result result = []() -> Result {
+ RETURN_IF_ERROR(Status(4));
+ return Value(5);
+ }();
+ ASSERT_FALSE(result.ok());
+ EXPECT_EQ(4, result.error());
+}
+
+TEST(Result, ReturnStatusIfErrorSuccess) {
+ Status status = []() -> Status {
+ RETURN_STATUS_IF_ERROR(Status(0));
+ return Status(7);
+ }();
+ EXPECT_EQ(7, status);
+}
+
+TEST(Result, ReturnStatusIfErrorFailure) {
+ Status status = []() -> Status {
+ RETURN_STATUS_IF_ERROR(Status(3));
+ return Status(0);
+ }();
+ EXPECT_EQ(3, status);
+}
+
+TEST(Result, ValueOrFatalSuccess) {
+ Value value = VALUE_OR_FATAL(Result(Value(7)));
+ EXPECT_EQ(7, value);
+}
+
+TEST(Result, ValueOrFatalFailure) {
+ EXPECT_DEATH(VALUE_OR_FATAL(Result(base::unexpected(Status(3)))), "");
+}
+
+TEST(Result, FatalIfErrorSuccess) {
+ FATAL_IF_ERROR(Status(0));
+}
+
+TEST(Result, FatalIfErrorFailure) {
+ EXPECT_DEATH(FATAL_IF_ERROR(Status(3)), "");
+}
+
+} // namespace
+} // namespace android
diff --git a/media/liberror/include/error/Result.h b/media/liberror/include/error/Result.h
new file mode 100644
index 0000000..620e6d0
--- /dev/null
+++ b/media/liberror/include/error/Result.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 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 <error/expected_utils.h>
+#include <utils/Errors.h>
+
+namespace android {
+namespace error {
+
+/**
+ * A convenience short-hand for base::expected, where the error type is a status_t.
+ */
+template <typename T>
+using Result = base::expected<T, status_t>;
+
+} // namespace error
+} // namespace android
+
+// Below are the implementations of errorIsOk and errorToString for status_t .
+// This allows status_t to be used in conjunction with the expected_utils.h macros.
+// Unfortuantely, since status_t is merely a typedef for int rather than a unique type, we have to
+// overload these methods for any int, and do so in the global namespace for ADL to work.
+
+inline bool errorIsOk(int status) {
+ return status == android::OK;
+}
+
+inline std::string errorToString(int status) {
+ return android::statusToString(status);
+}
diff --git a/media/liberror/include/error/expected_utils.h b/media/liberror/include/error/expected_utils.h
new file mode 100644
index 0000000..ddc8517
--- /dev/null
+++ b/media/liberror/include/error/expected_utils.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2021 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 <sstream>
+
+#include <android-base/expected.h>
+#include <log/log_main.h>
+
+/**
+ * Useful macros for working with status codes and base::expected.
+ *
+ * These macros facilitate various kinds of strategies for reduction of error-handling-related
+ * boilerplate. They can be can be classified by the following criteria:
+ * - Whether the argument is a standalone status code vs. base::expected (status or value). In the
+ * latter case, the macro will evaluate to the contained value in the case of success.
+ * - Whether to FATAL or return in response to an error.
+ * - In the latter case, whether the enclosing function returns a status code or a base::expected.
+ *
+ * The table below summarizes which macro serves which case, based on those criteria:
+ * +--------------------+------------------+------------------------------------------------------+
+ * | Error response | FATAL | Early return |
+ * | | +---------------------------+--------------------------+
+ * | Expression type | | Function returns expected | Function returns status |
+ * +--------------------+------------------+---------------------------+--------------------------+
+ * | status code | FATAL_IF_ERROR() | RETURN_IF_ERROR() | RETURN_STATUS_IF_ERROR() |
+ * +--------------------+------------------+---------------------------+--------------------------+
+ * | expected | VALUE_OR_FATAL() | VALUE_OR_RETURN() | VALUE_OR_RETURN_STATUS() |
+ * +--------------------+------------------+---------------------------+--------------------------+
+ *
+ * All macros expect that:
+ * - The error type and value value type are movable.
+ * - The macro argument can be assigned to a variable using `auto x = (exp)`.
+ * - The expression errorIsOk(e) for the error type evaluatea to a bool which is true iff the
+ * status is considered success.
+ * - The expression errorToString(e) for a given error type evaluated to a std::string containing a
+ * human-readable version of the status.
+ */
+
+#define VALUE_OR_RETURN(exp) \
+ ({ \
+ auto _tmp = (exp); \
+ if (!_tmp.ok()) return ::android::base::unexpected(std::move(_tmp.error())); \
+ std::move(_tmp.value()); \
+ })
+
+#define VALUE_OR_RETURN_STATUS(exp) \
+ ({ \
+ auto _tmp = (exp); \
+ if (!_tmp.ok()) return std::move(_tmp.error()); \
+ std::move(_tmp.value()); \
+ })
+
+#define VALUE_OR_FATAL(exp) \
+ ({ \
+ auto _tmp = (exp); \
+ LOG_ALWAYS_FATAL_IF(!_tmp.ok(), "Function: %s Line: %d Failed result (%s)", __FUNCTION__, \
+ __LINE__, errorToString(_tmp.error()).c_str()); \
+ std::move(_tmp.value()); \
+ })
+
+#define RETURN_IF_ERROR(exp) \
+ if (auto _tmp = (exp); !errorIsOk(_tmp)) return ::android::base::unexpected(std::move(_tmp));
+
+#define RETURN_STATUS_IF_ERROR(exp) \
+ if (auto _tmp = (exp); !errorIsOk(_tmp)) return _tmp;
+
+#define FATAL_IF_ERROR(exp) \
+ { \
+ auto _tmp = (exp); \
+ LOG_ALWAYS_FATAL_IF(!errorIsOk(_tmp), "Function: %s Line: %d Failed result: (%s)", \
+ __FUNCTION__, __LINE__, errorToString(_tmp).c_str()); \
+ }
diff --git a/media/libheadtracking/Android.bp b/media/libheadtracking/Android.bp
index b0563e2..1d41889 100644
--- a/media/libheadtracking/Android.bp
+++ b/media/libheadtracking/Android.bp
@@ -14,6 +14,7 @@
"HeadTrackingProcessor.cpp",
"ModeSelector.cpp",
"Pose.cpp",
+ "PoseBias.cpp",
"PoseDriftCompensator.cpp",
"PoseRateLimiter.cpp",
"QuaternionUtil.cpp",
@@ -67,6 +68,7 @@
"HeadTrackingProcessor-test.cpp",
"ModeSelector-test.cpp",
"Pose-test.cpp",
+ "PoseBias-test.cpp",
"PoseDriftCompensator-test.cpp",
"PoseRateLimiter-test.cpp",
"QuaternionUtil-test.cpp",
diff --git a/media/libheadtracking/HeadTrackingProcessor.cpp b/media/libheadtracking/HeadTrackingProcessor.cpp
index b2d2dbd..71fae8a 100644
--- a/media/libheadtracking/HeadTrackingProcessor.cpp
+++ b/media/libheadtracking/HeadTrackingProcessor.cpp
@@ -17,7 +17,7 @@
#include "media/HeadTrackingProcessor.h"
#include "ModeSelector.h"
-#include "PoseDriftCompensator.h"
+#include "PoseBias.h"
#include "QuaternionUtil.h"
#include "ScreenHeadFusion.h"
#include "StillnessDetector.h"
@@ -33,14 +33,6 @@
public:
HeadTrackingProcessorImpl(const Options& options, HeadTrackingMode initialMode)
: mOptions(options),
- mHeadPoseDriftCompensator(PoseDriftCompensator::Options{
- .translationalDriftTimeConstant = options.translationalDriftTimeConstant,
- .rotationalDriftTimeConstant = options.rotationalDriftTimeConstant,
- }),
- mScreenPoseDriftCompensator(PoseDriftCompensator::Options{
- .translationalDriftTimeConstant = options.translationalDriftTimeConstant,
- .rotationalDriftTimeConstant = options.rotationalDriftTimeConstant,
- }),
mHeadStillnessDetector(StillnessDetector::Options{
.defaultValue = false,
.windowDuration = options.autoRecenterWindowDuration,
@@ -65,7 +57,8 @@
const Twist3f& headTwist) override {
Pose3f predictedWorldToHead =
worldToHead * integrate(headTwist, mOptions.predictionDuration);
- mHeadPoseDriftCompensator.setInput(timestamp, predictedWorldToHead);
+ mHeadPoseBias.setInput(predictedWorldToHead);
+ mHeadStillnessDetector.setInput(timestamp, predictedWorldToHead);
mWorldToHeadTimestamp = timestamp;
}
@@ -76,8 +69,9 @@
mPhysicalToLogicalAngle = mPendingPhysicalToLogicalAngle;
}
- mScreenPoseDriftCompensator.setInput(
- timestamp, worldToScreen * Pose3f(rotateY(-mPhysicalToLogicalAngle)));
+ Pose3f worldToLogicalScreen = worldToScreen * Pose3f(rotateY(-mPhysicalToLogicalAngle));
+ mScreenPoseBias.setInput(worldToLogicalScreen);
+ mScreenStillnessDetector.setInput(timestamp, worldToLogicalScreen);
mWorldToScreenTimestamp = timestamp;
}
@@ -92,9 +86,7 @@
void calculate(int64_t timestamp) override {
// Handle the screen first, since it might trigger a recentering of the head.
if (mWorldToScreenTimestamp.has_value()) {
- const Pose3f worldToLogicalScreen = mScreenPoseDriftCompensator.getOutput();
- mScreenStillnessDetector.setInput(mWorldToScreenTimestamp.value(),
- worldToLogicalScreen);
+ const Pose3f worldToLogicalScreen = mScreenPoseBias.getOutput();
bool screenStable = mScreenStillnessDetector.calculate(timestamp);
mModeSelector.setScreenStable(mWorldToScreenTimestamp.value(), screenStable);
// Whenever the screen is unstable, recenter the head pose.
@@ -107,12 +99,11 @@
// Handle head.
if (mWorldToHeadTimestamp.has_value()) {
- Pose3f worldToHead = mHeadPoseDriftCompensator.getOutput();
- mHeadStillnessDetector.setInput(mWorldToHeadTimestamp.value(), worldToHead);
+ Pose3f worldToHead = mHeadPoseBias.getOutput();
// Auto-recenter.
if (mHeadStillnessDetector.calculate(timestamp)) {
recenter(true, false);
- worldToHead = mHeadPoseDriftCompensator.getOutput();
+ worldToHead = mHeadPoseBias.getOutput();
}
mScreenHeadFusion.setWorldToHeadPose(mWorldToHeadTimestamp.value(), worldToHead);
@@ -143,11 +134,11 @@
void recenter(bool recenterHead, bool recenterScreen) override {
if (recenterHead) {
- mHeadPoseDriftCompensator.recenter();
+ mHeadPoseBias.recenter();
mHeadStillnessDetector.reset();
}
if (recenterScreen) {
- mScreenPoseDriftCompensator.recenter();
+ mScreenPoseBias.recenter();
mScreenStillnessDetector.reset();
}
@@ -170,8 +161,8 @@
std::optional<int64_t> mWorldToHeadTimestamp;
std::optional<int64_t> mWorldToScreenTimestamp;
Pose3f mHeadToStagePose;
- PoseDriftCompensator mHeadPoseDriftCompensator;
- PoseDriftCompensator mScreenPoseDriftCompensator;
+ PoseBias mHeadPoseBias;
+ PoseBias mScreenPoseBias;
StillnessDetector mHeadStillnessDetector;
StillnessDetector mScreenStillnessDetector;
ScreenHeadFusion mScreenHeadFusion;
diff --git a/media/libheadtracking/PoseBias-test.cpp b/media/libheadtracking/PoseBias-test.cpp
new file mode 100644
index 0000000..9f42a2c
--- /dev/null
+++ b/media/libheadtracking/PoseBias-test.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 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 <gtest/gtest.h>
+
+#include "PoseBias.h"
+#include "QuaternionUtil.h"
+#include "TestUtil.h"
+
+namespace android {
+namespace media {
+namespace {
+
+using Eigen::Quaternionf;
+using Eigen::Vector3f;
+
+TEST(PoseBias, Initial) {
+ PoseBias bias;
+ EXPECT_EQ(bias.getOutput(), Pose3f());
+}
+
+TEST(PoseBias, Basic) {
+ Pose3f pose1({1, 2, 3}, Quaternionf::UnitRandom());
+ Pose3f pose2({4, 5, 6}, Quaternionf::UnitRandom());
+
+ PoseBias bias;
+ bias.setInput(pose1);
+ EXPECT_EQ(pose1, bias.getOutput());
+ bias.recenter();
+ EXPECT_EQ(bias.getOutput(), Pose3f());
+ bias.setInput(pose2);
+ EXPECT_EQ(bias.getOutput(), pose1.inverse() * pose2);
+ bias.recenter();
+ EXPECT_EQ(bias.getOutput(), Pose3f());
+}
+
+} // namespace
+} // namespace media
+} // namespace android
diff --git a/media/libheadtracking/PoseBias.cpp b/media/libheadtracking/PoseBias.cpp
new file mode 100644
index 0000000..33afca6
--- /dev/null
+++ b/media/libheadtracking/PoseBias.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 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 "PoseBias.h"
+
+namespace android {
+namespace media {
+
+void PoseBias::setInput(const Pose3f& input) {
+ mLastWorldToInput = input;
+}
+
+void PoseBias::recenter() {
+ mBiasToWorld = mLastWorldToInput.inverse();
+}
+
+Pose3f PoseBias::getOutput() const {
+ return mBiasToWorld * mLastWorldToInput;
+}
+
+} // namespace media
+} // namespace android
diff --git a/media/libheadtracking/PoseBias.h b/media/libheadtracking/PoseBias.h
new file mode 100644
index 0000000..9acb49d
--- /dev/null
+++ b/media/libheadtracking/PoseBias.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 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 "media/Pose.h"
+
+namespace android {
+namespace media {
+
+/**
+ * Biasing for a stream of poses.
+ *
+ * This filter takes a stream of poses and at any time during the stream, can change the frame of
+ * reference for the stream to be that of the last pose received, via the recenter() operation.
+ *
+ * Typical usage:
+ * PoseBias bias;
+ *
+ * bias.setInput(...);
+ * output = bias.getOutput();
+ * bias.setInput(...);
+ * output = bias.getOutput();
+ * bias.setInput(...);
+ * output = bias.getOutput();
+ * bias.recenter(); // Reference frame is now equal to the last input.
+ * output = bias.getOutput(); // This is now the identity pose.
+ *
+ * There doesn't need to be a 1:1 correspondence between setInput() and getOutput() calls.
+ * The initial bias point is identity.
+ *
+ * This implementation is thread-compatible, but not thread-safe.
+ */
+class PoseBias {
+ public:
+ void setInput(const Pose3f& input);
+
+ void recenter();
+
+ Pose3f getOutput() const;
+
+ private:
+ Pose3f mLastWorldToInput;
+ Pose3f mBiasToWorld;
+};
+
+} // namespace media
+} // namespace android
diff --git a/media/libheadtracking/PoseProcessingGraph.png b/media/libheadtracking/PoseProcessingGraph.png
index 0363068..325b667 100644
--- a/media/libheadtracking/PoseProcessingGraph.png
+++ b/media/libheadtracking/PoseProcessingGraph.png
Binary files differ
diff --git a/media/libheadtracking/README.md b/media/libheadtracking/README.md
index 3d5b71a..44f7bb2 100644
--- a/media/libheadtracking/README.md
+++ b/media/libheadtracking/README.md
@@ -115,11 +115,9 @@
#### World
It is sometimes convenient to use an intermediate frame when dealing with
-head-to-screen transforms. The “world” frame is an arbitrary frame of reference
-in the physical world, relative to which we can measure the head pose and screen
-pose. In (very common) cases when we can’t establish such an absolute frame, we
-can take each measurement relative to a separate, arbitrary frame and high-pass
-the result.
+head-to-screen transforms. The “world” frame is a frame of reference in the
+physical world, relative to which we can measure the head pose and screen pose.
+It is arbitrary, but expected to be stable (fixed).
## Processing Description
@@ -133,15 +131,10 @@
The Predictor block gets pose + twist (pose derivative) and extrapolates to
obtain a predicted head pose (w/ given latency).
-### Drift / Bias Compensator
+### Bias
-The Drift / Bias Compensator blocks serve two purposes:
-
-- Compensate for floating reference axes by applying a high-pass filter, which
- slowly pulls the pose toward identity.
-- Establish the reference frame for the poses by having the ability to set the
- current pose as the reference for future poses (recentering). Effectively,
- this is resetting the filter state to identity.
+The Bias blocks establish the reference frame for the poses by having the
+ability to set the current pose as the reference for future poses (recentering).
### Orientation Compensation
@@ -157,6 +150,14 @@
module may indicate that the user is likely not in front of the screen via the
“valid” output.
+### Stillness Detector
+
+The stillness detector blocks detect when their incoming pose stream has been
+stable for a given amount of time (allowing for a configurable amount of error).
+When the head is considered still, we would trigger a recenter operation
+(“auto-recentering”) and when the screen is considered not still, the mode
+selector would use this information to force static mode.
+
### Mode Selector
The Mode Selector block aggregates the various sources of pose information into
@@ -168,7 +169,8 @@
- If the desired mode is static, the actual mode is static.
- If the desired mode is world-relative:
- - If head poses are fresh, the actual mode is world-relative.
+ - If head and screen poses are fresh and the screen is stable (stillness
+ detector output is true), the actual mode is world-relative.
- Otherwise the actual mode is static.
- If the desired mode is screen-relative:
- If head and screen poses are fresh and the ‘valid’ signal is asserted, the
diff --git a/media/libheadtracking/SensorPoseProvider.cpp b/media/libheadtracking/SensorPoseProvider.cpp
index ec5e1ec..f3f9b77 100644
--- a/media/libheadtracking/SensorPoseProvider.cpp
+++ b/media/libheadtracking/SensorPoseProvider.cpp
@@ -133,14 +133,14 @@
{
std::lock_guard lock(mMutex);
- mEnabledSensorFormats.emplace(sensor, format);
+ mEnabledSensorsExtra.emplace(sensor, SensorExtra{ .format = format });
}
// Enable the sensor.
if (mQueue->enableSensor(sensor, samplingPeriod.count(), 0, 0)) {
ALOGE("Failed to enable sensor");
std::lock_guard lock(mMutex);
- mEnabledSensorFormats.erase(sensor);
+ mEnabledSensorsExtra.erase(sensor);
return false;
}
@@ -151,7 +151,7 @@
void stopSensor(int handle) override {
mEnabledSensors.erase(handle);
std::lock_guard lock(mMutex);
- mEnabledSensorFormats.erase(handle);
+ mEnabledSensorsExtra.erase(handle);
}
private:
@@ -159,6 +159,7 @@
kUnknown,
kQuaternion,
kRotationVectorsAndFlags,
+ kRotationVectorsAndDiscontinuityCount,
};
struct PoseEvent {
@@ -167,13 +168,18 @@
bool isNewReference;
};
+ struct SensorExtra {
+ DataFormat format;
+ std::optional<int32_t> discontinuityCount;
+ };
+
sp<Looper> mLooper;
Listener* const mListener;
SensorManager* const mSensorManager;
std::thread mThread;
std::mutex mMutex;
std::map<int32_t, SensorEnableGuard> mEnabledSensors;
- std::map<int32_t, DataFormat> mEnabledSensorFormats GUARDED_BY(mMutex);
+ std::map<int32_t, SensorExtra> mEnabledSensorsExtra GUARDED_BY(mMutex);
sp<SensorEventQueue> mQueue;
// We must do some of the initialization operations on the worker thread, because the API relies
@@ -248,17 +254,16 @@
}
void handleEvent(const ASensorEvent& event) {
- DataFormat format;
+ PoseEvent value;
{
std::lock_guard lock(mMutex);
- auto iter = mEnabledSensorFormats.find(event.sensor);
- if (iter == mEnabledSensorFormats.end()) {
+ auto iter = mEnabledSensorsExtra.find(event.sensor);
+ if (iter == mEnabledSensorsExtra.end()) {
// This can happen if we have any pending events shortly after stopping.
return;
}
- format = iter->second;
+ value = parseEvent(event, iter->second.format, &iter->second.discontinuityCount);
}
- auto value = parseEvent(event, format);
mListener->onPose(event.timestamp, event.sensor, value.pose, value.twist,
value.isNewReference);
}
@@ -274,6 +279,10 @@
return DataFormat::kQuaternion;
}
+ if (sensor->getType() == ASENSOR_TYPE_HEAD_TRACKER) {
+ return DataFormat::kRotationVectorsAndDiscontinuityCount;
+ }
+
if (sensor->getStringType() == "com.google.hardware.sensor.hid_dynamic.headtracker") {
return DataFormat::kRotationVectorsAndFlags;
}
@@ -313,8 +322,8 @@
return std::nullopt;
}
- static PoseEvent parseEvent(const ASensorEvent& event, DataFormat format) {
- // TODO(ytai): Add more types.
+ static PoseEvent parseEvent(const ASensorEvent& event, DataFormat format,
+ std::optional<int32_t>* discontinutyCount) {
switch (format) {
case DataFormat::kQuaternion: {
Eigen::Quaternionf quat(event.data[3], event.data[0], event.data[1], event.data[2]);
@@ -338,6 +347,21 @@
(flags & (1 << 0)) != 0};
}
+ case DataFormat::kRotationVectorsAndDiscontinuityCount: {
+ Eigen::Vector3f rotation = {event.head_tracker.rx, event.head_tracker.ry,
+ event.head_tracker.rz};
+ Eigen::Vector3f twist = {event.head_tracker.vx, event.head_tracker.vy,
+ event.head_tracker.vz};
+ Eigen::Quaternionf quat = rotationVectorToQuaternion(rotation);
+ bool isNewReference =
+ !discontinutyCount->has_value() ||
+ discontinutyCount->value() != event.head_tracker.discontinuity_count;
+ *discontinutyCount = event.head_tracker.discontinuity_count;
+
+ return PoseEvent{Pose3f(quat), Twist3f(Eigen::Vector3f::Zero(), twist),
+ isNewReference};
+ }
+
default:
LOG_ALWAYS_FATAL("Unexpected sensor type: %d", static_cast<int>(format));
}
diff --git a/media/libheadtracking/StillnessDetector-test.cpp b/media/libheadtracking/StillnessDetector-test.cpp
index 02f9d8a..b6cd479 100644
--- a/media/libheadtracking/StillnessDetector-test.cpp
+++ b/media/libheadtracking/StillnessDetector-test.cpp
@@ -83,13 +83,10 @@
EXPECT_EQ(mDefaultValue, detector.calculate(300));
detector.setInput(600, baseline);
EXPECT_EQ(mDefaultValue, detector.calculate(600));
- detector.setInput(900, withinThreshold);
- EXPECT_EQ(mDefaultValue, detector.calculate(900));
+ detector.setInput(1299, withinThreshold);
+ EXPECT_FALSE(detector.calculate(1299));
detector.setInput(1300, baseline);
- EXPECT_FALSE(detector.calculate(1300));
- detector.setInput(1500, baseline);
- EXPECT_FALSE(detector.calculate(1899));
- EXPECT_TRUE(detector.calculate(1900));
+ EXPECT_TRUE(detector.calculate(1300));
}
TEST_P(StillnessDetectorTest, NotStillRotation) {
@@ -110,13 +107,10 @@
EXPECT_EQ(mDefaultValue, detector.calculate(300));
detector.setInput(600, baseline);
EXPECT_EQ(mDefaultValue, detector.calculate(600));
- detector.setInput(900, withinThreshold);
- EXPECT_EQ(mDefaultValue, detector.calculate(900));
+ detector.setInput(1299, withinThreshold);
+ EXPECT_FALSE(detector.calculate(1299));
detector.setInput(1300, baseline);
- EXPECT_FALSE(detector.calculate(1300));
- detector.setInput(1500, baseline);
- EXPECT_FALSE(detector.calculate(1899));
- EXPECT_TRUE(detector.calculate(1900));
+ EXPECT_TRUE(detector.calculate(1300));
}
TEST_P(StillnessDetectorTest, Suppression) {
@@ -134,10 +128,10 @@
EXPECT_TRUE(detector.calculate(1000));
detector.setInput(1100, outsideThreshold);
EXPECT_FALSE(detector.calculate(1100));
- detector.setInput(2000, middlePoint);
- EXPECT_FALSE(detector.calculate(2000));
- EXPECT_FALSE(detector.calculate(2099));
- EXPECT_TRUE(detector.calculate(2100));
+ detector.setInput(1500, middlePoint);
+ EXPECT_FALSE(detector.calculate(1500));
+ EXPECT_FALSE(detector.calculate(1999));
+ EXPECT_TRUE(detector.calculate(2000));
}
TEST_P(StillnessDetectorTest, Reset) {
@@ -150,8 +144,8 @@
const Pose3f withinThreshold =
baseline * Pose3f(Vector3f(0.3, -0.3, 0), rotateX(0.01) * rotateY(-0.01));
EXPECT_EQ(mDefaultValue, detector.calculate(0));
- detector.setInput(0, baseline);
- EXPECT_EQ(mDefaultValue, detector.calculate(0));
+ detector.setInput(300, baseline);
+ EXPECT_EQ(mDefaultValue, detector.calculate(300));
detector.reset();
detector.setInput(600, baseline);
EXPECT_EQ(mDefaultValue, detector.calculate(600));
diff --git a/media/libheadtracking/StillnessDetector.cpp b/media/libheadtracking/StillnessDetector.cpp
index 9806352..be7c893 100644
--- a/media/libheadtracking/StillnessDetector.cpp
+++ b/media/libheadtracking/StillnessDetector.cpp
@@ -36,17 +36,22 @@
bool StillnessDetector::calculate(int64_t timestamp) {
discardOld(timestamp);
- // Check whether all the poses in the queue are in the proximity of the new
- // one. We want to do this before checking the overriding conditions below, in order to update
- // the suppression deadline correctly.
+ // Check whether all the poses in the queue are in the proximity of the new one. We want to do
+ // this before checking the overriding conditions below, in order to update the suppression
+ // deadline correctly. We always go from end to start, to find the most recent pose that
+ // violated stillness and update the suppression deadline if it has not been set or if the new
+ // one ends after the current one.
bool moved = false;
if (!mFifo.empty()) {
- for (auto iter = mFifo.begin(); iter != mFifo.end() - 1; ++iter) {
+ for (auto iter = mFifo.rbegin() + 1; iter != mFifo.rend(); ++iter) {
const auto& event = *iter;
if (!areNear(event.pose, mFifo.back().pose)) {
// Enable suppression for the duration of the window.
- mSuppressionDeadline = timestamp + mOptions.windowDuration;
+ int64_t deadline = event.timestamp + mOptions.windowDuration;
+ if (!mSuppressionDeadline.has_value() || mSuppressionDeadline.value() < deadline) {
+ mSuppressionDeadline = deadline;
+ }
moved = true;
break;
}
diff --git a/media/libheadtracking/include/media/HeadTrackingProcessor.h b/media/libheadtracking/include/media/HeadTrackingProcessor.h
index 2af560e..1744be3 100644
--- a/media/libheadtracking/include/media/HeadTrackingProcessor.h
+++ b/media/libheadtracking/include/media/HeadTrackingProcessor.h
@@ -38,8 +38,6 @@
struct Options {
float maxTranslationalVelocity = std::numeric_limits<float>::infinity();
float maxRotationalVelocity = std::numeric_limits<float>::infinity();
- float translationalDriftTimeConstant = std::numeric_limits<float>::infinity();
- float rotationalDriftTimeConstant = std::numeric_limits<float>::infinity();
int64_t freshnessTimeout = std::numeric_limits<int64_t>::max();
float predictionDuration = 0;
int64_t autoRecenterWindowDuration = std::numeric_limits<int64_t>::max();
diff --git a/media/libheadtracking/include/media/Twist.h b/media/libheadtracking/include/media/Twist.h
index e2fc203..291cea3 100644
--- a/media/libheadtracking/include/media/Twist.h
+++ b/media/libheadtracking/include/media/Twist.h
@@ -56,6 +56,16 @@
mRotationalVelocity.isApprox(other.mRotationalVelocity, prec);
}
+ template<typename T>
+ Twist3f operator*(const T& s) const {
+ return Twist3f(mTranslationalVelocity * s, mRotationalVelocity * s);
+ }
+
+ template<typename T>
+ Twist3f operator/(const T& s) const {
+ return Twist3f(mTranslationalVelocity / s, mRotationalVelocity / s);
+ }
+
private:
Eigen::Vector3f mTranslationalVelocity;
Eigen::Vector3f mRotationalVelocity;
diff --git a/media/libheif/Android.bp b/media/libheif/Android.bp
index 6a3427e..55ba61a 100644
--- a/media/libheif/Android.bp
+++ b/media/libheif/Android.bp
@@ -26,7 +26,5 @@
"-Wall",
],
- include_dirs: [],
-
export_include_dirs: ["include"],
}
diff --git a/media/libheif/HeifDecoderImpl.cpp b/media/libheif/HeifDecoderImpl.cpp
index fcac551..041b427 100644
--- a/media/libheif/HeifDecoderImpl.cpp
+++ b/media/libheif/HeifDecoderImpl.cpp
@@ -26,6 +26,7 @@
#include <binder/IMemory.h>
#include <binder/MemoryDealer.h>
#include <drm/drm_framework_common.h>
+#include <log/log.h>
#include <media/mediametadataretriever.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -422,7 +423,13 @@
initFrameInfo(&mSequenceInfo, videoFrame);
- mSequenceLength = atoi(mRetriever->extractMetadata(METADATA_KEY_VIDEO_FRAME_COUNT));
+ const char* frameCount = mRetriever->extractMetadata(METADATA_KEY_VIDEO_FRAME_COUNT);
+ if (frameCount == nullptr) {
+ android_errorWriteWithInfoLog(0x534e4554, "215002587", -1, NULL, 0);
+ ALOGD("No valid sequence information in metadata");
+ return false;
+ }
+ mSequenceLength = atoi(frameCount);
if (defaultInfo == nullptr) {
defaultInfo = &mSequenceInfo;
@@ -485,6 +492,11 @@
mOutputColor = HAL_PIXEL_FORMAT_BGRA_8888;
break;
}
+ case kHeifColorFormat_RGBA_1010102:
+ {
+ mOutputColor = HAL_PIXEL_FORMAT_RGBA_1010102;
+ break;
+ }
default:
ALOGE("Unsupported output color format %d", heifColor);
return false;
diff --git a/media/libheif/include/HeifDecoderAPI.h b/media/libheif/include/HeifDecoderAPI.h
index 9073672..fa51aef 100644
--- a/media/libheif/include/HeifDecoderAPI.h
+++ b/media/libheif/include/HeifDecoderAPI.h
@@ -23,9 +23,10 @@
* The output color pixel format of heif decoder.
*/
typedef enum {
- kHeifColorFormat_RGB565 = 0,
- kHeifColorFormat_RGBA_8888 = 1,
- kHeifColorFormat_BGRA_8888 = 2,
+ kHeifColorFormat_RGB565 = 0,
+ kHeifColorFormat_RGBA_8888 = 1,
+ kHeifColorFormat_BGRA_8888 = 2,
+ kHeifColorFormat_RGBA_1010102 = 3,
} HeifColorFormat;
/*
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 4a2523f..2dd5784 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -19,6 +19,10 @@
name: "libmedia_headers",
vendor_available: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
export_include_dirs: ["include"],
header_libs: [
@@ -214,6 +218,11 @@
name: "libmedia_midiiowrapper",
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ ],
+
srcs: ["MidiIoWrapper.cpp"],
@@ -441,6 +450,6 @@
apex_available: [
"//apex_available:platform",
- "com.android.media"
+ "com.android.media",
],
}
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index 67d33fa..85768bd 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -20,12 +20,14 @@
#define LOG_TAG "MediaProfiles"
#include <stdlib.h>
+#include <utils/misc.h>
#include <utils/Log.h>
#include <utils/Vector.h>
#include <cutils/properties.h>
#include <expat.h>
#include <media/MediaProfiles.h>
#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaCodecConstants.h>
#include <OMX_Video.h>
#include <sys/stat.h>
@@ -86,7 +88,24 @@
{"h263", VIDEO_ENCODER_H263},
{"h264", VIDEO_ENCODER_H264},
{"m4v", VIDEO_ENCODER_MPEG_4_SP},
- {"hevc", VIDEO_ENCODER_HEVC}
+ {"vp8", VIDEO_ENCODER_VP8},
+ {"hevc", VIDEO_ENCODER_HEVC},
+ {"vp9", VIDEO_ENCODER_VP9},
+ {"dolbyvision", VIDEO_ENCODER_DOLBY_VISION},
+};
+
+const MediaProfiles::NameToTagMap MediaProfiles::sChromaSubsamplingNameMap[] = {
+ {"yuv 4:2:0", CHROMA_SUBSAMPLING_YUV_420},
+ {"yuv 4:2:2", CHROMA_SUBSAMPLING_YUV_422},
+ {"yuv 4:4:4", CHROMA_SUBSAMPLING_YUV_444},
+};
+
+const MediaProfiles::NameToTagMap MediaProfiles::sHdrFormatNameMap[] = {
+ {"sdr", HDR_FORMAT_NONE},
+ {"hlg", HDR_FORMAT_HLG},
+ {"hdr10", HDR_FORMAT_HDR10},
+ {"hdr10+", HDR_FORMAT_HDR10PLUS},
+ {"dolbyvision", HDR_FORMAT_DOLBY_VISION},
};
const MediaProfiles::NameToTagMap MediaProfiles::sAudioEncoderNameMap[] = {
@@ -164,12 +183,18 @@
MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec UNUSED)
{
ALOGV("video codec:");
- ALOGV("codec = %d", codec.mCodec);
+ ALOGV("codec = %d (%s)", codec.mCodec,
+ findNameForTag(sVideoEncoderNameMap, NELEM(sVideoEncoderNameMap), codec.mCodec));
ALOGV("bit rate: %d", codec.mBitRate);
ALOGV("frame width: %d", codec.mFrameWidth);
ALOGV("frame height: %d", codec.mFrameHeight);
ALOGV("frame rate: %d", codec.mFrameRate);
ALOGV("profile: %d", codec.mProfile);
+ ALOGV("chroma: %s", findNameForTag(sChromaSubsamplingNameMap, NELEM(sChromaSubsamplingNameMap),
+ codec.mChromaSubsampling));
+ ALOGV("bit depth: %d", codec.mBitDepth);
+ ALOGV("hdr format: %s", findNameForTag(sHdrFormatNameMap, NELEM(sHdrFormatNameMap),
+ codec.mHdrFormat));
}
/*static*/ void
@@ -232,6 +257,155 @@
return tag;
}
+/*static*/ const char *
+MediaProfiles::findNameForTag(
+ const MediaProfiles::NameToTagMap *map, size_t nMappings, int tag, const char *def_)
+{
+ for (size_t i = 0; i < nMappings; ++i) {
+ if (map[i].tag == tag) {
+ return map[i].name;
+ }
+ }
+ return def_;
+}
+
+/*static*/ bool
+MediaProfiles::detectAdvancedVideoProfile(
+ video_encoder codec, int profile,
+ chroma_subsampling *chroma, int *bitDepth, hdr_format *hdr)
+{
+ // default values
+ *chroma = CHROMA_SUBSAMPLING_YUV_420;
+ *bitDepth = 8;
+ *hdr = HDR_FORMAT_NONE;
+
+ switch (codec) {
+ case VIDEO_ENCODER_H263:
+ case VIDEO_ENCODER_MPEG_4_SP:
+ case VIDEO_ENCODER_VP8:
+ // these are always 4:2:0 SDR 8-bit
+ return true;
+
+ case VIDEO_ENCODER_H264:
+ switch (profile) {
+ case AVCProfileBaseline:
+ case AVCProfileConstrainedBaseline:
+ case AVCProfileMain:
+ case AVCProfileExtended:
+ case AVCProfileHigh:
+ case AVCProfileConstrainedHigh:
+ return true;
+ case AVCProfileHigh10:
+ // returning false here as this could be an HLG stream
+ *bitDepth = 10;
+ return false;
+ case AVCProfileHigh422:
+ *chroma = CHROMA_SUBSAMPLING_YUV_422;
+ // returning false here as bit-depth could be 8 or 10
+ return false;
+ case AVCProfileHigh444:
+ *chroma = CHROMA_SUBSAMPLING_YUV_444;
+ // returning false here as bit-depth could be 8 or 10
+ return false;
+ default:
+ return false;
+ }
+ // flow does not get here
+
+ case VIDEO_ENCODER_HEVC:
+ switch (profile) {
+ case HEVCProfileMain:
+ return true;
+ case HEVCProfileMain10:
+ *bitDepth = 10;
+ // returning false here as this could be an HLG stream
+ return false;
+ case HEVCProfileMain10HDR10:
+ *bitDepth = 10;
+ *hdr = HDR_FORMAT_HDR10;
+ return true;
+ case HEVCProfileMain10HDR10Plus:
+ *bitDepth = 10;
+ *hdr = HDR_FORMAT_HDR10PLUS;
+ return true;
+ default:
+ return false;
+ }
+ // flow does not get here
+
+ case VIDEO_ENCODER_VP9:
+ switch (profile) {
+ case VP9Profile0:
+ return true;
+ case VP9Profile2:
+ // this is always 10-bit on Android */
+ *bitDepth = 10;
+ // returning false here as this could be an HLG stream
+ return false;
+ case VP9Profile2HDR:
+ // this is always 10-bit on Android */
+ *bitDepth = 10;
+ *hdr = HDR_FORMAT_HDR10;
+ return true;
+ case VP9Profile2HDR10Plus:
+ *bitDepth = 10;
+ *hdr = HDR_FORMAT_HDR10PLUS;
+ return true;
+ default:
+ return false;
+ }
+ // flow does not get here
+
+ case VIDEO_ENCODER_DOLBY_VISION:
+ {
+ // for Dolby Vision codec we always assume 10-bit DV
+ *bitDepth = 10;
+ *hdr = HDR_FORMAT_DOLBY_VISION;
+
+ switch (profile) {
+ case DolbyVisionProfileDvheDer /* profile 2 deprecated */:
+ case DolbyVisionProfileDvheDen /* profile 3 deprecated */:
+ case DolbyVisionProfileDvavPer /* profile 0 deprecated */:
+ case DolbyVisionProfileDvavPen /* profile 1 deprecated */:
+ case DolbyVisionProfileDvheDtr /* dvhe.04 */:
+ case DolbyVisionProfileDvheStn /* dvhe.05 */:
+ case DolbyVisionProfileDvheDth /* profile 6 deprecated */:
+ case DolbyVisionProfileDvheDtb /* dvhe.07 */:
+ case DolbyVisionProfileDvheSt /* dvhe.08 */:
+ case DolbyVisionProfileDvavSe /* dvav.09 */:
+ case DolbyVisionProfileDvav110 /* dvav1.10 */:
+ return true;
+ default:
+ return false;
+ }
+ // flow does not get here
+ }
+
+ case VIDEO_ENCODER_AV1:
+ switch (profile) {
+ case AV1ProfileMain10:
+ *bitDepth = 10;
+ // returning false here as this could be an HLG stream
+ return false;
+ case AV1ProfileMain10HDR10:
+ *bitDepth = 10;
+ *hdr = HDR_FORMAT_HDR10;
+ return true;
+ case AV1ProfileMain10HDR10Plus:
+ *bitDepth = 10;
+ *hdr = HDR_FORMAT_HDR10PLUS;
+ return true;
+ default:
+ return false;
+ }
+ // flow does not get here
+
+ default:
+ return false;
+ }
+ // flow does not get here
+}
+
/*static*/ void
MediaProfiles::createVideoCodec(const char **atts, size_t natts, MediaProfiles *profiles)
{
@@ -250,13 +424,56 @@
}
int profile = -1;
- if (natts >= 12 && !strcmp("profile", atts[10])) {
- profile = atoi(atts[11]);
+ chroma_subsampling chroma = CHROMA_SUBSAMPLING_YUV_420;
+ int bitDepth = 8;
+ hdr_format hdr = HDR_FORMAT_NONE;
+ if (codec == VIDEO_ENCODER_DOLBY_VISION) {
+ bitDepth = 10;
+ hdr = HDR_FORMAT_DOLBY_VISION;
}
- VideoCodec videoCodec {
+ if (natts >= 12 && !strcmp("profile", atts[10])) {
+ profile = atoi(atts[11]);
+ if (!detectAdvancedVideoProfile(
+ (video_encoder)codec, profile, &chroma, &bitDepth, &hdr)) {
+ // if not detected read values from the attributes
+ for (size_t ix = 12; natts >= ix + 2; ix += 2) {
+ if (!strcmp("chroma", atts[ix])) {
+ int chromaTag = findTagForName(sChromaSubsamplingNameMap,
+ NELEM(sChromaSubsamplingNameMap), atts[ix + 1]);
+ if (chromaTag == -1) {
+ ALOGE("MediaProfiles::createVideoCodec invalid chroma %s", atts[ix + 1]);
+ return;
+ } else {
+ chroma = (chroma_subsampling)chromaTag;
+ }
+ } else if (!strcmp("bitDepth", atts[ix])) {
+ bitDepth = atoi(atts[ix + 1]);
+ if (bitDepth < 8 || bitDepth > 16) {
+ ALOGE("MediaProfiles::createVideoCodec invalid bidDepth %s", atts[ix + 1]);
+ return;
+ }
+ } else if (!strcmp("hdr", atts[ix])) {
+ int hdrTag = findTagForName(sHdrFormatNameMap,
+ NELEM(sHdrFormatNameMap), atts[ix + 1]);
+ if (hdrTag == -1) {
+ ALOGE("MediaProfiles::createVideoCodec invalid hdr %s", atts[ix + 1]);
+ return;
+ } else {
+ hdr = (hdr_format)hdrTag;
+ }
+ } else {
+ // ignoring here. TODO: rewrite this whole file to ignore invalid attrs
+ ALOGD("MediaProfiles::createVideoCodec ignoring invalid attr %s", atts[ix]);
+ }
+ }
+ }
+ }
+
+ VideoCodec videoCodec{
static_cast<video_encoder>(codec),
- atoi(atts[3]), atoi(atts[5]), atoi(atts[7]), atoi(atts[9]), profile };
+ atoi(atts[3]) /* bitRate */, atoi(atts[5]) /* width */, atoi(atts[7]) /* height */,
+ atoi(atts[9]) /* frameRate */, profile, chroma, bitDepth, hdr };
logVideoCodec(videoCodec);
size_t nCamcorderProfiles;
diff --git a/media/libmedia/MediaResource.cpp b/media/libmedia/MediaResource.cpp
index ec52a49..a6f0b60 100644
--- a/media/libmedia/MediaResource.cpp
+++ b/media/libmedia/MediaResource.cpp
@@ -43,10 +43,10 @@
}
//static
-MediaResource MediaResource::CodecResource(bool secure, bool video, int64_t instanceCount) {
+MediaResource MediaResource::CodecResource(bool secure, SubType subType, int64_t instanceCount) {
return MediaResource(
secure ? Type::kSecureCodec : Type::kNonSecureCodec,
- video ? SubType::kVideoCodec : SubType::kAudioCodec,
+ subType,
instanceCount);
}
diff --git a/media/libmedia/include/media/MediaProfiles.h b/media/libmedia/include/media/MediaProfiles.h
index 4a898e2..e75b694 100644
--- a/media/libmedia/include/media/MediaProfiles.h
+++ b/media/libmedia/include/media/MediaProfiles.h
@@ -81,6 +81,19 @@
AUDIO_DECODER_WMA,
};
+enum chroma_subsampling {
+ CHROMA_SUBSAMPLING_YUV_420,
+ CHROMA_SUBSAMPLING_YUV_422,
+ CHROMA_SUBSAMPLING_YUV_444,
+};
+
+enum hdr_format {
+ HDR_FORMAT_NONE,
+ HDR_FORMAT_HLG,
+ HDR_FORMAT_HDR10,
+ HDR_FORMAT_HDR10PLUS,
+ HDR_FORMAT_DOLBY_VISION,
+};
class MediaProfiles
{
@@ -117,13 +130,19 @@
* @param profile codec profile (for MediaCodec) or -1 for none
*/
VideoCodec(video_encoder codec, int bitrate, int frameWidth, int frameHeight, int frameRate,
- int profile = -1)
+ int profile = -1,
+ chroma_subsampling chroma = CHROMA_SUBSAMPLING_YUV_420,
+ int bitDepth = 8,
+ hdr_format hdr = HDR_FORMAT_NONE)
: mCodec(codec),
mBitRate(bitrate),
mFrameWidth(frameWidth),
mFrameHeight(frameHeight),
mFrameRate(frameRate),
- mProfile(profile) {
+ mProfile(profile),
+ mChromaSubsampling(chroma),
+ mBitDepth(bitDepth),
+ mHdrFormat(hdr) {
}
VideoCodec(const VideoCodec&) = default;
@@ -160,6 +179,21 @@
return mProfile;
}
+ /** Returns the chroma subsampling. */
+ chroma_subsampling getChromaSubsampling() const {
+ return mChromaSubsampling;
+ }
+
+ /** Returns the bit depth. */
+ int getBitDepth() const {
+ return mBitDepth;
+ }
+
+ /** Returns the chroma subsampling. */
+ hdr_format getHdrFormat() const {
+ return mHdrFormat;
+ }
+
private:
video_encoder mCodec;
int mBitRate;
@@ -167,6 +201,9 @@
int mFrameHeight;
int mFrameRate;
int mProfile;
+ chroma_subsampling mChromaSubsampling;
+ int mBitDepth;
+ hdr_format mHdrFormat;
friend class MediaProfiles;
};
@@ -533,6 +570,39 @@
static int findTagForName(const NameToTagMap *map, size_t nMappings, const char *name);
/**
+ * Finds the string representation for an integer enum tag.
+ *
+ * This is the reverse for findTagForName
+ *
+ * @param map the name-to-tag map to search
+ * @param nMappings the number of mappings in |map|
+ * @param tag the enum value to find
+ * @param def_ the return value if the enum is not found
+ *
+ * @return the string name corresponding to |tag| or |def_| if not found.
+ */
+ static const char *findNameForTag(
+ const NameToTagMap *map, size_t nMappings,
+ int tag, const char *def_ = "(unknown)");
+
+ /**
+ * Updates the chroma subsampling, bit-depth and hdr-format for
+ * advanced codec profiles.
+ *
+ * @param codec the video codec type
+ * @param profile the MediaCodec profile
+ * @param chroma pointer to the chroma subsampling output
+ * @param bitDepth pointer to the bit depth output
+ * @param hdr pointer to the hdr format output
+ *
+ * @return true, if the profile fully determined chroma, bit-depth and hdr-format, false
+ * otherwise.
+ */
+ static bool detectAdvancedVideoProfile(
+ video_encoder codec, int profile,
+ chroma_subsampling *chroma, int *bitDepth, hdr_format *hdr);
+
+ /**
* Check on existing profiles with the following criteria:
* 1. Low quality profile must have the lowest video
* resolution product (width x height)
@@ -549,6 +619,8 @@
// Mappings from name (for instance, codec name) to enum value
static const NameToTagMap sVideoEncoderNameMap[];
+ static const NameToTagMap sChromaSubsamplingNameMap[];
+ static const NameToTagMap sHdrFormatNameMap[];
static const NameToTagMap sAudioEncoderNameMap[];
static const NameToTagMap sFileFormatMap[];
static const NameToTagMap sVideoDecoderNameMap[];
diff --git a/media/libmedia/include/media/MediaResource.h b/media/libmedia/include/media/MediaResource.h
index 4712528..3b69d4f 100644
--- a/media/libmedia/include/media/MediaResource.h
+++ b/media/libmedia/include/media/MediaResource.h
@@ -37,7 +37,8 @@
MediaResource(Type type, SubType subType, int64_t value);
MediaResource(Type type, const std::vector<uint8_t> &id, int64_t value);
- static MediaResource CodecResource(bool secure, bool video, int64_t instanceCount = 1);
+ static MediaResource CodecResource(bool secure, MediaResourceSubType subType,
+ int64_t instanceCount = 1);
static MediaResource GraphicMemoryResource(int64_t value);
static MediaResource CpuBoostResource();
static MediaResource VideoBatteryResource();
@@ -62,6 +63,7 @@
case MediaResource::SubType::kUnspecifiedSubType: return "unspecified";
case MediaResource::SubType::kAudioCodec: return "audio-codec";
case MediaResource::SubType::kVideoCodec: return "video-codec";
+ case MediaResource::SubType::kImageCodec: return "image-codec";
default: return def;
}
}
diff --git a/media/libmedia/include/media/mediarecorder.h b/media/libmedia/include/media/mediarecorder.h
index d54ff32..dd18144 100644
--- a/media/libmedia/include/media/mediarecorder.h
+++ b/media/libmedia/include/media/mediarecorder.h
@@ -108,7 +108,9 @@
VIDEO_ENCODER_MPEG_4_SP = 3,
VIDEO_ENCODER_VP8 = 4,
VIDEO_ENCODER_HEVC = 5,
-
+ VIDEO_ENCODER_VP9 = 6,
+ VIDEO_ENCODER_DOLBY_VISION = 7,
+ VIDEO_ENCODER_AV1 = 8,
VIDEO_ENCODER_LIST_END // must be the last - used to validate the video encoder type
};
diff --git a/media/libmediaformatshaper/Android.bp b/media/libmediaformatshaper/Android.bp
index bdd1465..7e8f351 100644
--- a/media/libmediaformatshaper/Android.bp
+++ b/media/libmediaformatshaper/Android.bp
@@ -95,10 +95,10 @@
min_sdk_version: "29",
- apex_available: [
- "//apex_available:platform",
- "com.android.media",
- ],
+ // the library lives only in the module
+ // framework accesses with dlopen() and uses "libmediaformatshaper_headers" so both
+ // sides track to the interface.
+ apex_available: ["com.android.media"],
version_script: "exports.lds",
diff --git a/media/libmediahelper/AudioValidator.cpp b/media/libmediahelper/AudioValidator.cpp
index 7eddbe1..5a0d517 100644
--- a/media/libmediahelper/AudioValidator.cpp
+++ b/media/libmediahelper/AudioValidator.cpp
@@ -47,8 +47,7 @@
const effect_descriptor_t& desc, std::string_view bugNumber)
{
status_t status = NO_ERROR;
- if (checkStringOverflow(desc.name)
- | /* always */ checkStringOverflow(desc.implementor)) {
+ if (checkStringOverflow(desc.name) || checkStringOverflow(desc.implementor)) {
status = BAD_VALUE;
}
return safetyNetLog(status, bugNumber);
diff --git a/media/libmediametrics/include/MediaMetricsConstants.h b/media/libmediametrics/include/MediaMetricsConstants.h
index 7f0a045..4247375 100644
--- a/media/libmediametrics/include/MediaMetricsConstants.h
+++ b/media/libmediametrics/include/MediaMetricsConstants.h
@@ -25,6 +25,9 @@
* 2) Consistent behavior and documentation.
*/
+#define AMEDIAMETRICS_INITIAL_MAX_VOLUME (0.f)
+#define AMEDIAMETRICS_INITIAL_MIN_VOLUME (1.f)
+
/*
* Taxonomy of audio keys
*
@@ -116,6 +119,11 @@
#define AMEDIAMETRICS_PROP_DEVICETIMENS "deviceTimeNs" // int64_t playback/record time
#define AMEDIAMETRICS_PROP_DEVICEVOLUME "deviceVolume" // double - average device volume
+#define AMEDIAMETRICS_PROP_DEVICEMAXVOLUMEDURATIONNS "deviceMaxVolumeDurationNs" // int64_t
+#define AMEDIAMETRICS_PROP_DEVICEMAXVOLUME "deviceMaxVolume" // double - maximum device volume
+#define AMEDIAMETRICS_PROP_DEVICEMINVOLUMEDURATIONNS "deviceMinVolumeDurationNs" // int64_t
+#define AMEDIAMETRICS_PROP_DEVICEMINVOLUME "deviceMinVolume" // double - minimum device volume
+
#define AMEDIAMETRICS_PROP_DIRECTION "direction" // string AAudio input or output
#define AMEDIAMETRICS_PROP_DURATIONNS "durationNs" // int64 duration time span
#define AMEDIAMETRICS_PROP_ENCODING "encoding" // string value of format
diff --git a/media/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
index f521b62..a23d1d9 100644
--- a/media/libmediaplayerservice/Android.bp
+++ b/media/libmediaplayerservice/Android.bp
@@ -79,6 +79,9 @@
"libstagefright_nuplayer",
"libstagefright_rtsp",
"libstagefright_timedtext",
+ // this needs it, but it can get it transitively through libstagefright.
+ // i'm going to leave it here.
+ "libstagefright_webm",
"framework-permission-aidl-cpp",
],
@@ -91,12 +94,12 @@
"libmediautils_headers",
],
- include_dirs: [
- "frameworks/av/media/libstagefright/webm",
- ],
-
local_include_dirs: ["include"],
+ export_include_dirs: [
+ ".",
+ ],
+
cflags: [
"-Werror",
"-Wno-error=deprecated-declarations",
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index 05f7365..cd411ea 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -30,7 +30,7 @@
#include "MediaPlayerFactory.h"
#include "TestPlayerStub.h"
-#include "nuplayer/NuPlayerDriver.h"
+#include <nuplayer/NuPlayerDriver.h>
namespace android {
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index b512982..a71631a 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -82,7 +82,7 @@
#include "MediaPlayerFactory.h"
#include "TestPlayerStub.h"
-#include "nuplayer/NuPlayerDriver.h"
+#include <nuplayer/NuPlayerDriver.h>
static const int kDumpLockRetries = 50;
diff --git a/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
index 8c86e16..609298f 100644
--- a/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
+++ b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
@@ -206,6 +206,7 @@
}
const char *mime;
+ bool isHeif = false;
if (!trackMeta->findCString(kKeyMIMEType, &mime)) {
ALOGE("image track has no mime type");
return NULL;
@@ -215,6 +216,7 @@
mime = MEDIA_MIMETYPE_VIDEO_HEVC;
trackMeta = new MetaData(*trackMeta);
trackMeta->setCString(kKeyMIMEType, mime);
+ isHeif = true;
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_AVIF)) {
mime = MEDIA_MIMETYPE_VIDEO_AV1;
trackMeta = new MetaData(*trackMeta);
@@ -240,6 +242,16 @@
format->setInt32("width", thumbWidth);
}
+ // If decoding tiled HEIF check decoder supports tile dimensions instead
+ if (!thumbnail && isHeif && format != NULL) {
+ int32_t tileWidth, tileHeight;
+ if (trackMeta->findInt32(kKeyTileWidth, &tileWidth) && tileWidth > 0
+ && trackMeta->findInt32(kKeyTileHeight, &tileHeight) && tileHeight > 0) {
+ format->setInt32("height", tileHeight);
+ format->setInt32("width", tileWidth);
+ }
+ }
+
MediaCodecList::findMatchingCodecs(
mime,
false, /* encoder */
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 31fa8e2..ea1fdf4 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -24,7 +24,8 @@
#include <android-base/logging.h>
#include <utils/Log.h>
-#include "WebmWriter.h"
+#include <webm/WebmWriter.h>
+
#include "StagefrightRecorder.h"
#include <algorithm>
diff --git a/media/libmediaplayerservice/fuzzer/Android.bp b/media/libmediaplayerservice/fuzzer/Android.bp
index d83d3c9..a36f1d6 100644
--- a/media/libmediaplayerservice/fuzzer/Android.bp
+++ b/media/libmediaplayerservice/fuzzer/Android.bp
@@ -28,9 +28,6 @@
cc_defaults {
name: "libmediaplayerserviceFuzzer_defaults",
- include_dirs: [
- "frameworks/av/media/libmediaplayerservice",
- ],
static_libs: [
"libmediaplayerservice",
"liblog",
diff --git a/media/libmediaplayerservice/nuplayer/AWakeLock.cpp b/media/libmediaplayerservice/nuplayer/AWakeLock.cpp
index af9cf45..c3bd207 100644
--- a/media/libmediaplayerservice/nuplayer/AWakeLock.cpp
+++ b/media/libmediaplayerservice/nuplayer/AWakeLock.cpp
@@ -62,7 +62,8 @@
binder::Status status = mPowerManager->acquireWakeLock(
binder, POWERMANAGER_PARTIAL_WAKE_LOCK,
String16("AWakeLock"), String16("media"),
- {} /* workSource */, {} /* historyTag */, -1 /* displayId */);
+ {} /* workSource */, {} /* historyTag */, -1 /* displayId */,
+ nullptr /* callback */);
IPCThreadState::self()->restoreCallingIdentity(token);
if (status.isOk()) {
mWakeLockToken = binder;
diff --git a/media/libmediaplayerservice/nuplayer/Android.bp b/media/libmediaplayerservice/nuplayer/Android.bp
index ac97e73..71a3168 100644
--- a/media/libmediaplayerservice/nuplayer/Android.bp
+++ b/media/libmediaplayerservice/nuplayer/Android.bp
@@ -37,21 +37,24 @@
"StreamingSource.cpp",
],
+ local_include_dirs: [
+ "include/nuplayer",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
header_libs: [
"libmediadrm_headers",
"libmediametrics_headers",
"media_plugin_headers",
"libstagefright_headers",
+ "libstagefright_httplive_headers",
+ "libstagefright_mpeg2support_headers",
"libstagefright_rtsp_headers",
],
- include_dirs: [
- "frameworks/av/media/libstagefright/httplive",
- "frameworks/av/media/libstagefright/mpeg2ts",
- "frameworks/av/media/libstagefright/timedtext",
- "frameworks/native/include/android",
- ],
-
cflags: [
"-Werror",
"-Wall",
@@ -73,10 +76,12 @@
"libmedia",
"libmediadrm",
"libpowermanager",
+ "android.hardware.drm-V1-ndk",
],
static_libs: [
"libplayerservice_datasource",
+ "libstagefright_timedtext",
],
name: "libstagefright_nuplayer",
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 439dbe8..36e4d4a 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -20,7 +20,6 @@
#include "GenericSource.h"
#include "NuPlayerDrm.h"
-#include "AnotherPacketSource.h"
#include <binder/IServiceManager.h>
#include <cutils/properties.h>
#include <datasource/PlayerServiceDataSourceFactory.h>
@@ -44,6 +43,7 @@
#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
+#include <mpeg2ts/AnotherPacketSource.h>
namespace android {
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index 77e7885..4e71e89 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -19,8 +19,6 @@
#include <utils/Log.h>
#include "HTTPLiveSource.h"
-
-#include "AnotherPacketSource.h"
#include "LiveDataSource.h"
#include <media/IMediaHTTPService.h>
@@ -31,6 +29,7 @@
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/Utils.h>
+#include <mpeg2ts/AnotherPacketSource.h>
// default buffer prepare/ready/underflow marks
static const int kReadyMarkMs = 5000; // 5 seconds
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 9ae7ddb..c6b22a6 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -35,9 +35,7 @@
#include "RTSPSource.h"
#include "StreamingSource.h"
#include "GenericSource.h"
-#include "TextDescriptions.h"
-
-#include "ATSParser.h"
+#include <timedtext/TextDescriptions.h>
#include <cutils/properties.h>
@@ -56,6 +54,8 @@
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
+#include <mpeg2ts/ATSParser.h>
+
#include <gui/IGraphicBufferProducer.h>
#include <gui/Surface.h>
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 2c1f158..52b2041 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -40,10 +40,9 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/SurfaceUtils.h>
+#include <mpeg2ts/ATSParser.h>
#include <gui/Surface.h>
-#include "ATSParser.h"
-
namespace android {
static float kDisplayRefreshingRate = 60.f; // TODO: get this from the display
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
index 793014e..cb91fd9 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
@@ -30,8 +30,7 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaErrors.h>
-
-#include "ATSParser.h"
+#include <mpeg2ts/ATSParser.h>
namespace android {
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index b52ea6b..75cedcc 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -20,13 +20,12 @@
#include "RTSPSource.h"
-#include "AnotherPacketSource.h"
-
#include <media/IMediaHTTPService.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/rtsp/MyHandler.h>
#include <media/stagefright/rtsp/SDPLoader.h>
+#include <mpeg2ts/AnotherPacketSource.h>
namespace android {
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index bec27d3..9d67ca4 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -20,8 +20,6 @@
#include "StreamingSource.h"
-#include "ATSParser.h"
-#include "AnotherPacketSource.h"
#include "NuPlayerStreamListener.h"
#include <media/stagefright/MediaSource.h>
@@ -31,6 +29,8 @@
#include <media/stagefright/foundation/MediaKeys.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
+#include <mpeg2ts/AnotherPacketSource.h>
+#include <mpeg2ts/ATSParser.h>
namespace android {
diff --git a/media/libmediaplayerservice/nuplayer/AWakeLock.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/AWakeLock.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/AWakeLock.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/AWakeLock.h
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/GenericSource.h
similarity index 99%
rename from media/libmediaplayerservice/nuplayer/GenericSource.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/GenericSource.h
index 7a2ab8f..80e06f1 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/include/nuplayer/GenericSource.h
@@ -21,11 +21,10 @@
#include "NuPlayer.h"
#include "NuPlayerSource.h"
-#include "ATSParser.h"
-
#include <android-base/unique_fd.h>
#include <media/mediaplayer.h>
#include <media/stagefright/MediaBuffer.h>
+#include <mpeg2ts/ATSParser.h>
namespace android {
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/HTTPLiveSource.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/HTTPLiveSource.h
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayer.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/NuPlayer.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayer.h
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerCCDecoder.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerCCDecoder.h
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerDecoder.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerDecoder.h
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerDecoderBase.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerDecoderBase.h
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerDecoderPassThrough.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerDecoderPassThrough.h
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerDriver.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerDriver.h
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerDrm.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/NuPlayerDrm.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerDrm.h
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerRenderer.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerRenderer.h
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerSource.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/NuPlayerSource.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerSource.h
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerStreamListener.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerStreamListener.h
diff --git a/media/libmediaplayerservice/nuplayer/RTPSource.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/RTPSource.h
similarity index 99%
rename from media/libmediaplayerservice/nuplayer/RTPSource.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/RTPSource.h
index d3021f3..7d9bb8f 100644
--- a/media/libmediaplayerservice/nuplayer/RTPSource.h
+++ b/media/libmediaplayerservice/nuplayer/include/nuplayer/RTPSource.h
@@ -29,19 +29,14 @@
#include <media/stagefright/rtsp/ASessionDescription.h>
#include <media/stagefright/Utils.h>
#include <media/BufferingSettings.h>
+#include <mpeg2ts/AnotherPacketSource.h>
#include <utils/KeyedVector.h>
#include <utils/Vector.h>
#include <utils/RefBase.h>
-#include "AnotherPacketSource.h"
#include "NuPlayerSource.h"
-
-
-
-
-
namespace android {
struct ALooper;
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/RTSPSource.h
similarity index 99%
rename from media/libmediaplayerservice/nuplayer/RTSPSource.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/RTSPSource.h
index 03fce08..7497e41 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.h
+++ b/media/libmediaplayerservice/nuplayer/include/nuplayer/RTSPSource.h
@@ -20,7 +20,7 @@
#include "NuPlayerSource.h"
-#include "ATSParser.h"
+#include <mpeg2ts/ATSParser.h>
namespace android {
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/StreamingSource.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/StreamingSource.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/StreamingSource.h
diff --git a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
index c81a659..2beb47f 100644
--- a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
+++ b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
@@ -61,7 +61,11 @@
return true;
}
- virtual bool isValidPid(int /* pid */) {
+ virtual bool isPidTrusted(int /* pid */) {
+ return true;
+ }
+
+ virtual bool isPidUidTrusted(int /* pid */, int /* uid */) {
return true;
}
diff --git a/media/libmediaplayerservice/tests/stagefrightRecorder/Android.bp b/media/libmediaplayerservice/tests/stagefrightRecorder/Android.bp
index 92236ea..6eb8c6f 100644
--- a/media/libmediaplayerservice/tests/stagefrightRecorder/Android.bp
+++ b/media/libmediaplayerservice/tests/stagefrightRecorder/Android.bp
@@ -33,10 +33,6 @@
"StagefrightRecorderTest.cpp",
],
- include_dirs: [
- "frameworks/av/media/libmediaplayerservice",
- ],
-
static_libs: [
"libmediaplayerservice",
"libstagefright_httplive",
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index a4fbbbc..7917395 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -2195,7 +2195,10 @@
}
if (!msg->findInt32("aac-max-output-channel_count", &maxOutputChannelCount)) {
- maxOutputChannelCount = -1;
+ // check non AAC-specific key
+ if (!msg->findInt32("max-output-channel-count", &maxOutputChannelCount)) {
+ maxOutputChannelCount = -1;
+ }
}
if (!msg->findInt32("aac-pcm-limiter-enable", &pcmLimiterEnable)) {
// value is unknown
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index 01cb9b3..5da32c9 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -35,6 +35,7 @@
#include <media/stagefright/FrameCaptureProcessor.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/Utils.h>
@@ -192,6 +193,13 @@
*dstBpp = 4;
return true;
}
+ case HAL_PIXEL_FORMAT_RGBA_1010102:
+ {
+ *dstFormat = (OMX_COLOR_FORMATTYPE)COLOR_Format32bitABGR2101010;
+ *captureFormat = ui::PixelFormat::RGBA_1010102;
+ *dstBpp = 4;
+ return true;
+ }
default:
{
ALOGE("Unsupported color format: %d", colorFormat);
@@ -523,8 +531,12 @@
return NULL;
}
- // TODO: Use Flexible color instead
- videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
+ if (dstFormat() == COLOR_Format32bitABGR2101010) {
+ videoFormat->setInt32("color-format", COLOR_FormatYUVP010);
+ } else {
+ // TODO: Use Flexible color instead
+ videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
+ }
// For the thumbnail extraction case, try to allocate single buffer in both
// input and output ports, if seeking to a sync frame. NOTE: This request may
@@ -632,6 +644,11 @@
crop_bottom = height - 1;
}
+ int32_t slice_height;
+ if (outputFormat->findInt32("slice-height", &slice_height) && slice_height > 0) {
+ height = slice_height;
+ }
+
if (mFrame == NULL) {
sp<IMemory> frameMem = allocVideoFrame(
trackMeta(),
@@ -831,8 +848,12 @@
return NULL;
}
- // TODO: Use Flexible color instead
- videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
+ if (dstFormat() == COLOR_Format32bitABGR2101010) {
+ videoFormat->setInt32("color-format", COLOR_FormatYUVP010);
+ } else {
+ // TODO: Use Flexible color instead
+ videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
+ }
if ((mGridRows == 1) && (mGridCols == 1)) {
videoFormat->setInt32("android._num-input-buffers", 1);
@@ -938,6 +959,11 @@
crop_bottom = height - 1;
}
+ int32_t slice_height;
+ if (outputFormat->findInt32("slice-height", &slice_height) && slice_height > 0) {
+ height = slice_height;
+ }
+
int32_t crop_width, crop_height;
crop_width = crop_right - crop_left + 1;
crop_height = crop_bottom - crop_top + 1;
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 7c7fcac..f81a5eb 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -156,7 +156,7 @@
bool isHeic() const { return mIsHeic; }
bool isAudio() const { return mIsAudio; }
bool isMPEG4() const { return mIsMPEG4; }
- bool usePrefix() const { return mIsAvc || mIsHevc || mIsHeic; }
+ bool usePrefix() const { return mIsAvc || mIsHevc || mIsHeic || mIsDovi; }
bool isExifData(MediaBufferBase *buffer, uint32_t *tiffHdrOffset) const;
void addChunkOffset(off64_t offset);
void addItemOffsetAndSize(off64_t offset, size_t size, bool isExif);
@@ -164,6 +164,7 @@
TrackId& getTrackId() { return mTrackId; }
status_t dump(int fd, const Vector<String16>& args) const;
static const char *getFourCCForMime(const char *mime);
+ const char *getDoviFourCC() const;
const char *getTrackType() const;
void resetInternal();
int64_t trackMetaDataSize();
@@ -316,6 +317,7 @@
volatile bool mStarted;
bool mIsAvc;
bool mIsHevc;
+ bool mIsDovi;
bool mIsAudio;
bool mIsVideo;
bool mIsHeic;
@@ -370,6 +372,10 @@
uint8_t mProfileCompatible;
uint8_t mLevelIdc;
+ uint8_t mDoviProfile;
+ void *mDoviConfigData;
+ size_t mDoviConfigDataSize;
+
void *mCodecSpecificData;
size_t mCodecSpecificDataSize;
bool mGotAllCodecSpecificData;
@@ -422,6 +428,8 @@
status_t parseHEVCCodecSpecificData(
const uint8_t *data, size_t size, HevcParameterSets ¶mSets);
+ status_t makeDoviCodecSpecificData();
+
// Track authoring progress status
void trackProgressStatus(int64_t timeUs, status_t err = OK);
void initTrackingProgressStatus(MetaData *params);
@@ -459,6 +467,7 @@
void writePaspBox();
void writeAvccBox();
void writeHvccBox();
+ void writeDoviConfigBox();
void writeUrlBox();
void writeDrefBox();
void writeDinfBox();
@@ -470,6 +479,7 @@
void writeHdlrBox();
void writeTkhdBox(uint32_t now);
void writeColrBox();
+ void writeMdcvAndClliBoxes();
void writeMp4aEsdsBox();
void writeMp4vEsdsBox();
void writeAudioFourCCBox();
@@ -617,6 +627,17 @@
return OK;
}
+const char *MPEG4Writer::Track::getDoviFourCC() const {
+ if (mDoviProfile == 5) {
+ return "dvh1";
+ } else if (mDoviProfile == 8) {
+ return "hvc1";
+ } else if (mDoviProfile == 9 || mDoviProfile == 32) {
+ return "avc1";
+ }
+ return (const char*)NULL;
+}
+
// static
const char *MPEG4Writer::Track::getFourCCForMime(const char *mime) {
if (mime == NULL) {
@@ -671,7 +692,9 @@
mIsBackgroundMode |= isBackgroundMode;
}
- if (Track::getFourCCForMime(mime) == NULL) {
+ if (!strcmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
+ ALOGV("Add source mime '%s'", mime);
+ } else if (Track::getFourCCForMime(mime) == NULL) {
ALOGE("Unsupported mime '%s'", mime);
return ERROR_UNSUPPORTED;
}
@@ -2150,6 +2173,8 @@
mMinCttsOffsetTimeUs(0),
mMinCttsOffsetTicks(0),
mMaxCttsOffsetTicks(0),
+ mDoviConfigData(NULL),
+ mDoviConfigDataSize(0),
mCodecSpecificData(NULL),
mCodecSpecificDataSize(0),
mGotAllCodecSpecificData(false),
@@ -2176,6 +2201,7 @@
mMeta->findCString(kKeyMIMEType, &mime);
mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
mIsHevc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);
+ mIsDovi = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION);
mIsAudio = !strncasecmp(mime, "audio/", 6);
mIsVideo = !strncasecmp(mime, "video/", 6);
mIsHeic = !strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC);
@@ -2610,7 +2636,12 @@
!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) {
mMeta->findData(kKeyHVCC, &type, &data, &size);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
- mMeta->findData(kKeyDVCC, &type, &data, &size);
+ makeDoviCodecSpecificData();
+ if (!mMeta->findData(kKeyAVCC, &type, &data, &size) &&
+ !mMeta->findData(kKeyHVCC, &type, &data, &size)) {
+ ALOGE("Failed: No HVCC/AVCC for Dolby Vision ..\n");
+ return;
+ }
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
if (mMeta->findData(kKeyESDS, &type, &data, &size)) {
@@ -2651,6 +2682,11 @@
free(mCodecSpecificData);
mCodecSpecificData = NULL;
}
+
+ if (mDoviConfigData != NULL) {
+ free(mDoviConfigData);
+ mDoviConfigData = NULL;
+ }
}
void MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) {
@@ -3329,6 +3365,37 @@
return OK;
}
+status_t MPEG4Writer::Track::makeDoviCodecSpecificData() {
+ uint32_t type;
+ const void *data = NULL;
+ size_t size = 0;
+
+ if (mDoviConfigData != NULL) {
+ ALOGE("Already have Dolby Vision codec specific data");
+ return OK;
+ }
+
+ if (!mMeta->findData(kKeyDVCC, &type, &data, &size)
+ && !mMeta->findData(kKeyDVVC, &type, &data, &size)
+ && !mMeta->findData(kKeyDVWC, &type, &data, &size)) {
+ ALOGE("Failed getting Dovi config for Dolby Vision %d", (int)size);
+ return ERROR_MALFORMED;
+ }
+
+ mDoviConfigData = malloc(size);
+ if (mDoviConfigData == NULL) {
+ ALOGE("Failed allocating Dolby Vision config data");
+ return ERROR_MALFORMED;
+ }
+
+ mDoviConfigDataSize = size;
+ memcpy(mDoviConfigData, data, size);
+
+ mDoviProfile = (((char *)data)[2] >> 1) & 0x7f; //getting profile info
+
+ return OK;
+}
+
/*
* Updates the drift time from the audio track so that
* the video track can get the updated drift time information
@@ -3474,6 +3541,23 @@
err = copyCodecSpecificData((const uint8_t *)buffer->data() + buffer->range_offset(),
buffer->range_length());
}
+ if (mIsDovi) {
+ err = makeDoviCodecSpecificData();
+
+ const void *data = NULL;
+ size_t size = 0;
+
+ uint32_t type = 0;
+ if (mDoviProfile == 9){
+ mMeta->findData(kKeyAVCC, &type, &data, &size);
+ } else if (mDoviProfile < 9) {
+ mMeta->findData(kKeyHVCC, &type, &data, &size);
+ }
+
+ if (data != NULL && copyCodecSpecificData((uint8_t *)data, size) == OK) {
+ mGotAllCodecSpecificData = true;
+ }
+ }
}
buffer->release();
@@ -4173,6 +4257,7 @@
!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) ||
!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime) ||
!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime) ||
+ !strcasecmp(MEDIA_MIMETYPE_VIDEO_DOLBY_VISION, mime) ||
!strcasecmp(MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC, mime)) {
if (!mCodecSpecificData ||
mCodecSpecificDataSize <= 0) {
@@ -4297,7 +4382,13 @@
const char *mime;
bool success = mMeta->findCString(kKeyMIMEType, &mime);
CHECK(success);
- const char *fourcc = getFourCCForMime(mime);
+ const char *fourcc;
+ if (!strcmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
+ fourcc = getDoviFourCC();
+ } else {
+ fourcc = getFourCCForMime(mime);
+ }
+
if (fourcc == NULL) {
ALOGE("Unknown mime type '%s'.", mime);
TRESPASS();
@@ -4337,10 +4428,18 @@
writeAvccBox();
} else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) {
writeHvccBox();
+ } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DOLBY_VISION, mime)) {
+ if (mDoviProfile <= 8) {
+ writeHvccBox();
+ } else if (mDoviProfile == 9 || mDoviProfile == 32) {
+ writeAvccBox();
+ }
+ writeDoviConfigBox();
}
writePaspBox();
writeColrBox();
+ writeMdcvAndClliBoxes();
mOwner->endBox(); // mp4v, s263 or avc1
}
@@ -4349,29 +4448,78 @@
memset(&aspects, 0, sizeof(aspects));
// Color metadata may have changed.
sp<MetaData> meta = mSource->getFormat();
- // TRICKY: using | instead of || because we want to execute all findInt32-s
- if (meta->findInt32(kKeyColorPrimaries, (int32_t*)&aspects.mPrimaries)
- | meta->findInt32(kKeyTransferFunction, (int32_t*)&aspects.mTransfer)
- | meta->findInt32(kKeyColorMatrix, (int32_t*)&aspects.mMatrixCoeffs)
- | meta->findInt32(kKeyColorRange, (int32_t*)&aspects.mRange)) {
- int32_t primaries, transfer, coeffs;
- bool fullRange;
- ALOGV("primaries=%s transfer=%s matrix=%s range=%s",
- asString(aspects.mPrimaries),
- asString(aspects.mTransfer),
- asString(aspects.mMatrixCoeffs),
- asString(aspects.mRange));
- ColorUtils::convertCodecColorAspectsToIsoAspects(
- aspects, &primaries, &transfer, &coeffs, &fullRange);
- mOwner->beginBox("colr");
- mOwner->writeFourcc("nclx");
- mOwner->writeInt16(primaries);
- mOwner->writeInt16(transfer);
- mOwner->writeInt16(coeffs);
- mOwner->writeInt8(int8_t(fullRange ? 0x80 : 0x0));
- mOwner->endBox(); // colr
- } else {
+ bool findPrimaries = meta->findInt32(kKeyColorPrimaries, (int32_t*)&aspects.mPrimaries);
+ bool findTransfer = meta->findInt32(kKeyTransferFunction, (int32_t*)&aspects.mTransfer);
+ bool findMatrix = meta->findInt32(kKeyColorMatrix, (int32_t*)&aspects.mMatrixCoeffs);
+ bool findRange = meta->findInt32(kKeyColorRange, (int32_t*)&aspects.mRange);
+ if (!findPrimaries && !findTransfer && !findMatrix && !findRange) {
ALOGV("no color information");
+ return;
+ }
+
+ int32_t primaries, transfer, coeffs;
+ bool fullRange;
+ ALOGV("primaries=%s transfer=%s matrix=%s range=%s",
+ asString(aspects.mPrimaries),
+ asString(aspects.mTransfer),
+ asString(aspects.mMatrixCoeffs),
+ asString(aspects.mRange));
+ ColorUtils::convertCodecColorAspectsToIsoAspects(
+ aspects, &primaries, &transfer, &coeffs, &fullRange);
+ mOwner->beginBox("colr");
+ mOwner->writeFourcc("nclx");
+ mOwner->writeInt16(primaries);
+ mOwner->writeInt16(transfer);
+ mOwner->writeInt16(coeffs);
+ mOwner->writeInt8(int8_t(fullRange ? 0x80 : 0x0));
+ mOwner->endBox(); // colr
+}
+
+void MPEG4Writer::Track::writeMdcvAndClliBoxes() {
+ sp<MetaData> meta = mSource->getFormat();
+ uint32_t type;
+ const uint8_t* data;
+ size_t size;
+ bool found =
+ meta->findData(kKeyHdrStaticInfo, &type, reinterpret_cast<const void**>(&data), &size);
+ if (found && size == 25) {
+ uint16_t displayPrimariesRX = U16LE_AT(&data[1]);
+ uint16_t displayPrimariesRY = U16LE_AT(&data[3]);
+
+ uint16_t displayPrimariesGX = U16LE_AT(&data[5]);
+ uint16_t displayPrimariesGY = U16LE_AT(&data[7]);
+
+ uint16_t displayPrimariesBX = U16LE_AT(&data[9]);
+ uint16_t displayPrimariesBY = U16LE_AT(&data[11]);
+
+ uint16_t whitePointX = U16LE_AT(&data[13]);
+ uint16_t whitePointY = U16LE_AT(&data[15]);
+
+ uint16_t maxDisplayMasteringLuminance = U16LE_AT(&data[17]);
+ uint16_t minDisplayMasteringLuminance = U16LE_AT(&data[19]);
+
+ uint16_t maxContentLightLevel = U16LE_AT(&data[21]);
+ uint16_t maxPicAverageLightLevel = U16LE_AT(&data[23]);
+
+ mOwner->beginBox("mdcv");
+ mOwner->writeInt16(displayPrimariesGX);
+ mOwner->writeInt16(displayPrimariesGY);
+ mOwner->writeInt16(displayPrimariesBX);
+ mOwner->writeInt16(displayPrimariesBY);
+ mOwner->writeInt16(displayPrimariesRX);
+ mOwner->writeInt16(displayPrimariesRY);
+ mOwner->writeInt16(whitePointX);
+ mOwner->writeInt16(whitePointY);
+ mOwner->writeInt32(maxDisplayMasteringLuminance * 10000);
+ mOwner->writeInt32(minDisplayMasteringLuminance * 10000);
+ mOwner->endBox(); // mdcv.
+
+ mOwner->beginBox("clli");
+ mOwner->writeInt16(maxContentLightLevel);
+ mOwner->writeInt16(maxPicAverageLightLevel);
+ mOwner->endBox(); // clli.
+ } else {
+ ALOGW("Ignoring HDR static info with unexpected size %d", (int)size);
}
}
@@ -4829,12 +4977,11 @@
mOwner->endBox(); // avcC
}
-
void MPEG4Writer::Track::writeHvccBox() {
CHECK(mCodecSpecificData);
CHECK_GE(mCodecSpecificDataSize, 5u);
- // Patch avcc's lengthSize field to match the number
+ // Patch hvcc's lengthSize field to match the number
// of bytes we use to indicate the size of a nal unit.
uint8_t *ptr = (uint8_t *)mCodecSpecificData;
ptr[21] = (ptr[21] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1);
@@ -4843,6 +4990,24 @@
mOwner->endBox(); // hvcC
}
+void MPEG4Writer::Track::writeDoviConfigBox() {
+ CHECK(mDoviConfigData);
+ CHECK_EQ(mDoviConfigDataSize, 24u);
+
+ uint8_t *ptr = (uint8_t *)mDoviConfigData;
+ uint8_t profile = (ptr[2] >> 1) & 0x7f;
+
+ if (profile > 10) {
+ mOwner->beginBox("dvwC");
+ } else if (profile > 7) {
+ mOwner->beginBox("dvvC");
+ } else {
+ mOwner->beginBox("dvcC");
+ }
+ mOwner->write(mDoviConfigData, mDoviConfigDataSize);
+ mOwner->endBox(); // dvwC/dvvC/dvcC
+}
+
void MPEG4Writer::Track::writeD263Box() {
mOwner->beginBox("d263");
mOwner->writeInt32(0); // vendor
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 1ea3f99..1ec09ea 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -102,6 +102,8 @@
static const char *kCodecMode = "android.media.mediacodec.mode"; /* audio, video */
static const char *kCodecModeVideo = "video"; /* values returned for kCodecMode */
static const char *kCodecModeAudio = "audio";
+static const char *kCodecModeImage = "image";
+static const char *kCodecModeUnknown = "unknown";
static const char *kCodecEncoder = "android.media.mediacodec.encoder"; /* 0,1 */
static const char *kCodecSecure = "android.media.mediacodec.secure"; /* 0, 1 */
static const char *kCodecWidth = "android.media.mediacodec.width"; /* 0..n */
@@ -112,6 +114,13 @@
static const char *kCodecCaptureRate = "android.media.mediacodec.capture-rate";
static const char *kCodecOperatingRate = "android.media.mediacodec.operating-rate";
static const char *kCodecPriority = "android.media.mediacodec.priority";
+static const char *kCodecConfigColorStandard = "android.media.mediacodec.config-color-standard";
+static const char *kCodecConfigColorRange = "android.media.mediacodec.config-color-range";
+static const char *kCodecConfigColorTransfer = "android.media.mediacodec.config-color-transfer";
+static const char *kCodecParsedColorStandard = "android.media.mediacodec.parsed-color-standard";
+static const char *kCodecParsedColorRange = "android.media.mediacodec.parsed-color-range";
+static const char *kCodecParsedColorTransfer = "android.media.mediacodec.parsed-color-transfer";
+static const char *kCodecHDRMetadataFlags = "android.media.mediacodec.hdr-metadata-flags";
// Min/Max QP before shaping
static const char *kCodecOriginalVideoQPIMin = "android.media.mediacodec.original-video-qp-i-min";
@@ -247,7 +256,7 @@
const std::shared_ptr<IResourceManagerClient> &client);
virtual ~ResourceManagerServiceProxy();
- void init();
+ status_t init();
// implements DeathRecipient
static void BinderDiedCallback(void* cookie);
@@ -276,6 +285,9 @@
pid_t pid, uid_t uid, const std::shared_ptr<IResourceManagerClient> &client)
: mPid(pid), mUid(uid), mClient(client),
mDeathRecipient(AIBinder_DeathRecipient_new(BinderDiedCallback)) {
+ if (mUid == MediaCodec::kNoUid) {
+ mUid = AIBinder_getCallingUid();
+ }
if (mPid == MediaCodec::kNoPid) {
mPid = AIBinder_getCallingPid();
}
@@ -294,12 +306,26 @@
}
}
-void MediaCodec::ResourceManagerServiceProxy::init() {
+status_t MediaCodec::ResourceManagerServiceProxy::init() {
::ndk::SpAIBinder binder(AServiceManager_getService("media.resource_manager"));
mService = IResourceManagerService::fromBinder(binder);
if (mService == nullptr) {
ALOGE("Failed to get ResourceManagerService");
- return;
+ return UNKNOWN_ERROR;
+ }
+
+ int callerPid = AIBinder_getCallingPid();
+ int callerUid = AIBinder_getCallingUid();
+ if (mPid != callerPid || mUid != callerUid) {
+ // Media processes don't need special permissions to act on behalf of other processes.
+ if (callerUid != AID_MEDIA) {
+ char const * permission = "android.permission.MEDIA_RESOURCE_OVERRIDE_PID";
+ if (!checkCallingPermission(String16(permission))) {
+ ALOGW("%s is required to override the caller's PID for media resource management.",
+ permission);
+ return PERMISSION_DENIED;
+ }
+ }
}
// Kill clients pending removal.
@@ -310,6 +336,7 @@
// after this, require mLock whenever using mService
AIBinder_linkToDeath(mService->asBinder().get(), mDeathRecipient.get(), this);
+ return OK;
}
//static
@@ -649,6 +676,24 @@
notify->post();
}
+static MediaResourceSubType toMediaResourceSubType(MediaCodec::Domain domain) {
+ switch (domain) {
+ case MediaCodec::DOMAIN_VIDEO: return MediaResourceSubType::kVideoCodec;
+ case MediaCodec::DOMAIN_AUDIO: return MediaResourceSubType::kAudioCodec;
+ case MediaCodec::DOMAIN_IMAGE: return MediaResourceSubType::kImageCodec;
+ default: return MediaResourceSubType::kUnspecifiedSubType;
+ }
+}
+
+static const char * toCodecMode(MediaCodec::Domain domain) {
+ switch (domain) {
+ case MediaCodec::DOMAIN_VIDEO: return kCodecModeVideo;
+ case MediaCodec::DOMAIN_AUDIO: return kCodecModeAudio;
+ case MediaCodec::DOMAIN_IMAGE: return kCodecModeImage;
+ default: return kCodecModeUnknown;
+ }
+}
+
} // namespace
////////////////////////////////////////////////////////////////////////////////
@@ -744,10 +789,11 @@
mFlags(0),
mStickyError(OK),
mSoftRenderer(NULL),
- mIsVideo(false),
- mVideoWidth(0),
- mVideoHeight(0),
+ mDomain(DOMAIN_UNKNOWN),
+ mWidth(0),
+ mHeight(0),
mRotationDegrees(0),
+ mHDRMetadataFlags(0),
mDequeueInputTimeoutGeneration(0),
mDequeueInputReplyID(0),
mDequeueOutputTimeoutGeneration(0),
@@ -773,12 +819,7 @@
mInputBufferCounter(0),
mGetCodecBase(getCodecBase),
mGetCodecInfo(getCodecInfo) {
- if (uid == kNoUid) {
- mUid = AIBinder_getCallingUid();
- } else {
- mUid = uid;
- }
- mResourceManagerProxy = new ResourceManagerServiceProxy(pid, mUid,
+ mResourceManagerProxy = new ResourceManagerServiceProxy(pid, uid,
::ndk::SharedRefBase::make<ResourceManagerClient>(this));
if (!mGetCodecBase) {
mGetCodecBase = [](const AString &name, const char *owner) {
@@ -807,7 +848,6 @@
return NAME_NOT_FOUND;
};
}
-
initMediametrics();
}
@@ -898,6 +938,8 @@
mediametrics_setInt64(mMetricsHandle, kCodecFirstFrameIndexLowLatencyModeOn,
mIndexOfFirstFrameWhenLowLatencyOn);
}
+
+ mediametrics_setInt32(mMetricsHandle, kCodecHDRMetadataFlags, mHDRMetadataFlags);
#if 0
// enable for short term, only while debugging
updateEphemeralMediametrics(mMetricsHandle);
@@ -1155,7 +1197,7 @@
});
}
- if (mIsVideo && (mFlags & kFlagIsEncoder)) {
+ if (mDomain == DOMAIN_VIDEO && (mFlags & kFlagIsEncoder)) {
mBytesInput += buffer->size();
mFramesInput++;
}
@@ -1184,7 +1226,7 @@
CHECK_NE(mState, UNINITIALIZED);
- if (mIsVideo && (mFlags & kFlagIsEncoder)) {
+ if (mDomain == DOMAIN_VIDEO && (mFlags & kFlagIsEncoder)) {
int32_t flags = 0;
(void) buffer->meta()->findInt32("flags", &flags);
@@ -1363,7 +1405,11 @@
}
status_t MediaCodec::init(const AString &name) {
- mResourceManagerProxy->init();
+ status_t err = mResourceManagerProxy->init();
+ if (err != OK) {
+ mCodec = NULL; // remove the codec
+ return err;
+ }
// save init parameters for reset
mInitName = name;
@@ -1378,7 +1424,7 @@
bool secureCodec = false;
const char *owner = "";
if (!name.startsWith("android.filter.")) {
- status_t err = mGetCodecInfo(name, &mCodecInfo);
+ err = mGetCodecInfo(name, &mCodecInfo);
if (err != OK) {
mCodec = NULL; // remove the codec.
return err;
@@ -1392,7 +1438,13 @@
mCodecInfo->getSupportedMediaTypes(&mediaTypes);
for (size_t i = 0; i < mediaTypes.size(); ++i) {
if (mediaTypes[i].startsWith("video/")) {
- mIsVideo = true;
+ mDomain = DOMAIN_VIDEO;
+ break;
+ } else if (mediaTypes[i].startsWith("audio/")) {
+ mDomain = DOMAIN_AUDIO;
+ break;
+ } else if (mediaTypes[i].startsWith("image/")) {
+ mDomain = DOMAIN_IMAGE;
break;
}
}
@@ -1405,7 +1457,7 @@
return NAME_NOT_FOUND;
}
- if (mIsVideo) {
+ if (mDomain == DOMAIN_VIDEO) {
// video codec needs dedicated looper
if (mCodecLooper == NULL) {
mCodecLooper = new ALooper;
@@ -1438,17 +1490,15 @@
if (mMetricsHandle != 0) {
mediametrics_setCString(mMetricsHandle, kCodecCodec, name.c_str());
- mediametrics_setCString(mMetricsHandle, kCodecMode,
- mIsVideo ? kCodecModeVideo : kCodecModeAudio);
+ mediametrics_setCString(mMetricsHandle, kCodecMode, toCodecMode(mDomain));
}
- if (mIsVideo) {
+ if (mDomain == DOMAIN_VIDEO) {
mBatteryChecker = new BatteryChecker(new AMessage(kWhatCheckBatteryStats, this));
}
- status_t err;
std::vector<MediaResourceParcel> resources;
- resources.push_back(MediaResource::CodecResource(secureCodec, mIsVideo));
+ resources.push_back(MediaResource::CodecResource(secureCodec, toMediaResourceSubType(mDomain)));
for (int i = 0; i <= kMaxRetry; ++i) {
if (i > 0) {
// Don't try to reclaim resource for the first time.
@@ -1529,16 +1579,16 @@
mediametrics_setCString(mMetricsHandle, kCodecLogSessionId, mLogSessionId.c_str());
}
- if (mIsVideo) {
- format->findInt32("width", &mVideoWidth);
- format->findInt32("height", &mVideoHeight);
+ if (mDomain == DOMAIN_VIDEO || mDomain == DOMAIN_IMAGE) {
+ format->findInt32("width", &mWidth);
+ format->findInt32("height", &mHeight);
if (!format->findInt32("rotation-degrees", &mRotationDegrees)) {
mRotationDegrees = 0;
}
if (mMetricsHandle != 0) {
- mediametrics_setInt32(mMetricsHandle, kCodecWidth, mVideoWidth);
- mediametrics_setInt32(mMetricsHandle, kCodecHeight, mVideoHeight);
+ mediametrics_setInt32(mMetricsHandle, kCodecWidth, mWidth);
+ mediametrics_setInt32(mMetricsHandle, kCodecHeight, mHeight);
mediametrics_setInt32(mMetricsHandle, kCodecRotation, mRotationDegrees);
int32_t maxWidth = 0;
if (format->findInt32("max-width", &maxWidth)) {
@@ -1552,28 +1602,47 @@
if (format->findInt32("color-format", &colorFormat)) {
mediametrics_setInt32(mMetricsHandle, kCodecColorFormat, colorFormat);
}
- float frameRate = -1.0;
- if (format->findFloat("frame-rate", &frameRate)) {
- mediametrics_setDouble(mMetricsHandle, kCodecFrameRate, frameRate);
+ if (mDomain == DOMAIN_VIDEO) {
+ float frameRate = -1.0;
+ if (format->findFloat("frame-rate", &frameRate)) {
+ mediametrics_setDouble(mMetricsHandle, kCodecFrameRate, frameRate);
+ }
+ float captureRate = -1.0;
+ if (format->findFloat("capture-rate", &captureRate)) {
+ mediametrics_setDouble(mMetricsHandle, kCodecCaptureRate, captureRate);
+ }
+ float operatingRate = -1.0;
+ if (format->findFloat("operating-rate", &operatingRate)) {
+ mediametrics_setDouble(mMetricsHandle, kCodecOperatingRate, operatingRate);
+ }
+ int32_t priority = -1;
+ if (format->findInt32("priority", &priority)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecPriority, priority);
+ }
}
- float captureRate = -1.0;
- if (format->findFloat("capture-rate", &captureRate)) {
- mediametrics_setDouble(mMetricsHandle, kCodecCaptureRate, captureRate);
+ int32_t colorStandard = -1;
+ if (format->findInt32(KEY_COLOR_STANDARD, &colorStandard)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecConfigColorStandard, colorStandard);
}
- float operatingRate = -1.0;
- if (format->findFloat("operating-rate", &operatingRate)) {
- mediametrics_setDouble(mMetricsHandle, kCodecOperatingRate, operatingRate);
+ int32_t colorRange = -1;
+ if (format->findInt32(KEY_COLOR_RANGE, &colorRange)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecConfigColorRange, colorRange);
}
- int32_t priority = -1;
- if (format->findInt32("priority", &priority)) {
- mediametrics_setInt32(mMetricsHandle, kCodecPriority, priority);
+ int32_t colorTransfer = -1;
+ if (format->findInt32(KEY_COLOR_TRANSFER, &colorTransfer)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecConfigColorTransfer, colorTransfer);
+ }
+ HDRStaticInfo info;
+ if (ColorUtils::getHDRStaticInfoFromFormat(format, &info)
+ && ColorUtils::isHDRStaticInfoValid(&info)) {
+ mHDRMetadataFlags |= kFlagHDRStaticInfo;
}
}
// Prevent possible integer overflow in downstream code.
- if (mVideoWidth < 0 || mVideoHeight < 0 ||
- (uint64_t)mVideoWidth * mVideoHeight > (uint64_t)INT32_MAX / 4) {
- ALOGE("Invalid size(s), width=%d, height=%d", mVideoWidth, mVideoHeight);
+ if (mWidth < 0 || mHeight < 0 ||
+ (uint64_t)mWidth * mHeight > (uint64_t)INT32_MAX / 4) {
+ ALOGE("Invalid size(s), width=%d, height=%d", mWidth, mHeight);
return BAD_VALUE;
}
@@ -1606,7 +1675,7 @@
}
// push min/max QP to MediaMetrics after shaping
- if (mIsVideo && mMetricsHandle != 0) {
+ if (mDomain == DOMAIN_VIDEO && mMetricsHandle != 0) {
int32_t qpIMin = -1;
if (format->findInt32("video-qp-i-min", &qpIMin)) {
mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPIMin, qpIMin);
@@ -1659,7 +1728,8 @@
status_t err;
std::vector<MediaResourceParcel> resources;
- resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));
+ resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure,
+ toMediaResourceSubType(mDomain)));
// Don't know the buffer size at this point, but it's fine to use 1 because
// the reclaimResource call doesn't consider the requester's buffer size for now.
resources.push_back(MediaResource::GraphicMemoryResource(1));
@@ -2240,7 +2310,7 @@
}
uint64_t MediaCodec::getGraphicBufferSize() {
- if (!mIsVideo) {
+ if (mDomain != DOMAIN_VIDEO && mDomain != DOMAIN_IMAGE) {
return 0;
}
@@ -2248,7 +2318,7 @@
size_t portNum = sizeof(mPortBuffers) / sizeof((mPortBuffers)[0]);
for (size_t i = 0; i < portNum; ++i) {
// TODO: this is just an estimation, we should get the real buffer size from ACodec.
- size += mPortBuffers[i].size() * mVideoWidth * mVideoHeight * 3 / 2;
+ size += mPortBuffers[i].size() * mWidth * mHeight * 3 / 2;
}
return size;
}
@@ -2260,7 +2330,8 @@
status_t err;
std::vector<MediaResourceParcel> resources;
- resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));
+ resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure,
+ toMediaResourceSubType(mDomain)));
// Don't know the buffer size at this point, but it's fine to use 1 because
// the reclaimResource call doesn't consider the requester's buffer size for now.
resources.push_back(MediaResource::GraphicMemoryResource(1));
@@ -3192,8 +3263,8 @@
: MediaCodecInfo::Attributes(0);
if (!(attr & MediaCodecInfo::kFlagIsSoftwareOnly)) {
// software codec is currently ignored.
- mResourceManagerProxy->addResource(
- MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));
+ mResourceManagerProxy->addResource(MediaResource::CodecResource(
+ mFlags & kFlagIsSecure, toMediaResourceSubType(mDomain)));
}
postPendingRepliesAndDeferredMessages("kWhatComponentAllocated");
@@ -3359,7 +3430,7 @@
}
CHECK_EQ(mState, STARTING);
- if (mIsVideo) {
+ if (mDomain == DOMAIN_VIDEO || mDomain == DOMAIN_IMAGE) {
mResourceManagerProxy->addResource(
MediaResource::GraphicMemoryResource(getGraphicBufferSize()));
}
@@ -4518,6 +4589,9 @@
HDRStaticInfo info;
if (ColorUtils::getHDRStaticInfoFromFormat(mOutputFormat, &info)) {
setNativeWindowHdrMetadata(mSurface.get(), &info);
+ if (ColorUtils::isHDRStaticInfoValid(&info)) {
+ mHDRMetadataFlags |= kFlagHDRStaticInfo;
+ }
}
}
@@ -4526,6 +4600,7 @@
&& hdr10PlusInfo != nullptr && hdr10PlusInfo->size() > 0) {
native_window_set_buffers_hdr10_plus_metadata(mSurface.get(),
hdr10PlusInfo->size(), hdr10PlusInfo->data());
+ mHDRMetadataFlags |= kFlagHDR10PlusInfo;
}
if (mime.startsWithIgnoreCase("video/")) {
@@ -4570,6 +4645,21 @@
mCrypto->notifyResolution(width, height);
}
}
+
+ if (mMetricsHandle != 0) {
+ int32_t colorStandard = -1;
+ if (format->findInt32(KEY_COLOR_STANDARD, &colorStandard)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecParsedColorStandard, colorStandard);
+ }
+ int32_t colorRange = -1;
+ if (format->findInt32( KEY_COLOR_RANGE, &colorRange)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecParsedColorRange, colorRange);
+ }
+ int32_t colorTransfer = -1;
+ if (format->findInt32(KEY_COLOR_TRANSFER, &colorTransfer)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecParsedColorTransfer, colorTransfer);
+ }
+ }
}
void MediaCodec::extractCSD(const sp<AMessage> &format) {
@@ -4599,7 +4689,6 @@
mCSD.erase(mCSD.begin());
std::shared_ptr<C2Buffer> c2Buffer;
sp<hardware::HidlMemory> memory;
- size_t offset = 0;
if (mFlags & kFlagUseBlockModel) {
if (hasCryptoOrDescrambler()) {
@@ -4620,7 +4709,6 @@
memcpy(mem->unsecurePointer(), csd->data(), csd->size());
ssize_t heapOffset;
memory = hardware::fromHeap(mem->getMemory(&heapOffset, nullptr));
- offset += heapOffset;
} else {
std::shared_ptr<C2LinearBlock> block =
FetchLinearBlock(csd->size(), {std::string{mComponentName.c_str()}});
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index 2ffe728..a3040f4 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -18,8 +18,6 @@
#define LOG_TAG "MediaCodecList"
#include <utils/Log.h>
-#include "MediaCodecListOverrides.h"
-
#include <binder/IServiceManager.h>
#include <media/IMediaCodecList.h>
@@ -34,6 +32,7 @@
#include <media/stagefright/CCodec.h>
#include <media/stagefright/Codec2InfoBuilder.h>
#include <media/stagefright/MediaCodecList.h>
+#include <media/stagefright/MediaCodecListOverrides.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/OmxInfoBuilder.h>
#include <media/stagefright/PersistentSurface.h>
diff --git a/media/libstagefright/MediaCodecListOverrides.cpp b/media/libstagefright/MediaCodecListOverrides.cpp
index 4a167d1..9304e45 100644
--- a/media/libstagefright/MediaCodecListOverrides.cpp
+++ b/media/libstagefright/MediaCodecListOverrides.cpp
@@ -18,8 +18,6 @@
#define LOG_TAG "MediaCodecListOverrides"
#include <utils/Log.h>
-#include "MediaCodecListOverrides.h"
-
#include <cutils/properties.h>
#include <gui/Surface.h>
#include <mediadrm/ICrypto.h>
@@ -30,6 +28,7 @@
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/MediaCodecList.h>
+#include <media/stagefright/MediaCodecListOverrides.h>
namespace android {
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index a6df5bb..1854588 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -28,9 +28,6 @@
#include "include/HevcUtils.h"
#include <cutils/properties.h>
-#include <media/openmax/OMX_Audio.h>
-#include <media/openmax/OMX_Video.h>
-#include <media/openmax/OMX_VideoExt.h>
#include <media/stagefright/CodecBase.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -57,6 +54,14 @@
#define AMEDIAFORMAT_KEY_MPEGH_COMPATIBLE_SETS \
"mpegh-compatible-sets"
+namespace {
+ // TODO: this should possibly be handled in an else
+ constexpr static int32_t AACObjectNull = 0;
+
+ // TODO: decide if we should just not transmit the level in this case
+ constexpr static int32_t DolbyVisionLevelUnknown = 0;
+}
+
namespace android {
static status_t copyNALUToABuffer(sp<ABuffer> *buffer, const uint8_t *ptr, size_t length) {
@@ -156,21 +161,22 @@
audioObjectType >>= 11;
}
- const static ALookup<uint16_t, OMX_AUDIO_AACPROFILETYPE> profiles {
- { 1, OMX_AUDIO_AACObjectMain },
- { 2, OMX_AUDIO_AACObjectLC },
- { 3, OMX_AUDIO_AACObjectSSR },
- { 4, OMX_AUDIO_AACObjectLTP },
- { 5, OMX_AUDIO_AACObjectHE },
- { 6, OMX_AUDIO_AACObjectScalable },
- { 17, OMX_AUDIO_AACObjectERLC },
- { 23, OMX_AUDIO_AACObjectLD },
- { 29, OMX_AUDIO_AACObjectHE_PS },
- { 39, OMX_AUDIO_AACObjectELD },
- { 42, OMX_AUDIO_AACObjectXHE },
+
+ const static ALookup<uint16_t, int32_t> profiles {
+ { 1, AACObjectMain },
+ { 2, AACObjectLC },
+ { 3, AACObjectSSR },
+ { 4, AACObjectLTP },
+ { 5, AACObjectHE },
+ { 6, AACObjectScalable },
+ { 17, AACObjectERLC },
+ { 23, AACObjectLD },
+ { 29, AACObjectHE_PS },
+ { 39, AACObjectELD },
+ { 42, AACObjectXHE },
};
- OMX_AUDIO_AACPROFILETYPE profile;
+ int32_t profile;
if (profiles.map(audioObjectType, &profile)) {
format->setInt32("profile", profile);
}
@@ -184,53 +190,53 @@
const uint8_t constraints = ptr[2];
const uint8_t level = ptr[3];
- const static ALookup<uint8_t, OMX_VIDEO_AVCLEVELTYPE> levels {
- { 9, OMX_VIDEO_AVCLevel1b }, // technically, 9 is only used for High+ profiles
- { 10, OMX_VIDEO_AVCLevel1 },
- { 11, OMX_VIDEO_AVCLevel11 }, // prefer level 1.1 for the value 11
- { 11, OMX_VIDEO_AVCLevel1b },
- { 12, OMX_VIDEO_AVCLevel12 },
- { 13, OMX_VIDEO_AVCLevel13 },
- { 20, OMX_VIDEO_AVCLevel2 },
- { 21, OMX_VIDEO_AVCLevel21 },
- { 22, OMX_VIDEO_AVCLevel22 },
- { 30, OMX_VIDEO_AVCLevel3 },
- { 31, OMX_VIDEO_AVCLevel31 },
- { 32, OMX_VIDEO_AVCLevel32 },
- { 40, OMX_VIDEO_AVCLevel4 },
- { 41, OMX_VIDEO_AVCLevel41 },
- { 42, OMX_VIDEO_AVCLevel42 },
- { 50, OMX_VIDEO_AVCLevel5 },
- { 51, OMX_VIDEO_AVCLevel51 },
- { 52, OMX_VIDEO_AVCLevel52 },
- { 60, OMX_VIDEO_AVCLevel6 },
- { 61, OMX_VIDEO_AVCLevel61 },
- { 62, OMX_VIDEO_AVCLevel62 },
+ const static ALookup<uint8_t, int32_t> levels {
+ { 9, AVCLevel1b }, // technically, 9 is only used for High+ profiles
+ { 10, AVCLevel1 },
+ { 11, AVCLevel11 }, // prefer level 1.1 for the value 11
+ { 11, AVCLevel1b },
+ { 12, AVCLevel12 },
+ { 13, AVCLevel13 },
+ { 20, AVCLevel2 },
+ { 21, AVCLevel21 },
+ { 22, AVCLevel22 },
+ { 30, AVCLevel3 },
+ { 31, AVCLevel31 },
+ { 32, AVCLevel32 },
+ { 40, AVCLevel4 },
+ { 41, AVCLevel41 },
+ { 42, AVCLevel42 },
+ { 50, AVCLevel5 },
+ { 51, AVCLevel51 },
+ { 52, AVCLevel52 },
+ { 60, AVCLevel6 },
+ { 61, AVCLevel61 },
+ { 62, AVCLevel62 },
};
- const static ALookup<uint8_t, OMX_VIDEO_AVCPROFILETYPE> profiles {
- { 66, OMX_VIDEO_AVCProfileBaseline },
- { 77, OMX_VIDEO_AVCProfileMain },
- { 88, OMX_VIDEO_AVCProfileExtended },
- { 100, OMX_VIDEO_AVCProfileHigh },
- { 110, OMX_VIDEO_AVCProfileHigh10 },
- { 122, OMX_VIDEO_AVCProfileHigh422 },
- { 244, OMX_VIDEO_AVCProfileHigh444 },
+ const static ALookup<uint8_t, int32_t> profiles {
+ { 66, AVCProfileBaseline },
+ { 77, AVCProfileMain },
+ { 88, AVCProfileExtended },
+ { 100, AVCProfileHigh },
+ { 110, AVCProfileHigh10 },
+ { 122, AVCProfileHigh422 },
+ { 244, AVCProfileHigh444 },
};
// set profile & level if they are recognized
- OMX_VIDEO_AVCPROFILETYPE codecProfile;
- OMX_VIDEO_AVCLEVELTYPE codecLevel;
+ int32_t codecProfile;
+ int32_t codecLevel;
if (profiles.map(profile, &codecProfile)) {
if (profile == 66 && (constraints & 0x40)) {
- codecProfile = (OMX_VIDEO_AVCPROFILETYPE)OMX_VIDEO_AVCProfileConstrainedBaseline;
+ codecProfile = AVCProfileConstrainedBaseline;
} else if (profile == 100 && (constraints & 0x0C) == 0x0C) {
- codecProfile = (OMX_VIDEO_AVCPROFILETYPE)OMX_VIDEO_AVCProfileConstrainedHigh;
+ codecProfile = AVCProfileConstrainedHigh;
}
format->setInt32("profile", codecProfile);
if (levels.map(level, &codecLevel)) {
// for 9 && 11 decide level based on profile and constraint_set3 flag
if (level == 11 && (profile == 66 || profile == 77 || profile == 88)) {
- codecLevel = (constraints & 0x10) ? OMX_VIDEO_AVCLevel1b : OMX_VIDEO_AVCLevel11;
+ codecLevel = (constraints & 0x10) ? AVCLevel1b : AVCLevel11;
}
format->setInt32("level", codecLevel);
}
@@ -256,41 +262,44 @@
// All Dolby Profiles will have profile and level info in MediaFormat
// Profile 8 and 9 will have bl_compatibility_id too.
- const static ALookup<uint8_t, OMX_VIDEO_DOLBYVISIONPROFILETYPE> profiles{
- {1, OMX_VIDEO_DolbyVisionProfileDvavPen},
- {3, OMX_VIDEO_DolbyVisionProfileDvheDen},
- {4, OMX_VIDEO_DolbyVisionProfileDvheDtr},
- {5, OMX_VIDEO_DolbyVisionProfileDvheStn},
- {6, OMX_VIDEO_DolbyVisionProfileDvheDth},
- {7, OMX_VIDEO_DolbyVisionProfileDvheDtb},
- {8, OMX_VIDEO_DolbyVisionProfileDvheSt},
- {9, OMX_VIDEO_DolbyVisionProfileDvavSe},
- {10, OMX_VIDEO_DolbyVisionProfileDvav110},
+ const static ALookup<uint8_t, int32_t> profiles{
+ {1, DolbyVisionProfileDvavPen},
+ {3, DolbyVisionProfileDvheDen},
+ {4, DolbyVisionProfileDvheDtr},
+ {5, DolbyVisionProfileDvheStn},
+ {6, DolbyVisionProfileDvheDth},
+ {7, DolbyVisionProfileDvheDtb},
+ {8, DolbyVisionProfileDvheSt},
+ {9, DolbyVisionProfileDvavSe},
+ {10, DolbyVisionProfileDvav110},
};
- const static ALookup<uint8_t, OMX_VIDEO_DOLBYVISIONLEVELTYPE> levels{
- {0, OMX_VIDEO_DolbyVisionLevelUnknown},
- {1, OMX_VIDEO_DolbyVisionLevelHd24},
- {2, OMX_VIDEO_DolbyVisionLevelHd30},
- {3, OMX_VIDEO_DolbyVisionLevelFhd24},
- {4, OMX_VIDEO_DolbyVisionLevelFhd30},
- {5, OMX_VIDEO_DolbyVisionLevelFhd60},
- {6, OMX_VIDEO_DolbyVisionLevelUhd24},
- {7, OMX_VIDEO_DolbyVisionLevelUhd30},
- {8, OMX_VIDEO_DolbyVisionLevelUhd48},
- {9, OMX_VIDEO_DolbyVisionLevelUhd60},
+ const static ALookup<uint8_t, int32_t> levels{
+ {0, DolbyVisionLevelUnknown},
+ {1, DolbyVisionLevelHd24},
+ {2, DolbyVisionLevelHd30},
+ {3, DolbyVisionLevelFhd24},
+ {4, DolbyVisionLevelFhd30},
+ {5, DolbyVisionLevelFhd60},
+ {6, DolbyVisionLevelUhd24},
+ {7, DolbyVisionLevelUhd30},
+ {8, DolbyVisionLevelUhd48},
+ {9, DolbyVisionLevelUhd60},
+ {10, DolbyVisionLevelUhd120},
+ {11, DolbyVisionLevel8k30},
+ {12, DolbyVisionLevel8k60},
};
// set rpuAssoc
if (rpu_present_flag && el_present_flag && !bl_present_flag) {
format->setInt32("rpuAssoc", 1);
}
// set profile & level if they are recognized
- OMX_VIDEO_DOLBYVISIONPROFILETYPE codecProfile;
- OMX_VIDEO_DOLBYVISIONLEVELTYPE codecLevel;
+ int32_t codecProfile;
+ int32_t codecLevel;
if (profiles.map(profile, &codecProfile)) {
format->setInt32("profile", codecProfile);
- if (codecProfile == OMX_VIDEO_DolbyVisionProfileDvheSt ||
- codecProfile == OMX_VIDEO_DolbyVisionProfileDvavSe) {
+ if (codecProfile == DolbyVisionProfileDvheSt ||
+ codecProfile == DolbyVisionProfileDvavSe) {
format->setInt32("bl_compatibility_id", bl_compatibility_id);
}
if (levels.map(level, &codecLevel)) {
@@ -307,32 +316,32 @@
const uint8_t profile = ptr[6];
const uint8_t level = ptr[5];
- const static ALookup<uint8_t, OMX_VIDEO_H263PROFILETYPE> profiles {
- { 0, OMX_VIDEO_H263ProfileBaseline },
- { 1, OMX_VIDEO_H263ProfileH320Coding },
- { 2, OMX_VIDEO_H263ProfileBackwardCompatible },
- { 3, OMX_VIDEO_H263ProfileISWV2 },
- { 4, OMX_VIDEO_H263ProfileISWV3 },
- { 5, OMX_VIDEO_H263ProfileHighCompression },
- { 6, OMX_VIDEO_H263ProfileInternet },
- { 7, OMX_VIDEO_H263ProfileInterlace },
- { 8, OMX_VIDEO_H263ProfileHighLatency },
+ const static ALookup<uint8_t, int32_t> profiles {
+ { 0, H263ProfileBaseline },
+ { 1, H263ProfileH320Coding },
+ { 2, H263ProfileBackwardCompatible },
+ { 3, H263ProfileISWV2 },
+ { 4, H263ProfileISWV3 },
+ { 5, H263ProfileHighCompression },
+ { 6, H263ProfileInternet },
+ { 7, H263ProfileInterlace },
+ { 8, H263ProfileHighLatency },
};
- const static ALookup<uint8_t, OMX_VIDEO_H263LEVELTYPE> levels {
- { 10, OMX_VIDEO_H263Level10 },
- { 20, OMX_VIDEO_H263Level20 },
- { 30, OMX_VIDEO_H263Level30 },
- { 40, OMX_VIDEO_H263Level40 },
- { 45, OMX_VIDEO_H263Level45 },
- { 50, OMX_VIDEO_H263Level50 },
- { 60, OMX_VIDEO_H263Level60 },
- { 70, OMX_VIDEO_H263Level70 },
+ const static ALookup<uint8_t, int32_t> levels {
+ { 10, H263Level10 },
+ { 20, H263Level20 },
+ { 30, H263Level30 },
+ { 40, H263Level40 },
+ { 45, H263Level45 },
+ { 50, H263Level50 },
+ { 60, H263Level60 },
+ { 70, H263Level70 },
};
// set profile & level if they are recognized
- OMX_VIDEO_H263PROFILETYPE codecProfile;
- OMX_VIDEO_H263LEVELTYPE codecLevel;
+ int32_t codecProfile;
+ int32_t codecLevel;
if (profiles.map(profile, &codecProfile)) {
format->setInt32("profile", codecProfile);
if (levels.map(level, &codecLevel)) {
@@ -350,59 +359,59 @@
const uint8_t tier = (ptr[1] & 0x20) >> 5;
const uint8_t level = ptr[12];
- const static ALookup<std::pair<uint8_t, uint8_t>, OMX_VIDEO_HEVCLEVELTYPE> levels {
- { { 0, 30 }, OMX_VIDEO_HEVCMainTierLevel1 },
- { { 0, 60 }, OMX_VIDEO_HEVCMainTierLevel2 },
- { { 0, 63 }, OMX_VIDEO_HEVCMainTierLevel21 },
- { { 0, 90 }, OMX_VIDEO_HEVCMainTierLevel3 },
- { { 0, 93 }, OMX_VIDEO_HEVCMainTierLevel31 },
- { { 0, 120 }, OMX_VIDEO_HEVCMainTierLevel4 },
- { { 0, 123 }, OMX_VIDEO_HEVCMainTierLevel41 },
- { { 0, 150 }, OMX_VIDEO_HEVCMainTierLevel5 },
- { { 0, 153 }, OMX_VIDEO_HEVCMainTierLevel51 },
- { { 0, 156 }, OMX_VIDEO_HEVCMainTierLevel52 },
- { { 0, 180 }, OMX_VIDEO_HEVCMainTierLevel6 },
- { { 0, 183 }, OMX_VIDEO_HEVCMainTierLevel61 },
- { { 0, 186 }, OMX_VIDEO_HEVCMainTierLevel62 },
- { { 1, 30 }, OMX_VIDEO_HEVCHighTierLevel1 },
- { { 1, 60 }, OMX_VIDEO_HEVCHighTierLevel2 },
- { { 1, 63 }, OMX_VIDEO_HEVCHighTierLevel21 },
- { { 1, 90 }, OMX_VIDEO_HEVCHighTierLevel3 },
- { { 1, 93 }, OMX_VIDEO_HEVCHighTierLevel31 },
- { { 1, 120 }, OMX_VIDEO_HEVCHighTierLevel4 },
- { { 1, 123 }, OMX_VIDEO_HEVCHighTierLevel41 },
- { { 1, 150 }, OMX_VIDEO_HEVCHighTierLevel5 },
- { { 1, 153 }, OMX_VIDEO_HEVCHighTierLevel51 },
- { { 1, 156 }, OMX_VIDEO_HEVCHighTierLevel52 },
- { { 1, 180 }, OMX_VIDEO_HEVCHighTierLevel6 },
- { { 1, 183 }, OMX_VIDEO_HEVCHighTierLevel61 },
- { { 1, 186 }, OMX_VIDEO_HEVCHighTierLevel62 },
+ const static ALookup<std::pair<uint8_t, uint8_t>, int32_t> levels {
+ { { 0, 30 }, HEVCMainTierLevel1 },
+ { { 0, 60 }, HEVCMainTierLevel2 },
+ { { 0, 63 }, HEVCMainTierLevel21 },
+ { { 0, 90 }, HEVCMainTierLevel3 },
+ { { 0, 93 }, HEVCMainTierLevel31 },
+ { { 0, 120 }, HEVCMainTierLevel4 },
+ { { 0, 123 }, HEVCMainTierLevel41 },
+ { { 0, 150 }, HEVCMainTierLevel5 },
+ { { 0, 153 }, HEVCMainTierLevel51 },
+ { { 0, 156 }, HEVCMainTierLevel52 },
+ { { 0, 180 }, HEVCMainTierLevel6 },
+ { { 0, 183 }, HEVCMainTierLevel61 },
+ { { 0, 186 }, HEVCMainTierLevel62 },
+ { { 1, 30 }, HEVCHighTierLevel1 },
+ { { 1, 60 }, HEVCHighTierLevel2 },
+ { { 1, 63 }, HEVCHighTierLevel21 },
+ { { 1, 90 }, HEVCHighTierLevel3 },
+ { { 1, 93 }, HEVCHighTierLevel31 },
+ { { 1, 120 }, HEVCHighTierLevel4 },
+ { { 1, 123 }, HEVCHighTierLevel41 },
+ { { 1, 150 }, HEVCHighTierLevel5 },
+ { { 1, 153 }, HEVCHighTierLevel51 },
+ { { 1, 156 }, HEVCHighTierLevel52 },
+ { { 1, 180 }, HEVCHighTierLevel6 },
+ { { 1, 183 }, HEVCHighTierLevel61 },
+ { { 1, 186 }, HEVCHighTierLevel62 },
};
- const static ALookup<uint8_t, OMX_VIDEO_HEVCPROFILETYPE> profiles {
- { 1, OMX_VIDEO_HEVCProfileMain },
- { 2, OMX_VIDEO_HEVCProfileMain10 },
+ const static ALookup<uint8_t, int32_t> profiles {
+ { 1, HEVCProfileMain },
+ { 2, HEVCProfileMain10 },
// use Main for Main Still Picture decoding
- { 3, OMX_VIDEO_HEVCProfileMain },
+ { 3, HEVCProfileMain },
};
// set profile & level if they are recognized
- OMX_VIDEO_HEVCPROFILETYPE codecProfile;
- OMX_VIDEO_HEVCLEVELTYPE codecLevel;
+ int32_t codecProfile;
+ int32_t codecLevel;
if (!profiles.map(profile, &codecProfile)) {
if (ptr[2] & 0x40 /* general compatibility flag 1 */) {
// Note that this case covers Main Still Picture too
- codecProfile = OMX_VIDEO_HEVCProfileMain;
+ codecProfile = HEVCProfileMain;
} else if (ptr[2] & 0x20 /* general compatibility flag 2 */) {
- codecProfile = OMX_VIDEO_HEVCProfileMain10;
+ codecProfile = HEVCProfileMain10;
} else {
return;
}
}
// bump to HDR profile
- if (isHdr(format) && codecProfile == OMX_VIDEO_HEVCProfileMain10) {
- codecProfile = OMX_VIDEO_HEVCProfileMain10HDR10;
+ if (isHdr(format) && codecProfile == HEVCProfileMain10) {
+ codecProfile = HEVCProfileMain10HDR10;
}
format->setInt32("profile", codecProfile);
@@ -422,36 +431,36 @@
}
const uint8_t indication = ((seq[4] & 0xF) << 4) | ((seq[5] & 0xF0) >> 4);
- const static ALookup<uint8_t, OMX_VIDEO_MPEG2PROFILETYPE> profiles {
- { 0x50, OMX_VIDEO_MPEG2ProfileSimple },
- { 0x40, OMX_VIDEO_MPEG2ProfileMain },
- { 0x30, OMX_VIDEO_MPEG2ProfileSNR },
- { 0x20, OMX_VIDEO_MPEG2ProfileSpatial },
- { 0x10, OMX_VIDEO_MPEG2ProfileHigh },
+ const static ALookup<uint8_t, int32_t> profiles {
+ { 0x50, MPEG2ProfileSimple },
+ { 0x40, MPEG2ProfileMain },
+ { 0x30, MPEG2ProfileSNR },
+ { 0x20, MPEG2ProfileSpatial },
+ { 0x10, MPEG2ProfileHigh },
};
- const static ALookup<uint8_t, OMX_VIDEO_MPEG2LEVELTYPE> levels {
- { 0x0A, OMX_VIDEO_MPEG2LevelLL },
- { 0x08, OMX_VIDEO_MPEG2LevelML },
- { 0x06, OMX_VIDEO_MPEG2LevelH14 },
- { 0x04, OMX_VIDEO_MPEG2LevelHL },
- { 0x02, OMX_VIDEO_MPEG2LevelHP },
+ const static ALookup<uint8_t, int32_t> levels {
+ { 0x0A, MPEG2LevelLL },
+ { 0x08, MPEG2LevelML },
+ { 0x06, MPEG2LevelH14 },
+ { 0x04, MPEG2LevelHL },
+ { 0x02, MPEG2LevelHP },
};
const static ALookup<uint8_t,
- std::pair<OMX_VIDEO_MPEG2PROFILETYPE, OMX_VIDEO_MPEG2LEVELTYPE>> escapes {
+ std::pair<int32_t, int32_t>> escapes {
/* unsupported
- { 0x8E, { XXX_MPEG2ProfileMultiView, OMX_VIDEO_MPEG2LevelLL } },
- { 0x8D, { XXX_MPEG2ProfileMultiView, OMX_VIDEO_MPEG2LevelML } },
- { 0x8B, { XXX_MPEG2ProfileMultiView, OMX_VIDEO_MPEG2LevelH14 } },
- { 0x8A, { XXX_MPEG2ProfileMultiView, OMX_VIDEO_MPEG2LevelHL } }, */
- { 0x85, { OMX_VIDEO_MPEG2Profile422, OMX_VIDEO_MPEG2LevelML } },
- { 0x82, { OMX_VIDEO_MPEG2Profile422, OMX_VIDEO_MPEG2LevelHL } },
+ { 0x8E, { XXX_MPEG2ProfileMultiView, MPEG2LevelLL } },
+ { 0x8D, { XXX_MPEG2ProfileMultiView, MPEG2LevelML } },
+ { 0x8B, { XXX_MPEG2ProfileMultiView, MPEG2LevelH14 } },
+ { 0x8A, { XXX_MPEG2ProfileMultiView, MPEG2LevelHL } }, */
+ { 0x85, { MPEG2Profile422, MPEG2LevelML } },
+ { 0x82, { MPEG2Profile422, MPEG2LevelHL } },
};
- OMX_VIDEO_MPEG2PROFILETYPE profile;
- OMX_VIDEO_MPEG2LEVELTYPE level;
- std::pair<OMX_VIDEO_MPEG2PROFILETYPE, OMX_VIDEO_MPEG2LEVELTYPE> profileLevel;
+ int32_t profile;
+ int32_t level;
+ std::pair<int32_t, int32_t> profileLevel;
if (escapes.map(indication, &profileLevel)) {
format->setInt32("profile", profileLevel.first);
format->setInt32("level", profileLevel.second);
@@ -468,16 +477,16 @@
// esds seems to only contain the profile for MPEG-2
uint8_t objType;
if (esds.getObjectTypeIndication(&objType) == OK) {
- const static ALookup<uint8_t, OMX_VIDEO_MPEG2PROFILETYPE> profiles{
- { 0x60, OMX_VIDEO_MPEG2ProfileSimple },
- { 0x61, OMX_VIDEO_MPEG2ProfileMain },
- { 0x62, OMX_VIDEO_MPEG2ProfileSNR },
- { 0x63, OMX_VIDEO_MPEG2ProfileSpatial },
- { 0x64, OMX_VIDEO_MPEG2ProfileHigh },
- { 0x65, OMX_VIDEO_MPEG2Profile422 },
+ const static ALookup<uint8_t, int32_t> profiles{
+ { 0x60, MPEG2ProfileSimple },
+ { 0x61, MPEG2ProfileMain },
+ { 0x62, MPEG2ProfileSNR },
+ { 0x63, MPEG2ProfileSpatial },
+ { 0x64, MPEG2ProfileHigh },
+ { 0x65, MPEG2Profile422 },
};
- OMX_VIDEO_MPEG2PROFILETYPE profile;
+ int32_t profile;
if (profiles.map(objType, &profile)) {
format->setInt32("profile", profile);
}
@@ -492,82 +501,82 @@
const uint8_t indication = seq[4];
const static ALookup<uint8_t,
- std::pair<OMX_VIDEO_MPEG4PROFILETYPE, OMX_VIDEO_MPEG4LEVELTYPE>> table {
- { 0b00000001, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level1 } },
- { 0b00000010, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level2 } },
- { 0b00000011, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level3 } },
- { 0b00000100, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level4a } },
- { 0b00000101, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level5 } },
- { 0b00000110, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level6 } },
- { 0b00001000, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0 } },
- { 0b00001001, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0b } },
- { 0b00010000, { OMX_VIDEO_MPEG4ProfileSimpleScalable, OMX_VIDEO_MPEG4Level0 } },
- { 0b00010001, { OMX_VIDEO_MPEG4ProfileSimpleScalable, OMX_VIDEO_MPEG4Level1 } },
- { 0b00010010, { OMX_VIDEO_MPEG4ProfileSimpleScalable, OMX_VIDEO_MPEG4Level2 } },
+ std::pair<int32_t, int32_t>> table {
+ { 0b00000001, { MPEG4ProfileSimple, MPEG4Level1 } },
+ { 0b00000010, { MPEG4ProfileSimple, MPEG4Level2 } },
+ { 0b00000011, { MPEG4ProfileSimple, MPEG4Level3 } },
+ { 0b00000100, { MPEG4ProfileSimple, MPEG4Level4a } },
+ { 0b00000101, { MPEG4ProfileSimple, MPEG4Level5 } },
+ { 0b00000110, { MPEG4ProfileSimple, MPEG4Level6 } },
+ { 0b00001000, { MPEG4ProfileSimple, MPEG4Level0 } },
+ { 0b00001001, { MPEG4ProfileSimple, MPEG4Level0b } },
+ { 0b00010000, { MPEG4ProfileSimpleScalable, MPEG4Level0 } },
+ { 0b00010001, { MPEG4ProfileSimpleScalable, MPEG4Level1 } },
+ { 0b00010010, { MPEG4ProfileSimpleScalable, MPEG4Level2 } },
/* unsupported
- { 0b00011101, { XXX_MPEG4ProfileSimpleScalableER, OMX_VIDEO_MPEG4Level0 } },
- { 0b00011110, { XXX_MPEG4ProfileSimpleScalableER, OMX_VIDEO_MPEG4Level1 } },
- { 0b00011111, { XXX_MPEG4ProfileSimpleScalableER, OMX_VIDEO_MPEG4Level2 } }, */
- { 0b00100001, { OMX_VIDEO_MPEG4ProfileCore, OMX_VIDEO_MPEG4Level1 } },
- { 0b00100010, { OMX_VIDEO_MPEG4ProfileCore, OMX_VIDEO_MPEG4Level2 } },
- { 0b00110010, { OMX_VIDEO_MPEG4ProfileMain, OMX_VIDEO_MPEG4Level2 } },
- { 0b00110011, { OMX_VIDEO_MPEG4ProfileMain, OMX_VIDEO_MPEG4Level3 } },
- { 0b00110100, { OMX_VIDEO_MPEG4ProfileMain, OMX_VIDEO_MPEG4Level4 } },
+ { 0b00011101, { XXX_MPEG4ProfileSimpleScalableER, MPEG4Level0 } },
+ { 0b00011110, { XXX_MPEG4ProfileSimpleScalableER, MPEG4Level1 } },
+ { 0b00011111, { XXX_MPEG4ProfileSimpleScalableER, MPEG4Level2 } }, */
+ { 0b00100001, { MPEG4ProfileCore, MPEG4Level1 } },
+ { 0b00100010, { MPEG4ProfileCore, MPEG4Level2 } },
+ { 0b00110010, { MPEG4ProfileMain, MPEG4Level2 } },
+ { 0b00110011, { MPEG4ProfileMain, MPEG4Level3 } },
+ { 0b00110100, { MPEG4ProfileMain, MPEG4Level4 } },
/* deprecated
- { 0b01000010, { OMX_VIDEO_MPEG4ProfileNbit, OMX_VIDEO_MPEG4Level2 } }, */
- { 0b01010001, { OMX_VIDEO_MPEG4ProfileScalableTexture, OMX_VIDEO_MPEG4Level1 } },
- { 0b01100001, { OMX_VIDEO_MPEG4ProfileSimpleFace, OMX_VIDEO_MPEG4Level1 } },
- { 0b01100010, { OMX_VIDEO_MPEG4ProfileSimpleFace, OMX_VIDEO_MPEG4Level2 } },
- { 0b01100011, { OMX_VIDEO_MPEG4ProfileSimpleFBA, OMX_VIDEO_MPEG4Level1 } },
- { 0b01100100, { OMX_VIDEO_MPEG4ProfileSimpleFBA, OMX_VIDEO_MPEG4Level2 } },
- { 0b01110001, { OMX_VIDEO_MPEG4ProfileBasicAnimated, OMX_VIDEO_MPEG4Level1 } },
- { 0b01110010, { OMX_VIDEO_MPEG4ProfileBasicAnimated, OMX_VIDEO_MPEG4Level2 } },
- { 0b10000001, { OMX_VIDEO_MPEG4ProfileHybrid, OMX_VIDEO_MPEG4Level1 } },
- { 0b10000010, { OMX_VIDEO_MPEG4ProfileHybrid, OMX_VIDEO_MPEG4Level2 } },
- { 0b10010001, { OMX_VIDEO_MPEG4ProfileAdvancedRealTime, OMX_VIDEO_MPEG4Level1 } },
- { 0b10010010, { OMX_VIDEO_MPEG4ProfileAdvancedRealTime, OMX_VIDEO_MPEG4Level2 } },
- { 0b10010011, { OMX_VIDEO_MPEG4ProfileAdvancedRealTime, OMX_VIDEO_MPEG4Level3 } },
- { 0b10010100, { OMX_VIDEO_MPEG4ProfileAdvancedRealTime, OMX_VIDEO_MPEG4Level4 } },
- { 0b10100001, { OMX_VIDEO_MPEG4ProfileCoreScalable, OMX_VIDEO_MPEG4Level1 } },
- { 0b10100010, { OMX_VIDEO_MPEG4ProfileCoreScalable, OMX_VIDEO_MPEG4Level2 } },
- { 0b10100011, { OMX_VIDEO_MPEG4ProfileCoreScalable, OMX_VIDEO_MPEG4Level3 } },
- { 0b10110001, { OMX_VIDEO_MPEG4ProfileAdvancedCoding, OMX_VIDEO_MPEG4Level1 } },
- { 0b10110010, { OMX_VIDEO_MPEG4ProfileAdvancedCoding, OMX_VIDEO_MPEG4Level2 } },
- { 0b10110011, { OMX_VIDEO_MPEG4ProfileAdvancedCoding, OMX_VIDEO_MPEG4Level3 } },
- { 0b10110100, { OMX_VIDEO_MPEG4ProfileAdvancedCoding, OMX_VIDEO_MPEG4Level4 } },
- { 0b11000001, { OMX_VIDEO_MPEG4ProfileAdvancedCore, OMX_VIDEO_MPEG4Level1 } },
- { 0b11000010, { OMX_VIDEO_MPEG4ProfileAdvancedCore, OMX_VIDEO_MPEG4Level2 } },
- { 0b11010001, { OMX_VIDEO_MPEG4ProfileAdvancedScalable, OMX_VIDEO_MPEG4Level1 } },
- { 0b11010010, { OMX_VIDEO_MPEG4ProfileAdvancedScalable, OMX_VIDEO_MPEG4Level2 } },
- { 0b11010011, { OMX_VIDEO_MPEG4ProfileAdvancedScalable, OMX_VIDEO_MPEG4Level3 } },
+ { 0b01000010, { MPEG4ProfileNbit, MPEG4Level2 } }, */
+ { 0b01010001, { MPEG4ProfileScalableTexture, MPEG4Level1 } },
+ { 0b01100001, { MPEG4ProfileSimpleFace, MPEG4Level1 } },
+ { 0b01100010, { MPEG4ProfileSimpleFace, MPEG4Level2 } },
+ { 0b01100011, { MPEG4ProfileSimpleFBA, MPEG4Level1 } },
+ { 0b01100100, { MPEG4ProfileSimpleFBA, MPEG4Level2 } },
+ { 0b01110001, { MPEG4ProfileBasicAnimated, MPEG4Level1 } },
+ { 0b01110010, { MPEG4ProfileBasicAnimated, MPEG4Level2 } },
+ { 0b10000001, { MPEG4ProfileHybrid, MPEG4Level1 } },
+ { 0b10000010, { MPEG4ProfileHybrid, MPEG4Level2 } },
+ { 0b10010001, { MPEG4ProfileAdvancedRealTime, MPEG4Level1 } },
+ { 0b10010010, { MPEG4ProfileAdvancedRealTime, MPEG4Level2 } },
+ { 0b10010011, { MPEG4ProfileAdvancedRealTime, MPEG4Level3 } },
+ { 0b10010100, { MPEG4ProfileAdvancedRealTime, MPEG4Level4 } },
+ { 0b10100001, { MPEG4ProfileCoreScalable, MPEG4Level1 } },
+ { 0b10100010, { MPEG4ProfileCoreScalable, MPEG4Level2 } },
+ { 0b10100011, { MPEG4ProfileCoreScalable, MPEG4Level3 } },
+ { 0b10110001, { MPEG4ProfileAdvancedCoding, MPEG4Level1 } },
+ { 0b10110010, { MPEG4ProfileAdvancedCoding, MPEG4Level2 } },
+ { 0b10110011, { MPEG4ProfileAdvancedCoding, MPEG4Level3 } },
+ { 0b10110100, { MPEG4ProfileAdvancedCoding, MPEG4Level4 } },
+ { 0b11000001, { MPEG4ProfileAdvancedCore, MPEG4Level1 } },
+ { 0b11000010, { MPEG4ProfileAdvancedCore, MPEG4Level2 } },
+ { 0b11010001, { MPEG4ProfileAdvancedScalable, MPEG4Level1 } },
+ { 0b11010010, { MPEG4ProfileAdvancedScalable, MPEG4Level2 } },
+ { 0b11010011, { MPEG4ProfileAdvancedScalable, MPEG4Level3 } },
/* unsupported
- { 0b11100001, { XXX_MPEG4ProfileSimpleStudio, OMX_VIDEO_MPEG4Level1 } },
- { 0b11100010, { XXX_MPEG4ProfileSimpleStudio, OMX_VIDEO_MPEG4Level2 } },
- { 0b11100011, { XXX_MPEG4ProfileSimpleStudio, OMX_VIDEO_MPEG4Level3 } },
- { 0b11100100, { XXX_MPEG4ProfileSimpleStudio, OMX_VIDEO_MPEG4Level4 } },
- { 0b11100101, { XXX_MPEG4ProfileCoreStudio, OMX_VIDEO_MPEG4Level1 } },
- { 0b11100110, { XXX_MPEG4ProfileCoreStudio, OMX_VIDEO_MPEG4Level2 } },
- { 0b11100111, { XXX_MPEG4ProfileCoreStudio, OMX_VIDEO_MPEG4Level3 } },
- { 0b11101000, { XXX_MPEG4ProfileCoreStudio, OMX_VIDEO_MPEG4Level4 } },
- { 0b11101011, { XXX_MPEG4ProfileSimpleStudio, OMX_VIDEO_MPEG4Level5 } },
- { 0b11101100, { XXX_MPEG4ProfileSimpleStudio, OMX_VIDEO_MPEG4Level6 } }, */
- { 0b11110000, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level0 } },
- { 0b11110001, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level1 } },
- { 0b11110010, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level2 } },
- { 0b11110011, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level3 } },
- { 0b11110100, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level4 } },
- { 0b11110101, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level5 } },
- { 0b11110111, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level3b } },
+ { 0b11100001, { XXX_MPEG4ProfileSimpleStudio, MPEG4Level1 } },
+ { 0b11100010, { XXX_MPEG4ProfileSimpleStudio, MPEG4Level2 } },
+ { 0b11100011, { XXX_MPEG4ProfileSimpleStudio, MPEG4Level3 } },
+ { 0b11100100, { XXX_MPEG4ProfileSimpleStudio, MPEG4Level4 } },
+ { 0b11100101, { XXX_MPEG4ProfileCoreStudio, MPEG4Level1 } },
+ { 0b11100110, { XXX_MPEG4ProfileCoreStudio, MPEG4Level2 } },
+ { 0b11100111, { XXX_MPEG4ProfileCoreStudio, MPEG4Level3 } },
+ { 0b11101000, { XXX_MPEG4ProfileCoreStudio, MPEG4Level4 } },
+ { 0b11101011, { XXX_MPEG4ProfileSimpleStudio, MPEG4Level5 } },
+ { 0b11101100, { XXX_MPEG4ProfileSimpleStudio, MPEG4Level6 } }, */
+ { 0b11110000, { MPEG4ProfileAdvancedSimple, MPEG4Level0 } },
+ { 0b11110001, { MPEG4ProfileAdvancedSimple, MPEG4Level1 } },
+ { 0b11110010, { MPEG4ProfileAdvancedSimple, MPEG4Level2 } },
+ { 0b11110011, { MPEG4ProfileAdvancedSimple, MPEG4Level3 } },
+ { 0b11110100, { MPEG4ProfileAdvancedSimple, MPEG4Level4 } },
+ { 0b11110101, { MPEG4ProfileAdvancedSimple, MPEG4Level5 } },
+ { 0b11110111, { MPEG4ProfileAdvancedSimple, MPEG4Level3b } },
/* deprecated
- { 0b11111000, { XXX_MPEG4ProfileFineGranularityScalable, OMX_VIDEO_MPEG4Level0 } },
- { 0b11111001, { XXX_MPEG4ProfileFineGranularityScalable, OMX_VIDEO_MPEG4Level1 } },
- { 0b11111010, { XXX_MPEG4ProfileFineGranularityScalable, OMX_VIDEO_MPEG4Level2 } },
- { 0b11111011, { XXX_MPEG4ProfileFineGranularityScalable, OMX_VIDEO_MPEG4Level3 } },
- { 0b11111100, { XXX_MPEG4ProfileFineGranularityScalable, OMX_VIDEO_MPEG4Level4 } },
- { 0b11111101, { XXX_MPEG4ProfileFineGranularityScalable, OMX_VIDEO_MPEG4Level5 } }, */
+ { 0b11111000, { XXX_MPEG4ProfileFineGranularityScalable, MPEG4Level0 } },
+ { 0b11111001, { XXX_MPEG4ProfileFineGranularityScalable, MPEG4Level1 } },
+ { 0b11111010, { XXX_MPEG4ProfileFineGranularityScalable, MPEG4Level2 } },
+ { 0b11111011, { XXX_MPEG4ProfileFineGranularityScalable, MPEG4Level3 } },
+ { 0b11111100, { XXX_MPEG4ProfileFineGranularityScalable, MPEG4Level4 } },
+ { 0b11111101, { XXX_MPEG4ProfileFineGranularityScalable, MPEG4Level5 } }, */
};
- std::pair<OMX_VIDEO_MPEG4PROFILETYPE, OMX_VIDEO_MPEG4LEVELTYPE> profileLevel;
+ std::pair<int32_t, int32_t> profileLevel;
if (table.map(indication, &profileLevel)) {
format->setInt32("profile", profileLevel.first);
format->setInt32("level", profileLevel.second);
@@ -590,19 +599,19 @@
switch (id) {
case 1 /* profileId */:
if (length >= 1) {
- const static ALookup<uint8_t, OMX_VIDEO_VP9PROFILETYPE> profiles {
- { 0, OMX_VIDEO_VP9Profile0 },
- { 1, OMX_VIDEO_VP9Profile1 },
- { 2, OMX_VIDEO_VP9Profile2 },
- { 3, OMX_VIDEO_VP9Profile3 },
+ const static ALookup<uint8_t, int32_t> profiles {
+ { 0, VP9Profile0 },
+ { 1, VP9Profile1 },
+ { 2, VP9Profile2 },
+ { 3, VP9Profile3 },
};
- const static ALookup<OMX_VIDEO_VP9PROFILETYPE, OMX_VIDEO_VP9PROFILETYPE> toHdr {
- { OMX_VIDEO_VP9Profile2, OMX_VIDEO_VP9Profile2HDR },
- { OMX_VIDEO_VP9Profile3, OMX_VIDEO_VP9Profile3HDR },
+ const static ALookup<int32_t, int32_t> toHdr {
+ { VP9Profile2, VP9Profile2HDR },
+ { VP9Profile3, VP9Profile3HDR },
};
- OMX_VIDEO_VP9PROFILETYPE profile;
+ int32_t profile;
if (profiles.map(data[0], &profile)) {
// convert to HDR profile
if (isHdr(format)) {
@@ -615,24 +624,24 @@
break;
case 2 /* levelId */:
if (length >= 1) {
- const static ALookup<uint8_t, OMX_VIDEO_VP9LEVELTYPE> levels {
- { 10, OMX_VIDEO_VP9Level1 },
- { 11, OMX_VIDEO_VP9Level11 },
- { 20, OMX_VIDEO_VP9Level2 },
- { 21, OMX_VIDEO_VP9Level21 },
- { 30, OMX_VIDEO_VP9Level3 },
- { 31, OMX_VIDEO_VP9Level31 },
- { 40, OMX_VIDEO_VP9Level4 },
- { 41, OMX_VIDEO_VP9Level41 },
- { 50, OMX_VIDEO_VP9Level5 },
- { 51, OMX_VIDEO_VP9Level51 },
- { 52, OMX_VIDEO_VP9Level52 },
- { 60, OMX_VIDEO_VP9Level6 },
- { 61, OMX_VIDEO_VP9Level61 },
- { 62, OMX_VIDEO_VP9Level62 },
+ const static ALookup<uint8_t, int32_t> levels {
+ { 10, VP9Level1 },
+ { 11, VP9Level11 },
+ { 20, VP9Level2 },
+ { 21, VP9Level21 },
+ { 30, VP9Level3 },
+ { 31, VP9Level31 },
+ { 40, VP9Level4 },
+ { 41, VP9Level41 },
+ { 50, VP9Level5 },
+ { 51, VP9Level51 },
+ { 52, VP9Level52 },
+ { 60, VP9Level6 },
+ { 61, VP9Level61 },
+ { 62, VP9Level62 },
};
- OMX_VIDEO_VP9LEVELTYPE level;
+ int32_t level;
if (levels.map(data[0], &level)) {
format->setInt32("level", level);
}
@@ -1504,7 +1513,30 @@
msg->setBuffer("csd-0", buffer);
}
- if (meta->findData(kKeyDVCC, &type, &data, &size)) {
+ if (meta->findData(kKeyDVCC, &type, &data, &size)
+ || meta->findData(kKeyDVVC, &type, &data, &size)
+ || meta->findData(kKeyDVWC, &type, &data, &size)) {
+ sp<ABuffer> buffer, csdOrg;
+ if (msg->findBuffer("csd-0", &csdOrg)) {
+ buffer = new (std::nothrow) ABuffer(size + csdOrg->size());
+ if (buffer.get() == NULL || buffer->base() == NULL) {
+ return NO_MEMORY;
+ }
+
+ memcpy(buffer->data(), csdOrg->data(), csdOrg->size());
+ memcpy(buffer->data() + csdOrg->size(), data, size);
+ } else {
+ buffer = new (std::nothrow) ABuffer(size);
+ if (buffer.get() == NULL || buffer->base() == NULL) {
+ return NO_MEMORY;
+ }
+ memcpy(buffer->data(), data, size);
+ }
+
+ buffer->meta()->setInt32("csd", true);
+ buffer->meta()->setInt64("timeUs", 0);
+ msg->setBuffer("csd-0", buffer);
+
const uint8_t *ptr = (const uint8_t *)data;
ALOGV("DV: calling parseDolbyVisionProfileLevelFromDvcc with data size %zu", size);
parseDolbyVisionProfileLevelFromDvcc(ptr, size, msg);
@@ -2009,30 +2041,134 @@
mime == MEDIA_MIMETYPE_IMAGE_AVIF) {
meta->setData(kKeyAV1C, 0, csd0->data(), csd0->size());
} else if (mime == MEDIA_MIMETYPE_VIDEO_DOLBY_VISION) {
- if (msg->findBuffer("csd-2", &csd2)) {
- //dvcc should be 24
- if (csd2->size() == 24) {
- meta->setData(kKeyDVCC, kTypeDVCC, csd2->data(), csd2->size());
- uint8_t *dvcc = csd2->data();
- const uint8_t profile = dvcc[2] >> 1;
- if (profile > 1 && profile < 9) {
+ int32_t needCreateDoviCSD = 0;
+ int32_t profile = 0;
+ uint8_t bl_compatibility = 0;
+ if (msg->findInt32("profile", &profile)) {
+ if (profile == DolbyVisionProfileDvheSt) {
+ profile = 8;
+ bl_compatibility = 4;
+ } else if (profile == DolbyVisionProfileDvavSe) {
+ profile = 9;
+ bl_compatibility = 2;
+ }
+ if (profile == 8 || profile == 9) {
+ needCreateDoviCSD = 1;
+ }
+ } else {
+ ALOGW("did not find dolby vision profile");
+ }
+ // No dovi csd data, need to create it
+ if (needCreateDoviCSD) {
+ uint8_t dvcc[24];
+ int32_t level = 0;
+ uint8_t level_val = 0;
+
+ if (msg->findInt32("level", &level)) {
+ const static ALookup<int32_t, uint8_t> levels {
+ {DolbyVisionLevelUnknown, 0},
+ {DolbyVisionLevelHd24, 1},
+ {DolbyVisionLevelHd30, 2},
+ {DolbyVisionLevelFhd24, 3},
+ {DolbyVisionLevelFhd30, 4},
+ {DolbyVisionLevelFhd60, 5},
+ {DolbyVisionLevelUhd24, 6},
+ {DolbyVisionLevelUhd30, 7},
+ {DolbyVisionLevelUhd48, 8},
+ {DolbyVisionLevelUhd60, 9},
+ {DolbyVisionLevelUhd120, 10},
+ {DolbyVisionLevel8k30, 11},
+ {DolbyVisionLevel8k60, 12},
+ };
+ levels.map(level, &level_val);
+ ALOGV("found dolby vision level: %d, value: %d", level, level_val);
+ }
+
+ dvcc[0] = 1; // major version
+ dvcc[1] = 0; // minor version
+ dvcc[2] = (uint8_t)((profile & 0x7f) << 1);// dolby vision profile
+ dvcc[2] = (uint8_t)((dvcc[2] | (uint8_t)((level_val >> 5) & 0x1)) & 0xff);
+ dvcc[3] = (uint8_t)((level_val & 0x1f) << 3); // dolby vision level
+ dvcc[3] = (uint8_t)(dvcc[3] | (1 << 2)); // rpu_present_flag
+ dvcc[3] = (uint8_t)(dvcc[3] | (1)); // bl_present_flag
+ dvcc[4] = (uint8_t)(bl_compatibility << 4);// bl_compatibility id
+
+ std::vector<uint8_t> dvcc_data(24);
+ memcpy(dvcc_data.data(), dvcc, 24);
+ if (profile > 10) {
+ meta->setData(kKeyDVWC, kTypeDVWC, dvcc_data.data(), 24);
+ } else if (profile > 7) {
+ meta->setData(kKeyDVVC, kTypeDVVC, dvcc_data.data(), 24);
+ } else {
+ meta->setData(kKeyDVCC, kTypeDVCC, dvcc_data.data(), 24);
+ }
+ } else if (csd0size >= 24) { // have dovi csd, just send it out...
+ uint8_t *dvconfig = csd0->data() + (csd0size -24);
+ profile = dvconfig[2] >> 1;
+ if (profile > 10) {
+ meta->setData(kKeyDVWC, kTypeDVWC, dvconfig, 24);
+ } else if (profile > 7) {
+ meta->setData(kKeyDVVC, kTypeDVVC, dvconfig, 24);
+ } else {
+ meta->setData(kKeyDVCC, kTypeDVCC, dvconfig, 24);
+ }
+ } else {
+ return BAD_VALUE;
+ }
+
+ // Send the avc/hevc/av1 csd data...
+ if (csd0size >= 24) {
+ sp<ABuffer> csd;
+ if ( profile > 1 && profile < 9) {
+ if (msg->findBuffer("csd-hevc", &csd)) {
+ meta->setData(kKeyHVCC, kTypeHVCC, csd->data(), csd->size());
+ } else if (csd0size > 24) {
std::vector<uint8_t> hvcc(csd0size + 1024);
size_t outsize = reassembleHVCC(csd0, hvcc.data(), hvcc.size(), 4);
meta->setData(kKeyHVCC, kTypeHVCC, hvcc.data(), outsize);
- } else if (DolbyVisionProfileDvav110 == profile) {
- meta->setData(kKeyAV1C, 0, csd0->data(), csd0->size());
- } else {
- sp<ABuffer> csd1;
- if (msg->findBuffer("csd-1", &csd1)) {
- std::vector<char> avcc(csd0size + csd1->size() + 1024);
- size_t outsize = reassembleAVCC(csd0, csd1, avcc.data());
- meta->setData(kKeyAVCC, kTypeAVCC, avcc.data(), outsize);
- }
}
+ } else if (profile == 9) {
+ sp<ABuffer> csd1;
+ if (msg->findBuffer("csd-avc", &csd)) {
+ meta->setData(kKeyAVCC, kTypeAVCC, csd->data(), csd->size());
+ } else if (msg->findBuffer("csd-1", &csd1)) {
+ std::vector<char> avcc(csd0size + csd1->size() + 1024);
+ size_t outsize = reassembleAVCC(csd0, csd1, avcc.data());
+ meta->setData(kKeyAVCC, kTypeAVCC, avcc.data(), outsize);
+ } else { // for dolby vision avc, csd0 also holds csd1
+ size_t i = 0;
+ int csd0realsize = 0;
+ do {
+ i = findNextNalStartCode(csd0->data() + i,
+ csd0->size() - i) - csd0->data();
+ if (i > 0) {
+ csd0realsize = i;
+ break;
+ }
+ i += 4;
+ } while(i < csd0->size());
+ // buffer0 -> csd0
+ sp<ABuffer> buffer0 = new (std::nothrow) ABuffer(csd0realsize);
+ if (buffer0.get() == NULL || buffer0->base() == NULL) {
+ return NO_MEMORY;
+ }
+ memcpy(buffer0->data(), csd0->data(), csd0realsize);
+ // buffer1 -> csd1
+ sp<ABuffer> buffer1 = new (std::nothrow)
+ ABuffer(csd0->size() - csd0realsize);
+ if (buffer1.get() == NULL || buffer1->base() == NULL) {
+ return NO_MEMORY;
+ }
+ memcpy(buffer1->data(), csd0->data()+csd0realsize,
+ csd0->size() - csd0realsize);
+
+ std::vector<char> avcc(csd0->size() + 1024);
+ size_t outsize = reassembleAVCC(buffer0, buffer1, avcc.data());
+ meta->setData(kKeyAVCC, kTypeAVCC, avcc.data(), outsize);
+ }
+ } else if (profile == 10) {
+ meta->setData(kKeyAV1C, 0, csd0->data(), csd0->size() - 24);
}
- } else {
- ALOGE("We need csd-2!!. %s", msg->debugString().c_str());
- return BAD_VALUE;
}
} else if (mime == MEDIA_MIMETYPE_VIDEO_VP9) {
meta->setData(kKeyVp9CodecPrivate, 0, csd0->data(), csd0->size());
@@ -2080,17 +2216,6 @@
meta->setData(kKeyStreamHeader, 'mdat', csd0->data(), csd0->size());
} else if (msg->findBuffer("d263", &csd0)) {
meta->setData(kKeyD263, kTypeD263, csd0->data(), csd0->size());
- } else if (mime == MEDIA_MIMETYPE_VIDEO_DOLBY_VISION && msg->findBuffer("csd-2", &csd2)) {
- meta->setData(kKeyDVCC, kTypeDVCC, csd2->data(), csd2->size());
-
- // Remove CSD-2 from the data here to avoid duplicate data in meta
- meta->remove(kKeyOpaqueCSD2);
-
- if (msg->findBuffer("csd-avc", &csd0)) {
- meta->setData(kKeyAVCC, kTypeAVCC, csd0->data(), csd0->size());
- } else if (msg->findBuffer("csd-hevc", &csd0)) {
- meta->setData(kKeyHVCC, kTypeHVCC, csd0->data(), csd0->size());
- }
}
// XXX TODO add whatever other keys there are
@@ -2173,29 +2298,29 @@
}
struct aac_format_conv_t {
- OMX_AUDIO_AACPROFILETYPE eAacProfileType;
+ int32_t eAacProfileType;
audio_format_t format;
};
static const struct aac_format_conv_t profileLookup[] = {
- { OMX_AUDIO_AACObjectMain, AUDIO_FORMAT_AAC_MAIN},
- { OMX_AUDIO_AACObjectLC, AUDIO_FORMAT_AAC_LC},
- { OMX_AUDIO_AACObjectSSR, AUDIO_FORMAT_AAC_SSR},
- { OMX_AUDIO_AACObjectLTP, AUDIO_FORMAT_AAC_LTP},
- { OMX_AUDIO_AACObjectHE, AUDIO_FORMAT_AAC_HE_V1},
- { OMX_AUDIO_AACObjectScalable, AUDIO_FORMAT_AAC_SCALABLE},
- { OMX_AUDIO_AACObjectERLC, AUDIO_FORMAT_AAC_ERLC},
- { OMX_AUDIO_AACObjectLD, AUDIO_FORMAT_AAC_LD},
- { OMX_AUDIO_AACObjectHE_PS, AUDIO_FORMAT_AAC_HE_V2},
- { OMX_AUDIO_AACObjectELD, AUDIO_FORMAT_AAC_ELD},
- { OMX_AUDIO_AACObjectXHE, AUDIO_FORMAT_AAC_XHE},
- { OMX_AUDIO_AACObjectNull, AUDIO_FORMAT_AAC},
+ { AACObjectMain, AUDIO_FORMAT_AAC_MAIN},
+ { AACObjectLC, AUDIO_FORMAT_AAC_LC},
+ { AACObjectSSR, AUDIO_FORMAT_AAC_SSR},
+ { AACObjectLTP, AUDIO_FORMAT_AAC_LTP},
+ { AACObjectHE, AUDIO_FORMAT_AAC_HE_V1},
+ { AACObjectScalable, AUDIO_FORMAT_AAC_SCALABLE},
+ { AACObjectERLC, AUDIO_FORMAT_AAC_ERLC},
+ { AACObjectLD, AUDIO_FORMAT_AAC_LD},
+ { AACObjectHE_PS, AUDIO_FORMAT_AAC_HE_V2},
+ { AACObjectELD, AUDIO_FORMAT_AAC_ELD},
+ { AACObjectXHE, AUDIO_FORMAT_AAC_XHE},
+ { AACObjectNull, AUDIO_FORMAT_AAC},
};
void mapAACProfileToAudioFormat( audio_format_t& format, uint64_t eAacProfile)
{
-const struct aac_format_conv_t* p = &profileLookup[0];
- while (p->eAacProfileType != OMX_AUDIO_AACObjectNull) {
+ const struct aac_format_conv_t* p = &profileLookup[0];
+ while (p->eAacProfileType != AACObjectNull) {
if (eAacProfile == p->eAacProfileType) {
format = p->format;
return;
@@ -2235,7 +2360,7 @@
// Offloading depends on audio DSP capabilities.
int32_t aacaot = -1;
if (meta->findInt32(kKeyAACAOT, &aacaot)) {
- mapAACProfileToAudioFormat(info->format,(OMX_AUDIO_AACPROFILETYPE) aacaot);
+ mapAACProfileToAudioFormat(info->format, aacaot);
}
int32_t srate = -1;
diff --git a/media/libstagefright/codecs/common/Android.bp b/media/libstagefright/codecs/common/Android.bp
index 08691e7..affc837 100644
--- a/media/libstagefright/codecs/common/Android.bp
+++ b/media/libstagefright/codecs/common/Android.bp
@@ -21,6 +21,10 @@
name: "libstagefright_enc_common",
vendor_available: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
srcs: ["cmnMemory.c"],
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index c7dc415..6004cf8 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -23,6 +23,7 @@
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/ColorUtils.h>
#include <media/stagefright/ColorConverter.h>
+#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/MediaErrors.h>
#include "libyuv/convert_from.h"
@@ -51,13 +52,17 @@
static bool isRGB(OMX_COLOR_FORMATTYPE colorFormat) {
return colorFormat == OMX_COLOR_Format16bitRGB565
|| colorFormat == OMX_COLOR_Format32BitRGBA8888
- || colorFormat == OMX_COLOR_Format32bitBGRA8888;
+ || colorFormat == OMX_COLOR_Format32bitBGRA8888
+ || colorFormat == COLOR_Format32bitABGR2101010;
}
bool ColorConverter::ColorSpace::isBt709() {
return (mStandard == ColorUtils::kColorStandardBT709);
}
+bool ColorConverter::ColorSpace::isBt2020() {
+ return (mStandard == ColorUtils::kColorStandardBT2020);
+}
bool ColorConverter::ColorSpace::isJpeg() {
return ((mStandard == ColorUtils::kColorStandardBT601_625)
@@ -70,16 +75,19 @@
: mSrcFormat(from),
mDstFormat(to),
mSrcColorSpace({0, 0, 0}),
- mClip(NULL) {
+ mClip(NULL),
+ mClip10Bit(NULL) {
}
ColorConverter::~ColorConverter() {
delete[] mClip;
mClip = NULL;
+ delete[] mClip10Bit;
+ mClip10Bit = NULL;
}
bool ColorConverter::isValid() const {
- switch (mSrcFormat) {
+ switch ((int32_t)mSrcFormat) {
case OMX_COLOR_FormatYUV420Planar16:
if (mDstFormat == OMX_COLOR_FormatYUV444Y410) {
return true;
@@ -102,6 +110,8 @@
#else
return mDstFormat == OMX_COLOR_Format16bitRGB565;
#endif
+ case COLOR_FormatYUVP010:
+ return mDstFormat == COLOR_Format32bitABGR2101010;
default:
return false;
@@ -143,9 +153,10 @@
mCropTop(cropTop),
mCropRight(cropRight),
mCropBottom(cropBottom) {
- switch(mColorFormat) {
+ switch((int32_t)mColorFormat) {
case OMX_COLOR_Format16bitRGB565:
case OMX_COLOR_FormatYUV420Planar16:
+ case COLOR_FormatYUVP010:
case OMX_COLOR_FormatCbYCrY:
mBpp = 2;
mStride = 2 * mWidth;
@@ -153,6 +164,7 @@
case OMX_COLOR_Format32bitBGRA8888:
case OMX_COLOR_Format32BitRGBA8888:
+ case COLOR_Format32bitABGR2101010:
case OMX_COLOR_FormatYUV444Y410:
mBpp = 4;
mStride = 4 * mWidth;
@@ -213,7 +225,7 @@
status_t err;
- switch (mSrcFormat) {
+ switch ((int32_t)mSrcFormat) {
case OMX_COLOR_FormatYUV420Planar:
#ifdef USE_LIBYUV
err = convertYUV420PlanarUseLibYUV(src, dst);
@@ -235,6 +247,19 @@
break;
}
+ case COLOR_FormatYUVP010:
+ {
+#if PERF_PROFILING
+ int64_t startTimeUs = ALooper::GetNowUs();
+#endif
+ err = convertYUVP010(src, dst);
+#if PERF_PROFILING
+ int64_t endTimeUs = ALooper::GetNowUs();
+ ALOGD("convertYUVP010 took %lld us", (long long) (endTimeUs - startTimeUs));
+#endif
+ break;
+ }
+
case OMX_COLOR_FormatCbYCrY:
err = convertCbYCrY(src, dst);
break;
@@ -439,23 +464,23 @@
}
std::function<void (void *, bool, signed, signed, signed, signed, signed, signed)>
-getWriteToDst(OMX_COLOR_FORMATTYPE dstFormat, uint8_t *kAdjustedClip) {
- switch (dstFormat) {
+getWriteToDst(OMX_COLOR_FORMATTYPE dstFormat, void *kAdjustedClip) {
+ switch ((int)dstFormat) {
case OMX_COLOR_Format16bitRGB565:
{
return [kAdjustedClip](void *dst_ptr, bool uncropped,
signed r1, signed g1, signed b1,
signed r2, signed g2, signed b2) {
uint32_t rgb1 =
- ((kAdjustedClip[r1] >> 3) << 11)
- | ((kAdjustedClip[g1] >> 2) << 5)
- | (kAdjustedClip[b1] >> 3);
+ ((((uint8_t *)kAdjustedClip)[r1] >> 3) << 11)
+ | ((((uint8_t *)kAdjustedClip)[g1] >> 2) << 5)
+ | (((uint8_t *)kAdjustedClip)[b1] >> 3);
if (uncropped) {
uint32_t rgb2 =
- ((kAdjustedClip[r2] >> 3) << 11)
- | ((kAdjustedClip[g2] >> 2) << 5)
- | (kAdjustedClip[b2] >> 3);
+ ((((uint8_t *)kAdjustedClip)[r2] >> 3) << 11)
+ | ((((uint8_t *)kAdjustedClip)[g2] >> 2) << 5)
+ | (((uint8_t *)kAdjustedClip)[b2] >> 3);
*(uint32_t *)dst_ptr = (rgb2 << 16) | rgb1;
} else {
@@ -469,16 +494,16 @@
signed r1, signed g1, signed b1,
signed r2, signed g2, signed b2) {
((uint32_t *)dst_ptr)[0] =
- (kAdjustedClip[r1])
- | (kAdjustedClip[g1] << 8)
- | (kAdjustedClip[b1] << 16)
+ (((uint8_t *)kAdjustedClip)[r1])
+ | (((uint8_t *)kAdjustedClip)[g1] << 8)
+ | (((uint8_t *)kAdjustedClip)[b1] << 16)
| (0xFF << 24);
if (uncropped) {
((uint32_t *)dst_ptr)[1] =
- (kAdjustedClip[r2])
- | (kAdjustedClip[g2] << 8)
- | (kAdjustedClip[b2] << 16)
+ (((uint8_t *)kAdjustedClip)[r2])
+ | (((uint8_t *)kAdjustedClip)[g2] << 8)
+ | (((uint8_t *)kAdjustedClip)[b2] << 16)
| (0xFF << 24);
}
};
@@ -489,20 +514,41 @@
signed r1, signed g1, signed b1,
signed r2, signed g2, signed b2) {
((uint32_t *)dst_ptr)[0] =
- (kAdjustedClip[b1])
- | (kAdjustedClip[g1] << 8)
- | (kAdjustedClip[r1] << 16)
+ (((uint8_t *)kAdjustedClip)[b1])
+ | (((uint8_t *)kAdjustedClip)[g1] << 8)
+ | (((uint8_t *)kAdjustedClip)[r1] << 16)
| (0xFF << 24);
if (uncropped) {
((uint32_t *)dst_ptr)[1] =
- (kAdjustedClip[b2])
- | (kAdjustedClip[g2] << 8)
- | (kAdjustedClip[r2] << 16)
+ (((uint8_t *)kAdjustedClip)[b2])
+ | (((uint8_t *)kAdjustedClip)[g2] << 8)
+ | (((uint8_t *)kAdjustedClip)[r2] << 16)
| (0xFF << 24);
}
};
}
+ case COLOR_Format32bitABGR2101010:
+ {
+ return [kAdjustedClip](void *dst_ptr, bool uncropped,
+ signed r1, signed g1, signed b1,
+ signed r2, signed g2, signed b2) {
+ ((uint32_t *)dst_ptr)[0] =
+ (((uint16_t *)kAdjustedClip)[r1])
+ | (((uint16_t *)kAdjustedClip)[g1] << 10)
+ | (((uint16_t *)kAdjustedClip)[b1] << 20)
+ | (3 << 30);
+
+ if (uncropped) {
+ ((uint32_t *)dst_ptr)[1] =
+ (((uint16_t *)kAdjustedClip)[r2])
+ | (((uint16_t *)kAdjustedClip)[g2] << 10)
+ | (((uint16_t *)kAdjustedClip)[b2] << 20)
+ | (3 << 30);
+ }
+ };
+ }
+
default:
TRESPASS();
}
@@ -514,7 +560,7 @@
uint8_t *kAdjustedClip = initClip();
auto readFromSrc = getReadFromSrc(mSrcFormat);
- auto writeToDst = getWriteToDst(mDstFormat, kAdjustedClip);
+ auto writeToDst = getWriteToDst(mDstFormat, (void *)kAdjustedClip);
uint8_t *dst_ptr = (uint8_t *)dst.mBits
+ dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
@@ -591,34 +637,116 @@
return convertYUV420Planar(src, dst);
}
-/*
- * Pack 10-bit YUV into RGBA_1010102.
- *
- * Media sends 10-bit YUV in a RGBA_1010102 format buffer. SF will handle
- * the conversion to RGB using RenderEngine fallback.
- *
- * We do not perform a YUV->RGB conversion here, however the conversion with
- * BT2020 to Full range is below for reference:
- *
- * B = 1.168 *(Y - 64) + 2.148 *(U - 512)
- * G = 1.168 *(Y - 64) - 0.652 *(V - 512) - 0.188 *(U - 512)
- * R = 1.168 *(Y - 64) + 1.683 *(V - 512)
- *
- * B = 1196/1024 *(Y - 64) + 2200/1024 *(U - 512)
- * G = .................... - 668/1024 *(V - 512) - 192/1024 *(U - 512)
- * R = .................... + 1723/1024 *(V - 512)
- *
- * min_B = (1196 *(- 64) + 2200 *(- 512)) / 1024 = -1175
- * min_G = (1196 *(- 64) - 668 *(1023 - 512) - 192 *(1023 - 512)) / 1024 = -504
- * min_R = (1196 *(- 64) + 1723 *(- 512)) / 1024 = -937
- *
- * max_B = (1196 *(1023 - 64) + 2200 *(1023 - 512)) / 1024 = 2218
- * max_G = (1196 *(1023 - 64) - 668 *(- 512) - 192 *(- 512)) / 1024 = 1551
- * max_R = (1196 *(1023 - 64) + 1723 *(1023 - 512)) / 1024 = 1980
- *
- * clip range -1175 .. 2218
- *
- */
+status_t ColorConverter::convertYUVP010(
+ const BitmapParams &src, const BitmapParams &dst) {
+ if (mDstFormat == COLOR_Format32bitABGR2101010) {
+ return convertYUVP010ToRGBA1010102(src, dst);
+ }
+
+ return ERROR_UNSUPPORTED;
+}
+
+status_t ColorConverter::convertYUVP010ToRGBA1010102(
+ const BitmapParams &src, const BitmapParams &dst) {
+ uint16_t *kAdjustedClip10bit = initClip10Bit();
+
+// auto readFromSrc = getReadFromSrc(mSrcFormat);
+ auto writeToDst = getWriteToDst(mDstFormat, (void *)kAdjustedClip10bit);
+
+ uint8_t *dst_ptr = (uint8_t *)dst.mBits
+ + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
+
+ uint16_t *src_y = (uint16_t *)((uint8_t *)src.mBits
+ + src.mCropTop * src.mStride + src.mCropLeft * src.mBpp);
+
+ uint16_t *src_uv = (uint16_t *)((uint8_t *)src.mBits
+ + src.mStride * src.mHeight
+ + (src.mCropTop / 2) * src.mStride + src.mCropLeft * src.mBpp);
+
+ // BT.2020 Limited Range conversion
+
+ // B = 1.168 *(Y - 64) + 2.148 *(U - 512)
+ // G = 1.168 *(Y - 64) - 0.652 *(V - 512) - 0.188 *(U - 512)
+ // R = 1.168 *(Y - 64) + 1.683 *(V - 512)
+
+ // B = 1196/1024 *(Y - 64) + 2200/1024 *(U - 512)
+ // G = .................... - 668/1024 *(V - 512) - 192/1024 *(U - 512)
+ // R = .................... + 1723/1024 *(V - 512)
+
+ // min_B = (1196 *(- 64) + 2200 *(- 512)) / 1024 = -1175
+ // min_G = (1196 *(- 64) - 668 *(1023 - 512) - 192 *(1023 - 512)) / 1024 = -504
+ // min_R = (1196 *(- 64) + 1723 *(- 512)) / 1024 = -937
+
+ // max_B = (1196 *(1023 - 64) + 2200 *(1023 - 512)) / 1024 = 2218
+ // max_G = (1196 *(1023 - 64) - 668 *(- 512) - 192 *(- 512)) / 1024 = 1551
+ // max_R = (1196 *(1023 - 64) + 1723 *(1023 - 512)) / 1024 = 1980
+
+ // clip range -1175 .. 2218
+
+ // BT.709 Limited Range conversion
+
+ // B = 1.164 * (Y - 64) + 2.018 * (U - 512)
+ // G = 1.164 * (Y - 64) - 0.813 * (V - 512) - 0.391 * (U - 512)
+ // R = 1.164 * (Y - 64) + 1.596 * (V - 512)
+
+ // B = 1192/1024 * (Y - 64) + 2068/1024 * (U - 512)
+ // G = .................... - 832/1024 * (V - 512) - 400/1024 * (U - 512)
+ // R = .................... + 1636/1024 * (V - 512)
+
+ // min_B = (1192 * (- 64) + 2068 * (- 512)) / 1024 = -1108
+
+ // max_B = (1192 * (1023 - 64) + 517 * (1023 - 512)) / 1024 = 2148
+
+ // clip range -1108 .. 2148
+
+ signed mY = 1196, mU_B = 2200, mV_G = -668, mV_R = 1723, mU_G = -192;
+ if (!mSrcColorSpace.isBt2020()) {
+ mY = 1192;
+ mU_B = 2068;
+ mV_G = -832;
+ mV_R = 1636;
+ mU_G = -400;
+ }
+ for (size_t y = 0; y < src.cropHeight(); ++y) {
+ for (size_t x = 0; x < src.cropWidth(); x += 2) {
+ signed y1, y2, u, v;
+ y1 = (src_y[x] >> 6) - 64;
+ y2 = (src_y[x + 1] >> 6) - 64;
+ u = int(src_uv[x] >> 6) - 512;
+ v = int(src_uv[x + 1] >> 6) - 512;
+
+ signed u_b = u * mU_B;
+ signed u_g = u * mU_G;
+ signed v_g = v * mV_G;
+ signed v_r = v * mV_R;
+
+ signed tmp1 = y1 * mY;
+ signed b1 = (tmp1 + u_b) / 1024;
+ signed g1 = (tmp1 + v_g + u_g) / 1024;
+ signed r1 = (tmp1 + v_r) / 1024;
+
+ signed tmp2 = y2 * mY;
+ signed b2 = (tmp2 + u_b) / 1024;
+ signed g2 = (tmp2 + v_g + u_g) / 1024;
+ signed r2 = (tmp2 + v_r) / 1024;
+
+ bool uncropped = x + 1 < src.cropWidth();
+
+ writeToDst(dst_ptr + x * dst.mBpp, uncropped, r1, g1, b1, r2, g2, b2);
+ }
+
+ src_y += src.mStride / 2;
+
+ if (y & 1) {
+ src_uv += src.mStride / 2;
+ }
+
+ dst_ptr += dst.mStride;
+ }
+
+ return OK;
+}
+
#if !USE_NEON_Y410
@@ -1033,4 +1161,19 @@
return &mClip[-kClipMin];
}
+uint16_t *ColorConverter::initClip10Bit() {
+ static const signed kClipMin = -1176;
+ static const signed kClipMax = 2219;
+
+ if (mClip10Bit == NULL) {
+ mClip10Bit = new uint16_t[kClipMax - kClipMin + 1];
+
+ for (signed i = kClipMin; i <= kClipMax; ++i) {
+ mClip10Bit[i - kClipMin] = (i < 0) ? 0 : (i > 1023) ? 1023 : (uint16_t)i;
+ }
+ }
+
+ return &mClip10Bit[-kClipMin];
+}
+
} // namespace android
diff --git a/media/libstagefright/filters/Android.bp b/media/libstagefright/filters/Android.bp
index b46a271..e6d59ad 100644
--- a/media/libstagefright/filters/Android.bp
+++ b/media/libstagefright/filters/Android.bp
@@ -22,6 +22,14 @@
"ZeroFilter.cpp",
],
+ export_include_dirs: [
+ "include",
+ ],
+
+ local_include_dirs: [
+ "include/filters",
+ ],
+
cflags: [
"-Wno-multichar",
"-Werror",
diff --git a/media/libstagefright/filters/ColorConvert.h b/media/libstagefright/filters/include/filters/ColorConvert.h
similarity index 100%
rename from media/libstagefright/filters/ColorConvert.h
rename to media/libstagefright/filters/include/filters/ColorConvert.h
diff --git a/media/libstagefright/filters/GraphicBufferListener.h b/media/libstagefright/filters/include/filters/GraphicBufferListener.h
similarity index 100%
rename from media/libstagefright/filters/GraphicBufferListener.h
rename to media/libstagefright/filters/include/filters/GraphicBufferListener.h
diff --git a/media/libstagefright/filters/IntrinsicBlurFilter.h b/media/libstagefright/filters/include/filters/IntrinsicBlurFilter.h
similarity index 100%
rename from media/libstagefright/filters/IntrinsicBlurFilter.h
rename to media/libstagefright/filters/include/filters/IntrinsicBlurFilter.h
diff --git a/media/libstagefright/filters/RSFilter.h b/media/libstagefright/filters/include/filters/RSFilter.h
similarity index 100%
rename from media/libstagefright/filters/RSFilter.h
rename to media/libstagefright/filters/include/filters/RSFilter.h
diff --git a/media/libstagefright/filters/SaturationFilter.h b/media/libstagefright/filters/include/filters/SaturationFilter.h
similarity index 100%
rename from media/libstagefright/filters/SaturationFilter.h
rename to media/libstagefright/filters/include/filters/SaturationFilter.h
diff --git a/media/libstagefright/filters/SimpleFilter.h b/media/libstagefright/filters/include/filters/SimpleFilter.h
similarity index 100%
rename from media/libstagefright/filters/SimpleFilter.h
rename to media/libstagefright/filters/include/filters/SimpleFilter.h
diff --git a/media/libstagefright/filters/ZeroFilter.h b/media/libstagefright/filters/include/filters/ZeroFilter.h
similarity index 100%
rename from media/libstagefright/filters/ZeroFilter.h
rename to media/libstagefright/filters/include/filters/ZeroFilter.h
diff --git a/media/libstagefright/flac/dec/Android.bp b/media/libstagefright/flac/dec/Android.bp
index 665aae1..83fcc01 100644
--- a/media/libstagefright/flac/dec/Android.bp
+++ b/media/libstagefright/flac/dec/Android.bp
@@ -21,6 +21,12 @@
name: "libstagefright_flacdec",
vendor_available: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ "com.android.media.swcodec",
+ ],
+
host_supported: true,
srcs: [
diff --git a/media/libstagefright/foundation/Android.bp b/media/libstagefright/foundation/Android.bp
index 5f86c22..1b31392 100644
--- a/media/libstagefright/foundation/Android.bp
+++ b/media/libstagefright/foundation/Android.bp
@@ -23,6 +23,11 @@
vendor_available: true,
host_supported: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ "com.android.media.swcodec",
+ ],
}
cc_defaults {
@@ -130,12 +135,19 @@
name: "libstagefright_foundation",
defaults: ["libstagefright_foundation_defaults"],
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ "com.android.media.swcodec",
+ ],
}
cc_library_static {
name: "libstagefright_foundation_without_imemory",
defaults: ["libstagefright_foundation_defaults"],
min_sdk_version: "29",
+ apex_available: ["com.android.media"],
+
cflags: [
"-Wno-multichar",
diff --git a/media/libstagefright/foundation/ColorUtils.cpp b/media/libstagefright/foundation/ColorUtils.cpp
index fa722b5..6dc8157 100644
--- a/media/libstagefright/foundation/ColorUtils.cpp
+++ b/media/libstagefright/foundation/ColorUtils.cpp
@@ -590,9 +590,10 @@
uint32_t gfxRange = range;
uint32_t gfxStandard = standard;
uint32_t gfxTransfer = transfer;
- // TRICKY: use & to ensure all three mappings are completed
- if (!(sGfxRanges.map(range, &gfxRange) & sGfxStandards.map(standard, &gfxStandard)
- & sGfxTransfers.map(transfer, &gfxTransfer))) {
+ bool mappedRange = sGfxRanges.map(range, &gfxRange);
+ bool mappedStandard = sGfxStandards.map(standard, &gfxStandard);
+ bool mappedTransfer = sGfxTransfers.map(transfer, &gfxTransfer);
+ if (! (mappedRange && mappedStandard && mappedTransfer)) {
ALOGW("could not safely map platform color aspects (R:%u(%s) S:%u(%s) T:%u(%s) to "
"graphics dataspace (R:%u S:%u T:%u)",
range, asString(range), standard, asString(standard), transfer, asString(transfer),
@@ -626,9 +627,10 @@
CU::ColorRange cuRange = CU::kColorRangeUnspecified;
CU::ColorStandard cuStandard = CU::kColorStandardUnspecified;
CU::ColorTransfer cuTransfer = CU::kColorTransferUnspecified;
- // TRICKY: use & to ensure all three mappings are completed
- if (!(sGfxRanges.map(gfxRange, &cuRange) & sGfxStandards.map(gfxStandard, &cuStandard)
- & sGfxTransfers.map(gfxTransfer, &cuTransfer))) {
+ bool mappedRange = sGfxRanges.map(gfxRange, &cuRange);
+ bool mappedStandard = sGfxStandards.map(gfxStandard, &cuStandard);
+ bool mappedTransfer = sGfxTransfers.map(gfxTransfer, &cuTransfer);
+ if (! (mappedRange && mappedStandard && mappedTransfer)) {
ALOGW("could not safely map graphics dataspace (R:%u S:%u T:%u) to "
"platform color aspects (R:%u(%s) S:%u(%s) T:%u(%s)",
gfxRange, gfxStandard, gfxTransfer,
@@ -781,5 +783,14 @@
return true;
}
+// static
+bool ColorUtils::isHDRStaticInfoValid(HDRStaticInfo *info) {
+ if (info->sType1.mMaxDisplayLuminance > 0.0f
+ && info->sType1.mMinDisplayLuminance > 0.0f) return true;
+ if (info->sType1.mMaxContentLightLevel > 0.0f
+ && info->sType1.mMaxFrameAverageLightLevel > 0.0f) return true;
+ return false;
+}
+
} // namespace android
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/ColorUtils.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ColorUtils.h
index a2b6c4f..72c8074 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/ColorUtils.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/ColorUtils.h
@@ -193,6 +193,9 @@
static void setHDRStaticInfoIntoAMediaFormat(const HDRStaticInfo &info, AMediaFormat *format);
// (internal) used by the setHDRStaticInfoInfo* routines
static void fillHdrStaticInfoBuffer( const HDRStaticInfo &info, uint8_t *data);
+
+ // determine whether HDR static info is valid
+ static bool isHDRStaticInfoValid(HDRStaticInfo *info);
};
inline static const char *asString(android::ColorUtils::ColorStandard i, const char *def = "??") {
diff --git a/media/libstagefright/http/Android.bp b/media/libstagefright/http/Android.bp
index f4d6d99..f25318d 100644
--- a/media/libstagefright/http/Android.bp
+++ b/media/libstagefright/http/Android.bp
@@ -12,10 +12,8 @@
srcs: ["HTTPHelper.cpp"],
- include_dirs: [
- "frameworks/av/media/libstagefright",
- "frameworks/native/include/media/openmax",
- "frameworks/base/core/jni",
+ header_libs: [
+ "libstagefright_headers",
],
shared_libs: [
diff --git a/media/libstagefright/httplive/Android.bp b/media/libstagefright/httplive/Android.bp
index 7acf735..7e26bd6 100644
--- a/media/libstagefright/httplive/Android.bp
+++ b/media/libstagefright/httplive/Android.bp
@@ -28,10 +28,6 @@
"PlaylistFetcher.cpp",
],
- include_dirs: [
- "frameworks/native/include/media/openmax",
- ],
-
cflags: [
"-Werror",
"-Wall",
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 0d7cadd..09ca1c9 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -23,7 +23,7 @@
#include "M3UParser.h"
#include "PlaylistFetcher.h"
-#include <AnotherPacketSource.h>
+#include <mpeg2ts/AnotherPacketSource.h>
#include <cutils/properties.h>
#include <media/MediaHTTPService.h>
diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
index ceea41d..ed38a2e 100644
--- a/media/libstagefright/httplive/LiveSession.h
+++ b/media/libstagefright/httplive/LiveSession.h
@@ -24,7 +24,7 @@
#include <utils/String8.h>
-#include <ATSParser.h>
+#include <mpeg2ts/ATSParser.h>
namespace android {
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index 907b326..b339fd2 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -25,8 +25,8 @@
#include "LiveSession.h"
#include "M3UParser.h"
#include <ID3.h>
-#include <AnotherPacketSource.h>
-#include <HlsSampleDecryptor.h>
+#include <mpeg2ts/AnotherPacketSource.h>
+#include <mpeg2ts/HlsSampleDecryptor.h>
#include <datasource/DataURISource.h>
#include <media/stagefright/foundation/ABitReader.h>
diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h
index 2e28164..716df63 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.h
+++ b/media/libstagefright/httplive/PlaylistFetcher.h
@@ -21,7 +21,7 @@
#include <media/stagefright/foundation/AHandler.h>
#include <openssl/aes.h>
-#include <ATSParser.h>
+#include <mpeg2ts/ATSParser.h>
#include "LiveSession.h"
namespace android {
diff --git a/media/libstagefright/id3/Android.bp b/media/libstagefright/id3/Android.bp
index 3f5ba47..bea3e34 100644
--- a/media/libstagefright/id3/Android.bp
+++ b/media/libstagefright/id3/Android.bp
@@ -20,6 +20,11 @@
cc_library_static {
name: "libstagefright_id3",
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ ],
+
srcs: ["ID3.cpp"],
diff --git a/media/libstagefright/include/media/stagefright/ColorConverter.h b/media/libstagefright/include/media/stagefright/ColorConverter.h
index 75b0d8e..1d86a22 100644
--- a/media/libstagefright/include/media/stagefright/ColorConverter.h
+++ b/media/libstagefright/include/media/stagefright/ColorConverter.h
@@ -54,6 +54,7 @@
uint32_t mTransfer;
bool isBt709();
+ bool isBt2020();
bool isJpeg();
};
@@ -78,8 +79,10 @@
OMX_COLOR_FORMATTYPE mSrcFormat, mDstFormat;
ColorSpace mSrcColorSpace;
uint8_t *mClip;
+ uint16_t *mClip10Bit;
uint8_t *initClip();
+ uint16_t *initClip10Bit();
status_t convertCbYCrY(
const BitmapParams &src, const BitmapParams &dst);
@@ -111,6 +114,12 @@
status_t convertTIYUV420PackedSemiPlanar(
const BitmapParams &src, const BitmapParams &dst);
+ status_t convertYUVP010(
+ const BitmapParams &src, const BitmapParams &dst);
+
+ status_t convertYUVP010ToRGBA1010102(
+ const BitmapParams &src, const BitmapParams &dst);
+
ColorConverter(const ColorConverter &);
ColorConverter &operator=(const ColorConverter &);
};
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index d372140..f5af50d 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -70,6 +70,13 @@
using aidl::android::media::MediaResourceParcel;
struct MediaCodec : public AHandler {
+ enum Domain {
+ DOMAIN_UNKNOWN = 0,
+ DOMAIN_VIDEO = 1,
+ DOMAIN_AUDIO = 2,
+ DOMAIN_IMAGE = 3
+ };
+
enum ConfigureFlags {
CONFIGURE_FLAG_ENCODE = 1,
CONFIGURE_FLAG_USE_BLOCK_MODEL = 2,
@@ -401,7 +408,6 @@
struct ResourceManagerServiceProxy;
State mState;
- uid_t mUid;
bool mReleasedByResourceManager;
sp<ALooper> mLooper;
sp<ALooper> mCodecLooper;
@@ -438,13 +444,19 @@
sp<ResourceManagerServiceProxy> mResourceManagerProxy;
- bool mIsVideo;
+ Domain mDomain;
AString mLogSessionId;
- int32_t mVideoWidth;
- int32_t mVideoHeight;
+ int32_t mWidth;
+ int32_t mHeight;
int32_t mRotationDegrees;
int32_t mAllowFrameDroppingBySurface;
+ uint32_t mHDRMetadataFlags; /* bitmask of kFlagHDR* */
+ enum {
+ kFlagHDRStaticInfo = 1 << 0,
+ kFlagHDR10PlusInfo = 1 << 1,
+ };
+
// initial create parameters
AString mInitName;
@@ -496,7 +508,7 @@
std::shared_ptr<BufferChannelBase> mBufferChannel;
- PlaybackDurationAccumulator * mPlaybackDurationAccumulator;
+ std::unique_ptr<PlaybackDurationAccumulator> mPlaybackDurationAccumulator;
bool mIsSurfaceToScreen;
MediaCodec(
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index 3a01925..84653eb 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -540,6 +540,9 @@
constexpr int32_t DolbyVisionLevelUhd30 = 0x40;
constexpr int32_t DolbyVisionLevelUhd48 = 0x80;
constexpr int32_t DolbyVisionLevelUhd60 = 0x100;
+constexpr int32_t DolbyVisionLevelUhd120 = 0x200;
+constexpr int32_t DolbyVisionLevel8k30 = 0x400;
+constexpr int32_t DolbyVisionLevel8k60 = 0x800;
inline static const char *asString_DolbyVisionLevel(int32_t i, const char *def = "??") {
switch (i) {
@@ -552,6 +555,9 @@
case DolbyVisionLevelUhd30: return "Uhd30";
case DolbyVisionLevelUhd48: return "Uhd48";
case DolbyVisionLevelUhd60: return "Uhd60";
+ case DolbyVisionLevelUhd120: return "Uhd120";
+ case DolbyVisionLevel8k30: return "8k30";
+ case DolbyVisionLevel8k60: return "8k60";
default: return def;
}
}
@@ -586,9 +592,11 @@
constexpr int32_t COLOR_Format24bitBGR888 = 12;
constexpr int32_t COLOR_Format24bitRGB888 = 11;
constexpr int32_t COLOR_Format25bitARGB1888 = 14;
+constexpr int32_t COLOR_Format32bitABGR2101010 = 0x7F00AAA2;
constexpr int32_t COLOR_Format32bitABGR8888 = 0x7F00A000;
constexpr int32_t COLOR_Format32bitARGB8888 = 16;
constexpr int32_t COLOR_Format32bitBGRA8888 = 15;
+constexpr int32_t COLOR_Format64bitABGRFloat = 0x7F000F16;
constexpr int32_t COLOR_Format8bitRGB332 = 2;
constexpr int32_t COLOR_FormatCbYCrY = 27;
constexpr int32_t COLOR_FormatCrYCbY = 28;
@@ -642,9 +650,11 @@
case COLOR_Format24bitBGR888: return "24bitBGR888";
case COLOR_Format24bitRGB888: return "24bitRGB888";
case COLOR_Format25bitARGB1888: return "25bitARGB1888";
+ case COLOR_Format32bitABGR2101010: return "32bitABGR2101010";
case COLOR_Format32bitABGR8888: return "32bitABGR8888";
case COLOR_Format32bitARGB8888: return "32bitARGB8888";
case COLOR_Format32bitBGRA8888: return "32bitBGRA8888";
+ case COLOR_Format64bitABGRFloat: return "64bitABGRFloat";
case COLOR_Format8bitRGB332: return "8bitRGB332";
case COLOR_FormatCbYCrY: return "CbYCrY";
case COLOR_FormatCrYCbY: return "CrYCbY";
@@ -677,6 +687,7 @@
case COLOR_FormatYUV422SemiPlanar: return "YUV422SemiPlanar";
case COLOR_FormatYUV444Flexible: return "YUV444Flexible";
case COLOR_FormatYUV444Interleaved: return "YUV444Interleaved";
+ case COLOR_FormatYUVP010: return "YUVP010";
case COLOR_QCOM_FormatYUV420SemiPlanar: return "QCOM_YUV420SemiPlanar";
case COLOR_TI_FormatYUV420PackedSemiPlanar: return "TI_YUV420PackedSemiPlanar";
default: return def;
@@ -684,6 +695,7 @@
}
constexpr char FEATURE_AdaptivePlayback[] = "adaptive-playback";
+constexpr char FEATURE_EncodingStatistics[] = "encoding-statistics";
constexpr char FEATURE_IntraRefresh[] = "intra-refresh";
constexpr char FEATURE_PartialFrame[] = "partial-frame";
constexpr char FEATURE_QpBounds[] = "qp-bounds";
@@ -737,6 +749,14 @@
constexpr int32_t COLOR_TRANSFER_SDR_VIDEO = 3;
constexpr int32_t COLOR_TRANSFER_ST2084 = 6;
+constexpr int32_t PICTURE_TYPE_I = 1;
+constexpr int32_t PICTURE_TYPE_P = 2;
+constexpr int32_t PICTURE_TYPE_B = 3;
+constexpr int32_t PICTURE_TYPE_UNKNOWN = 0;
+
+constexpr int32_t VIDEO_ENCODING_STATISTICS_LEVEL_1 = 1;
+constexpr int32_t VIDEO_ENCODING_STATISTICS_LEVEL_NONE = 0;
+
constexpr char KEY_AAC_DRC_ALBUM_MODE[] = "aac-drc-album-mode";
constexpr char KEY_AAC_DRC_ATTENUATION_FACTOR[] = "aac-drc-cut-level";
constexpr char KEY_AAC_DRC_BOOST_FACTOR[] = "aac-drc-boost-level";
@@ -789,12 +809,14 @@
constexpr char KEY_MAX_FPS_TO_ENCODER[] = "max-fps-to-encoder";
constexpr char KEY_MAX_HEIGHT[] = "max-height";
constexpr char KEY_MAX_INPUT_SIZE[] = "max-input-size";
+constexpr char KEY_MAX_OUTPUT_CHANNEL_COUNT[] = "max-output-channel-count";
constexpr char KEY_MAX_PTS_GAP_TO_ENCODER[] = "max-pts-gap-to-encoder";
constexpr char KEY_MAX_WIDTH[] = "max-width";
constexpr char KEY_MIME[] = "mime";
constexpr char KEY_OPERATING_RATE[] = "operating-rate";
constexpr char KEY_OUTPUT_REORDER_DEPTH[] = "output-reorder-depth";
constexpr char KEY_PCM_ENCODING[] = "pcm-encoding";
+constexpr char KEY_PICTURE_TYPE[] = "picture_type";
constexpr char KEY_PIXEL_ASPECT_RATIO_HEIGHT[] = "sar-height";
constexpr char KEY_PIXEL_ASPECT_RATIO_WIDTH[] = "sar-width";
constexpr char KEY_PREPEND_HEADER_TO_SYNC_FRAMES[] = "prepend-sps-pps-to-idr-frames";
@@ -811,6 +833,8 @@
constexpr char KEY_TILE_HEIGHT[] = "tile-height";
constexpr char KEY_TILE_WIDTH[] = "tile-width";
constexpr char KEY_TRACK_ID[] = "track-id";
+constexpr char KEY_VIDEO_ENCODING_STATISTICS_LEVEL[] = "video-encoding-statistics-level";
+constexpr char KEY_VIDEO_QP_AVERAGE[] = "video-qp-average";
constexpr char KEY_VIDEO_QP_B_MAX[] = "video-qp-b-max";
constexpr char KEY_VIDEO_QP_B_MIN[] = "video-qp-b-min";
constexpr char KEY_VIDEO_QP_I_MAX[] = "video-qp-i-max";
diff --git a/media/libstagefright/MediaCodecListOverrides.h b/media/libstagefright/include/media/stagefright/MediaCodecListOverrides.h
similarity index 100%
rename from media/libstagefright/MediaCodecListOverrides.h
rename to media/libstagefright/include/media/stagefright/MediaCodecListOverrides.h
diff --git a/media/libstagefright/include/media/stagefright/MetaDataBase.h b/media/libstagefright/include/media/stagefright/MetaDataBase.h
index c80012e..88c1f3f 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataBase.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataBase.h
@@ -60,6 +60,8 @@
kKeyAVCC = 'avcc', // raw data
kKeyHVCC = 'hvcc', // raw data
kKeyDVCC = 'dvcc', // raw data
+ kKeyDVVC = 'dvvc', // raw data
+ kKeyDVWC = 'dvwc', // raw data
kKeyAV1C = 'av1c', // raw data
kKeyThumbnailHVCC = 'thvc', // raw data
kKeyThumbnailAV1C = 'tav1', // raw data
@@ -283,6 +285,8 @@
kTypeHVCC = 'hvcc',
kTypeAV1C = 'av1c',
kTypeDVCC = 'dvcc',
+ kTypeDVVC = 'dvvc',
+ kTypeDVWC = 'dvwc',
kTypeD263 = 'd263',
kTypeHCOS = 'hcos',
};
diff --git a/media/libstagefright/include/media/stagefright/ProcessInfo.h b/media/libstagefright/include/media/stagefright/ProcessInfo.h
index b8a3c10..06b9c92 100644
--- a/media/libstagefright/include/media/stagefright/ProcessInfo.h
+++ b/media/libstagefright/include/media/stagefright/ProcessInfo.h
@@ -30,7 +30,8 @@
ProcessInfo();
virtual bool getPriority(int pid, int* priority);
- virtual bool isValidPid(int pid);
+ virtual bool isPidTrusted(int pid);
+ virtual bool isPidUidTrusted(int pid, int uid);
virtual bool overrideProcessInfo(int pid, int procState, int oomScore);
virtual void removeProcessInfoOverride(int pid);
diff --git a/media/libstagefright/include/media/stagefright/ProcessInfoInterface.h b/media/libstagefright/include/media/stagefright/ProcessInfoInterface.h
index 9260181..b7fc858 100644
--- a/media/libstagefright/include/media/stagefright/ProcessInfoInterface.h
+++ b/media/libstagefright/include/media/stagefright/ProcessInfoInterface.h
@@ -23,7 +23,8 @@
struct ProcessInfoInterface : public RefBase {
virtual bool getPriority(int pid, int* priority) = 0;
- virtual bool isValidPid(int pid) = 0;
+ virtual bool isPidTrusted(int pid) = 0;
+ virtual bool isPidUidTrusted(int pid, int uid) = 0;
virtual bool overrideProcessInfo(int pid, int procState, int oomScore);
virtual void removeProcessInfoOverride(int pid);
diff --git a/media/libstagefright/mpeg2ts/Android.bp b/media/libstagefright/mpeg2ts/Android.bp
index fbfa8cc..283df1e 100644
--- a/media/libstagefright/mpeg2ts/Android.bp
+++ b/media/libstagefright/mpeg2ts/Android.bp
@@ -54,16 +54,21 @@
"libstagefright_foundation_headers",
],
- export_include_dirs: ["."],
+ export_include_dirs: ["include"],
+
+ local_include_dirs: ["include/mpeg2ts"],
whole_static_libs: [
"libstagefright_metadatautils",
],
+}
+
+cc_defaults {
+ name: "libstagefright_mpeg2support_sdk_defaults",
+
min_sdk_version: "29",
-
host_supported: true,
-
target: {
darwin: {
enabled: false,
@@ -71,10 +76,19 @@
},
}
+cc_library_headers {
+ name: "libstagefright_mpeg2support_headers",
+ defaults: [
+ "libstagefright_mpeg2support_sdk_defaults",
+ ],
+ export_include_dirs: ["include"],
+}
+
cc_library_static {
name: "libstagefright_mpeg2support",
defaults: [
"libstagefright_mpeg2support_defaults",
+ "libstagefright_mpeg2support_sdk_defaults",
],
cflags: [
"-DENABLE_CRYPTO",
@@ -91,6 +105,7 @@
name: "libstagefright_mpeg2support_nocrypto",
defaults: [
"libstagefright_mpeg2support_defaults",
+ "libstagefright_mpeg2support_sdk_defaults",
],
apex_available: [
"com.android.media",
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/include/mpeg2ts/ATSParser.h
similarity index 100%
rename from media/libstagefright/mpeg2ts/ATSParser.h
rename to media/libstagefright/mpeg2ts/include/mpeg2ts/ATSParser.h
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/include/mpeg2ts/AnotherPacketSource.h
similarity index 100%
rename from media/libstagefright/mpeg2ts/AnotherPacketSource.h
rename to media/libstagefright/mpeg2ts/include/mpeg2ts/AnotherPacketSource.h
diff --git a/media/libstagefright/mpeg2ts/CasManager.h b/media/libstagefright/mpeg2ts/include/mpeg2ts/CasManager.h
similarity index 100%
rename from media/libstagefright/mpeg2ts/CasManager.h
rename to media/libstagefright/mpeg2ts/include/mpeg2ts/CasManager.h
diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/include/mpeg2ts/ESQueue.h
similarity index 100%
rename from media/libstagefright/mpeg2ts/ESQueue.h
rename to media/libstagefright/mpeg2ts/include/mpeg2ts/ESQueue.h
diff --git a/media/libstagefright/mpeg2ts/HlsSampleDecryptor.h b/media/libstagefright/mpeg2ts/include/mpeg2ts/HlsSampleDecryptor.h
similarity index 100%
rename from media/libstagefright/mpeg2ts/HlsSampleDecryptor.h
rename to media/libstagefright/mpeg2ts/include/mpeg2ts/HlsSampleDecryptor.h
diff --git a/media/libstagefright/mpeg2ts/SampleDecryptor.h b/media/libstagefright/mpeg2ts/include/mpeg2ts/SampleDecryptor.h
similarity index 100%
rename from media/libstagefright/mpeg2ts/SampleDecryptor.h
rename to media/libstagefright/mpeg2ts/include/mpeg2ts/SampleDecryptor.h
diff --git a/media/libstagefright/mpeg2ts/test/Mpeg2tsUnitTest.cpp b/media/libstagefright/mpeg2ts/test/Mpeg2tsUnitTest.cpp
index 7f25d78..9e24a99 100644
--- a/media/libstagefright/mpeg2ts/test/Mpeg2tsUnitTest.cpp
+++ b/media/libstagefright/mpeg2ts/test/Mpeg2tsUnitTest.cpp
@@ -26,9 +26,8 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaDataBase.h>
#include <media/stagefright/foundation/AUtils.h>
-
-#include <ATSParser.h>
-#include <AnotherPacketSource.h>
+#include <mpeg2ts/AnotherPacketSource.h>
+#include <mpeg2ts/ATSParser.h>
#include "Mpeg2tsUnitTestEnvironment.h"
diff --git a/media/libstagefright/rtsp/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp
index 5a8f471..7d72510 100644
--- a/media/libstagefright/rtsp/ARTPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTPConnection.cpp
@@ -558,6 +558,7 @@
if (n != (ssize_t)buffer->size()) {
ALOGW("failed to send RTCP receiver report (%s).",
n >= 0 ? "connection gone" : strerror(errno));
+ ++it;
continue;
}
diff --git a/media/libstagefright/rtsp/Android.bp b/media/libstagefright/rtsp/Android.bp
index 97d4abe..5b63cc2 100644
--- a/media/libstagefright/rtsp/Android.bp
+++ b/media/libstagefright/rtsp/Android.bp
@@ -101,6 +101,10 @@
//###############################################################################
+// 2022-01-13: this is stale; it's been disabled for 5 years.
+// test references UDPPusher and ARTPSession, neither of which is built into
+// libstagefright_rtsp
+//
cc_test {
name: "rtp_test",
gtest: false,
@@ -119,10 +123,9 @@
static_libs: ["libstagefright_rtsp"],
- include_dirs: [
- "frameworks/av/media/libstagefright",
- "frameworks/av/cmds/stagefright",
- "frameworks/native/include/media/openmax",
+ header_libs: [
+ "libstagefright_headers",
+ "libstagefright_rtsp_headers",
],
cflags: [
diff --git a/media/libstagefright/rtsp/rtp_test.cpp b/media/libstagefright/rtsp/rtp_test.cpp
index 1ae4a09..a8cd7e4 100644
--- a/media/libstagefright/rtsp/rtp_test.cpp
+++ b/media/libstagefright/rtsp/rtp_test.cpp
@@ -182,7 +182,7 @@
CHECK_EQ(decoder->start(), (status_t)OK);
for (;;) {
- MediaBuffer *buffer;
+ MediaBufferBase *buffer;
status_t err = decoder->read(&buffer);
if (err != OK) {
@@ -201,7 +201,7 @@
#if 1
if (buffer->range_length() != 0) {
int64_t timeUs;
- CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
+ CHECK(buffer->meta_data().findInt64(kKeyTime, &timeUs));
printf("decoder returned frame of size %zu at time %.2f secs\n",
buffer->range_length(), timeUs / 1E6);
diff --git a/media/libstagefright/tests/Android.bp b/media/libstagefright/tests/Android.bp
index a799a13..e6b67ce 100644
--- a/media/libstagefright/tests/Android.bp
+++ b/media/libstagefright/tests/Android.bp
@@ -32,11 +32,6 @@
"liblog",
],
- include_dirs: [
- "frameworks/av/media/libstagefright",
- "frameworks/av/media/libstagefright/include",
- ],
-
cflags: [
"-Werror",
"-Wall",
diff --git a/media/libstagefright/tests/MediaCodecListOverrides_test.cpp b/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
index 0c22a42..20737db 100644
--- a/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
+++ b/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
@@ -20,11 +20,10 @@
#include <gtest/gtest.h>
-#include "MediaCodecListOverrides.h"
-
#include <media/MediaCodecInfo.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaCodecList.h>
+#include <media/stagefright/MediaCodecListOverrides.h>
#include <vector>
diff --git a/media/libstagefright/tests/fuzzers/Android.bp b/media/libstagefright/tests/fuzzers/Android.bp
index 250ffb9..2bcfd67 100644
--- a/media/libstagefright/tests/fuzzers/Android.bp
+++ b/media/libstagefright/tests/fuzzers/Android.bp
@@ -32,9 +32,6 @@
"liblog",
"media_permission-aidl-cpp",
],
- include_dirs: [
- "frameworks/av/media/libstagefright",
- ],
}
cc_fuzz {
@@ -86,6 +83,9 @@
],
dictionary: "dictionaries/formats.dict",
defaults: ["libstagefright_fuzzer_defaults"],
+ header_libs: [
+ "libstagefright_webm_headers",
+ ],
static_libs: [
"libdatasource",
],
diff --git a/media/libstagefright/tests/fuzzers/FrameDecoderFuzzer.cpp b/media/libstagefright/tests/fuzzers/FrameDecoderFuzzer.cpp
index b346718..4218d2d 100644
--- a/media/libstagefright/tests/fuzzers/FrameDecoderFuzzer.cpp
+++ b/media/libstagefright/tests/fuzzers/FrameDecoderFuzzer.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "include/FrameDecoder.h"
+#include <FrameDecoder.h>
#include <fuzzer/FuzzedDataProvider.h>
#include <media/IMediaSource.h>
#include <media/stagefright/MetaData.h>
diff --git a/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.cpp b/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.cpp
index 810ae95..d94c8ff 100644
--- a/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.cpp
+++ b/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.cpp
@@ -23,7 +23,8 @@
#include <media/stagefright/OggWriter.h>
#include "MediaMimeTypes.h"
-#include "webm/WebmWriter.h"
+
+#include <webm/WebmWriter.h>
namespace android {
std::string genMimeType(FuzzedDataProvider *dataProvider) {
@@ -121,4 +122,4 @@
}
return writer;
}
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/media/libstagefright/tests/writer/WriterTest.cpp b/media/libstagefright/tests/writer/WriterTest.cpp
index 398c592..d170e7c 100644
--- a/media/libstagefright/tests/writer/WriterTest.cpp
+++ b/media/libstagefright/tests/writer/WriterTest.cpp
@@ -36,7 +36,7 @@
#include <media/stagefright/MPEG2TSWriter.h>
#include <media/stagefright/MPEG4Writer.h>
#include <media/stagefright/OggWriter.h>
-#include <WebmWriter.h>
+#include <webm/WebmWriter.h>
#include "WriterTestEnvironment.h"
#include "WriterUtility.h"
diff --git a/media/libstagefright/timedtext/Android.bp b/media/libstagefright/timedtext/Android.bp
index 6590ef7..619e06b 100644
--- a/media/libstagefright/timedtext/Android.bp
+++ b/media/libstagefright/timedtext/Android.bp
@@ -35,8 +35,16 @@
cfi: true,
},
- include_dirs: [
- "frameworks/av/media/libstagefright",
+ export_include_dirs: [
+ "include",
+ ],
+
+ local_include_dirs: [
+ "include/timedtext",
+ ],
+
+ header_libs: [
+ "libstagefright_headers",
],
shared_libs: ["libmedia"],
diff --git a/media/libstagefright/timedtext/TextDescriptions.h b/media/libstagefright/timedtext/include/timedtext/TextDescriptions.h
similarity index 100%
rename from media/libstagefright/timedtext/TextDescriptions.h
rename to media/libstagefright/timedtext/include/timedtext/TextDescriptions.h
diff --git a/media/libstagefright/timedtext/test/Android.bp b/media/libstagefright/timedtext/test/Android.bp
index 0b632bf..58c68ef 100644
--- a/media/libstagefright/timedtext/test/Android.bp
+++ b/media/libstagefright/timedtext/test/Android.bp
@@ -39,8 +39,8 @@
"libstagefright_foundation",
],
- include_dirs: [
- "frameworks/av/media/libstagefright",
+ header_libs: [
+ "libstagefright_headers",
],
shared_libs: [
diff --git a/media/libstagefright/timedtext/test/TimedTextUnitTest.cpp b/media/libstagefright/timedtext/test/TimedTextUnitTest.cpp
index d85ae39..f934b54 100644
--- a/media/libstagefright/timedtext/test/TimedTextUnitTest.cpp
+++ b/media/libstagefright/timedtext/test/TimedTextUnitTest.cpp
@@ -27,7 +27,7 @@
#include <media/stagefright/foundation/AString.h>
#include <media/stagefright/foundation/ByteUtils.h>
-#include "timedtext/TextDescriptions.h"
+#include <timedtext/TextDescriptions.h>
#include "TimedTextTestEnvironment.h"
diff --git a/media/libstagefright/webm/Android.bp b/media/libstagefright/webm/Android.bp
index 4209aea..9d5f430 100644
--- a/media/libstagefright/webm/Android.bp
+++ b/media/libstagefright/webm/Android.bp
@@ -33,7 +33,11 @@
"WebmWriter.cpp",
],
- export_include_dirs: ["."],
+ local_include_dirs: [
+ "include/webm",
+ ],
+
+ export_include_dirs: ["include"],
shared_libs: [
"libdatasource",
@@ -49,3 +53,16 @@
"media_ndk_headers",
],
}
+
+
+cc_library_headers {
+ name: "libstagefright_webm_headers",
+ export_include_dirs: ["include"],
+
+ host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
diff --git a/media/libstagefright/webm/EbmlUtil.h b/media/libstagefright/webm/include/webm/EbmlUtil.h
similarity index 100%
rename from media/libstagefright/webm/EbmlUtil.h
rename to media/libstagefright/webm/include/webm/EbmlUtil.h
diff --git a/media/libstagefright/webm/LinkedBlockingQueue.h b/media/libstagefright/webm/include/webm/LinkedBlockingQueue.h
similarity index 100%
rename from media/libstagefright/webm/LinkedBlockingQueue.h
rename to media/libstagefright/webm/include/webm/LinkedBlockingQueue.h
diff --git a/media/libstagefright/webm/WebmConstants.h b/media/libstagefright/webm/include/webm/WebmConstants.h
similarity index 100%
rename from media/libstagefright/webm/WebmConstants.h
rename to media/libstagefright/webm/include/webm/WebmConstants.h
diff --git a/media/libstagefright/webm/WebmElement.h b/media/libstagefright/webm/include/webm/WebmElement.h
similarity index 100%
rename from media/libstagefright/webm/WebmElement.h
rename to media/libstagefright/webm/include/webm/WebmElement.h
diff --git a/media/libstagefright/webm/WebmFrame.h b/media/libstagefright/webm/include/webm/WebmFrame.h
similarity index 100%
rename from media/libstagefright/webm/WebmFrame.h
rename to media/libstagefright/webm/include/webm/WebmFrame.h
diff --git a/media/libstagefright/webm/WebmFrameThread.h b/media/libstagefright/webm/include/webm/WebmFrameThread.h
similarity index 100%
rename from media/libstagefright/webm/WebmFrameThread.h
rename to media/libstagefright/webm/include/webm/WebmFrameThread.h
diff --git a/media/libstagefright/webm/WebmWriter.h b/media/libstagefright/webm/include/webm/WebmWriter.h
similarity index 100%
rename from media/libstagefright/webm/WebmWriter.h
rename to media/libstagefright/webm/include/webm/WebmWriter.h
diff --git a/media/libstagefright/webm/tests/Android.bp b/media/libstagefright/webm/tests/Android.bp
index 4443766..629ee47 100644
--- a/media/libstagefright/webm/tests/Android.bp
+++ b/media/libstagefright/webm/tests/Android.bp
@@ -31,8 +31,8 @@
"WebmFrameThreadUnitTest.cpp",
],
- include_dirs: [
- "frameworks/av/media/libstagefright",
+ header_libs: [
+ "libstagefright_headers",
],
static_libs: [
diff --git a/media/libstagefright/writer_fuzzers/Android.bp b/media/libstagefright/writer_fuzzers/Android.bp
index a33b888..b81f27e 100644
--- a/media/libstagefright/writer_fuzzers/Android.bp
+++ b/media/libstagefright/writer_fuzzers/Android.bp
@@ -119,7 +119,7 @@
"libstagefright_webm",
"libdatasource",
],
- include_dirs: [
- "frameworks/av/media/libstagefright",
+ header_libs: [
+ "libstagefright_headers",
],
}
diff --git a/media/libwatchdog/Android.bp b/media/libwatchdog/Android.bp
index 411c206..5506a73 100644
--- a/media/libwatchdog/Android.bp
+++ b/media/libwatchdog/Android.bp
@@ -39,7 +39,7 @@
darwin: {
enabled: false,
},
- linux_glibc: {
+ glibc: {
cflags: [
"-Dsigev_notify_thread_id=_sigev_un._tid",
],
diff --git a/media/mediaserver/Android.bp b/media/mediaserver/Android.bp
index 116999e..537df76 100644
--- a/media/mediaserver/Android.bp
+++ b/media/mediaserver/Android.bp
@@ -47,10 +47,6 @@
"libregistermsext",
],
- include_dirs: [
- "frameworks/av/media/libmediaplayerservice",
- ],
-
// By default mediaserver runs in 32-bit to save memory, except
// on 64-bit-only lunch targets.
// ****************************************************************
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index 58e2d2a..026847a 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -25,9 +25,8 @@
#include <utils/Log.h>
#include "RegisterExtensions.h"
-// from LOCAL_C_INCLUDES
-#include "MediaPlayerService.h"
-#include "ResourceManagerService.h"
+#include <MediaPlayerService.h>
+#include <ResourceManagerService.h>
using namespace android;
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 6c5e6cb..f7bc177 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -145,6 +145,7 @@
"libgui",
"libui",
"libmediandk_utils",
+ "android.hardware.drm-V1-ndk",
],
export_header_lib_headers: ["jni_headers"],
@@ -177,10 +178,6 @@
"NdkMediaDataSourceCallbacks.cpp",
],
- include_dirs: [
- "frameworks/av/media/libstagefright/include",
- "frameworks/av/media/ndk/include",
- ],
export_include_dirs: [
"include",
@@ -193,6 +190,7 @@
],
header_libs: [
+ "libstagefright_headers",
"libmedia_headers",
],
@@ -223,6 +221,7 @@
"libcutils",
"android.hardware.graphics.bufferqueue@1.0",
],
+
header_libs: [
"libstagefright_foundation_headers",
],
@@ -230,9 +229,6 @@
cflags: [
"-D__ANDROID_VNDK__",
],
- include_dirs: [
- "frameworks/av/media/ndk/",
- ],
}
cc_library_static {
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index 0e2de4e..354971a 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -29,6 +29,7 @@
#include <gui/Surface.h>
#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/PersistentSurface.h>
@@ -59,6 +60,7 @@
kWhatAsyncNotify,
kWhatRequestActivityNotifications,
kWhatStopActivityNotifications,
+ kWhatFrameRenderedNotify,
};
struct AMediaCodecPersistentSurface : public Surface {
@@ -98,6 +100,11 @@
mutable Mutex mAsyncCallbackLock;
AMediaCodecOnAsyncNotifyCallback mAsyncCallback;
void *mAsyncCallbackUserData;
+
+ sp<AMessage> mFrameRenderedNotify;
+ mutable Mutex mFrameRenderedCallbackLock;
+ AMediaCodecOnFrameRendered mFrameRenderedCallback;
+ void *mFrameRenderedCallbackUserData;
};
CodecHandler::CodecHandler(AMediaCodec *codec) {
@@ -158,8 +165,7 @@
}
Mutex::Autolock _l(mCodec->mAsyncCallbackLock);
- if (mCodec->mAsyncCallbackUserData != NULL
- || mCodec->mAsyncCallback.onAsyncInputAvailable != NULL) {
+ if (mCodec->mAsyncCallback.onAsyncInputAvailable != NULL) {
mCodec->mAsyncCallback.onAsyncInputAvailable(
mCodec,
mCodec->mAsyncCallbackUserData,
@@ -205,8 +211,7 @@
(uint32_t)flags};
Mutex::Autolock _l(mCodec->mAsyncCallbackLock);
- if (mCodec->mAsyncCallbackUserData != NULL
- || mCodec->mAsyncCallback.onAsyncOutputAvailable != NULL) {
+ if (mCodec->mAsyncCallback.onAsyncOutputAvailable != NULL) {
mCodec->mAsyncCallback.onAsyncOutputAvailable(
mCodec,
mCodec->mAsyncCallbackUserData,
@@ -234,8 +239,7 @@
AMediaFormat *aMediaFormat = AMediaFormat_fromMsg(©);
Mutex::Autolock _l(mCodec->mAsyncCallbackLock);
- if (mCodec->mAsyncCallbackUserData != NULL
- || mCodec->mAsyncCallback.onAsyncFormatChanged != NULL) {
+ if (mCodec->mAsyncCallback.onAsyncFormatChanged != NULL) {
mCodec->mAsyncCallback.onAsyncFormatChanged(
mCodec,
mCodec->mAsyncCallbackUserData,
@@ -263,8 +267,7 @@
err, actionCode, detail.c_str());
Mutex::Autolock _l(mCodec->mAsyncCallbackLock);
- if (mCodec->mAsyncCallbackUserData != NULL
- || mCodec->mAsyncCallback.onAsyncError != NULL) {
+ if (mCodec->mAsyncCallback.onAsyncError != NULL) {
mCodec->mAsyncCallback.onAsyncError(
mCodec,
mCodec->mAsyncCallbackUserData,
@@ -298,6 +301,43 @@
break;
}
+ case kWhatFrameRenderedNotify:
+ {
+ sp<AMessage> data;
+ if (!msg->findMessage("data", &data)) {
+ ALOGE("kWhatFrameRenderedNotify: data is expected.");
+ break;
+ }
+
+ AMessage::Type type;
+ int64_t mediaTimeUs, systemNano;
+ size_t index = 0;
+
+ // TODO. This code has dependency with MediaCodec::CreateFramesRenderedMessage.
+ for (size_t ix = 0; ix < data->countEntries(); ix++) {
+ AString name = data->getEntryNameAt(ix, &type);
+ if (name.startsWith(AStringPrintf("%zu-media-time-us", index).c_str())) {
+ AMessage::ItemData data = msg->getEntryAt(index);
+ data.find(&mediaTimeUs);
+ } else if (name.startsWith(AStringPrintf("%zu-system-nano", index).c_str())) {
+ AMessage::ItemData data = msg->getEntryAt(index);
+ data.find(&systemNano);
+
+ Mutex::Autolock _l(mCodec->mFrameRenderedCallbackLock);
+ if (mCodec->mFrameRenderedCallback != NULL) {
+ mCodec->mFrameRenderedCallback(
+ mCodec,
+ mCodec->mFrameRenderedCallbackUserData,
+ mediaTimeUs,
+ systemNano);
+ }
+
+ index++;
+ }
+ }
+ break;
+ }
+
default:
ALOGE("shouldn't be here");
break;
@@ -474,22 +514,46 @@
AMediaCodec *mData,
AMediaCodecOnAsyncNotifyCallback callback,
void *userdata) {
- if (mData->mAsyncNotify == NULL && userdata != NULL) {
- mData->mAsyncNotify = new AMessage(kWhatAsyncNotify, mData->mHandler);
- status_t err = mData->mCodec->setCallback(mData->mAsyncNotify);
- if (err != OK) {
- ALOGE("setAsyncNotifyCallback: err(%d), failed to set async callback", err);
- return translate_error(err);
- }
- }
Mutex::Autolock _l(mData->mAsyncCallbackLock);
+
+ if (mData->mAsyncNotify == NULL) {
+ mData->mAsyncNotify = new AMessage(kWhatAsyncNotify, mData->mHandler);
+ }
+
+ // always call, codec may have been reset/re-configured since last call.
+ status_t err = mData->mCodec->setCallback(mData->mAsyncNotify);
+ if (err != OK) {
+ ALOGE("setAsyncNotifyCallback: err(%d), failed to set async callback", err);
+ return translate_error(err);
+ }
+
mData->mAsyncCallback = callback;
mData->mAsyncCallbackUserData = userdata;
return AMEDIA_OK;
}
+EXPORT
+media_status_t AMediaCodec_setOnFrameRenderedCallback(
+ AMediaCodec *mData,
+ AMediaCodecOnFrameRendered callback,
+ void *userdata) {
+ Mutex::Autolock _l(mData->mFrameRenderedCallbackLock);
+ if (mData->mFrameRenderedNotify == NULL) {
+ mData->mFrameRenderedNotify = new AMessage(kWhatFrameRenderedNotify, mData->mHandler);
+ }
+ status_t err = mData->mCodec->setOnFrameRenderedNotification(mData->mFrameRenderedNotify);
+ if (err != OK) {
+ ALOGE("setOnFrameRenderedNotifyCallback: err(%d), failed to set callback", err);
+ return translate_error(err);
+ }
+
+ mData->mFrameRenderedCallback = callback;
+ mData->mFrameRenderedCallbackUserData = userdata;
+
+ return AMEDIA_OK;
+}
EXPORT
media_status_t AMediaCodec_releaseCrypto(AMediaCodec *mData) {
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index 69ab242..923453a 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -361,6 +361,7 @@
"mpegh-reference-channel-layout";
EXPORT const char* AMEDIAFORMAT_KEY_OPERATING_RATE = "operating-rate";
EXPORT const char* AMEDIAFORMAT_KEY_PCM_ENCODING = "pcm-encoding";
+EXPORT const char* AMEDIAFORMAT_KEY_PICTURE_TYPE = "picture-type";
EXPORT const char* AMEDIAFORMAT_KEY_PRIORITY = "priority";
EXPORT const char* AMEDIAFORMAT_KEY_PROFILE = "profile";
EXPORT const char* AMEDIAFORMAT_KEY_PCM_BIG_ENDIAN = "pcm-big-endian";
@@ -394,6 +395,9 @@
EXPORT const char* AMEDIAFORMAT_KEY_TRACK_ID = "track-id";
EXPORT const char* AMEDIAFORMAT_KEY_TRACK_INDEX = "track-index";
EXPORT const char* AMEDIAFORMAT_KEY_VALID_SAMPLES = "valid-samples";
+EXPORT const char* AMEDIAFORMAT_KEY_VIDEO_ENCODING_STATISTICS_LEVEL =
+ "video-encoding-statistics-level";
+EXPORT const char* AMEDIAFORMAT_KEY_VIDEO_QP_AVERAGE = "video-qp-average";
EXPORT const char* AMEDIAFORMAT_VIDEO_QP_B_MAX = "video-qp-b-max";
EXPORT const char* AMEDIAFORMAT_VIDEO_QP_B_MIN = "video-qp-b-min";
EXPORT const char* AMEDIAFORMAT_VIDEO_QP_I_MAX = "video-qp-i-max";
diff --git a/media/ndk/include/media/NdkMediaCodec.h b/media/ndk/include/media/NdkMediaCodec.h
index 519148e..5633374 100644
--- a/media/ndk/include/media/NdkMediaCodec.h
+++ b/media/ndk/include/media/NdkMediaCodec.h
@@ -39,6 +39,8 @@
#include <stdint.h>
#include <sys/cdefs.h>
+#include <android/api-level.h>
+
#include "NdkMediaCrypto.h"
#include "NdkMediaError.h"
#include "NdkMediaFormat.h"
@@ -122,6 +124,25 @@
} AMediaCodecOnAsyncNotifyCallback;
/**
+ * Called when an output frame has rendered on the output surface.
+ *
+ * \param codec The codec object that generated this notification.
+ * \param userdata The user data set at AMediaCodec_setOnFrameRenderedCallback.
+ * \param mediaTimeUs The presentation time (media time) of the frame rendered.
+ * This is usually the same as specified in
+ * AMediaCodec_queueInputBuffer, but some codecs may alter
+ * the media time by applying some time-based transformation,
+ * such as frame rate conversion. In that case, presentation
+ * time corresponds to the actual output frame rendered.
+ * \param systemNano The system time when the frame was rendered.
+ */
+typedef void (*AMediaCodecOnFrameRendered)(
+ AMediaCodec *codec,
+ void *userdata,
+ int64_t mediaTimeUs,
+ int64_t systemNano);
+
+/**
* Create codec by name. Use this if you know the exact codec you want to use.
* When configuring, you will need to specify whether to use the codec as an
* encoder or decoder.
@@ -441,6 +462,32 @@
void *userdata) __INTRODUCED_IN(28);
/**
+ * Registers a callback to be invoked when an output frame is rendered on the output surface.
+ *
+ * This method can be called in any codec state, but will only have an effect in the
+ * Executing state for codecs that render buffers to the output surface.
+ *
+ * This callback is for informational purposes only: to get precise
+ * render timing samples, and can be significantly delayed and batched. Some frames may have
+ * been rendered even if there was no callback generated.
+ *
+ * Refer to the definition of AMediaCodecOnFrameRendered on how each
+ * callback function is called and what are specified.
+ * The specified userdata is the pointer used when those callback functions are
+ * called.
+ *
+ * All callbacks are fired on one NDK internal thread.
+ * AMediaCodec_setOnFrameRenderedCallback should not be called on the callback thread.
+ * No heavy duty task should be performed on callback thread.
+ *
+ * Available since Android T.
+ */
+media_status_t AMediaCodec_setOnFrameRenderedCallback(
+ AMediaCodec*,
+ AMediaCodecOnFrameRendered callback,
+ void *userdata) __INTRODUCED_IN(__ANDROID_API_T__);
+
+/**
* Release the crypto if applicable.
*
* Available since API level 28.
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index 2d2fcc0..2195657 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -311,6 +311,10 @@
extern const char* AMEDIAFORMAT_KEY_LAST_SAMPLE_INDEX_IN_CHUNK __INTRODUCED_IN(31);
extern const char* AMEDIAFORMAT_KEY_SAMPLE_TIME_BEFORE_APPEND __INTRODUCED_IN(31);
+extern const char* AMEDIAFORMAT_KEY_PICTURE_TYPE __INTRODUCED_IN(33);
+extern const char* AMEDIAFORMAT_KEY_VIDEO_ENCODING_STATISTICS_LEVEL __INTRODUCED_IN(33);
+extern const char* AMEDIAFORMAT_KEY_VIDEO_QP_AVERAGE __INTRODUCED_IN(33);
+
extern const char* AMEDIAFORMAT_VIDEO_QP_B_MAX __INTRODUCED_IN(31);
extern const char* AMEDIAFORMAT_VIDEO_QP_B_MIN __INTRODUCED_IN(31);
extern const char* AMEDIAFORMAT_VIDEO_QP_I_MAX __INTRODUCED_IN(31);
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index b228945..c8faced 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -203,6 +203,7 @@
AMediaCodec_releaseOutputBuffer;
AMediaCodec_releaseOutputBufferAtTime;
AMediaCodec_setAsyncNotifyCallback; # introduced=28
+ AMediaCodec_setOnFrameRenderedCallback; # introduced=Tiramisu
AMediaCodec_setOutputSurface; # introduced=24
AMediaCodec_setParameters; # introduced=26
AMediaCodec_setInputSurface; # introduced=26
diff --git a/media/utils/Android.bp b/media/utils/Android.bp
index c1c7df5..ba8f199 100644
--- a/media/utils/Android.bp
+++ b/media/utils/Android.bp
@@ -122,7 +122,10 @@
cc_test {
name: "libmediautils_test",
- srcs: ["TimerThread-test.cpp"],
+ srcs: [
+ "memory-test.cpp",
+ "TimerThread-test.cpp",
+ ],
shared_libs: [
"libmediautils",
"libutils",
diff --git a/media/utils/ProcessInfo.cpp b/media/utils/ProcessInfo.cpp
index e212794..da199c4 100644
--- a/media/utils/ProcessInfo.cpp
+++ b/media/utils/ProcessInfo.cpp
@@ -64,11 +64,27 @@
return true;
}
-bool ProcessInfo::isValidPid(int pid) {
+bool ProcessInfo::isPidTrusted(int pid) {
+ return isPidUidTrusted(pid, -1);
+}
+
+bool ProcessInfo::isPidUidTrusted(int pid, int uid) {
int callingPid = IPCThreadState::self()->getCallingPid();
int callingUid = IPCThreadState::self()->getCallingUid();
- // Trust it if this is called from the same process otherwise pid has to match the calling pid.
- return (callingPid == getpid()) || (callingPid == pid) || (callingUid == AID_MEDIA);
+ // Always trust when the caller is acting on their own behalf.
+ if (pid == callingPid && (uid == callingUid || uid == -1)) { // UID can be optional
+ return true;
+ }
+ // Implicitly trust when the caller is our own process.
+ if (callingPid == getpid()) {
+ return true;
+ }
+ // Implicitly trust when a media process is calling.
+ if (callingUid == AID_MEDIA) {
+ return true;
+ }
+ // Otherwise, allow the caller to act as another process when the caller has permissions.
+ return checkCallingPermission(String16("android.permission.MEDIA_RESOURCE_OVERRIDE_PID"));
}
bool ProcessInfo::overrideProcessInfo(int pid, int procState, int oomScore) {
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index 15d6d3697..1ab5bc1 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -220,6 +220,17 @@
return ok;
}
+bool accessUltrasoundAllowed(const AttributionSourceState& attributionSource) {
+ uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
+ uid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(attributionSource.pid));
+ if (isAudioServerOrRootUid(uid)) return true;
+ static const String16 sAccessUltrasound(
+ "android.permission.ACCESS_ULTRASOUND");
+ bool ok = PermissionCache::checkPermission(sAccessUltrasound, pid, uid);
+ if (!ok) ALOGE("Request requires android.permission.ACCESS_ULTRASOUND");
+ return ok;
+}
+
bool captureHotwordAllowed(const AttributionSourceState& attributionSource) {
// CAPTURE_AUDIO_HOTWORD permission implies RECORD_AUDIO permission
bool ok = recordingAllowed(attributionSource);
diff --git a/media/utils/fuzzers/Android.bp b/media/utils/fuzzers/Android.bp
index c4dc24f..d26e6c2 100644
--- a/media/utils/fuzzers/Android.bp
+++ b/media/utils/fuzzers/Android.bp
@@ -32,11 +32,6 @@
"bionic_libc_platform_headers",
"libmedia_headers",
],
-
- include_dirs: [
- // For DEBUGGER_SIGNAL
- "system/core/debuggerd/include",
- ],
}
cc_fuzz {
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index cb428ec..de20d55 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -96,6 +96,7 @@
bool captureMediaOutputAllowed(const AttributionSourceState& attributionSource);
bool captureTunerAudioInputAllowed(const AttributionSourceState& attributionSource);
bool captureVoiceCommunicationOutputAllowed(const AttributionSourceState& attributionSource);
+bool accessUltrasoundAllowed(const AttributionSourceState& attributionSource);
bool captureHotwordAllowed(const AttributionSourceState& attributionSource);
bool settingsAllowed();
bool modifyAudioRoutingAllowed();
diff --git a/media/utils/include/mediautils/memory.h b/media/utils/include/mediautils/memory.h
new file mode 100644
index 0000000..cc00bb6
--- /dev/null
+++ b/media/utils/include/mediautils/memory.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 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
+
+namespace android {
+
+namespace {
+struct FreeDeleter {
+ void operator()(void* p) { free(p); }
+};
+
+} // namespace
+
+/**
+ * Used to wrap pointers allocated by legacy code using malloc / calloc / etc.
+ */
+template <typename T>
+using unique_malloced_ptr = std::unique_ptr<T, FreeDeleter>;
+
+} // namespace android
diff --git a/media/utils/memory-test.cpp b/media/utils/memory-test.cpp
new file mode 100644
index 0000000..2409bc2
--- /dev/null
+++ b/media/utils/memory-test.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 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 <gtest/gtest.h>
+#include <mediautils/memory.h>
+
+namespace android {
+namespace {
+
+TEST(UniqueMallocedPtr, Void) {
+ unique_malloced_ptr<void> p(std::malloc(10));
+}
+
+TEST(UniqueMallocedPtr, Char) {
+ unique_malloced_ptr<char> p(reinterpret_cast<char*>(std::malloc(10)));
+}
+
+TEST(UniqueMallocedPtr, Null) {
+ unique_malloced_ptr<char> p(nullptr);
+}
+
+TEST(UniqueMallocedPtr, Default) {
+ unique_malloced_ptr<char> p;
+}
+
+} // namespace
+} // namespace android
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index ed4666f..eb3c164 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -31,6 +31,7 @@
#include <sys/resource.h>
#include <thread>
+#include <android-base/stringprintf.h>
#include <android/media/IAudioPolicyService.h>
#include <android/os/IExternalVibratorService.h>
#include <binder/IPCThreadState.h>
@@ -104,8 +105,9 @@
namespace android {
-#define MAX_AAUDIO_PROPERTY_DEVICE_HAL_VERSION 7.0
+#define MAX_AAUDIO_PROPERTY_DEVICE_HAL_VERSION 7.1
+using ::android::base::StringPrintf;
using media::IEffectClient;
using media::audio::common::AudioMMapPolicyInfo;
using media::audio::common::AudioMMapPolicyType;
@@ -384,6 +386,24 @@
return mAAudioHwBurstMinMicros;
}
+status_t AudioFlinger::setDeviceConnectedState(const struct audio_port_v7 *port, bool connected) {
+ status_t final_result = NO_INIT;
+ Mutex::Autolock _l(mLock);
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_HW_SET_CONNECTED_STATE;
+ for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+ sp<DeviceHalInterface> dev = mAudioHwDevs.valueAt(i)->hwDevice();
+ status_t result = dev->setConnectedState(port, connected);
+ // Same logic as with setParameter: it's a success if at least one
+ // HAL module accepts the update.
+ if (final_result != NO_ERROR) {
+ final_result = result;
+ }
+ }
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return final_result;
+}
+
// getDefaultVibratorInfo_l must be called with AudioFlinger lock held.
std::optional<media::AudioVibratorInfo> AudioFlinger::getDefaultVibratorInfo_l() {
if (mAudioVibratorInfos.empty()) {
@@ -2340,11 +2360,12 @@
if (mDevicesFactoryHal->getHalVersion() > MAX_AAUDIO_PROPERTY_DEVICE_HAL_VERSION) {
if (int32_t mixerBursts = dev->getAAudioMixerBurstCount();
- mixerBursts > mAAudioBurstsPerBuffer) {
+ mixerBursts > 0 && mixerBursts > mAAudioBurstsPerBuffer) {
mAAudioBurstsPerBuffer = mixerBursts;
}
if (int32_t hwBurstMinMicros = dev->getAAudioHardwareBurstMinUsec();
- hwBurstMinMicros < mAAudioHwBurstMinMicros || mAAudioHwBurstMinMicros == 0) {
+ hwBurstMinMicros > 0
+ && (hwBurstMinMicros < mAAudioHwBurstMinMicros || mAAudioHwBurstMinMicros == 0)) {
mAAudioHwBurstMinMicros = hwBurstMinMicros;
}
}
@@ -2473,21 +2494,17 @@
if (dev == nullptr) {
return AUDIO_HW_SYNC_INVALID;
}
- String8 reply;
- AudioParameter param;
- if (dev->getParameters(String8(AudioParameter::keyHwAvSync), &reply) == OK) {
- param = AudioParameter(reply);
- }
- int value;
- if (param.getInt(String8(AudioParameter::keyHwAvSync), value) != NO_ERROR) {
+ error::Result<audio_hw_sync_t> result = dev->getHwAvSync();
+ if (!result.ok()) {
ALOGW("getAudioHwSyncForSession error getting sync for session %d", sessionId);
return AUDIO_HW_SYNC_INVALID;
}
+ audio_hw_sync_t value = VALUE_OR_FATAL(result);
// allow only one session for a given HW A/V sync ID.
for (size_t i = 0; i < mHwAvSyncIds.size(); i++) {
- if (mHwAvSyncIds.valueAt(i) == (audio_hw_sync_t)value) {
+ if (mHwAvSyncIds.valueAt(i) == value) {
ALOGV("getAudioHwSyncForSession removing ID %d for session %d",
value, mHwAvSyncIds.keyAt(i));
mHwAvSyncIds.removeItemsAt(i);
@@ -2590,7 +2607,7 @@
{
AudioHwDevice *outHwDev = findSuitableHwDev_l(module, deviceType);
if (outHwDev == NULL) {
- return 0;
+ return nullptr;
}
if (*output == AUDIO_IO_HANDLE_NONE) {
@@ -2599,9 +2616,17 @@
// Audio Policy does not currently request a specific output handle.
// If this is ever needed, see openInput_l() for example code.
ALOGE("openOutput_l requested output handle %d is not AUDIO_IO_HANDLE_NONE", *output);
- return 0;
+ return nullptr;
}
+#ifndef MULTICHANNEL_EFFECT_CHAIN
+ if (flags & AUDIO_OUTPUT_FLAG_SPATIALIZER) {
+ ALOGE("openOutput_l() cannot create spatializer thread "
+ "without #define MULTICHANNEL_EFFECT_CHAIN");
+ return nullptr;
+ }
+#endif
+
mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
// FOR TESTING ONLY:
@@ -2646,18 +2671,11 @@
return thread;
} else {
sp<PlaybackThread> thread;
- //TODO: b/193496180 use spatializer flag at audio HAL when available
- if (flags == (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_FAST
- | AUDIO_OUTPUT_FLAG_DEEP_BUFFER)) {
-#ifdef MULTICHANNEL_EFFECT_CHAIN
+ if (flags & AUDIO_OUTPUT_FLAG_SPATIALIZER) {
thread = new SpatializerThread(this, outputStream, *output,
mSystemReady, mixerConfig);
- ALOGD("openOutput_l() created spatializer output: ID %d thread %p",
+ ALOGV("openOutput_l() created spatializer output: ID %d thread %p",
*output, thread.get());
-#else
- ALOGE("openOutput_l() cannot create spatializer thread "
- "without #define MULTICHANNEL_EFFECT_CHAIN");
-#endif
} else if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
thread = new OffloadThread(this, outputStream, *output, mSystemReady);
ALOGV("openOutput_l() created offload output: ID %d thread %p",
@@ -2683,7 +2701,7 @@
}
}
- return 0;
+ return nullptr;
}
status_t AudioFlinger::openOutput(const media::OpenOutputRequest& request,
@@ -3987,6 +4005,12 @@
Register:
if (!probe && (lStatus == NO_ERROR || lStatus == ALREADY_EXISTS)) {
+ if (lStatus == ALREADY_EXISTS) {
+ response->alreadyExists = true;
+ lStatus = NO_ERROR;
+ } else {
+ response->alreadyExists = false;
+ }
// Check CPU and memory usage
sp<EffectBase> effect = handle->effect().promote();
if (effect != nullptr) {
@@ -4079,6 +4103,7 @@
// so that a new chain is created with correct parameters when first effect is added. This is
// otherwise unnecessary as removeEffect_l() will remove the chain when last effect is
// removed.
+ // TODO(b/216875016): consider holding the effect chain locks for the duration of the move.
srcThread->removeEffectChain_l(chain);
// transfer all effects one by one so that new effect chain is created on new thread with
@@ -4087,24 +4112,24 @@
sp<EffectModule> effect = chain->getEffectFromId_l(0);
Vector< sp<EffectModule> > removed;
status_t status = NO_ERROR;
- while (effect != 0) {
+ std::string errorString;
+ while (effect != nullptr) {
srcThread->removeEffect_l(effect);
removed.add(effect);
status = dstThread->addEffect_l(effect);
if (status != NO_ERROR) {
+ errorString = StringPrintf(
+ "cannot add effect %p to destination thread", effect.get());
break;
}
- // removeEffect_l() has stopped the effect if it was active so it must be restarted
- if (effect->state() == EffectModule::ACTIVE ||
- effect->state() == EffectModule::STOPPING) {
- effect->start();
- }
// if the move request is not received from audio policy manager, the effect must be
- // re-registered with the new strategy and output
- if (dstChain == 0) {
+ // re-registered with the new strategy and output.
+
+ // We obtain the dstChain once the effect is on the new thread.
+ if (dstChain == nullptr) {
dstChain = effect->getCallback()->chain().promote();
- if (dstChain == 0) {
- ALOGW("moveEffectChain_l() cannot get chain from effect %p", effect.get());
+ if (dstChain == nullptr) {
+ errorString = StringPrintf("cannot get chain from effect %p", effect.get());
status = NO_INIT;
break;
}
@@ -4112,12 +4137,53 @@
effect = chain->getEffectFromId_l(0);
}
+ size_t restored = 0;
if (status != NO_ERROR) {
- for (size_t i = 0; i < removed.size(); i++) {
- srcThread->addEffect_l(removed[i]);
+ dstChain.clear(); // dstChain is now from the srcThread (could be recreated).
+ for (const auto& effect : removed) {
+ dstThread->removeEffect_l(effect); // Note: Depending on error location, the last
+ // effect may not have been placed on dstThread.
+ if (srcThread->addEffect_l(effect) == NO_ERROR) {
+ ++restored;
+ if (dstChain == nullptr) {
+ dstChain = effect->getCallback()->chain().promote();
+ }
+ }
}
}
+ // After all the effects have been moved to new thread (or put back) we restart the effects
+ // because removeEffect_l() has stopped the effect if it is currently active.
+ size_t started = 0;
+ if (dstChain != nullptr && !removed.empty()) {
+ // If we do not take the dstChain lock, it is possible that processing is ongoing
+ // while we are starting the effect. This can cause glitches with volume,
+ // see b/202360137.
+ dstChain->lock();
+ for (const auto& effect : removed) {
+ if (effect->state() == EffectModule::ACTIVE ||
+ effect->state() == EffectModule::STOPPING) {
+ ++started;
+ effect->start();
+ }
+ }
+ dstChain->unlock();
+ }
+
+ if (status != NO_ERROR) {
+ if (errorString.empty()) {
+ errorString = StringPrintf("%s: failed status %d", __func__, status);
+ }
+ ALOGW("%s: %s unsuccessful move of session %d from srcThread %p to dstThread %p "
+ "(%zu effects removed from srcThread, %zu effects restored to srcThread, "
+ "%zu effects started)",
+ __func__, errorString.c_str(), sessionId, srcThread, dstThread,
+ removed.size(), restored, started);
+ } else {
+ ALOGD("%s: successful move of session %d from srcThread %p to dstThread %p "
+ "(%zu effects moved, %zu effects started)",
+ __func__, sessionId, srcThread, dstThread, removed.size(), started);
+ }
return status;
}
@@ -4283,6 +4349,7 @@
case TransactionCode::SET_AUDIO_PORT_CONFIG:
case TransactionCode::SET_RECORD_SILENCED:
case TransactionCode::AUDIO_POLICY_READY:
+ case TransactionCode::SET_DEVICE_CONNECTED_STATE:
ALOGW("%s: transaction %d received from PID %d",
__func__, code, IPCThreadState::self()->getCallingPid());
// return status only for non void methods
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 8c546cc..59f22eb 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -290,6 +290,8 @@
virtual int32_t getAAudioHardwareBurstMinUsec();
+ virtual status_t setDeviceConnectedState(const struct audio_port_v7 *port, bool connected);
+
status_t onTransactWrapper(TransactionCode code, const Parcel& data, uint32_t flags,
const std::function<status_t()>& delegate) override;
@@ -912,6 +914,7 @@
AUDIO_HW_SET_MASTER_MUTE, // set_master_mute
AUDIO_HW_GET_MASTER_MUTE, // get_master_mute
AUDIO_HW_GET_MICROPHONES, // getMicrophones
+ AUDIO_HW_SET_CONNECTED_STATE, // setConnectedState
};
mutable hardware_call_state mHardwareStatus; // for dump only
diff --git a/services/audioflinger/OWNERS b/services/audioflinger/OWNERS
index 034d161..17d4c37 100644
--- a/services/audioflinger/OWNERS
+++ b/services/audioflinger/OWNERS
@@ -1,4 +1,4 @@
-gkasten@google.com
hunga@google.com
jmtrivi@google.com
mnaganov@google.com
+philburk@google.com
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index dd278f0..ae5772d 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -2104,10 +2104,8 @@
void AudioFlinger::PlaybackThread::preExit()
{
ALOGV(" preExit()");
- // FIXME this is using hard-coded strings but in the future, this functionality will be
- // converted to use audio HAL extensions required to support tunneling
- status_t result = mOutput->stream->setParameters(String8("exiting=1"));
- ALOGE_IF(result != OK, "Error when setting parameters on exit: %d", result);
+ status_t result = mOutput->stream->exit();
+ ALOGE_IF(result != OK, "Error when calling exit(): %d", result);
}
void AudioFlinger::PlaybackThread::dumpTracks_l(int fd, const Vector<String16>& args __unused)
@@ -4585,19 +4583,7 @@
patch->sinks,
handle);
} else {
- char *address;
- if (strcmp(patch->sinks[0].ext.device.address, "") != 0) {
- //FIXME: we only support address on first sink with HAL version < 3.0
- address = audio_device_address_to_parameter(
- patch->sinks[0].ext.device.type,
- patch->sinks[0].ext.device.address);
- } else {
- address = (char *)calloc(1, 1);
- }
- AudioParameter param = AudioParameter(String8(address));
- free(address);
- param.addInt(String8(AudioParameter::keyRouting), (int)type);
- status = mOutput->stream->setParameters(param.toString());
+ status = mOutput->stream->legacyCreateAudioPatch(patch->sinks[0], std::nullopt, type);
*handle = AUDIO_PATCH_HANDLE_NONE;
}
const std::string patchSinksAsString = patchSinksToString(patch);
@@ -4642,9 +4628,7 @@
sp<DeviceHalInterface> hwDevice = mOutput->audioHwDev->hwDevice();
status = hwDevice->releaseAudioPatch(handle);
} else {
- AudioParameter param;
- param.addInt(String8(AudioParameter::keyRouting), 0);
- status = mOutput->stream->setParameters(param.toString());
+ status = mOutput->stream->legacyReleaseAudioPatch();
}
return status;
}
@@ -9130,21 +9114,9 @@
patch->sinks,
handle);
} else {
- char *address;
- if (strcmp(patch->sources[0].ext.device.address, "") != 0) {
- address = audio_device_address_to_parameter(
- patch->sources[0].ext.device.type,
- patch->sources[0].ext.device.address);
- } else {
- address = (char *)calloc(1, 1);
- }
- AudioParameter param = AudioParameter(String8(address));
- free(address);
- param.addInt(String8(AudioParameter::keyRouting),
- (int)patch->sources[0].ext.device.type);
- param.addInt(String8(AudioParameter::keyInputSource),
- (int)patch->sinks[0].ext.mix.usecase.source);
- status = mInput->stream->setParameters(param.toString());
+ status = mInput->stream->legacyCreateAudioPatch(patch->sources[0],
+ patch->sinks[0].ext.mix.usecase.source,
+ patch->sources[0].ext.device.type);
*handle = AUDIO_PATCH_HANDLE_NONE;
}
@@ -9176,9 +9148,7 @@
sp<DeviceHalInterface> hwDevice = mInput->audioHwDev->hwDevice();
status = hwDevice->releaseAudioPatch(handle);
} else {
- AudioParameter param;
- param.addInt(String8(AudioParameter::keyRouting), 0);
- status = mInput->stream->setParameters(param.toString());
+ status = mInput->stream->legacyReleaseAudioPatch();
}
return status;
}
@@ -9897,29 +9867,18 @@
}
if (mAudioHwDev->supportsAudioPatches()) {
- status = mHalDevice->createAudioPatch(patch->num_sources,
- patch->sources,
- patch->num_sinks,
- patch->sinks,
- handle);
+ status = mHalDevice->createAudioPatch(patch->num_sources, patch->sources, patch->num_sinks,
+ patch->sinks, handle);
} else {
- char *address;
- if (strcmp(patch->sinks[0].ext.device.address, "") != 0) {
- //FIXME: we only support address on first sink with HAL version < 3.0
- address = audio_device_address_to_parameter(
- patch->sinks[0].ext.device.type,
- patch->sinks[0].ext.device.address);
+ audio_port_config port;
+ std::optional<audio_source_t> source;
+ if (isOutput()) {
+ port = patch->sinks[0];
} else {
- address = (char *)calloc(1, 1);
+ port = patch->sources[0];
+ source = patch->sinks[0].ext.mix.usecase.source;
}
- AudioParameter param = AudioParameter(String8(address));
- free(address);
- param.addInt(String8(AudioParameter::keyRouting), (int)type);
- if (!isOutput()) {
- param.addInt(String8(AudioParameter::keyInputSource),
- (int)patch->sinks[0].ext.mix.usecase.source);
- }
- status = mHalStream->setParameters(param.toString());
+ status = mHalStream->legacyCreateAudioPatch(port, source, type);
*handle = AUDIO_PATCH_HANDLE_NONE;
}
@@ -9958,9 +9917,7 @@
if (supportsAudioPatches) {
status = mHalDevice->releaseAudioPatch(handle);
} else {
- AudioParameter param;
- param.addInt(String8(AudioParameter::keyRouting), 0);
- status = mHalStream->setParameters(param.toString());
+ status = mHalStream->legacyReleaseAudioPatch();
}
return status;
}
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 61537a8..982893d 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1864,6 +1864,8 @@
bool isTimestampCorrectionEnabled() const override {
// checks popcount for exactly one device.
+ // Is currently disabled. Before enabling,
+ // verify compressed record timestamps.
return audio_is_input_device(mTimestampCorrectedDevice)
&& inDeviceType() == mTimestampCorrectedDevice;
}
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index b582b3a..98a1bd9 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -108,7 +108,8 @@
audio_attributes_t attributes() const { return mAttr; }
bool canBeSpatialized() const { return mIsOut && (mAttr.flags
- & (AUDIO_FLAG_CONTENT_SPATIALIZED | AUDIO_FLAG_NEVER_SPATIALIZE)) == 0; }
+ & (AUDIO_FLAG_CONTENT_SPATIALIZED | AUDIO_FLAG_NEVER_SPATIALIZE)) == 0
+ && mChannelCount > 2; }
#ifdef TEE_SINK
void dumpTee(int fd, const std::string &reason) const {
diff --git a/services/audioflinger/TrackMetrics.h b/services/audioflinger/TrackMetrics.h
index 7fb69be..30d69ab 100644
--- a/services/audioflinger/TrackMetrics.h
+++ b/services/audioflinger/TrackMetrics.h
@@ -116,6 +116,21 @@
mDeviceStartupMs.add(startupMs);
}
+ void updateMinMaxVolume(int64_t durationNs, double deviceVolume) {
+ if (deviceVolume > mMaxVolume) {
+ mMaxVolume = deviceVolume;
+ mMaxVolumeDurationNs = durationNs;
+ } else if (deviceVolume == mMaxVolume) {
+ mMaxVolumeDurationNs += durationNs;
+ }
+ if (deviceVolume < mMinVolume) {
+ mMinVolume = deviceVolume;
+ mMinVolumeDurationNs = durationNs;
+ } else if (deviceVolume == mMinVolume) {
+ mMinVolumeDurationNs += durationNs;
+ }
+ }
+
// may be called multiple times during an interval
void logVolume(float volume) {
const int64_t timeNs = systemTime();
@@ -123,10 +138,13 @@
if (mStartVolumeTimeNs == 0) {
mDeviceVolume = mVolume = volume;
mLastVolumeChangeTimeNs = mStartVolumeTimeNs = timeNs;
+ updateMinMaxVolume(0, mVolume);
return;
}
+ const int64_t durationNs = timeNs - mLastVolumeChangeTimeNs;
+ updateMinMaxVolume(durationNs, mVolume);
mDeviceVolume = (mDeviceVolume * (mLastVolumeChangeTimeNs - mStartVolumeTimeNs) +
- mVolume * (timeNs - mLastVolumeChangeTimeNs)) / (timeNs - mStartVolumeTimeNs);
+ mVolume * durationNs) / (timeNs - mStartVolumeTimeNs);
mVolume = volume;
mLastVolumeChangeTimeNs = timeNs;
}
@@ -157,7 +175,11 @@
.set(AMEDIAMETRICS_PROP_EVENT, eventName)
.set(AMEDIAMETRICS_PROP_INTERVALCOUNT, (int32_t)mIntervalCount);
if (mIsOut) {
- item.set(AMEDIAMETRICS_PROP_DEVICEVOLUME, mDeviceVolume);
+ item.set(AMEDIAMETRICS_PROP_DEVICEVOLUME, mDeviceVolume)
+ .set(AMEDIAMETRICS_PROP_DEVICEMAXVOLUMEDURATIONNS, mMaxVolumeDurationNs)
+ .set(AMEDIAMETRICS_PROP_DEVICEMAXVOLUME, mMaxVolume)
+ .set(AMEDIAMETRICS_PROP_DEVICEMINVOLUMEDURATIONNS, mMinVolumeDurationNs)
+ .set(AMEDIAMETRICS_PROP_DEVICEMINVOLUME, mMinVolume);
}
if (mDeviceLatencyMs.getN() > 0) {
item.set(AMEDIAMETRICS_PROP_DEVICELATENCYMS, mDeviceLatencyMs.getMean())
@@ -185,6 +207,10 @@
mDeviceVolume = 0.f;
mStartVolumeTimeNs = 0;
mLastVolumeChangeTimeNs = 0;
+ mMinVolume = AMEDIAMETRICS_INITIAL_MIN_VOLUME;
+ mMaxVolume = AMEDIAMETRICS_INITIAL_MAX_VOLUME;
+ mMinVolumeDurationNs = 0;
+ mMaxVolumeDurationNs = 0;
mDeviceLatencyMs.reset();
mDeviceStartupMs.reset();
@@ -214,6 +240,12 @@
int64_t mStartVolumeTimeNs GUARDED_BY(mLock) = 0;
int64_t mLastVolumeChangeTimeNs GUARDED_BY(mLock) = 0;
+ // Min/Max volume
+ double mMinVolume GUARDED_BY(mLock) = AMEDIAMETRICS_INITIAL_MIN_VOLUME;
+ double mMaxVolume GUARDED_BY(mLock) = AMEDIAMETRICS_INITIAL_MAX_VOLUME;
+ int64_t mMinVolumeDurationNs GUARDED_BY(mLock) = 0;
+ int64_t mMaxVolumeDurationNs GUARDED_BY(mLock) = 0;
+
// latency and startup for each interval.
audio_utils::Statistics<double> mDeviceLatencyMs GUARDED_BY(mLock);
audio_utils::Statistics<double> mDeviceStartupMs GUARDED_BY(mLock);
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 233865f..279ff3d 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -2635,6 +2635,8 @@
// ALOGD("FrameTime: %lld %lld", (long long)ft.frames, (long long)ft.timeNs);
mKernelFrameTime.store(ft);
if (!audio_is_linear_pcm(mFormat)) {
+ // Stream is direct, return provided timestamp with no conversion
+ mServerProxy->setTimestamp(timestamp);
return;
}
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index f6f3b9a..5b2b87e 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -105,10 +105,8 @@
virtual void onNewAudioModulesAvailable() = 0;
// indicate a change in device connection status
- virtual status_t setDeviceConnectionState(audio_devices_t device,
- audio_policy_dev_state_t state,
- const char *device_address,
- const char *device_name,
+ virtual status_t setDeviceConnectionState(audio_policy_dev_state_t state,
+ const android::media::audio::common::AudioPort& port,
audio_format_t encodedFormat) = 0;
// retrieve a device connection status
virtual audio_policy_dev_state_t getDeviceConnectionState(audio_devices_t device,
@@ -300,6 +298,8 @@
virtual bool isHapticPlaybackSupported() = 0;
+ virtual bool isUltrasoundSupported() = 0;
+
virtual status_t getHwOffloadFormatsSupportedForBluetoothMedia(
audio_devices_t device, std::vector<audio_format_t> *formats) = 0;
@@ -404,8 +404,11 @@
*/
virtual audio_direct_mode_t getDirectPlaybackSupport(const audio_attributes_t *attr,
const audio_config_t *config) = 0;
-};
+ // retrieves the list of available direct audio profiles for the given audio attributes
+ virtual status_t getDirectProfilesForAttributes(const audio_attributes_t* attr,
+ AudioProfileVector& audioProfiles) = 0;
+};
// Audio Policy client Interface
class AudioPolicyClientInterface
@@ -541,6 +544,8 @@
virtual status_t updateSecondaryOutputs(
const TrackSecondaryOutputsMap& trackSecondaryOutputs) = 0;
+
+ virtual status_t setDeviceConnectedState(const struct audio_port_v7 *port, bool connected) = 0;
};
// These are the signatures of createAudioPolicyManager/destroyAudioPolicyManager
diff --git a/services/audiopolicy/common/include/Volume.h b/services/audiopolicy/common/include/Volume.h
index 736f8b2..f0636a0 100644
--- a/services/audiopolicy/common/include/Volume.h
+++ b/services/audiopolicy/common/include/Volume.h
@@ -127,6 +127,7 @@
case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
case AUDIO_DEVICE_OUT_USB_HEADSET:
case AUDIO_DEVICE_OUT_BLE_HEADSET:
+ case AUDIO_DEVICE_OUT_BLE_BROADCAST:
return DEVICE_CATEGORY_HEADSET;
case AUDIO_DEVICE_OUT_HEARING_AID:
return DEVICE_CATEGORY_HEARING_AID;
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 577f641..3d3e0cf 100644
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -133,6 +133,7 @@
* - AUDIO_SOURCE_FM_TUNER
* - AUDIO_SOURCE_VOICE_RECOGNITION
* - AUDIO_SOURCE_HOTWORD
+ * - AUDIO_SOURCE_ULTRASOUND
*
* @return the corresponding input source priority or 0 if priority is irrelevant for this source.
* This happens when the specified source cannot share a given input stream (e.g remote submix)
@@ -142,22 +143,24 @@
{
switch (inputSource) {
case AUDIO_SOURCE_VOICE_COMMUNICATION:
- return 9;
+ return 10;
case AUDIO_SOURCE_CAMCORDER:
- return 8;
+ return 9;
case AUDIO_SOURCE_VOICE_PERFORMANCE:
- return 7;
+ return 8;
case AUDIO_SOURCE_UNPROCESSED:
- return 6;
+ return 7;
case AUDIO_SOURCE_MIC:
- return 5;
+ return 6;
case AUDIO_SOURCE_ECHO_REFERENCE:
- return 4;
+ return 5;
case AUDIO_SOURCE_FM_TUNER:
- return 3;
+ return 4;
case AUDIO_SOURCE_VOICE_RECOGNITION:
- return 2;
+ return 3;
case AUDIO_SOURCE_HOTWORD:
+ return 2;
+ case AUDIO_SOURCE_ULTRASOUND:
return 1;
default:
break;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
index a8fd856..cf1f64c 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -202,20 +202,6 @@
{AUDIO_FORMAT_AC4, {}}};
}
- //TODO: b/193496180 use spatializer flag at audio HAL when available
- // until then, use DEEP_BUFFER+FAST flag combo to indicate the spatializer output profile
- void convertSpatializerFlag()
- {
- for (const auto& hwModule : mHwModules) {
- for (const auto& curProfile : hwModule->getOutputProfiles()) {
- if (curProfile->getFlags()
- == (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_DEEP_BUFFER)) {
- curProfile->setFlags(AUDIO_OUTPUT_FLAG_SPATIALIZER);
- }
- }
- }
- }
-
private:
static const constexpr char* const kDefaultEngineLibraryNameSuffix = "default";
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 235e4aa..663c80a 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -565,10 +565,11 @@
mFlags = (audio_output_flags_t)(mFlags | flags);
- //TODO: b/193496180 use spatializer flag at audio HAL when available
- audio_output_flags_t halFlags = mFlags;
- if ((mFlags & AUDIO_OUTPUT_FLAG_SPATIALIZER) != 0) {
- halFlags = (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_DEEP_BUFFER);
+ // If no mixer config is specified for a spatializer output, default to 5.1 for proper
+ // configuration of the final downmixer or spatializer
+ if ((mFlags & AUDIO_OUTPUT_FLAG_SPATIALIZER) != 0
+ && mixerConfig == nullptr) {
+ lMixerConfig.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
}
ALOGV("opening output for device %s profile %p name %s",
@@ -580,7 +581,7 @@
&lMixerConfig,
device,
&mLatency,
- halFlags);
+ mFlags);
if (status == NO_ERROR) {
LOG_ALWAYS_FATAL_IF(*output == AUDIO_IO_HANDLE_NONE,
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index 4dfef73..d446e96 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -483,7 +483,14 @@
if (!flags.empty()) {
// Source role
if (portRole == AUDIO_PORT_ROLE_SOURCE) {
- mixPort->setFlags(OutputFlagConverter::maskFromString(flags, mFlagsSeparator.c_str()));
+ //TODO: b/193496180 use spatializer flag at audio HAL when available until then,
+ // use DEEP_BUFFER+FAST flag combo to indicate the spatializer output profile
+ uint32_t intFlags =
+ OutputFlagConverter::maskFromString(flags, mFlagsSeparator.c_str());
+ if (intFlags == (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_DEEP_BUFFER)) {
+ intFlags = AUDIO_OUTPUT_FLAG_SPATIALIZER;
+ }
+ mixPort->setFlags(intFlags);
} else {
// Sink role
mixPort->setFlags(InputFlagConverter::maskFromString(flags, mFlagsSeparator.c_str()));
@@ -869,10 +876,10 @@
ALOGE("%s: No version found in root node %s", __func__, rootName);
return BAD_VALUE;
}
- if (version == "7.0") {
+ if (version == "7.0" || version == "7.1") {
mChannelMasksSeparator = mSamplingRatesSeparator = mFlagsSeparator = " ";
} else if (version != "1.0") {
- ALOGE("%s: Version does not match; expected \"1.0\" or \"7.0\" got \"%s\"",
+ ALOGE("%s: Version does not match; expected \"1.0\", \"7.0\", or \"7.1\" got \"%s\"",
__func__, version.c_str());
return BAD_VALUE;
}
diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp
index 150a9a8..7a06206 100644
--- a/services/audiopolicy/engine/common/src/EngineBase.cpp
+++ b/services/audiopolicy/engine/common/src/EngineBase.cpp
@@ -71,7 +71,10 @@
audio_policy_dev_state_t state)
{
audio_devices_t deviceType = devDesc->type();
- if ((deviceType != AUDIO_DEVICE_NONE) && audio_is_output_device(deviceType)) {
+ if ((deviceType != AUDIO_DEVICE_NONE) && audio_is_output_device(deviceType)
+ && deviceType != AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) {
+ // USB dock does not follow the rule of last removable device connected wins.
+ // It is only used if no removable device is connected or if set as preferred device
mLastRemovableMediaDevices.setRemovableMediaDevices(devDesc, state);
}
diff --git a/services/audiopolicy/engine/common/src/EngineDefaultConfig.h b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
index 665c2dd..b036e12 100644
--- a/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
+++ b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
@@ -122,8 +122,12 @@
{"STRATEGY_TRANSMITTED_THROUGH_SPEAKER",
{
{"", AUDIO_STREAM_TTS, "AUDIO_STREAM_TTS",
- {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT,
- AUDIO_FLAG_BEACON, ""}}
+ {
+ {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT,
+ AUDIO_FLAG_BEACON, ""},
+ {AUDIO_CONTENT_TYPE_ULTRASOUND, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT,
+ AUDIO_FLAG_NONE, ""}
+ }
}
},
}
diff --git a/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp b/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
index b3f8947..06cc799 100644
--- a/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
+++ b/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
@@ -85,6 +85,7 @@
case AUDIO_DEVICE_OUT_HEARING_AID:
case AUDIO_DEVICE_OUT_BLE_HEADSET:
case AUDIO_DEVICE_OUT_BLE_SPEAKER:
+ case AUDIO_DEVICE_OUT_BLE_BROADCAST:
return GROUP_BT_A2DP;
default:
return GROUP_NONE;
diff --git a/services/audiopolicy/engineconfigurable/src/InputSource.cpp b/services/audiopolicy/engineconfigurable/src/InputSource.cpp
index 5779c00..6fd2b70 100644
--- a/services/audiopolicy/engineconfigurable/src/InputSource.cpp
+++ b/services/audiopolicy/engineconfigurable/src/InputSource.cpp
@@ -26,7 +26,8 @@
status_t Element<audio_source_t>::setIdentifier(audio_source_t identifier)
{
if (identifier > AUDIO_SOURCE_MAX && identifier != AUDIO_SOURCE_HOTWORD
- && identifier != AUDIO_SOURCE_FM_TUNER && identifier != AUDIO_SOURCE_ECHO_REFERENCE) {
+ && identifier != AUDIO_SOURCE_FM_TUNER && identifier != AUDIO_SOURCE_ECHO_REFERENCE
+ && identifier != AUDIO_SOURCE_ULTRASOUND) {
return BAD_VALUE;
}
mIdentifier = identifier;
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index c73c17d..dc34a38 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -272,7 +272,8 @@
devices = availableOutputDevices.getFirstDevicesFromTypes(
getLastRemovableMediaDevices());
if (!devices.isEmpty()) break;
- devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_EARPIECE);
+ devices = availableOutputDevices.getFirstDevicesFromTypes({
+ AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_EARPIECE});
} break;
case STRATEGY_SONIFICATION:
@@ -364,7 +365,8 @@
AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET);
}
if (devices2.isEmpty()) {
- devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
+ devices2 = availableOutputDevices.getFirstDevicesFromTypes({
+ AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_SPEAKER});
}
DeviceVector devices3;
if (strategy == STRATEGY_MEDIA) {
@@ -460,6 +462,7 @@
case AUDIO_SOURCE_HOTWORD:
case AUDIO_SOURCE_CAMCORDER:
case AUDIO_SOURCE_VOICE_PERFORMANCE:
+ case AUDIO_SOURCE_ULTRASOUND:
inputSource = AUDIO_SOURCE_VOICE_COMMUNICATION;
break;
default:
@@ -586,6 +589,10 @@
device = availableDevices.getDevice(
AUDIO_DEVICE_IN_ECHO_REFERENCE, String8(""), AUDIO_FORMAT_DEFAULT);
break;
+ case AUDIO_SOURCE_ULTRASOUND:
+ device = availableDevices.getFirstExistingDevice({
+ AUDIO_DEVICE_IN_BUILTIN_MIC, AUDIO_DEVICE_IN_BACK_MIC});
+ break;
default:
ALOGW("getDeviceForInputSource() invalid input source %d", inputSource);
break;
@@ -645,7 +652,7 @@
// there is a preferred device, is it available?
preferredAvailableDevVec =
availableOutputDevices.getDevicesFromDeviceTypeAddrVec(preferredStrategyDevices);
- if (preferredAvailableDevVec.size() == preferredAvailableDevVec.size()) {
+ if (preferredAvailableDevVec.size() == preferredStrategyDevices.size()) {
ALOGVV("%s using pref device %s for strategy %u",
__func__, preferredAvailableDevVec.toString().c_str(), strategy);
return preferredAvailableDevVec;
diff --git a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
index 654e4bf..7c6907d 100644
--- a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
+++ b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
@@ -30,6 +30,7 @@
#include <libxml/parser.h>
#include <libxml/xinclude.h>
#include <media/AudioPolicy.h>
+#include <media/AudioProfile.h>
#include <media/PatchBuilder.h>
#include <media/RecordingActivityTracker.h>
@@ -126,13 +127,20 @@
return result;
}();
+/**
+ * AudioSource - AUDIO_SOURCE_VOICE_COMMUNICATION and AUDIO_SOURCE_HOTWORD
+ * are excluded from kAudioSources[] in order to avoid the abort triggered
+ * for these two types of AudioSource in Engine::getDeviceForInputSource()
+ */
static const std::vector<audio_source_t> kAudioSources = [] {
std::vector<audio_source_t> result;
for (const auto enumVal : xsdc_enum_range<xsd::AudioSource>{}) {
audio_source_t audioSourceHal;
std::string audioSource = toString(enumVal);
- if (audio_source_from_string(audioSource.c_str(), &audioSourceHal)) {
- result.push_back(audioSourceHal);
+ if (enumVal != xsd::AudioSource::AUDIO_SOURCE_VOICE_COMMUNICATION &&
+ enumVal != xsd::AudioSource::AUDIO_SOURCE_HOTWORD &&
+ audio_source_from_string(audioSource.c_str(), &audioSourceHal)) {
+ result.push_back(audioSourceHal);
}
}
return result;
@@ -842,6 +850,7 @@
void process() override;
void fuzzGetDirectPlaybackSupport();
+ void fuzzGetDirectProfilesForAttributes();
protected:
void setDeviceConnectionState();
@@ -909,11 +918,25 @@
}
}
+void AudioPolicyManagerFuzzerDeviceConnection::fuzzGetDirectProfilesForAttributes() {
+ const uint32_t numTestCases = mFdp->ConsumeIntegralInRange<uint32_t>(1, 10);
+ for (int i = 0; i < numTestCases; ++i) {
+ AudioProfileVector audioProfiles;
+ audio_attributes_t attr = AUDIO_ATTRIBUTES_INITIALIZER;
+ attr.content_type = getValueFromVector<audio_content_type_t>(mFdp, kAudioContentTypes);
+ attr.usage = getValueFromVector<audio_usage_t>(mFdp, kAudioUsages);
+ attr.source = getValueFromVector<audio_source_t>(mFdp, kAudioSources);
+ attr.flags = getValueFromVector<audio_flags_mask_t>(mFdp, kAudioFlagMasks);
+ mManager->getDirectProfilesForAttributes(&attr, audioProfiles);
+ }
+}
+
void AudioPolicyManagerFuzzerDeviceConnection::process() {
if (initialize()) {
setDeviceConnectionState();
explicitlyRoutingAfterConnection();
fuzzGetDirectPlaybackSupport();
+ fuzzGetDirectProfilesForAttributes();
fuzzPatchCreation();
}
}
diff --git a/services/audiopolicy/managerdefault/Android.bp b/services/audiopolicy/managerdefault/Android.bp
index 0165dc8..4b4817e 100644
--- a/services/audiopolicy/managerdefault/Android.bp
+++ b/services/audiopolicy/managerdefault/Android.bp
@@ -36,6 +36,8 @@
"libaudiopolicyenginedefault",
"framework-permission-aidl-cpp",
"libaudioclient_aidl_conversion",
+ "android.media.audio.common.types-V1-cpp",
+ "audioclient-types-aidl-cpp",
],
header_libs: [
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index fc6e05e..cc36c08 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -38,6 +38,7 @@
#include <vector>
#include <Serializer.h>
+#include <android/media/audio/common/AudioPort.h>
#include <cutils/bitops.h>
#include <cutils/properties.h>
#include <media/AudioParameter.h>
@@ -53,6 +54,10 @@
namespace android {
+using android::media::audio::common::AudioDevice;
+using android::media::audio::common::AudioDeviceAddress;
+using android::media::audio::common::AudioPortDeviceExt;
+using android::media::audio::common::AudioPortExt;
using content::AttributionSourceState;
//FIXME: workaround for truncated touch sounds
@@ -97,44 +102,80 @@
// AudioPolicyInterface implementation
// ----------------------------------------------------------------------------
-status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device,
- audio_policy_dev_state_t state,
- const char *device_address,
- const char *device_name,
- audio_format_t encodedFormat)
-{
- status_t status = setDeviceConnectionStateInt(device, state, device_address,
- device_name, encodedFormat);
+status_t AudioPolicyManager::setDeviceConnectionState(audio_policy_dev_state_t state,
+ const android::media::audio::common::AudioPort& port, audio_format_t encodedFormat) {
+ status_t status = setDeviceConnectionStateInt(state, port, encodedFormat);
nextAudioPortGeneration();
return status;
}
+status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device,
+ audio_policy_dev_state_t state,
+ const char* device_address,
+ const char* device_name,
+ audio_format_t encodedFormat) {
+ media::AudioPort aidlPort;
+ if (status_t status = deviceToAudioPort(device, device_address, device_name, &aidlPort);
+ status == OK) {
+ return setDeviceConnectionState(state, aidlPort.hal, encodedFormat);
+ } else {
+ ALOGE("Failed to convert to AudioPort Parcelable: %s", statusToString(status).c_str());
+ return status;
+ }
+}
+
void AudioPolicyManager::broadcastDeviceConnectionState(const sp<DeviceDescriptor> &device,
audio_policy_dev_state_t state)
{
- AudioParameter param(String8(device->address().c_str()));
- const String8 key(state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE ?
- AudioParameter::keyDeviceConnect : AudioParameter::keyDeviceDisconnect);
- param.addInt(key, device->type());
- mpClientInterface->setParameters(AUDIO_IO_HANDLE_NONE, param.toString());
+ audio_port_v7 devicePort;
+ device->toAudioPort(&devicePort);
+ if (status_t status = mpClientInterface->setDeviceConnectedState(
+ &devicePort, state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
+ status != OK) {
+ ALOGE("Error %d while setting connected state for device %s", status,
+ device->getDeviceTypeAddr().toString(false).c_str());
+ }
+}
+
+status_t AudioPolicyManager::setDeviceConnectionStateInt(
+ audio_policy_dev_state_t state, const android::media::audio::common::AudioPort& port,
+ audio_format_t encodedFormat) {
+ // TODO: b/211601178 Forward 'port' to Audio HAL via mHwModules. For now, only device_type,
+ // device_address and device_name are forwarded.
+ if (port.ext.getTag() != AudioPortExt::device) {
+ return BAD_VALUE;
+ }
+ audio_devices_t device_type;
+ std::string device_address;
+ if (status_t status = aidl2legacy_AudioDevice_audio_device(
+ port.ext.get<AudioPortExt::device>().device, &device_type, &device_address);
+ status != OK) {
+ return status;
+ };
+ const char* device_name = port.name.c_str();
+ // connect/disconnect only 1 device at a time
+ if (!audio_is_output_device(device_type) && !audio_is_input_device(device_type))
+ return BAD_VALUE;
+
+ sp<DeviceDescriptor> device = mHwModules.getDeviceDescriptor(
+ device_type, device_address.c_str(), device_name, encodedFormat,
+ state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
+ return device ? setDeviceConnectionStateInt(device, state) : INVALID_OPERATION;
}
status_t AudioPolicyManager::setDeviceConnectionStateInt(audio_devices_t deviceType,
audio_policy_dev_state_t state,
- const char *device_address,
- const char *device_name,
- audio_format_t encodedFormat)
-{
- ALOGV("setDeviceConnectionStateInt() device: 0x%X, state %d, address %s name %s format 0x%X",
- deviceType, state, device_address, device_name, encodedFormat);
-
- // connect/disconnect only 1 device at a time
- if (!audio_is_output_device(deviceType) && !audio_is_input_device(deviceType)) return BAD_VALUE;
-
- sp<DeviceDescriptor> device =
- mHwModules.getDeviceDescriptor(deviceType, device_address, device_name, encodedFormat,
- state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
- return device ? setDeviceConnectionStateInt(device, state) : INVALID_OPERATION;
+ const char* device_address,
+ const char* device_name,
+ audio_format_t encodedFormat) {
+ media::AudioPort aidlPort;
+ if (status_t status = deviceToAudioPort(deviceType, device_address, device_name, &aidlPort);
+ status == OK) {
+ return setDeviceConnectionStateInt(state, aidlPort.hal, encodedFormat);
+ } else {
+ ALOGE("Failed to convert to AudioPort Parcelable: %s", statusToString(status).c_str());
+ return status;
+ }
}
status_t AudioPolicyManager::setDeviceConnectionStateInt(const sp<DeviceDescriptor> &device,
@@ -399,6 +440,14 @@
return BAD_VALUE;
}
+status_t AudioPolicyManager::deviceToAudioPort(audio_devices_t device, const char* device_address,
+ const char* device_name,
+ media::AudioPort* aidlPort) {
+ DeviceDescriptorBase devDescr(device, device_address);
+ devDescr.setName(device_name);
+ return devDescr.writeToParcelable(aidlPort);
+}
+
void AudioPolicyManager::setEngineDeviceConnectionState(const sp<DeviceDescriptor> device,
audio_policy_dev_state_t state) {
@@ -1386,8 +1435,14 @@
ALOGV("Set VoIP and Direct output flags for PCM format");
}
+ // Attach the Ultrasound flag for the AUDIO_CONTENT_TYPE_ULTRASOUND
+ if (attr->content_type == AUDIO_CONTENT_TYPE_ULTRASOUND) {
+ *flags = (audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_ULTRASOUND);
+ }
+
if (mSpatializerOutput != nullptr
- && canBeSpatialized(attr, config, devices.toTypeAddrVector())) {
+ && canBeSpatializedInt(attr, config,
+ devices.toTypeAddrVector(), false /* allowCurrentOutputReconfig */)) {
return mSpatializerOutput->mIoHandle;
}
@@ -1683,7 +1738,8 @@
// other criteria
static const audio_output_flags_t kFunctionalFlags = (audio_output_flags_t)
(AUDIO_OUTPUT_FLAG_VOIP_RX | AUDIO_OUTPUT_FLAG_INCALL_MUSIC |
- AUDIO_OUTPUT_FLAG_TTS | AUDIO_OUTPUT_FLAG_DIRECT_PCM);
+ AUDIO_OUTPUT_FLAG_TTS | AUDIO_OUTPUT_FLAG_DIRECT_PCM | AUDIO_OUTPUT_FLAG_ULTRASOUND |
+ AUDIO_OUTPUT_FLAG_SPATIALIZER);
// Flags expressing a performance request: have lower priority than serving
// requested sampling rate or channel mask
static const audio_output_flags_t kPerformanceFlags = (audio_output_flags_t)
@@ -2371,6 +2427,10 @@
flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_VOIP_TX);
}
+ if (attributes.source == AUDIO_SOURCE_ULTRASOUND) {
+ flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_ULTRASOUND);
+ }
+
// find a compatible input profile (not necessarily identical in parameters)
sp<IOProfile> profile;
// sampling rate and flags may be updated by getInputProfile
@@ -2387,7 +2447,7 @@
break; // success
} else if (profileFlags & AUDIO_INPUT_FLAG_RAW) {
profileFlags = (audio_input_flags_t) (profileFlags & ~AUDIO_INPUT_FLAG_RAW); // retry
- } else if (profileFlags != AUDIO_INPUT_FLAG_NONE) {
+ } else if (profileFlags != AUDIO_INPUT_FLAG_NONE && audio_is_linear_pcm(config->format)) {
profileFlags = AUDIO_INPUT_FLAG_NONE; // retry
} else { // fail
ALOGW("%s could not find profile for device %s, sampling rate %u, format %#x, "
@@ -3822,6 +3882,47 @@
return directMode;
}
+status_t AudioPolicyManager::getDirectProfilesForAttributes(const audio_attributes_t* attr,
+ AudioProfileVector& audioProfilesVector) {
+ AudioDeviceTypeAddrVector devices;
+ status_t status = getDevicesForAttributes(*attr, &devices);
+ if (status != OK) {
+ return status;
+ }
+ ALOGV("%s: found %zu output devices for attributes.", __func__, devices.size());
+ if (devices.empty()) {
+ return OK; // no output devices for the attributes
+ }
+
+ for (const auto& hwModule : mHwModules) {
+ for (const auto& curProfile : hwModule->getOutputProfiles()) {
+ if (!curProfile->asAudioPort()->isDirectOutput()) {
+ continue;
+ }
+ // Allow only profiles that support all the available and routed devices
+ DeviceVector supportedDevices = curProfile->getSupportedDevices();
+ if (supportedDevices.getDevicesFromDeviceTypeAddrVec(devices).size()
+ != devices.size()) {
+ continue;
+ }
+
+ const auto audioProfiles = curProfile->asAudioPort()->getAudioProfiles();
+ ALOGV("%s: found direct profile (%s) with %zu audio profiles.",
+ __func__, curProfile->getTagName().c_str(), audioProfiles.size());
+ for (const auto& audioProfile : audioProfiles) {
+ if (audioProfile->isValid() && !audioProfilesVector.contains(audioProfile)
+ // TODO - why do we have same PCM format with both dynamic and non dynamic format
+ && audioProfile->isDynamicFormat()) {
+ ALOGV("%s: adding audio profile with encoding (%d).",
+ __func__, audioProfile->getFormat());
+ audioProfilesVector.add(audioProfile);
+ }
+ }
+ }
+ }
+ return NO_ERROR;
+}
+
status_t AudioPolicyManager::listAudioPorts(audio_port_role_t role,
audio_port_type_t type,
unsigned int *num_ports,
@@ -4881,6 +4982,37 @@
return false;
}
+bool AudioPolicyManager::isUltrasoundSupported()
+{
+ bool hasUltrasoundOutput = false;
+ bool hasUltrasoundInput = false;
+ for (const auto& hwModule : mHwModules) {
+ const OutputProfileCollection &outputProfiles = hwModule->getOutputProfiles();
+ if (!hasUltrasoundOutput) {
+ for (const auto &outProfile : outputProfiles) {
+ if (outProfile->getFlags() & AUDIO_OUTPUT_FLAG_ULTRASOUND) {
+ hasUltrasoundOutput = true;
+ break;
+ }
+ }
+ }
+
+ const InputProfileCollection &inputProfiles = hwModule->getInputProfiles();
+ if (!hasUltrasoundInput) {
+ for (const auto &inputProfile : inputProfiles) {
+ if (inputProfile->getFlags() & AUDIO_INPUT_FLAG_ULTRASOUND) {
+ hasUltrasoundInput = true;
+ break;
+ }
+ }
+ }
+
+ if (hasUltrasoundOutput && hasUltrasoundInput)
+ return true;
+ }
+ return false;
+}
+
bool AudioPolicyManager::isCallScreenModeSupported()
{
return getConfig().isCallScreenModeSupported();
@@ -4949,9 +5081,10 @@
}
}
-bool AudioPolicyManager::canBeSpatialized(const audio_attributes_t *attr,
+bool AudioPolicyManager::canBeSpatializedInt(const audio_attributes_t *attr,
const audio_config_t *config,
- const AudioDeviceTypeAddrVector &devices) const
+ const AudioDeviceTypeAddrVector &devices,
+ bool allowCurrentOutputReconfig) const
{
// The caller can have the audio attributes criteria ignored by either passing a null ptr or
// the AUDIO_ATTRIBUTES_INITIALIZER value.
@@ -4987,7 +5120,8 @@
if (!isChannelMaskSpatialized(config->channel_mask)) {
return false;
}
- if (mSpatializerOutput != nullptr && mSpatializerOutput->mProfile == profile) {
+ if (!allowCurrentOutputReconfig && mSpatializerOutput != nullptr
+ && mSpatializerOutput->mProfile == profile) {
if ((config->channel_mask & mSpatializerOutput->mMixerChannelMask)
!= config->channel_mask) {
return false;
@@ -5008,7 +5142,8 @@
audio_config_base_t clientConfig = client->config();
audio_config_t config = audio_config_initializer(&clientConfig);
if (desc != mSpatializerOutput
- && canBeSpatialized(&attr, &config, devicesTypeAddress)) {
+ && canBeSpatializedInt(&attr, &config,
+ devicesTypeAddress, false /* allowCurrentOutputReconfig */)) {
streamsToInvalidate.insert(client->stream());
}
}
@@ -5032,7 +5167,8 @@
config = audio_config_initializer(mixerConfig);
configPtr = &config;
}
- if (!canBeSpatialized(attr, configPtr, devicesTypeAddress)) {
+ if (!canBeSpatializedInt(
+ attr, configPtr, devicesTypeAddress)) {
ALOGW("%s provided attributes or mixer config cannot be spatialized", __func__);
return BAD_VALUE;
}
@@ -5055,6 +5191,7 @@
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
if (!desc->isDuplicated() && desc->mProfile == profile) {
+ ALOGV("%s found output %d for spatializer profile", __func__, desc->mIoHandle);
mSpatializerOutput = desc;
break;
}
@@ -5074,39 +5211,29 @@
};
DeviceVector savedDevices = mSpatializerOutput->devices();
- closeOutput(mSpatializerOutput->mIoHandle);
- mSpatializerOutput.clear();
+ ALOGV("%s reopening spatializer output to match channel mask %#x (current mask %#x)",
+ __func__, configPtr->channel_mask, mSpatializerOutput->mMixerChannelMask);
- const sp<SwAudioOutputDescriptor> desc =
- new SwAudioOutputDescriptor(profile, mpClientInterface);
- status_t status = desc->open(nullptr, mixerConfig, devices,
- mEngine->getStreamTypeForAttributes(*attr),
- AUDIO_OUTPUT_FLAG_SPATIALIZER, output);
- if (status != NO_ERROR) {
- ALOGW("%s failed opening output: status %d, output %d", __func__, status, *output);
- if (*output != AUDIO_IO_HANDLE_NONE) {
- desc->close();
- }
+ closeOutput(mSpatializerOutput->mIoHandle);
+ //from now on mSpatializerOutput is null
+
+ sp<SwAudioOutputDescriptor> desc =
+ openOutputWithProfileAndDevice(profile, devices, mixerConfig);
+ if (desc == nullptr) {
// re open the spatializer output with previous channel mask
- status_t newStatus = desc->open(nullptr, &savedMixerConfig, savedDevices,
- mEngine->getStreamTypeForAttributes(*attr),
- AUDIO_OUTPUT_FLAG_SPATIALIZER, output);
- if (newStatus != NO_ERROR) {
- if (*output != AUDIO_IO_HANDLE_NONE) {
- desc->close();
- }
- ALOGE("%s failed to re-open mSpatializerOutput, status %d", __func__, newStatus);
+ desc = openOutputWithProfileAndDevice(profile, savedDevices, &savedMixerConfig);
+ if (desc == nullptr) {
+ ALOGE("%s failed to restore mSpatializerOutput with previous config", __func__);
} else {
mSpatializerOutput = desc;
- addOutput(*output, desc);
}
mPreviousOutputs = mOutputs;
mpClientInterface->onAudioPortListUpdate();
*output = AUDIO_IO_HANDLE_NONE;
- return status;
+ ALOGW("%s could not open spatializer output with requested config", __func__);
+ return BAD_VALUE;
}
mSpatializerOutput = desc;
- addOutput(*output, desc);
mPreviousOutputs = mOutputs;
mpClientInterface->onAudioPortListUpdate();
}
@@ -5182,8 +5309,6 @@
ALOGE("could not load audio policy configuration file, setting defaults");
getConfig().setDefault();
}
- //TODO: b/193496180 use spatializer flag at audio HAL when available
- getConfig().convertSpatializerFlag();
}
status_t AudioPolicyManager::initialize() {
@@ -5299,7 +5424,8 @@
ALOGW("Output profile contains no device on module %s", hwModule->getName());
continue;
}
- if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_TTS) != 0) {
+ if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_TTS) != 0 ||
+ (outProfile->getFlags() & AUDIO_OUTPUT_FLAG_ULTRASOUND) != 0) {
mTtsOutputAvailable = true;
}
@@ -5778,6 +5904,9 @@
removeOutput(output);
mPreviousOutputs = mOutputs;
+ if (closingOutput == mSpatializerOutput) {
+ mSpatializerOutput.clear();
+ }
// MSD patches may have been released to support a non-MSD direct output. Reset MSD patch if
// no direct outputs are open.
@@ -6297,6 +6426,7 @@
return devices.types();
}
+// TODO - consider MSD routes b/214971780
status_t AudioPolicyManager::getDevicesForAttributes(
const audio_attributes_t &attr, AudioDeviceTypeAddrVector *devices) {
if (devices == nullptr) {
@@ -7331,7 +7461,8 @@
}
sp<SwAudioOutputDescriptor> AudioPolicyManager::openOutputWithProfileAndDevice(
- const sp<IOProfile>& profile, const DeviceVector& devices)
+ const sp<IOProfile>& profile, const DeviceVector& devices,
+ const audio_config_base_t *mixerConfig)
{
for (const auto& device : devices) {
// TODO: This should be checking if the profile supports the device combo.
@@ -7341,7 +7472,7 @@
}
sp<SwAudioOutputDescriptor> desc = new SwAudioOutputDescriptor(profile, mpClientInterface);
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
- status_t status = desc->open(nullptr /* halConfig */, nullptr /* mixerConfig */, devices,
+ status_t status = desc->open(nullptr /* halConfig */, mixerConfig, devices,
AUDIO_STREAM_DEFAULT, AUDIO_OUTPUT_FLAG_NONE, &output);
if (status != NO_ERROR) {
return nullptr;
@@ -7371,7 +7502,7 @@
config.offload_info.channel_mask = config.channel_mask;
config.offload_info.format = config.format;
- status = desc->open(&config, nullptr /* mixerConfig */, devices,
+ status = desc->open(&config, mixerConfig, devices,
AUDIO_STREAM_DEFAULT, AUDIO_OUTPUT_FLAG_NONE, &output);
if (status != NO_ERROR) {
return nullptr;
@@ -7379,6 +7510,7 @@
}
addOutput(output, desc);
+
if (audio_is_remote_submix_device(deviceType) && address != "0") {
sp<AudioPolicyMix> policyMix;
if (mPolicyMixes.getAudioPolicyMix(deviceType, address, policyMix) == NO_ERROR) {
@@ -7389,9 +7521,13 @@
address.string());
}
- } else if (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) && hasPrimaryOutput()) {
- // no duplicated output for direct outputs and
- // outputs used by dynamic policy mixes
+ } else if (hasPrimaryOutput() && profile->getModule()
+ != mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY)
+ && ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0)) {
+ // no duplicated output for:
+ // - direct outputs
+ // - outputs used by dynamic policy mixes
+ // - outputs opened on the primary HW module
audio_io_handle_t duplicatedOutput = AUDIO_IO_HANDLE_NONE;
//TODO: configure audio effect output stage here
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index bdeba3d..a145c70 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -35,6 +35,7 @@
#include <media/PatchBuilder.h>
#include "AudioPolicyInterface.h"
+#include <android/media/audio/common/AudioPort.h>
#include <AudioPolicyManagerObserver.h>
#include <AudioPolicyConfig.h>
#include <PolicyAudioPort.h>
@@ -95,11 +96,8 @@
virtual ~AudioPolicyManager();
// AudioPolicyInterface
- virtual status_t setDeviceConnectionState(audio_devices_t device,
- audio_policy_dev_state_t state,
- const char *device_address,
- const char *device_name,
- audio_format_t encodedFormat);
+ virtual status_t setDeviceConnectionState(audio_policy_dev_state_t state,
+ const android::media::audio::common::AudioPort& port, audio_format_t encodedFormat);
virtual audio_policy_dev_state_t getDeviceConnectionState(audio_devices_t device,
const char *device_address);
virtual status_t handleDeviceConfigChange(audio_devices_t device,
@@ -327,6 +325,8 @@
virtual bool isHapticPlaybackSupported();
+ virtual bool isUltrasoundSupported();
+
virtual status_t listAudioProductStrategies(AudioProductStrategyVector &strategies)
{
return mEngine->listAudioProductStrategies(strategies);
@@ -358,7 +358,9 @@
virtual bool canBeSpatialized(const audio_attributes_t *attr,
const audio_config_t *config,
- const AudioDeviceTypeAddrVector &devices) const;
+ const AudioDeviceTypeAddrVector &devices) const {
+ return canBeSpatializedInt(attr, config, devices);
+ }
virtual status_t getSpatializerOutput(const audio_config_base_t *config,
const audio_attributes_t *attr,
@@ -369,6 +371,9 @@
virtual audio_direct_mode_t getDirectPlaybackSupport(const audio_attributes_t *attr,
const audio_config_t *config);
+ virtual status_t getDirectProfilesForAttributes(const audio_attributes_t* attr,
+ AudioProfileVector& audioProfiles);
+
bool isCallScreenModeSupported() override;
void onNewAudioModulesAvailable() override;
@@ -857,7 +862,8 @@
uint32_t mBeaconMuteRefCount; // ref count for stream that would mute beacon
uint32_t mBeaconPlayingRefCount;// ref count for the playing beacon streams
bool mBeaconMuted; // has STREAM_TTS been muted
- bool mTtsOutputAvailable; // true if a dedicated output for TTS stream is available
+ // true if a dedicated output for TTS stream or Ultrasound is available
+ bool mTtsOutputAvailable;
bool mMasterMono; // true if we wish to force all outputs to mono
AudioPolicyMixCollection mPolicyMixes; // list of registered mixes
@@ -903,6 +909,16 @@
PatchBuilder buildMsdPatch(bool msdIsSource, const sp<DeviceDescriptor> &device) const;
status_t setMsdOutputPatches(const DeviceVector *outputDevices = nullptr);
void releaseMsdOutputPatches(const DeviceVector& devices);
+
+ // Overload of setDeviceConnectionState()
+ status_t setDeviceConnectionState(audio_devices_t deviceType,
+ audio_policy_dev_state_t state,
+ const char* device_address, const char* device_name,
+ audio_format_t encodedFormat);
+
+ // Called by setDeviceConnectionState()
+ status_t deviceToAudioPort(audio_devices_t deviceType, const char* device_address,
+ const char* device_name, media::AudioPort* aidPort);
private:
void onNewAudioModulesAvailableInt(DeviceVector *newDevices);
@@ -964,6 +980,30 @@
const DeviceVector &devices,
audio_io_handle_t *output);
+ /**
+ * @brief Queries if some kind of spatialization will be performed if the audio playback
+ * context described by the provided arguments is present.
+ * The context is made of:
+ * - The audio attributes describing the playback use case.
+ * - The audio configuration describing the audio format, channels, sampling rate ...
+ * - The devices describing the sink audio device selected for playback.
+ * All arguments are optional and only the specified arguments are used to match against
+ * supported criteria. For instance, supplying no argument will tell if spatialization is
+ * supported or not in general.
+ * @param attr audio attributes describing the playback use case
+ * @param config audio configuration describing the audio format, channels, sample rate...
+ * @param devices the sink audio device selected for playback
+ * @param allowCurrentOutputReconfig if true, the result will be considering it is possible
+ * to close and reopen an existing spatializer output stream to match the requested
+ * criteria. If false, the criteria must be compatible with the opened sptializer
+ * output.
+ * @return true if spatialization is possible for this context, false otherwise.
+ */
+ virtual bool canBeSpatializedInt(const audio_attributes_t *attr,
+ const audio_config_t *config,
+ const AudioDeviceTypeAddrVector &devices,
+ bool allowCurrentOutputReconfig = true) const;
+
sp<IOProfile> getSpatializerOutputProfile(const audio_config_t *config,
const AudioDeviceTypeAddrVector &devices) const;
@@ -998,6 +1038,9 @@
bool isValidAttributes(const audio_attributes_t *paa);
// Called by setDeviceConnectionState().
+ status_t setDeviceConnectionStateInt(audio_policy_dev_state_t state,
+ const android::media::audio::common::AudioPort& port,
+ audio_format_t encodedFormat);
status_t setDeviceConnectionStateInt(audio_devices_t deviceType,
audio_policy_dev_state_t state,
const char *device_address,
@@ -1059,8 +1102,20 @@
bool areAllActiveTracksRerouted(const sp<SwAudioOutputDescriptor>& output);
- sp<SwAudioOutputDescriptor> openOutputWithProfileAndDevice(const sp<IOProfile>& profile,
- const DeviceVector& devices);
+ /**
+ * @brief Opens an output stream from the supplied IOProfile and route it to the
+ * supplied audio devices. If a mixer config is specified, it is forwarded to audio
+ * flinger. If not, a default config is derived from the output stream config.
+ * Also opens a duplicating output if needed and queries the audio HAL for supported
+ * audio profiles if the IOProfile is dynamic.
+ * @param[in] profile IOProfile to use as template
+ * @param[in] devices initial route to apply to this output stream
+ * @param[in] mixerConfig if not null, use this to configure the mixer
+ * @return an output descriptor for the newly opened stream or null in case of error.
+ */
+ sp<SwAudioOutputDescriptor> openOutputWithProfileAndDevice(
+ const sp<IOProfile>& profile, const DeviceVector& devices,
+ const audio_config_base_t *mixerConfig = nullptr);
bool isOffloadPossible(const audio_offload_info_t& offloadInfo,
bool durationIgnored = false);
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index aaf6fba..63a1e71 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -307,4 +307,15 @@
return af->updateSecondaryOutputs(trackSecondaryOutputs);
}
+status_t AudioPolicyService::AudioPolicyClient::setDeviceConnectedState(
+ const struct audio_port_v7 *port, bool connected) {
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == nullptr) {
+ ALOGW("%s: could not get AudioFlinger", __func__);
+ return PERMISSION_DENIED;
+ }
+ return af->setDeviceConnectedState(port, connected);
+}
+
+
} // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index 3f01de9..70fdfcb 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -345,7 +345,8 @@
(source > AUDIO_SOURCE_MAX &&
source != AUDIO_SOURCE_HOTWORD &&
source != AUDIO_SOURCE_FM_TUNER &&
- source != AUDIO_SOURCE_ECHO_REFERENCE)) {
+ source != AUDIO_SOURCE_ECHO_REFERENCE &&
+ source != AUDIO_SOURCE_ULTRASOUND)) {
ALOGE("addSourceDefaultEffect(): Unsupported source type %d", source);
return BAD_VALUE;
}
@@ -386,7 +387,7 @@
return res;
}
EffectDesc *effect = new EffectDesc(
- descriptor.name, *type, opPackageName, *uuid, priority, *id);
+ descriptor.name, descriptor.type, opPackageName, descriptor.uuid, priority, *id);
desc->mEffects.add(effect);
// TODO(b/71813697): Support setting params as well.
@@ -451,7 +452,7 @@
return res;
}
EffectDesc *effect = new EffectDesc(
- descriptor.name, *type, opPackageName, *uuid, priority, *id);
+ descriptor.name, descriptor.type, opPackageName, descriptor.uuid, priority, *id);
desc->mEffects.add(effect);
// TODO(b/71813697): Support setting params as well.
@@ -544,6 +545,7 @@
CAMCORDER_SRC_TAG,
VOICE_REC_SRC_TAG,
VOICE_COMM_SRC_TAG,
+ REMOTE_SUBMIX_SRC_TAG,
UNPROCESSED_SRC_TAG,
VOICE_PERFORMANCE_SRC_TAG
};
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 8ddd2a4..4da4ea0 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -119,14 +119,9 @@
}
Status AudioPolicyService::setDeviceConnectionState(
- const AudioDevice& deviceAidl,
media::AudioPolicyDeviceState stateAidl,
- const std::string& deviceNameAidl,
+ const android::media::audio::common::AudioPort& port,
const AudioFormatDescription& encodedFormatAidl) {
- audio_devices_t device;
- std::string address;
- RETURN_BINDER_STATUS_IF_ERROR(
- aidl2legacy_AudioDevice_audio_device(deviceAidl, &device, &address));
audio_policy_dev_state_t state = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_AudioPolicyDeviceState_audio_policy_dev_state_t(stateAidl));
audio_format_t encodedFormat = VALUE_OR_RETURN_BINDER_STATUS(
@@ -147,7 +142,7 @@
Mutex::Autolock _l(mLock);
AutoCallerClear acc;
status_t status = mAudioPolicyManager->setDeviceConnectionState(
- device, state, address.c_str(), deviceNameAidl.c_str(), encodedFormat);
+ state, port, encodedFormat);
if (status == NO_ERROR) {
onCheckSpatializer_l();
}
@@ -166,6 +161,7 @@
AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE));
return Status::ok();
}
+ Mutex::Autolock _l(mLock);
AutoCallerClear acc;
*_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(
legacy2aidl_audio_policy_dev_state_t_AudioPolicyDeviceState(
@@ -376,6 +372,15 @@
attr.flags = static_cast<audio_flags_mask_t>(
attr.flags & ~(AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY|AUDIO_FLAG_BYPASS_MUTE));
}
+
+ if (attr.content_type == AUDIO_CONTENT_TYPE_ULTRASOUND) {
+ if (!accessUltrasoundAllowed(adjAttributionSource)) {
+ ALOGE("%s: permission denied: ultrasound not allowed for uid %d pid %d",
+ __func__, adjAttributionSource.uid, adjAttributionSource.pid);
+ return binderStatusFromStatusT(PERMISSION_DENIED);
+ }
+ }
+
AutoCallerClear acc;
AudioPolicyInterface::output_type_t outputType;
status_t result = mAudioPolicyManager->getOutputForAttr(&attr, &output, session,
@@ -596,7 +601,8 @@
|| (inputSource >= AUDIO_SOURCE_CNT
&& inputSource != AUDIO_SOURCE_HOTWORD
&& inputSource != AUDIO_SOURCE_FM_TUNER
- && inputSource != AUDIO_SOURCE_ECHO_REFERENCE)) {
+ && inputSource != AUDIO_SOURCE_ECHO_REFERENCE
+ && inputSource != AUDIO_SOURCE_ULTRASOUND)) {
return binderStatusFromStatusT(BAD_VALUE);
}
@@ -677,6 +683,14 @@
return binderStatusFromStatusT(PERMISSION_DENIED);
}
+ if (attr.source == AUDIO_SOURCE_ULTRASOUND) {
+ if (!accessUltrasoundAllowed(adjAttributionSource)) {
+ ALOGE("%s: permission denied: ultrasound not allowed for uid %d pid %d",
+ __func__, adjAttributionSource.uid, adjAttributionSource.pid);
+ return binderStatusFromStatusT(PERMISSION_DENIED);
+ }
+ }
+
sp<AudioPolicyEffects>audioPolicyEffects;
{
status_t status;
@@ -1988,34 +2002,43 @@
mAudioPolicyManager->setSurroundFormatEnabled(audioFormat, enabled));
}
-Status AudioPolicyService::setAssistantUid(int32_t uidAidl)
-{
- uid_t uid = VALUE_OR_RETURN_BINDER_STATUS(aidl2legacy_int32_t_uid_t(uidAidl));
- Mutex::Autolock _l(mLock);
- mUidPolicy->setAssistantUid(uid);
+Status convertInt32VectorToUidVectorWithLimit(
+ const std::vector<int32_t>& uidsAidl, std::vector<uid_t>& uids) {
+ RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
+ convertRangeWithLimit(uidsAidl.begin(),
+ uidsAidl.end(),
+ std::back_inserter(uids),
+ aidl2legacy_int32_t_uid_t,
+ MAX_ITEMS_PER_LIST)));
+
return Status::ok();
}
-Status AudioPolicyService::setHotwordDetectionServiceUid(int32_t uidAidl)
+Status AudioPolicyService::setAssistantServicesUids(const std::vector<int32_t>& uidsAidl)
{
- uid_t uid = VALUE_OR_RETURN_BINDER_STATUS(aidl2legacy_int32_t_uid_t(uidAidl));
+ std::vector<uid_t> uids;
+ RETURN_IF_BINDER_ERROR(convertInt32VectorToUidVectorWithLimit(uidsAidl, uids));
+
Mutex::Autolock _l(mLock);
- mUidPolicy->setHotwordDetectionServiceUid(uid);
+ mUidPolicy->setAssistantUids(uids);
+ return Status::ok();
+}
+
+Status AudioPolicyService::setActiveAssistantServicesUids(
+ const std::vector<int32_t>& activeUidsAidl) {
+ std::vector<uid_t> activeUids;
+ RETURN_IF_BINDER_ERROR(convertInt32VectorToUidVectorWithLimit(activeUidsAidl, activeUids));
+
+ Mutex::Autolock _l(mLock);
+ mUidPolicy->setActiveAssistantUids(activeUids);
return Status::ok();
}
Status AudioPolicyService::setA11yServicesUids(const std::vector<int32_t>& uidsAidl)
{
- size_t size = uidsAidl.size();
- if (size > MAX_ITEMS_PER_LIST) {
- size = MAX_ITEMS_PER_LIST;
- }
std::vector<uid_t> uids;
- RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
- convertRange(uidsAidl.begin(),
- uidsAidl.begin() + size,
- std::back_inserter(uids),
- aidl2legacy_int32_t_uid_t)));
+ RETURN_IF_BINDER_ERROR(convertInt32VectorToUidVectorWithLimit(uidsAidl, uids));
+
Mutex::Autolock _l(mLock);
mUidPolicy->setA11yUids(uids);
return Status::ok();
@@ -2040,6 +2063,17 @@
return Status::ok();
}
+Status AudioPolicyService::isUltrasoundSupported(bool* _aidl_return)
+{
+ if (mAudioPolicyManager == NULL) {
+ return binderStatusFromStatusT(NO_INIT);
+ }
+ Mutex::Autolock _l(mLock);
+ AutoCallerClear acc;
+ *_aidl_return = mAudioPolicyManager->isUltrasoundSupported();
+ return Status::ok();
+}
+
Status AudioPolicyService::listAudioProductStrategies(
std::vector<media::AudioProductStrategy>* _aidl_return) {
AudioProductStrategyVector strategies;
@@ -2354,4 +2388,24 @@
return Status::ok();
}
+Status AudioPolicyService::getDirectProfilesForAttributes(
+ const media::AudioAttributesInternal& attrAidl,
+ std::vector<media::audio::common::AudioProfile>* _aidl_return) {
+ if (mAudioPolicyManager == nullptr) {
+ return binderStatusFromStatusT(NO_INIT);
+ }
+ audio_attributes_t attr = VALUE_OR_RETURN_BINDER_STATUS(
+ aidl2legacy_AudioAttributesInternal_audio_attributes_t(attrAidl));
+ AudioProfileVector audioProfiles;
+
+ Mutex::Autolock _l(mLock);
+ RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
+ mAudioPolicyManager->getDirectProfilesForAttributes(&attr, audioProfiles)));
+ *_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(
+ convertContainer<std::vector<media::audio::common::AudioProfile>>(
+ audioProfiles, legacy2aidl_AudioProfile_common, false /*isInput*/));
+
+ return Status::ok();
+}
+
} // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index ef7a83b..8263ad1 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -392,7 +392,8 @@
audio_config_base_t config = mSpatializer->getAudioInConfig();
status_t status =
mAudioPolicyManager->getSpatializerOutput(&config, &attr, &newOutput);
-
+ ALOGV("%s currentOutput %d newOutput %d channel_mask %#x",
+ __func__, currentOutput, newOutput, config.channel_mask);
if (status == NO_ERROR && currentOutput == newOutput) {
return;
}
@@ -593,6 +594,8 @@
}
write(fd, result.string(), result.size());
+
+ mUidPolicy->dumpInternals(fd);
return NO_ERROR;
}
@@ -606,13 +609,20 @@
{
// Go over all active clients and allow capture (does not force silence) in the
// following cases:
-// The client is the assistant
+// The client is in the active assistant list
+// AND is TOP
+// AND an accessibility service is TOP
+// AND source is either VOICE_RECOGNITION OR HOTWORD
+// OR there is no active privacy sensitive capture or call
+// OR client has CAPTURE_AUDIO_OUTPUT privileged permission
+// AND source is VOICE_RECOGNITION OR HOTWORD
+// The client is an assistant AND active assistant is not being used
// AND an accessibility service is on TOP or a RTT call is active
// AND the source is VOICE_RECOGNITION or HOTWORD
-// OR uses VOICE_RECOGNITION AND is on TOP
-// OR uses HOTWORD
-// AND there is no active privacy sensitive capture or call
+// OR there is no active privacy sensitive capture or call
// OR client has CAPTURE_AUDIO_OUTPUT privileged permission
+// AND is TOP most recent assistant and uses VOICE_RECOGNITION or HOTWORD
+// OR there is no top recent assistant and source is HOTWORD
// OR The client is an accessibility service
// AND Is on TOP
// AND the source is VOICE_RECOGNITION or HOTWORD
@@ -640,13 +650,16 @@
sp<AudioRecordClient> latestActive;
sp<AudioRecordClient> topSensitiveActive;
sp<AudioRecordClient> latestSensitiveActiveOrComm;
+ sp<AudioRecordClient> latestActiveAssistant;
nsecs_t topStartNs = 0;
nsecs_t latestStartNs = 0;
nsecs_t topSensitiveStartNs = 0;
nsecs_t latestSensitiveStartNs = 0;
+ nsecs_t latestAssistantStartNs = 0;
bool isA11yOnTop = mUidPolicy->isA11yOnTop();
bool isAssistantOnTop = false;
+ bool useActiveAssistantList = false;
bool isSensitiveActive = false;
bool isInCall = mPhoneState == AUDIO_MODE_IN_CALL;
bool isInCommunication = mPhoneState == AUDIO_MODE_IN_COMMUNICATION;
@@ -681,6 +694,7 @@
// for top or latest active to avoid masking regular clients started before
if (!isAccessibility && !isVirtualSource(current->attributes.source)) {
bool isAssistant = mUidPolicy->isAssistantUid(currentUid);
+ bool isActiveAssistant = mUidPolicy->isActiveAssistantUid(currentUid);
bool isPrivacySensitive =
(current->attributes.flags & AUDIO_FLAG_CAPTURE_PRIVATE) != 0;
@@ -698,6 +712,14 @@
}
if (isAssistant) {
isAssistantOnTop = true;
+ if (isActiveAssistant) {
+ useActiveAssistantList = true;
+ } else if (!useActiveAssistantList) {
+ if (current->startTimeNs > latestAssistantStartNs) {
+ latestActiveAssistant = current;
+ latestAssistantStartNs = current->startTimeNs;
+ }
+ }
}
}
// Clients capturing for HOTWORD are not considered
@@ -777,6 +799,8 @@
current->attributionSource.uid == topActive->attributionSource.uid;
bool isTopOrLatestSensitive = topSensitiveActive == nullptr ? false :
current->attributionSource.uid == topSensitiveActive->attributionSource.uid;
+ bool isTopOrLatestAssistant = latestActiveAssistant == nullptr ? false :
+ current->attributionSource.uid == latestActiveAssistant->attributionSource.uid;
auto canCaptureIfInCallOrCommunication = [&](const auto &recordClient) REQUIRES(mLock) {
uid_t recordUid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(
@@ -806,23 +830,45 @@
} else if (isVirtualSource(source)) {
// Allow capture for virtual (remote submix, call audio TX or RX...) sources
allowCapture = true;
- } else if (mUidPolicy->isAssistantUid(currentUid)) {
+ } else if (!useActiveAssistantList && mUidPolicy->isAssistantUid(currentUid)) {
// For assistant allow capture if:
- // An accessibility service is on TOP or a RTT call is active
+ // Active assistant list is not being used
+ // AND accessibility service is on TOP or a RTT call is active
// AND the source is VOICE_RECOGNITION or HOTWORD
- // OR is on TOP AND uses VOICE_RECOGNITION
- // OR uses HOTWORD
- // AND there is no active privacy sensitive capture or call
- // OR client has CAPTURE_AUDIO_OUTPUT privileged permission
+ // OR there is no active privacy sensitive capture or call
+ // OR client has CAPTURE_AUDIO_OUTPUT privileged permission
+ // AND is latest TOP assistant AND
+ // uses VOICE_RECOGNITION OR uses HOTWORD
+ // OR there is no TOP assistant and uses HOTWORD
if (isA11yOnTop || rttCallActive) {
if (source == AUDIO_SOURCE_HOTWORD || source == AUDIO_SOURCE_VOICE_RECOGNITION) {
allowCapture = true;
}
- } else {
- if (((isAssistantOnTop && source == AUDIO_SOURCE_VOICE_RECOGNITION) ||
- source == AUDIO_SOURCE_HOTWORD)
- && !(isSensitiveActive && !current->canCaptureOutput)
+ } else if (!(isSensitiveActive && !current->canCaptureOutput)
+ && canCaptureIfInCallOrCommunication(current)) {
+ if (isTopOrLatestAssistant
+ && (source == AUDIO_SOURCE_VOICE_RECOGNITION
+ || source == AUDIO_SOURCE_HOTWORD)) {
+ allowCapture = true;
+ } else if (!isAssistantOnTop && (source == AUDIO_SOURCE_HOTWORD)) {
+ allowCapture = true;
+ }
+ }
+ } else if (useActiveAssistantList && mUidPolicy->isActiveAssistantUid(currentUid)) {
+ // For assistant on active list and on top allow capture if:
+ // An accessibility service is on TOP
+ // AND the source is VOICE_RECOGNITION or HOTWORD
+ // OR there is no active privacy sensitive capture or call
+ // OR client has CAPTURE_AUDIO_OUTPUT privileged permission
+ // AND uses VOICE_RECOGNITION OR uses HOTWORD
+ if (isA11yOnTop) {
+ if (source == AUDIO_SOURCE_HOTWORD || source == AUDIO_SOURCE_VOICE_RECOGNITION) {
+ allowCapture = true;
+ }
+ } else if (!(isSensitiveActive && !current->canCaptureOutput)
&& canCaptureIfInCallOrCommunication(current)) {
+ if ((source == AUDIO_SOURCE_VOICE_RECOGNITION) || (source == AUDIO_SOURCE_HOTWORD))
+ {
allowCapture = true;
}
}
@@ -1035,7 +1081,8 @@
case TRANSACTION_getSurroundFormats:
case TRANSACTION_getReportedSurroundFormats:
case TRANSACTION_setSurroundFormatEnabled:
- case TRANSACTION_setAssistantUid:
+ case TRANSACTION_setAssistantServicesUids:
+ case TRANSACTION_setActiveAssistantServicesUids:
case TRANSACTION_setA11yServicesUids:
case TRANSACTION_setUidDeviceAffinities:
case TRANSACTION_removeUidDeviceAffinities:
@@ -1473,6 +1520,66 @@
return it != mA11yUids.end();
}
+void AudioPolicyService::UidPolicy::setAssistantUids(const std::vector<uid_t>& uids) {
+ mAssistantUids.clear();
+ mAssistantUids = uids;
+}
+
+bool AudioPolicyService::UidPolicy::isAssistantUid(uid_t uid)
+{
+ std::vector<uid_t>::iterator it = find(mAssistantUids.begin(), mAssistantUids.end(), uid);
+ return it != mAssistantUids.end();
+}
+
+void AudioPolicyService::UidPolicy::setActiveAssistantUids(const std::vector<uid_t>& activeUids) {
+ mActiveAssistantUids = activeUids;
+}
+
+bool AudioPolicyService::UidPolicy::isActiveAssistantUid(uid_t uid)
+{
+ std::vector<uid_t>::iterator it = find(mActiveAssistantUids.begin(),
+ mActiveAssistantUids.end(), uid);
+ return it != mActiveAssistantUids.end();
+}
+
+void AudioPolicyService::UidPolicy::dumpInternals(int fd) {
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ auto appendUidsToResult = [&](const char* title, const std::vector<uid_t> &uids) {
+ snprintf(buffer, SIZE, "\t%s: \n", title);
+ result.append(buffer);
+ int counter = 0;
+ if (uids.empty()) {
+ snprintf(buffer, SIZE, "\t\tNo UIDs present.\n");
+ result.append(buffer);
+ return;
+ }
+ for (const auto &uid : uids) {
+ snprintf(buffer, SIZE, "\t\tUID[%d]=%d\n", counter++, uid);
+ result.append(buffer);
+ }
+ };
+
+ snprintf(buffer, SIZE, "UID Policy:\n");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmObserverRegistered=%s\n",(mObserverRegistered ? "True":"False"));
+ result.append(buffer);
+
+ appendUidsToResult("Assistants UIDs", mAssistantUids);
+ appendUidsToResult("Active Assistants UIDs", mActiveAssistantUids);
+
+ appendUidsToResult("Accessibility UIDs", mA11yUids);
+
+ snprintf(buffer, SIZE, "\tInput Method Service UID=%d\n", mCurrentImeUid);
+ result.append(buffer);
+
+ snprintf(buffer, SIZE, "\tIs RTT Enabled: %s\n", (mRttEnabled ? "True":"False"));
+ result.append(buffer);
+
+ write(fd, result.string(), result.size());
+}
+
// ----------- AudioPolicyService::SensorPrivacyService implementation ----------
void AudioPolicyService::SensorPrivacyPolicy::registerSelf() {
SensorPrivacyManager spm;
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 84b1e50..ae65a65 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -82,9 +82,8 @@
//
binder::Status onNewAudioModulesAvailable() override;
binder::Status setDeviceConnectionState(
- const AudioDevice& device,
media::AudioPolicyDeviceState state,
- const std::string& deviceName,
+ const android::media::audio::common::AudioPort& port,
const AudioFormatDescription& encodedFormat) override;
binder::Status getDeviceConnectionState(const AudioDevice& device,
media::AudioPolicyDeviceState* _aidl_return) override;
@@ -219,11 +218,12 @@
std::vector<AudioFormatDescription>* _aidl_return) override;
binder::Status setSurroundFormatEnabled(const AudioFormatDescription& audioFormat,
bool enabled) override;
- binder::Status setAssistantUid(int32_t uid) override;
- binder::Status setHotwordDetectionServiceUid(int32_t uid) override;
+ binder::Status setAssistantServicesUids(const std::vector<int32_t>& uids) override;
+ binder::Status setActiveAssistantServicesUids(const std::vector<int32_t>& activeUids) override;
binder::Status setA11yServicesUids(const std::vector<int32_t>& uids) override;
binder::Status setCurrentImeUid(int32_t uid) override;
binder::Status isHapticPlaybackSupported(bool* _aidl_return) override;
+ binder::Status isUltrasoundSupported(bool* _aidl_return) override;
binder::Status listAudioProductStrategies(
std::vector<media::AudioProductStrategy>* _aidl_return) override;
binder::Status getProductStrategyFromAudioAttributes(const media::AudioAttributesEx& aa,
@@ -276,6 +276,9 @@
const AudioConfig& config,
media::AudioDirectMode* _aidl_return) override;
+ binder::Status getDirectProfilesForAttributes(const media::AudioAttributesInternal& attr,
+ std::vector<media::audio::common::AudioProfile>* _aidl_return) override;
+
status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override;
// IBinder::DeathRecipient
@@ -417,7 +420,7 @@
public:
explicit UidPolicy(wp<AudioPolicyService> service)
: mService(service), mObserverRegistered(false),
- mAssistantUid(0), mHotwordDetectionServiceUid(0), mCurrentImeUid(0),
+ mCurrentImeUid(0),
mRttEnabled(false) {}
void registerSelf();
@@ -428,13 +431,10 @@
bool isUidActive(uid_t uid);
int getUidState(uid_t uid);
- void setAssistantUid(uid_t uid) { mAssistantUid = uid; };
- void setHotwordDetectionServiceUid(uid_t uid) { mHotwordDetectionServiceUid = uid; }
- bool isAssistantUid(uid_t uid) const {
- // The HotwordDetectionService is part of the Assistant package but runs with a separate
- // (isolated) uid, so we check for either uid here.
- return uid == mAssistantUid || uid == mHotwordDetectionServiceUid;
- }
+ void setAssistantUids(const std::vector<uid_t>& uids);
+ bool isAssistantUid(uid_t uid);
+ void setActiveAssistantUids(const std::vector<uid_t>& activeUids);
+ bool isActiveAssistantUid(uid_t uid);
void setA11yUids(const std::vector<uid_t>& uids) { mA11yUids.clear(); mA11yUids = uids; }
bool isA11yUid(uid_t uid);
bool isA11yOnTop();
@@ -456,6 +456,8 @@
void updateUid(std::unordered_map<uid_t, std::pair<bool, int>> *uids,
uid_t uid, bool active, int state, bool insert);
+ void dumpInternals(int fd);
+
private:
void notifyService();
void updateOverrideUid(uid_t uid, bool active, bool insert);
@@ -469,8 +471,8 @@
bool mObserverRegistered = false;
std::unordered_map<uid_t, std::pair<bool, int>> mOverrideUids;
std::unordered_map<uid_t, std::pair<bool, int>> mCachedUids;
- uid_t mAssistantUid = -1;
- uid_t mHotwordDetectionServiceUid = -1;
+ std::vector<uid_t> mAssistantUids;
+ std::vector<uid_t> mActiveAssistantUids;
std::vector<uid_t> mA11yUids;
uid_t mCurrentImeUid = -1;
bool mRttEnabled = false;
@@ -804,6 +806,9 @@
status_t updateSecondaryOutputs(
const TrackSecondaryOutputsMap& trackSecondaryOutputs) override;
+ status_t setDeviceConnectedState(
+ const struct audio_port_v7 *port, bool connected) override;
+
private:
AudioPolicyService *mAudioPolicyService;
};
diff --git a/services/audiopolicy/service/Spatializer.cpp b/services/audiopolicy/service/Spatializer.cpp
index 0fdbe20..54d9094 100644
--- a/services/audiopolicy/service/Spatializer.cpp
+++ b/services/audiopolicy/service/Spatializer.cpp
@@ -227,12 +227,8 @@
if (status != NO_ERROR) {
return status;
}
- status = getHalParameter<true>(effect, SPATIALIZER_PARAM_SUPPORTED_CHANNEL_MASKS,
+ return getHalParameter<true>(effect, SPATIALIZER_PARAM_SUPPORTED_CHANNEL_MASKS,
&mChannelMasks);
- if (status != NO_ERROR) {
- return status;
- }
- return NO_ERROR;
}
/** Gets the channel mask, sampling rate and format set for the spatializer input. */
diff --git a/services/audiopolicy/service/SpatializerPoseController.cpp b/services/audiopolicy/service/SpatializerPoseController.cpp
index 440a7ff..6a3c9d1 100644
--- a/services/audiopolicy/service/SpatializerPoseController.cpp
+++ b/services/audiopolicy/service/SpatializerPoseController.cpp
@@ -40,25 +40,11 @@
// This is how fast, in rad/s, we allow rotation angle to shift during rate-limiting.
constexpr float kMaxRotationalVelocity = 8;
-// This should be set to the typical time scale that the translation sensors used drift in. This
-// means, loosely, for how long we can trust the reading to be "accurate enough". This would
-// determine the time constants used for high-pass filtering those readings. If the value is set
-// too high, we may experience drift. If it is set too low, we may experience poses tending toward
-// identity too fast.
-constexpr auto kTranslationalDriftTimeConstant = 40s;
-
-// This should be set to the typical time scale that the rotation sensors used drift in. This
-// means, loosely, for how long we can trust the reading to be "accurate enough". This would
-// determine the time constants used for high-pass filtering those readings. If the value is set
-// too high, we may experience drift. If it is set too low, we may experience poses tending toward
-// identity too fast.
-constexpr auto kRotationalDriftTimeConstant = 60s;
-
// This is how far into the future we predict the head pose, using linear extrapolation based on
// twist (velocity). It should be set to a value that matches the characteristic durations of moving
// one's head. The higher we set this, the more latency we are able to reduce, but setting this too
// high will result in high prediction errors whenever the head accelerates (changes velocity).
-constexpr auto kPredictionDuration = 10ms;
+constexpr auto kPredictionDuration = 50ms;
// After losing this many consecutive samples from either sensor, we would treat the measurement as
// stale;
@@ -100,9 +86,6 @@
mProcessor(createHeadTrackingProcessor(HeadTrackingProcessor::Options{
.maxTranslationalVelocity = kMaxTranslationalVelocity / kTicksPerSecond,
.maxRotationalVelocity = kMaxRotationalVelocity / kTicksPerSecond,
- .translationalDriftTimeConstant =
- double(Ticks(kTranslationalDriftTimeConstant).count()),
- .rotationalDriftTimeConstant = double(Ticks(kRotationalDriftTimeConstant).count()),
.freshnessTimeout = Ticks(sensorPeriod * kMaxLostSamples).count(),
.predictionDuration = Ticks(kPredictionDuration).count(),
.autoRecenterWindowDuration = Ticks(kAutoRecenterWindowDuration).count(),
@@ -253,7 +236,8 @@
const std::optional<Twist3f>& twist, bool isNewReference) {
std::lock_guard lock(mMutex);
if (sensor == mHeadSensor) {
- mProcessor->setWorldToHeadPose(timestamp, pose, twist.value_or(Twist3f()));
+ mProcessor->setWorldToHeadPose(timestamp, pose,
+ twist.value_or(Twist3f()) / kTicksPerSecond);
if (isNewReference) {
mProcessor->recenter(true, false);
}
diff --git a/services/audiopolicy/tests/Android.bp b/services/audiopolicy/tests/Android.bp
index 8fbe8b2..2e220bc 100644
--- a/services/audiopolicy/tests/Android.bp
+++ b/services/audiopolicy/tests/Android.bp
@@ -31,7 +31,7 @@
static_libs: [
"libaudiopolicycomponents",
- "libgmock"
+ "libgmock",
],
header_libs: [
@@ -65,6 +65,12 @@
"liblog",
"libmedia_helper",
"libutils",
+ "android.media.audio.common.types-V1-cpp",
+ "libaudioclient_aidl_conversion",
+ "libstagefright_foundation",
+ "libshmemcompat",
+ "libshmemutil",
+ "audioclient-types-aidl-cpp",
],
static_libs: ["libaudiopolicycomponents"],
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
index 84b40d2..adef8f1 100644
--- a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
@@ -103,6 +103,11 @@
++mAudioPortListUpdateCount;
}
+ status_t setDeviceConnectedState(
+ const struct audio_port_v7 *port __unused, bool connected __unused) override {
+ return NO_ERROR;
+ }
+
// Helper methods for tests
size_t getActivePatchesCount() const { return mActivePatches.size(); }
diff --git a/services/audiopolicy/tests/AudioPolicyTestClient.h b/services/audiopolicy/tests/AudioPolicyTestClient.h
index 4e0735b..da85658 100644
--- a/services/audiopolicy/tests/AudioPolicyTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyTestClient.h
@@ -96,6 +96,10 @@
const TrackSecondaryOutputsMap& trackSecondaryOutputs __unused) override {
return NO_INIT;
}
+ status_t setDeviceConnectedState(
+ const struct audio_port_v7 *port __unused, bool connected __unused) override {
+ return NO_INIT;
+ }
};
} // namespace android
diff --git a/services/audiopolicy/tests/AudioPolicyTestManager.h b/services/audiopolicy/tests/AudioPolicyTestManager.h
index 9d0d558..7441f20 100644
--- a/services/audiopolicy/tests/AudioPolicyTestManager.h
+++ b/services/audiopolicy/tests/AudioPolicyTestManager.h
@@ -34,6 +34,9 @@
using AudioPolicyManager::setMsdOutputPatches;
using AudioPolicyManager::getAudioPatches;
using AudioPolicyManager::getDirectPlaybackSupport;
+ using AudioPolicyManager::getDirectProfilesForAttributes;
+ using AudioPolicyManager::setDeviceConnectionState;
+ using AudioPolicyManager::deviceToAudioPort;
uint32_t getAudioPortGeneration() const { return mAudioPortGeneration; }
};
diff --git a/services/audiopolicy/tests/audio_health_tests.cpp b/services/audiopolicy/tests/audio_health_tests.cpp
index df4389b..10f8dc0 100644
--- a/services/audiopolicy/tests/audio_health_tests.cpp
+++ b/services/audiopolicy/tests/audio_health_tests.cpp
@@ -111,16 +111,17 @@
continue;
}
std::string address = "11:22:33:44:55:66";
+ media::AudioPort aidlPort;
+ ASSERT_EQ(OK, manager.deviceToAudioPort(device->type(), address.c_str(), "" /*name*/,
+ &aidlPort));
ASSERT_EQ(AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
AudioSystem::getDeviceConnectionState(device->type(), address.c_str()));
ASSERT_EQ(NO_ERROR, AudioSystem::setDeviceConnectionState(
- device->type(), AUDIO_POLICY_DEVICE_STATE_AVAILABLE, address.c_str(),
- "" /*device_name*/, AUDIO_FORMAT_DEFAULT));
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE, aidlPort.hal, AUDIO_FORMAT_DEFAULT));
ASSERT_EQ(AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
AudioSystem::getDeviceConnectionState(device->type(), address.c_str()));
ASSERT_EQ(NO_ERROR, AudioSystem::setDeviceConnectionState(
- device->type(), AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, address.c_str(),
- "" /*device_name*/, AUDIO_FORMAT_DEFAULT));
+ AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, aidlPort.hal, AUDIO_FORMAT_DEFAULT));
ASSERT_EQ(AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
AudioSystem::getDeviceConnectionState(device->type(), address.c_str()));
}
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index 1b54e75..3626378 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -48,6 +48,8 @@
"common/CameraOfflineSessionBase.cpp",
"common/CameraProviderManager.cpp",
"common/FrameProcessorBase.cpp",
+ "common/hidl/HidlProviderInfo.cpp",
+ "common/aidl/AidlProviderInfo.cpp",
"api1/Camera2Client.cpp",
"api1/client2/Parameters.cpp",
"api1/client2/FrameProcessor.cpp",
@@ -80,6 +82,12 @@
"device3/Camera3DeviceInjectionMethods.cpp",
"device3/UHRCropAndMeteringRegionMapper.cpp",
"device3/PreviewFrameScheduler.cpp",
+ "device3/hidl/HidlCamera3Device.cpp",
+ "device3/hidl/HidlCamera3OfflineSession.cpp",
+ "device3/hidl/HidlCamera3OutputUtils.cpp",
+ "device3/aidl/AidlCamera3Device.cpp",
+ "device3/aidl/AidlCamera3OutputUtils.cpp",
+ "device3/aidl/AidlCamera3OfflineSession.cpp",
"gui/RingBufferConsumer.cpp",
"hidl/AidlCameraDeviceCallbacks.cpp",
"hidl/AidlCameraServiceListener.cpp",
@@ -111,6 +119,7 @@
"libutilscallstack",
"libutils",
"libbinder",
+ "libbinder_ndk",
"libactivitymanager_aidl",
"libpermission",
"libcutils",
@@ -144,6 +153,7 @@
"android.hardware.camera.provider@2.5",
"android.hardware.camera.provider@2.6",
"android.hardware.camera.provider@2.7",
+ "android.hardware.camera.provider-V1-ndk",
"android.hardware.camera.device@3.2",
"android.hardware.camera.device@3.3",
"android.hardware.camera.device@3.4",
@@ -151,10 +161,12 @@
"android.hardware.camera.device@3.6",
"android.hardware.camera.device@3.7",
"android.hardware.camera.device@3.8",
+ "android.hardware.camera.device-V1-ndk",
"media_permission-aidl-cpp",
],
static_libs: [
+ "libaidlcommonsupport",
"libprocessinfoservice_aidl",
"libbinderthreadstateutils",
"media_permission-aidl-cpp",
diff --git a/services/camera/libcameraservice/CameraFlashlight.cpp b/services/camera/libcameraservice/CameraFlashlight.cpp
index 015ae2f..ffd38be 100644
--- a/services/camera/libcameraservice/CameraFlashlight.cpp
+++ b/services/camera/libcameraservice/CameraFlashlight.cpp
@@ -32,8 +32,6 @@
namespace android {
-using hardware::camera::common::V1_0::TorchModeStatus;
-
/////////////////////////////////////////////////////////////////////
// CameraFlashlight implementation begins
// used by camera service to control flashflight.
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index a593500..271cfec 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -91,8 +91,6 @@
using hardware::ICamera;
using hardware::ICameraClient;
using hardware::ICameraServiceListener;
-using hardware::camera::common::V1_0::CameraDeviceStatus;
-using hardware::camera::common::V1_0::TorchModeStatus;
using hardware::camera2::ICameraInjectionCallback;
using hardware::camera2::ICameraInjectionSession;
using hardware::camera2::utils::CameraIdAndSessionConfiguration;
@@ -134,8 +132,9 @@
static const String16
sCameraInjectExternalCameraPermission("android.permission.CAMERA_INJECT_EXTERNAL_CAMERA");
const char *sFileName = "lastOpenSessionDumpFile";
-static constexpr int32_t kVendorClientScore = resource_policy::PERCEPTIBLE_APP_ADJ;
-static constexpr int32_t kVendorClientState = ActivityManager::PROCESS_STATE_PERSISTENT_UI;
+static constexpr int32_t kSystemNativeClientScore = resource_policy::PERCEPTIBLE_APP_ADJ;
+static constexpr int32_t kSystemNativeClientState =
+ ActivityManager::PROCESS_STATE_PERSISTENT_UI;
const String8 CameraService::kOfflineDevice("offline-");
const String16 CameraService::kWatchAllClientsFlag("all");
@@ -157,6 +156,12 @@
}
}
+// The word 'System' here does not refer to clients only on the system
+// partition. They just need to have a android system uid.
+static bool doesClientHaveSystemUid() {
+ return (CameraThreadState::getCallingUid() < AID_APP_START);
+}
+
void CameraService::onFirstRef()
{
@@ -363,7 +368,7 @@
void CameraService::addStates(const String8 id) {
std::string cameraId(id.c_str());
- hardware::camera::common::V1_0::CameraResourceCost cost;
+ CameraResourceCost cost;
status_t res = mCameraProviderManager->getResourceCost(cameraId, &cost);
if (res != OK) {
ALOGE("Failed to query device resource cost: %s (%d)", strerror(-res), res);
@@ -925,7 +930,7 @@
}
Status CameraService::makeClient(const sp<CameraService>& cameraService,
- const sp<IInterface>& cameraCb, const String16& packageName,
+ const sp<IInterface>& cameraCb, const String16& packageName, bool systemNativeClient,
const std::optional<String16>& featureId, const String8& cameraId,
int api1CameraId, int facing, int sensorOrientation, int clientPid, uid_t clientUid,
int servicePid, int deviceVersion, apiLevel effectiveApiLevel, bool overrideForPerfClass,
@@ -951,15 +956,14 @@
if (effectiveApiLevel == API_1) { // Camera1 API route
sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
*client = new Camera2Client(cameraService, tmp, packageName, featureId,
- cameraId, api1CameraId,
- facing, sensorOrientation, clientPid, clientUid,
+ cameraId, api1CameraId, facing, sensorOrientation, clientPid, clientUid,
servicePid, overrideForPerfClass);
} else { // Camera2 API route
sp<hardware::camera2::ICameraDeviceCallbacks> tmp =
static_cast<hardware::camera2::ICameraDeviceCallbacks*>(cameraCb.get());
- *client = new CameraDeviceClient(cameraService, tmp, packageName, featureId,
- cameraId, facing, sensorOrientation, clientPid, clientUid, servicePid,
- overrideForPerfClass);
+ *client = new CameraDeviceClient(cameraService, tmp, packageName,
+ systemNativeClient, featureId, cameraId, facing, sensorOrientation,
+ clientPid, clientUid, servicePid, overrideForPerfClass);
}
break;
default:
@@ -1055,7 +1059,7 @@
sp<Client> tmp = nullptr;
if (!(ret = connectHelper<ICameraClient,Client>(
sp<ICameraClient>{nullptr}, id, cameraId,
- internalPackageName, {}, uid, USE_CALLING_PID,
+ internalPackageName, /*systemNativeClient*/ false, {}, uid, USE_CALLING_PID,
API_1, /*shimUpdateOnly*/ true, /*oomScoreOffset*/ 0,
/*targetSdkVersion*/ __ANDROID_API_FUTURE__, /*out*/ tmp)
).isOk()) {
@@ -1290,9 +1294,9 @@
userid_t clientUserId = multiuser_get_user_id(clientUid);
- // Only allow clients who are being used by the current foreground device user, unless calling
- // from our own process OR the caller is using the cameraserver's HIDL interface.
- if (getCurrentServingCall() != BinderCallType::HWBINDER && callingPid != getpid() &&
+ // For non-system clients : Only allow clients who are being used by the current foreground
+ // device user, unless calling from our own process.
+ if (!doesClientHaveSystemUid() && callingPid != getpid() &&
(mAllowedUsers.find(clientUserId) == mAllowedUsers.end())) {
ALOGE("CameraService::connect X (PID %d) rejected (cannot connect from "
"device user %d, currently allowed device users: %s)", callingPid, clientUserId,
@@ -1329,12 +1333,12 @@
}
void CameraService::finishConnectLocked(const sp<BasicClient>& client,
- const CameraService::DescriptorPtr& desc, int oomScoreOffset) {
+ const CameraService::DescriptorPtr& desc, int oomScoreOffset, bool systemNativeClient) {
// Make a descriptor for the incoming client
auto clientDescriptor =
CameraService::CameraClientManager::makeClientDescriptor(client, desc,
- oomScoreOffset);
+ oomScoreOffset, systemNativeClient);
auto evicted = mActiveClientManager.addAndEvict(clientDescriptor);
logConnected(desc->getKey(), static_cast<int>(desc->getOwnerId()),
@@ -1364,7 +1368,7 @@
status_t CameraService::handleEvictionsLocked(const String8& cameraId, int clientPid,
apiLevel effectiveApiLevel, const sp<IBinder>& remoteCallback, const String8& packageName,
- int oomScoreOffset,
+ int oomScoreOffset, bool systemNativeClient,
/*out*/
sp<BasicClient>* client,
std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<BasicClient>>>* partial) {
@@ -1439,7 +1443,7 @@
clientDescriptor = CameraClientManager::makeClientDescriptor(cameraId,
sp<BasicClient>{nullptr}, static_cast<int32_t>(state->getCost()),
state->getConflicting(), actualScore, clientPid, actualState,
- oomScoreOffset);
+ oomScoreOffset, systemNativeClient);
resource_policy::ClientPriority clientPriority = clientDescriptor->getPriority();
@@ -1582,7 +1586,7 @@
String8 id = cameraIdIntToStr(api1CameraId);
sp<Client> client = nullptr;
ret = connectHelper<ICameraClient,Client>(cameraClient, id, api1CameraId,
- clientPackageName, {}, clientUid, clientPid, API_1,
+ clientPackageName,/*systemNativeClient*/ false, {}, clientUid, clientPid, API_1,
/*shimUpdateOnly*/ false, /*oomScoreOffset*/ 0, targetSdkVersion, /*out*/client);
if(!ret.isOk()) {
@@ -1614,14 +1618,14 @@
// 1) If cameraserver tries to access this camera device, accept the
// connection.
// 2) The camera device is a publicly hidden secure camera device AND some
- // component is trying to access it on a non-hwbinder thread (generally a non HAL client),
- // reject it.
+ // non system component is trying to access it.
// 3) if the camera device is advertised by the camera HAL as SYSTEM_ONLY
// and the serving thread is a non hwbinder thread, the client must have
// android.permission.SYSTEM_CAMERA permissions to connect.
int cPid = CameraThreadState::getCallingPid();
int cUid = CameraThreadState::getCallingUid();
+ bool systemClient = doesClientHaveSystemUid();
SystemCameraKind systemCameraKind = SystemCameraKind::PUBLIC;
if (getSystemCameraKind(cameraId, &systemCameraKind) != OK) {
// This isn't a known camera ID, so it's not a system camera
@@ -1634,8 +1638,7 @@
return false;
}
// (2)
- if (getCurrentServingCall() != BinderCallType::HWBINDER &&
- systemCameraKind == SystemCameraKind::HIDDEN_SECURE_CAMERA) {
+ if (!systemClient && systemCameraKind == SystemCameraKind::HIDDEN_SECURE_CAMERA) {
ALOGW("Rejecting access to secure hidden camera %s", cameraId.c_str());
return true;
}
@@ -1643,8 +1646,7 @@
// getCameraCharacteristics() allows for calls to succeed (albeit after hiding some
// characteristics) even if clients don't have android.permission.CAMERA. We do not want the
// same behavior for system camera devices.
- if (getCurrentServingCall() != BinderCallType::HWBINDER &&
- systemCameraKind == SystemCameraKind::SYSTEM_ONLY_CAMERA &&
+ if (!systemClient && systemCameraKind == SystemCameraKind::SYSTEM_ONLY_CAMERA &&
!hasPermissionsForSystemCamera(cPid, cUid, /*logPermissionFailure*/true)) {
ALOGW("Rejecting access to system only camera %s, inadequete permissions",
cameraId.c_str());
@@ -1669,11 +1671,12 @@
sp<CameraDeviceClient> client = nullptr;
String16 clientPackageNameAdj = clientPackageName;
int callingPid = CameraThreadState::getCallingPid();
-
- if (getCurrentServingCall() == BinderCallType::HWBINDER) {
- std::string vendorClient =
- StringPrintf("vendor.client.pid<%d>", CameraThreadState::getCallingPid());
- clientPackageNameAdj = String16(vendorClient.c_str());
+ bool systemNativeClient = false;
+ if (doesClientHaveSystemUid() && (clientPackageNameAdj.size() == 0)) {
+ std::string systemClient =
+ StringPrintf("client.pid<%d>", CameraThreadState::getCallingPid());
+ clientPackageNameAdj = String16(systemClient.c_str());
+ systemNativeClient = true;
}
if (oomScoreOffset < 0) {
@@ -1697,7 +1700,7 @@
}
ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,
- /*api1CameraId*/-1, clientPackageNameAdj, clientFeatureId,
+ /*api1CameraId*/-1, clientPackageNameAdj, systemNativeClient,clientFeatureId,
clientUid, USE_CALLING_PID, API_2, /*shimUpdateOnly*/ false, oomScoreOffset,
targetSdkVersion, /*out*/client);
@@ -1728,7 +1731,7 @@
template<class CALLBACK, class CLIENT>
Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
- int api1CameraId, const String16& clientPackageName,
+ int api1CameraId, const String16& clientPackageName, bool systemNativeClient,
const std::optional<String16>& clientFeatureId, int clientUid, int clientPid,
apiLevel effectiveApiLevel, bool shimUpdateOnly, int oomScoreOffset, int targetSdkVersion,
/*out*/sp<CLIENT>& device) {
@@ -1747,7 +1750,7 @@
sp<CLIENT> client = nullptr;
int facing = -1;
int orientation = 0;
- bool isNdk = (clientPackageName.size() == 0);
+ bool isNonSystemNdk = (clientPackageName.size() == 0);
{
// Acquire mServiceLock and prevent other clients from connecting
std::unique_ptr<AutoConditionLock> lock =
@@ -1781,8 +1784,8 @@
sp<BasicClient> clientTmp = nullptr;
std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<BasicClient>>> partial;
if ((err = handleEvictionsLocked(cameraId, originalClientPid, effectiveApiLevel,
- IInterface::asBinder(cameraCb), clientName8, oomScoreOffset, /*out*/&clientTmp,
- /*out*/&partial)) != NO_ERROR) {
+ IInterface::asBinder(cameraCb), clientName8, oomScoreOffset, systemNativeClient,
+ /*out*/&clientTmp, /*out*/&partial)) != NO_ERROR) {
switch (err) {
case -ENODEV:
return STATUS_ERROR_FMT(ERROR_DISCONNECTED,
@@ -1822,8 +1825,8 @@
sp<BasicClient> tmp = nullptr;
bool overrideForPerfClass = SessionConfigurationUtils::targetPerfClassPrimaryCamera(
mPerfClassPrimaryCameraIds, cameraId.string(), targetSdkVersion);
- if(!(ret = makeClient(this, cameraCb, clientPackageName, clientFeatureId,
- cameraId, api1CameraId, facing, orientation,
+ if(!(ret = makeClient(this, cameraCb, clientPackageName, systemNativeClient,
+ clientFeatureId, cameraId, api1CameraId, facing, orientation,
clientPid, clientUid, getpid(),
deviceVersion, effectiveApiLevel, overrideForPerfClass,
/*out*/&tmp)).isOk()) {
@@ -1925,7 +1928,7 @@
mServiceLock.lock();
} else {
// Otherwise, add client to active clients list
- finishConnectLocked(client, partial, oomScoreOffset);
+ finishConnectLocked(client, partial, oomScoreOffset, systemNativeClient);
}
client->setImageDumpMask(mImageDumpMask);
@@ -1937,7 +1940,7 @@
int32_t openLatencyMs = ns2ms(systemTime() - openTimeNs);
CameraServiceProxyWrapper::logOpen(cameraId, facing, clientPackageName,
- effectiveApiLevel, isNdk, openLatencyMs);
+ effectiveApiLevel, isNonSystemNdk, openLatencyMs);
{
Mutex::Autolock lock(mInjectionParametersLock);
@@ -2000,7 +2003,8 @@
kOfflineDevice + onlineClientDesc->getKey(), offlineClient, /*cost*/ 0,
/*conflictingKeys*/ std::set<String8>(), onlinePriority.getScore(),
onlineClientDesc->getOwnerId(), onlinePriority.getState(),
- /*ommScoreOffset*/ 0);
+ // native clients don't have offline processing support.
+ /*ommScoreOffset*/ 0, /*systemNativeClient*/false);
// Allow only one offline device per camera
auto incompatibleClients = mActiveClientManager.getIncompatibleClients(offlineClientDesc);
@@ -2335,6 +2339,13 @@
doUserSwitch(/*newUserIds*/ args);
break;
}
+ case ICameraService::EVENT_USB_DEVICE_ATTACHED:
+ case ICameraService::EVENT_USB_DEVICE_DETACHED: {
+ // Notify CameraProviderManager for lazy HALs
+ mCameraProviderManager->notifyUsbDeviceEvent(eventId,
+ std::to_string(args[0]));
+ break;
+ }
case ICameraService::EVENT_NONE:
default: {
ALOGW("%s: Received invalid system event from system_server: %d", __FUNCTION__,
@@ -2377,23 +2388,7 @@
ATRACE_CALL();
- using hardware::camera::provider::V2_5::DeviceState;
- hardware::hidl_bitfield<DeviceState> newDeviceState{};
- if (newState & ICameraService::DEVICE_STATE_BACK_COVERED) {
- newDeviceState |= DeviceState::BACK_COVERED;
- }
- if (newState & ICameraService::DEVICE_STATE_FRONT_COVERED) {
- newDeviceState |= DeviceState::FRONT_COVERED;
- }
- if (newState & ICameraService::DEVICE_STATE_FOLDED) {
- newDeviceState |= DeviceState::FOLDED;
- }
- // Only map vendor bits directly
- uint64_t vendorBits = static_cast<uint64_t>(newState) & 0xFFFFFFFF00000000l;
- newDeviceState |= vendorBits;
-
- ALOGV("%s: New device state 0x%" PRIx64, __FUNCTION__, newDeviceState);
- mCameraProviderManager->notifyDeviceStateChange(newDeviceState);
+ mCameraProviderManager->notifyDeviceStateChange(newState);
return Status::ok();
}
@@ -3180,7 +3175,7 @@
CameraService::Client::Client(const sp<CameraService>& cameraService,
const sp<ICameraClient>& cameraClient,
- const String16& clientPackageName,
+ const String16& clientPackageName, bool systemNativeClient,
const std::optional<String16>& clientFeatureId,
const String8& cameraIdStr,
int api1CameraId, int cameraFacing, int sensorOrientation,
@@ -3188,7 +3183,7 @@
int servicePid) :
CameraService::BasicClient(cameraService,
IInterface::asBinder(cameraClient),
- clientPackageName, clientFeatureId,
+ clientPackageName, systemNativeClient, clientFeatureId,
cameraIdStr, cameraFacing, sensorOrientation,
clientPid, clientUid,
servicePid),
@@ -3218,13 +3213,14 @@
CameraService::BasicClient::BasicClient(const sp<CameraService>& cameraService,
const sp<IBinder>& remoteCallback,
- const String16& clientPackageName, const std::optional<String16>& clientFeatureId,
- const String8& cameraIdStr, int cameraFacing, int sensorOrientation,
- int clientPid, uid_t clientUid,
+ const String16& clientPackageName, bool nativeClient,
+ const std::optional<String16>& clientFeatureId, const String8& cameraIdStr,
+ int cameraFacing, int sensorOrientation, int clientPid, uid_t clientUid,
int servicePid):
mDestructionStarted(false),
mCameraIdStr(cameraIdStr), mCameraFacing(cameraFacing), mOrientation(sensorOrientation),
- mClientPackageName(clientPackageName), mClientFeatureId(clientFeatureId),
+ mClientPackageName(clientPackageName), mSystemNativeClient(nativeClient),
+ mClientFeatureId(clientFeatureId),
mClientPid(clientPid), mClientUid(clientUid),
mServicePid(servicePid),
mDisconnected(false), mUidIsTrusted(false),
@@ -3267,7 +3263,19 @@
}
mClientPackageName = packages[0];
}
- if (getCurrentServingCall() != BinderCallType::HWBINDER) {
+
+ // There are 2 scenarios in which a client won't have AppOps operations
+ // (both scenarios : native clients)
+ // 1) It's an system native client*, the package name will be empty
+ // and it will return from this function in the previous if condition
+ // (This is the same as the previously existing behavior).
+ // 2) It is a system native client, but its package name has been
+ // modified for debugging, however it still must not use AppOps since
+ // the package name is not a real one.
+ //
+ // * system native client - native client with UID < AID_APP_START. It
+ // doesn't exclude clients not on the system partition.
+ if (!mSystemNativeClient) {
mAppOpsManager = std::make_unique<AppOpsManager>();
}
@@ -4089,23 +4097,23 @@
CameraService::DescriptorPtr CameraService::CameraClientManager::makeClientDescriptor(
const String8& key, const sp<BasicClient>& value, int32_t cost,
const std::set<String8>& conflictingKeys, int32_t score, int32_t ownerId,
- int32_t state, int32_t oomScoreOffset) {
+ int32_t state, int32_t oomScoreOffset, bool systemNativeClient) {
- bool isVendorClient = getCurrentServingCall() == BinderCallType::HWBINDER;
- int32_t score_adj = isVendorClient ? kVendorClientScore : score;
- int32_t state_adj = isVendorClient ? kVendorClientState: state;
+ int32_t score_adj = systemNativeClient ? kSystemNativeClientScore : score;
+ int32_t state_adj = systemNativeClient ? kSystemNativeClientState: state;
return std::make_shared<resource_policy::ClientDescriptor<String8, sp<BasicClient>>>(
- key, value, cost, conflictingKeys, score_adj, ownerId, state_adj, isVendorClient,
- oomScoreOffset);
+ key, value, cost, conflictingKeys, score_adj, ownerId, state_adj,
+ systemNativeClient, oomScoreOffset);
}
CameraService::DescriptorPtr CameraService::CameraClientManager::makeClientDescriptor(
const sp<BasicClient>& value, const CameraService::DescriptorPtr& partial,
- int32_t oomScoreOffset) {
+ int32_t oomScoreOffset, bool systemNativeClient) {
return makeClientDescriptor(partial->getKey(), value, partial->getCost(),
partial->getConflicting(), partial->getPriority().getScore(),
- partial->getOwnerId(), partial->getPriority().getState(), oomScoreOffset);
+ partial->getOwnerId(), partial->getPriority().getState(), oomScoreOffset,
+ systemNativeClient);
}
// ----------------------------------------------------------------------------
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 701d6b7..95d5101 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -106,19 +106,19 @@
// HAL Callbacks - implements CameraProviderManager::StatusListener
virtual void onDeviceStatusChanged(const String8 &cameraId,
- hardware::camera::common::V1_0::CameraDeviceStatus newHalStatus) override;
+ CameraDeviceStatus newHalStatus) override;
virtual void onDeviceStatusChanged(const String8 &cameraId,
const String8 &physicalCameraId,
- hardware::camera::common::V1_0::CameraDeviceStatus newHalStatus) override;
+ CameraDeviceStatus newHalStatus) override;
// This method may hold CameraProviderManager::mInterfaceMutex as a part
// of calling getSystemCameraKind() internally. Care should be taken not to
// directly / indirectly call this from callers who also hold
// mInterfaceMutex.
virtual void onTorchStatusChanged(const String8& cameraId,
- hardware::camera::common::V1_0::TorchModeStatus newStatus) override;
+ TorchModeStatus newStatus) override;
// Does not hold CameraProviderManager::mInterfaceMutex.
virtual void onTorchStatusChanged(const String8& cameraId,
- hardware::camera::common::V1_0::TorchModeStatus newStatus,
+ TorchModeStatus newStatus,
SystemCameraKind kind) override;
virtual void onNewProviderRegistered() override;
@@ -350,6 +350,7 @@
BasicClient(const sp<CameraService>& cameraService,
const sp<IBinder>& remoteCallback,
const String16& clientPackageName,
+ bool nativeClient,
const std::optional<String16>& clientFeatureId,
const String8& cameraIdStr,
int cameraFacing,
@@ -372,6 +373,7 @@
const int mCameraFacing;
const int mOrientation;
String16 mClientPackageName;
+ bool mSystemNativeClient;
std::optional<String16> mClientFeatureId;
pid_t mClientPid;
const uid_t mClientUid;
@@ -459,6 +461,7 @@
Client(const sp<CameraService>& cameraService,
const sp<hardware::ICameraClient>& cameraClient,
const String16& clientPackageName,
+ bool systemNativeClient,
const std::optional<String16>& clientFeatureId,
const String8& cameraIdStr,
int api1CameraId,
@@ -542,14 +545,15 @@
*/
static DescriptorPtr makeClientDescriptor(const String8& key, const sp<BasicClient>& value,
int32_t cost, const std::set<String8>& conflictingKeys, int32_t score,
- int32_t ownerId, int32_t state, int oomScoreOffset);
+ int32_t ownerId, int32_t state, int oomScoreOffset, bool systemNativeClient);
/**
* Make a ClientDescriptor object wrapping the given BasicClient strong pointer with
* values intialized from a prior ClientDescriptor.
*/
static DescriptorPtr makeClientDescriptor(const sp<BasicClient>& value,
- const CameraService::DescriptorPtr& partial, int oomScoreOffset);
+ const CameraService::DescriptorPtr& partial, int oomScoreOffset,
+ bool systemNativeClient);
}; // class CameraClientManager
@@ -558,8 +562,6 @@
private:
- typedef hardware::camera::common::V1_0::CameraDeviceStatus CameraDeviceStatus;
-
/**
* Typesafe version of device status, containing both the HAL-layer and the service interface-
* layer values.
@@ -785,7 +787,7 @@
// Only call with with mServiceLock held.
status_t handleEvictionsLocked(const String8& cameraId, int clientPid,
apiLevel effectiveApiLevel, const sp<IBinder>& remoteCallback, const String8& packageName,
- int scoreOffset,
+ int scoreOffset, bool systemNativeClient,
/*out*/
sp<BasicClient>* client,
std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<BasicClient>>>* partial);
@@ -817,7 +819,7 @@
// Single implementation shared between the various connect calls
template<class CALLBACK, class CLIENT>
binder::Status connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
- int api1CameraId, const String16& clientPackageName,
+ int api1CameraId, const String16& clientPackageName, bool systemNativeClient,
const std::optional<String16>& clientFeatureId, int clientUid, int clientPid,
apiLevel effectiveApiLevel, bool shimUpdateOnly, int scoreOffset, int targetSdkVersion,
/*out*/sp<CLIENT>& device);
@@ -894,7 +896,7 @@
* This method must be called with mServiceLock held.
*/
void finishConnectLocked(const sp<BasicClient>& client, const DescriptorPtr& desc,
- int oomScoreOffset);
+ int oomScoreOffset, bool systemNativeClient);
/**
* Returns the underlying camera Id string mapped to a camera id int
@@ -1102,7 +1104,7 @@
// guard mTorchUidMap
Mutex mTorchUidMapMutex;
// camera id -> torch status
- KeyedVector<String8, hardware::camera::common::V1_0::TorchModeStatus>
+ KeyedVector<String8, TorchModeStatus>
mTorchStatusMap;
// camera id -> torch client binder
// only store the last client that turns on each camera's torch mode
@@ -1116,16 +1118,16 @@
// handle torch mode status change and invoke callbacks. mTorchStatusMutex
// should be locked.
void onTorchStatusChangedLocked(const String8& cameraId,
- hardware::camera::common::V1_0::TorchModeStatus newStatus,
+ TorchModeStatus newStatus,
SystemCameraKind systemCameraKind);
// get a camera's torch status. mTorchStatusMutex should be locked.
status_t getTorchStatusLocked(const String8 &cameraId,
- hardware::camera::common::V1_0::TorchModeStatus *status) const;
+ TorchModeStatus *status) const;
// set a camera's torch status. mTorchStatusMutex should be locked.
status_t setTorchStatusLocked(const String8 &cameraId,
- hardware::camera::common::V1_0::TorchModeStatus status);
+ TorchModeStatus status);
// notify physical camera status when the physical camera is public.
// Expects mStatusListenerLock to be locked.
@@ -1228,22 +1230,21 @@
static binder::Status makeClient(const sp<CameraService>& cameraService,
const sp<IInterface>& cameraCb, const String16& packageName,
- const std::optional<String16>& featureId, const String8& cameraId, int api1CameraId,
- int facing, int sensorOrientation, int clientPid, uid_t clientUid, int servicePid,
- int deviceVersion, apiLevel effectiveApiLevel, bool overrideForPerfClass,
- /*out*/sp<BasicClient>* client);
+ bool systemNativeClient, const std::optional<String16>& featureId,
+ const String8& cameraId, int api1CameraId, int facing, int sensorOrientation,
+ int clientPid, uid_t clientUid, int servicePid, int deviceVersion,
+ apiLevel effectiveApiLevel, bool overrideForPerfClass, /*out*/sp<BasicClient>* client);
status_t checkCameraAccess(const String16& opPackageName);
static String8 toString(std::set<userid_t> intSet);
- static int32_t mapToInterface(hardware::camera::common::V1_0::TorchModeStatus status);
- static StatusInternal mapToInternal(hardware::camera::common::V1_0::CameraDeviceStatus status);
+ static int32_t mapToInterface(TorchModeStatus status);
+ static StatusInternal mapToInternal(CameraDeviceStatus status);
static int32_t mapToInterface(StatusInternal status);
void broadcastTorchModeStatus(const String8& cameraId,
- hardware::camera::common::V1_0::TorchModeStatus status,
- SystemCameraKind systemCameraKind);
+ TorchModeStatus status, SystemCameraKind systemCameraKind);
void broadcastTorchStrengthLevel(const String8& cameraId, int32_t newTorchStrengthLevel);
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 8c72bd7..5fcd43e 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -60,9 +60,10 @@
uid_t clientUid,
int servicePid,
bool overrideForPerfClass):
- Camera2ClientBase(cameraService, cameraClient, clientPackageName, clientFeatureId,
- cameraDeviceId, api1CameraId, cameraFacing, sensorOrientation,
- clientPid, clientUid, servicePid, overrideForPerfClass, /*legacyClient*/ true),
+ Camera2ClientBase(cameraService, cameraClient, clientPackageName,
+ false/*systemNativeClient - since no ndk for api1*/, clientFeatureId,
+ cameraDeviceId, api1CameraId, cameraFacing, sensorOrientation, clientPid,
+ clientUid, servicePid, overrideForPerfClass, /*legacyClient*/ true),
mParameters(api1CameraId, cameraFacing)
{
ATRACE_CALL();
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index a406e62..9a7ada2 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -75,23 +75,43 @@
// Treat the H.264 max size as the max supported video size.
MediaProfiles *videoEncoderProfiles = MediaProfiles::getInstance();
Vector<video_encoder> encoders = videoEncoderProfiles->getVideoEncoders();
+ int32_t minVideoWidth = MAX_PREVIEW_WIDTH;
+ int32_t minVideoHeight = MAX_PREVIEW_HEIGHT;
int32_t maxVideoWidth = 0;
int32_t maxVideoHeight = 0;
for (size_t i = 0; i < encoders.size(); i++) {
- int width = videoEncoderProfiles->getVideoEncoderParamByName(
+ int w0 = videoEncoderProfiles->getVideoEncoderParamByName(
+ "enc.vid.width.min", encoders[i]);
+ int h0 = videoEncoderProfiles->getVideoEncoderParamByName(
+ "enc.vid.height.min", encoders[i]);
+ int w1 = videoEncoderProfiles->getVideoEncoderParamByName(
"enc.vid.width.max", encoders[i]);
- int height = videoEncoderProfiles->getVideoEncoderParamByName(
+ int h1 = videoEncoderProfiles->getVideoEncoderParamByName(
"enc.vid.height.max", encoders[i]);
- // Treat width/height separately here to handle the case where different
- // profile might report max size of different aspect ratio
- if (width > maxVideoWidth) {
- maxVideoWidth = width;
+ // Assume the min size is 0 if it's not reported by encoder
+ if (w0 == -1) {
+ w0 = 0;
}
- if (height > maxVideoHeight) {
- maxVideoHeight = height;
+ if (h0 == -1) {
+ h0 = 0;
+ }
+ // Treat width/height separately here to handle the case where different
+ // profile might report min/max size of different aspect ratio
+ if (w0 < minVideoWidth) {
+ minVideoWidth = w0;
+ }
+ if (h0 < minVideoHeight) {
+ minVideoHeight = h0;
+ }
+ if (w1 > maxVideoWidth) {
+ maxVideoWidth = w1;
+ }
+ if (h1 > maxVideoHeight) {
+ maxVideoHeight = h1;
}
}
- // This is just an upper bound and may not be an actually valid video size
+ // These are upper/lower bounds and may not be an actually valid video size
+ const Size VIDEO_SIZE_LOWER_BOUND = {minVideoWidth, minVideoHeight};
Size videoSizeUpperBound = {maxVideoWidth, maxVideoHeight};
if (fastInfo.supportsPreferredConfigs) {
@@ -99,9 +119,10 @@
videoSizeUpperBound = getMaxSize(getPreferredVideoSizes());
}
- res = getFilteredSizes(maxPreviewSize, &availablePreviewSizes);
+ res = getFilteredSizes(Size{0, 0}, maxPreviewSize, &availablePreviewSizes);
if (res != OK) return res;
- res = getFilteredSizes(videoSizeUpperBound, &availableVideoSizes);
+ res = getFilteredSizes(
+ VIDEO_SIZE_LOWER_BOUND, videoSizeUpperBound, &availableVideoSizes);
if (res != OK) return res;
// Select initial preview and video size that's under the initial bound and
@@ -1055,7 +1076,8 @@
if (fastInfo.supportsPreferredConfigs) {
previewSizeBound = getMaxSize(getPreferredPreviewSizes());
}
- status_t res = getFilteredSizes(previewSizeBound, &supportedPreviewSizes);
+ status_t res = getFilteredSizes(
+ Size{0, 0}, previewSizeBound, &supportedPreviewSizes);
if (res != OK) return res;
for (size_t i=0; i < availableFpsRanges.count; i += 2) {
if (!isFpsSupported(supportedPreviewSizes,
@@ -2998,7 +3020,8 @@
}
}
-status_t Parameters::getFilteredSizes(Size limit, Vector<Size> *sizes) {
+status_t Parameters::getFilteredSizes(const Size &lower, const Size &upper,
+ Vector<Size> *sizes) {
if (info == NULL) {
ALOGE("%s: Static metadata is not initialized", __FUNCTION__);
return NO_INIT;
@@ -3014,7 +3037,8 @@
const StreamConfiguration &sc = scs[i];
if (sc.isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
sc.format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED &&
- ((sc.width * sc.height) <= (limit.width * limit.height))) {
+ ((sc.width * sc.height) >= (lower.width * lower.height)) &&
+ ((sc.width * sc.height) <= (upper.width * upper.height))) {
int64_t minFrameDuration = getMinFrameDurationNs(
{sc.width, sc.height}, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
if (minFrameDuration > MAX_PREVIEW_RECORD_DURATION_NS) {
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index 1b2ceda..263025e 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -396,9 +396,10 @@
Vector<Size> availablePreviewSizes;
Vector<Size> availableVideoSizes;
- // Get size list (that are no larger than limit) from static metadata.
+ // Get size list (that fall within lower/upper bounds) from static metadata.
// This method filtered size with minFrameDuration < MAX_PREVIEW_RECORD_DURATION_NS
- status_t getFilteredSizes(Size limit, Vector<Size> *sizes);
+ status_t getFilteredSizes(const Size &lower, const Size &upper,
+ Vector<Size> *sizes);
// Get max size (from the size array) that matches the given aspect ratio.
Size getMaxSizeForRatio(float ratio, const int32_t* sizeArray, size_t count);
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index a7ebcf4..1020c13 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -58,6 +58,7 @@
const sp<CameraService>& cameraService,
const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
const String16& clientPackageName,
+ bool systemNativeClient,
const std::optional<String16>& clientFeatureId,
const String8& cameraId,
int api1CameraId,
@@ -69,6 +70,7 @@
BasicClient(cameraService,
IInterface::asBinder(remoteCallback),
clientPackageName,
+ systemNativeClient,
clientFeatureId,
cameraId,
cameraFacing,
@@ -86,6 +88,7 @@
CameraDeviceClient::CameraDeviceClient(const sp<CameraService>& cameraService,
const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
const String16& clientPackageName,
+ bool systemNativeClient,
const std::optional<String16>& clientFeatureId,
const String8& cameraId,
int cameraFacing,
@@ -94,8 +97,8 @@
uid_t clientUid,
int servicePid,
bool overrideForPerfClass) :
- Camera2ClientBase(cameraService, remoteCallback, clientPackageName, clientFeatureId,
- cameraId, /*API1 camera ID*/ -1, cameraFacing, sensorOrientation,
+ Camera2ClientBase(cameraService, remoteCallback, clientPackageName, systemNativeClient,
+ clientFeatureId, cameraId, /*API1 camera ID*/ -1, cameraFacing, sensorOrientation,
clientPid, clientUid, servicePid, overrideForPerfClass),
mInputStream(),
mStreamingRequestId(REQUEST_ID_NONE),
@@ -145,9 +148,9 @@
ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
if (entry.count > 0) {
- const auto it = std::find(entry.data.i32, entry.data.i32 + entry.count,
+ const auto it = std::find(entry.data.u8, entry.data.u8 + entry.count,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT);
- if (it != entry.data.i32 + entry.count) {
+ if (it != entry.data.u8 + entry.count) {
entry = deviceInfo.find(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP);
if (entry.count > 0 || ((entry.count % 2) != 0)) {
int standardBitmap = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD;
@@ -206,6 +209,7 @@
int compositeIdx;
int idx = mStreamMap.indexOfKey(IInterface::asBinder(gbp));
+ Mutex::Autolock l(mCompositeLock);
// Trying to submit request with surface that wasn't created
if (idx == NAME_NOT_FOUND) {
ALOGE("%s: Camera %s: Tried to submit a request with a surface that"
@@ -640,6 +644,7 @@
offlineStreamIds->clear();
mDevice->getOfflineStreamIds(offlineStreamIds);
+ Mutex::Autolock l(mCompositeLock);
for (size_t i = 0; i < mCompositeStreamMap.size(); ++i) {
err = mCompositeStreamMap.valueAt(i)->configureStream();
if (err != OK) {
@@ -710,27 +715,9 @@
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
- hardware::camera::device::V3_8::StreamConfiguration streamConfiguration;
- bool earlyExit = false;
- camera3::metadataGetter getMetadata = [this](const String8 &id, bool /*overrideForPerfClass*/) {
- return mDevice->infoPhysical(id);};
- std::vector<std::string> physicalCameraIds;
- mProviderManager->isLogicalCamera(mCameraIdStr.string(), &physicalCameraIds);
- res = SessionConfigurationUtils::convertToHALStreamCombination(sessionConfiguration,
- mCameraIdStr, mDevice->info(), getMetadata, physicalCameraIds, streamConfiguration,
- mOverrideForPerfClass, &earlyExit);
- if (!res.isOk()) {
- return res;
- }
-
- if (earlyExit) {
- *status = false;
- return binder::Status::ok();
- }
-
*status = false;
ret = mProviderManager->isSessionConfigurationSupported(mCameraIdStr.string(),
- streamConfiguration, status);
+ sessionConfiguration, mOverrideForPerfClass, status);
switch (ret) {
case OK:
// Expected, do nothing.
@@ -792,6 +779,7 @@
}
}
+ Mutex::Autolock l(mCompositeLock);
for (size_t i = 0; i < mCompositeStreamMap.size(); ++i) {
if (streamId == mCompositeStreamMap.valueAt(i)->getStreamId()) {
compositeIndex = i;
@@ -830,6 +818,7 @@
}
if (compositeIndex != NAME_NOT_FOUND) {
+ Mutex::Autolock l(mCompositeLock);
status_t ret;
if ((ret = mCompositeStreamMap.valueAt(compositeIndex)->deleteStream())
!= OK) {
@@ -874,6 +863,9 @@
bool deferredConsumerOnly = deferredConsumer && numBufferProducers == 0;
bool isMultiResolution = outputConfiguration.isMultiResolution();
int dynamicRangeProfile = outputConfiguration.getDynamicRangeProfile();
+ int streamUseCase = outputConfiguration.getStreamUseCase();
+ int timestampBase = outputConfiguration.getTimestampBase();
+ int mirrorMode = outputConfiguration.getMirrorMode();
res = SessionConfigurationUtils::checkSurfaceType(numBufferProducers, deferredConsumer,
outputConfiguration.getSurfaceType());
@@ -917,7 +909,8 @@
sp<Surface> surface;
res = SessionConfigurationUtils::createSurfaceFromGbp(streamInfo,
isStreamInfoValid, surface, bufferProducer, mCameraIdStr,
- mDevice->infoPhysical(physicalCameraId), sensorPixelModesUsed, dynamicRangeProfile);
+ mDevice->infoPhysical(physicalCameraId), sensorPixelModesUsed, dynamicRangeProfile,
+ streamUseCase, timestampBase, mirrorMode);
if (!res.isOk())
return res;
@@ -953,6 +946,7 @@
&streamId, physicalCameraId, streamInfo.sensorPixelModesUsed, &surfaceIds,
outputConfiguration.getSurfaceSetID(), isShared, isMultiResolution);
if (err == OK) {
+ Mutex::Autolock l(mCompositeLock);
mCompositeStreamMap.add(IInterface::asBinder(surfaces[0]->getIGraphicBufferProducer()),
compositeStream);
}
@@ -962,7 +956,8 @@
static_cast<camera_stream_rotation_t>(outputConfiguration.getRotation()),
&streamId, physicalCameraId, streamInfo.sensorPixelModesUsed, &surfaceIds,
outputConfiguration.getSurfaceSetID(), isShared, isMultiResolution,
- streamInfo.dynamicRangeProfile);
+ /*consumerUsage*/0, streamInfo.dynamicRangeProfile, streamInfo.streamUseCase,
+ streamInfo.timestampBase, streamInfo.mirrorMode);
}
if (err != OK) {
@@ -988,7 +983,7 @@
streamInfo.height, streamInfo.format);
// Set transform flags to ensure preview to be rotated correctly.
- res = setStreamTransformLocked(streamId);
+ res = setStreamTransformLocked(streamId, streamInfo.mirrorMode);
// Fill in mHighResolutionCameraIdToStreamIdSet map
const String8 &cameraIdUsed =
@@ -1057,7 +1052,9 @@
&surfaceIds,
outputConfiguration.getSurfaceSetID(), isShared,
outputConfiguration.isMultiResolution(), consumerUsage,
- outputConfiguration.getDynamicRangeProfile());
+ outputConfiguration.getDynamicRangeProfile(),
+ outputConfiguration.getStreamUseCase(),
+ outputConfiguration.getMirrorMode());
if (err != OK) {
res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
@@ -1071,14 +1068,17 @@
mStreamInfoMap.emplace(std::piecewise_construct, std::forward_as_tuple(streamId),
std::forward_as_tuple(width, height, format, dataSpace, consumerUsage,
overriddenSensorPixelModesUsed,
- outputConfiguration.getDynamicRangeProfile()));
+ outputConfiguration.getDynamicRangeProfile(),
+ outputConfiguration.getStreamUseCase(),
+ outputConfiguration.getTimestampBase(),
+ outputConfiguration.getMirrorMode()));
ALOGV("%s: Camera %s: Successfully created a new stream ID %d for a deferred surface"
" (%d x %d) stream with format 0x%x.",
__FUNCTION__, mCameraIdStr.string(), streamId, width, height, format);
// Set transform flags to ensure preview to be rotated correctly.
- res = setStreamTransformLocked(streamId);
+ res = setStreamTransformLocked(streamId, outputConfiguration.getMirrorMode());
*newStreamId = streamId;
// Fill in mHighResolutionCameraIdToStreamIdSet
@@ -1092,7 +1092,7 @@
return res;
}
-binder::Status CameraDeviceClient::setStreamTransformLocked(int streamId) {
+binder::Status CameraDeviceClient::setStreamTransformLocked(int streamId, int mirrorMode) {
int32_t transform = 0;
status_t err;
binder::Status res;
@@ -1101,7 +1101,7 @@
return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
}
- err = getRotationTransformLocked(&transform);
+ err = getRotationTransformLocked(mirrorMode, &transform);
if (err != OK) {
// Error logged by getRotationTransformLocked.
return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
@@ -1259,15 +1259,18 @@
}
const std::vector<int32_t> &sensorPixelModesUsed =
outputConfiguration.getSensorPixelModesUsed();
-
+ int streamUseCase = outputConfiguration.getStreamUseCase();
+ int timestampBase = outputConfiguration.getTimestampBase();
int dynamicRangeProfile = outputConfiguration.getDynamicRangeProfile();
+ int mirrorMode = outputConfiguration.getMirrorMode();
for (size_t i = 0; i < newOutputsMap.size(); i++) {
OutputStreamInfo outInfo;
sp<Surface> surface;
res = SessionConfigurationUtils::createSurfaceFromGbp(outInfo,
/*isStreamInfoValid*/ false, surface, newOutputsMap.valueAt(i), mCameraIdStr,
- mDevice->infoPhysical(physicalCameraId), sensorPixelModesUsed, dynamicRangeProfile);
+ mDevice->infoPhysical(physicalCameraId), sensorPixelModesUsed, dynamicRangeProfile,
+ streamUseCase, timestampBase, mirrorMode);
if (!res.isOk())
return res;
@@ -1625,6 +1628,9 @@
const std::vector<int32_t> &sensorPixelModesUsed =
outputConfiguration.getSensorPixelModesUsed();
int dynamicRangeProfile = outputConfiguration.getDynamicRangeProfile();
+ int streamUseCase= outputConfiguration.getStreamUseCase();
+ int timestampBase = outputConfiguration.getTimestampBase();
+ int mirrorMode = outputConfiguration.getMirrorMode();
for (auto& bufferProducer : bufferProducers) {
// Don't create multiple streams for the same target surface
ssize_t index = mStreamMap.indexOfKey(IInterface::asBinder(bufferProducer));
@@ -1637,7 +1643,8 @@
sp<Surface> surface;
res = SessionConfigurationUtils::createSurfaceFromGbp(mStreamInfoMap[streamId],
true /*isStreamInfoValid*/, surface, bufferProducer, mCameraIdStr,
- mDevice->infoPhysical(physicalId), sensorPixelModesUsed, dynamicRangeProfile);
+ mDevice->infoPhysical(physicalId), sensorPixelModesUsed, dynamicRangeProfile,
+ streamUseCase, timestampBase, mirrorMode);
if (!res.isOk())
return res;
@@ -1772,10 +1779,11 @@
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
+ Mutex::Autolock l(mCompositeLock);
bool isCompositeStream = false;
- for (const auto& gbp : mConfiguredOutputs[streamId].getGraphicBufferProducers()) {
+ for (const auto& gbp : mConfiguredOutputs.valueAt(index).getGraphicBufferProducers()) {
sp<Surface> s = new Surface(gbp, false /*controlledByApp*/);
- isCompositeStream = camera3::DepthCompositeStream::isDepthCompositeStream(s) |
+ isCompositeStream = camera3::DepthCompositeStream::isDepthCompositeStream(s) ||
camera3::HeicCompositeStream::isHeicCompositeStream(s);
if (isCompositeStream) {
auto compositeIdx = mCompositeStreamMap.indexOfKey(IInterface::asBinder(gbp));
@@ -1822,6 +1830,7 @@
mConfiguredOutputs.clear();
mDeferredStreams.clear();
mStreamInfoMap.clear();
+ Mutex::Autolock l(mCompositeLock);
mCompositeStreamMap.clear();
mInputStream = {false, 0, 0, 0, 0};
} else {
@@ -1917,11 +1926,16 @@
// Thread safe. Don't bother locking.
sp<hardware::camera2::ICameraDeviceCallbacks> remoteCb = getRemoteCallback();
- // Composites can have multiple internal streams. Error notifications coming from such internal
- // streams may need to remain within camera service.
bool skipClientNotification = false;
- for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
- skipClientNotification |= mCompositeStreamMap.valueAt(i)->onError(errorCode, resultExtras);
+ {
+ // Access to the composite stream map must be synchronized
+ Mutex::Autolock l(mCompositeLock);
+ // Composites can have multiple internal streams. Error notifications coming from such
+ // internal streams may need to remain within camera service.
+ for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
+ skipClientNotification |= mCompositeStreamMap.valueAt(i)->onError(errorCode,
+ resultExtras);
+ }
}
if ((remoteCb != 0) && (!skipClientNotification)) {
@@ -1961,6 +1975,8 @@
}
Camera2ClientBase::notifyShutter(resultExtras, timestamp);
+ // Access to the composite stream map must be synchronized
+ Mutex::Autolock l(mCompositeLock);
for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
mCompositeStreamMap.valueAt(i)->onShutter(resultExtras, timestamp);
}
@@ -1988,13 +2004,15 @@
nsecs_t startTime = systemTime();
ALOGV("Camera %s: Stopping processors", mCameraIdStr.string());
- mFrameProcessor->removeListener(camera2::FrameProcessorBase::FRAME_PROCESSOR_LISTENER_MIN_ID,
- camera2::FrameProcessorBase::FRAME_PROCESSOR_LISTENER_MAX_ID,
- /*listener*/this);
- mFrameProcessor->requestExit();
- ALOGV("Camera %s: Waiting for threads", mCameraIdStr.string());
- mFrameProcessor->join();
- ALOGV("Camera %s: Disconnecting device", mCameraIdStr.string());
+ if (mFrameProcessor.get() != nullptr) {
+ mFrameProcessor->removeListener(
+ camera2::FrameProcessorBase::FRAME_PROCESSOR_LISTENER_MIN_ID,
+ camera2::FrameProcessorBase::FRAME_PROCESSOR_LISTENER_MAX_ID, /*listener*/this);
+ mFrameProcessor->requestExit();
+ ALOGV("Camera %s: Waiting for threads", mCameraIdStr.string());
+ mFrameProcessor->join();
+ ALOGV("Camera %s: Disconnecting device", mCameraIdStr.string());
+ }
// WORKAROUND: HAL refuses to disconnect while there's streams in flight
{
@@ -2010,14 +2028,17 @@
}
}
- for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
- auto ret = mCompositeStreamMap.valueAt(i)->deleteInternalStreams();
- if (ret != OK) {
- ALOGE("%s: Failed removing composite stream %s (%d)", __FUNCTION__,
- strerror(-ret), ret);
+ {
+ Mutex::Autolock l(mCompositeLock);
+ for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
+ auto ret = mCompositeStreamMap.valueAt(i)->deleteInternalStreams();
+ if (ret != OK) {
+ ALOGE("%s: Failed removing composite stream %s (%d)", __FUNCTION__,
+ strerror(-ret), ret);
+ }
}
+ mCompositeStreamMap.clear();
}
- mCompositeStreamMap.clear();
Camera2ClientBase::detachDevice();
@@ -2037,6 +2058,8 @@
result.mPhysicalMetadatas);
}
+ // Access to the composite stream map must be synchronized
+ Mutex::Autolock l(mCompositeLock);
for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
mCompositeStreamMap.valueAt(i)->onResultAvailable(result);
}
@@ -2105,11 +2128,12 @@
return true;
}
-status_t CameraDeviceClient::getRotationTransformLocked(int32_t* transform) {
+status_t CameraDeviceClient::getRotationTransformLocked(int mirrorMode,
+ int32_t* transform) {
ALOGV("%s: begin", __FUNCTION__);
const CameraMetadata& staticInfo = mDevice->info();
- return CameraUtils::getRotationTransform(staticInfo, transform);
+ return CameraUtils::getRotationTransform(staticInfo, mirrorMode, transform);
}
binder::Status CameraDeviceClient::mapRequestTemplate(int templateId,
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 77cdf9c..6675e24 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -50,6 +50,7 @@
CameraDeviceClientBase(const sp<CameraService>& cameraService,
const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
const String16& clientPackageName,
+ bool systemNativeClient,
const std::optional<String16>& clientFeatureId,
const String8& cameraId,
int api1CameraId,
@@ -178,6 +179,7 @@
CameraDeviceClient(const sp<CameraService>& cameraService,
const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
const String16& clientPackageName,
+ bool clientPackageOverride,
const std::optional<String16>& clientFeatureId,
const String8& cameraId,
int cameraFacing,
@@ -227,7 +229,7 @@
virtual void detachDevice();
// Calculate the ANativeWindow transform from android.sensor.orientation
- status_t getRotationTransformLocked(/*out*/int32_t* transform);
+ status_t getRotationTransformLocked(int mirrorMode, /*out*/int32_t* transform);
bool isUltraHighResolutionSensor(const String8 &cameraId);
@@ -287,7 +289,7 @@
// Set the stream transform flags to automatically rotate the camera stream for preview use
// cases.
- binder::Status setStreamTransformLocked(int streamId);
+ binder::Status setStreamTransformLocked(int streamId, int mirrorMode);
// Utility method to insert the surface into SurfaceMap
binder::Status insertGbpLocked(const sp<IGraphicBufferProducer>& gbp,
@@ -339,6 +341,8 @@
// set of high resolution camera id (logical / physical)
std::unordered_set<std::string> mHighResolutionSensors;
+ // Synchronize access to 'mCompositeStreamMap'
+ Mutex mCompositeLock;
KeyedVector<sp<IBinder>, sp<CompositeStream>> mCompositeStreamMap;
sp<CameraProviderManager> mProviderManager;
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
index 920a176..ef1d2de 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
@@ -54,7 +54,8 @@
CameraService::BasicClient(
cameraService,
IInterface::asBinder(remoteCallback),
- clientPackageName, clientFeatureId,
+ // (v)ndk doesn't have offline session support
+ clientPackageName, /*overridePackageName*/false, clientFeatureId,
cameraIdStr, cameraFacing, sensorOrientation, clientPid, clientUid, servicePid),
mRemoteCallback(remoteCallback), mOfflineSession(session),
mCompositeStreamMap(offlineCompositeStreamMap) {}
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 5d17c11..a29f3a6 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -34,6 +34,8 @@
#include "api2/CameraDeviceClient.h"
#include "device3/Camera3Device.h"
+#include "device3/aidl/AidlCamera3Device.h"
+#include "device3/hidl/HidlCamera3Device.h"
#include "utils/CameraThreadState.h"
#include "utils/CameraServiceProxyWrapper.h"
@@ -47,6 +49,7 @@
const sp<CameraService>& cameraService,
const sp<TCamCallbacks>& remoteCallback,
const String16& clientPackageName,
+ bool systemNativeClient,
const std::optional<String16>& clientFeatureId,
const String8& cameraId,
int api1CameraId,
@@ -57,19 +60,19 @@
int servicePid,
bool overrideForPerfClass,
bool legacyClient):
- TClientBase(cameraService, remoteCallback, clientPackageName, clientFeatureId,
- cameraId, api1CameraId, cameraFacing, sensorOrientation, clientPid, clientUid,
- servicePid),
+ TClientBase(cameraService, remoteCallback, clientPackageName, systemNativeClient,
+ clientFeatureId, cameraId, api1CameraId, cameraFacing, sensorOrientation, clientPid,
+ clientUid, servicePid),
mSharedCameraCallbacks(remoteCallback),
mDeviceVersion(cameraService->getDeviceVersion(TClientBase::mCameraIdStr)),
- mDevice(new Camera3Device(cameraId, overrideForPerfClass, legacyClient)),
mDeviceActive(false), mApi1CameraId(api1CameraId)
{
ALOGI("Camera %s: Opened. Client: %s (PID %d, UID %d)", cameraId.string(),
String8(clientPackageName).string(), clientPid, clientUid);
mInitialClientPid = clientPid;
- LOG_ALWAYS_FATAL_IF(mDevice == 0, "Device should never be NULL here.");
+ mOverrideForPerfClass = overrideForPerfClass;
+ mLegacyClient = legacyClient;
}
template <typename TClientBase>
@@ -104,7 +107,28 @@
if (res != OK) {
return res;
}
-
+ IPCTransport providerTransport = IPCTransport::INVALID;
+ res = providerPtr->getCameraIdIPCTransport(TClientBase::mCameraIdStr.string(),
+ &providerTransport);
+ if (res != OK) {
+ return res;
+ }
+ switch (providerTransport) {
+ case IPCTransport::HIDL:
+ mDevice =
+ new HidlCamera3Device(TClientBase::mCameraIdStr, mOverrideForPerfClass,
+ mLegacyClient);
+ break;
+ case IPCTransport::AIDL:
+ mDevice =
+ new AidlCamera3Device(TClientBase::mCameraIdStr, mOverrideForPerfClass,
+ mLegacyClient);
+ break;
+ default:
+ ALOGE("%s Invalid transport for camera id %s", __FUNCTION__,
+ TClientBase::mCameraIdStr.string());
+ return NO_INIT;
+ }
if (mDevice == NULL) {
ALOGE("%s: Camera %s: No device connected",
__FUNCTION__, TClientBase::mCameraIdStr.string());
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index 4688502..182e6ef 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -48,6 +48,7 @@
Camera2ClientBase(const sp<CameraService>& cameraService,
const sp<TCamCallbacks>& remoteCallback,
const String16& clientPackageName,
+ bool systemNativeClient,
const std::optional<String16>& clientFeatureId,
const String8& cameraId,
int api1CameraId,
@@ -126,6 +127,8 @@
// The PID provided in the constructor call
pid_t mInitialClientPid;
+ bool mOverrideForPerfClass = false;
+ bool mLegacyClient = false;
virtual sp<IBinder> asBinderWrapper() {
return IInterface::asBinder(this);
@@ -145,9 +148,12 @@
const int mDeviceVersion;
- // Set to const to avoid mDevice being updated (update of sp<> is racy) during
- // dumpDevice (which is important to be lock free for debugging purpose)
- const sp<CameraDeviceBase> mDevice;
+ // Note: This was previously set to const to avoid mDevice being updated -
+ // b/112639939 (update of sp<> is racy) during dumpDevice (which is important to be lock free
+ // for debugging purpose). The const has been removed since CameraDeviceBase
+ // needs to be set during initializeImpl(). This must not be set / cleared
+ // anywhere else.
+ sp<CameraDeviceBase> mDevice;
/** Utility members */
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index e936cb6..bde0693 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -183,7 +183,10 @@
int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
bool isShared = false, bool isMultiResolution = false,
uint64_t consumerUsage = 0,
- int dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) = 0;
+ int dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
+ int streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
+ int timestampBase = OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
+ int mirrorMode = OutputConfiguration::MIRROR_MODE_AUTO) = 0;
/**
* Create an output stream of the requested size, format, rotation and
@@ -201,7 +204,10 @@
int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
bool isShared = false, bool isMultiResolution = false,
uint64_t consumerUsage = 0,
- int dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) = 0;
+ int dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
+ int streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
+ int timestampBase = OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
+ int mirrorMode = OutputConfiguration::MIRROR_MODE_AUTO) = 0;
/**
* Create an input stream of width, height, and format.
diff --git a/services/camera/libcameraservice/common/CameraProviderInfoTemplated.h b/services/camera/libcameraservice/common/CameraProviderInfoTemplated.h
new file mode 100644
index 0000000..db7692a
--- /dev/null
+++ b/services/camera/libcameraservice/common/CameraProviderInfoTemplated.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2022 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_SERVERS_CAMERA_CAMERAPROVIDERINFO_TEMPLATEDH
+#define ANDROID_SERVERS_CAMERA_CAMERAPROVIDERINFO_TEMPLATEDH
+
+#include "common/CameraProviderManager.h"
+
+namespace android {
+
+template <class VendorTagSectionVectorType, class VendorTagSectionType>
+status_t IdlVendorTagDescriptor::createDescriptorFromIdl(
+ const VendorTagSectionVectorType& vts,
+ sp<VendorTagDescriptor>& descriptor) {
+
+ int tagCount = 0;
+
+ for (size_t s = 0; s < vts.size(); s++) {
+ tagCount += vts[s].tags.size();
+ }
+
+ if (tagCount < 0 || tagCount > INT32_MAX) {
+ ALOGE("%s: tag count %d from vendor tag sections is invalid.", __FUNCTION__, tagCount);
+ return BAD_VALUE;
+ }
+
+ Vector<uint32_t> tagArray;
+ LOG_ALWAYS_FATAL_IF(tagArray.resize(tagCount) != tagCount,
+ "%s: too many (%u) vendor tags defined.", __FUNCTION__, tagCount);
+ sp<IdlVendorTagDescriptor> desc = new IdlVendorTagDescriptor();
+ desc->mTagCount = tagCount;
+
+ SortedVector<String8> sections;
+ KeyedVector<uint32_t, String8> tagToSectionMap;
+
+ int idx = 0;
+ for (size_t s = 0; s < vts.size(); s++) {
+ const VendorTagSectionType& section = vts[s];
+ const char *sectionName = section.sectionName.c_str();
+ if (sectionName == NULL) {
+ ALOGE("%s: no section name defined for vendor tag section %zu.", __FUNCTION__, s);
+ return BAD_VALUE;
+ }
+ String8 sectionString(sectionName);
+ sections.add(sectionString);
+
+ for (size_t j = 0; j < section.tags.size(); j++) {
+ uint32_t tag = section.tags[j].tagId;
+ if (tag < CAMERA_METADATA_VENDOR_TAG_BOUNDARY) {
+ ALOGE("%s: vendor tag %d not in vendor tag section.", __FUNCTION__, tag);
+ return BAD_VALUE;
+ }
+
+ tagArray.editItemAt(idx++) = section.tags[j].tagId;
+
+ const char *tagName = section.tags[j].tagName.c_str();
+ if (tagName == NULL) {
+ ALOGE("%s: no tag name defined for vendor tag %d.", __FUNCTION__, tag);
+ return BAD_VALUE;
+ }
+ desc->mTagToNameMap.add(tag, String8(tagName));
+ tagToSectionMap.add(tag, sectionString);
+
+ int tagType = (int) section.tags[j].tagType;
+ if (tagType < 0 || tagType >= NUM_TYPES) {
+ ALOGE("%s: tag type %d from vendor ops does not exist.", __FUNCTION__, tagType);
+ return BAD_VALUE;
+ }
+ desc->mTagToTypeMap.add(tag, tagType);
+ }
+ }
+
+ desc->mSections = sections;
+
+ for (size_t i = 0; i < tagArray.size(); ++i) {
+ uint32_t tag = tagArray[i];
+ String8 sectionString = tagToSectionMap.valueFor(tag);
+
+ // Set up tag to section index map
+ ssize_t index = sections.indexOf(sectionString);
+ LOG_ALWAYS_FATAL_IF(index < 0, "index %zd must be non-negative", index);
+ desc->mTagToSectionMap.add(tag, static_cast<uint32_t>(index));
+
+ // Set up reverse mapping
+ ssize_t reverseIndex = -1;
+ if ((reverseIndex = desc->mReverseMapping.indexOfKey(sectionString)) < 0) {
+ KeyedVector<String8, uint32_t>* nameMapper = new KeyedVector<String8, uint32_t>();
+ reverseIndex = desc->mReverseMapping.add(sectionString, nameMapper);
+ }
+ desc->mReverseMapping[reverseIndex]->add(desc->mTagToNameMap.valueFor(tag), tag);
+ }
+
+ descriptor = std::move(desc);
+ return OK;
+}
+
+
+} // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 5e8d188..c337eda 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -20,14 +20,18 @@
#include "CameraProviderManager.h"
+#include <aidl/android/hardware/camera/device/ICameraDevice.h>
#include <android/hardware/camera/device/3.8/ICameraDevice.h>
#include <algorithm>
#include <chrono>
#include "common/DepthPhotoProcessor.h"
+#include "hidl/HidlProviderInfo.h"
+#include "aidl/AidlProviderInfo.h"
#include <dlfcn.h>
#include <future>
#include <inttypes.h>
+#include <android/binder_manager.h>
#include <android/hidl/manager/1.2/IServiceManager.h>
#include <hidl/ServiceManagement.h>
#include <functional>
@@ -45,26 +49,58 @@
namespace android {
using namespace ::android::hardware::camera;
-using namespace ::android::hardware::camera::common::V1_0;
using namespace ::android::camera3;
+using android::hardware::camera::common::V1_0::Status;
+using namespace camera3::SessionConfigurationUtils;
using std::literals::chrono_literals::operator""s;
using hardware::camera2::utils::CameraIdAndSessionConfiguration;
-using hardware::camera::provider::V2_7::CameraIdAndStreamCombination;
namespace {
const bool kEnableLazyHal(property_get_bool("ro.camera.enableLazyHal", false));
+const std::string kExternalProviderName = "external/0";
} // anonymous namespace
const float CameraProviderManager::kDepthARTolerance = .1f;
-CameraProviderManager::HardwareServiceInteractionProxy
-CameraProviderManager::sHardwareServiceInteractionProxy{};
+// AIDL Devices start with major version 1, offset added to bring them up to HIDL.
+const uint16_t kAidlDeviceMajorOffset = 2;
+// AIDL Devices start with minor version 1, offset added to bring them up to HIDL.
+const uint16_t kAidlDeviceMinorOffset = 7;
+
+CameraProviderManager::HidlServiceInteractionProxyImpl
+CameraProviderManager::sHidlServiceInteractionProxy{};
CameraProviderManager::~CameraProviderManager() {
}
+const char* FrameworkTorchStatusToString(const TorchModeStatus& s) {
+ switch (s) {
+ case TorchModeStatus::NOT_AVAILABLE:
+ return "NOT_AVAILABLE";
+ case TorchModeStatus::AVAILABLE_OFF:
+ return "AVAILABLE_OFF";
+ case TorchModeStatus::AVAILABLE_ON:
+ return "AVAILABLE_ON";
+ }
+ ALOGW("Unexpected HAL torch mode status code %d", s);
+ return "UNKNOWN_STATUS";
+}
+
+const char* FrameworkDeviceStatusToString(const CameraDeviceStatus& s) {
+ switch (s) {
+ case CameraDeviceStatus::NOT_PRESENT:
+ return "NOT_PRESENT";
+ case CameraDeviceStatus::PRESENT:
+ return "PRESENT";
+ case CameraDeviceStatus::ENUMERATING:
+ return "ENUMERATING";
+ }
+ ALOGW("Unexpected HAL device status code %d", s);
+ return "UNKNOWN_STATUS";
+}
+
hardware::hidl_vec<hardware::hidl_string>
-CameraProviderManager::HardwareServiceInteractionProxy::listServices() {
+CameraProviderManager::HidlServiceInteractionProxyImpl::listServices() {
hardware::hidl_vec<hardware::hidl_string> ret;
auto manager = hardware::defaultServiceManager1_2();
if (manager != nullptr) {
@@ -76,20 +112,11 @@
return ret;
}
-status_t CameraProviderManager::initialize(wp<CameraProviderManager::StatusListener> listener,
- ServiceInteractionProxy* proxy) {
- std::lock_guard<std::mutex> lock(mInterfaceMutex);
- if (proxy == nullptr) {
- ALOGE("%s: No valid service interaction proxy provided", __FUNCTION__);
- return BAD_VALUE;
- }
- mListener = listener;
- mServiceProxy = proxy;
- mDeviceState = static_cast<hardware::hidl_bitfield<provider::V2_5::DeviceState>>(
- provider::V2_5::DeviceState::NORMAL);
-
+status_t CameraProviderManager::tryToInitAndAddHidlProvidersLocked(
+ HidlServiceInteractionProxy *hidlProxy) {
+ mHidlServiceProxy = hidlProxy;
// Registering will trigger notifications for all already-known providers
- bool success = mServiceProxy->registerForNotifications(
+ bool success = mHidlServiceProxy->registerForNotifications(
/* instance name, empty means no filter */ "",
this);
if (!success) {
@@ -98,14 +125,57 @@
return INVALID_OPERATION;
}
-
- for (const auto& instance : mServiceProxy->listServices()) {
- this->addProviderLocked(instance);
+ for (const auto& instance : mHidlServiceProxy->listServices()) {
+ this->addHidlProviderLocked(instance);
}
+ return OK;
+}
+
+static std::string getFullAidlProviderName(const std::string instance) {
+ std::string aidlHalServiceDescriptor =
+ std::string(aidl::android::hardware::camera::provider::ICameraProvider::descriptor);
+ return aidlHalServiceDescriptor + "/" + instance;
+}
+
+status_t CameraProviderManager::tryToAddAidlProvidersLocked() {
+ const char * aidlHalServiceDescriptor =
+ aidl::android::hardware::camera::provider::ICameraProvider::descriptor;
+ auto sm = defaultServiceManager();
+ auto aidlProviders = sm->getDeclaredInstances(
+ String16(aidlHalServiceDescriptor));
+ for (const auto &aidlInstance : aidlProviders) {
+ std::string aidlServiceName =
+ getFullAidlProviderName(std::string(String8(aidlInstance).c_str()));
+ auto res = sm->registerForNotifications(String16(aidlServiceName.c_str()), this);
+ if (res != OK) {
+ ALOGE("%s Unable to register for notifications with AIDL service manager",
+ __FUNCTION__);
+ return res;
+ }
+ addAidlProviderLocked(aidlServiceName);
+ }
+ return OK;
+}
+
+status_t CameraProviderManager::initialize(wp<CameraProviderManager::StatusListener> listener,
+ HidlServiceInteractionProxy* hidlProxy) {
+ std::lock_guard<std::mutex> lock(mInterfaceMutex);
+ if (hidlProxy == nullptr) {
+ ALOGE("%s: No valid service interaction proxy provided", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ mListener = listener;
+ mDeviceState = 0;
+ auto res = tryToInitAndAddHidlProvidersLocked(hidlProxy);
+ if (res != OK) {
+ // Logging done in called function;
+ return res;
+ }
+ res = tryToAddAidlProvidersLocked();
IPCThreadState::self()->flushCommands();
- return OK;
+ return res;
}
std::pair<int, int> CameraProviderManager::getCameraCount() const {
@@ -267,7 +337,7 @@
}
status_t CameraProviderManager::isSessionConfigurationSupported(const std::string& id,
- const hardware::camera::device::V3_8::StreamConfiguration &configuration,
+ const SessionConfiguration &configuration, bool overrideForPerfClass,
bool *status /*out*/) const {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
auto deviceInfo = findDeviceInfoLocked(id);
@@ -275,7 +345,22 @@
return NAME_NOT_FOUND;
}
- return deviceInfo->isSessionConfigurationSupported(configuration, status);
+ return deviceInfo->isSessionConfigurationSupported(configuration, overrideForPerfClass, status);
+}
+
+status_t CameraProviderManager::getCameraIdIPCTransport(const std::string &id,
+ IPCTransport *providerTransport) const {
+ std::lock_guard<std::mutex> lock(mInterfaceMutex);
+ auto deviceInfo = findDeviceInfoLocked(id);
+ if (deviceInfo == nullptr) {
+ return NAME_NOT_FOUND;
+ }
+ sp<ProviderInfo> parentProvider = deviceInfo->mParentProvider.promote();
+ if (parentProvider == nullptr) {
+ return DEAD_OBJECT;
+ }
+ *providerTransport = parentProvider->getIPCTransport();
+ return OK;
}
status_t CameraProviderManager::getCameraCharacteristics(const std::string &id,
@@ -284,6 +369,9 @@
return getCameraCharacteristicsLocked(id, overrideForPerfClass, characteristics);
}
+// Till hidl is removed from the android source tree, we use this for aidl as
+// well. We artificially give aidl camera device version 1 a major version 3 and minor
+// version 8.
status_t CameraProviderManager::getHighestSupportedVersion(const std::string &id,
hardware::hidl_version *v) {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
@@ -362,6 +450,22 @@
return false;
}
+template <class ProviderInfoType, class HalCameraProviderType>
+status_t CameraProviderManager::setTorchModeT(sp<ProviderInfo> &parentProvider,
+ std::shared_ptr<HalCameraProvider> *halCameraProvider) {
+ if (halCameraProvider == nullptr) {
+ return BAD_VALUE;
+ }
+ ProviderInfoType *idlProviderInfo = static_cast<ProviderInfoType *>(parentProvider.get());
+ auto idlInterface = idlProviderInfo->startProviderInterface();
+ if (idlInterface == nullptr) {
+ return DEAD_OBJECT;
+ }
+ *halCameraProvider =
+ std::make_shared<HalCameraProviderType>(idlInterface, idlInterface->descriptor);
+ return OK;
+}
+
status_t CameraProviderManager::setTorchMode(const std::string &id, bool enabled) {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
@@ -374,11 +478,26 @@
if (parentProvider == nullptr) {
return DEAD_OBJECT;
}
- const sp<provider::V2_4::ICameraProvider> interface = parentProvider->startProviderInterface();
- if (interface == nullptr) {
- return DEAD_OBJECT;
+ std::shared_ptr<HalCameraProvider> halCameraProvider = nullptr;
+ IPCTransport providerTransport = parentProvider->getIPCTransport();
+ status_t res = OK;
+ if (providerTransport == IPCTransport::HIDL) {
+ res = setTorchModeT<HidlProviderInfo, HidlHalCameraProvider>(parentProvider,
+ &halCameraProvider);
+ if (res != OK) {
+ return res;
+ }
+ } else if (providerTransport == IPCTransport::AIDL) {
+ res = setTorchModeT<AidlProviderInfo, AidlHalCameraProvider>(parentProvider,
+ &halCameraProvider);
+ if (res != OK) {
+ return res;
+ }
+ } else {
+ ALOGE("%s Invalid provider transport", __FUNCTION__);
+ return INVALID_OPERATION;
}
- saveRef(DeviceMode::TORCH, deviceInfo->mId, interface);
+ saveRef(DeviceMode::TORCH, deviceInfo->mId, halCameraProvider);
return deviceInfo->setTorchMode(enabled);
}
@@ -395,8 +514,72 @@
return OK;
}
-status_t CameraProviderManager::notifyDeviceStateChange(
- hardware::hidl_bitfield<provider::V2_5::DeviceState> newState) {
+sp<CameraProviderManager::ProviderInfo> CameraProviderManager::startExternalLazyProvider() const {
+ std::lock_guard<std::mutex> providerLock(mProviderLifecycleLock);
+ std::lock_guard<std::mutex> lock(mInterfaceMutex);
+
+ for (const auto& providerInfo : mProviders) {
+ if (providerInfo->isExternalLazyHAL()) {
+ if (!providerInfo->successfullyStartedProviderInterface()) {
+ return nullptr;
+ } else {
+ return providerInfo;
+ }
+ }
+ }
+ return nullptr;
+}
+
+status_t CameraProviderManager::notifyUsbDeviceEvent(int32_t eventId,
+ const std::string& usbDeviceId) {
+ if (!kEnableLazyHal) {
+ return OK;
+ }
+
+ ALOGV("notifySystemEvent: %d usbDeviceId : %s", eventId, usbDeviceId.c_str());
+
+ if (eventId == android::hardware::ICameraService::EVENT_USB_DEVICE_ATTACHED) {
+ sp<ProviderInfo> externalProvider = startExternalLazyProvider();
+ if (externalProvider != nullptr) {
+ auto usbDevices = mExternalUsbDevicesForProvider.first;
+ usbDevices.push_back(usbDeviceId);
+ mExternalUsbDevicesForProvider = {usbDevices, externalProvider};
+ }
+ } else if (eventId
+ == android::hardware::ICameraService::EVENT_USB_DEVICE_DETACHED) {
+ usbDeviceDetached(usbDeviceId);
+ }
+
+ return OK;
+}
+
+status_t CameraProviderManager::usbDeviceDetached(const std::string &usbDeviceId) {
+ std::lock_guard<std::mutex> providerLock(mProviderLifecycleLock);
+ std::lock_guard<std::mutex> interfaceLock(mInterfaceMutex);
+
+ auto usbDevices = mExternalUsbDevicesForProvider.first;
+ auto foundId = std::find(usbDevices.begin(), usbDevices.end(), usbDeviceId);
+ if (foundId != usbDevices.end()) {
+ sp<ProviderInfo> providerInfo = mExternalUsbDevicesForProvider.second;
+ if (providerInfo == nullptr) {
+ ALOGE("%s No valid external provider for USB device: %s",
+ __FUNCTION__,
+ usbDeviceId.c_str());
+ mExternalUsbDevicesForProvider = {std::vector<std::string>(), nullptr};
+ return DEAD_OBJECT;
+ } else {
+ mInterfaceMutex.unlock();
+ providerInfo->removeAllDevices();
+ mInterfaceMutex.lock();
+ mExternalUsbDevicesForProvider = {std::vector<std::string>(), nullptr};
+ }
+ } else {
+ return DEAD_OBJECT;
+ }
+ return OK;
+}
+
+status_t CameraProviderManager::notifyDeviceStateChange(int64_t newState) {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
mDeviceState = newState;
status_t res = OK;
@@ -422,7 +605,90 @@
return res;
}
-status_t CameraProviderManager::openSession(const std::string &id,
+status_t CameraProviderManager::openAidlSession(const std::string &id,
+ const std::shared_ptr<
+ aidl::android::hardware::camera::device::ICameraDeviceCallback>& callback,
+ /*out*/
+ std::shared_ptr<aidl::android::hardware::camera::device::ICameraDeviceSession> *session) {
+
+ std::lock_guard<std::mutex> lock(mInterfaceMutex);
+
+ auto deviceInfo = findDeviceInfoLocked(id,
+ /*minVersion*/ {3,0}, /*maxVersion*/ {4,0});
+ if (deviceInfo == nullptr) return NAME_NOT_FOUND;
+
+ auto *aidlDeviceInfo3 = static_cast<AidlProviderInfo::AidlDeviceInfo3*>(deviceInfo);
+ sp<ProviderInfo> parentProvider = deviceInfo->mParentProvider.promote();
+ if (parentProvider == nullptr) {
+ return DEAD_OBJECT;
+ }
+ auto provider =
+ static_cast<AidlProviderInfo *>(parentProvider.get())->startProviderInterface();
+ if (provider == nullptr) {
+ return DEAD_OBJECT;
+ }
+ std::shared_ptr<HalCameraProvider> halCameraProvider =
+ std::make_shared<AidlHalCameraProvider>(provider, provider->descriptor);
+ saveRef(DeviceMode::CAMERA, id, halCameraProvider);
+
+ auto interface = aidlDeviceInfo3->startDeviceInterface();
+ if (interface == nullptr) {
+ removeRef(DeviceMode::CAMERA, id);
+ return DEAD_OBJECT;
+ }
+
+ auto ret = interface->open(callback, session);
+ if (!ret.isOk()) {
+ removeRef(DeviceMode::CAMERA, id);
+ ALOGE("%s: Transaction error opening a session for camera device %s: %s",
+ __FUNCTION__, id.c_str(), ret.getMessage());
+ return DEAD_OBJECT;
+ }
+ return OK;
+}
+
+status_t CameraProviderManager::openAidlInjectionSession(const std::string &id,
+ const std::shared_ptr<
+ aidl::android::hardware::camera::device::ICameraDeviceCallback>& callback,
+ /*out*/
+ std::shared_ptr<
+ aidl::android::hardware::camera::device::ICameraInjectionSession> *session) {
+
+ std::lock_guard<std::mutex> lock(mInterfaceMutex);
+
+ auto deviceInfo = findDeviceInfoLocked(id);
+ if (deviceInfo == nullptr) return NAME_NOT_FOUND;
+
+ auto *aidlDeviceInfo3 = static_cast<AidlProviderInfo::AidlDeviceInfo3*>(deviceInfo);
+ sp<ProviderInfo> parentProvider = deviceInfo->mParentProvider.promote();
+ if (parentProvider == nullptr) {
+ return DEAD_OBJECT;
+ }
+ auto provider =
+ static_cast<AidlProviderInfo *>(parentProvider.get())->startProviderInterface();
+ if (provider == nullptr) {
+ return DEAD_OBJECT;
+ }
+ std::shared_ptr<HalCameraProvider> halCameraProvider =
+ std::make_shared<AidlHalCameraProvider>(provider, provider->descriptor);
+ saveRef(DeviceMode::CAMERA, id, halCameraProvider);
+
+ auto interface = aidlDeviceInfo3->startDeviceInterface();
+ if (interface == nullptr) {
+ return DEAD_OBJECT;
+ }
+
+ auto ret = interface->openInjectionSession(callback, session);
+ if (!ret.isOk()) {
+ removeRef(DeviceMode::CAMERA, id);
+ ALOGE("%s: Transaction error opening a session for camera device %s: %s",
+ __FUNCTION__, id.c_str(), ret.getMessage());
+ return DEAD_OBJECT;
+ }
+ return OK;
+}
+
+status_t CameraProviderManager::openHidlSession(const std::string &id,
const sp<device::V3_2::ICameraDeviceCallback>& callback,
/*out*/
sp<device::V3_2::ICameraDeviceSession> *session) {
@@ -433,21 +699,23 @@
/*minVersion*/ {3,0}, /*maxVersion*/ {4,0});
if (deviceInfo == nullptr) return NAME_NOT_FOUND;
- auto *deviceInfo3 = static_cast<ProviderInfo::DeviceInfo3*>(deviceInfo);
+ auto *hidlDeviceInfo3 = static_cast<HidlProviderInfo::HidlDeviceInfo3*>(deviceInfo);
sp<ProviderInfo> parentProvider = deviceInfo->mParentProvider.promote();
if (parentProvider == nullptr) {
return DEAD_OBJECT;
}
- const sp<provider::V2_4::ICameraProvider> provider = parentProvider->startProviderInterface();
+ const sp<provider::V2_4::ICameraProvider> provider =
+ static_cast<HidlProviderInfo *>(parentProvider.get())->startProviderInterface();
if (provider == nullptr) {
return DEAD_OBJECT;
}
- saveRef(DeviceMode::CAMERA, id, provider);
+ std::shared_ptr<HalCameraProvider> halCameraProvider =
+ std::make_shared<HidlHalCameraProvider>(provider, provider->descriptor);
+ saveRef(DeviceMode::CAMERA, id, halCameraProvider);
Status status;
hardware::Return<void> ret;
- auto interface = deviceInfo3->startDeviceInterface<
- CameraProviderManager::ProviderInfo::DeviceInfo3::InterfaceT>();
+ auto interface = hidlDeviceInfo3->startDeviceInterface();
if (interface == nullptr) {
return DEAD_OBJECT;
}
@@ -465,17 +733,18 @@
__FUNCTION__, id.c_str(), ret.description().c_str());
return DEAD_OBJECT;
}
- return mapToStatusT(status);
+ return HidlProviderInfo::mapToStatusT(status);
}
void CameraProviderManager::saveRef(DeviceMode usageType, const std::string &cameraId,
- sp<provider::V2_4::ICameraProvider> provider) {
+ std::shared_ptr<HalCameraProvider> provider) {
if (!kEnableLazyHal) {
return;
}
- ALOGV("Saving camera provider %s for camera device %s", provider->descriptor, cameraId.c_str());
+ ALOGV("Saving camera provider %s for camera device %s", provider->mDescriptor.c_str(),
+ cameraId.c_str());
std::lock_guard<std::mutex> lock(mProviderInterfaceMapLock);
- std::unordered_map<std::string, sp<provider::V2_4::ICameraProvider>> *primaryMap, *alternateMap;
+ std::unordered_map<std::string, std::shared_ptr<HalCameraProvider>> *primaryMap, *alternateMap;
if (usageType == DeviceMode::TORCH) {
primaryMap = &mTorchProviderByCameraId;
alternateMap = &mCameraProviderByCameraId;
@@ -498,7 +767,7 @@
return;
}
ALOGV("Removing camera device %s", cameraId.c_str());
- std::unordered_map<std::string, sp<provider::V2_4::ICameraProvider>> *providerMap;
+ std::unordered_map<std::string, std::shared_ptr<HalCameraProvider>> *providerMap;
if (usageType == DeviceMode::TORCH) {
providerMap = &mTorchProviderByCameraId;
} else {
@@ -523,6 +792,26 @@
}
}
+// We ignore sp<IBinder> param here since we need std::shared_ptr<...> which
+// will be retrieved through the ndk api through addAidlProviderLocked ->
+// tryToInitializeAidlProvider.
+void CameraProviderManager::onServiceRegistration(const String16 &name, const sp<IBinder>&) {
+ status_t res = OK;
+ std::lock_guard<std::mutex> providerLock(mProviderLifecycleLock);
+ {
+ std::lock_guard<std::mutex> lock(mInterfaceMutex);
+
+ res = addAidlProviderLocked(String8(name).c_str());
+ }
+
+ sp<StatusListener> listener = getStatusListener();
+ if (nullptr != listener.get() && res == OK) {
+ listener->onNewProviderRegistered();
+ }
+
+ IPCThreadState::self()->flushCommands();
+}
+
hardware::Return<void> CameraProviderManager::onRegistration(
const hardware::hidl_string& /*fqName*/,
const hardware::hidl_string& name,
@@ -532,7 +821,7 @@
{
std::lock_guard<std::mutex> lock(mInterfaceMutex);
- res = addProviderLocked(name, preexisting);
+ res = addHidlProviderLocked(name, preexisting);
}
sp<StatusListener> listener = getStatusListener();
@@ -554,6 +843,59 @@
return OK;
}
+void CameraProviderManager::ProviderInfo::initializeProviderInfoCommon(
+ const std::vector<std::string> &devices) {
+
+ sp<StatusListener> listener = mManager->getStatusListener();
+
+ for (auto& device : devices) {
+ std::string id;
+ status_t res = addDevice(device, CameraDeviceStatus::PRESENT, &id);
+ if (res != OK) {
+ ALOGE("%s: Unable to enumerate camera device '%s': %s (%d)",
+ __FUNCTION__, device.c_str(), strerror(-res), res);
+ continue;
+ }
+ }
+
+ ALOGI("Camera provider %s ready with %zu camera devices",
+ mProviderName.c_str(), mDevices.size());
+
+ // Process cached status callbacks
+ std::unique_ptr<std::vector<CameraStatusInfoT>> cachedStatus =
+ std::make_unique<std::vector<CameraStatusInfoT>>();
+ {
+ std::lock_guard<std::mutex> lock(mInitLock);
+
+ for (auto& statusInfo : mCachedStatus) {
+ std::string id, physicalId;
+ status_t res = OK;
+ if (statusInfo.isPhysicalCameraStatus) {
+ res = physicalCameraDeviceStatusChangeLocked(&id, &physicalId,
+ statusInfo.cameraId, statusInfo.physicalCameraId, statusInfo.status);
+ } else {
+ res = cameraDeviceStatusChangeLocked(&id, statusInfo.cameraId, statusInfo.status);
+ }
+ if (res == OK) {
+ cachedStatus->emplace_back(statusInfo.isPhysicalCameraStatus,
+ id.c_str(), physicalId.c_str(), statusInfo.status);
+ }
+ }
+ mCachedStatus.clear();
+
+ mInitialized = true;
+ }
+
+ // The cached status change callbacks cannot be fired directly from this
+ // function, due to same-thread deadlock trying to acquire mInterfaceMutex
+ // twice.
+ if (listener != nullptr) {
+ mInitialStatusCallbackFuture = std::async(std::launch::async,
+ &CameraProviderManager::ProviderInfo::notifyInitialStatusChange, this,
+ listener, std::move(cachedStatus));
+ }
+}
+
CameraProviderManager::ProviderInfo::DeviceInfo* CameraProviderManager::findDeviceInfoLocked(
const std::string& id,
hardware::hidl_version minVersion, hardware::hidl_version maxVersion) const {
@@ -1288,23 +1630,89 @@
return falseRet;
}
-status_t CameraProviderManager::tryToInitializeProviderLocked(
+status_t CameraProviderManager::tryToInitializeAidlProviderLocked(
const std::string& providerName, const sp<ProviderInfo>& providerInfo) {
- sp<provider::V2_4::ICameraProvider> interface;
- interface = mServiceProxy->tryGetService(providerName);
+ using aidl::android::hardware::camera::provider::ICameraProvider;
+ std::shared_ptr<ICameraProvider> interface =
+ ICameraProvider::fromBinder(ndk::SpAIBinder(
+ AServiceManager_getService(providerName.c_str())));
if (interface == nullptr) {
- // The interface may not be started yet. In that case, this is not a
- // fatal error.
- ALOGW("%s: Camera provider HAL '%s' is not actually available", __FUNCTION__,
+ ALOGW("%s: AIDL Camera provider HAL '%s' is not actually available", __FUNCTION__,
providerName.c_str());
return BAD_VALUE;
}
- return providerInfo->initialize(interface, mDeviceState);
+ AidlProviderInfo *aidlProviderInfo = static_cast<AidlProviderInfo *>(providerInfo.get());
+ return aidlProviderInfo->initializeAidlProvider(interface, mDeviceState);
}
-status_t CameraProviderManager::addProviderLocked(const std::string& newProvider,
+status_t CameraProviderManager::tryToInitializeHidlProviderLocked(
+ const std::string& providerName, const sp<ProviderInfo>& providerInfo) {
+ sp<provider::V2_4::ICameraProvider> interface;
+ interface = mHidlServiceProxy->tryGetService(providerName);
+
+ if (interface == nullptr) {
+ // The interface may not be started yet. In that case, this is not a
+ // fatal error.
+ ALOGW("%s: HIDL Camera provider HAL '%s' is not actually available", __FUNCTION__,
+ providerName.c_str());
+ return BAD_VALUE;
+ }
+
+ HidlProviderInfo *hidlProviderInfo = static_cast<HidlProviderInfo *>(providerInfo.get());
+ return hidlProviderInfo->initializeHidlProvider(interface, mDeviceState);
+}
+
+status_t CameraProviderManager::addAidlProviderLocked(const std::string& newProvider) {
+ // Several camera provider instances can be temporarily present.
+ // Defer initialization of a new instance until the older instance is properly removed.
+ auto providerInstance = newProvider + "-" + std::to_string(mProviderInstanceId);
+ bool providerPresent = false;
+ bool preexisting =
+ (mAidlProviderWithBinders.find(newProvider) != mAidlProviderWithBinders.end());
+
+ // We need to use the extracted provider name here since 'newProvider' has
+ // the fully qualified name of the provider service in case of AIDL. We want
+ // just instance name.
+ using aidl::android::hardware::camera::provider::ICameraProvider;
+ std::string extractedProviderName =
+ newProvider.substr(std::string(ICameraProvider::descriptor).size() + 1);
+ for (const auto& providerInfo : mProviders) {
+ if (providerInfo->mProviderName == extractedProviderName) {
+ ALOGW("%s: Camera provider HAL with name '%s' already registered",
+ __FUNCTION__, newProvider.c_str());
+ // Do not add new instances for lazy HAL external provider or aidl
+ // binders previously seen.
+ if (preexisting || providerInfo->isExternalLazyHAL()) {
+ return ALREADY_EXISTS;
+ } else {
+ ALOGW("%s: The new provider instance will get initialized immediately after the"
+ " currently present instance is removed!", __FUNCTION__);
+ providerPresent = true;
+ break;
+ }
+ }
+ }
+
+ sp<AidlProviderInfo> providerInfo =
+ new AidlProviderInfo(extractedProviderName, providerInstance, this);
+
+ if (!providerPresent) {
+ status_t res = tryToInitializeAidlProviderLocked(newProvider, providerInfo);
+ if (res != OK) {
+ return res;
+ }
+ mAidlProviderWithBinders.emplace(newProvider);
+ }
+
+ mProviders.push_back(providerInfo);
+ mProviderInstanceId++;
+
+ return OK;
+}
+
+status_t CameraProviderManager::addHidlProviderLocked(const std::string& newProvider,
bool preexisting) {
// Several camera provider instances can be temporarily present.
// Defer initialization of a new instance until the older instance is properly removed.
@@ -1314,9 +1722,10 @@
if (providerInfo->mProviderName == newProvider) {
ALOGW("%s: Camera provider HAL with name '%s' already registered",
__FUNCTION__, newProvider.c_str());
- if (preexisting) {
+ // Do not add new instances for lazy HAL external provider
+ if (preexisting || providerInfo->isExternalLazyHAL()) {
return ALREADY_EXISTS;
- } else{
+ } else {
ALOGW("%s: The new provider instance will get initialized immediately after the"
" currently present instance is removed!", __FUNCTION__);
providerPresent = true;
@@ -1325,9 +1734,9 @@
}
}
- sp<ProviderInfo> providerInfo = new ProviderInfo(newProvider, providerInstance, this);
+ sp<HidlProviderInfo> providerInfo = new HidlProviderInfo(newProvider, providerInstance, this);
if (!providerPresent) {
- status_t res = tryToInitializeProviderLocked(newProvider, providerInfo);
+ status_t res = tryToInitializeHidlProviderLocked(newProvider, providerInfo);
if (res != OK) {
return res;
}
@@ -1365,7 +1774,17 @@
// initialize.
for (const auto& providerInfo : mProviders) {
if (providerInfo->mProviderName == removedProviderName) {
- return tryToInitializeProviderLocked(removedProviderName, providerInfo);
+ IPCTransport providerTransport = providerInfo->getIPCTransport();
+ std::string removedAidlProviderName = getFullAidlProviderName(removedProviderName);
+ switch(providerTransport) {
+ case IPCTransport::HIDL:
+ return tryToInitializeHidlProviderLocked(removedProviderName, providerInfo);
+ case IPCTransport::AIDL:
+ return tryToInitializeAidlProviderLocked(removedAidlProviderName,
+ providerInfo);
+ default:
+ ALOGE("%s Unsupported Transport %d", __FUNCTION__, providerTransport);
+ }
}
}
@@ -1387,7 +1806,6 @@
sp<CameraProviderManager::StatusListener> CameraProviderManager::getStatusListener() const {
return mListener.promote();
}
-
/**** Methods for ProviderInfo ****/
@@ -1403,248 +1821,13 @@
(void) mManager;
}
-status_t CameraProviderManager::ProviderInfo::initialize(
- sp<provider::V2_4::ICameraProvider>& interface,
- hardware::hidl_bitfield<provider::V2_5::DeviceState> currentDeviceState) {
- status_t res = parseProviderName(mProviderName, &mType, &mId);
- if (res != OK) {
- ALOGE("%s: Invalid provider name, ignoring", __FUNCTION__);
- return BAD_VALUE;
- }
- ALOGI("Connecting to new camera provider: %s, isRemote? %d",
- mProviderName.c_str(), interface->isRemote());
-
- // Determine minor version
- mMinorVersion = 4;
- auto cast2_6 = provider::V2_6::ICameraProvider::castFrom(interface);
- sp<provider::V2_6::ICameraProvider> interface2_6 = nullptr;
- if (cast2_6.isOk()) {
- interface2_6 = cast2_6;
- if (interface2_6 != nullptr) {
- mMinorVersion = 6;
- }
- }
- // We need to check again since cast2_6.isOk() succeeds even if the provider
- // version isn't actually 2.6.
- if (interface2_6 == nullptr){
- auto cast2_5 =
- provider::V2_5::ICameraProvider::castFrom(interface);
- sp<provider::V2_5::ICameraProvider> interface2_5 = nullptr;
- if (cast2_5.isOk()) {
- interface2_5 = cast2_5;
- if (interface != nullptr) {
- mMinorVersion = 5;
- }
- }
- } else {
- auto cast2_7 = provider::V2_7::ICameraProvider::castFrom(interface);
- if (cast2_7.isOk()) {
- sp<provider::V2_7::ICameraProvider> interface2_7 = cast2_7;
- if (interface2_7 != nullptr) {
- mMinorVersion = 7;
- }
- }
- }
-
- // cameraDeviceStatusChange callbacks may be called (and causing new devices added)
- // before setCallback returns
- hardware::Return<Status> status = interface->setCallback(this);
- if (!status.isOk()) {
- ALOGE("%s: Transaction error setting up callbacks with camera provider '%s': %s",
- __FUNCTION__, mProviderName.c_str(), status.description().c_str());
- return DEAD_OBJECT;
- }
- if (status != Status::OK) {
- ALOGE("%s: Unable to register callbacks with camera provider '%s'",
- __FUNCTION__, mProviderName.c_str());
- return mapToStatusT(status);
- }
-
- hardware::Return<bool> linked = interface->linkToDeath(this, /*cookie*/ mId);
- if (!linked.isOk()) {
- ALOGE("%s: Transaction error in linking to camera provider '%s' death: %s",
- __FUNCTION__, mProviderName.c_str(), linked.description().c_str());
- return DEAD_OBJECT;
- } else if (!linked) {
- ALOGW("%s: Unable to link to provider '%s' death notifications",
- __FUNCTION__, mProviderName.c_str());
- }
-
- if (!kEnableLazyHal) {
- // Save HAL reference indefinitely
- mSavedInterface = interface;
- } else {
- mActiveInterface = interface;
- }
-
- ALOGV("%s: Setting device state for %s: 0x%" PRIx64,
- __FUNCTION__, mProviderName.c_str(), mDeviceState);
- notifyDeviceStateChange(currentDeviceState);
-
- res = setUpVendorTags();
- if (res != OK) {
- ALOGE("%s: Unable to set up vendor tags from provider '%s'",
- __FUNCTION__, mProviderName.c_str());
- return res;
- }
-
- // Get initial list of camera devices, if any
- std::vector<std::string> devices;
- hardware::Return<void> ret = interface->getCameraIdList([&status, this, &devices](
- Status idStatus,
- const hardware::hidl_vec<hardware::hidl_string>& cameraDeviceNames) {
- status = idStatus;
- if (status == Status::OK) {
- for (auto& name : cameraDeviceNames) {
- uint16_t major, minor;
- std::string type, id;
- status_t res = parseDeviceName(name, &major, &minor, &type, &id);
- if (res != OK) {
- ALOGE("%s: Error parsing deviceName: %s: %d", __FUNCTION__, name.c_str(), res);
- status = Status::INTERNAL_ERROR;
- } else {
- devices.push_back(name);
- mProviderPublicCameraIds.push_back(id);
- }
- }
- } });
- if (!ret.isOk()) {
- ALOGE("%s: Transaction error in getting camera ID list from provider '%s': %s",
- __FUNCTION__, mProviderName.c_str(), linked.description().c_str());
- return DEAD_OBJECT;
- }
- if (status != Status::OK) {
- ALOGE("%s: Unable to query for camera devices from provider '%s'",
- __FUNCTION__, mProviderName.c_str());
- return mapToStatusT(status);
- }
-
- // Get list of concurrent streaming camera device combinations
- if (mMinorVersion >= 6) {
- res = getConcurrentCameraIdsInternalLocked(interface2_6);
- if (res != OK) {
- return res;
- }
- }
-
- ret = interface->isSetTorchModeSupported(
- [this](auto status, bool supported) {
- if (status == Status::OK) {
- mSetTorchModeSupported = supported;
- }
- });
- if (!ret.isOk()) {
- ALOGE("%s: Transaction error checking torch mode support '%s': %s",
- __FUNCTION__, mProviderName.c_str(), ret.description().c_str());
- return DEAD_OBJECT;
- }
-
- mIsRemote = interface->isRemote();
-
- sp<StatusListener> listener = mManager->getStatusListener();
- for (auto& device : devices) {
- std::string id;
- status_t res = addDevice(device, common::V1_0::CameraDeviceStatus::PRESENT, &id);
- if (res != OK) {
- ALOGE("%s: Unable to enumerate camera device '%s': %s (%d)",
- __FUNCTION__, device.c_str(), strerror(-res), res);
- continue;
- }
- }
-
- ALOGI("Camera provider %s ready with %zu camera devices",
- mProviderName.c_str(), mDevices.size());
-
- // Process cached status callbacks
- std::unique_ptr<std::vector<CameraStatusInfoT>> cachedStatus =
- std::make_unique<std::vector<CameraStatusInfoT>>();
- {
- std::lock_guard<std::mutex> lock(mInitLock);
-
- for (auto& statusInfo : mCachedStatus) {
- std::string id, physicalId;
- status_t res = OK;
- if (statusInfo.isPhysicalCameraStatus) {
- res = physicalCameraDeviceStatusChangeLocked(&id, &physicalId,
- statusInfo.cameraId, statusInfo.physicalCameraId, statusInfo.status);
- } else {
- res = cameraDeviceStatusChangeLocked(&id, statusInfo.cameraId, statusInfo.status);
- }
- if (res == OK) {
- cachedStatus->emplace_back(statusInfo.isPhysicalCameraStatus,
- id.c_str(), physicalId.c_str(), statusInfo.status);
- }
- }
- mCachedStatus.clear();
-
- mInitialized = true;
- }
-
- // The cached status change callbacks cannot be fired directly from this
- // function, due to same-thread deadlock trying to acquire mInterfaceMutex
- // twice.
- if (listener != nullptr) {
- mInitialStatusCallbackFuture = std::async(std::launch::async,
- &CameraProviderManager::ProviderInfo::notifyInitialStatusChange, this,
- listener, std::move(cachedStatus));
- }
-
- return OK;
-}
-
-const sp<provider::V2_4::ICameraProvider>
-CameraProviderManager::ProviderInfo::startProviderInterface() {
- ATRACE_CALL();
- ALOGV("Request to start camera provider: %s", mProviderName.c_str());
- if (mSavedInterface != nullptr) {
- return mSavedInterface;
- }
- if (!kEnableLazyHal) {
- ALOGE("Bad provider state! Should not be here on a non-lazy HAL!");
- return nullptr;
- }
-
- auto interface = mActiveInterface.promote();
- if (interface == nullptr) {
- ALOGI("Camera HAL provider needs restart, calling getService(%s)", mProviderName.c_str());
- interface = mManager->mServiceProxy->getService(mProviderName);
- interface->setCallback(this);
- hardware::Return<bool> linked = interface->linkToDeath(this, /*cookie*/ mId);
- if (!linked.isOk()) {
- ALOGE("%s: Transaction error in linking to camera provider '%s' death: %s",
- __FUNCTION__, mProviderName.c_str(), linked.description().c_str());
- mManager->removeProvider(mProviderName);
- return nullptr;
- } else if (!linked) {
- ALOGW("%s: Unable to link to provider '%s' death notifications",
- __FUNCTION__, mProviderName.c_str());
- }
- // Send current device state
- if (mMinorVersion >= 5) {
- auto castResult = provider::V2_5::ICameraProvider::castFrom(interface);
- if (castResult.isOk()) {
- sp<provider::V2_5::ICameraProvider> interface_2_5 = castResult;
- if (interface_2_5 != nullptr) {
- ALOGV("%s: Initial device state for %s: 0x %" PRIx64,
- __FUNCTION__, mProviderName.c_str(), mDeviceState);
- interface_2_5->notifyDeviceStateChange(mDeviceState);
- }
- }
- }
-
- mActiveInterface = interface;
- } else {
- ALOGV("Camera provider (%s) already in use. Re-using instance.", mProviderName.c_str());
- }
- return interface;
-}
-
const std::string& CameraProviderManager::ProviderInfo::getType() const {
return mType;
}
-status_t CameraProviderManager::ProviderInfo::addDevice(const std::string& name,
- CameraDeviceStatus initialStatus, /*out*/ std::string* parsedId) {
+status_t CameraProviderManager::ProviderInfo::addDevice(
+ const std::string& name, CameraDeviceStatus initialStatus,
+ /*out*/ std::string* parsedId) {
ALOGI("Enumerating new camera device: %s", name.c_str());
@@ -1655,6 +1838,13 @@
if (res != OK) {
return res;
}
+ if (getIPCTransport() == IPCTransport::AIDL) {
+ // Till HIDL support exists, map AIDL versions to HIDL.
+ // TODO:b/196432585 Explore if we can get rid of this.
+ major += kAidlDeviceMajorOffset;
+ minor += kAidlDeviceMinorOffset;
+ }
+
if (type != mType) {
ALOGE("%s: Device type %s does not match provider type %s", __FUNCTION__,
type.c_str(), mType.c_str());
@@ -1668,21 +1858,16 @@
std::unique_ptr<DeviceInfo> deviceInfo;
switch (major) {
- case 1:
- ALOGE("%s: Device %s: Unsupported HIDL device HAL major version %d:", __FUNCTION__,
- name.c_str(), major);
- return BAD_VALUE;
case 3:
- deviceInfo = initializeDeviceInfo<DeviceInfo3>(name, mProviderTagid,
- id, minor);
+ deviceInfo = initializeDeviceInfo(name, mProviderTagid, id, minor);
break;
default:
- ALOGE("%s: Device %s: Unknown HIDL device HAL major version %d:", __FUNCTION__,
+ ALOGE("%s: Device %s: Unsupported IDL device HAL major version %d:", __FUNCTION__,
name.c_str(), major);
return BAD_VALUE;
}
if (deviceInfo == nullptr) return BAD_VALUE;
- deviceInfo->notifyDeviceStateChange(mDeviceState);
+ deviceInfo->notifyDeviceStateChange(getDeviceState());
deviceInfo->mStatus = initialStatus;
bool isAPI1Compatible = deviceInfo->isAPI1Compatible();
@@ -1710,15 +1895,50 @@
mUniqueCameraIds.erase(id);
if ((*it)->isAPI1Compatible()) {
mUniqueAPI1CompatibleCameraIds.erase(std::remove(
- mUniqueAPI1CompatibleCameraIds.begin(),
- mUniqueAPI1CompatibleCameraIds.end(), id));
+ mUniqueAPI1CompatibleCameraIds.begin(),
+ mUniqueAPI1CompatibleCameraIds.end(), id));
}
+
+ // Remove reference to camera provider to avoid pointer leak when
+ // unplugging external camera while in use with lazy HALs
+ mManager->removeRef(DeviceMode::CAMERA, id);
+ mManager->removeRef(DeviceMode::TORCH, id);
+
mDevices.erase(it);
break;
}
}
}
+void CameraProviderManager::ProviderInfo::removeAllDevices() {
+ std::lock_guard<std::mutex> lock(mLock);
+
+ auto itDevices = mDevices.begin();
+ while (itDevices != mDevices.end()) {
+ std::string id = (*itDevices)->mId;
+ std::string deviceName = (*itDevices)->mName;
+ removeDevice(id);
+ // device was removed, reset iterator
+ itDevices = mDevices.begin();
+
+ //notify CameraService of status change
+ sp<StatusListener> listener = mManager->getStatusListener();
+ if (listener != nullptr) {
+ mLock.unlock();
+ ALOGV("%s: notify device not_present: %s",
+ __FUNCTION__,
+ deviceName.c_str());
+ listener->onDeviceStatusChanged(String8(id.c_str()),
+ CameraDeviceStatus::NOT_PRESENT);
+ mLock.lock();
+ }
+ }
+}
+
+bool CameraProviderManager::ProviderInfo::isExternalLazyHAL() const {
+ return kEnableLazyHal && (mProviderName == kExternalProviderName);
+}
+
status_t CameraProviderManager::ProviderInfo::dump(int fd, const Vector<String16>&) const {
dprintf(fd, "== Camera Provider HAL %s (v2.%d, %s) static info: %zu devices: ==\n",
mProviderInstance.c_str(),
@@ -1793,117 +2013,57 @@
return OK;
}
-status_t CameraProviderManager::ProviderInfo::getConcurrentCameraIdsInternalLocked(
- sp<provider::V2_6::ICameraProvider> &interface2_6) {
- if (interface2_6 == nullptr) {
- ALOGE("%s: null interface provided", __FUNCTION__);
- return BAD_VALUE;
- }
- Status status = Status::OK;
- hardware::Return<void> ret =
- interface2_6->getConcurrentStreamingCameraIds([&status, this](
- Status concurrentIdStatus, // TODO: Move all instances of hidl_string to 'using'
- const hardware::hidl_vec<hardware::hidl_vec<hardware::hidl_string>>&
- cameraDeviceIdCombinations) {
- status = concurrentIdStatus;
- if (status == Status::OK) {
- mConcurrentCameraIdCombinations.clear();
- for (auto& combination : cameraDeviceIdCombinations) {
- std::unordered_set<std::string> deviceIds;
- for (auto &cameraDeviceId : combination) {
- deviceIds.insert(cameraDeviceId.c_str());
- }
- mConcurrentCameraIdCombinations.push_back(std::move(deviceIds));
- }
- } });
- if (!ret.isOk()) {
- ALOGE("%s: Transaction error in getting concurrent camera ID list from provider '%s'",
- __FUNCTION__, mProviderName.c_str());
- return DEAD_OBJECT;
- }
- if (status != Status::OK) {
- ALOGE("%s: Unable to query for camera devices from provider '%s'",
- __FUNCTION__, mProviderName.c_str());
- return mapToStatusT(status);
- }
- return OK;
-}
-
-status_t CameraProviderManager::ProviderInfo::reCacheConcurrentStreamingCameraIdsLocked() {
- if (mMinorVersion < 6) {
- // Unsupported operation, nothing to do here
- return OK;
- }
- // Check if the provider is currently active - not going to start it up for this notification
- auto interface = mSavedInterface != nullptr ? mSavedInterface : mActiveInterface.promote();
- if (interface == nullptr) {
- ALOGE("%s: camera provider interface for %s is not valid", __FUNCTION__,
- mProviderName.c_str());
- return INVALID_OPERATION;
- }
- auto castResult = provider::V2_6::ICameraProvider::castFrom(interface);
-
- if (castResult.isOk()) {
- sp<provider::V2_6::ICameraProvider> interface2_6 = castResult;
- if (interface2_6 != nullptr) {
- return getConcurrentCameraIdsInternalLocked(interface2_6);
- } else {
- // This should not happen since mMinorVersion >= 6
- ALOGE("%s: mMinorVersion was >= 6, but interface2_6 was nullptr", __FUNCTION__);
- return UNKNOWN_ERROR;
- }
- }
- return OK;
-}
-
std::vector<std::unordered_set<std::string>>
CameraProviderManager::ProviderInfo::getConcurrentCameraIdCombinations() {
std::lock_guard<std::mutex> lock(mLock);
return mConcurrentCameraIdCombinations;
}
-hardware::Return<void> CameraProviderManager::ProviderInfo::cameraDeviceStatusChange(
- const hardware::hidl_string& cameraDeviceName,
- CameraDeviceStatus newStatus) {
+void CameraProviderManager::ProviderInfo::cameraDeviceStatusChangeInternal(
+ const std::string& cameraDeviceName, CameraDeviceStatus newStatus) {
sp<StatusListener> listener;
std::string id;
std::lock_guard<std::mutex> lock(mInitLock);
-
+ CameraDeviceStatus internalNewStatus = newStatus;
if (!mInitialized) {
mCachedStatus.emplace_back(false /*isPhysicalCameraStatus*/,
- cameraDeviceName.c_str(), std::string().c_str(), newStatus);
- return hardware::Void();
+ cameraDeviceName.c_str(), std::string().c_str(),
+ internalNewStatus);
+ return;
}
{
std::lock_guard<std::mutex> lock(mLock);
if (OK != cameraDeviceStatusChangeLocked(&id, cameraDeviceName, newStatus)) {
- return hardware::Void();
+ return;
}
listener = mManager->getStatusListener();
}
// Call without lock held to allow reentrancy into provider manager
if (listener != nullptr) {
- listener->onDeviceStatusChanged(String8(id.c_str()), newStatus);
+ listener->onDeviceStatusChanged(String8(id.c_str()), internalNewStatus);
}
-
- return hardware::Void();
}
status_t CameraProviderManager::ProviderInfo::cameraDeviceStatusChangeLocked(
- std::string* id, const hardware::hidl_string& cameraDeviceName,
+ std::string* id, const std::string& cameraDeviceName,
CameraDeviceStatus newStatus) {
bool known = false;
std::string cameraId;
for (auto& deviceInfo : mDevices) {
if (deviceInfo->mName == cameraDeviceName) {
+ Mutex::Autolock l(deviceInfo->mDeviceAvailableLock);
ALOGI("Camera device %s status is now %s, was %s", cameraDeviceName.c_str(),
- deviceStatusToString(newStatus), deviceStatusToString(deviceInfo->mStatus));
+ FrameworkDeviceStatusToString(newStatus),
+ FrameworkDeviceStatusToString(deviceInfo->mStatus));
deviceInfo->mStatus = newStatus;
// TODO: Handle device removal (NOT_PRESENT)
cameraId = deviceInfo->mId;
known = true;
+ deviceInfo->mIsDeviceAvailable =
+ (newStatus == CameraDeviceStatus::PRESENT);
+ deviceInfo->mDeviceAvailableSignal.signal();
break;
}
}
@@ -1917,7 +2077,13 @@
addDevice(cameraDeviceName, newStatus, &cameraId);
} else if (newStatus == CameraDeviceStatus::NOT_PRESENT) {
removeDevice(cameraId);
+ } else if (isExternalLazyHAL()) {
+ // Do not notify CameraService for PRESENT->PRESENT (lazy HAL restart)
+ // because NOT_AVAILABLE is set on CameraService::connect and a PRESENT
+ // notif. would overwrite it
+ return BAD_VALUE;
}
+
if (reCacheConcurrentStreamingCameraIdsLocked() != OK) {
ALOGE("%s: CameraProvider %s could not re-cache concurrent streaming camera id list ",
__FUNCTION__, mProviderName.c_str());
@@ -1926,19 +2092,18 @@
return OK;
}
-hardware::Return<void> CameraProviderManager::ProviderInfo::physicalCameraDeviceStatusChange(
- const hardware::hidl_string& cameraDeviceName,
- const hardware::hidl_string& physicalCameraDeviceName,
+void CameraProviderManager::ProviderInfo::physicalCameraDeviceStatusChangeInternal(
+ const std::string& cameraDeviceName,
+ const std::string& physicalCameraDeviceName,
CameraDeviceStatus newStatus) {
sp<StatusListener> listener;
std::string id;
std::string physicalId;
std::lock_guard<std::mutex> lock(mInitLock);
-
if (!mInitialized) {
mCachedStatus.emplace_back(true /*isPhysicalCameraStatus*/, cameraDeviceName,
physicalCameraDeviceName, newStatus);
- return hardware::Void();
+ return;
}
{
@@ -1946,7 +2111,7 @@
if (OK != physicalCameraDeviceStatusChangeLocked(&id, &physicalId, cameraDeviceName,
physicalCameraDeviceName, newStatus)) {
- return hardware::Void();
+ return;
}
listener = mManager->getStatusListener();
@@ -1956,13 +2121,13 @@
listener->onDeviceStatusChanged(String8(id.c_str()),
String8(physicalId.c_str()), newStatus);
}
- return hardware::Void();
+ return;
}
status_t CameraProviderManager::ProviderInfo::physicalCameraDeviceStatusChangeLocked(
std::string* id, std::string* physicalId,
- const hardware::hidl_string& cameraDeviceName,
- const hardware::hidl_string& physicalCameraDeviceName,
+ const std::string& cameraDeviceName,
+ const std::string& physicalCameraDeviceName,
CameraDeviceStatus newStatus) {
bool known = false;
std::string cameraId;
@@ -1982,7 +2147,7 @@
}
ALOGI("Camera device %s physical device %s status is now %s",
cameraDeviceName.c_str(), physicalCameraDeviceName.c_str(),
- deviceStatusToString(newStatus));
+ FrameworkDeviceStatusToString(newStatus));
known = true;
break;
}
@@ -2000,8 +2165,8 @@
return OK;
}
-hardware::Return<void> CameraProviderManager::ProviderInfo::torchModeStatusChange(
- const hardware::hidl_string& cameraDeviceName,
+void CameraProviderManager::ProviderInfo::torchModeStatusChangeInternal(
+ const std::string& cameraDeviceName,
TorchModeStatus newStatus) {
sp<StatusListener> listener;
SystemCameraKind systemCameraKind = SystemCameraKind::PUBLIC;
@@ -2013,12 +2178,12 @@
for (auto& deviceInfo : mDevices) {
if (deviceInfo->mName == cameraDeviceName) {
ALOGI("Camera device %s torch status is now %s", cameraDeviceName.c_str(),
- torchStatusToString(newStatus));
+ FrameworkTorchStatusToString(newStatus));
id = deviceInfo->mId;
known = true;
systemCameraKind = deviceInfo->mSystemCameraKind;
if (TorchModeStatus::AVAILABLE_ON != newStatus) {
- mManager->removeRef(DeviceMode::TORCH, id);
+ mManager->removeRef(CameraProviderManager::DeviceMode::TORCH, id);
}
break;
}
@@ -2026,7 +2191,7 @@
if (!known) {
ALOGW("Camera provider %s says an unknown camera %s now has torch status %d. Curious.",
mProviderName.c_str(), cameraDeviceName.c_str(), newStatus);
- return hardware::Void();
+ return;
}
// no lock needed since listener is set up only once during
// CameraProviderManager initialization and then never changed till it is
@@ -2042,167 +2207,17 @@
if (listener != nullptr) {
listener->onTorchStatusChanged(String8(id.c_str()), newStatus, systemCameraKind);
}
- return hardware::Void();
-}
-
-void CameraProviderManager::ProviderInfo::serviceDied(uint64_t cookie,
- const wp<hidl::base::V1_0::IBase>& who) {
- (void) who;
- ALOGI("Camera provider '%s' has died; removing it", mProviderInstance.c_str());
- if (cookie != mId) {
- ALOGW("%s: Unexpected serviceDied cookie %" PRIu64 ", expected %" PRIu32,
- __FUNCTION__, cookie, mId);
- }
- mManager->removeProvider(mProviderInstance);
-}
-
-status_t CameraProviderManager::ProviderInfo::setUpVendorTags() {
- if (mVendorTagDescriptor != nullptr)
- return OK;
-
- hardware::hidl_vec<VendorTagSection> vts;
- Status status;
- hardware::Return<void> ret;
- const sp<provider::V2_4::ICameraProvider> interface = startProviderInterface();
- if (interface == nullptr) {
- return DEAD_OBJECT;
- }
- ret = interface->getVendorTags(
- [&](auto s, const auto& vendorTagSecs) {
- status = s;
- if (s == Status::OK) {
- vts = vendorTagSecs;
- }
- });
- if (!ret.isOk()) {
- ALOGE("%s: Transaction error getting vendor tags from provider '%s': %s",
- __FUNCTION__, mProviderName.c_str(), ret.description().c_str());
- return DEAD_OBJECT;
- }
- if (status != Status::OK) {
- return mapToStatusT(status);
- }
-
- // Read all vendor tag definitions into a descriptor
- status_t res;
- if ((res = HidlVendorTagDescriptor::createDescriptorFromHidl(vts, /*out*/mVendorTagDescriptor))
- != OK) {
- ALOGE("%s: Could not generate descriptor from vendor tag operations,"
- "received error %s (%d). Camera clients will not be able to use"
- "vendor tags", __FUNCTION__, strerror(res), res);
- return res;
- }
-
- return OK;
+ return;
}
void CameraProviderManager::ProviderInfo::notifyDeviceInfoStateChangeLocked(
- hardware::hidl_bitfield<provider::V2_5::DeviceState> newDeviceState) {
+ int64_t newDeviceState) {
std::lock_guard<std::mutex> lock(mLock);
for (auto it = mDevices.begin(); it != mDevices.end(); it++) {
(*it)->notifyDeviceStateChange(newDeviceState);
}
}
-status_t CameraProviderManager::ProviderInfo::notifyDeviceStateChange(
- hardware::hidl_bitfield<provider::V2_5::DeviceState> newDeviceState) {
- mDeviceState = newDeviceState;
- if (mMinorVersion >= 5) {
- // Check if the provider is currently active - not going to start it up for this notification
- auto interface = mSavedInterface != nullptr ? mSavedInterface : mActiveInterface.promote();
- if (interface != nullptr) {
- // Send current device state
- auto castResult = provider::V2_5::ICameraProvider::castFrom(interface);
- if (castResult.isOk()) {
- sp<provider::V2_5::ICameraProvider> interface_2_5 = castResult;
- if (interface_2_5 != nullptr) {
- interface_2_5->notifyDeviceStateChange(mDeviceState);
- }
- }
- }
- }
- return OK;
-}
-
-status_t CameraProviderManager::ProviderInfo::isConcurrentSessionConfigurationSupported(
- const hardware::hidl_vec<CameraIdAndStreamCombination> &halCameraIdsAndStreamCombinations,
- bool *isSupported) {
- status_t res = OK;
- if (mMinorVersion >= 6) {
- // Check if the provider is currently active - not going to start it up for this notification
- auto interface = mSavedInterface != nullptr ? mSavedInterface : mActiveInterface.promote();
- if (interface == nullptr) {
- // TODO: This might be some other problem
- return INVALID_OPERATION;
- }
- auto castResult2_6 = provider::V2_6::ICameraProvider::castFrom(interface);
- auto castResult2_7 = provider::V2_7::ICameraProvider::castFrom(interface);
- Status callStatus;
- auto cb =
- [&isSupported, &callStatus](Status s, bool supported) {
- callStatus = s;
- *isSupported = supported; };
-
- ::android::hardware::Return<void> ret;
- sp<provider::V2_7::ICameraProvider> interface_2_7;
- sp<provider::V2_6::ICameraProvider> interface_2_6;
- if (mMinorVersion >= 7 && castResult2_7.isOk()) {
- interface_2_7 = castResult2_7;
- if (interface_2_7 != nullptr) {
- ret = interface_2_7->isConcurrentStreamCombinationSupported_2_7(
- halCameraIdsAndStreamCombinations, cb);
- }
- } else if (mMinorVersion == 6 && castResult2_6.isOk()) {
- interface_2_6 = castResult2_6;
- if (interface_2_6 != nullptr) {
- hardware::hidl_vec<provider::V2_6::CameraIdAndStreamCombination>
- halCameraIdsAndStreamCombinations_2_6;
- size_t numStreams = halCameraIdsAndStreamCombinations.size();
- halCameraIdsAndStreamCombinations_2_6.resize(numStreams);
- for (size_t i = 0; i < numStreams; i++) {
- using namespace camera3;
- auto const& combination = halCameraIdsAndStreamCombinations[i];
- halCameraIdsAndStreamCombinations_2_6[i].cameraId = combination.cameraId;
- bool success =
- SessionConfigurationUtils::convertHALStreamCombinationFromV37ToV34(
- halCameraIdsAndStreamCombinations_2_6[i].streamConfiguration,
- combination.streamConfiguration);
- if (!success) {
- *isSupported = false;
- return OK;
- }
- }
- ret = interface_2_6->isConcurrentStreamCombinationSupported(
- halCameraIdsAndStreamCombinations_2_6, cb);
- }
- }
-
- if (interface_2_7 != nullptr || interface_2_6 != nullptr) {
- if (ret.isOk()) {
- switch (callStatus) {
- case Status::OK:
- // Expected case, do nothing.
- res = OK;
- break;
- case Status::METHOD_NOT_SUPPORTED:
- res = INVALID_OPERATION;
- break;
- default:
- ALOGE("%s: Session configuration query failed: %d", __FUNCTION__,
- callStatus);
- res = UNKNOWN_ERROR;
- }
- } else {
- ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, ret.description().c_str());
- res = UNKNOWN_ERROR;
- }
- return res;
- }
- }
- // unsupported operation
- return INVALID_OPERATION;
-}
-
void CameraProviderManager::ProviderInfo::notifyInitialStatusChange(
sp<StatusListener> listener,
std::unique_ptr<std::vector<CameraStatusInfoT>> cachedStatus) {
@@ -2217,306 +2232,16 @@
}
}
-template<class DeviceInfoT>
-std::unique_ptr<CameraProviderManager::ProviderInfo::DeviceInfo>
- CameraProviderManager::ProviderInfo::initializeDeviceInfo(
- const std::string &name, const metadata_vendor_id_t tagId,
- const std::string &id, uint16_t minorVersion) {
- Status status;
-
- auto cameraInterface =
- startDeviceInterface<typename DeviceInfoT::InterfaceT>(name);
- if (cameraInterface == nullptr) return nullptr;
-
- CameraResourceCost resourceCost;
- cameraInterface->getResourceCost([&status, &resourceCost](
- Status s, CameraResourceCost cost) {
- status = s;
- resourceCost = cost;
- });
- if (status != Status::OK) {
- ALOGE("%s: Unable to obtain resource costs for camera device %s: %s", __FUNCTION__,
- name.c_str(), statusToString(status));
- return nullptr;
- }
-
- for (auto& conflictName : resourceCost.conflictingDevices) {
- uint16_t major, minor;
- std::string type, id;
- status_t res = parseDeviceName(conflictName, &major, &minor, &type, &id);
- if (res != OK) {
- ALOGE("%s: Failed to parse conflicting device %s", __FUNCTION__, conflictName.c_str());
- return nullptr;
- }
- conflictName = id;
- }
-
- return std::unique_ptr<DeviceInfo>(
- new DeviceInfoT(name, tagId, id, minorVersion, resourceCost, this,
- mProviderPublicCameraIds, cameraInterface));
-}
-
-template<class InterfaceT>
-sp<InterfaceT>
-CameraProviderManager::ProviderInfo::startDeviceInterface(const std::string &name) {
- ALOGE("%s: Device %s: Unknown HIDL device HAL major version %d:", __FUNCTION__,
- name.c_str(), InterfaceT::version.get_major());
- return nullptr;
-}
-
-template<>
-sp<device::V3_2::ICameraDevice>
-CameraProviderManager::ProviderInfo::startDeviceInterface
- <device::V3_2::ICameraDevice>(const std::string &name) {
- Status status;
- sp<device::V3_2::ICameraDevice> cameraInterface;
- hardware::Return<void> ret;
- const sp<provider::V2_4::ICameraProvider> interface = startProviderInterface();
- if (interface == nullptr) {
- return nullptr;
- }
- ret = interface->getCameraDeviceInterface_V3_x(name, [&status, &cameraInterface](
- Status s, sp<device::V3_2::ICameraDevice> interface) {
- status = s;
- cameraInterface = interface;
- });
- if (!ret.isOk()) {
- ALOGE("%s: Transaction error trying to obtain interface for camera device %s: %s",
- __FUNCTION__, name.c_str(), ret.description().c_str());
- return nullptr;
- }
- if (status != Status::OK) {
- ALOGE("%s: Unable to obtain interface for camera device %s: %s", __FUNCTION__,
- name.c_str(), statusToString(status));
- return nullptr;
- }
- return cameraInterface;
-}
-
-CameraProviderManager::ProviderInfo::DeviceInfo::~DeviceInfo() {}
-
-template<class InterfaceT>
-sp<InterfaceT> CameraProviderManager::ProviderInfo::DeviceInfo::startDeviceInterface() {
- sp<InterfaceT> device;
- ATRACE_CALL();
- if (mSavedInterface == nullptr) {
- sp<ProviderInfo> parentProvider = mParentProvider.promote();
- if (parentProvider != nullptr) {
- device = parentProvider->startDeviceInterface<InterfaceT>(mName);
- }
- } else {
- device = (InterfaceT *) mSavedInterface.get();
- }
- return device;
-}
-
-template<class InterfaceT>
-status_t CameraProviderManager::ProviderInfo::DeviceInfo::setTorchMode(InterfaceT& interface,
- bool enabled) {
- Status s = interface->setTorchMode(enabled ? TorchMode::ON : TorchMode::OFF);
- return mapToStatusT(s);
-}
-
CameraProviderManager::ProviderInfo::DeviceInfo3::DeviceInfo3(const std::string& name,
const metadata_vendor_id_t tagId, const std::string &id,
uint16_t minorVersion,
const CameraResourceCost& resourceCost,
sp<ProviderInfo> parentProvider,
- const std::vector<std::string>& publicCameraIds,
- sp<InterfaceT> interface) :
+ const std::vector<std::string>& publicCameraIds) :
DeviceInfo(name, tagId, id, hardware::hidl_version{3, minorVersion},
- publicCameraIds, resourceCost, parentProvider) {
- // Get camera characteristics and initialize flash unit availability
- Status status;
- hardware::Return<void> ret;
- ret = interface->getCameraCharacteristics([&status, this](Status s,
- device::V3_2::CameraMetadata metadata) {
- status = s;
- if (s == Status::OK) {
- camera_metadata_t *buffer =
- reinterpret_cast<camera_metadata_t*>(metadata.data());
- size_t expectedSize = metadata.size();
- int res = validate_camera_metadata_structure(buffer, &expectedSize);
- if (res == OK || res == CAMERA_METADATA_VALIDATION_SHIFTED) {
- set_camera_metadata_vendor_id(buffer, mProviderTagid);
- mCameraCharacteristics = buffer;
- } else {
- ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
- status = Status::INTERNAL_ERROR;
- }
- }
- });
- if (!ret.isOk()) {
- ALOGE("%s: Transaction error getting camera characteristics for device %s"
- " to check for a flash unit: %s", __FUNCTION__, id.c_str(),
- ret.description().c_str());
- return;
- }
- if (status != Status::OK) {
- ALOGE("%s: Unable to get camera characteristics for device %s: %s (%d)",
- __FUNCTION__, id.c_str(), CameraProviderManager::statusToString(status), status);
- return;
- }
+ publicCameraIds, resourceCost, parentProvider) { }
- if (mCameraCharacteristics.exists(ANDROID_INFO_DEVICE_STATE_ORIENTATIONS)) {
- const auto &stateMap = mCameraCharacteristics.find(ANDROID_INFO_DEVICE_STATE_ORIENTATIONS);
- if ((stateMap.count > 0) && ((stateMap.count % 2) == 0)) {
- for (size_t i = 0; i < stateMap.count; i += 2) {
- mDeviceStateOrientationMap.emplace(stateMap.data.i64[i], stateMap.data.i64[i+1]);
- }
- } else {
- ALOGW("%s: Invalid ANDROID_INFO_DEVICE_STATE_ORIENTATIONS map size: %zu", __FUNCTION__,
- stateMap.count);
- }
- }
-
- mSystemCameraKind = getSystemCameraKind();
-
- status_t res = fixupMonochromeTags();
- if (OK != res) {
- ALOGE("%s: Unable to fix up monochrome tags based for older HAL version: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return;
- }
- auto stat = addDynamicDepthTags();
- if (OK != stat) {
- ALOGE("%s: Failed appending dynamic depth tags: %s (%d)", __FUNCTION__, strerror(-stat),
- stat);
- }
- res = deriveHeicTags();
- if (OK != res) {
- ALOGE("%s: Unable to derive HEIC tags based on camera and media capabilities: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- }
-
- if (SessionConfigurationUtils::isUltraHighResolutionSensor(mCameraCharacteristics)) {
- status_t status = addDynamicDepthTags(/*maxResolution*/true);
- if (OK != status) {
- ALOGE("%s: Failed appending dynamic depth tags for maximum resolution mode: %s (%d)",
- __FUNCTION__, strerror(-status), status);
- }
-
- status = deriveHeicTags(/*maxResolution*/true);
- if (OK != status) {
- ALOGE("%s: Unable to derive HEIC tags based on camera and media capabilities for"
- "maximum resolution mode: %s (%d)", __FUNCTION__, strerror(-status), status);
- }
- }
-
- res = addRotateCropTags();
- if (OK != res) {
- ALOGE("%s: Unable to add default SCALER_ROTATE_AND_CROP tags: %s (%d)", __FUNCTION__,
- strerror(-res), res);
- }
- res = addPreCorrectionActiveArraySize();
- if (OK != res) {
- ALOGE("%s: Unable to add PRE_CORRECTION_ACTIVE_ARRAY_SIZE: %s (%d)", __FUNCTION__,
- strerror(-res), res);
- }
- res = camera3::ZoomRatioMapper::overrideZoomRatioTags(
- &mCameraCharacteristics, &mSupportNativeZoomRatio);
- if (OK != res) {
- ALOGE("%s: Unable to override zoomRatio related tags: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- }
-
- camera_metadata_entry flashAvailable =
- mCameraCharacteristics.find(ANDROID_FLASH_INFO_AVAILABLE);
- if (flashAvailable.count == 1 &&
- flashAvailable.data.u8[0] == ANDROID_FLASH_INFO_AVAILABLE_TRUE) {
- mHasFlashUnit = true;
- } else {
- mHasFlashUnit = false;
- }
-
- camera_metadata_entry entry =
- mCameraCharacteristics.find(ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL);
- if (entry.count == 1) {
- mTorchDefaultStrengthLevel = entry.data.i32[0];
- } else {
- mTorchDefaultStrengthLevel = 0;
- }
-
- entry = mCameraCharacteristics.find(ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL);
- if (entry.count == 1) {
- mTorchMaximumStrengthLevel = entry.data.i32[0];
- } else {
- mTorchMaximumStrengthLevel = 0;
- }
-
- mTorchStrengthLevel = 0;
- queryPhysicalCameraIds();
-
- // Get physical camera characteristics if applicable
- auto castResult = device::V3_5::ICameraDevice::castFrom(interface);
- if (!castResult.isOk()) {
- ALOGV("%s: Unable to convert ICameraDevice instance to version 3.5", __FUNCTION__);
- return;
- }
- sp<device::V3_5::ICameraDevice> interface_3_5 = castResult;
- if (interface_3_5 == nullptr) {
- ALOGE("%s: Converted ICameraDevice instance to nullptr", __FUNCTION__);
- return;
- }
-
- if (mIsLogicalCamera) {
- for (auto& id : mPhysicalIds) {
- if (std::find(mPublicCameraIds.begin(), mPublicCameraIds.end(), id) !=
- mPublicCameraIds.end()) {
- continue;
- }
-
- hardware::hidl_string hidlId(id);
- ret = interface_3_5->getPhysicalCameraCharacteristics(hidlId,
- [&status, &id, this](Status s, device::V3_2::CameraMetadata metadata) {
- status = s;
- if (s == Status::OK) {
- camera_metadata_t *buffer =
- reinterpret_cast<camera_metadata_t*>(metadata.data());
- size_t expectedSize = metadata.size();
- int res = validate_camera_metadata_structure(buffer, &expectedSize);
- if (res == OK || res == CAMERA_METADATA_VALIDATION_SHIFTED) {
- set_camera_metadata_vendor_id(buffer, mProviderTagid);
- mPhysicalCameraCharacteristics[id] = buffer;
- } else {
- ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
- status = Status::INTERNAL_ERROR;
- }
- }
- });
-
- if (!ret.isOk()) {
- ALOGE("%s: Transaction error getting physical camera %s characteristics for %s: %s",
- __FUNCTION__, id.c_str(), id.c_str(), ret.description().c_str());
- return;
- }
- if (status != Status::OK) {
- ALOGE("%s: Unable to get physical camera %s characteristics for device %s: %s (%d)",
- __FUNCTION__, id.c_str(), mId.c_str(),
- CameraProviderManager::statusToString(status), status);
- return;
- }
-
- res = camera3::ZoomRatioMapper::overrideZoomRatioTags(
- &mPhysicalCameraCharacteristics[id], &mSupportNativeZoomRatio);
- if (OK != res) {
- ALOGE("%s: Unable to override zoomRatio related tags: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- }
- }
- }
-
- if (!kEnableLazyHal) {
- // Save HAL reference indefinitely
- mSavedInterface = interface;
- }
-}
-
-CameraProviderManager::ProviderInfo::DeviceInfo3::~DeviceInfo3() {}
-
-void CameraProviderManager::ProviderInfo::DeviceInfo3::notifyDeviceStateChange(
- hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState> newState) {
-
+void CameraProviderManager::ProviderInfo::DeviceInfo3::notifyDeviceStateChange(int64_t newState) {
if (!mDeviceStateOrientationMap.empty() &&
(mDeviceStateOrientationMap.find(newState) != mDeviceStateOrientationMap.end())) {
mCameraCharacteristics.update(ANDROID_SENSOR_ORIENTATION,
@@ -2524,84 +2249,6 @@
}
}
-status_t CameraProviderManager::ProviderInfo::DeviceInfo3::setTorchMode(bool enabled) {
- return setTorchModeForDevice<InterfaceT>(enabled);
-}
-
-status_t CameraProviderManager::ProviderInfo::DeviceInfo3::turnOnTorchWithStrengthLevel(
- int32_t torchStrength) {
- const sp<CameraProviderManager::ProviderInfo::DeviceInfo3::InterfaceT> interface =
- startDeviceInterface<CameraProviderManager::ProviderInfo::DeviceInfo3::InterfaceT>();
- if (interface == nullptr) {
- return DEAD_OBJECT;
- }
- sp<hardware::camera::device::V3_8::ICameraDevice> interface_3_8 = nullptr;
- auto castResult_3_8 = device::V3_8::ICameraDevice::castFrom(interface);
- if (castResult_3_8.isOk()) {
- interface_3_8 = castResult_3_8;
- }
-
- if (interface_3_8 == nullptr) {
- return INVALID_OPERATION;
- }
-
- Status s = interface_3_8->turnOnTorchWithStrengthLevel(torchStrength);
- if (s == Status::OK) {
- mTorchStrengthLevel = torchStrength;
- }
- return mapToStatusT(s);
-}
-
-status_t CameraProviderManager::ProviderInfo::DeviceInfo3::getTorchStrengthLevel(
- int32_t *torchStrength) {
- if (torchStrength == nullptr) {
- return BAD_VALUE;
- }
- const sp<CameraProviderManager::ProviderInfo::DeviceInfo3::InterfaceT> interface =
- startDeviceInterface<CameraProviderManager::ProviderInfo::DeviceInfo3::InterfaceT>();
- if (interface == nullptr) {
- return DEAD_OBJECT;
- }
- auto castResult_3_8 = device::V3_8::ICameraDevice::castFrom(interface);
- sp<hardware::camera::device::V3_8::ICameraDevice> interface_3_8 = nullptr;
- if (castResult_3_8.isOk()) {
- interface_3_8 = castResult_3_8;
- }
-
- if (interface_3_8 == nullptr) {
- return INVALID_OPERATION;
- }
-
- Status callStatus;
- status_t res;
- hardware::Return<void> ret = interface_3_8->getTorchStrengthLevel([&callStatus, &torchStrength]
- (Status status, const int32_t& torchStrengthLevel) {
- callStatus = status;
- if (status == Status::OK) {
- *torchStrength = torchStrengthLevel;
- } });
-
- if (ret.isOk()) {
- switch (callStatus) {
- case Status::OK:
- // Expected case, do nothing.
- res = OK;
- break;
- case Status::METHOD_NOT_SUPPORTED:
- res = INVALID_OPERATION;
- break;
- default:
- ALOGE("%s: Get torch strength level failed: %d", __FUNCTION__, callStatus);
- res = UNKNOWN_ERROR;
- }
- } else {
- ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, ret.description().c_str());
- res = UNKNOWN_ERROR;
- }
-
- return res;
-}
-
status_t CameraProviderManager::ProviderInfo::DeviceInfo3::getCameraInfo(
hardware::CameraInfo *info) const {
if (info == nullptr) return BAD_VALUE;
@@ -2657,21 +2304,6 @@
return isBackwardCompatible;
}
-status_t CameraProviderManager::ProviderInfo::DeviceInfo3::dumpState(int fd) {
- native_handle_t* handle = native_handle_create(1,0);
- handle->data[0] = fd;
- const sp<InterfaceT> interface = startDeviceInterface<InterfaceT>();
- if (interface == nullptr) {
- return DEAD_OBJECT;
- }
- auto ret = interface->dumpState(handle);
- native_handle_delete(handle);
- if (!ret.isOk()) {
- return INVALID_OPERATION;
- }
- return OK;
-}
-
status_t CameraProviderManager::ProviderInfo::DeviceInfo3::getCameraCharacteristics(
bool overrideForPerfClass, CameraMetadata *characteristics) const {
if (characteristics == nullptr) return BAD_VALUE;
@@ -2697,81 +2329,6 @@
return OK;
}
-status_t CameraProviderManager::ProviderInfo::DeviceInfo3::isSessionConfigurationSupported(
- const hardware::camera::device::V3_8::StreamConfiguration &configuration,
- bool *status /*out*/) {
-
- const sp<CameraProviderManager::ProviderInfo::DeviceInfo3::InterfaceT> interface =
- this->startDeviceInterface<CameraProviderManager::ProviderInfo::DeviceInfo3::InterfaceT>();
- if (interface == nullptr) {
- return DEAD_OBJECT;
- }
- auto castResult_3_5 = device::V3_5::ICameraDevice::castFrom(interface);
- sp<hardware::camera::device::V3_5::ICameraDevice> interface_3_5 = castResult_3_5;
- auto castResult_3_7 = device::V3_7::ICameraDevice::castFrom(interface);
- sp<hardware::camera::device::V3_7::ICameraDevice> interface_3_7 = castResult_3_7;
- auto castResult_3_8 = device::V3_8::ICameraDevice::castFrom(interface);
- sp<hardware::camera::device::V3_8::ICameraDevice> interface_3_8 = castResult_3_8;
-
- status_t res;
- Status callStatus;
- ::android::hardware::Return<void> ret;
- auto halCb =
- [&callStatus, &status] (Status s, bool combStatus) {
- callStatus = s;
- *status = combStatus;
- };
- if (interface_3_8 != nullptr) {
- ret = interface_3_8->isStreamCombinationSupported_3_8(configuration, halCb);
- } else if (interface_3_7 != nullptr) {
- hardware::camera::device::V3_7::StreamConfiguration configuration_3_7;
- bool success = SessionConfigurationUtils::convertHALStreamCombinationFromV38ToV37(
- configuration_3_7, configuration);
- if (!success) {
- *status = false;
- return OK;
- }
- ret = interface_3_7->isStreamCombinationSupported_3_7(configuration_3_7, halCb);
- } else if (interface_3_5 != nullptr) {
- hardware::camera::device::V3_7::StreamConfiguration configuration_3_7;
- bool success = SessionConfigurationUtils::convertHALStreamCombinationFromV38ToV37(
- configuration_3_7, configuration);
- if (!success) {
- *status = false;
- return OK;
- }
- hardware::camera::device::V3_4::StreamConfiguration configuration_3_4;
- success = SessionConfigurationUtils::convertHALStreamCombinationFromV37ToV34(
- configuration_3_4, configuration_3_7);
- if (!success) {
- *status = false;
- return OK;
- }
- ret = interface_3_5->isStreamCombinationSupported(configuration_3_4, halCb);
- } else {
- return INVALID_OPERATION;
- }
- if (ret.isOk()) {
- switch (callStatus) {
- case Status::OK:
- // Expected case, do nothing.
- res = OK;
- break;
- case Status::METHOD_NOT_SUPPORTED:
- res = INVALID_OPERATION;
- break;
- default:
- ALOGE("%s: Session configuration query failed: %d", __FUNCTION__, callStatus);
- res = UNKNOWN_ERROR;
- }
- } else {
- ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, ret.description().c_str());
- res = UNKNOWN_ERROR;
- }
-
- return res;
-}
-
status_t CameraProviderManager::ProviderInfo::DeviceInfo3::filterSmallJpegSizes() {
int32_t thresholdW = SessionConfigurationUtils::PERF_CLASS_JPEG_THRESH_W;
int32_t thresholdH = SessionConfigurationUtils::PERF_CLASS_JPEG_THRESH_H;
@@ -3023,8 +2580,6 @@
return OK;
}
-
-
CameraProviderManager::ProviderInfo::~ProviderInfo() {
if (mInitialStatusCallbackFuture.valid()) {
mInitialStatusCallbackFuture.wait();
@@ -3033,167 +2588,6 @@
// CameraProvider interface dies, so do not unregister callbacks.
}
-status_t CameraProviderManager::mapToStatusT(const Status& s) {
- switch(s) {
- case Status::OK:
- return OK;
- case Status::ILLEGAL_ARGUMENT:
- return BAD_VALUE;
- case Status::CAMERA_IN_USE:
- return -EBUSY;
- case Status::MAX_CAMERAS_IN_USE:
- return -EUSERS;
- case Status::METHOD_NOT_SUPPORTED:
- return UNKNOWN_TRANSACTION;
- case Status::OPERATION_NOT_SUPPORTED:
- return INVALID_OPERATION;
- case Status::CAMERA_DISCONNECTED:
- return DEAD_OBJECT;
- case Status::INTERNAL_ERROR:
- return INVALID_OPERATION;
- }
- ALOGW("Unexpected HAL status code %d", s);
- return INVALID_OPERATION;
-}
-
-const char* CameraProviderManager::statusToString(const Status& s) {
- switch(s) {
- case Status::OK:
- return "OK";
- case Status::ILLEGAL_ARGUMENT:
- return "ILLEGAL_ARGUMENT";
- case Status::CAMERA_IN_USE:
- return "CAMERA_IN_USE";
- case Status::MAX_CAMERAS_IN_USE:
- return "MAX_CAMERAS_IN_USE";
- case Status::METHOD_NOT_SUPPORTED:
- return "METHOD_NOT_SUPPORTED";
- case Status::OPERATION_NOT_SUPPORTED:
- return "OPERATION_NOT_SUPPORTED";
- case Status::CAMERA_DISCONNECTED:
- return "CAMERA_DISCONNECTED";
- case Status::INTERNAL_ERROR:
- return "INTERNAL_ERROR";
- }
- ALOGW("Unexpected HAL status code %d", s);
- return "UNKNOWN_ERROR";
-}
-
-const char* CameraProviderManager::deviceStatusToString(const CameraDeviceStatus& s) {
- switch(s) {
- case CameraDeviceStatus::NOT_PRESENT:
- return "NOT_PRESENT";
- case CameraDeviceStatus::PRESENT:
- return "PRESENT";
- case CameraDeviceStatus::ENUMERATING:
- return "ENUMERATING";
- }
- ALOGW("Unexpected HAL device status code %d", s);
- return "UNKNOWN_STATUS";
-}
-
-const char* CameraProviderManager::torchStatusToString(const TorchModeStatus& s) {
- switch(s) {
- case TorchModeStatus::NOT_AVAILABLE:
- return "NOT_AVAILABLE";
- case TorchModeStatus::AVAILABLE_OFF:
- return "AVAILABLE_OFF";
- case TorchModeStatus::AVAILABLE_ON:
- return "AVAILABLE_ON";
- }
- ALOGW("Unexpected HAL torch mode status code %d", s);
- return "UNKNOWN_STATUS";
-}
-
-
-status_t HidlVendorTagDescriptor::createDescriptorFromHidl(
- const hardware::hidl_vec<common::V1_0::VendorTagSection>& vts,
- /*out*/
- sp<VendorTagDescriptor>& descriptor) {
-
- int tagCount = 0;
-
- for (size_t s = 0; s < vts.size(); s++) {
- tagCount += vts[s].tags.size();
- }
-
- if (tagCount < 0 || tagCount > INT32_MAX) {
- ALOGE("%s: tag count %d from vendor tag sections is invalid.", __FUNCTION__, tagCount);
- return BAD_VALUE;
- }
-
- Vector<uint32_t> tagArray;
- LOG_ALWAYS_FATAL_IF(tagArray.resize(tagCount) != tagCount,
- "%s: too many (%u) vendor tags defined.", __FUNCTION__, tagCount);
-
-
- sp<HidlVendorTagDescriptor> desc = new HidlVendorTagDescriptor();
- desc->mTagCount = tagCount;
-
- SortedVector<String8> sections;
- KeyedVector<uint32_t, String8> tagToSectionMap;
-
- int idx = 0;
- for (size_t s = 0; s < vts.size(); s++) {
- const common::V1_0::VendorTagSection& section = vts[s];
- const char *sectionName = section.sectionName.c_str();
- if (sectionName == NULL) {
- ALOGE("%s: no section name defined for vendor tag section %zu.", __FUNCTION__, s);
- return BAD_VALUE;
- }
- String8 sectionString(sectionName);
- sections.add(sectionString);
-
- for (size_t j = 0; j < section.tags.size(); j++) {
- uint32_t tag = section.tags[j].tagId;
- if (tag < CAMERA_METADATA_VENDOR_TAG_BOUNDARY) {
- ALOGE("%s: vendor tag %d not in vendor tag section.", __FUNCTION__, tag);
- return BAD_VALUE;
- }
-
- tagArray.editItemAt(idx++) = section.tags[j].tagId;
-
- const char *tagName = section.tags[j].tagName.c_str();
- if (tagName == NULL) {
- ALOGE("%s: no tag name defined for vendor tag %d.", __FUNCTION__, tag);
- return BAD_VALUE;
- }
- desc->mTagToNameMap.add(tag, String8(tagName));
- tagToSectionMap.add(tag, sectionString);
-
- int tagType = (int) section.tags[j].tagType;
- if (tagType < 0 || tagType >= NUM_TYPES) {
- ALOGE("%s: tag type %d from vendor ops does not exist.", __FUNCTION__, tagType);
- return BAD_VALUE;
- }
- desc->mTagToTypeMap.add(tag, tagType);
- }
- }
-
- desc->mSections = sections;
-
- for (size_t i = 0; i < tagArray.size(); ++i) {
- uint32_t tag = tagArray[i];
- String8 sectionString = tagToSectionMap.valueFor(tag);
-
- // Set up tag to section index map
- ssize_t index = sections.indexOf(sectionString);
- LOG_ALWAYS_FATAL_IF(index < 0, "index %zd must be non-negative", index);
- desc->mTagToSectionMap.add(tag, static_cast<uint32_t>(index));
-
- // Set up reverse mapping
- ssize_t reverseIndex = -1;
- if ((reverseIndex = desc->mReverseMapping.indexOfKey(sectionString)) < 0) {
- KeyedVector<String8, uint32_t>* nameMapper = new KeyedVector<String8, uint32_t>();
- reverseIndex = desc->mReverseMapping.add(sectionString, nameMapper);
- }
- desc->mReverseMapping[reverseIndex]->add(desc->mTagToNameMap.valueFor(tag), tag);
- }
-
- descriptor = std::move(desc);
- return OK;
-}
-
// Expects to have mInterfaceMutex locked
std::vector<std::unordered_set<std::string>>
CameraProviderManager::getConcurrentCameraIds() const {
@@ -3207,60 +2601,6 @@
return deviceIdCombinations;
}
-status_t CameraProviderManager::convertToHALStreamCombinationAndCameraIdsLocked(
- const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs,
- const std::set<std::string>& perfClassPrimaryCameraIds,
- int targetSdkVersion,
- hardware::hidl_vec<CameraIdAndStreamCombination> *halCameraIdsAndStreamCombinations,
- bool *earlyExit) {
- binder::Status bStatus = binder::Status::ok();
- std::vector<CameraIdAndStreamCombination> halCameraIdsAndStreamsV;
- bool shouldExit = false;
- status_t res = OK;
- for (auto &cameraIdAndSessionConfig : cameraIdsAndSessionConfigs) {
- const std::string& cameraId = cameraIdAndSessionConfig.mCameraId;
- hardware::camera::device::V3_8::StreamConfiguration streamConfiguration;
- CameraMetadata deviceInfo;
- bool overrideForPerfClass =
- SessionConfigurationUtils::targetPerfClassPrimaryCamera(
- perfClassPrimaryCameraIds, cameraId, targetSdkVersion);
- res = getCameraCharacteristicsLocked(cameraId, overrideForPerfClass, &deviceInfo);
- if (res != OK) {
- return res;
- }
- camera3::metadataGetter getMetadata =
- [this](const String8 &id, bool overrideForPerfClass) {
- CameraMetadata physicalDeviceInfo;
- getCameraCharacteristicsLocked(id.string(), overrideForPerfClass,
- &physicalDeviceInfo);
- return physicalDeviceInfo;
- };
- std::vector<std::string> physicalCameraIds;
- isLogicalCameraLocked(cameraId, &physicalCameraIds);
- bStatus =
- SessionConfigurationUtils::convertToHALStreamCombination(
- cameraIdAndSessionConfig.mSessionConfiguration,
- String8(cameraId.c_str()), deviceInfo, getMetadata,
- physicalCameraIds, streamConfiguration,
- overrideForPerfClass, &shouldExit);
- if (!bStatus.isOk()) {
- ALOGE("%s: convertToHALStreamCombination failed", __FUNCTION__);
- return INVALID_OPERATION;
- }
- if (shouldExit) {
- *earlyExit = true;
- return OK;
- }
- CameraIdAndStreamCombination halCameraIdAndStream;
- halCameraIdAndStream.cameraId = cameraId;
- SessionConfigurationUtils::convertHALStreamCombinationFromV38ToV37(
- halCameraIdAndStream.streamConfiguration, streamConfiguration);
- halCameraIdsAndStreamsV.push_back(halCameraIdAndStream);
- }
- *halCameraIdsAndStreamCombinations = halCameraIdsAndStreamsV;
- return OK;
-}
-
// Checks if the containing vector of sets has any set that contains all of the
// camera ids in cameraIdsAndSessionConfigs.
static bool checkIfSetContainsAll(
@@ -3295,27 +2635,9 @@
for (auto &provider : mProviders) {
if (checkIfSetContainsAll(cameraIdsAndSessionConfigs,
provider->getConcurrentCameraIdCombinations())) {
- // For each camera device in cameraIdsAndSessionConfigs collect
- // the streamConfigs and create the HAL
- // CameraIdAndStreamCombination, exit early if needed
- hardware::hidl_vec<CameraIdAndStreamCombination> halCameraIdsAndStreamCombinations;
- bool knowUnsupported = false;
- status_t res = convertToHALStreamCombinationAndCameraIdsLocked(
- cameraIdsAndSessionConfigs, perfClassPrimaryCameraIds,
- targetSdkVersion, &halCameraIdsAndStreamCombinations, &knowUnsupported);
- if (res != OK) {
- ALOGE("%s unable to convert session configurations provided to HAL stream"
- "combinations", __FUNCTION__);
- return res;
- }
- if (knowUnsupported) {
- // We got to know the streams aren't valid before doing the HAL
- // call itself.
- *isSupported = false;
- return OK;
- }
return provider->isConcurrentSessionConfigurationSupported(
- halCameraIdsAndStreamCombinations, isSupported);
+ cameraIdsAndSessionConfigs, perfClassPrimaryCameraIds, targetSdkVersion,
+ isSupported);
}
}
*isSupported = false;
@@ -3325,7 +2647,7 @@
status_t CameraProviderManager::getCameraCharacteristicsLocked(const std::string &id,
bool overrideForPerfClass, CameraMetadata* characteristics) const {
- auto deviceInfo = findDeviceInfoLocked(id, /*minVersion*/ {3,0}, /*maxVersion*/ {5,0});
+ auto deviceInfo = findDeviceInfoLocked(id, /*minVersion*/ {3, 0}, /*maxVersion*/ {5, 0});
if (deviceInfo != nullptr) {
return deviceInfo->getCameraCharacteristics(overrideForPerfClass, characteristics);
}
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 891c8b1..3d108bd 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -29,7 +29,11 @@
#include <camera/CameraParameters2.h>
#include <camera/CameraMetadata.h>
#include <camera/CameraBase.h>
+#include <utils/Condition.h>
#include <utils/Errors.h>
+#include <android/hardware/ICameraService.h>
+#include <utils/IPCTransport.h>
+#include <aidl/android/hardware/camera/provider/ICameraProvider.h>
#include <android/hardware/camera/common/1.0/types.h>
#include <android/hardware/camera/provider/2.5/ICameraProvider.h>
#include <android/hardware/camera/provider/2.6/ICameraProviderCallback.h>
@@ -38,26 +42,28 @@
#include <android/hardware/camera/device/3.7/types.h>
#include <android/hardware/camera/device/3.8/types.h>
#include <android/hidl/manager/1.0/IServiceNotification.h>
+#include <binder/IServiceManager.h>
#include <camera/VendorTagDescriptor.h>
namespace android {
-/**
- * The vendor tag descriptor class that takes HIDL vendor tag information as
- * input. Not part of VendorTagDescriptor class because that class is used
- * in AIDL generated sources which don't have access to HIDL headers.
- */
-class HidlVendorTagDescriptor : public VendorTagDescriptor {
-public:
- /**
- * Create a VendorTagDescriptor object from the HIDL VendorTagSection
- * vector.
- *
- * Returns OK on success, or a negative error code.
- */
- static status_t createDescriptorFromHidl(
- const hardware::hidl_vec<hardware::camera::common::V1_0::VendorTagSection>& vts,
- /*out*/
- sp<VendorTagDescriptor>& descriptor);
+
+using hardware::camera2::utils::CameraIdAndSessionConfiguration;
+
+enum class CameraDeviceStatus : uint32_t {
+ NOT_PRESENT = 0,
+ PRESENT = 1,
+ ENUMERATING = 2
+};
+
+enum class TorchModeStatus : uint32_t {
+ NOT_AVAILABLE = 0,
+ AVAILABLE_OFF = 1,
+ AVAILABLE_ON = 2
+};
+
+struct CameraResourceCost {
+ uint32_t resourceCost;
+ std::vector<std::string> conflictingDevices;
};
enum SystemCameraKind {
@@ -92,6 +98,26 @@
#define CAMERA_DEVICE_API_VERSION_3_8 HARDWARE_DEVICE_API_VERSION(3, 8)
/**
+ * The vendor tag descriptor class that takes HIDL/AIDL vendor tag information as
+ * input. Not part of VendorTagDescriptor class because that class is used
+ * in AIDL generated sources which don't have access to AIDL / HIDL headers.
+ */
+class IdlVendorTagDescriptor : public VendorTagDescriptor {
+public:
+ /**
+ * Create a VendorTagDescriptor object from the HIDL/AIDL VendorTagSection
+ * vector.
+ *
+ * Returns OK on success, or a negative error code.
+ */
+ template <class VendorTagSectionVectorType, class VendorTagSectionType>
+ static status_t createDescriptorFromIdl(
+ const VendorTagSectionVectorType& vts,
+ /*out*/
+ sp<VendorTagDescriptor>& descriptor);
+};
+
+/**
* A manager for all camera providers available on an Android device.
*
* Responsible for enumerating providers and the individual camera devices
@@ -101,14 +127,18 @@
* opening them for active use.
*
*/
-class CameraProviderManager : virtual public hidl::manager::V1_0::IServiceNotification {
+class CameraProviderManager : virtual public hidl::manager::V1_0::IServiceNotification,
+ public virtual IServiceManager::LocalRegistrationCallback {
public:
-
+ // needs to be made friend strict since HidlProviderInfo needs to inherit
+ // from CameraProviderManager::ProviderInfo which isn't a public member.
+ friend struct HidlProviderInfo;
+ friend struct AidlProviderInfo;
~CameraProviderManager();
// Tiny proxy for the static methods in a HIDL interface that communicate with the hardware
// service manager, to be replacable in unit tests with a fake.
- struct ServiceInteractionProxy {
+ struct HidlServiceInteractionProxy {
virtual bool registerForNotifications(
const std::string &serviceName,
const sp<hidl::manager::V1_0::IServiceNotification>
@@ -120,12 +150,12 @@
virtual sp<hardware::camera::provider::V2_4::ICameraProvider> getService(
const std::string &serviceName) = 0;
virtual hardware::hidl_vec<hardware::hidl_string> listServices() = 0;
- virtual ~ServiceInteractionProxy() {}
+ virtual ~HidlServiceInteractionProxy() {}
};
// Standard use case - call into the normal generated static methods which invoke
// the real hardware service manager
- struct HardwareServiceInteractionProxy : public ServiceInteractionProxy {
+ struct HidlServiceInteractionProxyImpl : public HidlServiceInteractionProxy {
virtual bool registerForNotifications(
const std::string &serviceName,
const sp<hidl::manager::V1_0::IServiceNotification>
@@ -152,15 +182,15 @@
~StatusListener() {}
virtual void onDeviceStatusChanged(const String8 &cameraId,
- hardware::camera::common::V1_0::CameraDeviceStatus newStatus) = 0;
+ CameraDeviceStatus newStatus) = 0;
virtual void onDeviceStatusChanged(const String8 &cameraId,
const String8 &physicalCameraId,
- hardware::camera::common::V1_0::CameraDeviceStatus newStatus) = 0;
+ CameraDeviceStatus newStatus) = 0;
virtual void onTorchStatusChanged(const String8 &cameraId,
- hardware::camera::common::V1_0::TorchModeStatus newStatus,
+ TorchModeStatus newStatus,
SystemCameraKind kind) = 0;
virtual void onTorchStatusChanged(const String8 &cameraId,
- hardware::camera::common::V1_0::TorchModeStatus newStatus) = 0;
+ TorchModeStatus newStatus) = 0;
virtual void onNewProviderRegistered() = 0;
};
@@ -180,7 +210,10 @@
* used for testing. The lifetime of the proxy must exceed the lifetime of the manager.
*/
status_t initialize(wp<StatusListener> listener,
- ServiceInteractionProxy *proxy = &sHardwareServiceInteractionProxy);
+ HidlServiceInteractionProxy *hidlProxy = &sHidlServiceInteractionProxy);
+
+ status_t getCameraIdIPCTransport(const std::string &id,
+ IPCTransport *providerTransport) const;
/**
* Retrieve the total number of available cameras.
@@ -218,7 +251,7 @@
* Return the resource cost of this camera device
*/
status_t getResourceCost(const std::string &id,
- hardware::camera::common::V1_0::CameraResourceCost* cost) const;
+ CameraResourceCost* cost) const;
/**
* Return the old camera API camera info
@@ -244,7 +277,8 @@
* Check for device support of specific stream combination.
*/
status_t isSessionConfigurationSupported(const std::string& id,
- const hardware::camera::device::V3_8::StreamConfiguration &configuration,
+ const SessionConfiguration &configuration,
+ bool overrideForPerfClass,
bool *status /*out*/) const;
/**
@@ -302,8 +336,19 @@
/**
* Inform registered providers about a device state change, such as folding or unfolding
*/
- status_t notifyDeviceStateChange(
- android::hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState> newState);
+ status_t notifyDeviceStateChange(int64_t newState);
+
+ status_t openAidlSession(const std::string &id,
+ const std::shared_ptr<
+ aidl::android::hardware::camera::device::ICameraDeviceCallback>& callback,
+ /*out*/
+ std::shared_ptr<aidl::android::hardware::camera::device::ICameraDeviceSession> *session);
+
+ status_t openAidlInjectionSession(const std::string &id,
+ const std::shared_ptr<
+ aidl::android::hardware::camera::device::ICameraDeviceCallback>& callback,
+ /*out*/
+ std::shared_ptr<aidl::android::hardware::camera::device::ICameraInjectionSession> *session);
/**
* Open an active session to a camera device.
@@ -311,7 +356,7 @@
* This fully powers on the camera device hardware, and returns a handle to a
* session to be used for hardware configuration and operation.
*/
- status_t openSession(const std::string &id,
+ status_t openHidlSession(const std::string &id,
const sp<hardware::camera::device::V3_2::ICameraDeviceCallback>& callback,
/*out*/
sp<hardware::camera::device::V3_2::ICameraDeviceSession> *session);
@@ -329,6 +374,9 @@
const hardware::hidl_string& name,
bool preexisting) override;
+ // LocalRegistrationCallback::onServiceRegistration
+ virtual void onServiceRegistration(const String16& name, const sp<IBinder> &binder) override;
+
/**
* Dump out information about available providers and devices
*/
@@ -358,104 +406,91 @@
status_t filterSmallJpegSizes(const std::string& cameraId);
+ status_t notifyUsbDeviceEvent(int32_t eventId, const std::string &usbDeviceId);
+
static const float kDepthARTolerance;
private:
// All private members, unless otherwise noted, expect mInterfaceMutex to be locked before use
mutable std::mutex mInterfaceMutex;
wp<StatusListener> mListener;
- ServiceInteractionProxy* mServiceProxy;
+ HidlServiceInteractionProxy* mHidlServiceProxy;
// Current overall Android device physical status
- android::hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState> mDeviceState;
+ int64_t mDeviceState;
// mProviderLifecycleLock is locked during onRegistration and removeProvider
mutable std::mutex mProviderLifecycleLock;
- static HardwareServiceInteractionProxy sHardwareServiceInteractionProxy;
+ static HidlServiceInteractionProxyImpl sHidlServiceInteractionProxy;
+
+ struct HalCameraProvider {
+ // Empty parent struct for storing either aidl / hidl camera provider reference
+ HalCameraProvider(const char *descriptor) : mDescriptor(descriptor) { };
+ virtual ~HalCameraProvider() {};
+ std::string mDescriptor;
+ };
+
+ struct HidlHalCameraProvider : public HalCameraProvider {
+ HidlHalCameraProvider(
+ const sp<hardware::camera::provider::V2_4::ICameraProvider> &provider,
+ const char *descriptor) :
+ HalCameraProvider(descriptor), mCameraProvider(provider) { };
+ private:
+ sp<hardware::camera::provider::V2_4::ICameraProvider> mCameraProvider;
+ };
+
+ struct AidlHalCameraProvider : public HalCameraProvider {
+ AidlHalCameraProvider(
+ const std::shared_ptr<
+ aidl::android::hardware::camera::provider::ICameraProvider> &provider,
+ const char *descriptor) :
+ HalCameraProvider(descriptor), mCameraProvider(provider) { };
+ private:
+ std::shared_ptr<aidl::android::hardware::camera::provider::ICameraProvider> mCameraProvider;
+ };
+
// Mapping from CameraDevice IDs to CameraProviders. This map is used to keep the
// ICameraProvider alive while it is in use by the camera with the given ID for camera
// capabilities
- std::unordered_map<std::string, sp<hardware::camera::provider::V2_4::ICameraProvider>>
+ std::unordered_map<std::string, std::shared_ptr<HalCameraProvider>>
mCameraProviderByCameraId;
// Mapping from CameraDevice IDs to CameraProviders. This map is used to keep the
// ICameraProvider alive while it is in use by the camera with the given ID for torch
// capabilities
- std::unordered_map<std::string, sp<hardware::camera::provider::V2_4::ICameraProvider>>
+ std::unordered_map<std::string, std::shared_ptr<HalCameraProvider>>
mTorchProviderByCameraId;
// Lock for accessing mCameraProviderByCameraId and mTorchProviderByCameraId
std::mutex mProviderInterfaceMapLock;
-
- struct ProviderInfo :
- virtual public hardware::camera::provider::V2_6::ICameraProviderCallback,
- virtual public hardware::hidl_death_recipient
- {
+ struct ProviderInfo : public virtual RefBase {
+ friend struct HidlProviderInfo;
+ friend struct AidlProviderInfo;
const std::string mProviderName;
const std::string mProviderInstance;
const metadata_vendor_id_t mProviderTagid;
- int mMinorVersion;
+ int32_t mMinorVersion;
sp<VendorTagDescriptor> mVendorTagDescriptor;
bool mSetTorchModeSupported;
bool mIsRemote;
- // Current overall Android device physical status
- hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState> mDeviceState;
-
- // This pointer is used to keep a reference to the ICameraProvider that was last accessed.
- wp<hardware::camera::provider::V2_4::ICameraProvider> mActiveInterface;
-
- sp<hardware::camera::provider::V2_4::ICameraProvider> mSavedInterface;
-
ProviderInfo(const std::string &providerName, const std::string &providerInstance,
CameraProviderManager *manager);
~ProviderInfo();
- status_t initialize(sp<hardware::camera::provider::V2_4::ICameraProvider>& interface,
- hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState>
- currentDeviceState);
-
- const sp<hardware::camera::provider::V2_4::ICameraProvider> startProviderInterface();
+ virtual IPCTransport getIPCTransport() = 0;
const std::string& getType() const;
- status_t addDevice(const std::string& name,
- hardware::camera::common::V1_0::CameraDeviceStatus initialStatus =
- hardware::camera::common::V1_0::CameraDeviceStatus::PRESENT,
- /*out*/ std::string *parsedId = nullptr);
-
status_t dump(int fd, const Vector<String16>& args) const;
- // ICameraProviderCallbacks interface - these lock the parent mInterfaceMutex
- hardware::Return<void> cameraDeviceStatusChange(
- const hardware::hidl_string& cameraDeviceName,
- hardware::camera::common::V1_0::CameraDeviceStatus newStatus) override;
- hardware::Return<void> torchModeStatusChange(
- const hardware::hidl_string& cameraDeviceName,
- hardware::camera::common::V1_0::TorchModeStatus newStatus) override;
- hardware::Return<void> physicalCameraDeviceStatusChange(
- const hardware::hidl_string& cameraDeviceName,
- const hardware::hidl_string& physicalCameraDeviceName,
- hardware::camera::common::V1_0::CameraDeviceStatus newStatus) override;
-
- status_t cameraDeviceStatusChangeLocked(
- std::string* id, const hardware::hidl_string& cameraDeviceName,
- hardware::camera::common::V1_0::CameraDeviceStatus newStatus);
- status_t physicalCameraDeviceStatusChangeLocked(
- std::string* id, std::string* physicalId,
- const hardware::hidl_string& cameraDeviceName,
- const hardware::hidl_string& physicalCameraDeviceName,
- hardware::camera::common::V1_0::CameraDeviceStatus newStatus);
-
- // hidl_death_recipient interface - this locks the parent mInterfaceMutex
- virtual void serviceDied(uint64_t cookie, const wp<hidl::base::V1_0::IBase>& who) override;
-
+ void initializeProviderInfoCommon(const std::vector<std::string> &devices);
/**
* Setup vendor tags for this provider
*/
- status_t setUpVendorTags();
+ virtual status_t setUpVendorTags() = 0;
/**
* Notify provider about top-level device physical state changes
@@ -464,9 +499,11 @@
* It is possible for camera providers to add/remove devices and try to
* acquire it.
*/
- status_t notifyDeviceStateChange(
- hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState>
- newDeviceState);
+ virtual status_t notifyDeviceStateChange(int64_t newDeviceState) = 0;
+
+ virtual bool successfullyStartedProviderInterface() = 0;
+
+ virtual int64_t getDeviceState() = 0;
std::vector<std::unordered_set<std::string>> getConcurrentCameraIdCombinations();
@@ -475,34 +512,43 @@
*
* Note that 'mInterfaceMutex' should be held when calling this method.
*/
- void notifyDeviceInfoStateChangeLocked(
- hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState>
- newDeviceState);
+ void notifyDeviceInfoStateChangeLocked(int64_t newDeviceState);
/**
* Query the camera provider for concurrent stream configuration support
*/
- status_t isConcurrentSessionConfigurationSupported(
- const hardware::hidl_vec<
- hardware::camera::provider::V2_7::CameraIdAndStreamCombination>
- &halCameraIdsAndStreamCombinations,
- bool *isSupported);
+ virtual status_t isConcurrentSessionConfigurationSupported(
+ const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs,
+ const std::set<std::string>& perfClassPrimaryCameraIds,
+ int targetSdkVersion, bool *isSupported) = 0;
+
+ /**
+ * Remove all devices associated with this provider and notify listeners
+ * with NOT_PRESENT state.
+ */
+ void removeAllDevices();
+
+ /**
+ * Provider is an external lazy HAL
+ */
+ bool isExternalLazyHAL() const;
// Basic device information, common to all camera devices
struct DeviceInfo {
const std::string mName; // Full instance name
const std::string mId; // ID section of full name
+ //Both hidl and aidl DeviceInfos. Aidl deviceInfos get {3, 8} to
+ //start off.
const hardware::hidl_version mVersion;
const metadata_vendor_id_t mProviderTagid;
bool mIsLogicalCamera;
std::vector<std::string> mPhysicalIds;
hardware::CameraInfo mInfo;
- sp<IBase> mSavedInterface;
SystemCameraKind mSystemCameraKind = SystemCameraKind::PUBLIC;
- const hardware::camera::common::V1_0::CameraResourceCost mResourceCost;
+ const CameraResourceCost mResourceCost;
- hardware::camera::common::V1_0::CameraDeviceStatus mStatus;
+ CameraDeviceStatus mStatus;
wp<ProviderInfo> mParentProvider;
// Torch strength default, maximum levels if the torch strength control
@@ -511,6 +557,12 @@
int32_t mTorchMaximumStrengthLevel;
int32_t mTorchDefaultStrengthLevel;
+ // Wait for lazy HALs to confirm device availability
+ static const nsecs_t kDeviceAvailableTimeout = 2000e6; // 2000 ms
+ Mutex mDeviceAvailableLock;
+ Condition mDeviceAvailableSignal;
+ bool mIsDeviceAvailable = true;
+
bool hasFlashUnit() const { return mHasFlashUnit; }
bool supportNativeZoomRatio() const { return mSupportNativeZoomRatio; }
virtual status_t setTorchMode(bool enabled) = 0;
@@ -533,46 +585,32 @@
}
virtual status_t isSessionConfigurationSupported(
- const hardware::camera::device::V3_8::StreamConfiguration &/*configuration*/,
+ const SessionConfiguration &/*configuration*/,
+ bool /*overrideForPerfClass*/,
bool * /*status*/) {
return INVALID_OPERATION;
}
virtual status_t filterSmallJpegSizes() = 0;
- virtual void notifyDeviceStateChange(
- hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState>
- /*newState*/) {}
-
- template<class InterfaceT>
- sp<InterfaceT> startDeviceInterface();
+ virtual void notifyDeviceStateChange(int64_t /*newState*/) {}
DeviceInfo(const std::string& name, const metadata_vendor_id_t tagId,
const std::string &id, const hardware::hidl_version& version,
const std::vector<std::string>& publicCameraIds,
- const hardware::camera::common::V1_0::CameraResourceCost& resourceCost,
+ const CameraResourceCost& resourceCost,
sp<ProviderInfo> parentProvider) :
mName(name), mId(id), mVersion(version), mProviderTagid(tagId),
mIsLogicalCamera(false), mResourceCost(resourceCost),
- mStatus(hardware::camera::common::V1_0::CameraDeviceStatus::PRESENT),
+ mStatus(CameraDeviceStatus::PRESENT),
mParentProvider(parentProvider), mTorchStrengthLevel(0),
mTorchMaximumStrengthLevel(0), mTorchDefaultStrengthLevel(0),
mHasFlashUnit(false), mSupportNativeZoomRatio(false),
mPublicCameraIds(publicCameraIds) {}
- virtual ~DeviceInfo();
+ virtual ~DeviceInfo() {}
protected:
+
bool mHasFlashUnit; // const after constructor
bool mSupportNativeZoomRatio; // const after constructor
const std::vector<std::string>& mPublicCameraIds;
-
- template<class InterfaceT>
- static status_t setTorchMode(InterfaceT& interface, bool enabled);
-
- template<class InterfaceT>
- status_t setTorchModeForDevice(bool enabled) {
- // Don't save the ICameraProvider interface here because we assume that this was
- // called from CameraProviderManager::setTorchMode(), which does save it.
- const sp<InterfaceT> interface = startDeviceInterface<InterfaceT>();
- return DeviceInfo::setTorchMode(interface, enabled);
- }
};
std::vector<std::unique_ptr<DeviceInfo>> mDevices;
std::unordered_set<std::string> mUniqueCameraIds;
@@ -587,36 +625,33 @@
// HALv3-specific camera fields, including the actual device interface
struct DeviceInfo3 : public DeviceInfo {
- typedef hardware::camera::device::V3_2::ICameraDevice InterfaceT;
- virtual status_t setTorchMode(bool enabled) override;
- virtual status_t turnOnTorchWithStrengthLevel(int32_t torchStrength) override;
- virtual status_t getTorchStrengthLevel(int32_t *torchStrength) override;
-
+ virtual status_t setTorchMode(bool enabled) = 0;
+ virtual status_t turnOnTorchWithStrengthLevel(int32_t torchStrength) = 0;
+ virtual status_t getTorchStrengthLevel(int32_t *torchStrength) = 0;
virtual status_t getCameraInfo(hardware::CameraInfo *info) const override;
virtual bool isAPI1Compatible() const override;
- virtual status_t dumpState(int fd) override;
+ virtual status_t dumpState(int fd) = 0;
virtual status_t getCameraCharacteristics(
bool overrideForPerfClass,
CameraMetadata *characteristics) const override;
virtual status_t getPhysicalCameraCharacteristics(const std::string& physicalCameraId,
CameraMetadata *characteristics) const override;
virtual status_t isSessionConfigurationSupported(
- const hardware::camera::device::V3_8::StreamConfiguration &configuration,
- bool *status /*out*/)
- override;
+ const SessionConfiguration &configuration, bool /*overrideForPerfClass*/,
+ bool *status /*out*/) = 0;
virtual status_t filterSmallJpegSizes() override;
virtual void notifyDeviceStateChange(
- hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState>
- newState) override;
+ int64_t newState) override;
DeviceInfo3(const std::string& name, const metadata_vendor_id_t tagId,
const std::string &id, uint16_t minorVersion,
- const hardware::camera::common::V1_0::CameraResourceCost& resourceCost,
+ const CameraResourceCost& resourceCost,
sp<ProviderInfo> parentProvider,
- const std::vector<std::string>& publicCameraIds, sp<InterfaceT> interface);
- virtual ~DeviceInfo3();
- private:
+ const std::vector<std::string>& publicCameraIds);
+ virtual ~DeviceInfo3() {};
+ protected:
+ // Modified by derived transport specific (hidl / aidl) class
CameraMetadata mCameraCharacteristics;
// Map device states to sensor orientations
std::unordered_map<int64_t, int32_t> mDeviceStateOrientationMap;
@@ -656,8 +691,7 @@
const camera_metadata_entry& halStreamConfigs,
const camera_metadata_entry& halStreamDurations);
};
-
- private:
+ protected:
std::string mType;
uint32_t mId;
@@ -667,12 +701,12 @@
struct CameraStatusInfoT {
bool isPhysicalCameraStatus = false;
- hardware::hidl_string cameraId;
- hardware::hidl_string physicalCameraId;
- hardware::camera::common::V1_0::CameraDeviceStatus status;
- CameraStatusInfoT(bool isForPhysicalCamera, const hardware::hidl_string& id,
- const hardware::hidl_string& physicalId,
- hardware::camera::common::V1_0::CameraDeviceStatus s) :
+ std::string cameraId;
+ std::string physicalCameraId;
+ CameraDeviceStatus status;
+ CameraStatusInfoT(bool isForPhysicalCamera, const std::string& id,
+ const std::string& physicalId,
+ CameraDeviceStatus s) :
isPhysicalCameraStatus(isForPhysicalCamera), cameraId(id),
physicalCameraId(physicalId), status(s) {}
};
@@ -684,22 +718,19 @@
// End of scope for mInitLock
std::future<void> mInitialStatusCallbackFuture;
+
+ std::unique_ptr<ProviderInfo::DeviceInfo>
+ virtual initializeDeviceInfo(
+ const std::string &name, const metadata_vendor_id_t tagId,
+ const std::string &id, uint16_t minorVersion) = 0;
+
+ virtual status_t reCacheConcurrentStreamingCameraIdsLocked() = 0;
+
void notifyInitialStatusChange(sp<StatusListener> listener,
std::unique_ptr<std::vector<CameraStatusInfoT>> cachedStatus);
std::vector<std::unordered_set<std::string>> mConcurrentCameraIdCombinations;
- // Templated method to instantiate the right kind of DeviceInfo and call the
- // right CameraProvider getCameraDeviceInterface_* method.
- template<class DeviceInfoT>
- std::unique_ptr<DeviceInfo> initializeDeviceInfo(const std::string &name,
- const metadata_vendor_id_t tagId, const std::string &id,
- uint16_t minorVersion);
-
- // Helper for initializeDeviceInfo to use the right CameraProvider get method.
- template<class InterfaceT>
- sp<InterfaceT> startDeviceInterface(const std::string &name);
-
// Parse provider instance name for type and id
static status_t parseProviderName(const std::string& name,
std::string *type, uint32_t *id);
@@ -711,20 +742,51 @@
// Generate vendor tag id
static metadata_vendor_id_t generateVendorTagId(const std::string &name);
+ status_t addDevice(
+ const std::string& name, CameraDeviceStatus initialStatus,
+ /*out*/ std::string* parsedId);
+
+ void cameraDeviceStatusChangeInternal(const std::string& cameraDeviceName,
+ CameraDeviceStatus newStatus);
+
+ status_t cameraDeviceStatusChangeLocked(
+ std::string* id, const std::string& cameraDeviceName,
+ CameraDeviceStatus newStatus);
+
+ void physicalCameraDeviceStatusChangeInternal(const std::string& cameraDeviceName,
+ const std::string& physicalCameraDeviceName,
+ CameraDeviceStatus newStatus);
+
+ status_t physicalCameraDeviceStatusChangeLocked(
+ std::string* id, std::string* physicalId,
+ const std::string& cameraDeviceName,
+ const std::string& physicalCameraDeviceName,
+ CameraDeviceStatus newStatus);
+
+ void torchModeStatusChangeInternal(const std::string& cameraDeviceName,
+ TorchModeStatus newStatus);
+
void removeDevice(std::string id);
- // Expects to have mLock locked
- status_t reCacheConcurrentStreamingCameraIdsLocked();
- // Expects to have mLock locked
- status_t getConcurrentCameraIdsInternalLocked(
- sp<hardware::camera::provider::V2_6::ICameraProvider> &interface2_6);
};
+ template <class ProviderInfoType, class HalCameraProviderType>
+ status_t setTorchModeT(sp<ProviderInfo> &parentProvider,
+ std::shared_ptr<HalCameraProvider> *halCameraProvider);
+
+ // Try to get hidl provider services declared. Expects mInterfaceMutex to be
+ // locked. Also registers for hidl provider service notifications.
+ status_t tryToInitAndAddHidlProvidersLocked(HidlServiceInteractionProxy *hidlProxy);
+
+ // Try to get aidl provider services declared. Expects mInterfaceMutex to be
+ // locked. Also registers for aidl provider service notifications.
+ status_t tryToAddAidlProvidersLocked();
+
/**
* Save the ICameraProvider while it is being used by a camera or torch client
*/
void saveRef(DeviceMode usageType, const std::string &cameraId,
- sp<hardware::camera::provider::V2_4::ICameraProvider> provider);
+ std::shared_ptr<HalCameraProvider> provider);
// Utility to find a DeviceInfo by ID; pointer is only valid while mInterfaceMutex is held
// and the calling code doesn't mutate the list of providers or their lists of devices.
@@ -735,13 +797,28 @@
hardware::hidl_version minVersion = hardware::hidl_version{0,0},
hardware::hidl_version maxVersion = hardware::hidl_version{1000,0}) const;
- status_t addProviderLocked(const std::string& newProvider, bool preexisting = false);
+ // Map external providers to USB devices in order to handle USB hotplug
+ // events for lazy HALs
+ std::pair<std::vector<std::string>, sp<ProviderInfo>>
+ mExternalUsbDevicesForProvider;
+ sp<ProviderInfo> startExternalLazyProvider() const;
- status_t tryToInitializeProviderLocked(const std::string& providerName,
+ status_t addHidlProviderLocked(const std::string& newProvider, bool preexisting = false);
+
+ status_t addAidlProviderLocked(const std::string& newProvider);
+
+ status_t tryToInitializeHidlProviderLocked(const std::string& providerName,
+ const sp<ProviderInfo>& providerInfo);
+
+ status_t tryToInitializeAidlProviderLocked(const std::string& providerName,
const sp<ProviderInfo>& providerInfo);
bool isLogicalCameraLocked(const std::string& id, std::vector<std::string>* physicalCameraIds);
+ // No method corresponding to the same provider / member belonging to the
+ // same provider should be used after this method is called since it'll lead
+ // to invalid memory access (especially since this is called by ProviderInfo methods on hal
+ // service death).
status_t removeProvider(const std::string& provider);
sp<StatusListener> getStatusListener() const;
@@ -749,14 +826,8 @@
size_t mProviderInstanceId = 0;
std::vector<sp<ProviderInfo>> mProviders;
-
- void addProviderToMap(
- const std::string &cameraId,
- sp<hardware::camera::provider::V2_4::ICameraProvider> provider,
- bool isTorchUsage);
- void removeCameraIdFromMap(
- std::unordered_map<std::string, sp<hardware::camera::provider::V2_4::ICameraProvider>> &map,
- const std::string &cameraId);
+ // Provider names of AIDL providers with retrieved binders.
+ std::set<std::string> mAidlProviderWithBinders;
static const char* deviceStatusToString(
const hardware::camera::common::V1_0::CameraDeviceStatus&);
@@ -768,20 +839,16 @@
void filterLogicalCameraIdsLocked(std::vector<std::string>& deviceIds) const;
status_t getSystemCameraKindLocked(const std::string& id, SystemCameraKind *kind) const;
- std::pair<bool, ProviderInfo::DeviceInfo *> isHiddenPhysicalCameraInternal(const std::string& cameraId) const;
+ std::pair<bool, ProviderInfo::DeviceInfo *> isHiddenPhysicalCameraInternal(
+ const std::string& cameraId) const;
void collectDeviceIdsLocked(const std::vector<std::string> deviceIds,
std::vector<std::string>& normalDeviceIds,
std::vector<std::string>& systemCameraDeviceIds) const;
- status_t convertToHALStreamCombinationAndCameraIdsLocked(
- const std::vector<hardware::camera2::utils::CameraIdAndSessionConfiguration>
- &cameraIdsAndSessionConfigs,
- const std::set<std::string>& perfClassPrimaryCameraIds,
- int targetSdkVersion,
- hardware::hidl_vec<hardware::camera::provider::V2_7::CameraIdAndStreamCombination>
- *halCameraIdsAndStreamCombinations,
- bool *earlyExit);
+ status_t usbDeviceDetached(const std::string &usbDeviceId);
+ ndk::ScopedAStatus onAidlRegistration(const std::string& in_name,
+ const ::ndk::SpAIBinder& in_binder);
};
} // namespace android
diff --git a/services/camera/libcameraservice/common/HalConversionsTemplated.h b/services/camera/libcameraservice/common/HalConversionsTemplated.h
new file mode 100644
index 0000000..96a715c
--- /dev/null
+++ b/services/camera/libcameraservice/common/HalConversionsTemplated.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 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_SERVERS_CAMERA_HAL_CONVERSION_TEMPLATED_H
+#define ANDROID_SERVERS_CAMERA_HAL_CONVERSION_TEMPLATED_H
+
+#include "common/CameraProviderManager.h"
+
+#include <device3/Camera3StreamInterface.h>
+
+namespace android {
+
+template <class HalCameraDeviceStatus>
+HalCameraDeviceStatus mapFrameworkToHalCameraDeviceStatus(
+ const CameraDeviceStatus& s) {
+ switch(s) {
+ case CameraDeviceStatus::PRESENT:
+ return HalCameraDeviceStatus::PRESENT;
+ case CameraDeviceStatus::NOT_PRESENT:
+ return HalCameraDeviceStatus::NOT_PRESENT;
+ case CameraDeviceStatus::ENUMERATING:
+ return HalCameraDeviceStatus::ENUMERATING;
+ }
+ ALOGW("Unexpectedcamera device status code %d", s);
+ return HalCameraDeviceStatus::NOT_PRESENT;
+}
+
+template <class HalCameraDeviceStatus>
+CameraDeviceStatus HalToFrameworkCameraDeviceStatus(
+ const HalCameraDeviceStatus& s) {
+ switch(s) {
+ case HalCameraDeviceStatus::PRESENT:
+ return CameraDeviceStatus::PRESENT;
+ case HalCameraDeviceStatus::NOT_PRESENT:
+ return CameraDeviceStatus::NOT_PRESENT;
+ case HalCameraDeviceStatus::ENUMERATING:
+ return CameraDeviceStatus::ENUMERATING;
+ }
+ ALOGW("Unexpectedcamera device status code %d", s);
+ return CameraDeviceStatus::NOT_PRESENT;
+}
+
+template <class HalCameraResourceCost>
+CameraResourceCost HalToFrameworkResourceCost(
+ const HalCameraResourceCost& s) {
+ CameraResourceCost internalResourceCost;
+ internalResourceCost.resourceCost = (uint32_t)s.resourceCost;
+ for (const auto device : s.conflictingDevices) {
+ internalResourceCost.conflictingDevices.emplace_back(device.c_str());
+ }
+ return internalResourceCost;
+}
+
+template <class HalTorchModeStatus>
+TorchModeStatus HalToFrameworkTorchModeStatus(
+ const HalTorchModeStatus& s) {
+ switch(s) {
+ case HalTorchModeStatus::NOT_AVAILABLE:
+ return TorchModeStatus::NOT_AVAILABLE;
+ case HalTorchModeStatus::AVAILABLE_OFF:
+ return TorchModeStatus::AVAILABLE_OFF;
+ case HalTorchModeStatus::AVAILABLE_ON:
+ return TorchModeStatus::AVAILABLE_ON;
+ }
+ ALOGW("Unexpectedcamera torch mode status code %d", s);
+ return TorchModeStatus::NOT_AVAILABLE;
+}
+
+template <class HalCameraDeviceStatus>
+ const char* HalDeviceStatusToString(const HalCameraDeviceStatus& s) {
+ switch(s) {
+ case HalCameraDeviceStatus::NOT_PRESENT:
+ return "NOT_PRESENT";
+ case HalCameraDeviceStatus::PRESENT:
+ return "PRESENT";
+ case HalCameraDeviceStatus::ENUMERATING:
+ return "ENUMERATING";
+ }
+ ALOGW("Unexpected HAL device status code %d", s);
+ return "UNKNOWN_STATUS";
+}
+
+}
+
+#endif
diff --git a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
new file mode 100644
index 0000000..0922b74
--- /dev/null
+++ b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
@@ -0,0 +1,813 @@
+/*
+ * Copyright (C) 2021 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 "AidlProviderInfo.h"
+#include "common/HalConversionsTemplated.h"
+#include "common/CameraProviderInfoTemplated.h"
+
+#include <cutils/properties.h>
+
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android/binder_manager.h>
+#include <android/hardware/ICameraService.h>
+#include <camera_metadata_hidden.h>
+
+#include "device3/ZoomRatioMapper.h"
+#include <utils/SessionConfigurationUtils.h>
+#include <utils/Trace.h>
+
+namespace {
+const bool kEnableLazyHal(property_get_bool("ro.camera.enableLazyHal", false));
+} // anonymous namespace
+
+namespace android {
+
+namespace SessionConfigurationUtils = ::android::camera3::SessionConfigurationUtils;
+
+using namespace aidl::android::hardware;
+using namespace hardware::camera;
+using hardware::camera2::utils::CameraIdAndSessionConfiguration;
+using hardware::ICameraService;
+
+using HalDeviceStatusType = aidl::android::hardware::camera::common::CameraDeviceStatus;
+using ICameraProvider = aidl::android::hardware::camera::provider::ICameraProvider;
+using StatusListener = CameraProviderManager::StatusListener;
+
+status_t AidlProviderInfo::mapToStatusT(const ndk::ScopedAStatus& s) {
+ using Status = aidl::android::hardware::camera::common::Status;
+ Status st = static_cast<Status>(s.getServiceSpecificError());
+ switch(st) {
+ case Status::OK:
+ return OK;
+ case Status::ILLEGAL_ARGUMENT:
+ return BAD_VALUE;
+ case Status::CAMERA_IN_USE:
+ return -EBUSY;
+ case Status::MAX_CAMERAS_IN_USE:
+ return -EUSERS;
+ case Status::METHOD_NOT_SUPPORTED:
+ return UNKNOWN_TRANSACTION;
+ case Status::OPERATION_NOT_SUPPORTED:
+ return INVALID_OPERATION;
+ case Status::CAMERA_DISCONNECTED:
+ return DEAD_OBJECT;
+ case Status::INTERNAL_ERROR:
+ return INVALID_OPERATION;
+ }
+ ALOGW("Unexpected HAL status code %d", static_cast<int>(st));
+ return INVALID_OPERATION;
+}
+
+AidlProviderInfo::AidlProviderInfo(
+ const std::string &providerName,
+ const std::string &providerInstance,
+ CameraProviderManager *manager) :
+ CameraProviderManager::ProviderInfo(providerName, providerInstance, manager) {}
+
+status_t AidlProviderInfo::initializeAidlProvider(
+ std::shared_ptr<ICameraProvider>& interface, int64_t currentDeviceState) {
+
+ status_t res = parseProviderName(mProviderName, &mType, &mId);
+ if (res != OK) {
+ ALOGE("%s: Invalid provider name, ignoring", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ ALOGI("Connecting to new camera provider: %s, isRemote? %d",
+ mProviderName.c_str(), interface->isRemote());
+
+ // cameraDeviceStatusChange callbacks may be called (and causing new devices added)
+ // before setCallback returns
+ mCallbacks =
+ ndk::SharedRefBase::make<AidlProviderCallbacks>(this);
+ ndk::ScopedAStatus status =
+ interface->setCallback(mCallbacks);
+ if (!status.isOk()) {
+ ALOGE("%s: Transaction error setting up callbacks with camera provider '%s': %s",
+ __FUNCTION__, mProviderName.c_str(), status.getMessage());
+ return mapToStatusT(status);
+ }
+
+ mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(binderDied));
+ auto link = AIBinder_linkToDeath(interface->asBinder().get(), mDeathRecipient.get(), this);
+ if (link != STATUS_OK) {
+ ALOGW("%s: Unable to link to provider '%s' death notifications",
+ __FUNCTION__, mProviderName.c_str());
+ return DEAD_OBJECT;
+ }
+
+ if (!kEnableLazyHal) {
+ // Save HAL reference indefinitely
+ mSavedInterface = interface;
+ } else {
+ mActiveInterface = interface;
+ }
+
+ ALOGV("%s: Setting device state for %s: 0x%" PRIx64,
+ __FUNCTION__, mProviderName.c_str(), mDeviceState);
+ notifyDeviceStateChange(currentDeviceState);
+
+ res = setUpVendorTags();
+ if (res != OK) {
+ ALOGE("%s: Unable to set up vendor tags from provider '%s'",
+ __FUNCTION__, mProviderName.c_str());
+ return res;
+ }
+
+ // Get initial list of camera devices, if any
+ std::vector<std::string> devices;
+ std::vector<std::string> retDevices;
+ status = interface->getCameraIdList(&retDevices);
+ if (!status.isOk()) {
+ ALOGE("%s: Transaction error in getting camera ID list from provider '%s': %s",
+ __FUNCTION__, mProviderName.c_str(), status.getMessage());
+ return mapToStatusT(status);
+ }
+
+ for (auto& name : retDevices) {
+ uint16_t major, minor;
+ std::string type, id;
+ status_t res = parseDeviceName(name, &major, &minor, &type, &id);
+ if (res != OK) {
+ ALOGE("%s: Error parsing deviceName: %s: %d", __FUNCTION__, name.c_str(), res);
+ return res;
+ } else {
+ devices.push_back(name);
+ mProviderPublicCameraIds.push_back(id);
+ }
+ }
+
+ // Get list of concurrent streaming camera device combinations
+ res = getConcurrentCameraIdsInternalLocked(interface);
+ if (res != OK) {
+ return res;
+ }
+
+ mSetTorchModeSupported = true;
+
+ mIsRemote = interface->isRemote();
+
+ initializeProviderInfoCommon(devices);
+ return OK;
+}
+
+void AidlProviderInfo::binderDied(void *cookie) {
+ AidlProviderInfo *provider = reinterpret_cast<AidlProviderInfo *>(cookie);
+ ALOGI("Camera provider '%s' has died; removing it", provider->mProviderInstance.c_str());
+ provider->mManager->removeProvider(provider->mProviderInstance);
+}
+
+status_t AidlProviderInfo::setUpVendorTags() {
+ if (mVendorTagDescriptor != nullptr)
+ return OK;
+
+ std::vector<camera::common::VendorTagSection> vts;
+ ::ndk::ScopedAStatus status;
+ const std::shared_ptr<ICameraProvider> interface = startProviderInterface();
+ if (interface == nullptr) {
+ return DEAD_OBJECT;
+ }
+ status = interface->getVendorTags(&vts);
+ if (!status.isOk()) {
+ ALOGE("%s: Transaction error getting vendor tags from provider '%s': %s",
+ __FUNCTION__, mProviderName.c_str(), status.getMessage());
+ return mapToStatusT(status);
+ }
+
+ // Read all vendor tag definitions into a descriptor
+ status_t res;
+ if ((res =
+ IdlVendorTagDescriptor::
+ createDescriptorFromIdl<std::vector<camera::common::VendorTagSection>,
+ camera::common::VendorTagSection>(vts, /*out*/mVendorTagDescriptor))
+ != OK) {
+ ALOGE("%s: Could not generate descriptor from vendor tag operations,"
+ "received error %s (%d). Camera clients will not be able to use"
+ "vendor tags", __FUNCTION__, strerror(res), res);
+ return res;
+ }
+
+ return OK;
+}
+
+status_t AidlProviderInfo::notifyDeviceStateChange(int64_t newDeviceState) {
+
+ mDeviceState = newDeviceState;
+ // Check if the provider is currently active - not going to start it up for this notification
+ auto interface = mSavedInterface != nullptr ? mSavedInterface : mActiveInterface.lock();
+ if (interface != nullptr) {
+ // Send current device state
+ interface->notifyDeviceStateChange(mDeviceState);
+ }
+ return OK;
+}
+
+bool AidlProviderInfo::successfullyStartedProviderInterface() {
+ return startProviderInterface() != nullptr;
+}
+
+std::shared_ptr<camera::device::ICameraDevice>
+AidlProviderInfo::startDeviceInterface(const std::string &name) {
+ ::ndk::ScopedAStatus status;
+ std::shared_ptr<camera::device::ICameraDevice> cameraInterface;
+ const std::shared_ptr<ICameraProvider> interface = startProviderInterface();
+ if (interface == nullptr) {
+ return nullptr;
+ }
+ status = interface->getCameraDeviceInterface(name, &cameraInterface);
+ if (!status.isOk()) {
+ ALOGE("%s: Transaction error trying to obtain interface for camera device %s: %s",
+ __FUNCTION__, name.c_str(), status.getMessage());
+ return nullptr;
+ }
+ return cameraInterface;
+}
+
+const std::shared_ptr<ICameraProvider> AidlProviderInfo::startProviderInterface() {
+ ATRACE_CALL();
+ ALOGV("Request to start camera provider: %s", mProviderName.c_str());
+ if (mSavedInterface != nullptr) {
+ return mSavedInterface;
+ }
+ if (!kEnableLazyHal) {
+ ALOGE("Bad provider state! Should not be here on a non-lazy HAL!");
+ return nullptr;
+ }
+
+ auto interface = mActiveInterface.lock();
+ if (interface == nullptr) {
+ // Try to get service without starting
+ interface =
+ ICameraProvider::fromBinder(
+ ndk::SpAIBinder(AServiceManager_checkService(mProviderName.c_str())));
+ if (interface == nullptr) {
+ ALOGV("Camera provider actually needs restart, calling getService(%s)",
+ mProviderName.c_str());
+ interface =
+ ICameraProvider::fromBinder(
+ ndk::SpAIBinder(
+ AServiceManager_getService(mProviderName.c_str())));
+
+ // Set all devices as ENUMERATING, provider should update status
+ // to PRESENT after initializing.
+ // This avoids failing getCameraDeviceInterface_V3_x before devices
+ // are ready.
+ for (auto& device : mDevices) {
+ device->mIsDeviceAvailable = false;
+ }
+
+ interface->setCallback(mCallbacks);
+ auto link = AIBinder_linkToDeath(interface->asBinder().get(), mDeathRecipient.get(),
+ this);
+ if (link != STATUS_OK) {
+ ALOGW("%s: Unable to link to provider '%s' death notifications",
+ __FUNCTION__, mProviderName.c_str());
+ mManager->removeProvider(mProviderName);
+ return nullptr;
+ }
+
+ // Send current device state
+ interface->notifyDeviceStateChange(mDeviceState);
+ }
+ mActiveInterface = interface;
+ } else {
+ ALOGV("Camera provider (%s) already in use. Re-using instance.",
+ mProviderName.c_str());
+ }
+
+ return interface;
+}
+
+::ndk::ScopedAStatus AidlProviderInfo::AidlProviderCallbacks::cameraDeviceStatusChange(
+ const std::string& cameraDeviceName,
+ HalDeviceStatusType newStatus) {
+ sp<AidlProviderInfo> parent = mParent.promote();
+ if (parent == nullptr) {
+ ALOGE("%s: Parent provider not alive", __FUNCTION__);
+ return ::ndk::ScopedAStatus::ok();
+ }
+ return parent->cameraDeviceStatusChange(cameraDeviceName, newStatus);
+}
+
+::ndk::ScopedAStatus AidlProviderInfo::AidlProviderCallbacks::torchModeStatusChange(
+ const std::string& cameraDeviceName,
+ aidl::android::hardware::camera::common::TorchModeStatus newStatus) {
+ sp<AidlProviderInfo> parent = mParent.promote();
+ if (parent == nullptr) {
+ ALOGE("%s: Parent provider not alive", __FUNCTION__);
+ return ::ndk::ScopedAStatus::ok();
+ }
+ return parent->torchModeStatusChange(cameraDeviceName, newStatus);
+
+};
+
+::ndk::ScopedAStatus AidlProviderInfo::AidlProviderCallbacks::physicalCameraDeviceStatusChange(
+ const std::string& cameraDeviceName,
+ const std::string& physicalCameraDeviceName,
+ HalDeviceStatusType newStatus) {
+ sp<AidlProviderInfo> parent = mParent.promote();
+ if (parent == nullptr) {
+ ALOGE("%s: Parent provider not alive", __FUNCTION__);
+ return ::ndk::ScopedAStatus::ok();
+ }
+ return parent->physicalCameraDeviceStatusChange(cameraDeviceName, physicalCameraDeviceName,
+ newStatus);
+};
+
+::ndk::ScopedAStatus AidlProviderInfo::cameraDeviceStatusChange(const std::string& cameraDeviceName,
+ HalDeviceStatusType newStatus) {
+ cameraDeviceStatusChangeInternal(cameraDeviceName, HalToFrameworkCameraDeviceStatus(newStatus));
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus AidlProviderInfo::torchModeStatusChange(const std::string& cameraDeviceName,
+ aidl::android::hardware::camera::common::TorchModeStatus newStatus) {
+ torchModeStatusChangeInternal(cameraDeviceName, HalToFrameworkTorchModeStatus(newStatus));
+ return ::ndk::ScopedAStatus::ok();
+};
+
+::ndk::ScopedAStatus AidlProviderInfo::physicalCameraDeviceStatusChange(
+ const std::string& cameraDeviceName,
+ const std::string& physicalCameraDeviceName,
+ HalDeviceStatusType newStatus) {
+ physicalCameraDeviceStatusChangeInternal(cameraDeviceName, physicalCameraDeviceName,
+ HalToFrameworkCameraDeviceStatus(newStatus));
+ return ::ndk::ScopedAStatus::ok();
+};
+
+std::unique_ptr<CameraProviderManager::ProviderInfo::DeviceInfo>
+ AidlProviderInfo::initializeDeviceInfo(
+ const std::string &name, const metadata_vendor_id_t tagId,
+ const std::string &id, uint16_t minorVersion) {
+ ::ndk::ScopedAStatus status;
+
+ auto cameraInterface = startDeviceInterface(name);
+ if (cameraInterface == nullptr) return nullptr;
+
+ camera::common::CameraResourceCost resourceCost;
+ status = cameraInterface->getResourceCost(&resourceCost);
+ if (!status.isOk()) {
+ ALOGE("%s: Unable to obtain resource costs for camera device %s: %s", __FUNCTION__,
+ name.c_str(), status.getMessage());
+ return nullptr;
+ }
+
+ for (auto& conflictName : resourceCost.conflictingDevices) {
+ uint16_t major, minor;
+ std::string type, id;
+ status_t res = parseDeviceName(conflictName, &major, &minor, &type, &id);
+ if (res != OK) {
+ ALOGE("%s: Failed to parse conflicting device %s", __FUNCTION__, conflictName.c_str());
+ return nullptr;
+ }
+ conflictName = id;
+ }
+
+ return std::unique_ptr<DeviceInfo3>(
+ new AidlDeviceInfo3(name, tagId, id, minorVersion, HalToFrameworkResourceCost(resourceCost),
+ this, mProviderPublicCameraIds, cameraInterface));
+}
+
+status_t AidlProviderInfo::reCacheConcurrentStreamingCameraIdsLocked() {
+
+ // Check if the provider is currently active - not going to start it up for this notification
+ auto interface = mSavedInterface != nullptr ? mSavedInterface : mActiveInterface.lock();
+ if (interface == nullptr) {
+ ALOGE("%s: camera provider interface for %s is not valid", __FUNCTION__,
+ mProviderName.c_str());
+ return INVALID_OPERATION;
+ }
+
+ return getConcurrentCameraIdsInternalLocked(interface);
+}
+
+status_t AidlProviderInfo::getConcurrentCameraIdsInternalLocked(
+ std::shared_ptr<ICameraProvider> &interface) {
+ if (interface == nullptr) {
+ ALOGE("%s: null interface provided", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ std::vector<aidl::android::hardware::camera::provider::ConcurrentCameraIdCombination> combs;
+ ::ndk::ScopedAStatus status = interface->getConcurrentCameraIds(&combs);
+
+ if (!status.isOk()) {
+ ALOGE("%s: Transaction error in getting concurrent camera ID list from provider '%s'",
+ __FUNCTION__, mProviderName.c_str());
+ return mapToStatusT(status);
+ }
+ mConcurrentCameraIdCombinations.clear();
+ for (const auto& combination : combs) {
+ std::unordered_set<std::string> deviceIds;
+ for (const auto &cameraDeviceId : combination.combination) {
+ deviceIds.insert(cameraDeviceId.c_str());
+ }
+ mConcurrentCameraIdCombinations.push_back(std::move(deviceIds));
+ }
+
+ return OK;
+}
+
+AidlProviderInfo::AidlDeviceInfo3::AidlDeviceInfo3(
+ const std::string& name,
+ const metadata_vendor_id_t tagId,
+ const std::string &id, uint16_t minorVersion,
+ const CameraResourceCost& resourceCost,
+ sp<CameraProviderManager::ProviderInfo> parentProvider,
+ const std::vector<std::string>& publicCameraIds,
+ std::shared_ptr<aidl::android::hardware::camera::device::ICameraDevice> interface) :
+ DeviceInfo3(name, tagId, id, minorVersion, resourceCost, parentProvider, publicCameraIds) {
+
+ // Get camera characteristics and initialize flash unit availability
+ aidl::android::hardware::camera::device::CameraMetadata chars;
+ ::ndk::ScopedAStatus status = interface->getCameraCharacteristics(&chars);
+ std::vector<uint8_t> &metadata = chars.metadata;
+ camera_metadata_t *buffer = reinterpret_cast<camera_metadata_t*>(metadata.data());
+ size_t expectedSize = metadata.size();
+ int resV = validate_camera_metadata_structure(buffer, &expectedSize);
+ if (resV == OK || resV == CAMERA_METADATA_VALIDATION_SHIFTED) {
+ set_camera_metadata_vendor_id(buffer, mProviderTagid);
+ mCameraCharacteristics = buffer;
+ } else {
+ ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
+ return;
+ }
+
+ if (!status.isOk()) {
+ ALOGE("%s: Transaction error getting camera characteristics for device %s"
+ " to check for a flash unit: %s", __FUNCTION__, id.c_str(),
+ status.getMessage());
+ return;
+ }
+
+ if (mCameraCharacteristics.exists(ANDROID_INFO_DEVICE_STATE_ORIENTATIONS)) {
+ const auto &stateMap = mCameraCharacteristics.find(ANDROID_INFO_DEVICE_STATE_ORIENTATIONS);
+ if ((stateMap.count > 0) && ((stateMap.count % 2) == 0)) {
+ for (size_t i = 0; i < stateMap.count; i += 2) {
+ mDeviceStateOrientationMap.emplace(stateMap.data.i64[i], stateMap.data.i64[i+1]);
+ }
+ } else {
+ ALOGW("%s: Invalid ANDROID_INFO_DEVICE_STATE_ORIENTATIONS map size: %zu", __FUNCTION__,
+ stateMap.count);
+ }
+ }
+
+ mSystemCameraKind = getSystemCameraKind();
+
+ status_t res = fixupMonochromeTags();
+ if (OK != res) {
+ ALOGE("%s: Unable to fix up monochrome tags based for older HAL version: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return;
+ }
+ auto stat = addDynamicDepthTags();
+ if (OK != stat) {
+ ALOGE("%s: Failed appending dynamic depth tags: %s (%d)", __FUNCTION__, strerror(-stat),
+ stat);
+ }
+ res = deriveHeicTags();
+ if (OK != res) {
+ ALOGE("%s: Unable to derive HEIC tags based on camera and media capabilities: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ }
+
+ if (camera3::SessionConfigurationUtils::isUltraHighResolutionSensor(mCameraCharacteristics)) {
+ status_t status = addDynamicDepthTags(/*maxResolution*/true);
+ if (OK != status) {
+ ALOGE("%s: Failed appending dynamic depth tags for maximum resolution mode: %s (%d)",
+ __FUNCTION__, strerror(-status), status);
+ }
+
+ status = deriveHeicTags(/*maxResolution*/true);
+ if (OK != status) {
+ ALOGE("%s: Unable to derive HEIC tags based on camera and media capabilities for"
+ "maximum resolution mode: %s (%d)", __FUNCTION__, strerror(-status), status);
+ }
+ }
+
+ res = addRotateCropTags();
+ if (OK != res) {
+ ALOGE("%s: Unable to add default SCALER_ROTATE_AND_CROP tags: %s (%d)", __FUNCTION__,
+ strerror(-res), res);
+ }
+ res = addPreCorrectionActiveArraySize();
+ if (OK != res) {
+ ALOGE("%s: Unable to add PRE_CORRECTION_ACTIVE_ARRAY_SIZE: %s (%d)", __FUNCTION__,
+ strerror(-res), res);
+ }
+ res = camera3::ZoomRatioMapper::overrideZoomRatioTags(
+ &mCameraCharacteristics, &mSupportNativeZoomRatio);
+ if (OK != res) {
+ ALOGE("%s: Unable to override zoomRatio related tags: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ }
+
+ camera_metadata_entry flashAvailable =
+ mCameraCharacteristics.find(ANDROID_FLASH_INFO_AVAILABLE);
+ if (flashAvailable.count == 1 &&
+ flashAvailable.data.u8[0] == ANDROID_FLASH_INFO_AVAILABLE_TRUE) {
+ mHasFlashUnit = true;
+ } else {
+ mHasFlashUnit = false;
+ }
+
+ camera_metadata_entry entry =
+ mCameraCharacteristics.find(ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL);
+ if (entry.count == 1) {
+ mTorchDefaultStrengthLevel = entry.data.i32[0];
+ } else {
+ mTorchDefaultStrengthLevel = 0;
+ }
+ entry = mCameraCharacteristics.find(ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL);
+ if (entry.count == 1) {
+ mTorchMaximumStrengthLevel = entry.data.i32[0];
+ } else {
+ mTorchMaximumStrengthLevel = 0;
+ }
+
+ mTorchStrengthLevel = 0;
+
+ queryPhysicalCameraIds();
+
+ // Get physical camera characteristics if applicable
+ if (mIsLogicalCamera) {
+ for (auto& id : mPhysicalIds) {
+ if (std::find(mPublicCameraIds.begin(), mPublicCameraIds.end(), id) !=
+ mPublicCameraIds.end()) {
+ continue;
+ }
+
+ aidl::android::hardware::camera::device::CameraMetadata pChars;
+ status = interface->getPhysicalCameraCharacteristics(id, &pChars);
+ if (!status.isOk()) {
+ ALOGE("%s: Transaction error getting physical camera %s characteristics for %s: %s",
+ __FUNCTION__, id.c_str(), id.c_str(), status.getMessage());
+ return;
+ }
+ std::vector<uint8_t> &pMetadata = pChars.metadata;
+ camera_metadata_t *pBuffer =
+ reinterpret_cast<camera_metadata_t*>(pMetadata.data());
+ size_t expectedSize = pMetadata.size();
+ int res = validate_camera_metadata_structure(pBuffer, &expectedSize);
+ if (res == OK || res == CAMERA_METADATA_VALIDATION_SHIFTED) {
+ set_camera_metadata_vendor_id(pBuffer, mProviderTagid);
+ mPhysicalCameraCharacteristics[id] = pBuffer;
+ } else {
+ ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
+ return;
+ }
+
+ res = camera3::ZoomRatioMapper::overrideZoomRatioTags(
+ &mPhysicalCameraCharacteristics[id], &mSupportNativeZoomRatio);
+ if (OK != res) {
+ ALOGE("%s: Unable to override zoomRatio related tags: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ }
+ }
+ }
+
+ if (!kEnableLazyHal) {
+ // Save HAL reference indefinitely
+ mSavedInterface = interface;
+ }
+}
+
+status_t AidlProviderInfo::AidlDeviceInfo3::setTorchMode(bool enabled) {
+ const std::shared_ptr<camera::device::ICameraDevice> interface = startDeviceInterface();
+ ::ndk::ScopedAStatus s = interface->setTorchMode(enabled);
+ if (!s.isOk()) {
+ ALOGE("%s Unable to set torch mode: %s", __FUNCTION__, s.getMessage());
+ return mapToStatusT(s);
+ }
+ return OK;
+}
+
+status_t AidlProviderInfo::AidlDeviceInfo3::turnOnTorchWithStrengthLevel(
+ int32_t torchStrength) {
+ const std::shared_ptr<camera::device::ICameraDevice> interface = startDeviceInterface();
+ if (interface == nullptr) {
+ return DEAD_OBJECT;
+ }
+
+ ::ndk::ScopedAStatus s = interface->turnOnTorchWithStrengthLevel(torchStrength);
+ if (!s.isOk()) {
+ ALOGE("%s Unable to set torch mode strength %d : %s", __FUNCTION__, torchStrength,
+ s.getMessage());
+ return mapToStatusT(s);
+ }
+ mTorchStrengthLevel = torchStrength;
+ return OK;
+}
+
+status_t AidlProviderInfo::AidlDeviceInfo3::getTorchStrengthLevel(int32_t *torchStrength) {
+ if (torchStrength == nullptr) {
+ return BAD_VALUE;
+ }
+ const std::shared_ptr<camera::device::ICameraDevice> interface = startDeviceInterface();
+ if (interface == nullptr) {
+ return DEAD_OBJECT;
+ }
+
+ ::ndk::ScopedAStatus status = interface->getTorchStrengthLevel(torchStrength);
+ if (!status.isOk()) {
+ ALOGE("%s: Couldn't get torch strength level: %s", __FUNCTION__, status.getMessage());
+ return mapToStatusT(status);
+ }
+ return OK;
+}
+
+std::shared_ptr<aidl::android::hardware::camera::device::ICameraDevice>
+AidlProviderInfo::AidlDeviceInfo3::startDeviceInterface() {
+ Mutex::Autolock l(mDeviceAvailableLock);
+ std::shared_ptr<camera::device::ICameraDevice> device;
+ ATRACE_CALL();
+ if (mSavedInterface == nullptr) {
+ sp<AidlProviderInfo> parentProvider =
+ static_cast<AidlProviderInfo *>(mParentProvider.promote().get());
+ if (parentProvider != nullptr) {
+ // Wait for lazy HALs to confirm device availability
+ if (parentProvider->isExternalLazyHAL() && !mIsDeviceAvailable) {
+ ALOGV("%s: Wait for external device to become available %s",
+ __FUNCTION__,
+ mId.c_str());
+
+ auto res = mDeviceAvailableSignal.waitRelative(mDeviceAvailableLock,
+ kDeviceAvailableTimeout);
+ if (res != OK) {
+ ALOGE("%s: Failed waiting for device to become available",
+ __FUNCTION__);
+ return nullptr;
+ }
+ }
+
+ device = parentProvider->startDeviceInterface(mName);
+ }
+ } else {
+ device = mSavedInterface;
+ }
+ return device;
+}
+
+status_t AidlProviderInfo::AidlDeviceInfo3::dumpState(int fd) {
+ native_handle_t* handle = native_handle_create(1,0);
+ handle->data[0] = fd;
+ const std::shared_ptr<camera::device::ICameraDevice> interface = startDeviceInterface();
+ if (interface == nullptr) {
+ return DEAD_OBJECT;
+ }
+ ::ndk::ScopedFileDescriptor sFd;
+ sFd.set(fcntl(fd, F_DUPFD_CLOEXEC, 0));
+ auto ret = interface->dumpState(sFd);
+ native_handle_delete(handle);
+ if (!ret.isOk()) {
+ return mapToStatusT(ret);
+ }
+ return OK;
+}
+
+status_t AidlProviderInfo::AidlDeviceInfo3::isSessionConfigurationSupported(
+ const SessionConfiguration &configuration, bool overrideForPerfClass, bool *status) {
+
+ camera::device::StreamConfiguration streamConfiguration;
+ bool earlyExit = false;
+ camera3::metadataGetter getMetadata = [this](const String8 &id, bool /*overrideForPerfClass*/) {
+ CameraMetadata physicalChars;
+ getPhysicalCameraCharacteristics(id.c_str(), &physicalChars);
+ return physicalChars;
+ };
+ auto bRes = SessionConfigurationUtils::convertToHALStreamCombination(configuration,
+ String8(mId.c_str()), mCameraCharacteristics, getMetadata, mPhysicalIds,
+ streamConfiguration, overrideForPerfClass, &earlyExit);
+
+ if (!bRes.isOk()) {
+ return UNKNOWN_ERROR;
+ }
+
+ if (earlyExit) {
+ *status = false;
+ return OK;
+ }
+
+ const std::shared_ptr<camera::device::ICameraDevice> interface =
+ startDeviceInterface();
+
+ if (interface == nullptr) {
+ return DEAD_OBJECT;
+ }
+
+ ::ndk::ScopedAStatus ret =
+ interface->isStreamCombinationSupported(streamConfiguration, status);
+ if (!ret.isOk()) {
+ *status = false;
+ ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, ret.getMessage());
+ return mapToStatusT(ret);
+ }
+ return OK;
+
+}
+
+status_t AidlProviderInfo::convertToAidlHALStreamCombinationAndCameraIdsLocked(
+ const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs,
+ const std::set<std::string>& perfClassPrimaryCameraIds,
+ int targetSdkVersion,
+ std::vector<camera::provider::CameraIdAndStreamCombination>
+ *halCameraIdsAndStreamCombinations,
+ bool *earlyExit) {
+ binder::Status bStatus = binder::Status::ok();
+ std::vector<camera::provider::CameraIdAndStreamCombination> halCameraIdsAndStreamsV;
+ bool shouldExit = false;
+ status_t res = OK;
+ for (auto &cameraIdAndSessionConfig : cameraIdsAndSessionConfigs) {
+ const std::string& cameraId = cameraIdAndSessionConfig.mCameraId;
+ camera::device::StreamConfiguration streamConfiguration;
+ CameraMetadata deviceInfo;
+ bool overrideForPerfClass =
+ SessionConfigurationUtils::targetPerfClassPrimaryCamera(
+ perfClassPrimaryCameraIds, cameraId, targetSdkVersion);
+ res = mManager->getCameraCharacteristicsLocked(cameraId, overrideForPerfClass, &deviceInfo);
+ if (res != OK) {
+ return res;
+ }
+ camera3::metadataGetter getMetadata =
+ [this](const String8 &id, bool overrideForPerfClass) {
+ CameraMetadata physicalDeviceInfo;
+ mManager->getCameraCharacteristicsLocked(id.string(), overrideForPerfClass,
+ &physicalDeviceInfo);
+ return physicalDeviceInfo;
+ };
+ std::vector<std::string> physicalCameraIds;
+ mManager->isLogicalCameraLocked(cameraId, &physicalCameraIds);
+ bStatus =
+ SessionConfigurationUtils::convertToHALStreamCombination(
+ cameraIdAndSessionConfig.mSessionConfiguration,
+ String8(cameraId.c_str()), deviceInfo, getMetadata,
+ physicalCameraIds, streamConfiguration,
+ overrideForPerfClass, &shouldExit);
+ if (!bStatus.isOk()) {
+ ALOGE("%s: convertToHALStreamCombination failed", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if (shouldExit) {
+ *earlyExit = true;
+ return OK;
+ }
+ camera::provider::CameraIdAndStreamCombination halCameraIdAndStream;
+ halCameraIdAndStream.cameraId = cameraId;
+ halCameraIdAndStream.streamConfiguration = streamConfiguration;
+ halCameraIdsAndStreamsV.push_back(halCameraIdAndStream);
+ }
+ *halCameraIdsAndStreamCombinations = halCameraIdsAndStreamsV;
+ return OK;
+}
+
+status_t AidlProviderInfo::isConcurrentSessionConfigurationSupported(
+ const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs,
+ const std::set<std::string>& perfClassPrimaryCameraIds,
+ int targetSdkVersion, bool *isSupported) {
+
+ std::vector<camera::provider::CameraIdAndStreamCombination> halCameraIdsAndStreamCombinations;
+ bool knowUnsupported = false;
+ status_t res = convertToAidlHALStreamCombinationAndCameraIdsLocked(
+ cameraIdsAndSessionConfigs, perfClassPrimaryCameraIds,
+ targetSdkVersion, &halCameraIdsAndStreamCombinations, &knowUnsupported);
+ if (res != OK) {
+ ALOGE("%s unable to convert session configurations provided to HAL stream"
+ "combinations", __FUNCTION__);
+ return res;
+ }
+ if (knowUnsupported) {
+ // We got to know the streams aren't valid before doing the HAL
+ // call itself.
+ *isSupported = false;
+ return OK;
+ }
+
+ // Check if the provider is currently active - not going to start it up for this notification
+ auto interface = mSavedInterface != nullptr ? mSavedInterface : mActiveInterface.lock();
+ if (interface == nullptr) {
+ // TODO: This might be some other problem
+ return INVALID_OPERATION;
+ }
+ ::ndk::ScopedAStatus status = interface->isConcurrentStreamCombinationSupported(
+ halCameraIdsAndStreamCombinations, isSupported);
+ if (!status.isOk()) {
+ *isSupported = false;
+ ALOGE("%s: hal interface session configuration query failed", __FUNCTION__);
+ return mapToStatusT(status);
+ }
+
+ return OK;
+}
+
+} //namespace android
diff --git a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h
new file mode 100644
index 0000000..aa71e85
--- /dev/null
+++ b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2021 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_SERVERS_CAMERA_CAMERAPROVIDER_AIDLPROVIDERINFOH
+#define ANDROID_SERVERS_CAMERA_CAMERAPROVIDER_AIDLPROVIDERINFOH
+
+#include "common/CameraProviderManager.h"
+
+#include <aidl/android/hardware/camera/common/Status.h>
+#include <aidl/android/hardware/camera/provider/BnCameraProviderCallback.h>
+#include <aidl/android/hardware/camera/device/ICameraDevice.h>
+
+namespace android {
+
+struct AidlProviderInfo : public CameraProviderManager::ProviderInfo {
+ // Current overall Android device physical status
+ int64_t mDeviceState;
+
+ // This pointer is used to keep a reference to the ICameraProvider that was last accessed.
+ std::weak_ptr<aidl::android::hardware::camera::provider::ICameraProvider> mActiveInterface;
+
+ std::shared_ptr<aidl::android::hardware::camera::provider::ICameraProvider> mSavedInterface;
+
+ AidlProviderInfo(
+ const std::string &providerName,
+ const std::string &providerInstance,
+ CameraProviderManager *manager);
+
+ static status_t mapToStatusT(const ndk::ScopedAStatus& s);
+
+ // Start camera device interface, start the camera provider process for lazy
+ // hals, if needed
+ status_t initializeAidlProvider(
+ std::shared_ptr<aidl::android::hardware::camera::provider::ICameraProvider>& interface,
+ int64_t currentDeviceState);
+
+ static void binderDied(void *cookie);
+
+ virtual IPCTransport getIPCTransport() override {return IPCTransport::AIDL;}
+
+ const std::shared_ptr<aidl::android::hardware::camera::provider::ICameraProvider>
+ startProviderInterface();
+
+ virtual status_t setUpVendorTags() override;
+ virtual status_t notifyDeviceStateChange(int64_t newDeviceState) override;
+
+ virtual bool successfullyStartedProviderInterface() override;
+
+ virtual int64_t getDeviceState() override { return mDeviceState; };
+
+ /**
+ * Query the camera provider for concurrent stream configuration support
+ */
+ virtual status_t isConcurrentSessionConfigurationSupported(
+ const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs,
+ const std::set<std::string>& perfClassPrimaryCameraIds,
+ int targetSdkVersion, bool *isSupported) override;
+
+ std::shared_ptr<aidl::android::hardware::camera::device::ICameraDevice>
+ startDeviceInterface(const std::string &deviceName);
+
+ // AIDL ICameraProviderCallback interface - these lock the parent
+ // mInterfaceMutex
+
+ ::ndk::ScopedAStatus cameraDeviceStatusChange(const std::string& cameraDeviceName,
+ ::aidl::android::hardware::camera::common::CameraDeviceStatus newStatus);
+
+ ::ndk::ScopedAStatus torchModeStatusChange(const std::string& cameraDeviceName,
+ ::aidl::android::hardware::camera::common::TorchModeStatus newStatus);
+
+ ::ndk::ScopedAStatus physicalCameraDeviceStatusChange(
+ const std::string& cameraDeviceName,
+ const std::string& physicalCameraDeviceName,
+ ::aidl::android::hardware::camera::common::CameraDeviceStatus newStatus);
+
+ struct AidlProviderCallbacks :
+ public aidl::android::hardware::camera::provider::BnCameraProviderCallback {
+ AidlProviderCallbacks(wp<AidlProviderInfo> parent) : mParent(parent) { }
+ virtual ::ndk::ScopedAStatus cameraDeviceStatusChange(const std::string& cameraDeviceName,
+ ::aidl::android::hardware::camera::common::CameraDeviceStatus newStatus) override;
+
+ virtual ::ndk::ScopedAStatus torchModeStatusChange(const std::string& cameraDeviceName,
+ ::aidl::android::hardware::camera::common::TorchModeStatus newStatus) override;
+
+ virtual ::ndk::ScopedAStatus physicalCameraDeviceStatusChange(
+ const std::string& cameraDeviceName,
+ const std::string& physicalCameraDeviceName,
+ ::aidl::android::hardware::camera::common::CameraDeviceStatus newStatus) override;
+
+ private:
+ wp<AidlProviderInfo> mParent = nullptr;
+
+ };
+
+ struct AidlDeviceInfo3 : public CameraProviderManager::ProviderInfo::DeviceInfo3 {
+
+ //TODO: fix init
+ const hardware::hidl_version mVersion = hardware::hidl_version{3, 2};
+ std::shared_ptr<aidl::android::hardware::camera::device::ICameraDevice>
+ mSavedInterface = nullptr;
+
+ AidlDeviceInfo3(const std::string& , const metadata_vendor_id_t ,
+ const std::string &, uint16_t ,
+ const CameraResourceCost& ,
+ sp<ProviderInfo> ,
+ const std::vector<std::string>& ,
+ std::shared_ptr<aidl::android::hardware::camera::device::ICameraDevice>);
+
+ ~AidlDeviceInfo3() {}
+
+ virtual status_t setTorchMode(bool enabled) override;
+ virtual status_t turnOnTorchWithStrengthLevel(int32_t torchStrength) override;
+ virtual status_t getTorchStrengthLevel(int32_t *torchStrength) override;
+
+ virtual status_t dumpState(int fd) override;
+
+ virtual status_t isSessionConfigurationSupported(
+ const SessionConfiguration &/*configuration*/,
+ bool overrideForPerfClass,
+ bool *status/*status*/);
+
+ std::shared_ptr<aidl::android::hardware::camera::device::ICameraDevice>
+ startDeviceInterface();
+ };
+
+ private:
+
+ // Helper for initializeDeviceInfo to use the right CameraProvider get method.
+ virtual std::unique_ptr<DeviceInfo> initializeDeviceInfo(const std::string &,
+ const metadata_vendor_id_t , const std::string &,
+ uint16_t ) override;
+
+ virtual status_t reCacheConcurrentStreamingCameraIdsLocked() override;
+
+ //Expects to have mLock locked
+
+ status_t getConcurrentCameraIdsInternalLocked(
+ std::shared_ptr<aidl::android::hardware::camera::provider::ICameraProvider> &interface);
+
+ //expects to have mManager->mInterfaceMutex locked
+
+ status_t convertToAidlHALStreamCombinationAndCameraIdsLocked(
+ const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs,
+ const std::set<std::string>& perfClassPrimaryCameraIds,
+ int targetSdkVersion,
+ std::vector<aidl::android::hardware::camera::provider::CameraIdAndStreamCombination>
+ *halCameraIdsAndStreamCombinations,
+ bool *earlyExit);
+ std::shared_ptr<AidlProviderCallbacks> mCallbacks = nullptr;
+ ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+
+};
+
+} // namespace android
+#endif
diff --git a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
new file mode 100644
index 0000000..3c5ea75
--- /dev/null
+++ b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
@@ -0,0 +1,1127 @@
+/*
+ * Copyright (C) 2022 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 "HidlProviderInfo.h"
+#include "common/HalConversionsTemplated.h"
+#include "common/CameraProviderInfoTemplated.h"
+
+#include <cutils/properties.h>
+
+#include <android/hardware/ICameraService.h>
+#include <camera_metadata_hidden.h>
+
+#include "device3/ZoomRatioMapper.h"
+#include <utils/SessionConfigurationUtils.h>
+#include <utils/Trace.h>
+
+#include <android/hardware/camera/device/3.7/ICameraDevice.h>
+#include <android/hardware/camera/device/3.8/ICameraDevice.h>
+
+namespace {
+const bool kEnableLazyHal(property_get_bool("ro.camera.enableLazyHal", false));
+} // anonymous namespace
+
+namespace android {
+
+using namespace android::camera3;
+using namespace hardware::camera;
+using hardware::camera::common::V1_0::VendorTagSection;
+using hardware::camera::common::V1_0::Status;
+using hardware::camera::provider::V2_7::CameraIdAndStreamCombination;
+using hardware::camera2::utils::CameraIdAndSessionConfiguration;
+
+
+using StatusListener = CameraProviderManager::StatusListener;
+using HalDeviceStatusType = android::hardware::camera::common::V1_0::CameraDeviceStatus;
+
+using hardware::camera::provider::V2_5::DeviceState;
+using hardware::ICameraService;
+
+status_t HidlProviderInfo::mapToStatusT(const Status& s) {
+ switch(s) {
+ case Status::OK:
+ return OK;
+ case Status::ILLEGAL_ARGUMENT:
+ return BAD_VALUE;
+ case Status::CAMERA_IN_USE:
+ return -EBUSY;
+ case Status::MAX_CAMERAS_IN_USE:
+ return -EUSERS;
+ case Status::METHOD_NOT_SUPPORTED:
+ return UNKNOWN_TRANSACTION;
+ case Status::OPERATION_NOT_SUPPORTED:
+ return INVALID_OPERATION;
+ case Status::CAMERA_DISCONNECTED:
+ return DEAD_OBJECT;
+ case Status::INTERNAL_ERROR:
+ return INVALID_OPERATION;
+ }
+ ALOGW("Unexpected HAL status code %d", s);
+ return INVALID_OPERATION;
+}
+
+static hardware::hidl_bitfield<DeviceState> mapToHidlDeviceState(int64_t newState) {
+ hardware::hidl_bitfield<DeviceState> newDeviceState{};
+ if (newState & ICameraService::DEVICE_STATE_BACK_COVERED) {
+ newDeviceState |= DeviceState::BACK_COVERED;
+ }
+ if (newState & ICameraService::DEVICE_STATE_FRONT_COVERED) {
+ newDeviceState |= DeviceState::FRONT_COVERED;
+ }
+ if (newState & ICameraService::DEVICE_STATE_FOLDED) {
+ newDeviceState |= DeviceState::FOLDED;
+ }
+ // Only map vendor bits directly
+ uint64_t vendorBits = static_cast<uint64_t>(newState) & 0xFFFFFFFF00000000l;
+ newDeviceState |= vendorBits;
+
+ ALOGV("%s: New device state 0x%" PRIx64, __FUNCTION__, newDeviceState);
+ return newDeviceState;
+}
+
+const char* statusToString(const Status& s) {
+ switch(s) {
+ case Status::OK:
+ return "OK";
+ case Status::ILLEGAL_ARGUMENT:
+ return "ILLEGAL_ARGUMENT";
+ case Status::CAMERA_IN_USE:
+ return "CAMERA_IN_USE";
+ case Status::MAX_CAMERAS_IN_USE:
+ return "MAX_CAMERAS_IN_USE";
+ case Status::METHOD_NOT_SUPPORTED:
+ return "METHOD_NOT_SUPPORTED";
+ case Status::OPERATION_NOT_SUPPORTED:
+ return "OPERATION_NOT_SUPPORTED";
+ case Status::CAMERA_DISCONNECTED:
+ return "CAMERA_DISCONNECTED";
+ case Status::INTERNAL_ERROR:
+ return "INTERNAL_ERROR";
+ }
+ ALOGW("Unexpected HAL status code %d", s);
+ return "UNKNOWN_ERROR";
+}
+
+status_t HidlProviderInfo::initializeHidlProvider(
+ sp<provider::V2_4::ICameraProvider>& interface,
+ int64_t currentDeviceState) {
+ status_t res = parseProviderName(mProviderName, &mType, &mId);
+ if (res != OK) {
+ ALOGE("%s: Invalid provider name, ignoring", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ ALOGI("Connecting to new camera provider: %s, isRemote? %d",
+ mProviderName.c_str(), interface->isRemote());
+
+ // Determine minor version
+ mMinorVersion = 4;
+ auto cast2_6 = provider::V2_6::ICameraProvider::castFrom(interface);
+ sp<provider::V2_6::ICameraProvider> interface2_6 = nullptr;
+ if (cast2_6.isOk()) {
+ interface2_6 = cast2_6;
+ if (interface2_6 != nullptr) {
+ mMinorVersion = 6;
+ }
+ }
+ // We need to check again since cast2_6.isOk() succeeds even if the provider
+ // version isn't actually 2.6.
+ if (interface2_6 == nullptr){
+ auto cast2_5 =
+ provider::V2_5::ICameraProvider::castFrom(interface);
+ sp<provider::V2_5::ICameraProvider> interface2_5 = nullptr;
+ if (cast2_5.isOk()) {
+ interface2_5 = cast2_5;
+ if (interface != nullptr) {
+ mMinorVersion = 5;
+ }
+ }
+ } else {
+ auto cast2_7 = provider::V2_7::ICameraProvider::castFrom(interface);
+ if (cast2_7.isOk()) {
+ sp<provider::V2_7::ICameraProvider> interface2_7 = cast2_7;
+ if (interface2_7 != nullptr) {
+ mMinorVersion = 7;
+ }
+ }
+ }
+
+ // cameraDeviceStatusChange callbacks may be called (and causing new devices added)
+ // before setCallback returns
+ hardware::Return<Status> status = interface->setCallback(this);
+ if (!status.isOk()) {
+ ALOGE("%s: Transaction error setting up callbacks with camera provider '%s': %s",
+ __FUNCTION__, mProviderName.c_str(), status.description().c_str());
+ return DEAD_OBJECT;
+ }
+ if (status != Status::OK) {
+ ALOGE("%s: Unable to register callbacks with camera provider '%s'",
+ __FUNCTION__, mProviderName.c_str());
+ return mapToStatusT(status);
+ }
+
+ hardware::Return<bool> linked = interface->linkToDeath(this, /*cookie*/ mId);
+ if (!linked.isOk()) {
+ ALOGE("%s: Transaction error in linking to camera provider '%s' death: %s",
+ __FUNCTION__, mProviderName.c_str(), linked.description().c_str());
+ return DEAD_OBJECT;
+ } else if (!linked) {
+ ALOGW("%s: Unable to link to provider '%s' death notifications",
+ __FUNCTION__, mProviderName.c_str());
+ }
+
+ if (!kEnableLazyHal) {
+ // Save HAL reference indefinitely
+ mSavedInterface = interface;
+ } else {
+ mActiveInterface = interface;
+ }
+
+ ALOGV("%s: Setting device state for %s: 0x%" PRIx64,
+ __FUNCTION__, mProviderName.c_str(), mDeviceState);
+ notifyDeviceStateChange(currentDeviceState);
+
+ res = setUpVendorTags();
+ if (res != OK) {
+ ALOGE("%s: Unable to set up vendor tags from provider '%s'",
+ __FUNCTION__, mProviderName.c_str());
+ return res;
+ }
+
+ // Get initial list of camera devices, if any
+ std::vector<std::string> devices;
+ hardware::Return<void> ret = interface->getCameraIdList([&status, this, &devices](
+ Status idStatus,
+ const hardware::hidl_vec<hardware::hidl_string>& cameraDeviceNames) {
+ status = idStatus;
+ if (status == Status::OK) {
+ for (auto& name : cameraDeviceNames) {
+ uint16_t major, minor;
+ std::string type, id;
+ status_t res = parseDeviceName(name, &major, &minor, &type, &id);
+ if (res != OK) {
+ ALOGE("%s: Error parsing deviceName: %s: %d", __FUNCTION__, name.c_str(), res);
+ status = Status::INTERNAL_ERROR;
+ } else {
+ devices.push_back(name);
+ mProviderPublicCameraIds.push_back(id);
+ }
+ }
+ } });
+ if (!ret.isOk()) {
+ ALOGE("%s: Transaction error in getting camera ID list from provider '%s': %s",
+ __FUNCTION__, mProviderName.c_str(), linked.description().c_str());
+ return DEAD_OBJECT;
+ }
+ if (status != Status::OK) {
+ ALOGE("%s: Unable to query for camera devices from provider '%s'",
+ __FUNCTION__, mProviderName.c_str());
+ return mapToStatusT(status);
+ }
+
+ // Get list of concurrent streaming camera device combinations
+ if (mMinorVersion >= 6) {
+ res = getConcurrentCameraIdsInternalLocked(interface2_6);
+ if (res != OK) {
+ return res;
+ }
+ }
+
+ ret = interface->isSetTorchModeSupported(
+ [this](auto status, bool supported) {
+ if (status == Status::OK) {
+ mSetTorchModeSupported = supported;
+ }
+ });
+ if (!ret.isOk()) {
+ ALOGE("%s: Transaction error checking torch mode support '%s': %s",
+ __FUNCTION__, mProviderName.c_str(), ret.description().c_str());
+ return DEAD_OBJECT;
+ }
+
+ mIsRemote = interface->isRemote();
+
+ initializeProviderInfoCommon(devices);
+
+ return OK;
+}
+
+status_t HidlProviderInfo::setUpVendorTags() {
+ if (mVendorTagDescriptor != nullptr)
+ return OK;
+
+ hardware::hidl_vec<VendorTagSection> vts;
+ Status status;
+ hardware::Return<void> ret;
+ const sp<hardware::camera::provider::V2_4::ICameraProvider> interface =
+ startProviderInterface();
+ if (interface == nullptr) {
+ return DEAD_OBJECT;
+ }
+ ret = interface->getVendorTags(
+ [&](auto s, const auto& vendorTagSecs) {
+ status = s;
+ if (s == Status::OK) {
+ vts = vendorTagSecs;
+ }
+ });
+ if (!ret.isOk()) {
+ ALOGE("%s: Transaction error getting vendor tags from provider '%s': %s",
+ __FUNCTION__, mProviderName.c_str(), ret.description().c_str());
+ return DEAD_OBJECT;
+ }
+ if (status != Status::OK) {
+ return mapToStatusT(status);
+ }
+
+ // Read all vendor tag definitions into a descriptor
+ status_t res;
+ if ((res = IdlVendorTagDescriptor::createDescriptorFromIdl<
+ hardware::hidl_vec<hardware::camera::common::V1_0::VendorTagSection>,
+ hardware::camera::common::V1_0::VendorTagSection>(vts,
+ /*out*/mVendorTagDescriptor))
+ != OK) {
+ ALOGE("%s: Could not generate descriptor from vendor tag operations,"
+ "received error %s (%d). Camera clients will not be able to use"
+ "vendor tags", __FUNCTION__, strerror(res), res);
+ return res;
+ }
+
+ return OK;
+}
+
+status_t HidlProviderInfo::notifyDeviceStateChange(int64_t newDeviceState) {
+ mDeviceState = mapToHidlDeviceState(newDeviceState);
+ if (mMinorVersion >= 5) {
+ // Check if the provider is currently active - not going to start it for this notification
+ auto interface = mSavedInterface != nullptr ? mSavedInterface : mActiveInterface.promote();
+ if (interface != nullptr) {
+ // Send current device state
+ auto castResult = provider::V2_5::ICameraProvider::castFrom(interface);
+ if (castResult.isOk()) {
+ sp<provider::V2_5::ICameraProvider> interface_2_5 = castResult;
+ if (interface_2_5 != nullptr) {
+ interface_2_5->notifyDeviceStateChange(mDeviceState);
+ }
+ }
+ }
+ }
+ return OK;
+}
+
+sp<device::V3_2::ICameraDevice>
+HidlProviderInfo::startDeviceInterface(const std::string &name) {
+ Status status;
+ sp<device::V3_2::ICameraDevice> cameraInterface;
+ hardware::Return<void> ret;
+ const sp<provider::V2_4::ICameraProvider> interface = startProviderInterface();
+ if (interface == nullptr) {
+ return nullptr;
+ }
+ ret = interface->getCameraDeviceInterface_V3_x(name, [&status, &cameraInterface](
+ Status s, sp<device::V3_2::ICameraDevice> interface) {
+ status = s;
+ cameraInterface = interface;
+ });
+ if (!ret.isOk()) {
+ ALOGE("%s: Transaction error trying to obtain interface for camera device %s: %s",
+ __FUNCTION__, name.c_str(), ret.description().c_str());
+ return nullptr;
+ }
+ if (status != Status::OK) {
+ ALOGE("%s: Unable to obtain interface for camera device %s: %s", __FUNCTION__,
+ name.c_str(), statusToString(status));
+ return nullptr;
+ }
+ return cameraInterface;
+}
+
+bool HidlProviderInfo::successfullyStartedProviderInterface() {
+ return startProviderInterface() != nullptr;
+}
+
+const sp<provider::V2_4::ICameraProvider>
+HidlProviderInfo::startProviderInterface() {
+ ATRACE_CALL();
+ ALOGV("Request to start camera provider: %s", mProviderName.c_str());
+ if (mSavedInterface != nullptr) {
+ return mSavedInterface;
+ }
+ if (!kEnableLazyHal) {
+ ALOGE("Bad provider state! Should not be here on a non-lazy HAL!");
+ return nullptr;
+ }
+
+ auto interface = mActiveInterface.promote();
+ if (interface == nullptr) {
+ // Try to get service without starting
+ interface = mManager->mHidlServiceProxy->tryGetService(mProviderName);
+ if (interface == nullptr) {
+ ALOGV("Camera provider actually needs restart, calling getService(%s)",
+ mProviderName.c_str());
+ interface = mManager->mHidlServiceProxy->getService(mProviderName);
+
+ // Set all devices as ENUMERATING, provider should update status
+ // to PRESENT after initializing.
+ // This avoids failing getCameraDeviceInterface_V3_x before devices
+ // are ready.
+ for (auto& device : mDevices) {
+ device->mIsDeviceAvailable = false;
+ }
+
+ interface->setCallback(this);
+ hardware::Return<bool>
+ linked = interface->linkToDeath(this, /*cookie*/ mId);
+ if (!linked.isOk()) {
+ ALOGE(
+ "%s: Transaction error in linking to camera provider '%s' death: %s",
+ __FUNCTION__,
+ mProviderName.c_str(),
+ linked.description().c_str());
+ mManager->removeProvider(mProviderName);
+ return nullptr;
+ } else if (!linked) {
+ ALOGW("%s: Unable to link to provider '%s' death notifications",
+ __FUNCTION__, mProviderName.c_str());
+ }
+ // Send current device state
+ if (mMinorVersion >= 5) {
+ auto castResult =
+ provider::V2_5::ICameraProvider::castFrom(interface);
+ if (castResult.isOk()) {
+ sp<provider::V2_5::ICameraProvider> interface_2_5 = castResult;
+ if (interface_2_5 != nullptr) {
+ ALOGV("%s: Initial device state for %s: 0x %" PRIx64,
+ __FUNCTION__, mProviderName.c_str(), mDeviceState);
+ interface_2_5->notifyDeviceStateChange(mDeviceState);
+ }
+ }
+ }
+ }
+ mActiveInterface = interface;
+ } else {
+ ALOGV("Camera provider (%s) already in use. Re-using instance.",
+ mProviderName.c_str());
+ }
+
+ return interface;
+}
+
+hardware::Return<void> HidlProviderInfo::cameraDeviceStatusChange(
+ const hardware::hidl_string& cameraDeviceName,
+ HalDeviceStatusType newStatus) {
+ cameraDeviceStatusChangeInternal(cameraDeviceName, HalToFrameworkCameraDeviceStatus(newStatus));
+ return hardware::Void();
+}
+
+hardware::Return<void> HidlProviderInfo::physicalCameraDeviceStatusChange(
+ const hardware::hidl_string& cameraDeviceName,
+ const hardware::hidl_string& physicalCameraDeviceName,
+ HalDeviceStatusType newStatus) {
+ physicalCameraDeviceStatusChangeInternal(cameraDeviceName, physicalCameraDeviceName,
+ HalToFrameworkCameraDeviceStatus(newStatus));
+ return hardware::Void();
+}
+
+hardware::Return<void> HidlProviderInfo::torchModeStatusChange(
+ const hardware::hidl_string& cameraDeviceName,
+ hardware::camera::common::V1_0::TorchModeStatus newStatus) {
+
+ torchModeStatusChangeInternal(cameraDeviceName, HalToFrameworkTorchModeStatus(newStatus));
+ return hardware::Void();
+}
+
+void HidlProviderInfo::serviceDied(uint64_t cookie,
+ const wp<hidl::base::V1_0::IBase>& who) {
+ (void) who;
+ ALOGI("Camera provider '%s' has died; removing it", mProviderInstance.c_str());
+ if (cookie != mId) {
+ ALOGW("%s: Unexpected serviceDied cookie %" PRIu64 ", expected %" PRIu32,
+ __FUNCTION__, cookie, mId);
+ }
+ mManager->removeProvider(mProviderInstance);
+}
+
+std::unique_ptr<CameraProviderManager::ProviderInfo::DeviceInfo>
+ HidlProviderInfo::initializeDeviceInfo(
+ const std::string &name, const metadata_vendor_id_t tagId,
+ const std::string &id, uint16_t minorVersion) {
+ Status status;
+
+ auto cameraInterface = startDeviceInterface(name);
+ if (cameraInterface == nullptr) return nullptr;
+
+ common::V1_0::CameraResourceCost resourceCost;
+ cameraInterface->getResourceCost([&status, &resourceCost](
+ Status s, common::V1_0::CameraResourceCost cost) {
+ status = s;
+ resourceCost = cost;
+ });
+ if (status != Status::OK) {
+ ALOGE("%s: Unable to obtain resource costs for camera device %s: %s", __FUNCTION__,
+ name.c_str(), statusToString(status));
+ return nullptr;
+ }
+
+ for (auto& conflictName : resourceCost.conflictingDevices) {
+ uint16_t major, minor;
+ std::string type, id;
+ status_t res = parseDeviceName(conflictName, &major, &minor, &type, &id);
+ if (res != OK) {
+ ALOGE("%s: Failed to parse conflicting device %s", __FUNCTION__, conflictName.c_str());
+ return nullptr;
+ }
+ conflictName = id;
+ }
+
+ return std::unique_ptr<DeviceInfo3>(
+ new HidlDeviceInfo3(name, tagId, id, minorVersion, HalToFrameworkResourceCost(resourceCost),
+ this, mProviderPublicCameraIds, cameraInterface));
+}
+
+status_t HidlProviderInfo::reCacheConcurrentStreamingCameraIdsLocked() {
+ if (mMinorVersion < 6) {
+ // Unsupported operation, nothing to do here
+ return OK;
+ }
+ // Check if the provider is currently active - not going to start it up for this notification
+ auto interface = mSavedInterface != nullptr ? mSavedInterface : mActiveInterface.promote();
+ if (interface == nullptr) {
+ ALOGE("%s: camera provider interface for %s is not valid", __FUNCTION__,
+ mProviderName.c_str());
+ return INVALID_OPERATION;
+ }
+ auto castResult = provider::V2_6::ICameraProvider::castFrom(interface);
+
+ if (castResult.isOk()) {
+ sp<provider::V2_6::ICameraProvider> interface2_6 = castResult;
+ if (interface2_6 != nullptr) {
+ return getConcurrentCameraIdsInternalLocked(interface2_6);
+ } else {
+ // This should not happen since mMinorVersion >= 6
+ ALOGE("%s: mMinorVersion was >= 6, but interface2_6 was nullptr", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+ }
+ return OK;
+}
+
+status_t HidlProviderInfo::getConcurrentCameraIdsInternalLocked(
+ sp<provider::V2_6::ICameraProvider> &interface2_6) {
+ if (interface2_6 == nullptr) {
+ ALOGE("%s: null interface provided", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ Status status = Status::OK;
+ hardware::Return<void> ret =
+ interface2_6->getConcurrentStreamingCameraIds([&status, this](
+ Status concurrentIdStatus, // TODO: Move all instances of hidl_string to 'using'
+ const hardware::hidl_vec<hardware::hidl_vec<hardware::hidl_string>>&
+ cameraDeviceIdCombinations) {
+ status = concurrentIdStatus;
+ if (status == Status::OK) {
+ mConcurrentCameraIdCombinations.clear();
+ for (auto& combination : cameraDeviceIdCombinations) {
+ std::unordered_set<std::string> deviceIds;
+ for (auto &cameraDeviceId : combination) {
+ deviceIds.insert(cameraDeviceId.c_str());
+ }
+ mConcurrentCameraIdCombinations.push_back(std::move(deviceIds));
+ }
+ } });
+ if (!ret.isOk()) {
+ ALOGE("%s: Transaction error in getting concurrent camera ID list from provider '%s'",
+ __FUNCTION__, mProviderName.c_str());
+ return DEAD_OBJECT;
+ }
+ if (status != Status::OK) {
+ ALOGE("%s: Unable to query for camera devices from provider '%s'",
+ __FUNCTION__, mProviderName.c_str());
+ return mapToStatusT(status);
+ }
+ return OK;
+}
+
+HidlProviderInfo::HidlDeviceInfo3::HidlDeviceInfo3(
+ const std::string& name,
+ const metadata_vendor_id_t tagId,
+ const std::string &id, uint16_t minorVersion,
+ const CameraResourceCost& resourceCost,
+ sp<CameraProviderManager::ProviderInfo> parentProvider,
+ const std::vector<std::string>& publicCameraIds,
+ sp<hardware::camera::device::V3_2::ICameraDevice> interface) :
+ DeviceInfo3(name, tagId, id, minorVersion, resourceCost, parentProvider, publicCameraIds) {
+
+ // Get camera characteristics and initialize flash unit availability
+ Status status;
+ hardware::Return<void> ret;
+ ret = interface->getCameraCharacteristics([&status, this](Status s,
+ device::V3_2::CameraMetadata metadata) {
+ status = s;
+ if (s == Status::OK) {
+ camera_metadata_t *buffer =
+ reinterpret_cast<camera_metadata_t*>(metadata.data());
+ size_t expectedSize = metadata.size();
+ int res = validate_camera_metadata_structure(buffer, &expectedSize);
+ if (res == OK || res == CAMERA_METADATA_VALIDATION_SHIFTED) {
+ set_camera_metadata_vendor_id(buffer, mProviderTagid);
+ mCameraCharacteristics = buffer;
+ } else {
+ ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
+ status = Status::INTERNAL_ERROR;
+ }
+ }
+ });
+ if (!ret.isOk()) {
+ ALOGE("%s: Transaction error getting camera characteristics for device %s"
+ " to check for a flash unit: %s", __FUNCTION__, id.c_str(),
+ ret.description().c_str());
+ return;
+ }
+ if (status != Status::OK) {
+ ALOGE("%s: Unable to get camera characteristics for device %s: %s (%d)",
+ __FUNCTION__, id.c_str(), statusToString(status), status);
+ return;
+ }
+
+ if (mCameraCharacteristics.exists(ANDROID_INFO_DEVICE_STATE_ORIENTATIONS)) {
+ const auto &stateMap = mCameraCharacteristics.find(ANDROID_INFO_DEVICE_STATE_ORIENTATIONS);
+ if ((stateMap.count > 0) && ((stateMap.count % 2) == 0)) {
+ for (size_t i = 0; i < stateMap.count; i += 2) {
+ mDeviceStateOrientationMap.emplace(stateMap.data.i64[i], stateMap.data.i64[i+1]);
+ }
+ } else {
+ ALOGW("%s: Invalid ANDROID_INFO_DEVICE_STATE_ORIENTATIONS map size: %zu", __FUNCTION__,
+ stateMap.count);
+ }
+ }
+
+ mSystemCameraKind = getSystemCameraKind();
+
+ status_t res = fixupMonochromeTags();
+ if (OK != res) {
+ ALOGE("%s: Unable to fix up monochrome tags based for older HAL version: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return;
+ }
+ auto stat = addDynamicDepthTags();
+ if (OK != stat) {
+ ALOGE("%s: Failed appending dynamic depth tags: %s (%d)", __FUNCTION__, strerror(-stat),
+ stat);
+ }
+ res = deriveHeicTags();
+ if (OK != res) {
+ ALOGE("%s: Unable to derive HEIC tags based on camera and media capabilities: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ }
+
+ if (SessionConfigurationUtils::isUltraHighResolutionSensor(mCameraCharacteristics)) {
+ status_t status = addDynamicDepthTags(/*maxResolution*/true);
+ if (OK != status) {
+ ALOGE("%s: Failed appending dynamic depth tags for maximum resolution mode: %s (%d)",
+ __FUNCTION__, strerror(-status), status);
+ }
+
+ status = deriveHeicTags(/*maxResolution*/true);
+ if (OK != status) {
+ ALOGE("%s: Unable to derive HEIC tags based on camera and media capabilities for"
+ "maximum resolution mode: %s (%d)", __FUNCTION__, strerror(-status), status);
+ }
+ }
+
+ res = addRotateCropTags();
+ if (OK != res) {
+ ALOGE("%s: Unable to add default SCALER_ROTATE_AND_CROP tags: %s (%d)", __FUNCTION__,
+ strerror(-res), res);
+ }
+ res = addPreCorrectionActiveArraySize();
+ if (OK != res) {
+ ALOGE("%s: Unable to add PRE_CORRECTION_ACTIVE_ARRAY_SIZE: %s (%d)", __FUNCTION__,
+ strerror(-res), res);
+ }
+ res = camera3::ZoomRatioMapper::overrideZoomRatioTags(
+ &mCameraCharacteristics, &mSupportNativeZoomRatio);
+ if (OK != res) {
+ ALOGE("%s: Unable to override zoomRatio related tags: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ }
+
+ camera_metadata_entry flashAvailable =
+ mCameraCharacteristics.find(ANDROID_FLASH_INFO_AVAILABLE);
+ if (flashAvailable.count == 1 &&
+ flashAvailable.data.u8[0] == ANDROID_FLASH_INFO_AVAILABLE_TRUE) {
+ mHasFlashUnit = true;
+ } else {
+ mHasFlashUnit = false;
+ }
+
+ camera_metadata_entry entry =
+ mCameraCharacteristics.find(ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL);
+ if (entry.count == 1) {
+ mTorchDefaultStrengthLevel = entry.data.i32[0];
+ } else {
+ mTorchDefaultStrengthLevel = 0;
+ }
+ entry = mCameraCharacteristics.find(ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL);
+ if (entry.count == 1) {
+ mTorchMaximumStrengthLevel = entry.data.i32[0];
+ } else {
+ mTorchMaximumStrengthLevel = 0;
+ }
+
+ mTorchStrengthLevel = 0;
+
+ queryPhysicalCameraIds();
+
+ // Get physical camera characteristics if applicable
+ auto castResult = device::V3_5::ICameraDevice::castFrom(interface);
+ if (!castResult.isOk()) {
+ ALOGV("%s: Unable to convert ICameraDevice instance to version 3.5", __FUNCTION__);
+ return;
+ }
+ sp<device::V3_5::ICameraDevice> interface_3_5 = castResult;
+ if (interface_3_5 == nullptr) {
+ ALOGE("%s: Converted ICameraDevice instance to nullptr", __FUNCTION__);
+ return;
+ }
+
+ if (mIsLogicalCamera) {
+ for (auto& id : mPhysicalIds) {
+ if (std::find(mPublicCameraIds.begin(), mPublicCameraIds.end(), id) !=
+ mPublicCameraIds.end()) {
+ continue;
+ }
+
+ hardware::hidl_string hidlId(id);
+ ret = interface_3_5->getPhysicalCameraCharacteristics(hidlId,
+ [&status, &id, this](Status s, device::V3_2::CameraMetadata metadata) {
+ status = s;
+ if (s == Status::OK) {
+ camera_metadata_t *buffer =
+ reinterpret_cast<camera_metadata_t*>(metadata.data());
+ size_t expectedSize = metadata.size();
+ int res = validate_camera_metadata_structure(buffer, &expectedSize);
+ if (res == OK || res == CAMERA_METADATA_VALIDATION_SHIFTED) {
+ set_camera_metadata_vendor_id(buffer, mProviderTagid);
+ mPhysicalCameraCharacteristics[id] = buffer;
+ } else {
+ ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
+ status = Status::INTERNAL_ERROR;
+ }
+ }
+ });
+
+ if (!ret.isOk()) {
+ ALOGE("%s: Transaction error getting physical camera %s characteristics for %s: %s",
+ __FUNCTION__, id.c_str(), id.c_str(), ret.description().c_str());
+ return;
+ }
+ if (status != Status::OK) {
+ ALOGE("%s: Unable to get physical camera %s characteristics for device %s: %s (%d)",
+ __FUNCTION__, id.c_str(), mId.c_str(),
+ statusToString(status), status);
+ return;
+ }
+
+ res = camera3::ZoomRatioMapper::overrideZoomRatioTags(
+ &mPhysicalCameraCharacteristics[id], &mSupportNativeZoomRatio);
+ if (OK != res) {
+ ALOGE("%s: Unable to override zoomRatio related tags: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ }
+ }
+ }
+
+ if (!kEnableLazyHal) {
+ // Save HAL reference indefinitely
+ mSavedInterface = interface;
+ }
+
+
+}
+
+status_t HidlProviderInfo::HidlDeviceInfo3::setTorchMode(bool enabled) {
+ using hardware::camera::common::V1_0::TorchMode;
+ const sp<hardware::camera::device::V3_2::ICameraDevice> interface = startDeviceInterface();
+ Status s = interface->setTorchMode(enabled ? TorchMode::ON : TorchMode::OFF);
+ return mapToStatusT(s);
+}
+
+status_t HidlProviderInfo::HidlDeviceInfo3::turnOnTorchWithStrengthLevel(
+ int32_t torchStrength) {
+ const sp<hardware::camera::device::V3_2::ICameraDevice> interface = startDeviceInterface();
+ if (interface == nullptr) {
+ return DEAD_OBJECT;
+ }
+ sp<hardware::camera::device::V3_8::ICameraDevice> interface_3_8 = nullptr;
+ auto castResult_3_8 = device::V3_8::ICameraDevice::castFrom(interface);
+ if (castResult_3_8.isOk()) {
+ interface_3_8 = castResult_3_8;
+ }
+
+ if (interface_3_8 == nullptr) {
+ return INVALID_OPERATION;
+ }
+
+ Status s = interface_3_8->turnOnTorchWithStrengthLevel(torchStrength);
+ if (s == Status::OK) {
+ mTorchStrengthLevel = torchStrength;
+ }
+ return mapToStatusT(s);
+}
+
+status_t HidlProviderInfo::HidlDeviceInfo3::getTorchStrengthLevel(int32_t *torchStrength) {
+ if (torchStrength == nullptr) {
+ return BAD_VALUE;
+ }
+ const sp<hardware::camera::device::V3_2::ICameraDevice> interface = startDeviceInterface();
+ if (interface == nullptr) {
+ return DEAD_OBJECT;
+ }
+ auto castResult_3_8 = device::V3_8::ICameraDevice::castFrom(interface);
+ sp<hardware::camera::device::V3_8::ICameraDevice> interface_3_8 = nullptr;
+ if (castResult_3_8.isOk()) {
+ interface_3_8 = castResult_3_8;
+ }
+
+ if (interface_3_8 == nullptr) {
+ return INVALID_OPERATION;
+ }
+
+ Status callStatus;
+ status_t res;
+ hardware::Return<void> ret = interface_3_8->getTorchStrengthLevel([&callStatus, &torchStrength]
+ (Status status, const int32_t& torchStrengthLevel) {
+ callStatus = status;
+ if (status == Status::OK) {
+ *torchStrength = torchStrengthLevel;
+ } });
+
+ if (ret.isOk()) {
+ switch (callStatus) {
+ case Status::OK:
+ // Expected case, do nothing.
+ res = OK;
+ break;
+ case Status::METHOD_NOT_SUPPORTED:
+ res = INVALID_OPERATION;
+ break;
+ default:
+ ALOGE("%s: Get torch strength level failed: %d", __FUNCTION__, callStatus);
+ res = UNKNOWN_ERROR;
+ }
+ } else {
+ ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, ret.description().c_str());
+ res = UNKNOWN_ERROR;
+ }
+
+ return res;
+}
+
+sp<hardware::camera::device::V3_2::ICameraDevice>
+HidlProviderInfo::HidlDeviceInfo3::startDeviceInterface() {
+ Mutex::Autolock l(mDeviceAvailableLock);
+ sp<hardware::camera::device::V3_2::ICameraDevice> device;
+ ATRACE_CALL();
+ if (mSavedInterface == nullptr) {
+ sp<HidlProviderInfo> parentProvider =
+ static_cast<HidlProviderInfo *>(mParentProvider.promote().get());
+ if (parentProvider != nullptr) {
+ // Wait for lazy HALs to confirm device availability
+ if (parentProvider->isExternalLazyHAL() && !mIsDeviceAvailable) {
+ ALOGV("%s: Wait for external device to become available %s",
+ __FUNCTION__,
+ mId.c_str());
+
+ auto res = mDeviceAvailableSignal.waitRelative(mDeviceAvailableLock,
+ kDeviceAvailableTimeout);
+ if (res != OK) {
+ ALOGE("%s: Failed waiting for device to become available",
+ __FUNCTION__);
+ return nullptr;
+ }
+ }
+
+ device = parentProvider->startDeviceInterface(mName);
+ }
+ } else {
+ device = (hardware::camera::device::V3_2::ICameraDevice *) mSavedInterface.get();
+ }
+ return device;
+}
+
+status_t HidlProviderInfo::HidlDeviceInfo3::dumpState(int fd) {
+ native_handle_t* handle = native_handle_create(1,0);
+ handle->data[0] = fd;
+ const sp<hardware::camera::device::V3_2::ICameraDevice> interface =
+ startDeviceInterface();
+ if (interface == nullptr) {
+ return DEAD_OBJECT;
+ }
+ auto ret = interface->dumpState(handle);
+ native_handle_delete(handle);
+ if (!ret.isOk()) {
+ return INVALID_OPERATION;
+ }
+ return OK;
+}
+
+status_t HidlProviderInfo::HidlDeviceInfo3::isSessionConfigurationSupported(
+ const SessionConfiguration &configuration, bool overrideForPerfClass, bool *status) {
+
+ hardware::camera::device::V3_8::StreamConfiguration streamConfiguration;
+ bool earlyExit = false;
+ camera3::metadataGetter getMetadata = [this](const String8 &id, bool /*overrideForPerfClass*/) {
+ CameraMetadata physicalChars;
+ getPhysicalCameraCharacteristics(id.c_str(), &physicalChars);
+ return physicalChars;
+ };
+ auto bRes = SessionConfigurationUtils::convertToHALStreamCombination(configuration,
+ String8(mId.c_str()), mCameraCharacteristics, getMetadata, mPhysicalIds,
+ streamConfiguration, overrideForPerfClass, &earlyExit);
+
+ if (!bRes.isOk()) {
+ return UNKNOWN_ERROR;
+ }
+
+ if (earlyExit) {
+ *status = false;
+ return OK;
+ }
+
+ const sp<hardware::camera::device::V3_2::ICameraDevice> interface =
+ startDeviceInterface();
+
+ if (interface == nullptr) {
+ return DEAD_OBJECT;
+ }
+
+ auto castResult_3_5 = device::V3_5::ICameraDevice::castFrom(interface);
+ sp<hardware::camera::device::V3_5::ICameraDevice> interface_3_5 = castResult_3_5;
+ auto castResult_3_7 = device::V3_7::ICameraDevice::castFrom(interface);
+ sp<hardware::camera::device::V3_7::ICameraDevice> interface_3_7 = castResult_3_7;
+ auto castResult_3_8 = device::V3_8::ICameraDevice::castFrom(interface);
+ sp<hardware::camera::device::V3_8::ICameraDevice> interface_3_8 = castResult_3_8;
+
+ status_t res;
+ Status callStatus;
+ ::android::hardware::Return<void> ret;
+ auto halCb =
+ [&callStatus, &status] (Status s, bool combStatus) {
+ callStatus = s;
+ *status = combStatus;
+ };
+ if (interface_3_8 != nullptr) {
+ ret = interface_3_8->isStreamCombinationSupported_3_8(streamConfiguration, halCb);
+ } else if (interface_3_7 != nullptr) {
+ hardware::camera::device::V3_7::StreamConfiguration configuration_3_7;
+ bool success = SessionConfigurationUtils::convertHALStreamCombinationFromV38ToV37(
+ configuration_3_7, streamConfiguration);
+ if (!success) {
+ *status = false;
+ return OK;
+ }
+ ret = interface_3_7->isStreamCombinationSupported_3_7(configuration_3_7, halCb);
+ } else if (interface_3_5 != nullptr) {
+ hardware::camera::device::V3_7::StreamConfiguration configuration_3_7;
+ bool success = SessionConfigurationUtils::convertHALStreamCombinationFromV38ToV37(
+ configuration_3_7, streamConfiguration);
+ if (!success) {
+ *status = false;
+ return OK;
+ }
+ hardware::camera::device::V3_4::StreamConfiguration configuration_3_4;
+ success = SessionConfigurationUtils::convertHALStreamCombinationFromV37ToV34(
+ configuration_3_4, configuration_3_7);
+ if (!success) {
+ *status = false;
+ return OK;
+ }
+ ret = interface_3_5->isStreamCombinationSupported(configuration_3_4, halCb);
+ } else {
+ return INVALID_OPERATION;
+ }
+ if (ret.isOk()) {
+ switch (callStatus) {
+ case Status::OK:
+ // Expected case, do nothing.
+ res = OK;
+ break;
+ case Status::METHOD_NOT_SUPPORTED:
+ res = INVALID_OPERATION;
+ break;
+ default:
+ ALOGE("%s: Session configuration query failed: %d", __FUNCTION__, callStatus);
+ res = UNKNOWN_ERROR;
+ }
+ } else {
+ ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, ret.description().c_str());
+ res = UNKNOWN_ERROR;
+ }
+
+ return res;
+}
+
+status_t HidlProviderInfo::convertToHALStreamCombinationAndCameraIdsLocked(
+ const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs,
+ const std::set<std::string>& perfClassPrimaryCameraIds,
+ int targetSdkVersion,
+ hardware::hidl_vec<CameraIdAndStreamCombination> *halCameraIdsAndStreamCombinations,
+ bool *earlyExit) {
+ binder::Status bStatus = binder::Status::ok();
+ std::vector<CameraIdAndStreamCombination> halCameraIdsAndStreamsV;
+ bool shouldExit = false;
+ status_t res = OK;
+ for (auto &cameraIdAndSessionConfig : cameraIdsAndSessionConfigs) {
+ const std::string& cameraId = cameraIdAndSessionConfig.mCameraId;
+ hardware::camera::device::V3_8::StreamConfiguration streamConfiguration;
+ CameraMetadata deviceInfo;
+ bool overrideForPerfClass =
+ SessionConfigurationUtils::targetPerfClassPrimaryCamera(
+ perfClassPrimaryCameraIds, cameraId, targetSdkVersion);
+ res = mManager->getCameraCharacteristicsLocked(cameraId, overrideForPerfClass, &deviceInfo);
+ if (res != OK) {
+ return res;
+ }
+ camera3::metadataGetter getMetadata =
+ [this](const String8 &id, bool overrideForPerfClass) {
+ CameraMetadata physicalDeviceInfo;
+ mManager->getCameraCharacteristicsLocked(id.string(), overrideForPerfClass,
+ &physicalDeviceInfo);
+ return physicalDeviceInfo;
+ };
+ std::vector<std::string> physicalCameraIds;
+ mManager->isLogicalCameraLocked(cameraId, &physicalCameraIds);
+ bStatus =
+ SessionConfigurationUtils::convertToHALStreamCombination(
+ cameraIdAndSessionConfig.mSessionConfiguration,
+ String8(cameraId.c_str()), deviceInfo, getMetadata,
+ physicalCameraIds, streamConfiguration,
+ overrideForPerfClass, &shouldExit);
+ if (!bStatus.isOk()) {
+ ALOGE("%s: convertToHALStreamCombination failed", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if (shouldExit) {
+ *earlyExit = true;
+ return OK;
+ }
+ CameraIdAndStreamCombination halCameraIdAndStream;
+ halCameraIdAndStream.cameraId = cameraId;
+ SessionConfigurationUtils::convertHALStreamCombinationFromV38ToV37(
+ halCameraIdAndStream.streamConfiguration, streamConfiguration);
+ halCameraIdsAndStreamsV.push_back(halCameraIdAndStream);
+ }
+ *halCameraIdsAndStreamCombinations = halCameraIdsAndStreamsV;
+ return OK;
+}
+
+status_t HidlProviderInfo::isConcurrentSessionConfigurationSupported(
+ const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs,
+ const std::set<std::string>& perfClassPrimaryCameraIds,
+ int targetSdkVersion, bool *isSupported) {
+
+ hardware::hidl_vec<CameraIdAndStreamCombination> halCameraIdsAndStreamCombinations;
+ bool knowUnsupported = false;
+ status_t res = convertToHALStreamCombinationAndCameraIdsLocked(
+ cameraIdsAndSessionConfigs, perfClassPrimaryCameraIds,
+ targetSdkVersion, &halCameraIdsAndStreamCombinations, &knowUnsupported);
+ if (res != OK) {
+ ALOGE("%s unable to convert session configurations provided to HAL stream"
+ "combinations", __FUNCTION__);
+ return res;
+ }
+ if (knowUnsupported) {
+ // We got to know the streams aren't valid before doing the HAL
+ // call itself.
+ *isSupported = false;
+ return OK;
+ }
+
+ if (mMinorVersion >= 6) {
+ // Check if the provider is currently active - not going to start it for this notification
+ auto interface = mSavedInterface != nullptr ? mSavedInterface : mActiveInterface.promote();
+ if (interface == nullptr) {
+ // TODO: This might be some other problem
+ return INVALID_OPERATION;
+ }
+ auto castResult2_6 = provider::V2_6::ICameraProvider::castFrom(interface);
+ auto castResult2_7 = provider::V2_7::ICameraProvider::castFrom(interface);
+ Status callStatus;
+ auto cb =
+ [&isSupported, &callStatus](Status s, bool supported) {
+ callStatus = s;
+ *isSupported = supported; };
+
+ ::android::hardware::Return<void> ret;
+ sp<provider::V2_7::ICameraProvider> interface_2_7;
+ sp<provider::V2_6::ICameraProvider> interface_2_6;
+ if (mMinorVersion >= 7 && castResult2_7.isOk()) {
+ interface_2_7 = castResult2_7;
+ if (interface_2_7 != nullptr) {
+ ret = interface_2_7->isConcurrentStreamCombinationSupported_2_7(
+ halCameraIdsAndStreamCombinations, cb);
+ }
+ } else if (mMinorVersion == 6 && castResult2_6.isOk()) {
+ interface_2_6 = castResult2_6;
+ if (interface_2_6 != nullptr) {
+ hardware::hidl_vec<provider::V2_6::CameraIdAndStreamCombination>
+ halCameraIdsAndStreamCombinations_2_6;
+ size_t numStreams = halCameraIdsAndStreamCombinations.size();
+ halCameraIdsAndStreamCombinations_2_6.resize(numStreams);
+ for (size_t i = 0; i < numStreams; i++) {
+ using namespace camera3;
+ auto const& combination = halCameraIdsAndStreamCombinations[i];
+ halCameraIdsAndStreamCombinations_2_6[i].cameraId = combination.cameraId;
+ bool success =
+ SessionConfigurationUtils::convertHALStreamCombinationFromV37ToV34(
+ halCameraIdsAndStreamCombinations_2_6[i].streamConfiguration,
+ combination.streamConfiguration);
+ if (!success) {
+ *isSupported = false;
+ return OK;
+ }
+ }
+ ret = interface_2_6->isConcurrentStreamCombinationSupported(
+ halCameraIdsAndStreamCombinations_2_6, cb);
+ }
+ }
+
+ if (interface_2_7 != nullptr || interface_2_6 != nullptr) {
+ if (ret.isOk()) {
+ switch (callStatus) {
+ case Status::OK:
+ // Expected case, do nothing.
+ res = OK;
+ break;
+ case Status::METHOD_NOT_SUPPORTED:
+ res = INVALID_OPERATION;
+ break;
+ default:
+ ALOGE("%s: Session configuration query failed: %d", __FUNCTION__,
+ callStatus);
+ res = UNKNOWN_ERROR;
+ }
+ } else {
+ ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, ret.description().c_str());
+ res = UNKNOWN_ERROR;
+ }
+ return res;
+ }
+ }
+ // unsupported operation
+ return INVALID_OPERATION;
+}
+
+} //namespace android
diff --git a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h
new file mode 100644
index 0000000..4181fea
--- /dev/null
+++ b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2022 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_SERVERS_CAMERA_CAMERAPROVIDER_HIDLPROVIDERINFOH
+#define ANDROID_SERVERS_CAMERA_CAMERAPROVIDER_HIDLPROVIDERINFOH
+
+#include "common/CameraProviderManager.h"
+
+namespace android {
+
+struct HidlProviderInfo : public CameraProviderManager::ProviderInfo,
+ virtual public hardware::camera::provider::V2_6::ICameraProviderCallback,
+ virtual public hardware::hidl_death_recipient {
+ // Current overall Android device physical status
+ hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState> mDeviceState;
+
+ // This pointer is used to keep a reference to the ICameraProvider that was last accessed.
+ wp<hardware::camera::provider::V2_4::ICameraProvider> mActiveInterface;
+
+ sp<hardware::camera::provider::V2_4::ICameraProvider> mSavedInterface;
+ HidlProviderInfo(
+ const std::string &providerName,
+ const std::string &providerInstance,
+ CameraProviderManager *manager) :
+ CameraProviderManager::ProviderInfo(providerName, providerInstance, manager) {}
+
+ virtual ~HidlProviderInfo() {}
+
+ static status_t mapToStatusT(const hardware::camera::common::V1_0::Status &status);
+
+ status_t initializeHidlProvider(
+ sp<hardware::camera::provider::V2_4::ICameraProvider>& interface,
+ int64_t currentDeviceState);
+
+ IPCTransport getIPCTransport() override {return IPCTransport::HIDL;}
+
+ const sp<hardware::camera::provider::V2_4::ICameraProvider> startProviderInterface();
+
+ virtual bool successfullyStartedProviderInterface() override;
+
+ virtual int64_t getDeviceState() override {return mDeviceState;};
+
+ virtual status_t setUpVendorTags() override;
+ virtual status_t notifyDeviceStateChange(int64_t) override;
+
+ /**
+ * Query the camera provider for concurrent stream configuration support
+ */
+ virtual status_t isConcurrentSessionConfigurationSupported(
+ const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs,
+ const std::set<std::string>& perfClassPrimaryCameraIds,
+ int targetSdkVersion, bool *isSupported) override;
+
+ // Helper for initializeDeviceInfo to use the right CameraProvider get method.
+ sp<hardware::camera::device::V3_2::ICameraDevice>
+ startDeviceInterface(const std::string &deviceName);
+
+ // ICameraProviderCallbacks interface - these lock the parent mInterfaceMutex
+ hardware::Return<void> cameraDeviceStatusChange(
+ const hardware::hidl_string& ,
+ hardware::camera::common::V1_0::CameraDeviceStatus ) override;
+ hardware::Return<void> torchModeStatusChange(
+ const hardware::hidl_string& ,
+ hardware::camera::common::V1_0::TorchModeStatus ) override;
+ hardware::Return<void> physicalCameraDeviceStatusChange(
+ const hardware::hidl_string& ,
+ const hardware::hidl_string& ,
+ hardware::camera::common::V1_0::CameraDeviceStatus ) override;
+
+ // hidl_death_recipient interface - this locks the parent mInterfaceMutex
+ virtual void serviceDied(uint64_t , const wp<hidl::base::V1_0::IBase>& ) override;
+
+ struct HidlDeviceInfo3 : public CameraProviderManager::ProviderInfo::DeviceInfo3 {
+
+ const hardware::hidl_version mVersion = hardware::hidl_version{3, 2};
+ sp<IBase> mSavedInterface = nullptr;
+
+ HidlDeviceInfo3(const std::string& , const metadata_vendor_id_t ,
+ const std::string &, uint16_t ,
+ const CameraResourceCost& ,
+ sp<ProviderInfo> ,
+ const std::vector<std::string>& ,
+ sp<hardware::camera::device::V3_2::ICameraDevice>);
+
+ ~HidlDeviceInfo3() {}
+
+ virtual status_t setTorchMode(bool enabled) override;
+ virtual status_t turnOnTorchWithStrengthLevel(int32_t torchStrength) override;
+ virtual status_t getTorchStrengthLevel(int32_t *torchStrength) override;
+
+ virtual status_t dumpState(int fd) override;
+
+ virtual status_t isSessionConfigurationSupported(
+ const SessionConfiguration &/*configuration*/,
+ bool overrideForPerfClass,
+ bool *status/*status*/);
+ sp<hardware::camera::device::V3_2::ICameraDevice> startDeviceInterface();
+ };
+
+ private:
+
+ virtual std::unique_ptr<DeviceInfo> initializeDeviceInfo(const std::string &,
+ const metadata_vendor_id_t , const std::string &,
+ uint16_t ) override;
+ virtual status_t reCacheConcurrentStreamingCameraIdsLocked() override;
+
+ //Expects to have mLock locked
+ status_t getConcurrentCameraIdsInternalLocked(
+ sp<hardware::camera::provider::V2_6::ICameraProvider> &);
+
+ //expects to have mManager->mInterfaceMutex locked
+ status_t convertToHALStreamCombinationAndCameraIdsLocked(
+ const std::vector<hardware::camera2::utils::CameraIdAndSessionConfiguration>&
+ cameraIdsAndSessionConfigs,
+ const std::set<std::string>& perfClassPrimaryCameraIds,
+ int targetSdkVersion,
+ hardware::hidl_vec<hardware::camera::provider::V2_7::CameraIdAndStreamCombination>*
+ halCameraIdsAndStreamCombinations,
+ bool *earlyExit);
+}; // HidlProviderInfo
+
+} // namespace android
+#endif
diff --git a/services/camera/libcameraservice/device3/BufferUtils.cpp b/services/camera/libcameraservice/device3/BufferUtils.cpp
index f3adf20..c0d47d5 100644
--- a/services/camera/libcameraservice/device3/BufferUtils.cpp
+++ b/services/camera/libcameraservice/device3/BufferUtils.cpp
@@ -28,16 +28,6 @@
namespace android {
namespace camera3 {
-camera_buffer_status_t mapHidlBufferStatus(hardware::camera::device::V3_2::BufferStatus status) {
- using hardware::camera::device::V3_2::BufferStatus;
-
- switch (status) {
- case BufferStatus::OK: return CAMERA_BUFFER_STATUS_OK;
- case BufferStatus::ERROR: return CAMERA_BUFFER_STATUS_ERROR;
- }
- return CAMERA_BUFFER_STATUS_ERROR;
-}
-
void BufferRecords::takeInflightBufferMap(BufferRecords& other) {
std::lock_guard<std::mutex> oLock(other.mInflightLock);
std::lock_guard<std::mutex> lock(mInflightLock);
diff --git a/services/camera/libcameraservice/device3/BufferUtils.h b/services/camera/libcameraservice/device3/BufferUtils.h
index 03112ec..96fc111 100644
--- a/services/camera/libcameraservice/device3/BufferUtils.h
+++ b/services/camera/libcameraservice/device3/BufferUtils.h
@@ -154,9 +154,6 @@
}; // class BufferRecords
static const uint64_t BUFFER_ID_NO_BUFFER = 0;
-
- camera_buffer_status_t mapHidlBufferStatus(
- hardware::camera::device::V3_2::BufferStatus status);
} // namespace camera3
} // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 4c1e7f0..a5c4e4d 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -84,6 +84,7 @@
mStatusWaiters(0),
mUsePartialResult(false),
mNumPartialResults(1),
+ mDeviceTimeBaseIsRealtime(false),
mTimestampOffset(0),
mNextResultFrameNumber(0),
mNextReprocessResultFrameNumber(0),
@@ -112,164 +113,6 @@
return mId;
}
-status_t Camera3Device::initialize(sp<CameraProviderManager> manager, const String8& monitorTags) {
- ATRACE_CALL();
- Mutex::Autolock il(mInterfaceLock);
- Mutex::Autolock l(mLock);
-
- ALOGV("%s: Initializing HIDL device for camera %s", __FUNCTION__, mId.string());
- if (mStatus != STATUS_UNINITIALIZED) {
- CLOGE("Already initialized!");
- return INVALID_OPERATION;
- }
- if (manager == nullptr) return INVALID_OPERATION;
-
- sp<ICameraDeviceSession> session;
- ATRACE_BEGIN("CameraHal::openSession");
- status_t res = manager->openSession(mId.string(), this,
- /*out*/ &session);
- ATRACE_END();
- if (res != OK) {
- SET_ERR_L("Could not open camera session: %s (%d)", strerror(-res), res);
- return res;
- }
-
- res = manager->getCameraCharacteristics(mId.string(), mOverrideForPerfClass, &mDeviceInfo);
- if (res != OK) {
- SET_ERR_L("Could not retrieve camera characteristics: %s (%d)", strerror(-res), res);
- session->close();
- return res;
- }
- mSupportNativeZoomRatio = manager->supportNativeZoomRatio(mId.string());
-
- std::vector<std::string> physicalCameraIds;
- bool isLogical = manager->isLogicalCamera(mId.string(), &physicalCameraIds);
- if (isLogical) {
- for (auto& physicalId : physicalCameraIds) {
- // Do not override characteristics for physical cameras
- res = manager->getCameraCharacteristics(
- physicalId, /*overrideForPerfClass*/false, &mPhysicalDeviceInfoMap[physicalId]);
- if (res != OK) {
- SET_ERR_L("Could not retrieve camera %s characteristics: %s (%d)",
- physicalId.c_str(), strerror(-res), res);
- session->close();
- return res;
- }
-
- bool usePrecorrectArray =
- DistortionMapper::isDistortionSupported(mPhysicalDeviceInfoMap[physicalId]);
- if (usePrecorrectArray) {
- res = mDistortionMappers[physicalId].setupStaticInfo(
- mPhysicalDeviceInfoMap[physicalId]);
- if (res != OK) {
- SET_ERR_L("Unable to read camera %s's calibration fields for distortion "
- "correction", physicalId.c_str());
- session->close();
- return res;
- }
- }
-
- mZoomRatioMappers[physicalId] = ZoomRatioMapper(
- &mPhysicalDeviceInfoMap[physicalId],
- mSupportNativeZoomRatio, usePrecorrectArray);
-
- if (SessionConfigurationUtils::isUltraHighResolutionSensor(
- mPhysicalDeviceInfoMap[physicalId])) {
- mUHRCropAndMeteringRegionMappers[physicalId] =
- UHRCropAndMeteringRegionMapper(mPhysicalDeviceInfoMap[physicalId],
- usePrecorrectArray);
- }
- }
- }
-
- std::shared_ptr<RequestMetadataQueue> queue;
- auto requestQueueRet = session->getCaptureRequestMetadataQueue(
- [&queue](const auto& descriptor) {
- queue = std::make_shared<RequestMetadataQueue>(descriptor);
- if (!queue->isValid() || queue->availableToWrite() <= 0) {
- ALOGE("HAL returns empty request metadata fmq, not use it");
- queue = nullptr;
- // don't use the queue onwards.
- }
- });
- if (!requestQueueRet.isOk()) {
- ALOGE("Transaction error when getting request metadata fmq: %s, not use it",
- requestQueueRet.description().c_str());
- return DEAD_OBJECT;
- }
-
- std::unique_ptr<ResultMetadataQueue>& resQueue = mResultMetadataQueue;
- auto resultQueueRet = session->getCaptureResultMetadataQueue(
- [&resQueue](const auto& descriptor) {
- resQueue = std::make_unique<ResultMetadataQueue>(descriptor);
- if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
- ALOGE("HAL returns empty result metadata fmq, not use it");
- resQueue = nullptr;
- // Don't use the resQueue onwards.
- }
- });
- if (!resultQueueRet.isOk()) {
- ALOGE("Transaction error when getting result metadata queue from camera session: %s",
- resultQueueRet.description().c_str());
- return DEAD_OBJECT;
- }
- IF_ALOGV() {
- session->interfaceChain([](
- ::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) {
- ALOGV("Session interface chain:");
- for (const auto& iface : interfaceChain) {
- ALOGV(" %s", iface.c_str());
- }
- });
- }
-
- camera_metadata_entry bufMgrMode =
- mDeviceInfo.find(ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION);
- if (bufMgrMode.count > 0) {
- mUseHalBufManager = (bufMgrMode.data.u8[0] ==
- ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
- }
-
- camera_metadata_entry_t capabilities = mDeviceInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
- for (size_t i = 0; i < capabilities.count; i++) {
- uint8_t capability = capabilities.data.u8[i];
- if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING) {
- mSupportOfflineProcessing = true;
- }
- }
-
- mInterface = new HalInterface(session, queue, mUseHalBufManager, mSupportOfflineProcessing);
- std::string providerType;
- mVendorTagId = manager->getProviderTagIdLocked(mId.string());
- mTagMonitor.initialize(mVendorTagId);
- if (!monitorTags.isEmpty()) {
- mTagMonitor.parseTagsToMonitor(String8(monitorTags));
- }
-
- // Metadata tags needs fixup for monochrome camera device version less
- // than 3.5.
- hardware::hidl_version maxVersion{0,0};
- res = manager->getHighestSupportedVersion(mId.string(), &maxVersion);
- if (res != OK) {
- ALOGE("%s: Error in getting camera device version id: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return res;
- }
- int deviceVersion = HARDWARE_DEVICE_API_VERSION(
- maxVersion.get_major(), maxVersion.get_minor());
-
- bool isMonochrome = false;
- for (size_t i = 0; i < capabilities.count; i++) {
- uint8_t capability = capabilities.data.u8[i];
- if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME) {
- isMonochrome = true;
- }
- }
- mNeedFixupMonochromeTags = (isMonochrome && deviceVersion < CAMERA_DEVICE_API_VERSION_3_5);
-
- return initializeCommonLocked();
-}
-
status_t Camera3Device::initializeCommonLocked() {
/** Start up status tracker thread */
@@ -323,7 +166,7 @@
}
/** Start up request queue thread */
- mRequestThread = new RequestThread(
+ mRequestThread = createNewRequestThread(
this, mStatusTracker, mInterface, sessionParamKeys,
mUseHalBufManager, mSupportCameraMute);
res = mRequestThread->run(String8::format("C3Dev-%s-ReqQueue", mId.string()).string());
@@ -345,11 +188,12 @@
mIsInputStreamMultiResolution = false;
// Measure the clock domain offset between camera and video/hw_composer
+ mTimestampOffset = getMonoToBoottimeOffset();
camera_metadata_entry timestampSource =
mDeviceInfo.find(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE);
if (timestampSource.count > 0 && timestampSource.data.u8[0] ==
ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME) {
- mTimestampOffset = getMonoToBoottimeOffset();
+ mDeviceTimeBaseIsRealtime = true;
}
// Will the HAL be sending in early partial result metadata?
@@ -381,7 +225,8 @@
mRotateAndCropMappers.emplace(mId.c_str(), &mDeviceInfo);
}
- mInjectionMethods = new Camera3DeviceInjectionMethods(this);
+ // Hidl/AidlCamera3DeviceInjectionMethods
+ mInjectionMethods = createCamera3DeviceInjectionMethods(this);
return OK;
}
@@ -531,83 +376,6 @@
return measured;
}
-CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap
-Camera3Device::mapToHidlDynamicProfile(int dynamicRangeProfile) {
- return static_cast<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap>(
- dynamicRangeProfile);
-}
-
-hardware::graphics::common::V1_0::PixelFormat Camera3Device::mapToPixelFormat(
- int frameworkFormat) {
- return (hardware::graphics::common::V1_0::PixelFormat) frameworkFormat;
-}
-
-DataspaceFlags Camera3Device::mapToHidlDataspace(
- android_dataspace dataSpace) {
- return dataSpace;
-}
-
-BufferUsageFlags Camera3Device::mapToConsumerUsage(
- uint64_t usage) {
- return usage;
-}
-
-StreamRotation Camera3Device::mapToStreamRotation(camera_stream_rotation_t rotation) {
- switch (rotation) {
- case CAMERA_STREAM_ROTATION_0:
- return StreamRotation::ROTATION_0;
- case CAMERA_STREAM_ROTATION_90:
- return StreamRotation::ROTATION_90;
- case CAMERA_STREAM_ROTATION_180:
- return StreamRotation::ROTATION_180;
- case CAMERA_STREAM_ROTATION_270:
- return StreamRotation::ROTATION_270;
- }
- ALOGE("%s: Unknown stream rotation %d", __FUNCTION__, rotation);
- return StreamRotation::ROTATION_0;
-}
-
-status_t Camera3Device::mapToStreamConfigurationMode(
- camera_stream_configuration_mode_t operationMode, StreamConfigurationMode *mode) {
- if (mode == nullptr) return BAD_VALUE;
- if (operationMode < CAMERA_VENDOR_STREAM_CONFIGURATION_MODE_START) {
- switch(operationMode) {
- case CAMERA_STREAM_CONFIGURATION_NORMAL_MODE:
- *mode = StreamConfigurationMode::NORMAL_MODE;
- break;
- case CAMERA_STREAM_CONFIGURATION_CONSTRAINED_HIGH_SPEED_MODE:
- *mode = StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE;
- break;
- default:
- ALOGE("%s: Unknown stream configuration mode %d", __FUNCTION__, operationMode);
- return BAD_VALUE;
- }
- } else {
- *mode = static_cast<StreamConfigurationMode>(operationMode);
- }
- return OK;
-}
-
-int Camera3Device::mapToFrameworkFormat(
- hardware::graphics::common::V1_0::PixelFormat pixelFormat) {
- return static_cast<uint32_t>(pixelFormat);
-}
-
-android_dataspace Camera3Device::mapToFrameworkDataspace(
- DataspaceFlags dataSpace) {
- return static_cast<android_dataspace>(dataSpace);
-}
-
-uint64_t Camera3Device::mapConsumerToFrameworkUsage(
- BufferUsageFlags usage) {
- return usage;
-}
-
-uint64_t Camera3Device::mapProducerToFrameworkUsage(
- BufferUsageFlags usage) {
- return usage;
-}
-
ssize_t Camera3Device::getJpegBufferSize(const CameraMetadata &info, uint32_t width,
uint32_t height) const {
// Get max jpeg size (area-wise) for default sensor pixel mode
@@ -1050,186 +818,6 @@
return res;
}
-hardware::Return<void> Camera3Device::requestStreamBuffers(
- const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
- requestStreamBuffers_cb _hidl_cb) {
- RequestBufferStates states {
- mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder,
- *this, *mInterface, *this};
- camera3::requestStreamBuffers(states, bufReqs, _hidl_cb);
- return hardware::Void();
-}
-
-hardware::Return<void> Camera3Device::returnStreamBuffers(
- const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers) {
- ReturnBufferStates states {
- mId, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder, *mInterface};
- camera3::returnStreamBuffers(states, buffers);
- return hardware::Void();
-}
-
-hardware::Return<void> Camera3Device::processCaptureResult_3_4(
- const hardware::hidl_vec<
- hardware::camera::device::V3_4::CaptureResult>& results) {
- // Ideally we should grab mLock, but that can lead to deadlock, and
- // it's not super important to get up to date value of mStatus for this
- // warning print, hence skipping the lock here
- if (mStatus == STATUS_ERROR) {
- // Per API contract, HAL should act as closed after device error
- // But mStatus can be set to error by framework as well, so just log
- // a warning here.
- ALOGW("%s: received capture result in error state.", __FUNCTION__);
- }
-
- sp<NotificationListener> listener;
- {
- std::lock_guard<std::mutex> l(mOutputLock);
- listener = mListener.promote();
- }
-
- if (mProcessCaptureResultLock.tryLock() != OK) {
- // This should never happen; it indicates a wrong client implementation
- // that doesn't follow the contract. But, we can be tolerant here.
- ALOGE("%s: callback overlapped! waiting 1s...",
- __FUNCTION__);
- if (mProcessCaptureResultLock.timedLock(1000000000 /* 1s */) != OK) {
- ALOGE("%s: cannot acquire lock in 1s, dropping results",
- __FUNCTION__);
- // really don't know what to do, so bail out.
- return hardware::Void();
- }
- }
- CaptureOutputStates states {
- mId,
- mInFlightLock, mLastCompletedRegularFrameNumber,
- mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
- mInFlightMap, mOutputLock, mResultQueue, mResultSignal,
- mNextShutterFrameNumber,
- mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
- mNextResultFrameNumber,
- mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
- mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
- mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
- mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
- mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- *mInterface, mLegacyClient
- };
-
- for (const auto& result : results) {
- processOneCaptureResultLocked(states, result.v3_2, result.physicalCameraMetadata);
- }
- mProcessCaptureResultLock.unlock();
- return hardware::Void();
-}
-
-// Only one processCaptureResult should be called at a time, so
-// the locks won't block. The locks are present here simply to enforce this.
-hardware::Return<void> Camera3Device::processCaptureResult(
- const hardware::hidl_vec<
- hardware::camera::device::V3_2::CaptureResult>& results) {
- hardware::hidl_vec<hardware::camera::device::V3_4::PhysicalCameraMetadata> noPhysMetadata;
-
- // Ideally we should grab mLock, but that can lead to deadlock, and
- // it's not super important to get up to date value of mStatus for this
- // warning print, hence skipping the lock here
- if (mStatus == STATUS_ERROR) {
- // Per API contract, HAL should act as closed after device error
- // But mStatus can be set to error by framework as well, so just log
- // a warning here.
- ALOGW("%s: received capture result in error state.", __FUNCTION__);
- }
-
- sp<NotificationListener> listener;
- {
- std::lock_guard<std::mutex> l(mOutputLock);
- listener = mListener.promote();
- }
-
- if (mProcessCaptureResultLock.tryLock() != OK) {
- // This should never happen; it indicates a wrong client implementation
- // that doesn't follow the contract. But, we can be tolerant here.
- ALOGE("%s: callback overlapped! waiting 1s...",
- __FUNCTION__);
- if (mProcessCaptureResultLock.timedLock(1000000000 /* 1s */) != OK) {
- ALOGE("%s: cannot acquire lock in 1s, dropping results",
- __FUNCTION__);
- // really don't know what to do, so bail out.
- return hardware::Void();
- }
- }
-
- CaptureOutputStates states {
- mId,
- mInFlightLock, mLastCompletedRegularFrameNumber,
- mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
- mInFlightMap, mOutputLock, mResultQueue, mResultSignal,
- mNextShutterFrameNumber,
- mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
- mNextResultFrameNumber,
- mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
- mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
- mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
- mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
- mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- *mInterface, mLegacyClient
- };
-
- for (const auto& result : results) {
- processOneCaptureResultLocked(states, result, noPhysMetadata);
- }
- mProcessCaptureResultLock.unlock();
- return hardware::Void();
-}
-
-hardware::Return<void> Camera3Device::notify(
- const hardware::hidl_vec<hardware::camera::device::V3_2::NotifyMsg>& msgs) {
- return notifyHelper<hardware::camera::device::V3_2::NotifyMsg>(msgs);
-}
-
-hardware::Return<void> Camera3Device::notify_3_8(
- const hardware::hidl_vec<hardware::camera::device::V3_8::NotifyMsg>& msgs) {
- return notifyHelper<hardware::camera::device::V3_8::NotifyMsg>(msgs);
-}
-
-template<typename NotifyMsgType>
-hardware::Return<void> Camera3Device::notifyHelper(const hardware::hidl_vec<NotifyMsgType>& msgs) {
- // Ideally we should grab mLock, but that can lead to deadlock, and
- // it's not super important to get up to date value of mStatus for this
- // warning print, hence skipping the lock here
- if (mStatus == STATUS_ERROR) {
- // Per API contract, HAL should act as closed after device error
- // But mStatus can be set to error by framework as well, so just log
- // a warning here.
- ALOGW("%s: received notify message in error state.", __FUNCTION__);
- }
-
- sp<NotificationListener> listener;
- {
- std::lock_guard<std::mutex> l(mOutputLock);
- listener = mListener.promote();
- }
-
- CaptureOutputStates states {
- mId,
- mInFlightLock, mLastCompletedRegularFrameNumber,
- mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
- mInFlightMap, mOutputLock, mResultQueue, mResultSignal,
- mNextShutterFrameNumber,
- mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
- mNextResultFrameNumber,
- mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
- mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
- mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
- mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
- mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- *mInterface, mLegacyClient
- };
- for (const auto& msg : msgs) {
- camera3::notify(states, msg);
- }
- return hardware::Void();
-}
-
status_t Camera3Device::captureList(const List<const PhysicalCameraSettingsList> &requestsList,
const std::list<const SurfaceMap> &surfaceMaps,
int64_t *lastFrameNumber) {
@@ -1390,7 +978,8 @@
const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
std::vector<int> *surfaceIds, int streamSetId, bool isShared, bool isMultiResolution,
- uint64_t consumerUsage, int dynamicRangeProfile) {
+ uint64_t consumerUsage, int dynamicRangeProfile, int streamUseCase, int timestampBase,
+ int mirrorMode) {
ATRACE_CALL();
if (consumer == nullptr) {
@@ -1403,7 +992,8 @@
return createStream(consumers, /*hasDeferredConsumer*/ false, width, height,
format, dataSpace, rotation, id, physicalCameraId, sensorPixelModesUsed, surfaceIds,
- streamSetId, isShared, isMultiResolution, consumerUsage, dynamicRangeProfile);
+ streamSetId, isShared, isMultiResolution, consumerUsage, dynamicRangeProfile,
+ streamUseCase, timestampBase, mirrorMode);
}
static bool isRawFormat(int format) {
@@ -1423,16 +1013,19 @@
android_dataspace dataSpace, camera_stream_rotation_t rotation, int *id,
const String8& physicalCameraId, const std::unordered_set<int32_t> &sensorPixelModesUsed,
std::vector<int> *surfaceIds, int streamSetId, bool isShared, bool isMultiResolution,
- uint64_t consumerUsage, int dynamicRangeProfile) {
+ uint64_t consumerUsage, int dynamicRangeProfile, int streamUseCase, int timestampBase,
+ int mirrorMode) {
ATRACE_CALL();
Mutex::Autolock il(mInterfaceLock);
nsecs_t maxExpectedDuration = getExpectedInFlightDuration();
Mutex::Autolock l(mLock);
ALOGV("Camera %s: Creating new stream %d: %d x %d, format %d, dataspace %d rotation %d"
- " consumer usage %" PRIu64 ", isShared %d, physicalCameraId %s, isMultiResolution %d",
+ " consumer usage %" PRIu64 ", isShared %d, physicalCameraId %s, isMultiResolution %d"
+ " dynamicRangeProfile %d, streamUseCase %d, timestampBase %d, mirrorMode %d",
mId.string(), mNextStreamId, width, height, format, dataSpace, rotation,
- consumerUsage, isShared, physicalCameraId.string(), isMultiResolution);
+ consumerUsage, isShared, physicalCameraId.string(), isMultiResolution,
+ dynamicRangeProfile, streamUseCase, timestampBase, mirrorMode);
status_t res;
bool wasActive = false;
@@ -1501,7 +1094,8 @@
newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
width, height, blobBufferSize, format, dataSpace, rotation,
mTimestampOffset, physicalCameraId, sensorPixelModesUsed, streamSetId,
- isMultiResolution, dynamicRangeProfile);
+ isMultiResolution, dynamicRangeProfile, streamUseCase, mDeviceTimeBaseIsRealtime,
+ timestampBase, mirrorMode);
} else if (format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
bool maxResolution =
sensorPixelModesUsed.find(ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION) !=
@@ -1515,22 +1109,26 @@
newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
width, height, rawOpaqueBufferSize, format, dataSpace, rotation,
mTimestampOffset, physicalCameraId, sensorPixelModesUsed, streamSetId,
- isMultiResolution, dynamicRangeProfile);
+ isMultiResolution, dynamicRangeProfile, streamUseCase, mDeviceTimeBaseIsRealtime,
+ timestampBase, mirrorMode);
} else if (isShared) {
newStream = new Camera3SharedOutputStream(mNextStreamId, consumers,
width, height, format, consumerUsage, dataSpace, rotation,
mTimestampOffset, physicalCameraId, sensorPixelModesUsed, streamSetId,
- mUseHalBufManager, dynamicRangeProfile);
+ mUseHalBufManager, dynamicRangeProfile, streamUseCase, mDeviceTimeBaseIsRealtime,
+ timestampBase, mirrorMode);
} else if (consumers.size() == 0 && hasDeferredConsumer) {
newStream = new Camera3OutputStream(mNextStreamId,
width, height, format, consumerUsage, dataSpace, rotation,
mTimestampOffset, physicalCameraId, sensorPixelModesUsed, streamSetId,
- isMultiResolution, dynamicRangeProfile);
+ isMultiResolution, dynamicRangeProfile, streamUseCase, mDeviceTimeBaseIsRealtime,
+ timestampBase, mirrorMode);
} else {
newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
width, height, format, dataSpace, rotation,
mTimestampOffset, physicalCameraId, sensorPixelModesUsed, streamSetId,
- isMultiResolution, dynamicRangeProfile);
+ isMultiResolution, dynamicRangeProfile, streamUseCase, mDeviceTimeBaseIsRealtime,
+ timestampBase, mirrorMode);
}
size_t consumerCount = consumers.size();
@@ -1649,7 +1247,7 @@
CLOGE("Stream %d does not exist", id);
return BAD_VALUE;
}
- return stream->setTransform(transform);
+ return stream->setTransform(transform, false /*mayChangeMirror*/);
}
status_t Camera3Device::deleteStream(int id) {
@@ -2224,14 +1822,16 @@
streamIds.push_back(stream->getId());
Camera3Stream* camera3Stream = Camera3Stream::cast(stream->asHalStream());
int64_t usage = 0LL;
+ int streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT;
if (camera3Stream != nullptr) {
usage = camera3Stream->getUsage();
+ streamUseCase = camera3Stream->getStreamUseCase();
}
streamStats.emplace_back(stream->getWidth(), stream->getHeight(),
stream->getFormat(), stream->getDataSpace(), usage,
stream->getMaxHalBuffers(),
stream->getMaxTotalBuffers() - stream->getMaxHalBuffers(),
- stream->getDynamicRangeProfile());
+ stream->getDynamicRangeProfile(), streamUseCase);
}
}
}
@@ -3137,738 +2737,7 @@
physicalMetadata, outputBuffers, numOutputBuffers, inputStreamId);
}
-/**
- * HalInterface inner class methods
- */
-
-Camera3Device::HalInterface::HalInterface(
- sp<ICameraDeviceSession> &session,
- std::shared_ptr<RequestMetadataQueue> queue,
- bool useHalBufManager, bool supportOfflineProcessing) :
- mHidlSession(session),
- mRequestMetadataQueue(queue),
- mUseHalBufManager(useHalBufManager),
- mIsReconfigurationQuerySupported(true),
- mSupportOfflineProcessing(supportOfflineProcessing) {
- // Check with hardware service manager if we can downcast these interfaces
- // Somewhat expensive, so cache the results at startup
- auto castResult_3_8 = device::V3_8::ICameraDeviceSession::castFrom(mHidlSession);
- if (castResult_3_8.isOk()) {
- mHidlSession_3_8 = castResult_3_8;
- }
- auto castResult_3_7 = device::V3_7::ICameraDeviceSession::castFrom(mHidlSession);
- if (castResult_3_7.isOk()) {
- mHidlSession_3_7 = castResult_3_7;
- }
- auto castResult_3_6 = device::V3_6::ICameraDeviceSession::castFrom(mHidlSession);
- if (castResult_3_6.isOk()) {
- mHidlSession_3_6 = castResult_3_6;
- }
- auto castResult_3_5 = device::V3_5::ICameraDeviceSession::castFrom(mHidlSession);
- if (castResult_3_5.isOk()) {
- mHidlSession_3_5 = castResult_3_5;
- }
- auto castResult_3_4 = device::V3_4::ICameraDeviceSession::castFrom(mHidlSession);
- if (castResult_3_4.isOk()) {
- mHidlSession_3_4 = castResult_3_4;
- }
- auto castResult_3_3 = device::V3_3::ICameraDeviceSession::castFrom(mHidlSession);
- if (castResult_3_3.isOk()) {
- mHidlSession_3_3 = castResult_3_3;
- }
-}
-
-Camera3Device::HalInterface::HalInterface() :
- mUseHalBufManager(false),
- mSupportOfflineProcessing(false) {}
-
-Camera3Device::HalInterface::HalInterface(const HalInterface& other) :
- mHidlSession(other.mHidlSession),
- mRequestMetadataQueue(other.mRequestMetadataQueue),
- mUseHalBufManager(other.mUseHalBufManager),
- mSupportOfflineProcessing(other.mSupportOfflineProcessing) {}
-
-bool Camera3Device::HalInterface::valid() {
- return (mHidlSession != nullptr);
-}
-
-void Camera3Device::HalInterface::clear() {
- mHidlSession_3_8.clear();
- mHidlSession_3_7.clear();
- mHidlSession_3_6.clear();
- mHidlSession_3_5.clear();
- mHidlSession_3_4.clear();
- mHidlSession_3_3.clear();
- mHidlSession.clear();
-}
-
-status_t Camera3Device::HalInterface::constructDefaultRequestSettings(
- camera_request_template_t templateId,
- /*out*/ camera_metadata_t **requestTemplate) {
- ATRACE_NAME("CameraHal::constructDefaultRequestSettings");
- if (!valid()) return INVALID_OPERATION;
- status_t res = OK;
-
- common::V1_0::Status status;
-
- auto requestCallback = [&status, &requestTemplate]
- (common::V1_0::Status s, const device::V3_2::CameraMetadata& request) {
- status = s;
- if (status == common::V1_0::Status::OK) {
- const camera_metadata *r =
- reinterpret_cast<const camera_metadata_t*>(request.data());
- size_t expectedSize = request.size();
- int ret = validate_camera_metadata_structure(r, &expectedSize);
- if (ret == OK || ret == CAMERA_METADATA_VALIDATION_SHIFTED) {
- *requestTemplate = clone_camera_metadata(r);
- if (*requestTemplate == nullptr) {
- ALOGE("%s: Unable to clone camera metadata received from HAL",
- __FUNCTION__);
- status = common::V1_0::Status::INTERNAL_ERROR;
- }
- } else {
- ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
- status = common::V1_0::Status::INTERNAL_ERROR;
- }
- }
- };
- hardware::Return<void> err;
- RequestTemplate id;
- switch (templateId) {
- case CAMERA_TEMPLATE_PREVIEW:
- id = RequestTemplate::PREVIEW;
- break;
- case CAMERA_TEMPLATE_STILL_CAPTURE:
- id = RequestTemplate::STILL_CAPTURE;
- break;
- case CAMERA_TEMPLATE_VIDEO_RECORD:
- id = RequestTemplate::VIDEO_RECORD;
- break;
- case CAMERA_TEMPLATE_VIDEO_SNAPSHOT:
- id = RequestTemplate::VIDEO_SNAPSHOT;
- break;
- case CAMERA_TEMPLATE_ZERO_SHUTTER_LAG:
- id = RequestTemplate::ZERO_SHUTTER_LAG;
- break;
- case CAMERA_TEMPLATE_MANUAL:
- id = RequestTemplate::MANUAL;
- break;
- default:
- // Unknown template ID, or this HAL is too old to support it
- return BAD_VALUE;
- }
- err = mHidlSession->constructDefaultRequestSettings(id, requestCallback);
-
- if (!err.isOk()) {
- ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
- res = DEAD_OBJECT;
- } else {
- res = CameraProviderManager::mapToStatusT(status);
- }
-
- return res;
-}
-
-bool Camera3Device::HalInterface::isReconfigurationRequired(CameraMetadata& oldSessionParams,
- CameraMetadata& newSessionParams) {
- // We do reconfiguration by default;
- bool ret = true;
- if ((mHidlSession_3_5 != nullptr) && mIsReconfigurationQuerySupported) {
- android::hardware::hidl_vec<uint8_t> oldParams, newParams;
- camera_metadata_t* oldSessioMeta = const_cast<camera_metadata_t*>(
- oldSessionParams.getAndLock());
- camera_metadata_t* newSessioMeta = const_cast<camera_metadata_t*>(
- newSessionParams.getAndLock());
- oldParams.setToExternal(reinterpret_cast<uint8_t*>(oldSessioMeta),
- get_camera_metadata_size(oldSessioMeta));
- newParams.setToExternal(reinterpret_cast<uint8_t*>(newSessioMeta),
- get_camera_metadata_size(newSessioMeta));
- hardware::camera::common::V1_0::Status callStatus;
- bool required;
- auto hidlCb = [&callStatus, &required] (hardware::camera::common::V1_0::Status s,
- bool requiredFlag) {
- callStatus = s;
- required = requiredFlag;
- };
- auto err = mHidlSession_3_5->isReconfigurationRequired(oldParams, newParams, hidlCb);
- oldSessionParams.unlock(oldSessioMeta);
- newSessionParams.unlock(newSessioMeta);
- if (err.isOk()) {
- switch (callStatus) {
- case hardware::camera::common::V1_0::Status::OK:
- ret = required;
- break;
- case hardware::camera::common::V1_0::Status::METHOD_NOT_SUPPORTED:
- mIsReconfigurationQuerySupported = false;
- ret = true;
- break;
- default:
- ALOGV("%s: Reconfiguration query failed: %d", __FUNCTION__, callStatus);
- ret = true;
- }
- } else {
- ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, err.description().c_str());
- ret = true;
- }
- }
-
- return ret;
-}
-
-status_t Camera3Device::HalInterface::configureStreams(const camera_metadata_t *sessionParams,
- camera_stream_configuration *config, const std::vector<uint32_t>& bufferSizes) {
- ATRACE_NAME("CameraHal::configureStreams");
- if (!valid()) return INVALID_OPERATION;
- status_t res = OK;
-
- if (config->input_is_multi_resolution && mHidlSession_3_7 == nullptr) {
- ALOGE("%s: Camera device doesn't support multi-resolution input stream", __FUNCTION__);
- return BAD_VALUE;
- }
-
- // Convert stream config to HIDL
- std::set<int> activeStreams;
- device::V3_2::StreamConfiguration requestedConfiguration3_2;
- device::V3_4::StreamConfiguration requestedConfiguration3_4;
- device::V3_7::StreamConfiguration requestedConfiguration3_7;
- device::V3_8::StreamConfiguration requestedConfiguration3_8;
- requestedConfiguration3_2.streams.resize(config->num_streams);
- requestedConfiguration3_4.streams.resize(config->num_streams);
- requestedConfiguration3_7.streams.resize(config->num_streams);
- requestedConfiguration3_8.streams.resize(config->num_streams);
- for (size_t i = 0; i < config->num_streams; i++) {
- device::V3_2::Stream &dst3_2 = requestedConfiguration3_2.streams[i];
- device::V3_4::Stream &dst3_4 = requestedConfiguration3_4.streams[i];
- device::V3_7::Stream &dst3_7 = requestedConfiguration3_7.streams[i];
- device::V3_8::Stream &dst3_8 = requestedConfiguration3_8.streams[i];
- camera3::camera_stream_t *src = config->streams[i];
-
- Camera3Stream* cam3stream = Camera3Stream::cast(src);
- cam3stream->setBufferFreedListener(this);
- int streamId = cam3stream->getId();
- StreamType streamType;
- switch (src->stream_type) {
- case CAMERA_STREAM_OUTPUT:
- streamType = StreamType::OUTPUT;
- break;
- case CAMERA_STREAM_INPUT:
- streamType = StreamType::INPUT;
- break;
- default:
- ALOGE("%s: Stream %d: Unsupported stream type %d",
- __FUNCTION__, streamId, config->streams[i]->stream_type);
- return BAD_VALUE;
- }
- dst3_2.id = streamId;
- dst3_2.streamType = streamType;
- dst3_2.width = src->width;
- dst3_2.height = src->height;
- dst3_2.usage = mapToConsumerUsage(cam3stream->getUsage());
- dst3_2.rotation = mapToStreamRotation((camera_stream_rotation_t) src->rotation);
- // For HidlSession version 3.5 or newer, the format and dataSpace sent
- // to HAL are original, not the overridden ones.
- if (mHidlSession_3_5 != nullptr) {
- dst3_2.format = mapToPixelFormat(cam3stream->isFormatOverridden() ?
- cam3stream->getOriginalFormat() : src->format);
- dst3_2.dataSpace = mapToHidlDataspace(cam3stream->isDataSpaceOverridden() ?
- cam3stream->getOriginalDataSpace() : src->data_space);
- } else {
- dst3_2.format = mapToPixelFormat(src->format);
- dst3_2.dataSpace = mapToHidlDataspace(src->data_space);
- }
- dst3_4.v3_2 = dst3_2;
- dst3_4.bufferSize = bufferSizes[i];
- if (src->physical_camera_id != nullptr) {
- dst3_4.physicalCameraId = src->physical_camera_id;
- }
- dst3_7.v3_4 = dst3_4;
- dst3_7.groupId = cam3stream->getHalStreamGroupId();
- dst3_7.sensorPixelModesUsed.resize(src->sensor_pixel_modes_used.size());
- size_t j = 0;
- for (int mode : src->sensor_pixel_modes_used) {
- dst3_7.sensorPixelModesUsed[j++] =
- static_cast<CameraMetadataEnumAndroidSensorPixelMode>(mode);
- }
- if ((src->dynamic_range_profile !=
- ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) &&
- (mHidlSession_3_8 == nullptr)) {
- ALOGE("%s: Camera device doesn't support non-standard dynamic range profiles: %d",
- __FUNCTION__, src->dynamic_range_profile);
- return BAD_VALUE;
- }
- dst3_8.v3_7 = dst3_7;
- dst3_8.dynamicRangeProfile = mapToHidlDynamicProfile(src->dynamic_range_profile);
- activeStreams.insert(streamId);
- // Create Buffer ID map if necessary
- mBufferRecords.tryCreateBufferCache(streamId);
- }
- // remove BufferIdMap for deleted streams
- mBufferRecords.removeInactiveBufferCaches(activeStreams);
-
- StreamConfigurationMode operationMode;
- res = mapToStreamConfigurationMode(
- (camera_stream_configuration_mode_t) config->operation_mode,
- /*out*/ &operationMode);
- if (res != OK) {
- return res;
- }
- requestedConfiguration3_2.operationMode = operationMode;
- requestedConfiguration3_4.operationMode = operationMode;
- requestedConfiguration3_7.operationMode = operationMode;
- size_t sessionParamSize = get_camera_metadata_size(sessionParams);
- requestedConfiguration3_4.sessionParams.setToExternal(
- reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
- sessionParamSize);
- requestedConfiguration3_7.operationMode = operationMode;
- requestedConfiguration3_7.sessionParams.setToExternal(
- reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
- sessionParamSize);
- requestedConfiguration3_8.operationMode = operationMode;
- requestedConfiguration3_8.sessionParams.setToExternal(
- reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
- sessionParamSize);
-
- // Invoke configureStreams
- device::V3_3::HalStreamConfiguration finalConfiguration;
- device::V3_4::HalStreamConfiguration finalConfiguration3_4;
- device::V3_6::HalStreamConfiguration finalConfiguration3_6;
- common::V1_0::Status status;
-
- auto configStream34Cb = [&status, &finalConfiguration3_4]
- (common::V1_0::Status s, const device::V3_4::HalStreamConfiguration& halConfiguration) {
- finalConfiguration3_4 = halConfiguration;
- status = s;
- };
-
- auto configStream36Cb = [&status, &finalConfiguration3_6]
- (common::V1_0::Status s, const device::V3_6::HalStreamConfiguration& halConfiguration) {
- finalConfiguration3_6 = halConfiguration;
- status = s;
- };
-
- auto postprocConfigStream34 = [&finalConfiguration, &finalConfiguration3_4]
- (hardware::Return<void>& err) -> status_t {
- if (!err.isOk()) {
- ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
- return DEAD_OBJECT;
- }
- finalConfiguration.streams.resize(finalConfiguration3_4.streams.size());
- for (size_t i = 0; i < finalConfiguration3_4.streams.size(); i++) {
- finalConfiguration.streams[i] = finalConfiguration3_4.streams[i].v3_3;
- }
- return OK;
- };
-
- auto postprocConfigStream36 = [&finalConfiguration, &finalConfiguration3_6]
- (hardware::Return<void>& err) -> status_t {
- if (!err.isOk()) {
- ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
- return DEAD_OBJECT;
- }
- finalConfiguration.streams.resize(finalConfiguration3_6.streams.size());
- for (size_t i = 0; i < finalConfiguration3_6.streams.size(); i++) {
- finalConfiguration.streams[i] = finalConfiguration3_6.streams[i].v3_4.v3_3;
- }
- return OK;
- };
-
- // See which version of HAL we have
- if (mHidlSession_3_8 != nullptr) {
- ALOGV("%s: v3.8 device found", __FUNCTION__);
- requestedConfiguration3_8.streamConfigCounter = mNextStreamConfigCounter++;
- requestedConfiguration3_8.multiResolutionInputImage = config->input_is_multi_resolution;
- auto err = mHidlSession_3_8->configureStreams_3_8(requestedConfiguration3_8,
- configStream36Cb);
- res = postprocConfigStream36(err);
- if (res != OK) {
- return res;
- }
- } else if (mHidlSession_3_7 != nullptr) {
- ALOGV("%s: v3.7 device found", __FUNCTION__);
- requestedConfiguration3_7.streamConfigCounter = mNextStreamConfigCounter++;
- requestedConfiguration3_7.multiResolutionInputImage = config->input_is_multi_resolution;
- auto err = mHidlSession_3_7->configureStreams_3_7(
- requestedConfiguration3_7, configStream36Cb);
- res = postprocConfigStream36(err);
- if (res != OK) {
- return res;
- }
- } else if (mHidlSession_3_6 != nullptr) {
- ALOGV("%s: v3.6 device found", __FUNCTION__);
- device::V3_5::StreamConfiguration requestedConfiguration3_5;
- requestedConfiguration3_5.v3_4 = requestedConfiguration3_4;
- requestedConfiguration3_5.streamConfigCounter = mNextStreamConfigCounter++;
- auto err = mHidlSession_3_6->configureStreams_3_6(
- requestedConfiguration3_5, configStream36Cb);
- res = postprocConfigStream36(err);
- if (res != OK) {
- return res;
- }
- } else if (mHidlSession_3_5 != nullptr) {
- ALOGV("%s: v3.5 device found", __FUNCTION__);
- device::V3_5::StreamConfiguration requestedConfiguration3_5;
- requestedConfiguration3_5.v3_4 = requestedConfiguration3_4;
- requestedConfiguration3_5.streamConfigCounter = mNextStreamConfigCounter++;
- auto err = mHidlSession_3_5->configureStreams_3_5(
- requestedConfiguration3_5, configStream34Cb);
- res = postprocConfigStream34(err);
- if (res != OK) {
- return res;
- }
- } else if (mHidlSession_3_4 != nullptr) {
- // We do; use v3.4 for the call
- ALOGV("%s: v3.4 device found", __FUNCTION__);
- auto err = mHidlSession_3_4->configureStreams_3_4(
- requestedConfiguration3_4, configStream34Cb);
- res = postprocConfigStream34(err);
- if (res != OK) {
- return res;
- }
- } else if (mHidlSession_3_3 != nullptr) {
- // We do; use v3.3 for the call
- ALOGV("%s: v3.3 device found", __FUNCTION__);
- auto err = mHidlSession_3_3->configureStreams_3_3(requestedConfiguration3_2,
- [&status, &finalConfiguration]
- (common::V1_0::Status s, const device::V3_3::HalStreamConfiguration& halConfiguration) {
- finalConfiguration = halConfiguration;
- status = s;
- });
- if (!err.isOk()) {
- ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
- return DEAD_OBJECT;
- }
- } else {
- // We don't; use v3.2 call and construct a v3.3 HalStreamConfiguration
- ALOGV("%s: v3.2 device found", __FUNCTION__);
- HalStreamConfiguration finalConfiguration_3_2;
- auto err = mHidlSession->configureStreams(requestedConfiguration3_2,
- [&status, &finalConfiguration_3_2]
- (common::V1_0::Status s, const HalStreamConfiguration& halConfiguration) {
- finalConfiguration_3_2 = halConfiguration;
- status = s;
- });
- if (!err.isOk()) {
- ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
- return DEAD_OBJECT;
- }
- finalConfiguration.streams.resize(finalConfiguration_3_2.streams.size());
- for (size_t i = 0; i < finalConfiguration_3_2.streams.size(); i++) {
- finalConfiguration.streams[i].v3_2 = finalConfiguration_3_2.streams[i];
- finalConfiguration.streams[i].overrideDataSpace =
- requestedConfiguration3_2.streams[i].dataSpace;
- }
- }
-
- if (status != common::V1_0::Status::OK ) {
- return CameraProviderManager::mapToStatusT(status);
- }
-
- // And convert output stream configuration from HIDL
-
- for (size_t i = 0; i < config->num_streams; i++) {
- camera3::camera_stream_t *dst = config->streams[i];
- int streamId = Camera3Stream::cast(dst)->getId();
-
- // Start scan at i, with the assumption that the stream order matches
- size_t realIdx = i;
- bool found = false;
- size_t halStreamCount = finalConfiguration.streams.size();
- for (size_t idx = 0; idx < halStreamCount; idx++) {
- if (finalConfiguration.streams[realIdx].v3_2.id == streamId) {
- found = true;
- break;
- }
- realIdx = (realIdx >= halStreamCount - 1) ? 0 : realIdx + 1;
- }
- if (!found) {
- ALOGE("%s: Stream %d not found in stream configuration response from HAL",
- __FUNCTION__, streamId);
- return INVALID_OPERATION;
- }
- device::V3_3::HalStream &src = finalConfiguration.streams[realIdx];
- device::V3_6::HalStream &src_36 = finalConfiguration3_6.streams[realIdx];
-
- Camera3Stream* dstStream = Camera3Stream::cast(dst);
- int overrideFormat = mapToFrameworkFormat(src.v3_2.overrideFormat);
- android_dataspace overrideDataSpace = mapToFrameworkDataspace(src.overrideDataSpace);
-
- if (mHidlSession_3_6 != nullptr) {
- dstStream->setOfflineProcessingSupport(src_36.supportOffline);
- }
-
- if (dstStream->getOriginalFormat() != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
- dstStream->setFormatOverride(false);
- dstStream->setDataSpaceOverride(false);
- if (dst->format != overrideFormat) {
- ALOGE("%s: Stream %d: Format override not allowed for format 0x%x", __FUNCTION__,
- streamId, dst->format);
- }
- if (dst->data_space != overrideDataSpace) {
- ALOGE("%s: Stream %d: DataSpace override not allowed for format 0x%x", __FUNCTION__,
- streamId, dst->format);
- }
- } else {
- bool needFormatOverride =
- requestedConfiguration3_2.streams[i].format != src.v3_2.overrideFormat;
- bool needDataspaceOverride =
- requestedConfiguration3_2.streams[i].dataSpace != src.overrideDataSpace;
- // Override allowed with IMPLEMENTATION_DEFINED
- dstStream->setFormatOverride(needFormatOverride);
- dstStream->setDataSpaceOverride(needDataspaceOverride);
- dst->format = overrideFormat;
- dst->data_space = overrideDataSpace;
- }
-
- if (dst->stream_type == CAMERA_STREAM_INPUT) {
- if (src.v3_2.producerUsage != 0) {
- ALOGE("%s: Stream %d: INPUT streams must have 0 for producer usage",
- __FUNCTION__, streamId);
- return INVALID_OPERATION;
- }
- dstStream->setUsage(
- mapConsumerToFrameworkUsage(src.v3_2.consumerUsage));
- } else {
- // OUTPUT
- if (src.v3_2.consumerUsage != 0) {
- ALOGE("%s: Stream %d: OUTPUT streams must have 0 for consumer usage",
- __FUNCTION__, streamId);
- return INVALID_OPERATION;
- }
- dstStream->setUsage(
- mapProducerToFrameworkUsage(src.v3_2.producerUsage));
- }
- dst->max_buffers = src.v3_2.maxBuffers;
- }
-
- return res;
-}
-
-status_t Camera3Device::HalInterface::configureInjectedStreams(
- const camera_metadata_t* sessionParams, camera_stream_configuration* config,
- const std::vector<uint32_t>& bufferSizes,
- const CameraMetadata& cameraCharacteristics) {
- ATRACE_NAME("InjectionCameraHal::configureStreams");
- if (!valid()) return INVALID_OPERATION;
- status_t res = OK;
-
- if (config->input_is_multi_resolution) {
- ALOGE("%s: Injection camera device doesn't support multi-resolution input "
- "stream", __FUNCTION__);
- return BAD_VALUE;
- }
-
- // Convert stream config to HIDL
- std::set<int> activeStreams;
- device::V3_2::StreamConfiguration requestedConfiguration3_2;
- device::V3_4::StreamConfiguration requestedConfiguration3_4;
- device::V3_7::StreamConfiguration requestedConfiguration3_7;
- requestedConfiguration3_2.streams.resize(config->num_streams);
- requestedConfiguration3_4.streams.resize(config->num_streams);
- requestedConfiguration3_7.streams.resize(config->num_streams);
- for (size_t i = 0; i < config->num_streams; i++) {
- device::V3_2::Stream& dst3_2 = requestedConfiguration3_2.streams[i];
- device::V3_4::Stream& dst3_4 = requestedConfiguration3_4.streams[i];
- device::V3_7::Stream& dst3_7 = requestedConfiguration3_7.streams[i];
- camera3::camera_stream_t* src = config->streams[i];
-
- Camera3Stream* cam3stream = Camera3Stream::cast(src);
- cam3stream->setBufferFreedListener(this);
- int streamId = cam3stream->getId();
- StreamType streamType;
- switch (src->stream_type) {
- case CAMERA_STREAM_OUTPUT:
- streamType = StreamType::OUTPUT;
- break;
- case CAMERA_STREAM_INPUT:
- streamType = StreamType::INPUT;
- break;
- default:
- ALOGE("%s: Stream %d: Unsupported stream type %d", __FUNCTION__,
- streamId, config->streams[i]->stream_type);
- return BAD_VALUE;
- }
- dst3_2.id = streamId;
- dst3_2.streamType = streamType;
- dst3_2.width = src->width;
- dst3_2.height = src->height;
- dst3_2.usage = mapToConsumerUsage(cam3stream->getUsage());
- dst3_2.rotation =
- mapToStreamRotation((camera_stream_rotation_t)src->rotation);
- // For HidlSession version 3.5 or newer, the format and dataSpace sent
- // to HAL are original, not the overridden ones.
- if (mHidlSession_3_5 != nullptr) {
- dst3_2.format = mapToPixelFormat(cam3stream->isFormatOverridden()
- ? cam3stream->getOriginalFormat()
- : src->format);
- dst3_2.dataSpace =
- mapToHidlDataspace(cam3stream->isDataSpaceOverridden()
- ? cam3stream->getOriginalDataSpace()
- : src->data_space);
- } else {
- dst3_2.format = mapToPixelFormat(src->format);
- dst3_2.dataSpace = mapToHidlDataspace(src->data_space);
- }
- dst3_4.v3_2 = dst3_2;
- dst3_4.bufferSize = bufferSizes[i];
- if (src->physical_camera_id != nullptr) {
- dst3_4.physicalCameraId = src->physical_camera_id;
- }
- dst3_7.v3_4 = dst3_4;
- dst3_7.groupId = cam3stream->getHalStreamGroupId();
- dst3_7.sensorPixelModesUsed.resize(src->sensor_pixel_modes_used.size());
- size_t j = 0;
- for (int mode : src->sensor_pixel_modes_used) {
- dst3_7.sensorPixelModesUsed[j++] =
- static_cast<CameraMetadataEnumAndroidSensorPixelMode>(mode);
- }
- activeStreams.insert(streamId);
- // Create Buffer ID map if necessary
- mBufferRecords.tryCreateBufferCache(streamId);
- }
- // remove BufferIdMap for deleted streams
- mBufferRecords.removeInactiveBufferCaches(activeStreams);
-
- StreamConfigurationMode operationMode;
- res = mapToStreamConfigurationMode(
- (camera_stream_configuration_mode_t)config->operation_mode,
- /*out*/ &operationMode);
- if (res != OK) {
- return res;
- }
- requestedConfiguration3_7.operationMode = operationMode;
- size_t sessionParamSize = get_camera_metadata_size(sessionParams);
- requestedConfiguration3_7.operationMode = operationMode;
- requestedConfiguration3_7.sessionParams.setToExternal(
- reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
- sessionParamSize);
-
- // See which version of HAL we have
- if (mHidlSession_3_7 != nullptr) {
- requestedConfiguration3_7.streamConfigCounter = mNextStreamConfigCounter++;
- requestedConfiguration3_7.multiResolutionInputImage =
- config->input_is_multi_resolution;
-
- const camera_metadata_t* rawMetadata = cameraCharacteristics.getAndLock();
- ::android::hardware::camera::device::V3_2::CameraMetadata hidlChars = {};
- hidlChars.setToExternal(
- reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(rawMetadata)),
- get_camera_metadata_size(rawMetadata));
- cameraCharacteristics.unlock(rawMetadata);
-
- sp<hardware::camera::device::V3_7::ICameraInjectionSession>
- hidlInjectionSession_3_7;
- auto castInjectionResult_3_7 =
- device::V3_7::ICameraInjectionSession::castFrom(mHidlSession_3_7);
- if (castInjectionResult_3_7.isOk()) {
- hidlInjectionSession_3_7 = castInjectionResult_3_7;
- } else {
- ALOGE("%s: Transaction error: %s", __FUNCTION__,
- castInjectionResult_3_7.description().c_str());
- return DEAD_OBJECT;
- }
-
- auto err = hidlInjectionSession_3_7->configureInjectionStreams(
- requestedConfiguration3_7, hidlChars);
- if (!err.isOk()) {
- ALOGE("%s: Transaction error: %s", __FUNCTION__,
- err.description().c_str());
- return DEAD_OBJECT;
- }
- } else {
- ALOGE("%s: mHidlSession_3_7 does not exist, the lowest version of injection "
- "session is 3.7", __FUNCTION__);
- return DEAD_OBJECT;
- }
-
- return res;
-}
-
-status_t Camera3Device::HalInterface::wrapAsHidlRequest(camera_capture_request_t* request,
- /*out*/device::V3_2::CaptureRequest* captureRequest,
- /*out*/std::vector<native_handle_t*>* handlesCreated,
- /*out*/std::vector<std::pair<int32_t, int32_t>>* inflightBuffers) {
- ATRACE_CALL();
- if (captureRequest == nullptr || handlesCreated == nullptr || inflightBuffers == nullptr) {
- ALOGE("%s: captureRequest (%p), handlesCreated (%p), and inflightBuffers(%p) "
- "must not be null", __FUNCTION__, captureRequest, handlesCreated, inflightBuffers);
- return BAD_VALUE;
- }
-
- captureRequest->frameNumber = request->frame_number;
-
- captureRequest->fmqSettingsSize = 0;
-
- {
- if (request->input_buffer != nullptr) {
- int32_t streamId = Camera3Stream::cast(request->input_buffer->stream)->getId();
- buffer_handle_t buf = *(request->input_buffer->buffer);
- auto pair = getBufferId(buf, streamId);
- bool isNewBuffer = pair.first;
- uint64_t bufferId = pair.second;
- captureRequest->inputBuffer.streamId = streamId;
- captureRequest->inputBuffer.bufferId = bufferId;
- captureRequest->inputBuffer.buffer = (isNewBuffer) ? buf : nullptr;
- captureRequest->inputBuffer.status = BufferStatus::OK;
- native_handle_t *acquireFence = nullptr;
- if (request->input_buffer->acquire_fence != -1) {
- acquireFence = native_handle_create(1,0);
- acquireFence->data[0] = request->input_buffer->acquire_fence;
- handlesCreated->push_back(acquireFence);
- }
- captureRequest->inputBuffer.acquireFence = acquireFence;
- captureRequest->inputBuffer.releaseFence = nullptr;
-
- mBufferRecords.pushInflightBuffer(captureRequest->frameNumber, streamId,
- request->input_buffer->buffer);
- inflightBuffers->push_back(std::make_pair(captureRequest->frameNumber, streamId));
- } else {
- captureRequest->inputBuffer.streamId = -1;
- captureRequest->inputBuffer.bufferId = BUFFER_ID_NO_BUFFER;
- }
-
- captureRequest->outputBuffers.resize(request->num_output_buffers);
- for (size_t i = 0; i < request->num_output_buffers; i++) {
- const camera_stream_buffer_t *src = request->output_buffers + i;
- StreamBuffer &dst = captureRequest->outputBuffers[i];
- int32_t streamId = Camera3Stream::cast(src->stream)->getId();
- if (src->buffer != nullptr) {
- buffer_handle_t buf = *(src->buffer);
- auto pair = getBufferId(buf, streamId);
- bool isNewBuffer = pair.first;
- dst.bufferId = pair.second;
- dst.buffer = isNewBuffer ? buf : nullptr;
- native_handle_t *acquireFence = nullptr;
- if (src->acquire_fence != -1) {
- acquireFence = native_handle_create(1,0);
- acquireFence->data[0] = src->acquire_fence;
- handlesCreated->push_back(acquireFence);
- }
- dst.acquireFence = acquireFence;
- } else if (mUseHalBufManager) {
- // HAL buffer management path
- dst.bufferId = BUFFER_ID_NO_BUFFER;
- dst.buffer = nullptr;
- dst.acquireFence = nullptr;
- } else {
- ALOGE("%s: cannot send a null buffer in capture request!", __FUNCTION__);
- return BAD_VALUE;
- }
- dst.streamId = streamId;
- dst.status = BufferStatus::OK;
- dst.releaseFence = nullptr;
-
- // Output buffers are empty when using HAL buffer manager
- if (!mUseHalBufManager) {
- mBufferRecords.pushInflightBuffer(
- captureRequest->frameNumber, streamId, src->buffer);
- inflightBuffers->push_back(std::make_pair(captureRequest->frameNumber, streamId));
- }
- }
- }
- return OK;
-}
-
-void Camera3Device::HalInterface::cleanupNativeHandles(
+void Camera3Device::cleanupNativeHandles(
std::vector<native_handle_t*> *handles, bool closeFd) {
if (handles == nullptr) {
return;
@@ -3885,313 +2754,9 @@
return;
}
-status_t Camera3Device::HalInterface::processBatchCaptureRequests(
- std::vector<camera_capture_request_t*>& requests,/*out*/uint32_t* numRequestProcessed) {
- ATRACE_NAME("CameraHal::processBatchCaptureRequests");
- if (!valid()) return INVALID_OPERATION;
-
- sp<device::V3_4::ICameraDeviceSession> hidlSession_3_4;
- sp<device::V3_7::ICameraDeviceSession> hidlSession_3_7;
- auto castResult_3_7 = device::V3_7::ICameraDeviceSession::castFrom(mHidlSession);
- if (castResult_3_7.isOk()) {
- hidlSession_3_7 = castResult_3_7;
- }
- auto castResult_3_4 = device::V3_4::ICameraDeviceSession::castFrom(mHidlSession);
- if (castResult_3_4.isOk()) {
- hidlSession_3_4 = castResult_3_4;
- }
-
- hardware::hidl_vec<device::V3_2::CaptureRequest> captureRequests;
- hardware::hidl_vec<device::V3_4::CaptureRequest> captureRequests_3_4;
- hardware::hidl_vec<device::V3_7::CaptureRequest> captureRequests_3_7;
- size_t batchSize = requests.size();
- if (hidlSession_3_7 != nullptr) {
- captureRequests_3_7.resize(batchSize);
- } else if (hidlSession_3_4 != nullptr) {
- captureRequests_3_4.resize(batchSize);
- } else {
- captureRequests.resize(batchSize);
- }
- std::vector<native_handle_t*> handlesCreated;
- std::vector<std::pair<int32_t, int32_t>> inflightBuffers;
-
- status_t res = OK;
- for (size_t i = 0; i < batchSize; i++) {
- if (hidlSession_3_7 != nullptr) {
- res = wrapAsHidlRequest(requests[i], /*out*/&captureRequests_3_7[i].v3_4.v3_2,
- /*out*/&handlesCreated, /*out*/&inflightBuffers);
- } else if (hidlSession_3_4 != nullptr) {
- res = wrapAsHidlRequest(requests[i], /*out*/&captureRequests_3_4[i].v3_2,
- /*out*/&handlesCreated, /*out*/&inflightBuffers);
- } else {
- res = wrapAsHidlRequest(requests[i], /*out*/&captureRequests[i],
- /*out*/&handlesCreated, /*out*/&inflightBuffers);
- }
- if (res != OK) {
- mBufferRecords.popInflightBuffers(inflightBuffers);
- cleanupNativeHandles(&handlesCreated);
- return res;
- }
- }
-
- std::vector<device::V3_2::BufferCache> cachesToRemove;
- {
- std::lock_guard<std::mutex> lock(mFreedBuffersLock);
- for (auto& pair : mFreedBuffers) {
- // The stream might have been removed since onBufferFreed
- if (mBufferRecords.isStreamCached(pair.first)) {
- cachesToRemove.push_back({pair.first, pair.second});
- }
- }
- mFreedBuffers.clear();
- }
-
- common::V1_0::Status status = common::V1_0::Status::INTERNAL_ERROR;
- *numRequestProcessed = 0;
-
- // Write metadata to FMQ.
- for (size_t i = 0; i < batchSize; i++) {
- camera_capture_request_t* request = requests[i];
- device::V3_2::CaptureRequest* captureRequest;
- if (hidlSession_3_7 != nullptr) {
- captureRequest = &captureRequests_3_7[i].v3_4.v3_2;
- } else if (hidlSession_3_4 != nullptr) {
- captureRequest = &captureRequests_3_4[i].v3_2;
- } else {
- captureRequest = &captureRequests[i];
- }
-
- if (request->settings != nullptr) {
- size_t settingsSize = get_camera_metadata_size(request->settings);
- if (mRequestMetadataQueue != nullptr && mRequestMetadataQueue->write(
- reinterpret_cast<const uint8_t*>(request->settings), settingsSize)) {
- captureRequest->settings.resize(0);
- captureRequest->fmqSettingsSize = settingsSize;
- } else {
- if (mRequestMetadataQueue != nullptr) {
- ALOGW("%s: couldn't utilize fmq, fallback to hwbinder", __FUNCTION__);
- }
- captureRequest->settings.setToExternal(
- reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(request->settings)),
- get_camera_metadata_size(request->settings));
- captureRequest->fmqSettingsSize = 0u;
- }
- } else {
- // A null request settings maps to a size-0 CameraMetadata
- captureRequest->settings.resize(0);
- captureRequest->fmqSettingsSize = 0u;
- }
-
- // hidl session 3.7 specific handling.
- if (hidlSession_3_7 != nullptr) {
- captureRequests_3_7[i].inputWidth = request->input_width;
- captureRequests_3_7[i].inputHeight = request->input_height;
- }
-
- // hidl session 3.7 and 3.4 specific handling.
- if (hidlSession_3_7 != nullptr || hidlSession_3_4 != nullptr) {
- hardware::hidl_vec<device::V3_4::PhysicalCameraSetting>& physicalCameraSettings =
- (hidlSession_3_7 != nullptr) ?
- captureRequests_3_7[i].v3_4.physicalCameraSettings :
- captureRequests_3_4[i].physicalCameraSettings;
- physicalCameraSettings.resize(request->num_physcam_settings);
- for (size_t j = 0; j < request->num_physcam_settings; j++) {
- if (request->physcam_settings != nullptr) {
- size_t settingsSize = get_camera_metadata_size(request->physcam_settings[j]);
- if (mRequestMetadataQueue != nullptr && mRequestMetadataQueue->write(
- reinterpret_cast<const uint8_t*>(request->physcam_settings[j]),
- settingsSize)) {
- physicalCameraSettings[j].settings.resize(0);
- physicalCameraSettings[j].fmqSettingsSize = settingsSize;
- } else {
- if (mRequestMetadataQueue != nullptr) {
- ALOGW("%s: couldn't utilize fmq, fallback to hwbinder", __FUNCTION__);
- }
- physicalCameraSettings[j].settings.setToExternal(
- reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(
- request->physcam_settings[j])),
- get_camera_metadata_size(request->physcam_settings[j]));
- physicalCameraSettings[j].fmqSettingsSize = 0u;
- }
- } else {
- physicalCameraSettings[j].fmqSettingsSize = 0u;
- physicalCameraSettings[j].settings.resize(0);
- }
- physicalCameraSettings[j].physicalCameraId = request->physcam_id[j];
- }
- }
- }
-
- hardware::details::return_status err;
- auto resultCallback =
- [&status, &numRequestProcessed] (auto s, uint32_t n) {
- status = s;
- *numRequestProcessed = n;
- };
- if (hidlSession_3_7 != nullptr) {
- err = hidlSession_3_7->processCaptureRequest_3_7(captureRequests_3_7, cachesToRemove,
- resultCallback);
- } else if (hidlSession_3_4 != nullptr) {
- err = hidlSession_3_4->processCaptureRequest_3_4(captureRequests_3_4, cachesToRemove,
- resultCallback);
- } else {
- err = mHidlSession->processCaptureRequest(captureRequests, cachesToRemove,
- resultCallback);
- }
- if (!err.isOk()) {
- ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
- status = common::V1_0::Status::CAMERA_DISCONNECTED;
- }
-
- if (status == common::V1_0::Status::OK && *numRequestProcessed != batchSize) {
- ALOGE("%s: processCaptureRequest returns OK but processed %d/%zu requests",
- __FUNCTION__, *numRequestProcessed, batchSize);
- status = common::V1_0::Status::INTERNAL_ERROR;
- }
-
- res = CameraProviderManager::mapToStatusT(status);
- if (res == OK) {
- if (mHidlSession->isRemote()) {
- // Only close acquire fence FDs when the HIDL transaction succeeds (so the FDs have been
- // sent to camera HAL processes)
- cleanupNativeHandles(&handlesCreated, /*closeFd*/true);
- } else {
- // In passthrough mode the FDs are now owned by HAL
- cleanupNativeHandles(&handlesCreated);
- }
- } else {
- mBufferRecords.popInflightBuffers(inflightBuffers);
- cleanupNativeHandles(&handlesCreated);
- }
- return res;
-}
-
-status_t Camera3Device::HalInterface::flush() {
- ATRACE_NAME("CameraHal::flush");
- if (!valid()) return INVALID_OPERATION;
- status_t res = OK;
-
- auto err = mHidlSession->flush();
- if (!err.isOk()) {
- ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
- res = DEAD_OBJECT;
- } else {
- res = CameraProviderManager::mapToStatusT(err);
- }
-
- return res;
-}
-
-status_t Camera3Device::HalInterface::dump(int /*fd*/) {
- ATRACE_NAME("CameraHal::dump");
- if (!valid()) return INVALID_OPERATION;
-
- // Handled by CameraProviderManager::dump
-
- return OK;
-}
-
-status_t Camera3Device::HalInterface::repeatingRequestEnd(uint32_t frameNumber,
- hardware::hidl_vec<int32_t> streamIds) {
- ATRACE_NAME("CameraHal::repeatingRequestEnd");
- if (!valid()) return INVALID_OPERATION;
-
- if (mHidlSession_3_8.get() != nullptr) {
- mHidlSession_3_8->repeatingRequestEnd(frameNumber, streamIds);
- }
-
- return OK;
-}
-
-status_t Camera3Device::HalInterface::close() {
- ATRACE_NAME("CameraHal::close()");
- if (!valid()) return INVALID_OPERATION;
- status_t res = OK;
-
- auto err = mHidlSession->close();
- // Interface will be dead shortly anyway, so don't log errors
- if (!err.isOk()) {
- res = DEAD_OBJECT;
- }
-
- return res;
-}
-
-void Camera3Device::HalInterface::signalPipelineDrain(const std::vector<int>& streamIds) {
- ATRACE_NAME("CameraHal::signalPipelineDrain");
- if (!valid() || mHidlSession_3_5 == nullptr) {
- ALOGE("%s called on invalid camera!", __FUNCTION__);
- return;
- }
-
- auto err = mHidlSession_3_5->signalStreamFlush(streamIds, mNextStreamConfigCounter - 1);
- if (!err.isOk()) {
- ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
- return;
- }
-}
-
-status_t Camera3Device::HalInterface::switchToOffline(
- const std::vector<int32_t>& streamsToKeep,
- /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
- /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
- /*out*/camera3::BufferRecords* bufferRecords) {
- ATRACE_NAME("CameraHal::switchToOffline");
- if (!valid() || mHidlSession_3_6 == nullptr) {
- ALOGE("%s called on invalid camera!", __FUNCTION__);
- return INVALID_OPERATION;
- }
-
- if (offlineSessionInfo == nullptr || offlineSession == nullptr || bufferRecords == nullptr) {
- ALOGE("%s: output arguments must not be null!", __FUNCTION__);
- return INVALID_OPERATION;
- }
-
- common::V1_0::Status status = common::V1_0::Status::INTERNAL_ERROR;
- auto resultCallback =
- [&status, &offlineSessionInfo, &offlineSession] (auto s, auto info, auto session) {
- status = s;
- *offlineSessionInfo = info;
- *offlineSession = session;
- };
- auto err = mHidlSession_3_6->switchToOffline(streamsToKeep, resultCallback);
-
- if (!err.isOk()) {
- ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
- return DEAD_OBJECT;
- }
-
- status_t ret = CameraProviderManager::mapToStatusT(status);
- if (ret != OK) {
- return ret;
- }
-
- // TODO: assert no ongoing requestBuffer/returnBuffer call here
- // TODO: update RequestBufferStateMachine to block requestBuffer/returnBuffer once HAL
- // returns from switchToOffline.
-
-
- // Validate buffer caches
- std::vector<int32_t> streams;
- streams.reserve(offlineSessionInfo->offlineStreams.size());
- for (auto offlineStream : offlineSessionInfo->offlineStreams) {
- int32_t id = offlineStream.id;
- streams.push_back(id);
- // Verify buffer caches
- std::vector<uint64_t> bufIds(offlineStream.circulatingBufferIds.begin(),
- offlineStream.circulatingBufferIds.end());
- if (!verifyBufferIds(id, bufIds)) {
- ALOGE("%s: stream ID %d buffer cache records mismatch!", __FUNCTION__, id);
- return UNKNOWN_ERROR;
- }
- }
-
- // Move buffer records
- bufferRecords->takeBufferCaches(mBufferRecords, streams);
- bufferRecords->takeInflightBufferMap(mBufferRecords);
- bufferRecords->takeRequestedBufferMap(mBufferRecords);
- return ret;
-}
+/**
+ * HalInterface inner class methods
+ */
void Camera3Device::HalInterface::getInflightBufferKeys(
std::vector<std::pair<int32_t, int32_t>>* out) {
@@ -5415,38 +3980,6 @@
mPrevRequest.clear();
}
-status_t Camera3Device::RequestThread::switchToOffline(
- const std::vector<int32_t>& streamsToKeep,
- /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
- /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
- /*out*/camera3::BufferRecords* bufferRecords) {
- Mutex::Autolock l(mRequestLock);
- clearRepeatingRequestsLocked(/*lastFrameNumber*/nullptr);
-
- // Wait until request thread is fully stopped
- // TBD: check if request thread is being paused by other APIs (shouldn't be)
-
- // We could also check for mRepeatingRequests.empty(), but the API interface
- // is serialized by Camera3Device::mInterfaceLock so no one should be able to submit any
- // new requests during the call; hence skip that check.
- bool queueEmpty = mNextRequests.empty() && mRequestQueue.empty();
- while (!queueEmpty) {
- status_t res = mRequestSubmittedSignal.waitRelative(mRequestLock, kRequestSubmitTimeout);
- if (res == TIMED_OUT) {
- ALOGE("%s: request thread failed to submit one request within timeout!", __FUNCTION__);
- return res;
- } else if (res != OK) {
- ALOGE("%s: request thread failed to submit a request: %s (%d)!",
- __FUNCTION__, strerror(-res), res);
- return res;
- }
- queueEmpty = mNextRequests.empty() && mRequestQueue.empty();
- }
-
- return mInterface->switchToOffline(
- streamsToKeep, offlineSessionInfo, offlineSession, bufferRecords);
-}
-
status_t Camera3Device::RequestThread::setRotateAndCropAutoBehavior(
camera_metadata_enum_android_scaler_rotate_and_crop_t rotateAndCropValue) {
ATRACE_CALL();
@@ -6477,220 +5010,6 @@
return ret;
}
-status_t Camera3Device::switchToOffline(
- const std::vector<int32_t>& streamsToKeep,
- /*out*/ sp<CameraOfflineSessionBase>* session) {
- ATRACE_CALL();
- if (session == nullptr) {
- ALOGE("%s: session must not be null", __FUNCTION__);
- return BAD_VALUE;
- }
-
- Mutex::Autolock il(mInterfaceLock);
-
- bool hasInputStream = mInputStream != nullptr;
- int32_t inputStreamId = hasInputStream ? mInputStream->getId() : -1;
- bool inputStreamSupportsOffline = hasInputStream ?
- mInputStream->getOfflineProcessingSupport() : false;
- auto outputStreamIds = mOutputStreams.getStreamIds();
- auto streamIds = outputStreamIds;
- if (hasInputStream) {
- streamIds.push_back(mInputStream->getId());
- }
-
- // Check all streams in streamsToKeep supports offline mode
- for (auto id : streamsToKeep) {
- if (std::find(streamIds.begin(), streamIds.end(), id) == streamIds.end()) {
- ALOGE("%s: Unknown stream ID %d", __FUNCTION__, id);
- return BAD_VALUE;
- } else if (id == inputStreamId) {
- if (!inputStreamSupportsOffline) {
- ALOGE("%s: input stream %d cannot be switched to offline",
- __FUNCTION__, id);
- return BAD_VALUE;
- }
- } else {
- sp<camera3::Camera3OutputStreamInterface> stream = mOutputStreams.get(id);
- if (!stream->getOfflineProcessingSupport()) {
- ALOGE("%s: output stream %d cannot be switched to offline",
- __FUNCTION__, id);
- return BAD_VALUE;
- }
- }
- }
-
- // TODO: block surface sharing and surface group streams until we can support them
-
- // Stop repeating request, wait until all remaining requests are submitted, then call into
- // HAL switchToOffline
- hardware::camera::device::V3_6::CameraOfflineSessionInfo offlineSessionInfo;
- sp<hardware::camera::device::V3_6::ICameraOfflineSession> offlineSession;
- camera3::BufferRecords bufferRecords;
- status_t ret = mRequestThread->switchToOffline(
- streamsToKeep, &offlineSessionInfo, &offlineSession, &bufferRecords);
-
- if (ret != OK) {
- SET_ERR("Switch to offline failed: %s (%d)", strerror(-ret), ret);
- return ret;
- }
-
- bool succ = mRequestBufferSM.onSwitchToOfflineSuccess();
- if (!succ) {
- SET_ERR("HAL must not be calling requestStreamBuffers call");
- // TODO: block ALL callbacks from HAL till app configured new streams?
- return UNKNOWN_ERROR;
- }
-
- // Verify offlineSessionInfo
- std::vector<int32_t> offlineStreamIds;
- offlineStreamIds.reserve(offlineSessionInfo.offlineStreams.size());
- for (auto offlineStream : offlineSessionInfo.offlineStreams) {
- // verify stream IDs
- int32_t id = offlineStream.id;
- if (std::find(streamIds.begin(), streamIds.end(), id) == streamIds.end()) {
- SET_ERR("stream ID %d not found!", id);
- return UNKNOWN_ERROR;
- }
-
- // When not using HAL buf manager, only allow streams requested by app to be preserved
- if (!mUseHalBufManager) {
- if (std::find(streamsToKeep.begin(), streamsToKeep.end(), id) == streamsToKeep.end()) {
- SET_ERR("stream ID %d must not be switched to offline!", id);
- return UNKNOWN_ERROR;
- }
- }
-
- offlineStreamIds.push_back(id);
- sp<Camera3StreamInterface> stream = (id == inputStreamId) ?
- static_cast<sp<Camera3StreamInterface>>(mInputStream) :
- static_cast<sp<Camera3StreamInterface>>(mOutputStreams.get(id));
- // Verify number of outstanding buffers
- if (stream->getOutstandingBuffersCount() != offlineStream.numOutstandingBuffers) {
- SET_ERR("Offline stream %d # of remaining buffer mismatch: (%zu,%d) (service/HAL)",
- id, stream->getOutstandingBuffersCount(), offlineStream.numOutstandingBuffers);
- return UNKNOWN_ERROR;
- }
- }
-
- // Verify all streams to be deleted don't have any outstanding buffers
- if (hasInputStream && std::find(offlineStreamIds.begin(), offlineStreamIds.end(),
- inputStreamId) == offlineStreamIds.end()) {
- if (mInputStream->hasOutstandingBuffers()) {
- SET_ERR("Input stream %d still has %zu outstanding buffer!",
- inputStreamId, mInputStream->getOutstandingBuffersCount());
- return UNKNOWN_ERROR;
- }
- }
-
- for (const auto& outStreamId : outputStreamIds) {
- if (std::find(offlineStreamIds.begin(), offlineStreamIds.end(),
- outStreamId) == offlineStreamIds.end()) {
- auto outStream = mOutputStreams.get(outStreamId);
- if (outStream->hasOutstandingBuffers()) {
- SET_ERR("Output stream %d still has %zu outstanding buffer!",
- outStreamId, outStream->getOutstandingBuffersCount());
- return UNKNOWN_ERROR;
- }
- }
- }
-
- InFlightRequestMap offlineReqs;
- // Verify inflight requests and their pending buffers
- {
- std::lock_guard<std::mutex> l(mInFlightLock);
- for (auto offlineReq : offlineSessionInfo.offlineRequests) {
- int idx = mInFlightMap.indexOfKey(offlineReq.frameNumber);
- if (idx == NAME_NOT_FOUND) {
- SET_ERR("Offline request frame number %d not found!", offlineReq.frameNumber);
- return UNKNOWN_ERROR;
- }
-
- const auto& inflightReq = mInFlightMap.valueAt(idx);
- // TODO: check specific stream IDs
- size_t numBuffersLeft = static_cast<size_t>(inflightReq.numBuffersLeft);
- if (numBuffersLeft != offlineReq.pendingStreams.size()) {
- SET_ERR("Offline request # of remaining buffer mismatch: (%d,%d) (service/HAL)",
- inflightReq.numBuffersLeft, offlineReq.pendingStreams.size());
- return UNKNOWN_ERROR;
- }
- offlineReqs.add(offlineReq.frameNumber, inflightReq);
- }
- }
-
- // Create Camera3OfflineSession and transfer object ownership
- // (streams, inflight requests, buffer caches)
- camera3::StreamSet offlineStreamSet;
- sp<camera3::Camera3Stream> inputStream;
- for (auto offlineStream : offlineSessionInfo.offlineStreams) {
- int32_t id = offlineStream.id;
- if (mInputStream != nullptr && id == mInputStream->getId()) {
- inputStream = mInputStream;
- } else {
- offlineStreamSet.add(id, mOutputStreams.get(id));
- }
- }
-
- // TODO: check if we need to lock before copying states
- // though technically no other thread should be talking to Camera3Device at this point
- Camera3OfflineStates offlineStates(
- mTagMonitor, mVendorTagId, mUseHalBufManager, mNeedFixupMonochromeTags,
- mUsePartialResult, mNumPartialResults, mLastCompletedRegularFrameNumber,
- mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
- mNextResultFrameNumber, mNextReprocessResultFrameNumber,
- mNextZslStillResultFrameNumber, mNextShutterFrameNumber,
- mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
- mDeviceInfo, mPhysicalDeviceInfoMap, mDistortionMappers,
- mZoomRatioMappers, mRotateAndCropMappers);
-
- *session = new Camera3OfflineSession(mId, inputStream, offlineStreamSet,
- std::move(bufferRecords), offlineReqs, offlineStates, offlineSession);
-
- // Delete all streams that has been transferred to offline session
- Mutex::Autolock l(mLock);
- for (auto offlineStream : offlineSessionInfo.offlineStreams) {
- int32_t id = offlineStream.id;
- if (mInputStream != nullptr && id == mInputStream->getId()) {
- mInputStream.clear();
- } else {
- mOutputStreams.remove(id);
- }
- }
-
- // disconnect all other streams and switch to UNCONFIGURED state
- if (mInputStream != nullptr) {
- ret = mInputStream->disconnect();
- if (ret != OK) {
- SET_ERR_L("disconnect input stream failed!");
- return UNKNOWN_ERROR;
- }
- }
-
- for (auto streamId : mOutputStreams.getStreamIds()) {
- sp<Camera3StreamInterface> stream = mOutputStreams.get(streamId);
- ret = stream->disconnect();
- if (ret != OK) {
- SET_ERR_L("disconnect output stream %d failed!", streamId);
- return UNKNOWN_ERROR;
- }
- }
-
- mInputStream.clear();
- mOutputStreams.clear();
- mNeedConfig = true;
- internalUpdateStatusLocked(STATUS_UNCONFIGURED);
- mOperatingMode = NO_MODE;
- mIsConstrainedHighSpeedConfiguration = false;
- mRequestThread->clearPreviousRequest();
-
- return OK;
- // TO be done by CameraDeviceClient/Camera3OfflineSession
- // register the offline client to camera service
- // Setup result passthing threads etc
- // Initialize offline session so HAL can start sending callback to it (result Fmq)
- // TODO: check how many onIdle callback will be sent
- // Java side to make sure the CameraCaptureSession is properly closed
-}
-
void Camera3Device::getOfflineStreamIds(std::vector<int> *offlineStreamIds) {
ATRACE_CALL();
@@ -6777,7 +5096,7 @@
}
}
- res = mInjectionMethods->injectionInitialize(injectedCamId, manager, this);
+ res = injectionCameraInitialize(injectedCamId, manager);
if (res != OK) {
ALOGE("%s: Failed to initialize the injection camera! ret != NO_ERROR: %d",
__FUNCTION__, res);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 3ce17f9..be976d0 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -29,20 +29,6 @@
#include <utils/KeyedVector.h>
#include <utils/Timers.h>
-#include <android/hardware/camera/device/3.2/ICameraDevice.h>
-#include <android/hardware/camera/device/3.2/ICameraDeviceSession.h>
-#include <android/hardware/camera/device/3.3/ICameraDeviceSession.h>
-#include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
-#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
-#include <android/hardware/camera/device/3.6/ICameraDeviceSession.h>
-#include <android/hardware/camera/device/3.7/ICameraDeviceSession.h>
-#include <android/hardware/camera/device/3.8/ICameraDeviceSession.h>
-#include <android/hardware/camera/device/3.2/ICameraDeviceCallback.h>
-#include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h>
-#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
-#include <android/hardware/camera/device/3.8/ICameraDeviceCallback.h>
-#include <fmq/MessageQueue.h>
-
#include <camera/CaptureResult.h>
#include "android/hardware/camera/metadata/3.8/types.h"
@@ -59,6 +45,7 @@
#include "device3/Camera3OfflineSession.h"
#include "device3/Camera3StreamInterface.h"
#include "utils/TagMonitor.h"
+#include "utils/IPCTransport.h"
#include "utils/LatencyHistogram.h"
#include <camera_metadata_hidden.h>
@@ -70,7 +57,6 @@
using android::camera3::camera_stream_configuration_mode_t;
using android::camera3::CAMERA_TEMPLATE_COUNT;
using android::camera3::OutputStreamInfo;
-using android::hardware::camera::metadata::V3_8::CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap;
namespace android {
@@ -87,16 +73,22 @@
*/
class Camera3Device :
public CameraDeviceBase,
- virtual public hardware::camera::device::V3_8::ICameraDeviceCallback,
public camera3::SetErrorInterface,
public camera3::InflightRequestUpdateInterface,
public camera3::RequestBufferInterface,
public camera3::FlushBufferInterface {
+ friend class HidlCamera3Device;
+ friend class AidlCamera3Device;
public:
explicit Camera3Device(const String8& id, bool overrideForPerfClass, bool legacyClient = false);
virtual ~Camera3Device();
+ // Delete and optionally close native handles and clear the input vector afterward
+ static void cleanupNativeHandles(
+ std::vector<native_handle_t*> *handles, bool closeFd = false);
+
+ IPCTransport getTransportType() { return mInterface->getTransportType(); }
/**
* CameraDeviceBase interface
@@ -107,7 +99,9 @@
metadata_vendor_id_t getVendorTagId() const override { return mVendorTagId; }
// Transitions to idle state on success.
- status_t initialize(sp<CameraProviderManager> manager, const String8& monitorTags) override;
+ virtual status_t initialize(sp<CameraProviderManager> /*manager*/,
+ const String8& /*monitorTags*/) = 0;
+
status_t disconnect() override;
status_t dump(int fd, const Vector<String16> &args) override;
status_t startWatchingTags(const String8 &tags) override;
@@ -146,7 +140,10 @@
bool isShared = false, bool isMultiResolution = false,
uint64_t consumerUsage = 0,
int dynamicRangeProfile =
- ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) override;
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
+ int streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
+ int timestampBase = OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
+ int mirrorMode = OutputConfiguration::MIRROR_MODE_AUTO) override;
status_t createStream(const std::vector<sp<Surface>>& consumers,
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
@@ -158,7 +155,10 @@
bool isShared = false, bool isMultiResolution = false,
uint64_t consumerUsage = 0,
int dynamicRangeProfile =
- ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) override;
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
+ int streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
+ int timestampBase = OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
+ int mirrorMode = OutputConfiguration::MIRROR_MODE_AUTO) override;
status_t createInputStream(
uint32_t width, uint32_t height, int format, bool isMultiResolution,
@@ -236,8 +236,10 @@
nsecs_t getExpectedInFlightDuration() override;
- status_t switchToOffline(const std::vector<int32_t>& streamsToKeep,
- /*out*/ sp<CameraOfflineSessionBase>* session) override;
+ virtual status_t switchToOffline(const std::vector<int32_t>& ,
+ /*out*/ sp<CameraOfflineSessionBase>* ) override {
+ return INVALID_OPERATION;
+ };
// RequestBufferInterface
bool startRequestBuffer() override;
@@ -288,35 +290,10 @@
*/
status_t stopInjection();
- /**
- * Helper functions to map between framework and HIDL values
- */
- static hardware::graphics::common::V1_0::PixelFormat mapToPixelFormat(int frameworkFormat);
- static hardware::camera::device::V3_2::DataspaceFlags mapToHidlDataspace(
- android_dataspace dataSpace);
- static CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap mapToHidlDynamicProfile(
- int dynamicRangeProfile);
- static hardware::camera::device::V3_2::BufferUsageFlags mapToConsumerUsage(uint64_t usage);
- static hardware::camera::device::V3_2::StreamRotation mapToStreamRotation(
- camera_stream_rotation_t rotation);
- // Returns a negative error code if the passed-in operation mode is not valid.
- static status_t mapToStreamConfigurationMode(camera_stream_configuration_mode_t operationMode,
- /*out*/ hardware::camera::device::V3_2::StreamConfigurationMode *mode);
- static int mapToFrameworkFormat(hardware::graphics::common::V1_0::PixelFormat pixelFormat);
- static android_dataspace mapToFrameworkDataspace(
- hardware::camera::device::V3_2::DataspaceFlags);
- static uint64_t mapConsumerToFrameworkUsage(
- hardware::camera::device::V3_2::BufferUsageFlags usage);
- static uint64_t mapProducerToFrameworkUsage(
- hardware::camera::device::V3_2::BufferUsageFlags usage);
-
- private:
+ protected:
status_t disconnectImpl();
static status_t removeFwkOnlyRegionKeys(CameraMetadata *request);
- // internal typedefs
- using RequestMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
-
static const size_t kDumpLockAttempts = 10;
static const size_t kDumpSleepDuration = 100000; // 0.10 sec
static const nsecs_t kActiveTimeout = 500000000; // 500 ms
@@ -362,70 +339,65 @@
// Flag indicating is the current active stream configuration is constrained high speed.
bool mIsConstrainedHighSpeedConfiguration;
- // FMQ to write result on. Must be guarded by mProcessCaptureResultLock.
- std::unique_ptr<ResultMetadataQueue> mResultMetadataQueue;
-
/**** Scope for mLock ****/
- /**
- * Adapter for legacy HAL / HIDL HAL interface calls; calls either into legacy HALv3 or the
- * HIDL HALv3 interfaces.
- */
class HalInterface : public camera3::Camera3StreamBufferFreedListener,
public camera3::BufferRecordsInterface {
public:
- HalInterface(sp<hardware::camera::device::V3_2::ICameraDeviceSession> &session,
- std::shared_ptr<RequestMetadataQueue> queue,
- bool useHalBufManager, bool supportOfflineProcessing);
+ HalInterface(bool useHalBufManager, bool supportOfflineProcessing) :
+ mUseHalBufManager(useHalBufManager),
+ mIsReconfigurationQuerySupported(true),
+ mSupportOfflineProcessing(supportOfflineProcessing)
+ {};
HalInterface(const HalInterface &other);
HalInterface();
+ virtual IPCTransport getTransportType() = 0;
+
// Returns true if constructed with a valid device or session, and not yet cleared
- bool valid();
+ virtual bool valid() = 0;
// Reset this HalInterface object (does not call close())
- void clear();
+ virtual void clear() = 0;
// Calls into the HAL interface
// Caller takes ownership of requestTemplate
- status_t constructDefaultRequestSettings(camera_request_template templateId,
- /*out*/ camera_metadata_t **requestTemplate);
- status_t configureStreams(const camera_metadata_t *sessionParams,
- /*inout*/ camera_stream_configuration_t *config,
- const std::vector<uint32_t>& bufferSizes);
+ virtual status_t constructDefaultRequestSettings(camera_request_template templateId,
+ /*out*/ camera_metadata_t **requestTemplate) = 0;
+
+ virtual status_t configureStreams(const camera_metadata_t * sessionParams,
+ /*inout*/ camera_stream_configuration_t * config,
+ const std::vector<uint32_t>& bufferSizes) = 0;
// The injection camera configures the streams to hal.
- status_t configureInjectedStreams(
+ virtual status_t configureInjectedStreams(
const camera_metadata_t* sessionParams,
/*inout*/ camera_stream_configuration_t* config,
const std::vector<uint32_t>& bufferSizes,
- const CameraMetadata& cameraCharacteristics);
+ const CameraMetadata& cameraCharacteristics) = 0;
// When the call succeeds, the ownership of acquire fences in requests is transferred to
// HalInterface. More specifically, the current implementation will send the fence to
// HAL process and close the FD in cameraserver process. When the call fails, the ownership
// of the acquire fence still belongs to the caller.
- status_t processBatchCaptureRequests(
+ virtual status_t processBatchCaptureRequests(
std::vector<camera_capture_request_t*>& requests,
- /*out*/uint32_t* numRequestProcessed);
- status_t flush();
- status_t dump(int fd);
- status_t close();
+ /*out*/uint32_t* numRequestProcessed) = 0;
- void signalPipelineDrain(const std::vector<int>& streamIds);
- bool isReconfigurationRequired(CameraMetadata& oldSessionParams,
- CameraMetadata& newSessionParams);
+ virtual status_t flush() = 0;
- // Upon successful return, HalInterface will return buffer maps needed for offline
- // processing, and clear all its internal buffer maps.
- status_t switchToOffline(
- const std::vector<int32_t>& streamsToKeep,
- /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
- /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
- /*out*/camera3::BufferRecords* bufferRecords);
+ virtual status_t dump(int fd) = 0;
- status_t repeatingRequestEnd(uint32_t frameNumber, hardware::hidl_vec<int32_t> streamIds);
+ virtual status_t close() = 0;
+
+ virtual void signalPipelineDrain(const std::vector<int>& streamIds) = 0;
+
+ virtual bool isReconfigurationRequired(CameraMetadata& oldSessionParams,
+ CameraMetadata& newSessionParams) = 0;
+
+ virtual status_t repeatingRequestEnd(uint32_t frameNumber,
+ const std::vector<int32_t> &streamIds) = 0;
/////////////////////////////////////////////////////////////////////
// Implements BufferRecordsInterface
@@ -456,43 +428,35 @@
void onStreamReConfigured(int streamId);
- private:
- // Always valid
- sp<hardware::camera::device::V3_2::ICameraDeviceSession> mHidlSession;
- // Valid if ICameraDeviceSession is @3.3 or newer
- sp<hardware::camera::device::V3_3::ICameraDeviceSession> mHidlSession_3_3;
- // Valid if ICameraDeviceSession is @3.4 or newer
- sp<hardware::camera::device::V3_4::ICameraDeviceSession> mHidlSession_3_4;
- // Valid if ICameraDeviceSession is @3.5 or newer
- sp<hardware::camera::device::V3_5::ICameraDeviceSession> mHidlSession_3_5;
- // Valid if ICameraDeviceSession is @3.6 or newer
- sp<hardware::camera::device::V3_6::ICameraDeviceSession> mHidlSession_3_6;
- // Valid if ICameraDeviceSession is @3.7 or newer
- sp<hardware::camera::device::V3_7::ICameraDeviceSession> mHidlSession_3_7;
- // Valid if ICameraDeviceSession is @3.8 or newer
- sp<hardware::camera::device::V3_8::ICameraDeviceSession> mHidlSession_3_8;
-
- std::shared_ptr<RequestMetadataQueue> mRequestMetadataQueue;
-
- // The output HIDL request still depends on input camera_capture_request_t
- // Do not free input camera_capture_request_t before output HIDL request
- status_t wrapAsHidlRequest(camera_capture_request_t* in,
- /*out*/hardware::camera::device::V3_2::CaptureRequest* out,
- /*out*/std::vector<native_handle_t*>* handlesCreated,
- /*out*/std::vector<std::pair<int32_t, int32_t>>* inflightBuffers);
-
- status_t pushInflightBufferLocked(int32_t frameNumber, int32_t streamId,
- buffer_handle_t *buffer);
-
- // Pop inflight buffers based on pairs of (frameNumber,streamId)
- void popInflightBuffers(const std::vector<std::pair<int32_t, int32_t>>& buffers);
+ protected:
// Return true if the input caches match what we have; otherwise false
bool verifyBufferIds(int32_t streamId, std::vector<uint64_t>& inBufIds);
- // Delete and optionally close native handles and clear the input vector afterward
- static void cleanupNativeHandles(
- std::vector<native_handle_t*> *handles, bool closeFd = false);
+ template <typename OfflineSessionInfoT>
+ status_t verifyBufferCaches(
+ const OfflineSessionInfoT *offlineSessionInfo, camera3::BufferRecords *bufferRecords) {
+ // Validate buffer caches
+ std::vector<int32_t> streams;
+ streams.reserve(offlineSessionInfo->offlineStreams.size());
+ for (auto offlineStream : offlineSessionInfo->offlineStreams) {
+ int32_t id = offlineStream.id;
+ streams.push_back(id);
+ // Verify buffer caches
+ std::vector<uint64_t> bufIds(offlineStream.circulatingBufferIds.begin(),
+ offlineStream.circulatingBufferIds.end());
+ if (!verifyBufferIds(id, bufIds)) {
+ ALOGE("%s: stream ID %d buffer cache records mismatch!", __FUNCTION__, id);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ // Move buffer records
+ bufferRecords->takeBufferCaches(mBufferRecords, streams);
+ bufferRecords->takeInflightBufferMap(mBufferRecords);
+ bufferRecords->takeRequestedBufferMap(mBufferRecords);
+ return OK;
+ }
virtual void onBufferFreed(int streamId, const native_handle_t* handle) override;
@@ -508,7 +472,7 @@
bool mIsReconfigurationQuerySupported;
const bool mSupportOfflineProcessing;
- };
+ }; // class HalInterface
sp<HalInterface> mInterface;
@@ -568,6 +532,7 @@
/**** End scope for mLock ****/
+ bool mDeviceTimeBaseIsRealtime;
// The offset converting from clock domain of other subsystem
// (video/hardware composer) to that of camera. Assumption is that this
// offset won't change during the life cycle of the camera device. In other
@@ -634,41 +599,6 @@
bool repeating,
int64_t *lastFrameNumber = NULL);
-
- /**
- * Implementation of android::hardware::camera::device::V3_5::ICameraDeviceCallback
- */
-
- hardware::Return<void> processCaptureResult_3_4(
- const hardware::hidl_vec<
- hardware::camera::device::V3_4::CaptureResult>& results) override;
- hardware::Return<void> processCaptureResult(
- const hardware::hidl_vec<
- hardware::camera::device::V3_2::CaptureResult>& results) override;
- hardware::Return<void> notify(
- const hardware::hidl_vec<
- hardware::camera::device::V3_2::NotifyMsg>& msgs) override;
-
- hardware::Return<void> requestStreamBuffers(
- const hardware::hidl_vec<
- hardware::camera::device::V3_5::BufferRequest>& bufReqs,
- requestStreamBuffers_cb _hidl_cb) override;
-
- hardware::Return<void> returnStreamBuffers(
- const hardware::hidl_vec<
- hardware::camera::device::V3_2::StreamBuffer>& buffers) override;
-
- hardware::Return<void> notify_3_8(
- const hardware::hidl_vec<
- hardware::camera::device::V3_8::NotifyMsg>& msgs) override;
-
- template<typename NotifyMsgType>
- hardware::Return<void> notifyHelper(
- const hardware::hidl_vec<NotifyMsgType>& msgs);
-
- // Handle one notify message
- void notify(const hardware::camera::device::V3_2::NotifyMsg& msg);
-
// lock to ensure only one processCaptureResult is called at a time.
Mutex mProcessCaptureResultLock;
@@ -686,6 +616,9 @@
*/
virtual CameraMetadata getLatestRequestLocked();
+ virtual status_t injectionCameraInitialize(const String8 &injectCamId,
+ sp<CameraProviderManager> manager) = 0;
+
/**
* Update the current device status and wake all waiting threads.
*
@@ -934,12 +867,6 @@
void signalPipelineDrain(const std::vector<int>& streamIds);
void resetPipelineDrain();
- status_t switchToOffline(
- const std::vector<int32_t>& streamsToKeep,
- /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
- /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
- /*out*/camera3::BufferRecords* bufferRecords);
-
void clearPreviousRequest();
status_t setRotateAndCropAutoBehavior(
@@ -954,7 +881,6 @@
virtual bool threadLoop();
- private:
static const String8& getId(const wp<Camera3Device> &device);
status_t queueTriggerLocked(RequestTrigger trigger);
@@ -1119,6 +1045,14 @@
const bool mUseHalBufManager;
const bool mSupportCameraMute;
};
+
+ virtual sp<RequestThread> createNewRequestThread(wp<Camera3Device> /*parent*/,
+ sp<camera3::StatusTracker> /*statusTracker*/,
+ sp<HalInterface> /*interface*/,
+ const Vector<int32_t>& /*sessionParamKeys*/,
+ bool /*useHalBufManager*/,
+ bool /*supportCameraMute*/) = 0;
+
sp<RequestThread> mRequestThread;
/**
@@ -1394,13 +1328,6 @@
~Camera3DeviceInjectionMethods();
- // Initialize the injection camera and generate an hal interface.
- status_t injectionInitialize(
- const String8& injectedCamId, sp<CameraProviderManager> manager,
- const sp<
- android::hardware::camera::device::V3_2 ::ICameraDeviceCallback>&
- callback);
-
// Injection camera will replace the internal camera and configure streams
// when device is IDLE and request thread is paused.
status_t injectCamera(
@@ -1426,7 +1353,7 @@
const camera3::camera_stream_configuration& injectionConfig,
const std::vector<uint32_t>& injectionBufferSizes);
- private:
+ protected:
// Configure the streams of injection camera, it need wait until the
// output streams are created and configured to the original camera before
// proceeding.
@@ -1439,8 +1366,8 @@
// Use injection camera hal interface to replace and backup original
// camera hal interface.
- status_t replaceHalInterface(sp<HalInterface> newHalInterface,
- bool keepBackup);
+ virtual status_t replaceHalInterface(sp<HalInterface> /*newHalInterface*/,
+ bool /*keepBackup*/) = 0;
wp<Camera3Device> mParent;
@@ -1450,13 +1377,6 @@
// Generated injection camera hal interface.
sp<HalInterface> mInjectedCamHalInterface;
- // Backup of the original camera hal result FMQ.
- std::unique_ptr<ResultMetadataQueue> mBackupResultMetadataQueue;
-
- // FMQ writes the result for the injection camera. Must be guarded by
- // mProcessCaptureResultLock.
- std::unique_ptr<ResultMetadataQueue> mInjectionResultMetadataQueue;
-
// The flag indicates that the stream configuration is complete, the camera device is
// active, but the injection camera has not yet been injected.
bool mIsStreamConfigCompleteButNotInjected = false;
@@ -1477,6 +1397,10 @@
// The injection camera ID.
String8 mInjectedCamId;
};
+
+ virtual sp<Camera3DeviceInjectionMethods>
+ createCamera3DeviceInjectionMethods(wp<Camera3Device>) = 0;
+
sp<Camera3DeviceInjectionMethods> mInjectionMethods;
}; // class Camera3Device
diff --git a/services/camera/libcameraservice/device3/Camera3DeviceInjectionMethods.cpp b/services/camera/libcameraservice/device3/Camera3DeviceInjectionMethods.cpp
index 4744a6d..6818acf 100644
--- a/services/camera/libcameraservice/device3/Camera3DeviceInjectionMethods.cpp
+++ b/services/camera/libcameraservice/device3/Camera3DeviceInjectionMethods.cpp
@@ -39,92 +39,6 @@
injectionDisconnectImpl();
}
-status_t Camera3Device::Camera3DeviceInjectionMethods::injectionInitialize(
- const String8& injectedCamId, sp<CameraProviderManager> manager,
- const sp<android::hardware::camera::device::V3_2::ICameraDeviceCallback>&
- callback) {
- ATRACE_CALL();
- Mutex::Autolock lock(mInjectionLock);
-
- if (manager == nullptr) {
- ALOGE("%s: manager does not exist!", __FUNCTION__);
- return INVALID_OPERATION;
- }
-
- sp<Camera3Device> parent = mParent.promote();
- if (parent == nullptr) {
- ALOGE("%s: parent does not exist!", __FUNCTION__);
- return INVALID_OPERATION;
- }
-
- mInjectedCamId = injectedCamId;
- sp<ICameraDeviceSession> session;
- ATRACE_BEGIN("Injection CameraHal::openSession");
- status_t res = manager->openSession(injectedCamId.string(), callback,
- /*out*/ &session);
- ATRACE_END();
- if (res != OK) {
- ALOGE("Injection camera could not open camera session: %s (%d)",
- strerror(-res), res);
- return res;
- }
-
- std::shared_ptr<RequestMetadataQueue> queue;
- auto requestQueueRet =
- session->getCaptureRequestMetadataQueue([&queue](const auto& descriptor) {
- queue = std::make_shared<RequestMetadataQueue>(descriptor);
- if (!queue->isValid() || queue->availableToWrite() <= 0) {
- ALOGE("Injection camera HAL returns empty request metadata fmq, not "
- "use it");
- queue = nullptr;
- // don't use the queue onwards.
- }
- });
- if (!requestQueueRet.isOk()) {
- ALOGE("Injection camera transaction error when getting request metadata fmq: "
- "%s, not use it", requestQueueRet.description().c_str());
- return DEAD_OBJECT;
- }
-
- std::unique_ptr<ResultMetadataQueue>& resQueue = mInjectionResultMetadataQueue;
- auto resultQueueRet = session->getCaptureResultMetadataQueue(
- [&resQueue](const auto& descriptor) {
- resQueue = std::make_unique<ResultMetadataQueue>(descriptor);
- if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
- ALOGE("Injection camera HAL returns empty result metadata fmq, not use "
- "it");
- resQueue = nullptr;
- // Don't use the resQueue onwards.
- }
- });
- if (!resultQueueRet.isOk()) {
- ALOGE("Injection camera transaction error when getting result metadata queue "
- "from camera session: %s", resultQueueRet.description().c_str());
- return DEAD_OBJECT;
- }
- IF_ALOGV() {
- session->interfaceChain(
- [](::android::hardware::hidl_vec<::android::hardware::hidl_string>
- interfaceChain) {
- ALOGV("Injection camera session interface chain:");
- for (const auto& iface : interfaceChain) {
- ALOGV(" %s", iface.c_str());
- }
- });
- }
-
- ALOGV("%s: Injection camera interface = new HalInterface()", __FUNCTION__);
- mInjectedCamHalInterface =
- new HalInterface(session, queue, parent->mUseHalBufManager,
- parent->mSupportOfflineProcessing);
- if (mInjectedCamHalInterface == nullptr) {
- ALOGE("%s: mInjectedCamHalInterface does not exist!", __FUNCTION__);
- return DEAD_OBJECT;
- }
-
- return OK;
-}
-
status_t Camera3Device::Camera3DeviceInjectionMethods::injectCamera(
camera3::camera_stream_configuration& injectionConfig,
const std::vector<uint32_t>& injectionBufferSizes) {
@@ -379,37 +293,4 @@
}
}
-status_t Camera3Device::Camera3DeviceInjectionMethods::replaceHalInterface(
- sp<HalInterface> newHalInterface, bool keepBackup) {
- Mutex::Autolock lock(mInjectionLock);
- if (newHalInterface.get() == nullptr) {
- ALOGE("%s: The newHalInterface does not exist, to stop replacing.",
- __FUNCTION__);
- return DEAD_OBJECT;
- }
-
- sp<Camera3Device> parent = mParent.promote();
- if (parent == nullptr) {
- ALOGE("%s: parent does not exist!", __FUNCTION__);
- return INVALID_OPERATION;
- }
-
- if (keepBackup) {
- if (mBackupHalInterface == nullptr) {
- mBackupHalInterface = parent->mInterface;
- }
- if (mBackupResultMetadataQueue == nullptr) {
- mBackupResultMetadataQueue = std::move(parent->mResultMetadataQueue);
- parent->mResultMetadataQueue = std::move(mInjectionResultMetadataQueue);
- }
- } else {
- mBackupHalInterface = nullptr;
- parent->mResultMetadataQueue = std::move(mBackupResultMetadataQueue);
- mBackupResultMetadataQueue = nullptr;
- }
- parent->mInterface = newHalInterface;
-
- return OK;
-}
-
}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3FakeStream.cpp b/services/camera/libcameraservice/device3/Camera3FakeStream.cpp
index 61e43cb..19afd69 100644
--- a/services/camera/libcameraservice/device3/Camera3FakeStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3FakeStream.cpp
@@ -76,7 +76,7 @@
Camera3IOStreamBase::dump(fd, args);
}
-status_t Camera3FakeStream::setTransform(int) {
+status_t Camera3FakeStream::setTransform(int, bool) {
ATRACE_CALL();
// Do nothing
return OK;
diff --git a/services/camera/libcameraservice/device3/Camera3FakeStream.h b/services/camera/libcameraservice/device3/Camera3FakeStream.h
index df19c3d..48e44dc 100644
--- a/services/camera/libcameraservice/device3/Camera3FakeStream.h
+++ b/services/camera/libcameraservice/device3/Camera3FakeStream.h
@@ -52,7 +52,7 @@
virtual void dump(int fd, const Vector<String16> &args) const;
- status_t setTransform(int transform);
+ status_t setTransform(int transform, bool mayChangeMirror);
virtual status_t detachBuffer(sp<GraphicBuffer>* buffer, int* fenceFd);
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
index ba97367..f737ed6 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
@@ -34,11 +34,12 @@
android_dataspace dataSpace, camera_stream_rotation_t rotation,
const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
- int setId, bool isMultiResolution, int dynamicRangeProfile) :
+ int setId, bool isMultiResolution, int dynamicRangeProfile, int streamUseCase,
+ bool deviceTimeBaseIsRealtime, int timestampBase) :
Camera3Stream(id, type,
width, height, maxSize, format, dataSpace, rotation,
physicalCameraId, sensorPixelModesUsed, setId, isMultiResolution,
- dynamicRangeProfile),
+ dynamicRangeProfile, streamUseCase, deviceTimeBaseIsRealtime, timestampBase),
mTotalBufferCount(0),
mHandoutTotalBufferCount(0),
mHandoutOutputBufferCount(0),
@@ -89,6 +90,7 @@
lines.appendFormat(" Physical camera id: %s\n", camera_stream::physical_camera_id);
}
lines.appendFormat(" Dynamic Range Profile: 0x%x", camera_stream::dynamic_range_profile);
+ lines.appendFormat(" Stream use case: %d\n", camera_stream::use_case);
lines.appendFormat(" Frames produced: %d, last timestamp: %" PRId64 " ns\n",
mFrameCount, mLastTimestamp);
lines.appendFormat(" Total buffers: %zu, currently dequeued: %zu\n",
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
index 518ee42..300f207 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
@@ -38,7 +38,10 @@
const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false,
- int dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
+ int dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
+ int streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
+ bool deviceTimeBaseIsRealtime = false,
+ int timestampBase = OutputConfiguration::TIMESTAMP_BASE_DEFAULT);
public:
diff --git a/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp b/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp
index b702e20..7cfa255 100644
--- a/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp
@@ -47,14 +47,12 @@
const camera3::StreamSet& offlineStreamSet,
camera3::BufferRecords&& bufferRecords,
const camera3::InFlightRequestMap& offlineReqs,
- const Camera3OfflineStates& offlineStates,
- sp<hardware::camera::device::V3_6::ICameraOfflineSession> offlineSession) :
+ const Camera3OfflineStates& offlineStates) :
mId(id),
mInputStream(inputStream),
mOutputStreams(offlineStreamSet),
mBufferRecords(std::move(bufferRecords)),
mOfflineReqs(offlineReqs),
- mSession(offlineSession),
mTagMonitor(offlineStates.mTagMonitor),
mVendorTagId(offlineStates.mVendorTagId),
mUseHalBufManager(offlineStates.mUseHalBufManager),
@@ -90,43 +88,6 @@
return mId;
}
-status_t Camera3OfflineSession::initialize(wp<NotificationListener> listener) {
- ATRACE_CALL();
-
- if (mSession == nullptr) {
- ALOGE("%s: HIDL session is null!", __FUNCTION__);
- return DEAD_OBJECT;
- }
-
- {
- std::lock_guard<std::mutex> lock(mLock);
-
- mListener = listener;
-
- // setup result FMQ
- std::unique_ptr<ResultMetadataQueue>& resQueue = mResultMetadataQueue;
- auto resultQueueRet = mSession->getCaptureResultMetadataQueue(
- [&resQueue](const auto& descriptor) {
- resQueue = std::make_unique<ResultMetadataQueue>(descriptor);
- if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
- ALOGE("HAL returns empty result metadata fmq, not use it");
- resQueue = nullptr;
- // Don't use resQueue onwards.
- }
- });
- if (!resultQueueRet.isOk()) {
- ALOGE("Transaction error when getting result metadata queue from camera session: %s",
- resultQueueRet.description().c_str());
- return DEAD_OBJECT;
- }
- mStatus = STATUS_ACTIVE;
- }
-
- mSession->setCallback(this);
-
- return OK;
-}
-
status_t Camera3OfflineSession::dump(int /*fd*/) {
ATRACE_CALL();
std::lock_guard<std::mutex> il(mInterfaceLock);
@@ -135,6 +96,7 @@
status_t Camera3OfflineSession::disconnect() {
ATRACE_CALL();
+ disconnectSession();
return disconnectImpl();
}
@@ -170,10 +132,6 @@
streams.push_back(mInputStream);
}
- if (mSession != nullptr) {
- mSession->close();
- }
-
FlushInflightReqStates states {
mId, mOfflineReqsLock, mOfflineReqs, mUseHalBufManager,
listener, *this, mBufferRecords, *this, mSessionStatsBuilder};
@@ -182,7 +140,6 @@
{
std::lock_guard<std::mutex> lock(mLock);
- mSession.clear();
mOutputStreams.clear();
mInputStream.clear();
mStatus = STATUS_CLOSED;
@@ -235,149 +192,6 @@
return OK;
}
-hardware::Return<void> Camera3OfflineSession::processCaptureResult_3_4(
- const hardware::hidl_vec<
- hardware::camera::device::V3_4::CaptureResult>& results) {
- sp<NotificationListener> listener;
- {
- std::lock_guard<std::mutex> lock(mLock);
- if (mStatus != STATUS_ACTIVE) {
- ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
- return hardware::Void();
- }
- listener = mListener.promote();
- }
-
- CaptureOutputStates states {
- mId,
- mOfflineReqsLock, mLastCompletedRegularFrameNumber,
- mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
- mOfflineReqs, mOutputLock, mResultQueue, mResultSignal,
- mNextShutterFrameNumber,
- mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
- mNextResultFrameNumber,
- mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
- mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
- mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
- mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
- mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- mBufferRecords, /*legacyClient*/ false
- };
-
- std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
- for (const auto& result : results) {
- processOneCaptureResultLocked(states, result.v3_2, result.physicalCameraMetadata);
- }
- return hardware::Void();
-}
-
-hardware::Return<void> Camera3OfflineSession::processCaptureResult(
- const hardware::hidl_vec<
- hardware::camera::device::V3_2::CaptureResult>& results) {
- // TODO: changed impl to call into processCaptureResult_3_4 instead?
- // might need to figure how to reduce copy though.
- sp<NotificationListener> listener;
- {
- std::lock_guard<std::mutex> lock(mLock);
- if (mStatus != STATUS_ACTIVE) {
- ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
- return hardware::Void();
- }
- listener = mListener.promote();
- }
-
- hardware::hidl_vec<hardware::camera::device::V3_4::PhysicalCameraMetadata> noPhysMetadata;
-
- CaptureOutputStates states {
- mId,
- mOfflineReqsLock, mLastCompletedRegularFrameNumber,
- mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
- mOfflineReqs, mOutputLock, mResultQueue, mResultSignal,
- mNextShutterFrameNumber,
- mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
- mNextResultFrameNumber,
- mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
- mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
- mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
- mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
- mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- mBufferRecords, /*legacyClient*/ false
- };
-
- std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
- for (const auto& result : results) {
- processOneCaptureResultLocked(states, result, noPhysMetadata);
- }
- return hardware::Void();
-}
-
-hardware::Return<void> Camera3OfflineSession::notify(
- const hardware::hidl_vec<hardware::camera::device::V3_2::NotifyMsg>& msgs) {
- sp<NotificationListener> listener;
- {
- std::lock_guard<std::mutex> lock(mLock);
- if (mStatus != STATUS_ACTIVE) {
- ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
- return hardware::Void();
- }
- listener = mListener.promote();
- }
-
- CaptureOutputStates states {
- mId,
- mOfflineReqsLock, mLastCompletedRegularFrameNumber,
- mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
- mOfflineReqs, mOutputLock, mResultQueue, mResultSignal,
- mNextShutterFrameNumber,
- mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
- mNextResultFrameNumber,
- mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
- mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
- mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
- mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
- mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- mBufferRecords, /*legacyClient*/ false
- };
- for (const auto& msg : msgs) {
- camera3::notify(states, msg);
- }
- return hardware::Void();
-}
-
-hardware::Return<void> Camera3OfflineSession::requestStreamBuffers(
- const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
- requestStreamBuffers_cb _hidl_cb) {
- {
- std::lock_guard<std::mutex> lock(mLock);
- if (mStatus != STATUS_ACTIVE) {
- ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
- return hardware::Void();
- }
- }
-
- RequestBufferStates states {
- mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder,
- *this, mBufferRecords, *this};
- camera3::requestStreamBuffers(states, bufReqs, _hidl_cb);
- return hardware::Void();
-}
-
-hardware::Return<void> Camera3OfflineSession::returnStreamBuffers(
- const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers) {
- {
- std::lock_guard<std::mutex> lock(mLock);
- if (mStatus != STATUS_ACTIVE) {
- ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
- return hardware::Void();
- }
- }
-
- ReturnBufferStates states {
- mId, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder, mBufferRecords};
- camera3::returnStreamBuffers(states, buffers);
- return hardware::Void();
-}
-
void Camera3OfflineSession::setErrorState(const char *fmt, ...) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mLock);
diff --git a/services/camera/libcameraservice/device3/Camera3OfflineSession.h b/services/camera/libcameraservice/device3/Camera3OfflineSession.h
index 5581964..0f7d145 100644
--- a/services/camera/libcameraservice/device3/Camera3OfflineSession.h
+++ b/services/camera/libcameraservice/device3/Camera3OfflineSession.h
@@ -131,7 +131,6 @@
*/
class Camera3OfflineSession :
public CameraOfflineSessionBase,
- virtual public hardware::camera::device::V3_5::ICameraDeviceCallback,
public camera3::SetErrorInterface,
public camera3::InflightRequestUpdateInterface,
public camera3::RequestBufferInterface,
@@ -144,12 +143,11 @@
const camera3::StreamSet& offlineStreamSet,
camera3::BufferRecords&& bufferRecords,
const camera3::InFlightRequestMap& offlineReqs,
- const Camera3OfflineStates& offlineStates,
- sp<hardware::camera::device::V3_6::ICameraOfflineSession> offlineSession);
+ const Camera3OfflineStates& offlineStates);
virtual ~Camera3OfflineSession();
- virtual status_t initialize(wp<NotificationListener> listener) override;
+ virtual status_t initialize(wp<NotificationListener> /*listener*/) = 0;
/**
* CameraOfflineSessionBase interface
@@ -171,38 +169,7 @@
* End of CameraOfflineSessionBase interface
*/
- /**
- * HIDL ICameraDeviceCallback interface
- */
-
- /**
- * Implementation of android::hardware::camera::device::V3_5::ICameraDeviceCallback
- */
-
- hardware::Return<void> processCaptureResult_3_4(
- const hardware::hidl_vec<
- hardware::camera::device::V3_4::CaptureResult>& results) override;
- hardware::Return<void> processCaptureResult(
- const hardware::hidl_vec<
- hardware::camera::device::V3_2::CaptureResult>& results) override;
- hardware::Return<void> notify(
- const hardware::hidl_vec<
- hardware::camera::device::V3_2::NotifyMsg>& msgs) override;
-
- hardware::Return<void> requestStreamBuffers(
- const hardware::hidl_vec<
- hardware::camera::device::V3_5::BufferRequest>& bufReqs,
- requestStreamBuffers_cb _hidl_cb) override;
-
- hardware::Return<void> returnStreamBuffers(
- const hardware::hidl_vec<
- hardware::camera::device::V3_2::StreamBuffer>& buffers) override;
-
- /**
- * End of CameraOfflineSessionBase interface
- */
-
- private:
+ protected:
// Camera device ID
const String8 mId;
sp<camera3::Camera3Stream> mInputStream;
@@ -213,8 +180,6 @@
std::mutex mOfflineReqsLock;
camera3::InFlightRequestMap mOfflineReqs;
- sp<hardware::camera::device::V3_6::ICameraOfflineSession> mSession;
-
TagMonitor mTagMonitor;
const metadata_vendor_id_t mVendorTagId;
@@ -269,8 +234,6 @@
// End of mLock protect scope
std::mutex mProcessCaptureResultLock;
- // FMQ to write result on. Must be guarded by mProcessCaptureResultLock.
- std::unique_ptr<ResultMetadataQueue> mResultMetadataQueue;
// Tracking cause of fatal errors when in STATUS_ERROR
String8 mErrorCause;
@@ -305,6 +268,8 @@
void setErrorStateLockedV(const char *fmt, va_list args);
status_t disconnectImpl();
+ virtual void disconnectSession() = 0;
+
}; // class Camera3OfflineSession
}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 69723b6..9574309 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -46,11 +46,14 @@
android_dataspace dataSpace, camera_stream_rotation_t rotation,
nsecs_t timestampOffset, const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
- int setId, bool isMultiResolution, int dynamicRangeProfile) :
+ int setId, bool isMultiResolution, int dynamicRangeProfile,
+ int streamUseCase, bool deviceTimeBaseIsRealtime, int timestampBase,
+ int mirrorMode) :
Camera3IOStreamBase(id, CAMERA_STREAM_OUTPUT, width, height,
/*maxSize*/0, format, dataSpace, rotation,
physicalCameraId, sensorPixelModesUsed, setId, isMultiResolution,
- dynamicRangeProfile),
+ dynamicRangeProfile, streamUseCase, deviceTimeBaseIsRealtime,
+ timestampBase),
mConsumer(consumer),
mTransform(0),
mTraceFirstBuffer(true),
@@ -58,6 +61,7 @@
mTimestampOffset(timestampOffset),
mConsumerUsage(0),
mDropBuffers(false),
+ mMirrorMode(mirrorMode),
mDequeueBufferLatency(kDequeueLatencyBinSize) {
if (mConsumer == NULL) {
@@ -75,18 +79,21 @@
android_dataspace dataSpace, camera_stream_rotation_t rotation,
nsecs_t timestampOffset, const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
- int setId, bool isMultiResolution, int dynamicRangeProfile) :
+ int setId, bool isMultiResolution, int dynamicRangeProfile,
+ int streamUseCase, bool deviceTimeBaseIsRealtime, int timestampBase,
+ int mirrorMode) :
Camera3IOStreamBase(id, CAMERA_STREAM_OUTPUT, width, height, maxSize,
format, dataSpace, rotation, physicalCameraId, sensorPixelModesUsed,
- setId, isMultiResolution, dynamicRangeProfile),
+ setId, isMultiResolution, dynamicRangeProfile, streamUseCase,
+ deviceTimeBaseIsRealtime, timestampBase),
mConsumer(consumer),
mTransform(0),
mTraceFirstBuffer(true),
- mUseMonoTimestamp(false),
mUseBufferManager(false),
mTimestampOffset(timestampOffset),
mConsumerUsage(0),
mDropBuffers(false),
+ mMirrorMode(mirrorMode),
mDequeueBufferLatency(kDequeueLatencyBinSize) {
if (format != HAL_PIXEL_FORMAT_BLOB && format != HAL_PIXEL_FORMAT_RAW_OPAQUE) {
@@ -110,11 +117,14 @@
camera_stream_rotation_t rotation, nsecs_t timestampOffset,
const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
- int setId, bool isMultiResolution, int dynamicRangeProfile) :
+ int setId, bool isMultiResolution, int dynamicRangeProfile,
+ int streamUseCase, bool deviceTimeBaseIsRealtime, int timestampBase,
+ int mirrorMode) :
Camera3IOStreamBase(id, CAMERA_STREAM_OUTPUT, width, height,
/*maxSize*/0, format, dataSpace, rotation,
physicalCameraId, sensorPixelModesUsed, setId, isMultiResolution,
- dynamicRangeProfile),
+ dynamicRangeProfile, streamUseCase, deviceTimeBaseIsRealtime,
+ timestampBase),
mConsumer(nullptr),
mTransform(0),
mTraceFirstBuffer(true),
@@ -122,6 +132,7 @@
mTimestampOffset(timestampOffset),
mConsumerUsage(consumerUsage),
mDropBuffers(false),
+ mMirrorMode(mirrorMode),
mDequeueBufferLatency(kDequeueLatencyBinSize) {
// Deferred consumer only support preview surface format now.
if (format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
@@ -149,22 +160,25 @@
android_dataspace dataSpace,
camera_stream_rotation_t rotation,
const String8& physicalCameraId,
- const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
uint64_t consumerUsage, nsecs_t timestampOffset,
int setId, bool isMultiResolution,
- int dynamicRangeProfile) :
+ int dynamicRangeProfile, int streamUseCase,
+ bool deviceTimeBaseIsRealtime, int timestampBase,
+ int mirrorMode) :
Camera3IOStreamBase(id, type, width, height,
/*maxSize*/0,
format, dataSpace, rotation,
physicalCameraId, sensorPixelModesUsed, setId, isMultiResolution,
- dynamicRangeProfile),
+ dynamicRangeProfile, streamUseCase, deviceTimeBaseIsRealtime,
+ timestampBase),
mTransform(0),
mTraceFirstBuffer(true),
- mUseMonoTimestamp(false),
mUseBufferManager(false),
mTimestampOffset(timestampOffset),
mConsumerUsage(consumerUsage),
mDropBuffers(false),
+ mMirrorMode(mirrorMode),
mDequeueBufferLatency(kDequeueLatencyBinSize) {
bool needsReleaseNotify = setId > CAMERA3_STREAM_SET_ID_INVALID;
@@ -362,13 +376,10 @@
dumpImageToDisk(timestamp, anwBuffer, anwReleaseFence);
}
- /* Certain consumers (such as AudioSource or HardwareComposer) use
- * MONOTONIC time, causing time misalignment if camera timestamp is
- * in BOOTTIME. Do the conversion if necessary. */
nsecs_t t = mPreviewFrameScheduler != nullptr ? readoutTimestamp : timestamp;
- nsecs_t adjustedTs = mUseMonoTimestamp ? t - mTimestampOffset : t;
+ t -= mTimestampOffset;
if (mPreviewFrameScheduler != nullptr) {
- res = mPreviewFrameScheduler->queuePreviewBuffer(adjustedTs, transform,
+ res = mPreviewFrameScheduler->queuePreviewBuffer(t, transform,
anwBuffer, anwReleaseFence);
if (res != OK) {
ALOGE("%s: Stream %d: Error queuing buffer to preview buffer scheduler: %s (%d)",
@@ -376,8 +387,8 @@
return res;
}
} else {
- setTransform(transform);
- res = native_window_set_buffers_timestamp(mConsumer.get(), adjustedTs);
+ setTransform(transform, true/*mayChangeMirror*/);
+ res = native_window_set_buffers_timestamp(mConsumer.get(), t);
if (res != OK) {
ALOGE("%s: Stream %d: Error setting timestamp: %s (%d)",
__FUNCTION__, mId, strerror(-res), res);
@@ -423,9 +434,15 @@
" DequeueBuffer latency histogram:");
}
-status_t Camera3OutputStream::setTransform(int transform) {
+status_t Camera3OutputStream::setTransform(int transform, bool mayChangeMirror) {
ATRACE_CALL();
Mutex::Autolock l(mLock);
+ if (mMirrorMode != OutputConfiguration::MIRROR_MODE_AUTO && mayChangeMirror) {
+ // If the mirroring mode is not AUTO, do not allow transform update
+ // which may change mirror.
+ return OK;
+ }
+
return setTransformLocked(transform);
}
@@ -569,10 +586,18 @@
}
mTotalBufferCount = maxConsumerBuffers + camera_stream::max_buffers;
- if (allowPreviewScheduler && isConsumedByHWComposer()) {
+
+ int timestampBase = getTimestampBase();
+ bool isDefaultTimeBase = (timestampBase ==
+ OutputConfiguration::TIMESTAMP_BASE_DEFAULT);
+ if (allowPreviewScheduler) {
// We cannot distinguish between a SurfaceView and an ImageReader of
// preview buffer format. The PreviewFrameScheduler needs to handle both.
- if (!property_get_bool("camera.disable_preview_scheduler", false)) {
+ bool forceChoreographer = (timestampBase ==
+ OutputConfiguration::TIMESTAMP_BASE_CHOREOGRAPHER_SYNCED);
+ bool defaultToChoreographer = (isDefaultTimeBase && isConsumedByHWComposer() &&
+ !property_get_bool("camera.disable_preview_scheduler", false));
+ if (forceChoreographer || defaultToChoreographer) {
mPreviewFrameScheduler = std::make_unique<PreviewFrameScheduler>(*this, mConsumer);
mTotalBufferCount += PreviewFrameScheduler::kQueueDepthWatermark;
}
@@ -581,7 +606,27 @@
mHandoutTotalBufferCount = 0;
mFrameCount = 0;
mLastTimestamp = 0;
- mUseMonoTimestamp = (isConsumedByHWComposer() | isVideoStream());
+
+ if (isDeviceTimeBaseRealtime()) {
+ if (isDefaultTimeBase && !isConsumedByHWComposer() && !isVideoStream()) {
+ // Default time base, but not hardware composer or video encoder
+ mTimestampOffset = 0;
+ } else if (timestampBase == OutputConfiguration::TIMESTAMP_BASE_REALTIME ||
+ timestampBase == OutputConfiguration::TIMESTAMP_BASE_SENSOR) {
+ mTimestampOffset = 0;
+ }
+ // If timestampBase is CHOREOGRAPHER SYNCED or MONOTONIC, leave
+ // timestamp offset as bootTime - monotonicTime.
+ } else {
+ if (timestampBase == OutputConfiguration::TIMESTAMP_BASE_REALTIME) {
+ // Reverse offset for monotonicTime -> bootTime
+ mTimestampOffset = -mTimestampOffset;
+ } else {
+ // If timestampBase is DEFAULT, MONOTONIC, SENSOR, or
+ // CHOREOGRAPHER_SYNCED, timestamp offset is 0.
+ mTimestampOffset = 0;
+ }
+ }
res = native_window_set_buffer_count(mConsumer.get(),
mTotalBufferCount);
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index d9bf62a..80901d6 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -90,7 +90,11 @@
nsecs_t timestampOffset, const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false,
- int dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
+ int dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
+ int streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
+ bool deviceTimeBaseIsRealtime = false,
+ int timestampBase = OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
+ int mirrorMode = OutputConfiguration::MIRROR_MODE_AUTO);
/**
* Set up a stream for formats that have a variable buffer size for the same
* dimensions, such as compressed JPEG.
@@ -103,7 +107,11 @@
nsecs_t timestampOffset, const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false,
- int dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
+ int dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
+ int streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
+ bool deviceTimeBaseIsRealtime = false,
+ int timestampBase = OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
+ int mirrorMode = OutputConfiguration::MIRROR_MODE_AUTO);
/**
* Set up a stream with deferred consumer for formats that have 2 dimensions, such as
* RAW and YUV. The consumer must be set before using this stream for output. A valid
@@ -115,7 +123,11 @@
const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false,
- int dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
+ int dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
+ int streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
+ bool deviceTimeBaseIsRealtime = false,
+ int timestampBase = OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
+ int mirrorMode = OutputConfiguration::MIRROR_MODE_AUTO);
virtual ~Camera3OutputStream();
@@ -129,7 +141,7 @@
* Set the transform on the output stream; one of the
* HAL_TRANSFORM_* / NATIVE_WINDOW_TRANSFORM_* constants.
*/
- status_t setTransform(int transform);
+ status_t setTransform(int transform, bool mayChangeMirror);
/**
* Return if this output stream is for video encoding.
@@ -243,7 +255,11 @@
const std::unordered_set<int32_t> &sensorPixelModesUsed,
uint64_t consumerUsage = 0, nsecs_t timestampOffset = 0,
int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false,
- int dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
+ int dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
+ int streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
+ bool deviceTimeBaseIsRealtime = false,
+ int timestampBase = OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
+ int mirrorMode = OutputConfiguration::MIRROR_MODE_AUTO);
/**
* Note that we release the lock briefly in this function
@@ -285,9 +301,6 @@
// Name of Surface consumer
String8 mConsumerName;
- // Whether consumer assumes MONOTONIC timestamp
- bool mUseMonoTimestamp;
-
/**
* GraphicBuffer manager this stream is registered to. Used to replace the buffer
* allocation/deallocation role of BufferQueue.
@@ -306,7 +319,11 @@
bool mUseBufferManager;
/**
- * Timestamp offset for video and hardware composer consumed streams
+ * Offset used to override camera HAL produced timestamps
+ *
+ * The offset is first initialized to bootTime - monotonicTime in
+ * constructor, and may later be updated based on the client's timestampBase
+ * setting.
*/
nsecs_t mTimestampOffset;
@@ -330,6 +347,8 @@
std::vector<Surface::BatchBuffer> mBatchedBuffers;
// ---- End of mBatchLock protected scope ----
+ const int mMirrorMode;
+
/**
* Internal Camera3Stream interface
*/
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
index 49f9f62..e44e795 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
@@ -34,7 +34,7 @@
* Set the transform on the output stream; one of the
* HAL_TRANSFORM_* / NATIVE_WINDOW_TRANSFORM_* constants.
*/
- virtual status_t setTransform(int transform) = 0;
+ virtual status_t setTransform(int transform, bool mayChangeMirror) = 0;
/**
* Return if this output stream is for video encoding.
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
index 24f81f3..ab25322 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
@@ -376,43 +376,6 @@
insertResultLocked(states, &captureResult, frameNumber);
}
-// Reading one camera metadata from result argument via fmq or from the result
-// Assuming the fmq is protected by a lock already
-status_t readOneCameraMetadataLocked(
- std::unique_ptr<ResultMetadataQueue>& fmq,
- uint64_t fmqResultSize,
- hardware::camera::device::V3_2::CameraMetadata& resultMetadata,
- const hardware::camera::device::V3_2::CameraMetadata& result) {
- if (fmqResultSize > 0) {
- resultMetadata.resize(fmqResultSize);
- if (fmq == nullptr) {
- return NO_MEMORY; // logged in initialize()
- }
- if (!fmq->read(resultMetadata.data(), fmqResultSize)) {
- ALOGE("%s: Cannot read camera metadata from fmq, size = %" PRIu64,
- __FUNCTION__, fmqResultSize);
- return INVALID_OPERATION;
- }
- } else {
- resultMetadata.setToExternal(const_cast<uint8_t *>(result.data()),
- result.size());
- }
-
- if (resultMetadata.size() != 0) {
- status_t res;
- const camera_metadata_t* metadata =
- reinterpret_cast<const camera_metadata_t*>(resultMetadata.data());
- size_t expected_metadata_size = resultMetadata.size();
- if ((res = validate_camera_metadata_structure(metadata, &expected_metadata_size)) != OK) {
- ALOGE("%s: Invalid camera metadata received by camera service from HAL: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return INVALID_OPERATION;
- }
- }
-
- return OK;
-}
-
void removeInFlightMapEntryLocked(CaptureOutputStates& states, int idx) {
ATRACE_CALL();
InFlightRequestMap& inflightMap = states.inflightMap;
@@ -569,7 +532,7 @@
auto orientation = deviceInfo->second.find(ANDROID_SENSOR_ORIENTATION);
if (orientation.count > 0) {
ret = CameraUtils::getRotationTransform(deviceInfo->second,
- &request.transform);
+ OutputConfiguration::MIRROR_MODE_AUTO, &request.transform);
if (ret != OK) {
ALOGE("%s: Failed to calculate current stream transformation: %s (%d)",
__FUNCTION__, strerror(-ret), ret);
@@ -719,153 +682,6 @@
}
}
-void processOneCaptureResultLocked(
- CaptureOutputStates& states,
- const hardware::camera::device::V3_2::CaptureResult& result,
- const hardware::hidl_vec<
- hardware::camera::device::V3_4::PhysicalCameraMetadata> physicalCameraMetadata) {
- using hardware::camera::device::V3_2::StreamBuffer;
- using hardware::camera::device::V3_2::BufferStatus;
- std::unique_ptr<ResultMetadataQueue>& fmq = states.fmq;
- BufferRecordsInterface& bufferRecords = states.bufferRecordsIntf;
- camera_capture_result r;
- status_t res;
- r.frame_number = result.frameNumber;
-
- // Read and validate the result metadata.
- hardware::camera::device::V3_2::CameraMetadata resultMetadata;
- res = readOneCameraMetadataLocked(
- fmq, result.fmqResultSize,
- resultMetadata, result.result);
- if (res != OK) {
- ALOGE("%s: Frame %d: Failed to read capture result metadata",
- __FUNCTION__, result.frameNumber);
- return;
- }
- r.result = reinterpret_cast<const camera_metadata_t*>(resultMetadata.data());
-
- // Read and validate physical camera metadata
- size_t physResultCount = physicalCameraMetadata.size();
- std::vector<const char*> physCamIds(physResultCount);
- std::vector<const camera_metadata_t *> phyCamMetadatas(physResultCount);
- std::vector<hardware::camera::device::V3_2::CameraMetadata> physResultMetadata;
- physResultMetadata.resize(physResultCount);
- for (size_t i = 0; i < physicalCameraMetadata.size(); i++) {
- res = readOneCameraMetadataLocked(fmq, physicalCameraMetadata[i].fmqMetadataSize,
- physResultMetadata[i], physicalCameraMetadata[i].metadata);
- if (res != OK) {
- ALOGE("%s: Frame %d: Failed to read capture result metadata for camera %s",
- __FUNCTION__, result.frameNumber,
- physicalCameraMetadata[i].physicalCameraId.c_str());
- return;
- }
- physCamIds[i] = physicalCameraMetadata[i].physicalCameraId.c_str();
- phyCamMetadatas[i] = reinterpret_cast<const camera_metadata_t*>(
- physResultMetadata[i].data());
- }
- r.num_physcam_metadata = physResultCount;
- r.physcam_ids = physCamIds.data();
- r.physcam_metadata = phyCamMetadatas.data();
-
- std::vector<camera_stream_buffer_t> outputBuffers(result.outputBuffers.size());
- std::vector<buffer_handle_t> outputBufferHandles(result.outputBuffers.size());
- for (size_t i = 0; i < result.outputBuffers.size(); i++) {
- auto& bDst = outputBuffers[i];
- const StreamBuffer &bSrc = result.outputBuffers[i];
-
- sp<Camera3StreamInterface> stream = states.outputStreams.get(bSrc.streamId);
- if (stream == nullptr) {
- ALOGE("%s: Frame %d: Buffer %zu: Invalid output stream id %d",
- __FUNCTION__, result.frameNumber, i, bSrc.streamId);
- return;
- }
- bDst.stream = stream->asHalStream();
-
- bool noBufferReturned = false;
- buffer_handle_t *buffer = nullptr;
- if (states.useHalBufManager) {
- // This is suspicious most of the time but can be correct during flush where HAL
- // has to return capture result before a buffer is requested
- if (bSrc.bufferId == BUFFER_ID_NO_BUFFER) {
- if (bSrc.status == BufferStatus::OK) {
- ALOGE("%s: Frame %d: Buffer %zu: No bufferId for stream %d",
- __FUNCTION__, result.frameNumber, i, bSrc.streamId);
- // Still proceeds so other buffers can be returned
- }
- noBufferReturned = true;
- }
- if (noBufferReturned) {
- res = OK;
- } else {
- res = bufferRecords.popInflightRequestBuffer(bSrc.bufferId, &buffer);
- }
- } else {
- res = bufferRecords.popInflightBuffer(result.frameNumber, bSrc.streamId, &buffer);
- }
-
- if (res != OK) {
- ALOGE("%s: Frame %d: Buffer %zu: No in-flight buffer for stream %d",
- __FUNCTION__, result.frameNumber, i, bSrc.streamId);
- return;
- }
-
- bDst.buffer = buffer;
- bDst.status = mapHidlBufferStatus(bSrc.status);
- bDst.acquire_fence = -1;
- if (bSrc.releaseFence == nullptr) {
- bDst.release_fence = -1;
- } else if (bSrc.releaseFence->numFds == 1) {
- if (noBufferReturned) {
- ALOGE("%s: got releaseFence without output buffer!", __FUNCTION__);
- }
- bDst.release_fence = dup(bSrc.releaseFence->data[0]);
- } else {
- ALOGE("%s: Frame %d: Invalid release fence for buffer %zu, fd count is %d, not 1",
- __FUNCTION__, result.frameNumber, i, bSrc.releaseFence->numFds);
- return;
- }
- }
- r.num_output_buffers = outputBuffers.size();
- r.output_buffers = outputBuffers.data();
-
- camera_stream_buffer_t inputBuffer;
- if (result.inputBuffer.streamId == -1) {
- r.input_buffer = nullptr;
- } else {
- if (states.inputStream->getId() != result.inputBuffer.streamId) {
- ALOGE("%s: Frame %d: Invalid input stream id %d", __FUNCTION__,
- result.frameNumber, result.inputBuffer.streamId);
- return;
- }
- inputBuffer.stream = states.inputStream->asHalStream();
- buffer_handle_t *buffer;
- res = bufferRecords.popInflightBuffer(result.frameNumber, result.inputBuffer.streamId,
- &buffer);
- if (res != OK) {
- ALOGE("%s: Frame %d: Input buffer: No in-flight buffer for stream %d",
- __FUNCTION__, result.frameNumber, result.inputBuffer.streamId);
- return;
- }
- inputBuffer.buffer = buffer;
- inputBuffer.status = mapHidlBufferStatus(result.inputBuffer.status);
- inputBuffer.acquire_fence = -1;
- if (result.inputBuffer.releaseFence == nullptr) {
- inputBuffer.release_fence = -1;
- } else if (result.inputBuffer.releaseFence->numFds == 1) {
- inputBuffer.release_fence = dup(result.inputBuffer.releaseFence->data[0]);
- } else {
- ALOGE("%s: Frame %d: Invalid release fence for input buffer, fd count is %d, not 1",
- __FUNCTION__, result.frameNumber, result.inputBuffer.releaseFence->numFds);
- return;
- }
- r.input_buffer = &inputBuffer;
- }
-
- r.partial_result = result.partialResult;
-
- processCaptureResult(states, &r);
-}
-
void returnOutputBuffers(
bool useHalBufManager,
sp<NotificationListener> listener,
@@ -1194,330 +1010,6 @@
}
}
-void notify(CaptureOutputStates& states,
- const hardware::camera::device::V3_8::NotifyMsg& msg) {
- using android::hardware::camera::device::V3_2::MsgType;
-
- hardware::camera::device::V3_2::NotifyMsg msg_3_2;
- msg_3_2.type = msg.type;
- bool hasReadoutTime = false;
- uint64_t readoutTime = 0;
- switch (msg.type) {
- case MsgType::ERROR:
- msg_3_2.msg.error = msg.msg.error;
- break;
- case MsgType::SHUTTER:
- msg_3_2.msg.shutter = msg.msg.shutter.v3_2;
- hasReadoutTime = true;
- readoutTime = msg.msg.shutter.readoutTimestamp;
- break;
- }
- notify(states, msg_3_2, hasReadoutTime, readoutTime);
-}
-
-void notify(CaptureOutputStates& states,
- const hardware::camera::device::V3_2::NotifyMsg& msg,
- bool hasReadoutTime, uint64_t readoutTime) {
-
- using android::hardware::camera::device::V3_2::MsgType;
- using android::hardware::camera::device::V3_2::ErrorCode;
-
- ATRACE_CALL();
- camera_notify_msg m;
- switch (msg.type) {
- case MsgType::ERROR:
- m.type = CAMERA_MSG_ERROR;
- m.message.error.frame_number = msg.msg.error.frameNumber;
- if (msg.msg.error.errorStreamId >= 0) {
- sp<Camera3StreamInterface> stream =
- states.outputStreams.get(msg.msg.error.errorStreamId);
- if (stream == nullptr) {
- ALOGE("%s: Frame %d: Invalid error stream id %d", __FUNCTION__,
- m.message.error.frame_number, msg.msg.error.errorStreamId);
- return;
- }
- m.message.error.error_stream = stream->asHalStream();
- } else {
- m.message.error.error_stream = nullptr;
- }
- switch (msg.msg.error.errorCode) {
- case ErrorCode::ERROR_DEVICE:
- m.message.error.error_code = CAMERA_MSG_ERROR_DEVICE;
- break;
- case ErrorCode::ERROR_REQUEST:
- m.message.error.error_code = CAMERA_MSG_ERROR_REQUEST;
- break;
- case ErrorCode::ERROR_RESULT:
- m.message.error.error_code = CAMERA_MSG_ERROR_RESULT;
- break;
- case ErrorCode::ERROR_BUFFER:
- m.message.error.error_code = CAMERA_MSG_ERROR_BUFFER;
- break;
- }
- break;
- case MsgType::SHUTTER:
- m.type = CAMERA_MSG_SHUTTER;
- m.message.shutter.frame_number = msg.msg.shutter.frameNumber;
- m.message.shutter.timestamp = msg.msg.shutter.timestamp;
- m.message.shutter.readout_timestamp = hasReadoutTime ?
- readoutTime : m.message.shutter.timestamp;
- break;
- }
- notify(states, &m);
-}
-
-// The buffers requested through this call are not tied to any CaptureRequest in
-// particular. They may used by the hal for a particular frame's output buffer
-// or for its internal use as well. In the case that the hal does use any buffer
-// from the requested list here, for a particular frame's output buffer, the
-// buffer will be returned with the processCaptureResult call corresponding to
-// the frame. The other buffers will be returned through returnStreamBuffers.
-// The buffers returned via returnStreamBuffers will not have a valid
-// timestamp(0) and will be dropped by the bufferqueue.
-void requestStreamBuffers(RequestBufferStates& states,
- const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
- hardware::camera::device::V3_5::ICameraDeviceCallback::requestStreamBuffers_cb _hidl_cb) {
- using android::hardware::camera::device::V3_2::BufferStatus;
- using android::hardware::camera::device::V3_2::StreamBuffer;
- using android::hardware::camera::device::V3_5::BufferRequestStatus;
- using android::hardware::camera::device::V3_5::StreamBufferRet;
- using android::hardware::camera::device::V3_5::StreamBufferRequestError;
-
- std::lock_guard<std::mutex> lock(states.reqBufferLock);
-
- hardware::hidl_vec<StreamBufferRet> bufRets;
- if (!states.useHalBufManager) {
- ALOGE("%s: Camera %s does not support HAL buffer management",
- __FUNCTION__, states.cameraId.string());
- _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
- return;
- }
-
- SortedVector<int32_t> streamIds;
- ssize_t sz = streamIds.setCapacity(bufReqs.size());
- if (sz < 0 || static_cast<size_t>(sz) != bufReqs.size()) {
- ALOGE("%s: failed to allocate memory for %zu buffer requests",
- __FUNCTION__, bufReqs.size());
- _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
- return;
- }
-
- if (bufReqs.size() > states.outputStreams.size()) {
- ALOGE("%s: too many buffer requests (%zu > # of output streams %zu)",
- __FUNCTION__, bufReqs.size(), states.outputStreams.size());
- _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
- return;
- }
-
- // Check for repeated streamId
- for (const auto& bufReq : bufReqs) {
- if (streamIds.indexOf(bufReq.streamId) != NAME_NOT_FOUND) {
- ALOGE("%s: Stream %d appear multiple times in buffer requests",
- __FUNCTION__, bufReq.streamId);
- _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
- return;
- }
- streamIds.add(bufReq.streamId);
- }
-
- if (!states.reqBufferIntf.startRequestBuffer()) {
- ALOGE("%s: request buffer disallowed while camera service is configuring",
- __FUNCTION__);
- _hidl_cb(BufferRequestStatus::FAILED_CONFIGURING, bufRets);
- return;
- }
-
- bufRets.resize(bufReqs.size());
-
- bool allReqsSucceeds = true;
- bool oneReqSucceeds = false;
- for (size_t i = 0; i < bufReqs.size(); i++) {
- const auto& bufReq = bufReqs[i];
- auto& bufRet = bufRets[i];
- int32_t streamId = bufReq.streamId;
- sp<Camera3OutputStreamInterface> outputStream = states.outputStreams.get(streamId);
- if (outputStream == nullptr) {
- ALOGE("%s: Output stream id %d not found!", __FUNCTION__, streamId);
- hardware::hidl_vec<StreamBufferRet> emptyBufRets;
- _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, emptyBufRets);
- states.reqBufferIntf.endRequestBuffer();
- return;
- }
-
- bufRet.streamId = streamId;
- if (outputStream->isAbandoned()) {
- bufRet.val.error(StreamBufferRequestError::STREAM_DISCONNECTED);
- allReqsSucceeds = false;
- continue;
- }
-
- size_t handOutBufferCount = outputStream->getOutstandingBuffersCount();
- uint32_t numBuffersRequested = bufReq.numBuffersRequested;
- size_t totalHandout = handOutBufferCount + numBuffersRequested;
- uint32_t maxBuffers = outputStream->asHalStream()->max_buffers;
- if (totalHandout > maxBuffers) {
- // Not able to allocate enough buffer. Exit early for this stream
- ALOGE("%s: request too much buffers for stream %d: at HAL: %zu + requesting: %d"
- " > max: %d", __FUNCTION__, streamId, handOutBufferCount,
- numBuffersRequested, maxBuffers);
- bufRet.val.error(StreamBufferRequestError::MAX_BUFFER_EXCEEDED);
- allReqsSucceeds = false;
- continue;
- }
-
- hardware::hidl_vec<StreamBuffer> tmpRetBuffers(numBuffersRequested);
- bool currentReqSucceeds = true;
- std::vector<camera_stream_buffer_t> streamBuffers(numBuffersRequested);
- std::vector<buffer_handle_t> newBuffers;
- size_t numAllocatedBuffers = 0;
- size_t numPushedInflightBuffers = 0;
- for (size_t b = 0; b < numBuffersRequested; b++) {
- camera_stream_buffer_t& sb = streamBuffers[b];
- // Since this method can run concurrently with request thread
- // We need to update the wait duration everytime we call getbuffer
- nsecs_t waitDuration = states.reqBufferIntf.getWaitDuration();
- status_t res = outputStream->getBuffer(&sb, waitDuration);
- if (res != OK) {
- if (res == NO_INIT || res == DEAD_OBJECT) {
- ALOGV("%s: Can't get output buffer for stream %d: %s (%d)",
- __FUNCTION__, streamId, strerror(-res), res);
- bufRet.val.error(StreamBufferRequestError::STREAM_DISCONNECTED);
- states.sessionStatsBuilder.stopCounter(streamId);
- } else {
- ALOGE("%s: Can't get output buffer for stream %d: %s (%d)",
- __FUNCTION__, streamId, strerror(-res), res);
- if (res == TIMED_OUT || res == NO_MEMORY) {
- bufRet.val.error(StreamBufferRequestError::NO_BUFFER_AVAILABLE);
- } else {
- bufRet.val.error(StreamBufferRequestError::UNKNOWN_ERROR);
- }
- }
- currentReqSucceeds = false;
- break;
- }
- numAllocatedBuffers++;
-
- buffer_handle_t *buffer = sb.buffer;
- auto pair = states.bufferRecordsIntf.getBufferId(*buffer, streamId);
- bool isNewBuffer = pair.first;
- uint64_t bufferId = pair.second;
- StreamBuffer& hBuf = tmpRetBuffers[b];
-
- hBuf.streamId = streamId;
- hBuf.bufferId = bufferId;
- hBuf.buffer = (isNewBuffer) ? *buffer : nullptr;
- hBuf.status = BufferStatus::OK;
- hBuf.releaseFence = nullptr;
- if (isNewBuffer) {
- newBuffers.push_back(*buffer);
- }
-
- native_handle_t *acquireFence = nullptr;
- if (sb.acquire_fence != -1) {
- acquireFence = native_handle_create(1,0);
- acquireFence->data[0] = sb.acquire_fence;
- }
- hBuf.acquireFence.setTo(acquireFence, /*shouldOwn*/true);
- hBuf.releaseFence = nullptr;
-
- res = states.bufferRecordsIntf.pushInflightRequestBuffer(bufferId, buffer, streamId);
- if (res != OK) {
- ALOGE("%s: Can't get register request buffers for stream %d: %s (%d)",
- __FUNCTION__, streamId, strerror(-res), res);
- bufRet.val.error(StreamBufferRequestError::UNKNOWN_ERROR);
- currentReqSucceeds = false;
- break;
- }
- numPushedInflightBuffers++;
- }
- if (currentReqSucceeds) {
- bufRet.val.buffers(std::move(tmpRetBuffers));
- oneReqSucceeds = true;
- } else {
- allReqsSucceeds = false;
- for (size_t b = 0; b < numPushedInflightBuffers; b++) {
- StreamBuffer& hBuf = tmpRetBuffers[b];
- buffer_handle_t* buffer;
- status_t res = states.bufferRecordsIntf.popInflightRequestBuffer(
- hBuf.bufferId, &buffer);
- if (res != OK) {
- SET_ERR("%s: popInflightRequestBuffer failed for stream %d: %s (%d)",
- __FUNCTION__, streamId, strerror(-res), res);
- }
- }
- for (size_t b = 0; b < numAllocatedBuffers; b++) {
- camera_stream_buffer_t& sb = streamBuffers[b];
- sb.acquire_fence = -1;
- sb.status = CAMERA_BUFFER_STATUS_ERROR;
- }
- returnOutputBuffers(states.useHalBufManager, /*listener*/nullptr,
- streamBuffers.data(), numAllocatedBuffers, /*timestamp*/0,
- /*readoutTimestamp*/0, /*requested*/false,
- /*requestTimeNs*/0, states.sessionStatsBuilder);
- for (auto buf : newBuffers) {
- states.bufferRecordsIntf.removeOneBufferCache(streamId, buf);
- }
- }
- }
-
- _hidl_cb(allReqsSucceeds ? BufferRequestStatus::OK :
- oneReqSucceeds ? BufferRequestStatus::FAILED_PARTIAL :
- BufferRequestStatus::FAILED_UNKNOWN,
- bufRets);
- states.reqBufferIntf.endRequestBuffer();
-}
-
-void returnStreamBuffers(ReturnBufferStates& states,
- const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers) {
- if (!states.useHalBufManager) {
- ALOGE("%s: Camera %s does not support HAL buffer managerment",
- __FUNCTION__, states.cameraId.string());
- return;
- }
-
- for (const auto& buf : buffers) {
- if (buf.bufferId == BUFFER_ID_NO_BUFFER) {
- ALOGE("%s: cannot return a buffer without bufferId", __FUNCTION__);
- continue;
- }
-
- buffer_handle_t* buffer;
- status_t res = states.bufferRecordsIntf.popInflightRequestBuffer(buf.bufferId, &buffer);
-
- if (res != OK) {
- ALOGE("%s: cannot find in-flight buffer %" PRIu64 " for stream %d",
- __FUNCTION__, buf.bufferId, buf.streamId);
- continue;
- }
-
- camera_stream_buffer_t streamBuffer;
- streamBuffer.buffer = buffer;
- streamBuffer.status = CAMERA_BUFFER_STATUS_ERROR;
- streamBuffer.acquire_fence = -1;
- streamBuffer.release_fence = -1;
-
- if (buf.releaseFence == nullptr) {
- streamBuffer.release_fence = -1;
- } else if (buf.releaseFence->numFds == 1) {
- streamBuffer.release_fence = dup(buf.releaseFence->data[0]);
- } else {
- ALOGE("%s: Invalid release fence, fd count is %d, not 1",
- __FUNCTION__, buf.releaseFence->numFds);
- continue;
- }
-
- sp<Camera3StreamInterface> stream = states.outputStreams.get(buf.streamId);
- if (stream == nullptr) {
- ALOGE("%s: Output stream id %d not found!", __FUNCTION__, buf.streamId);
- continue;
- }
- streamBuffer.stream = stream->asHalStream();
- returnOutputBuffers(states.useHalBufManager, /*listener*/nullptr,
- &streamBuffer, /*size*/1, /*timestamp*/ 0, /*readoutTimestamp*/0,
- /*requested*/false, /*requestTimeNs*/0, states.sessionStatsBuilder);
- }
-}
-
void flushInflightRequests(FlushInflightReqStates& states) {
ATRACE_CALL();
{ // First return buffers cached in inFlightMap
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.h b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
index 51899ee..4d1eb75 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
@@ -40,8 +40,6 @@
namespace android {
-using ResultMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
-
namespace camera3 {
/**
@@ -97,7 +95,6 @@
const metadata_vendor_id_t vendorTagId;
const CameraMetadata& deviceInfo;
const std::unordered_map<std::string, CameraMetadata>& physicalDeviceInfoMap;
- std::unique_ptr<ResultMetadataQueue>& fmq;
std::unordered_map<std::string, camera3::DistortionMapper>& distortionMappers;
std::unordered_map<std::string, camera3::ZoomRatioMapper>& zoomRatioMappers;
std::unordered_map<std::string, camera3::RotateAndCropMapper>& rotateAndCropMappers;
@@ -112,20 +109,8 @@
bool legacyClient;
};
- // Handle one capture result. Assume callers hold the lock to serialize all
- // processCaptureResult calls
- void processOneCaptureResultLocked(
- CaptureOutputStates& states,
- const hardware::camera::device::V3_2::CaptureResult& result,
- const hardware::hidl_vec<
- hardware::camera::device::V3_4::PhysicalCameraMetadata> physicalCameraMetadata);
-
- // Handle one notify message
- void notify(CaptureOutputStates& states,
- const hardware::camera::device::V3_2::NotifyMsg& msg,
- bool hasReadoutTime = false, uint64_t readoutTime = 0LL);
- void notify(CaptureOutputStates& states,
- const hardware::camera::device::V3_8::NotifyMsg& msg);
+ void processCaptureResult(CaptureOutputStates& states, const camera_capture_result *result);
+ void notify(CaptureOutputStates& states, const camera_notify_msg *msg);
struct RequestBufferStates {
const String8& cameraId;
@@ -138,10 +123,6 @@
RequestBufferInterface& reqBufferIntf;
};
- void requestStreamBuffers(RequestBufferStates& states,
- const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
- hardware::camera::device::V3_5::ICameraDeviceCallback::requestStreamBuffers_cb _hidl_cb);
-
struct ReturnBufferStates {
const String8& cameraId;
const bool useHalBufManager;
@@ -150,9 +131,6 @@
BufferRecordsInterface& bufferRecordsIntf;
};
- void returnStreamBuffers(ReturnBufferStates& states,
- const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers);
-
struct FlushInflightReqStates {
const String8& cameraId;
std::mutex& inflightLock;
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtilsTemplated.h b/services/camera/libcameraservice/device3/Camera3OutputUtilsTemplated.h
new file mode 100644
index 0000000..2e05dda
--- /dev/null
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtilsTemplated.h
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2022 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_SERVERS_CAMERA3_OUTPUT_TEMPLUTILS_H
+#define ANDROID_SERVERS_CAMERA3_OUTPUT_TEMPLUTILS_H
+
+#include <inttypes.h>
+
+#include <utils/Log.h>
+#include <utils/SortedVector.h>
+#include <utils/Trace.h>
+
+#include <aidl/android/hardware/common/NativeHandle.h>
+#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
+
+#include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
+
+#include <camera/CameraUtils.h>
+#include <camera_metadata_hidden.h>
+
+#include "device3/Camera3OutputUtils.h"
+
+#include "system/camera_metadata.h"
+
+using namespace android::camera3;
+using namespace android::hardware::camera;
+
+namespace android {
+namespace camera3 {
+
+template <class BufferStatusType>
+camera_buffer_status_t mapBufferStatus(BufferStatusType status) {
+ switch (status) {
+ case BufferStatusType::OK: return CAMERA_BUFFER_STATUS_OK;
+ case BufferStatusType::ERROR: return CAMERA_BUFFER_STATUS_ERROR;
+ }
+ return CAMERA_BUFFER_STATUS_ERROR;
+}
+
+inline void readBufferFromVec(hardware::hidl_vec<uint8_t> &dst,
+ const hardware::hidl_vec<uint8_t> &src) {
+ // Not cloning here since that will be done in processCaptureResult whil
+ // assigning to CameraMetadata.
+ dst.setToExternal(const_cast<uint8_t *>(src.data()), src.size());
+}
+
+inline void readBufferFromVec(std::vector<uint8_t> &dst, const std::vector<uint8_t> &src) {
+ dst = src;
+}
+
+// Reading one camera metadata from result argument via fmq or from the result
+// Assuming the fmq is protected by a lock already
+template <class FmqType, class FmqPayloadType, class MetadataType>
+status_t readOneCameraMetadataLockedT(
+ std::unique_ptr<FmqType>& fmq,
+ uint64_t fmqResultSize,
+ MetadataType& resultMetadata,
+ const MetadataType& result) {
+ if (fmqResultSize > 0) {
+ resultMetadata.resize(fmqResultSize);
+ if (fmq == nullptr) {
+ return NO_MEMORY; // logged in initialize()
+ }
+ if (!fmq->read(reinterpret_cast<FmqPayloadType *>(resultMetadata.data()), fmqResultSize)) {
+ ALOGE("%s: Cannot read camera metadata from fmq, size = %" PRIu64,
+ __FUNCTION__, fmqResultSize);
+ return INVALID_OPERATION;
+ }
+ } else {
+ readBufferFromVec(resultMetadata, result);
+ }
+
+ if (resultMetadata.size() != 0) {
+ status_t res;
+ const camera_metadata_t* metadata =
+ reinterpret_cast<const camera_metadata_t*>(resultMetadata.data());
+ size_t expected_metadata_size = resultMetadata.size();
+ if ((res = validate_camera_metadata_structure(metadata, &expected_metadata_size)) != OK) {
+ ALOGE("%s: Invalid camera metadata received by camera service from HAL: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return INVALID_OPERATION;
+ }
+ }
+
+ return OK;
+}
+
+inline bool isHandleNull(const hardware::hidl_handle &handle) {
+ return handle == nullptr;
+}
+
+inline bool isHandleNull(const aidl::android::hardware::common::NativeHandle &handle) {
+ return (handle.fds.size() == 0) && (handle.ints.size() == 0);
+}
+
+inline size_t numFdsInHandle(const hardware::hidl_handle &handle) {
+ return handle->numFds;
+}
+
+inline size_t numFdsInHandle(const aidl::android::hardware::common::NativeHandle &handle) {
+ return handle.fds.size();
+}
+
+inline int32_t getHandleFirstFd(const hardware::hidl_handle &handle) {
+ if (handle->numFds != 1) {
+ return -1;
+ }
+ return handle->data[0];
+}
+
+inline int32_t getHandleFirstFd(const aidl::android::hardware::common::NativeHandle &handle) {
+ if (handle.fds.size() != 1) {
+ return -1;
+ }
+ return handle.fds[0].get();
+}
+
+inline const hardware::hidl_vec<uint8_t>&
+getResultMetadata(const android::hardware::camera::device::V3_2::CameraMetadata &result) {
+ return result;
+}
+
+inline const std::vector<uint8_t>&
+getResultMetadata(const aidl::android::hardware::camera::device::CameraMetadata &result) {
+ return result.metadata;
+}
+
+// Fmqpayload type is needed since AIDL generates an fmq of payload type int8_t
+// for a byte fmq vs MetadataType which is uint8_t. For HIDL, the same type is
+// generated for metadata and fmq payload : uint8_t.
+template <class StatesType, class CaptureResultType, class PhysMetadataType, class MetadataType,
+ class FmqType, class BufferStatusType, class FmqPayloadType = uint8_t>
+void processOneCaptureResultLockedT(
+ StatesType& states,
+ const CaptureResultType& result,
+ const PhysMetadataType &physicalCameraMetadata) {
+ std::unique_ptr<FmqType>& fmq = states.fmq;
+ BufferRecordsInterface& bufferRecords = states.bufferRecordsIntf;
+ camera_capture_result r;
+ status_t res;
+ r.frame_number = result.frameNumber;
+
+ // Read and validate the result metadata.
+ MetadataType resultMetadata;
+ res = readOneCameraMetadataLockedT<FmqType, FmqPayloadType, MetadataType>(
+ fmq, result.fmqResultSize,
+ resultMetadata, getResultMetadata(result.result));
+ if (res != OK) {
+ ALOGE("%s: Frame %d: Failed to read capture result metadata",
+ __FUNCTION__, result.frameNumber);
+ return;
+ }
+ r.result = reinterpret_cast<const camera_metadata_t*>(resultMetadata.data());
+
+ // Read and validate physical camera metadata
+ size_t physResultCount = physicalCameraMetadata.size();
+ std::vector<const char*> physCamIds(physResultCount);
+ std::vector<const camera_metadata_t *> phyCamMetadatas(physResultCount);
+ std::vector<MetadataType> physResultMetadata;
+ physResultMetadata.resize(physResultCount);
+ for (size_t i = 0; i < physicalCameraMetadata.size(); i++) {
+ res = readOneCameraMetadataLockedT<FmqType, FmqPayloadType, MetadataType>(fmq,
+ physicalCameraMetadata[i].fmqMetadataSize,
+ physResultMetadata[i], getResultMetadata(physicalCameraMetadata[i].metadata));
+ if (res != OK) {
+ ALOGE("%s: Frame %d: Failed to read capture result metadata for camera %s",
+ __FUNCTION__, result.frameNumber,
+ physicalCameraMetadata[i].physicalCameraId.c_str());
+ return;
+ }
+ physCamIds[i] = physicalCameraMetadata[i].physicalCameraId.c_str();
+ phyCamMetadatas[i] =
+ reinterpret_cast<const camera_metadata_t*>(physResultMetadata[i].data());
+ }
+ r.num_physcam_metadata = physResultCount;
+ r.physcam_ids = physCamIds.data();
+ r.physcam_metadata = phyCamMetadatas.data();
+
+ std::vector<camera_stream_buffer_t> outputBuffers(result.outputBuffers.size());
+ std::vector<buffer_handle_t> outputBufferHandles(result.outputBuffers.size());
+ for (size_t i = 0; i < result.outputBuffers.size(); i++) {
+ auto& bDst = outputBuffers[i];
+ const auto &bSrc = result.outputBuffers[i];
+
+ sp<Camera3StreamInterface> stream = states.outputStreams.get(bSrc.streamId);
+ if (stream == nullptr) {
+ ALOGE("%s: Frame %d: Buffer %zu: Invalid output stream id %d",
+ __FUNCTION__, result.frameNumber, i, bSrc.streamId);
+ return;
+ }
+ bDst.stream = stream->asHalStream();
+
+ bool noBufferReturned = false;
+ buffer_handle_t *buffer = nullptr;
+ if (states.useHalBufManager) {
+ // This is suspicious most of the time but can be correct during flush where HAL
+ // has to return capture result before a buffer is requested
+ if (bSrc.bufferId == BUFFER_ID_NO_BUFFER) {
+ if (bSrc.status == BufferStatusType::OK) {
+ ALOGE("%s: Frame %d: Buffer %zu: No bufferId for stream %d",
+ __FUNCTION__, result.frameNumber, i, bSrc.streamId);
+ // Still proceeds so other buffers can be returned
+ }
+ noBufferReturned = true;
+ }
+ if (noBufferReturned) {
+ res = OK;
+ } else {
+ res = bufferRecords.popInflightRequestBuffer(bSrc.bufferId, &buffer);
+ }
+ } else {
+ res = bufferRecords.popInflightBuffer(result.frameNumber, bSrc.streamId, &buffer);
+ }
+
+ if (res != OK) {
+ ALOGE("%s: Frame %d: Buffer %zu: No in-flight buffer for stream %d",
+ __FUNCTION__, result.frameNumber, i, bSrc.streamId);
+ return;
+ }
+
+ bDst.buffer = buffer;
+ bDst.status = mapBufferStatus<BufferStatusType>(bSrc.status);
+ bDst.acquire_fence = -1;
+ if (isHandleNull(bSrc.releaseFence)) {
+ bDst.release_fence = -1;
+ } else if (numFdsInHandle(bSrc.releaseFence) == 1) {
+ if (noBufferReturned) {
+ ALOGE("%s: got releaseFence without output buffer!", __FUNCTION__);
+ }
+ bDst.release_fence = dup(getHandleFirstFd(bSrc.releaseFence));
+ } else {
+ ALOGE("%s: Frame %d: Invalid release fence for buffer %zu, fd count is %d, not 1",
+ __FUNCTION__, result.frameNumber, i, (int)numFdsInHandle(bSrc.releaseFence));
+ return;
+ }
+ }
+ r.num_output_buffers = outputBuffers.size();
+ r.output_buffers = outputBuffers.data();
+
+ camera_stream_buffer_t inputBuffer;
+ if (result.inputBuffer.streamId == -1) {
+ r.input_buffer = nullptr;
+ } else {
+ if (states.inputStream->getId() != result.inputBuffer.streamId) {
+ ALOGE("%s: Frame %d: Invalid input stream id %d", __FUNCTION__,
+ result.frameNumber, result.inputBuffer.streamId);
+ return;
+ }
+ inputBuffer.stream = states.inputStream->asHalStream();
+ buffer_handle_t *buffer;
+ res = bufferRecords.popInflightBuffer(result.frameNumber, result.inputBuffer.streamId,
+ &buffer);
+ if (res != OK) {
+ ALOGE("%s: Frame %d: Input buffer: No in-flight buffer for stream %d",
+ __FUNCTION__, result.frameNumber, result.inputBuffer.streamId);
+ return;
+ }
+ inputBuffer.buffer = buffer;
+ inputBuffer.status = mapBufferStatus<BufferStatusType>(result.inputBuffer.status);
+ inputBuffer.acquire_fence = -1;
+ if (isHandleNull(result.inputBuffer.releaseFence)) {
+ inputBuffer.release_fence = -1;
+ } else if (numFdsInHandle(result.inputBuffer.releaseFence) == 1) {
+ inputBuffer.release_fence = dup(getHandleFirstFd(result.inputBuffer.releaseFence));
+ } else {
+ ALOGE("%s: Frame %d: Invalid release fence for input buffer, fd count is %d, not 1",
+ __FUNCTION__, result.frameNumber,
+ (int)numFdsInHandle(result.inputBuffer.releaseFence));
+ return;
+ }
+ r.input_buffer = &inputBuffer;
+ }
+
+ r.partial_result = result.partialResult;
+
+ processCaptureResult(states, &r);
+}
+
+template <class VecStreamBufferType>
+void returnStreamBuffersT(ReturnBufferStates& states,
+ const VecStreamBufferType& buffers) {
+ if (!states.useHalBufManager) {
+ ALOGE("%s: Camera %s does not support HAL buffer managerment",
+ __FUNCTION__, states.cameraId.string());
+ return;
+ }
+
+ for (const auto& buf : buffers) {
+ if (buf.bufferId == BUFFER_ID_NO_BUFFER) {
+ ALOGE("%s: cannot return a buffer without bufferId", __FUNCTION__);
+ continue;
+ }
+
+ buffer_handle_t* buffer;
+ status_t res = states.bufferRecordsIntf.popInflightRequestBuffer(buf.bufferId, &buffer);
+
+ if (res != OK) {
+ ALOGE("%s: cannot find in-flight buffer %" PRIu64 " for stream %d",
+ __FUNCTION__, buf.bufferId, buf.streamId);
+ continue;
+ }
+
+ camera_stream_buffer_t streamBuffer;
+ streamBuffer.buffer = buffer;
+ streamBuffer.status = CAMERA_BUFFER_STATUS_ERROR;
+ streamBuffer.acquire_fence = -1;
+ streamBuffer.release_fence = -1;
+
+ if (isHandleNull(buf.releaseFence)) {
+ streamBuffer.release_fence = -1;
+ } else if (numFdsInHandle(buf.releaseFence) == 1) {
+ streamBuffer.release_fence = dup(getHandleFirstFd(buf.releaseFence));
+ } else {
+ ALOGE("%s: Invalid release fence, fd count is %d, not 1",
+ __FUNCTION__, (int)numFdsInHandle(buf.releaseFence));
+ continue;
+ }
+
+ sp<Camera3StreamInterface> stream = states.outputStreams.get(buf.streamId);
+ if (stream == nullptr) {
+ ALOGE("%s: Output stream id %d not found!", __FUNCTION__, buf.streamId);
+ continue;
+ }
+ streamBuffer.stream = stream->asHalStream();
+ returnOutputBuffers(states.useHalBufManager, /*listener*/nullptr,
+ &streamBuffer, /*size*/1, /*timestamp*/ 0, /*readoutTimestamp*/0,
+ /*requested*/false, /*requestTimeNs*/0, states.sessionStatsBuilder);
+ }
+}
+
+} // camera3
+} // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
index 0e2671a..9bf7b6a 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
@@ -33,10 +33,14 @@
camera_stream_rotation_t rotation,
nsecs_t timestampOffset, const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
- int setId, bool useHalBufManager, int dynamicProfile) :
+ int setId, bool useHalBufManager, int dynamicProfile,
+ int streamUseCase, bool deviceTimeBaseIsRealtime, int timestampBase,
+ int mirrorMode) :
Camera3OutputStream(id, CAMERA_STREAM_OUTPUT, width, height,
format, dataSpace, rotation, physicalCameraId, sensorPixelModesUsed,
- consumerUsage, timestampOffset, setId, dynamicProfile),
+ consumerUsage, timestampOffset, setId, /*isMultiResolution*/false,
+ dynamicProfile, streamUseCase, deviceTimeBaseIsRealtime, timestampBase,
+ mirrorMode),
mUseHalBufManager(useHalBufManager) {
size_t consumerCount = std::min(surfaces.size(), kMaxOutputs);
if (surfaces.size() > consumerCount) {
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
index fafa26f..0061a52 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
@@ -41,7 +41,11 @@
const std::unordered_set<int32_t> &sensorPixelModesUsed,
int setId = CAMERA3_STREAM_SET_ID_INVALID,
bool useHalBufManager = false,
- int dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
+ int dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
+ int streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
+ bool deviceTimeBaseIsRealtime = false,
+ int timestampBase = OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
+ int mirrorMode = OutputConfiguration::MIRROR_MODE_AUTO);
virtual ~Camera3SharedOutputStream();
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 83f9a98..3f0299b 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -54,7 +54,8 @@
android_dataspace dataSpace, camera_stream_rotation_t rotation,
const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
- int setId, bool isMultiResolution, int dynamicRangeProfile) :
+ int setId, bool isMultiResolution, int dynamicRangeProfile,
+ int streamUseCase, bool deviceTimeBaseIsRealtime, int timestampBase) :
camera_stream(),
mId(id),
mSetId(setId),
@@ -79,7 +80,9 @@
mOriginalDataSpace(dataSpace),
mPhysicalCameraId(physicalCameraId),
mLastTimestamp(0),
- mIsMultiResolution(isMultiResolution) {
+ mIsMultiResolution(isMultiResolution),
+ mDeviceTimeBaseIsRealtime(deviceTimeBaseIsRealtime),
+ mTimestampBase(timestampBase) {
camera_stream::stream_type = type;
camera_stream::width = width;
@@ -91,6 +94,7 @@
camera_stream::physical_camera_id = mPhysicalCameraId.string();
camera_stream::sensor_pixel_modes_used = sensorPixelModesUsed;
camera_stream::dynamic_range_profile = dynamicRangeProfile;
+ camera_stream::use_case = streamUseCase;
if ((format == HAL_PIXEL_FORMAT_BLOB || format == HAL_PIXEL_FORMAT_RAW_OPAQUE) &&
maxSize == 0) {
@@ -175,6 +179,18 @@
return camera_stream::max_buffers;
}
+int Camera3Stream::getStreamUseCase() const {
+ return camera_stream::use_case;
+}
+
+int Camera3Stream::getTimestampBase() const {
+ return mTimestampBase;
+}
+
+bool Camera3Stream::isDeviceTimeBaseRealtime() const {
+ return mDeviceTimeBaseIsRealtime;
+}
+
void Camera3Stream::setOfflineProcessingSupport(bool support) {
mSupportOfflineProcessing = support;
}
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index bbbea8d..8232ce0 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -178,6 +178,9 @@
android_dataspace getOriginalDataSpace() const;
int getMaxHalBuffers() const;
const String8& physicalCameraId() const;
+ int getStreamUseCase() const;
+ int getTimestampBase() const;
+ bool isDeviceTimeBaseRealtime() const;
void setOfflineProcessingSupport(bool) override;
bool getOfflineProcessingSupport() const override;
@@ -505,7 +508,8 @@
android_dataspace dataSpace, camera_stream_rotation_t rotation,
const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
- int setId, bool isMultiResolution, int dynamicRangeProfile);
+ int setId, bool isMultiResolution, int dynamicRangeProfile,
+ int streamUseCase, bool deviceTimeBaseIsRealtime, int timestampBase);
wp<Camera3StreamBufferFreedListener> mBufferFreedListener;
@@ -628,6 +632,9 @@
bool mIsMultiResolution = false;
bool mSupportOfflineProcessing = false;
+
+ bool mDeviceTimeBaseIsRealtime;
+ int mTimestampBase;
}; // class Camera3Stream
}; // namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index ef10f0d..148e511 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -19,6 +19,7 @@
#include <utils/RefBase.h>
+#include <camera/camera2/OutputConfiguration.h>
#include <camera/CameraMetadata.h>
#include "Camera3StreamBufferListener.h"
#include "Camera3StreamBufferFreedListener.h"
@@ -65,6 +66,7 @@
std::unordered_set<int32_t> sensor_pixel_modes_used;
int dynamic_range_profile;
+ int use_case;
} camera_stream_t;
typedef struct camera_stream_buffer {
@@ -109,16 +111,23 @@
bool supportsOffline = false;
std::unordered_set<int32_t> sensorPixelModesUsed;
int dynamicRangeProfile;
+ int streamUseCase;
+ int timestampBase;
+ int mirrorMode;
OutputStreamInfo() :
width(-1), height(-1), format(-1), dataSpace(HAL_DATASPACE_UNKNOWN),
consumerUsage(0),
- dynamicRangeProfile(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) {}
+ dynamicRangeProfile(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD),
+ streamUseCase(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT),
+ timestampBase(OutputConfiguration::TIMESTAMP_BASE_DEFAULT),
+ mirrorMode(OutputConfiguration::MIRROR_MODE_AUTO) {}
OutputStreamInfo(int _width, int _height, int _format, android_dataspace _dataSpace,
uint64_t _consumerUsage, const std::unordered_set<int32_t>& _sensorPixelModesUsed,
- int _dynamicRangeProfile) :
+ int _dynamicRangeProfile, int _streamUseCase, int _timestampBase, int _mirrorMode) :
width(_width), height(_height), format(_format),
dataSpace(_dataSpace), consumerUsage(_consumerUsage),
- sensorPixelModesUsed(_sensorPixelModesUsed), dynamicRangeProfile(_dynamicRangeProfile){}
+ sensorPixelModesUsed(_sensorPixelModesUsed), dynamicRangeProfile(_dynamicRangeProfile),
+ streamUseCase(_streamUseCase), timestampBase(_timestampBase), mirrorMode(_mirrorMode) {}
};
/**
diff --git a/services/camera/libcameraservice/device3/PreviewFrameScheduler.cpp b/services/camera/libcameraservice/device3/PreviewFrameScheduler.cpp
index 6135f9e..154e6f5 100644
--- a/services/camera/libcameraservice/device3/PreviewFrameScheduler.cpp
+++ b/services/camera/libcameraservice/device3/PreviewFrameScheduler.cpp
@@ -187,7 +187,7 @@
status_t PreviewFrameScheduler::queueBufferToClientLocked(
const BufferHolder& bufferHolder, nsecs_t timestamp) {
- mParent.setTransform(bufferHolder.transform);
+ mParent.setTransform(bufferHolder.transform, true/*mayChangeMirror*/);
status_t res = native_window_set_buffers_timestamp(mConsumer.get(), timestamp);
if (res != OK) {
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
new file mode 100644
index 0000000..452c9f9
--- /dev/null
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
@@ -0,0 +1,1584 @@
+/*
+ * Copyright (C) 2022 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 "AidlCamera3-Device"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+//#define LOG_NNDEBUG 0 // Per-frame verbose logging
+
+#ifdef LOG_NNDEBUG
+#define ALOGVV(...) ALOGV(__VA_ARGS__)
+#else
+#define ALOGVV(...) ((void)0)
+#endif
+
+// Convenience macro for transient errors
+#define CLOGE(fmt, ...) ALOGE("Camera %s: %s: " fmt, mId.string(), __FUNCTION__, \
+ ##__VA_ARGS__)
+
+#define CLOGW(fmt, ...) ALOGW("Camera %s: %s: " fmt, mId.string(), __FUNCTION__, \
+ ##__VA_ARGS__)
+
+// Convenience macros for transitioning to the error state
+#define SET_ERR(fmt, ...) setErrorState( \
+ "%s: " fmt, __FUNCTION__, \
+ ##__VA_ARGS__)
+#define SET_ERR_L(fmt, ...) setErrorStateLocked( \
+ "%s: " fmt, __FUNCTION__, \
+ ##__VA_ARGS__)
+
+#include <inttypes.h>
+
+#include <utility>
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include <utils/Timers.h>
+#include <cutils/properties.h>
+
+#include <aidl/android/hardware/camera/device/ICameraInjectionSession.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android/hardware/camera2/ICameraDeviceUser.h>
+
+#include "utils/CameraTraces.h"
+#include "mediautils/SchedulingPolicyService.h"
+#include "device3/Camera3OutputStream.h"
+#include "device3/Camera3InputStream.h"
+#include "device3/Camera3FakeStream.h"
+#include "device3/Camera3SharedOutputStream.h"
+#include "device3/aidl/AidlCamera3OutputUtils.h"
+#include "device3/aidl/AidlCamera3OfflineSession.h"
+#include "CameraService.h"
+#include "utils/CameraThreadState.h"
+#include "utils/SessionConfigurationUtils.h"
+#include "utils/TraceHFR.h"
+#include "utils/CameraServiceProxyWrapper.h"
+
+#include "../../common/aidl/AidlProviderInfo.h"
+
+#include <algorithm>
+
+#include "AidlCamera3Device.h"
+
+using namespace android::camera3;
+using namespace aidl::android::hardware;
+using aidl::android::hardware::camera::metadata::SensorPixelMode;
+using aidl::android::hardware::camera::metadata::RequestAvailableDynamicRangeProfilesMap;
+using aidl::android::hardware::camera::metadata::ScalerAvailableStreamUseCases;
+
+namespace android {
+
+RequestAvailableDynamicRangeProfilesMap
+mapToAidlDynamicProfile(int dynamicRangeProfile) {
+ return static_cast<RequestAvailableDynamicRangeProfilesMap>(dynamicRangeProfile);
+}
+
+aidl::android::hardware::graphics::common::PixelFormat AidlCamera3Device::mapToAidlPixelFormat(
+ int frameworkFormat) {
+ return (aidl::android::hardware::graphics::common::PixelFormat) frameworkFormat;
+}
+
+aidl::android::hardware::graphics::common::Dataspace AidlCamera3Device::mapToAidlDataspace(
+ android_dataspace dataSpace) {
+ return (aidl::android::hardware::graphics::common::Dataspace)dataSpace;
+}
+
+aidl::android::hardware::graphics::common::BufferUsage AidlCamera3Device::mapToAidlConsumerUsage(
+ uint64_t usage) {
+ return (aidl::android::hardware::graphics::common::BufferUsage)usage;
+}
+
+aidl::android::hardware::camera::device::StreamRotation
+AidlCamera3Device::mapToAidlStreamRotation(camera_stream_rotation_t rotation) {
+ switch (rotation) {
+ case CAMERA_STREAM_ROTATION_0:
+ return aidl::android::hardware::camera::device::StreamRotation::ROTATION_0;
+ case CAMERA_STREAM_ROTATION_90:
+ return aidl::android::hardware::camera::device::StreamRotation::ROTATION_90;
+ case CAMERA_STREAM_ROTATION_180:
+ return aidl::android::hardware::camera::device::StreamRotation::ROTATION_180;
+ case CAMERA_STREAM_ROTATION_270:
+ return aidl::android::hardware::camera::device::StreamRotation::ROTATION_270;
+ }
+ ALOGE("%s: Unknown stream rotation %d", __FUNCTION__, rotation);
+ return aidl::android::hardware::camera::device::StreamRotation::ROTATION_0;
+}
+
+status_t AidlCamera3Device::mapToAidlStreamConfigurationMode(
+ camera_stream_configuration_mode_t operationMode,
+ aidl::android::hardware::camera::device::StreamConfigurationMode *mode) {
+ using StreamConfigurationMode =
+ aidl::android::hardware::camera::device::StreamConfigurationMode;
+ if (mode == nullptr) return BAD_VALUE;
+ if (operationMode < CAMERA_VENDOR_STREAM_CONFIGURATION_MODE_START) {
+ switch(operationMode) {
+ case CAMERA_STREAM_CONFIGURATION_NORMAL_MODE:
+ *mode = StreamConfigurationMode::NORMAL_MODE;
+ break;
+ case CAMERA_STREAM_CONFIGURATION_CONSTRAINED_HIGH_SPEED_MODE:
+ *mode = StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE;
+ break;
+ default:
+ ALOGE("%s: Unknown stream configuration mode %d", __FUNCTION__, operationMode);
+ return BAD_VALUE;
+ }
+ } else {
+ *mode = static_cast<StreamConfigurationMode>(operationMode);
+ }
+ return OK;
+}
+
+int AidlCamera3Device::mapToFrameworkFormat(
+ aidl::android::hardware::graphics::common::PixelFormat pixelFormat) {
+ return static_cast<uint32_t>(pixelFormat);
+}
+
+android_dataspace AidlCamera3Device::mapToFrameworkDataspace(
+ aidl::android::hardware::graphics::common::Dataspace dataSpace) {
+ return static_cast<android_dataspace>(dataSpace);
+}
+
+uint64_t AidlCamera3Device::mapConsumerToFrameworkUsage(
+ aidl::android::hardware::graphics::common::BufferUsage usage) {
+ return (uint64_t)usage;
+}
+
+uint64_t AidlCamera3Device::mapProducerToFrameworkUsage(
+ aidl::android::hardware::graphics::common::BufferUsage usage) {
+ return (uint64_t)usage;
+}
+
+AidlCamera3Device::AidlCamera3Device(const String8& id, bool overrideForPerfClass,
+ bool legacyClient) : Camera3Device(id, overrideForPerfClass, legacyClient) {
+ mCallbacks = ndk::SharedRefBase::make<AidlCameraDeviceCallbacks>(this);
+}
+
+status_t AidlCamera3Device::initialize(sp<CameraProviderManager> manager,
+ const String8& monitorTags) {
+ ATRACE_CALL();
+ Mutex::Autolock il(mInterfaceLock);
+ Mutex::Autolock l(mLock);
+
+ ALOGV("%s: Initializing AIDL device for camera %s", __FUNCTION__, mId.string());
+ if (mStatus != STATUS_UNINITIALIZED) {
+ CLOGE("Already initialized!");
+ return INVALID_OPERATION;
+ }
+ if (manager == nullptr) return INVALID_OPERATION;
+
+ std::shared_ptr<camera::device::ICameraDeviceSession> session;
+ ATRACE_BEGIN("CameraHal::openSession");
+ status_t res = manager->openAidlSession(mId.string(), mCallbacks,
+ /*out*/ &session);
+ ATRACE_END();
+ if (res != OK) {
+ SET_ERR_L("Could not open camera session: %s (%d)", strerror(-res), res);
+ return res;
+ }
+ if (session == nullptr) {
+ ALOGE("JCLog: null session returned");
+ SET_ERR("Session iface returned is null");
+ return INVALID_OPERATION;
+ }
+ res = manager->getCameraCharacteristics(mId.string(), mOverrideForPerfClass, &mDeviceInfo);
+ if (res != OK) {
+ SET_ERR_L("Could not retrieve camera characteristics: %s (%d)", strerror(-res), res);
+ session->close();
+ return res;
+ }
+ mSupportNativeZoomRatio = manager->supportNativeZoomRatio(mId.string());
+
+ std::vector<std::string> physicalCameraIds;
+ bool isLogical = manager->isLogicalCamera(mId.string(), &physicalCameraIds);
+ if (isLogical) {
+ for (auto& physicalId : physicalCameraIds) {
+ // Do not override characteristics for physical cameras
+ res = manager->getCameraCharacteristics(
+ physicalId, /*overrideForPerfClass*/false, &mPhysicalDeviceInfoMap[physicalId]);
+ if (res != OK) {
+ SET_ERR_L("Could not retrieve camera %s characteristics: %s (%d)",
+ physicalId.c_str(), strerror(-res), res);
+ session->close();
+ return res;
+ }
+
+ bool usePrecorrectArray =
+ DistortionMapper::isDistortionSupported(mPhysicalDeviceInfoMap[physicalId]);
+ if (usePrecorrectArray) {
+ res = mDistortionMappers[physicalId].setupStaticInfo(
+ mPhysicalDeviceInfoMap[physicalId]);
+ if (res != OK) {
+ SET_ERR_L("Unable to read camera %s's calibration fields for distortion "
+ "correction", physicalId.c_str());
+ session->close();
+ return res;
+ }
+ }
+
+ mZoomRatioMappers[physicalId] = ZoomRatioMapper(
+ &mPhysicalDeviceInfoMap[physicalId],
+ mSupportNativeZoomRatio, usePrecorrectArray);
+
+ if (SessionConfigurationUtils::isUltraHighResolutionSensor(
+ mPhysicalDeviceInfoMap[physicalId])) {
+ mUHRCropAndMeteringRegionMappers[physicalId] =
+ UHRCropAndMeteringRegionMapper(mPhysicalDeviceInfoMap[physicalId],
+ usePrecorrectArray);
+ }
+ }
+ }
+
+ std::shared_ptr<AidlRequestMetadataQueue> queue;
+ ::aidl::android::hardware::common::fmq::MQDescriptor<
+ int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite> desc;
+
+ ::ndk::ScopedAStatus requestQueueRet = session->getCaptureRequestMetadataQueue(&desc);
+ if (!requestQueueRet.isOk()) {
+ ALOGE("Transaction error when getting result metadata queue from camera session: %s",
+ requestQueueRet.getMessage());
+ return AidlProviderInfo::mapToStatusT(requestQueueRet);
+ }
+ queue = std::make_unique<AidlRequestMetadataQueue>(desc);
+ if (!queue->isValid() || queue->availableToWrite() <= 0) {
+ ALOGE("HAL returns empty result metadata fmq, not use it");
+ queue = nullptr;
+ // Don't use resQueue onwards.
+ }
+
+ std::unique_ptr<AidlResultMetadataQueue>& resQueue = mResultMetadataQueue;
+ ::aidl::android::hardware::common::fmq::MQDescriptor<
+ int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite> resDesc;
+ ::ndk::ScopedAStatus resultQueueRet = session->getCaptureResultMetadataQueue(&resDesc);
+ if (!resultQueueRet.isOk()) {
+ ALOGE("Transaction error when getting result metadata queue from camera session: %s",
+ resultQueueRet.getMessage());
+ return AidlProviderInfo::mapToStatusT(resultQueueRet);
+ }
+ resQueue = std::make_unique<AidlResultMetadataQueue>(resDesc);
+ if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
+ ALOGE("HAL returns empty result metadata fmq, not use it");
+ resQueue = nullptr;
+ // Don't use resQueue onwards.
+ }
+
+ camera_metadata_entry bufMgrMode =
+ mDeviceInfo.find(ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION);
+ if (bufMgrMode.count > 0) {
+ mUseHalBufManager = (bufMgrMode.data.u8[0] ==
+ ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
+ }
+
+ camera_metadata_entry_t capabilities = mDeviceInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+ for (size_t i = 0; i < capabilities.count; i++) {
+ uint8_t capability = capabilities.data.u8[i];
+ if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING) {
+ mSupportOfflineProcessing = true;
+ }
+ }
+
+ mInterface = new AidlHalInterface(session, queue, mUseHalBufManager, mSupportOfflineProcessing);
+
+ std::string providerType;
+ mVendorTagId = manager->getProviderTagIdLocked(mId.string());
+ mTagMonitor.initialize(mVendorTagId);
+ if (!monitorTags.isEmpty()) {
+ mTagMonitor.parseTagsToMonitor(String8(monitorTags));
+ }
+
+ for (size_t i = 0; i < capabilities.count; i++) {
+ uint8_t capability = capabilities.data.u8[i];
+ if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME) {
+ mNeedFixupMonochromeTags = true;
+ }
+ }
+
+ return initializeCommonLocked();
+}
+
+::ndk::ScopedAStatus AidlCamera3Device::AidlCameraDeviceCallbacks::processCaptureResult(
+ const std::vector<camera::device::CaptureResult>& results) {
+ sp<AidlCamera3Device> p = mParent.promote();
+ if (p == nullptr) {
+ ALOGE("%s Parent AidlCameraDevice not alive, can't process callbacks", __FUNCTION__);
+ return ::ndk::ScopedAStatus::ok();
+ }
+ return p->processCaptureResult(results);
+}
+
+::ndk::ScopedAStatus AidlCamera3Device::AidlCameraDeviceCallbacks::notify(
+ const std::vector<camera::device::NotifyMsg>& msgs) {
+ sp<AidlCamera3Device> p = mParent.promote();
+ if (p == nullptr) {
+ ALOGE("%s Parent AidlCameraDevice not alive, can't process callbacks", __FUNCTION__);
+ return ::ndk::ScopedAStatus::ok();
+ }
+ return p->notify(msgs);
+}
+
+::ndk::ScopedAStatus AidlCamera3Device::processCaptureResult(
+ const std::vector<camera::device::CaptureResult>& results) {
+ // Ideally we should grab mLock, but that can lead to deadlock, and
+ // it's not super important to get up to date value of mStatus for this
+ // warning print, hence skipping the lock here
+ if (mStatus == STATUS_ERROR) {
+ // Per API contract, HAL should act as closed after device error
+ // But mStatus can be set to error by framework as well, so just log
+ // a warning here.
+ ALOGW("%s: received capture result in error state.", __FUNCTION__);
+ }
+
+ sp<NotificationListener> listener;
+ {
+ std::lock_guard<std::mutex> l(mOutputLock);
+ listener = mListener.promote();
+ }
+
+ if (mProcessCaptureResultLock.tryLock() != OK) {
+ // This should never happen; it indicates a wrong client implementation
+ // that doesn't follow the contract. But, we can be tolerant here.
+ ALOGE("%s: callback overlapped! waiting 1s...",
+ __FUNCTION__);
+ if (mProcessCaptureResultLock.timedLock(1000000000 /* 1s */) != OK) {
+ ALOGE("%s: cannot acquire lock in 1s, dropping results",
+ __FUNCTION__);
+ // really don't know what to do, so bail out.
+ return ::ndk::ScopedAStatus::ok();
+ }
+ }
+ AidlCaptureOutputStates states {
+ {
+ mId,
+ mInFlightLock, mLastCompletedRegularFrameNumber,
+ mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+ mInFlightMap, mOutputLock, mResultQueue, mResultSignal,
+ mNextShutterFrameNumber,
+ mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+ mNextResultFrameNumber,
+ mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+ mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+ mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+ mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this,
+ *this, *(mInterface), mLegacyClient}, mResultMetadataQueue
+ };
+
+ for (const auto& result : results) {
+ processOneCaptureResultLocked(states, result, result.physicalCameraMetadata);
+ }
+ mProcessCaptureResultLock.unlock();
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus AidlCamera3Device::notify(
+ const std::vector<camera::device::NotifyMsg>& msgs) {
+ // Ideally we should grab mLock, but that can lead to deadlock, and
+ // it's not super important to get up to date value of mStatus for this
+ // warning print, hence skipping the lock here
+ if (mStatus == STATUS_ERROR) {
+ // Per API contract, HAL should act as closed after device error
+ // But mStatus can be set to error by framework as well, so just log
+ // a warning here.
+ ALOGW("%s: received notify message in error state.", __FUNCTION__);
+ }
+
+ sp<NotificationListener> listener;
+ {
+ std::lock_guard<std::mutex> l(mOutputLock);
+ listener = mListener.promote();
+ }
+
+ AidlCaptureOutputStates states {
+ { mId,
+ mInFlightLock, mLastCompletedRegularFrameNumber,
+ mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+ mInFlightMap, mOutputLock, mResultQueue, mResultSignal,
+ mNextShutterFrameNumber,
+ mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+ mNextResultFrameNumber,
+ mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+ mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+ mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+ mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this,
+ *this, *(mInterface), mLegacyClient}, mResultMetadataQueue
+ };
+ for (const auto& msg : msgs) {
+ camera3::notify(states, msg);
+ }
+ return ::ndk::ScopedAStatus::ok();
+
+}
+
+status_t AidlCamera3Device::switchToOffline(
+ const std::vector<int32_t>& streamsToKeep,
+ /*out*/ sp<CameraOfflineSessionBase>* session) {
+ ATRACE_CALL();
+ if (session == nullptr) {
+ ALOGE("%s: session must not be null", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock il(mInterfaceLock);
+
+ bool hasInputStream = mInputStream != nullptr;
+ int32_t inputStreamId = hasInputStream ? mInputStream->getId() : -1;
+ bool inputStreamSupportsOffline = hasInputStream ?
+ mInputStream->getOfflineProcessingSupport() : false;
+ auto outputStreamIds = mOutputStreams.getStreamIds();
+ auto streamIds = outputStreamIds;
+ if (hasInputStream) {
+ streamIds.push_back(mInputStream->getId());
+ }
+
+ // Check all streams in streamsToKeep supports offline mode
+ for (auto id : streamsToKeep) {
+ if (std::find(streamIds.begin(), streamIds.end(), id) == streamIds.end()) {
+ ALOGE("%s: Unknown stream ID %d", __FUNCTION__, id);
+ return BAD_VALUE;
+ } else if (id == inputStreamId) {
+ if (!inputStreamSupportsOffline) {
+ ALOGE("%s: input stream %d cannot be switched to offline",
+ __FUNCTION__, id);
+ return BAD_VALUE;
+ }
+ } else {
+ sp<camera3::Camera3OutputStreamInterface> stream = mOutputStreams.get(id);
+ if (!stream->getOfflineProcessingSupport()) {
+ ALOGE("%s: output stream %d cannot be switched to offline",
+ __FUNCTION__, id);
+ return BAD_VALUE;
+ }
+ }
+ }
+ // TODO: block surface sharing and surface group streams until we can support them
+
+ // Stop repeating request, wait until all remaining requests are submitted, then call into
+ // HAL switchToOffline
+ camera::device::CameraOfflineSessionInfo offlineSessionInfo;
+ std::shared_ptr<camera::device::ICameraOfflineSession> offlineSession;
+ camera3::BufferRecords bufferRecords;
+ status_t ret = static_cast<AidlRequestThread *>(mRequestThread.get())->switchToOffline(
+ streamsToKeep, &offlineSessionInfo, &offlineSession, &bufferRecords);
+
+ if (ret != OK) {
+ SET_ERR("Switch to offline failed: %s (%d)", strerror(-ret), ret);
+ return ret;
+ }
+
+ bool succ = mRequestBufferSM.onSwitchToOfflineSuccess();
+ if (!succ) {
+ SET_ERR("HAL must not be calling requestStreamBuffers call");
+ // TODO: block ALL callbacks from HAL till app configured new streams?
+ return UNKNOWN_ERROR;
+ }
+
+ // Verify offlineSessionInfo
+ std::vector<int32_t> offlineStreamIds;
+ offlineStreamIds.reserve(offlineSessionInfo.offlineStreams.size());
+ for (auto offlineStream : offlineSessionInfo.offlineStreams) {
+ // verify stream IDs
+ int32_t id = offlineStream.id;
+ if (std::find(streamIds.begin(), streamIds.end(), id) == streamIds.end()) {
+ SET_ERR("stream ID %d not found!", id);
+ return UNKNOWN_ERROR;
+ }
+
+ // When not using HAL buf manager, only allow streams requested by app to be preserved
+ if (!mUseHalBufManager) {
+ if (std::find(streamsToKeep.begin(), streamsToKeep.end(), id) == streamsToKeep.end()) {
+ SET_ERR("stream ID %d must not be switched to offline!", id);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ offlineStreamIds.push_back(id);
+ sp<Camera3StreamInterface> stream = (id == inputStreamId) ?
+ static_cast<sp<Camera3StreamInterface>>(mInputStream) :
+ static_cast<sp<Camera3StreamInterface>>(mOutputStreams.get(id));
+ // Verify number of outstanding buffers
+ if (stream->getOutstandingBuffersCount() != (uint32_t)offlineStream.numOutstandingBuffers) {
+ SET_ERR("Offline stream %d # of remaining buffer mismatch: (%zu,%d) (service/HAL)",
+ id, stream->getOutstandingBuffersCount(), offlineStream.numOutstandingBuffers);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ // Verify all streams to be deleted don't have any outstanding buffers
+ if (hasInputStream && std::find(offlineStreamIds.begin(), offlineStreamIds.end(),
+ inputStreamId) == offlineStreamIds.end()) {
+ if (mInputStream->hasOutstandingBuffers()) {
+ SET_ERR("Input stream %d still has %zu outstanding buffer!",
+ inputStreamId, mInputStream->getOutstandingBuffersCount());
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ for (const auto& outStreamId : outputStreamIds) {
+ if (std::find(offlineStreamIds.begin(), offlineStreamIds.end(),
+ outStreamId) == offlineStreamIds.end()) {
+ auto outStream = mOutputStreams.get(outStreamId);
+ if (outStream->hasOutstandingBuffers()) {
+ SET_ERR("Output stream %d still has %zu outstanding buffer!",
+ outStreamId, outStream->getOutstandingBuffersCount());
+ return UNKNOWN_ERROR;
+ }
+ }
+ }
+
+ InFlightRequestMap offlineReqs;
+ // Verify inflight requests and their pending buffers
+ {
+ std::lock_guard<std::mutex> l(mInFlightLock);
+ for (auto offlineReq : offlineSessionInfo.offlineRequests) {
+ int idx = mInFlightMap.indexOfKey(offlineReq.frameNumber);
+ if (idx == NAME_NOT_FOUND) {
+ SET_ERR("Offline request frame number %d not found!", offlineReq.frameNumber);
+ return UNKNOWN_ERROR;
+ }
+
+ const auto& inflightReq = mInFlightMap.valueAt(idx);
+ // TODO: check specific stream IDs
+ size_t numBuffersLeft = static_cast<size_t>(inflightReq.numBuffersLeft);
+ if (numBuffersLeft != offlineReq.pendingStreams.size()) {
+ SET_ERR("Offline request # of remaining buffer mismatch: (%d,%d) (service/HAL)",
+ inflightReq.numBuffersLeft, offlineReq.pendingStreams.size());
+ return UNKNOWN_ERROR;
+ }
+ offlineReqs.add(offlineReq.frameNumber, inflightReq);
+ }
+ }
+
+ // Create Camera3OfflineSession and transfer object ownership
+ // (streams, inflight requests, buffer caches)
+ camera3::StreamSet offlineStreamSet;
+ sp<camera3::Camera3Stream> inputStream;
+ for (auto offlineStream : offlineSessionInfo.offlineStreams) {
+ int32_t id = offlineStream.id;
+ if (mInputStream != nullptr && id == mInputStream->getId()) {
+ inputStream = mInputStream;
+ } else {
+ offlineStreamSet.add(id, mOutputStreams.get(id));
+ }
+ }
+
+ // TODO: check if we need to lock before copying states
+ // though technically no other thread should be talking to Camera3Device at this point
+ Camera3OfflineStates offlineStates(
+ mTagMonitor, mVendorTagId, mUseHalBufManager, mNeedFixupMonochromeTags,
+ mUsePartialResult, mNumPartialResults, mLastCompletedRegularFrameNumber,
+ mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+ mNextResultFrameNumber, mNextReprocessResultFrameNumber,
+ mNextZslStillResultFrameNumber, mNextShutterFrameNumber,
+ mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+ mDeviceInfo, mPhysicalDeviceInfoMap, mDistortionMappers,
+ mZoomRatioMappers, mRotateAndCropMappers);
+
+ *session = new AidlCamera3OfflineSession(mId, inputStream, offlineStreamSet,
+ std::move(bufferRecords), offlineReqs, offlineStates, offlineSession);
+
+ // Delete all streams that has been transferred to offline session
+ Mutex::Autolock l(mLock);
+ for (auto offlineStream : offlineSessionInfo.offlineStreams) {
+ int32_t id = offlineStream.id;
+ if (mInputStream != nullptr && id == mInputStream->getId()) {
+ mInputStream.clear();
+ } else {
+ mOutputStreams.remove(id);
+ }
+ }
+
+ // disconnect all other streams and switch to UNCONFIGURED state
+ if (mInputStream != nullptr) {
+ ret = mInputStream->disconnect();
+ if (ret != OK) {
+ SET_ERR_L("disconnect input stream failed!");
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ for (auto streamId : mOutputStreams.getStreamIds()) {
+ sp<Camera3StreamInterface> stream = mOutputStreams.get(streamId);
+ ret = stream->disconnect();
+ if (ret != OK) {
+ SET_ERR_L("disconnect output stream %d failed!", streamId);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ mInputStream.clear();
+ mOutputStreams.clear();
+ mNeedConfig = true;
+ internalUpdateStatusLocked(STATUS_UNCONFIGURED);
+ mOperatingMode = NO_MODE;
+ mIsConstrainedHighSpeedConfiguration = false;
+ mRequestThread->clearPreviousRequest();
+
+ return OK;
+ // TO be done by CameraDeviceClient/Camera3OfflineSession
+ // register the offline client to camera service
+ // Setup result passthing threads etc
+ // Initialize offline session so HAL can start sending callback to it (result Fmq)
+ // TODO: check how many onIdle callback will be sent
+ // Java side to make sure the CameraCaptureSession is properly closed
+}
+
+::ndk::ScopedAStatus AidlCamera3Device::AidlCameraDeviceCallbacks::requestStreamBuffers(
+ const std::vector<camera::device::BufferRequest>& bufReqs,
+ std::vector<aidl::android::hardware::camera::device::StreamBufferRet>* outBuffers,
+ aidl::android::hardware::camera::device::BufferRequestStatus* status) {
+
+ sp<AidlCamera3Device> p = mParent.promote();
+ if (p == nullptr) {
+ ALOGE("%s Parent AidlCameraDevice not alive, can't process callbacks", __FUNCTION__);
+ return ::ndk::ScopedAStatus::ok();
+ }
+ return p->requestStreamBuffers(bufReqs, outBuffers, status);
+}
+
+::ndk::ScopedAStatus AidlCamera3Device::requestStreamBuffers(
+ const std::vector<camera::device::BufferRequest>& bufReqs,
+ std::vector<aidl::android::hardware::camera::device::StreamBufferRet>* outBuffers,
+ aidl::android::hardware::camera::device::BufferRequestStatus* status) {
+
+ RequestBufferStates states {
+ mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams,
+ mSessionStatsBuilder, *this, *(mInterface), *this};
+ camera3::requestStreamBuffers(states, bufReqs, outBuffers, status);
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus AidlCamera3Device::AidlCameraDeviceCallbacks::returnStreamBuffers(
+ const std::vector<camera::device::StreamBuffer>& buffers) {
+ sp<AidlCamera3Device> p = mParent.promote();
+ if (p == nullptr) {
+ ALOGE("%s Parent AidlCameraDevice not alive, can't process callbacks", __FUNCTION__);
+ return ::ndk::ScopedAStatus::ok();
+ }
+ return p->returnStreamBuffers(buffers);
+}
+
+::ndk::ScopedAStatus AidlCamera3Device::returnStreamBuffers(
+ const std::vector<camera::device::StreamBuffer>& buffers) {
+ ReturnBufferStates states {
+ mId, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder,
+ *(mInterface)};
+ camera3::returnStreamBuffers(states, buffers);
+ return ::ndk::ScopedAStatus::ok();
+}
+
+AidlCamera3Device::AidlHalInterface::AidlHalInterface(
+ std::shared_ptr<aidl::android::hardware::camera::device::ICameraDeviceSession> &session,
+ std::shared_ptr<AidlRequestMetadataQueue> queue,
+ bool useHalBufManager, bool supportOfflineProcessing) :
+ HalInterface(useHalBufManager, supportOfflineProcessing),
+ mAidlSession(session),
+ mRequestMetadataQueue(queue) { }
+
+AidlCamera3Device::AidlHalInterface::AidlHalInterface(
+ std::shared_ptr<aidl::android::hardware::camera::device::ICameraDeviceSession>
+ &deviceSession,
+ std::shared_ptr<aidl::android::hardware::camera::device::ICameraInjectionSession>
+ &injectionSession, std::shared_ptr<AidlRequestMetadataQueue> queue,
+ bool useHalBufManager, bool supportOfflineProcessing) :
+ HalInterface(useHalBufManager, supportOfflineProcessing),
+ mAidlSession(deviceSession),
+ mAidlInjectionSession(injectionSession),
+ mRequestMetadataQueue(queue) { }
+
+bool AidlCamera3Device::AidlHalInterface::valid() {
+ return (mAidlSession != nullptr);
+}
+
+void AidlCamera3Device::AidlHalInterface::clear() {
+ mAidlSession.reset();
+}
+
+status_t AidlCamera3Device::AidlHalInterface::flush() {
+ ATRACE_NAME("CameraHal::flush");
+ if (!valid()) return INVALID_OPERATION;
+ status_t res = OK;
+
+ auto err = mAidlSession->flush();
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.getMessage());
+ res = AidlProviderInfo::mapToStatusT(err);
+ }
+
+ return res;
+}
+
+status_t AidlCamera3Device::AidlHalInterface::dump(int /*fd*/) {
+ ATRACE_NAME("CameraHal::dump");
+ if (!valid()) return INVALID_OPERATION;
+
+ // Handled by CameraProviderManager::dump
+
+ return OK;
+}
+
+status_t AidlCamera3Device::AidlHalInterface::repeatingRequestEnd(uint32_t frameNumber,
+ const std::vector<int32_t> &streamIds) {
+ ATRACE_NAME("AidlCameraHal::repeatingRequestEnd");
+ if (!valid()) return INVALID_OPERATION;
+
+ auto err = mAidlSession->repeatingRequestEnd(frameNumber, streamIds);
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.getMessage());
+ return AidlProviderInfo::mapToStatusT(err);
+ }
+
+ return OK;
+}
+
+status_t AidlCamera3Device::AidlHalInterface::close() {
+ ATRACE_NAME("CameraHal::close()");
+ if (!valid()) return INVALID_OPERATION;
+ status_t res = OK;
+
+ auto err = mAidlSession->close();
+ // Interface will be dead shortly anyway, so don't log errors
+ if (!err.isOk()) {
+ res = DEAD_OBJECT;
+ }
+
+ return res;
+}
+
+void AidlCamera3Device::AidlHalInterface::signalPipelineDrain(const std::vector<int>& streamIds) {
+ ATRACE_NAME("CameraHal::signalPipelineDrain");
+ if (!valid()) {
+ ALOGE("%s called on invalid camera!", __FUNCTION__);
+ return;
+ }
+
+ auto err = mAidlSession->signalStreamFlush(streamIds, mNextStreamConfigCounter - 1);
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.getMessage());
+ return;
+ }
+}
+
+bool AidlCamera3Device::AidlHalInterface::isReconfigurationRequired(
+ CameraMetadata& oldSessionParams, CameraMetadata& newSessionParams) {
+ // We do reconfiguration by default;
+ bool required = true;
+ if (mIsReconfigurationQuerySupported) {
+ aidl::android::hardware::camera::device::CameraMetadata oldParams, newParams;
+ camera_metadata_t* oldSessionMeta = const_cast<camera_metadata_t*>(
+ oldSessionParams.getAndLock());
+ uint8_t *oldSessionByteP = reinterpret_cast<uint8_t*>(oldSessionMeta);
+
+ camera_metadata_t* newSessionMeta = const_cast<camera_metadata_t*>(
+ newSessionParams.getAndLock());
+ uint8_t *newSessionByteP = reinterpret_cast<uint8_t*>(newSessionMeta);
+ // std::vector has no setToExternal, so we hacve to copy
+ oldParams.metadata.assign(oldSessionByteP,
+ oldSessionByteP + get_camera_metadata_size(oldSessionMeta));
+ newParams.metadata.assign(newSessionByteP,
+ newSessionByteP + get_camera_metadata_size(newSessionMeta));
+ auto err = mAidlSession->isReconfigurationRequired(oldParams, newParams, &required);
+ oldSessionParams.unlock(oldSessionMeta);
+ newSessionParams.unlock(newSessionMeta);
+ if (!err.isOk()) {
+ ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, err.getMessage());
+ return true;
+ }
+ }
+
+ return required;
+}
+
+status_t AidlCamera3Device::AidlHalInterface::constructDefaultRequestSettings(
+ camera_request_template_t templateId,
+ /*out*/ camera_metadata_t **requestTemplate) {
+ ATRACE_NAME("CameraAidlHal::constructDefaultRequestSettings");
+ using aidl::android::hardware::camera::device::RequestTemplate;
+ if (!valid()) return INVALID_OPERATION;
+ status_t res = OK;
+
+ RequestTemplate id;
+ aidl::android::hardware::camera::device::CameraMetadata request;
+ switch (templateId) {
+ case CAMERA_TEMPLATE_PREVIEW:
+ id = RequestTemplate::PREVIEW;
+ break;
+ case CAMERA_TEMPLATE_STILL_CAPTURE:
+ id = RequestTemplate::STILL_CAPTURE;
+ break;
+ case CAMERA_TEMPLATE_VIDEO_RECORD:
+ id = RequestTemplate::VIDEO_RECORD;
+ break;
+ case CAMERA_TEMPLATE_VIDEO_SNAPSHOT:
+ id = RequestTemplate::VIDEO_SNAPSHOT;
+ break;
+ case CAMERA_TEMPLATE_ZERO_SHUTTER_LAG:
+ id = RequestTemplate::ZERO_SHUTTER_LAG;
+ break;
+ case CAMERA_TEMPLATE_MANUAL:
+ id = RequestTemplate::MANUAL;
+ break;
+ default:
+ // Unknown template ID, or this HAL is too old to support it
+ return BAD_VALUE;
+ }
+ auto err = mAidlSession->constructDefaultRequestSettings(id, &request);
+
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.getMessage());
+ return AidlProviderInfo::mapToStatusT(err);
+ }
+ const camera_metadata *r =
+ reinterpret_cast<const camera_metadata_t*>(request.metadata.data());
+ size_t expectedSize = request.metadata.size();
+ int ret = validate_camera_metadata_structure(r, &expectedSize);
+ if (ret == OK || ret == CAMERA_METADATA_VALIDATION_SHIFTED) {
+ *requestTemplate = clone_camera_metadata(r);
+ if (*requestTemplate == nullptr) {
+ ALOGE("%s: Unable to clone camera metadata received from HAL",
+ __FUNCTION__);
+ res = UNKNOWN_ERROR;
+ }
+ } else {
+ ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
+ res = UNKNOWN_ERROR;
+ }
+
+ return res;
+}
+
+status_t AidlCamera3Device::AidlHalInterface::configureStreams(
+ const camera_metadata_t *sessionParams,
+ camera_stream_configuration *config, const std::vector<uint32_t>& bufferSizes) {
+ using camera::device::StreamType;
+ using camera::device::StreamConfigurationMode;
+
+ ATRACE_NAME("CameraHal::configureStreams");
+ if (!valid()) return INVALID_OPERATION;
+ status_t res = OK;
+
+ // Convert stream config to AIDL
+ std::set<int> activeStreams;
+ camera::device::StreamConfiguration requestedConfiguration;
+ requestedConfiguration.streams.resize(config->num_streams);
+ for (size_t i = 0; i < config->num_streams; i++) {
+ camera::device::Stream &dst = requestedConfiguration.streams[i];
+ camera3::camera_stream_t *src = config->streams[i];
+
+ Camera3Stream* cam3stream = Camera3Stream::cast(src);
+ cam3stream->setBufferFreedListener(this);
+ int streamId = cam3stream->getId();
+ StreamType streamType;
+ switch (src->stream_type) {
+ case CAMERA_STREAM_OUTPUT:
+ streamType = StreamType::OUTPUT;
+ break;
+ case CAMERA_STREAM_INPUT:
+ streamType = StreamType::INPUT;
+ break;
+ default:
+ ALOGE("%s: Stream %d: Unsupported stream type %d",
+ __FUNCTION__, streamId, config->streams[i]->stream_type);
+ return BAD_VALUE;
+ }
+ dst.id = streamId;
+ dst.streamType = streamType;
+ dst.width = src->width;
+ dst.height = src->height;
+ dst.usage = mapToAidlConsumerUsage(cam3stream->getUsage());
+ dst.rotation = mapToAidlStreamRotation((camera_stream_rotation_t) src->rotation);
+ dst.format = mapToAidlPixelFormat(cam3stream->isFormatOverridden() ?
+ cam3stream->getOriginalFormat() : src->format);
+ dst.dataSpace = mapToAidlDataspace(cam3stream->isDataSpaceOverridden() ?
+ cam3stream->getOriginalDataSpace() : src->data_space);
+
+ dst.bufferSize = bufferSizes[i];
+ if (src->physical_camera_id != nullptr) {
+ dst.physicalCameraId = src->physical_camera_id;
+ }
+ dst.groupId = cam3stream->getHalStreamGroupId();
+ dst.sensorPixelModesUsed.resize(src->sensor_pixel_modes_used.size());
+ size_t j = 0;
+ for (int mode : src->sensor_pixel_modes_used) {
+ dst.sensorPixelModesUsed[j++] = static_cast<SensorPixelMode>(mode);
+ }
+ dst.dynamicRangeProfile = mapToAidlDynamicProfile(src->dynamic_range_profile);
+ dst.useCase = static_cast<ScalerAvailableStreamUseCases>(src->use_case);
+ activeStreams.insert(streamId);
+ // Create Buffer ID map if necessary
+ mBufferRecords.tryCreateBufferCache(streamId);
+ }
+ // remove BufferIdMap for deleted streams
+ mBufferRecords.removeInactiveBufferCaches(activeStreams);
+
+ StreamConfigurationMode operationMode;
+ res = mapToAidlStreamConfigurationMode(
+ (camera_stream_configuration_mode_t) config->operation_mode,
+ /*out*/ &operationMode);
+ if (res != OK) {
+ return res;
+ }
+ requestedConfiguration.operationMode = operationMode;
+ size_t sessionParamSize = get_camera_metadata_size(sessionParams);
+ uint8_t *sessionParamP =
+ reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams));
+
+ // std::vector has no setToExternal, so we have to copy
+ requestedConfiguration.sessionParams.metadata.assign(
+ sessionParamP, sessionParamP + sessionParamSize);
+ requestedConfiguration.operationMode = operationMode;
+
+ // Invoke configureStreams
+ std::vector<camera::device::HalStream> finalConfiguration;
+
+ requestedConfiguration.streamConfigCounter = mNextStreamConfigCounter++;
+ requestedConfiguration.multiResolutionInputImage = config->input_is_multi_resolution;
+ auto err = mAidlSession->configureStreams(requestedConfiguration, &finalConfiguration);
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.getMessage());
+ return AidlProviderInfo::mapToStatusT(err);
+ }
+
+ // And convert output stream configuration from AIDL
+
+ for (size_t i = 0; i < config->num_streams; i++) {
+ camera3::camera_stream_t *dst = config->streams[i];
+ int streamId = Camera3Stream::cast(dst)->getId();
+
+ // Start scan at i, with the assumption that the stream order matches
+ size_t realIdx = i;
+ bool found = false;
+ size_t halStreamCount = finalConfiguration.size();
+ for (size_t idx = 0; idx < halStreamCount; idx++) {
+ if (finalConfiguration[realIdx].id == streamId) {
+ found = true;
+ break;
+ }
+ realIdx = (realIdx >= halStreamCount - 1) ? 0 : realIdx + 1;
+ }
+ if (!found) {
+ ALOGE("%s: Stream %d not found in stream configuration response from HAL",
+ __FUNCTION__, streamId);
+ return INVALID_OPERATION;
+ }
+ camera::device::HalStream &src = finalConfiguration[realIdx];
+
+ Camera3Stream* dstStream = Camera3Stream::cast(dst);
+ int overrideFormat = mapToFrameworkFormat(src.overrideFormat);
+ android_dataspace overrideDataSpace = mapToFrameworkDataspace(src.overrideDataSpace);
+
+ dstStream->setOfflineProcessingSupport(src.supportOffline);
+
+ if (dstStream->getOriginalFormat() != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+ dstStream->setFormatOverride(false);
+ dstStream->setDataSpaceOverride(false);
+ if (dst->format != overrideFormat) {
+ ALOGE("%s: Stream %d: Format override not allowed for format 0x%x", __FUNCTION__,
+ streamId, dst->format);
+ }
+ if (dst->data_space != overrideDataSpace) {
+ ALOGE("%s: Stream %d: DataSpace override not allowed for format 0x%x", __FUNCTION__,
+ streamId, dst->format);
+ }
+ } else {
+ bool needFormatOverride =
+ requestedConfiguration.streams[i].format != src.overrideFormat;
+ bool needDataspaceOverride =
+ requestedConfiguration.streams[i].dataSpace != src.overrideDataSpace;
+ // Override allowed with IMPLEMENTATION_DEFINED
+ dstStream->setFormatOverride(needFormatOverride);
+ dstStream->setDataSpaceOverride(needDataspaceOverride);
+ dst->format = overrideFormat;
+ dst->data_space = overrideDataSpace;
+ }
+
+ if (dst->stream_type == CAMERA_STREAM_INPUT) {
+ if (static_cast<int64_t>(src.producerUsage) != 0) {
+ ALOGE("%s: Stream %d: INPUT streams must have 0 for producer usage",
+ __FUNCTION__, streamId);
+ return INVALID_OPERATION;
+ }
+ dstStream->setUsage(
+ mapConsumerToFrameworkUsage(src.consumerUsage));
+ } else {
+ // OUTPUT
+ if (static_cast<int64_t>(src.consumerUsage) != 0) {
+ ALOGE("%s: Stream %d: OUTPUT streams must have 0 for consumer usage",
+ __FUNCTION__, streamId);
+ return INVALID_OPERATION;
+ }
+ dstStream->setUsage(
+ mapProducerToFrameworkUsage(src.producerUsage));
+ }
+ dst->max_buffers = src.maxBuffers;
+ }
+
+ return res;
+}
+
+status_t AidlCamera3Device::AidlHalInterface::configureInjectedStreams(
+ const camera_metadata_t* sessionParams, camera_stream_configuration* config,
+ const std::vector<uint32_t>& bufferSizes,
+ const CameraMetadata& cameraCharacteristics) {
+ using camera::device::StreamType;
+ using camera::device::StreamConfigurationMode;
+
+ ATRACE_NAME("InjectionCameraHal::configureStreams");
+ if (!valid()) return INVALID_OPERATION;
+ status_t res = OK;
+
+ if (config->input_is_multi_resolution) {
+ ALOGE("%s: Injection camera device doesn't support multi-resolution input "
+ "stream", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ // Convert stream config to AIDL
+ std::set<int> activeStreams;
+ camera::device::StreamConfiguration requestedConfiguration;
+ requestedConfiguration.streams.resize(config->num_streams);
+ for (size_t i = 0; i < config->num_streams; i++) {
+ camera::device::Stream& dst = requestedConfiguration.streams[i];
+ camera3::camera_stream_t* src = config->streams[i];
+
+ Camera3Stream* cam3stream = Camera3Stream::cast(src);
+ cam3stream->setBufferFreedListener(this);
+ int streamId = cam3stream->getId();
+ StreamType streamType;
+ switch (src->stream_type) {
+ case CAMERA_STREAM_OUTPUT:
+ streamType = StreamType::OUTPUT;
+ break;
+ case CAMERA_STREAM_INPUT:
+ streamType = StreamType::INPUT;
+ break;
+ default:
+ ALOGE("%s: Stream %d: Unsupported stream type %d", __FUNCTION__,
+ streamId, config->streams[i]->stream_type);
+ return BAD_VALUE;
+ }
+ dst.id = streamId;
+ dst.streamType = streamType;
+ dst.width = src->width;
+ dst.height = src->height;
+ dst.usage = mapToAidlConsumerUsage(cam3stream->getUsage());
+ dst.rotation = mapToAidlStreamRotation((camera_stream_rotation_t)src->rotation);
+ dst.format =
+ mapToAidlPixelFormat(cam3stream->isFormatOverridden() ? cam3stream->getOriginalFormat()
+ : src->format);
+ dst.dataSpace =
+ mapToAidlDataspace(cam3stream->isDataSpaceOverridden() ?
+ cam3stream->getOriginalDataSpace() : src->data_space);
+ dst.bufferSize = bufferSizes[i];
+ if (src->physical_camera_id != nullptr) {
+ dst.physicalCameraId = src->physical_camera_id;
+ }
+ dst.groupId = cam3stream->getHalStreamGroupId();
+ dst.sensorPixelModesUsed.resize(src->sensor_pixel_modes_used.size());
+ size_t j = 0;
+ for (int mode : src->sensor_pixel_modes_used) {
+ dst.sensorPixelModesUsed[j++] = static_cast<SensorPixelMode>(mode);
+ }
+ activeStreams.insert(streamId);
+ // Create Buffer ID map if necessary
+ mBufferRecords.tryCreateBufferCache(streamId);
+ }
+ // remove BufferIdMap for deleted streams
+ mBufferRecords.removeInactiveBufferCaches(activeStreams);
+
+ StreamConfigurationMode operationMode;
+ res = mapToAidlStreamConfigurationMode(
+ (camera_stream_configuration_mode_t)config->operation_mode,
+ /*out*/ &operationMode);
+ if (res != OK) {
+ return res;
+ }
+ requestedConfiguration.operationMode = operationMode;
+ size_t sessionParamSize = get_camera_metadata_size(sessionParams);
+ uint8_t *sessionParamP =
+ reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams));
+ requestedConfiguration.operationMode = operationMode;
+ requestedConfiguration.sessionParams.metadata.assign(
+ sessionParamP, sessionParamP + sessionParamSize);
+
+ // See which version of HAL we have
+ if (mAidlInjectionSession != nullptr) {
+ requestedConfiguration.streamConfigCounter = mNextStreamConfigCounter++;
+ requestedConfiguration.multiResolutionInputImage = config->input_is_multi_resolution;
+
+ const camera_metadata_t* rawMetadata = cameraCharacteristics.getAndLock();
+ uint8_t *aidlCharsP =
+ reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(rawMetadata));
+ aidl::android::hardware::camera::device::CameraMetadata aidlChars;
+ aidlChars.metadata.assign(aidlCharsP, aidlCharsP + get_camera_metadata_size(rawMetadata));
+ cameraCharacteristics.unlock(rawMetadata);
+
+ auto err = mAidlInjectionSession->configureInjectionStreams(requestedConfiguration,
+ aidlChars);
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.getMessage());
+ return AidlProviderInfo::mapToStatusT(err);
+ }
+ } else {
+ ALOGE("%s: mAidlInjectionSession == nullptr, the injection not supported ", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ return res;
+}
+
+status_t AidlCamera3Device::AidlHalInterface::processBatchCaptureRequests(
+ std::vector<camera_capture_request_t*>& requests,/*out*/uint32_t* numRequestProcessed) {
+ ATRACE_NAME("CameraHal::processBatchCaptureRequests");
+ if (!valid()) return INVALID_OPERATION;
+
+ std::vector<camera::device::CaptureRequest> captureRequests;
+ size_t batchSize = requests.size();
+ if (batchSize > INT_MAX) {
+ ALOGE("%s batchSize %zu > INT_MAX, aidl interface cannot handle batch size", __FUNCTION__,
+ batchSize);
+ return BAD_VALUE;
+ }
+ captureRequests.resize(batchSize);
+ std::vector<native_handle_t*> handlesCreated;
+ std::vector<std::pair<int32_t, int32_t>> inflightBuffers;
+
+ status_t res = OK;
+ for (size_t i = 0; i < batchSize; i++) {
+ res = wrapAsAidlRequest(requests[i], /*out*/&captureRequests[i],
+ /*out*/&handlesCreated, /*out*/&inflightBuffers);
+
+ if (res != OK) {
+ mBufferRecords.popInflightBuffers(inflightBuffers);
+ cleanupNativeHandles(&handlesCreated);
+ return res;
+ }
+ }
+
+ std::vector<camera::device::BufferCache> cachesToRemove;
+ {
+ std::lock_guard<std::mutex> lock(mFreedBuffersLock);
+ for (auto& pair : mFreedBuffers) {
+ // The stream might have been removed since onBufferFreed
+ if (mBufferRecords.isStreamCached(pair.first)) {
+ cachesToRemove.push_back({pair.first, static_cast<int64_t>(pair.second)});
+ }
+ }
+ mFreedBuffers.clear();
+ }
+
+ *numRequestProcessed = 0;
+
+ // Write metadata to FMQ.
+ for (size_t i = 0; i < batchSize; i++) {
+ camera_capture_request_t* request = requests[i];
+ camera::device::CaptureRequest* captureRequest;
+ captureRequest = &captureRequests[i];
+
+ if (request->settings != nullptr) {
+ size_t settingsSize = get_camera_metadata_size(request->settings);
+ if (mRequestMetadataQueue != nullptr && mRequestMetadataQueue->write(
+ reinterpret_cast<const int8_t*>(request->settings), settingsSize)) {
+ captureRequest->settings.metadata.resize(0);
+ captureRequest->fmqSettingsSize = settingsSize;
+ } else {
+ if (mRequestMetadataQueue != nullptr) {
+ ALOGW("%s: couldn't utilize fmq, fallback to hwbinder", __FUNCTION__);
+ }
+ uint8_t *settingsP =
+ reinterpret_cast<uint8_t*>(
+ const_cast<camera_metadata_t*>(request->settings));
+ size_t settingsSize = get_camera_metadata_size(request->settings);
+ captureRequest->settings.metadata.assign(settingsP, settingsP + settingsSize);
+ captureRequest->fmqSettingsSize = 0u;
+ }
+ } else {
+ // A null request settings maps to a size-0 CameraMetadata
+ captureRequest->settings.metadata.resize(0);
+ captureRequest->fmqSettingsSize = 0u;
+ }
+
+ captureRequest ->inputWidth = request->input_width;
+ captureRequest->inputHeight = request->input_height;
+
+ std::vector<camera::device::PhysicalCameraSetting>& physicalCameraSettings =
+ captureRequest->physicalCameraSettings;
+ physicalCameraSettings.resize(request->num_physcam_settings);
+ for (size_t j = 0; j < request->num_physcam_settings; j++) {
+ if (request->physcam_settings != nullptr) {
+ size_t settingsSize = get_camera_metadata_size(request->physcam_settings[j]);
+ if (mRequestMetadataQueue != nullptr && mRequestMetadataQueue->write(
+ reinterpret_cast<const int8_t*>(request->physcam_settings[j]),
+ settingsSize)) {
+ physicalCameraSettings[j].settings.metadata.resize(0);
+ physicalCameraSettings[j].fmqSettingsSize = settingsSize;
+ } else {
+ if (mRequestMetadataQueue != nullptr) {
+ ALOGW("%s: couldn't utilize fmq, fallback to hwbinder", __FUNCTION__);
+ }
+ uint8_t *physicalSettingsP =
+ reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(
+ request->physcam_settings[j]));
+ physicalCameraSettings[j].settings.metadata.assign(physicalSettingsP,
+ physicalSettingsP + settingsSize);
+ physicalCameraSettings[j].fmqSettingsSize = 0u;
+ }
+ } else {
+ physicalCameraSettings[j].fmqSettingsSize = 0u;
+ physicalCameraSettings[j].settings.metadata.resize(0);
+ }
+ physicalCameraSettings[j].physicalCameraId = request->physcam_id[j];
+ }
+ }
+
+ int32_t numRequests = 0;
+ auto retS = mAidlSession->processCaptureRequest(captureRequests, cachesToRemove,
+ &numRequests);
+ if (!retS.isOk()) {
+ res = AidlProviderInfo::mapToStatusT(retS);
+ }
+ if (res == OK) {
+ if (numRequests < 0) {
+ res = INVALID_OPERATION;
+ } else {
+ *numRequestProcessed = static_cast<uint32_t>(numRequests);
+ }
+
+ }
+ if (res == OK && *numRequestProcessed == batchSize) {
+ if (mAidlSession->isRemote()) {
+ // Only close acquire fence FDs when the AIDL transaction succeeds (so the FDs have been
+ // sent to camera HAL processes)
+ cleanupNativeHandles(&handlesCreated, /*closeFd*/true);
+ } else {
+ // In passthrough mode the FDs are now owned by HAL
+ cleanupNativeHandles(&handlesCreated);
+ }
+ } else {
+ ALOGE("%s Error with processCaptureRequest %s ", __FUNCTION__, retS.getMessage());
+ mBufferRecords.popInflightBuffers(inflightBuffers);
+ cleanupNativeHandles(&handlesCreated);
+ }
+ return res;
+}
+
+status_t AidlCamera3Device::AidlHalInterface::wrapAsAidlRequest(camera_capture_request_t* request,
+ /*out*/camera::device::CaptureRequest* captureRequest,
+ /*out*/std::vector<native_handle_t*>* handlesCreated,
+ /*out*/std::vector<std::pair<int32_t, int32_t>>* inflightBuffers) {
+ using camera::device::BufferStatus;
+ using camera::device::StreamBuffer;
+ ATRACE_CALL();
+ if (captureRequest == nullptr || handlesCreated == nullptr || inflightBuffers == nullptr) {
+ ALOGE("%s: captureRequest (%p), handlesCreated (%p), and inflightBuffers(%p) "
+ "must not be null", __FUNCTION__, captureRequest, handlesCreated, inflightBuffers);
+ return BAD_VALUE;
+ }
+
+ captureRequest->frameNumber = request->frame_number;
+
+ captureRequest->fmqSettingsSize = 0;
+
+ {
+ if (request->input_buffer != nullptr) {
+ int32_t streamId = Camera3Stream::cast(request->input_buffer->stream)->getId();
+ buffer_handle_t buf = *(request->input_buffer->buffer);
+ auto pair = getBufferId(buf, streamId);
+ bool isNewBuffer = pair.first;
+ uint64_t bufferId = pair.second;
+ captureRequest->inputBuffer.streamId = streamId;
+ captureRequest->inputBuffer.bufferId = bufferId;
+ captureRequest->inputBuffer.buffer =
+ (isNewBuffer) ? camera3::dupToAidlIfNotNull(buf) :
+ aidl::android::hardware::common::NativeHandle();
+ captureRequest->inputBuffer.status = BufferStatus::OK;
+ native_handle_t *acquireFence = nullptr;
+ if (request->input_buffer->acquire_fence != -1) {
+ acquireFence = native_handle_create(1,0);
+ acquireFence->data[0] = request->input_buffer->acquire_fence;
+ handlesCreated->push_back(acquireFence);
+ }
+ // duping here is okay, in aidl ownership is not given to aidl_handle
+ captureRequest->inputBuffer.acquireFence = camera3::dupToAidlIfNotNull(acquireFence);
+ captureRequest->inputBuffer.releaseFence =
+ aidl::android::hardware::common::NativeHandle();
+
+ mBufferRecords.pushInflightBuffer(captureRequest->frameNumber, streamId,
+ request->input_buffer->buffer);
+ inflightBuffers->push_back(std::make_pair(captureRequest->frameNumber, streamId));
+ } else {
+ captureRequest->inputBuffer.streamId = -1;
+ captureRequest->inputBuffer.bufferId = BUFFER_ID_NO_BUFFER;
+ }
+
+ captureRequest->outputBuffers.resize(request->num_output_buffers);
+ for (size_t i = 0; i < request->num_output_buffers; i++) {
+ const camera_stream_buffer_t *src = request->output_buffers + i;
+ StreamBuffer &dst = captureRequest->outputBuffers[i];
+ int32_t streamId = Camera3Stream::cast(src->stream)->getId();
+ if (src->buffer != nullptr) {
+ buffer_handle_t buf = *(src->buffer);
+ auto pair = getBufferId(buf, streamId);
+ bool isNewBuffer = pair.first;
+ dst.bufferId = pair.second;
+ dst.buffer = isNewBuffer ?
+ camera3::dupToAidlIfNotNull(buf) :
+ aidl::android::hardware::common::NativeHandle();
+ native_handle_t *acquireFence = nullptr;
+ if (src->acquire_fence != -1) {
+ acquireFence = native_handle_create(1,0);
+ acquireFence->data[0] = src->acquire_fence;
+ handlesCreated->push_back(acquireFence);
+ }
+ dst.acquireFence = camera3::dupToAidlIfNotNull(acquireFence);
+ } else if (mUseHalBufManager) {
+ // HAL buffer management path
+ dst.bufferId = BUFFER_ID_NO_BUFFER;
+ dst.buffer = aidl::android::hardware::common::NativeHandle();
+ dst.acquireFence = aidl::android::hardware::common::NativeHandle();
+ } else {
+ ALOGE("%s: cannot send a null buffer in capture request!", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ dst.streamId = streamId;
+ dst.status = BufferStatus::OK;
+ dst.releaseFence = aidl::android::hardware::common::NativeHandle();
+
+ // Output buffers are empty when using HAL buffer manager
+ if (!mUseHalBufManager) {
+ mBufferRecords.pushInflightBuffer(
+ captureRequest->frameNumber, streamId, src->buffer);
+ inflightBuffers->push_back(std::make_pair(captureRequest->frameNumber, streamId));
+ }
+ }
+ }
+ return OK;
+}
+
+status_t AidlCamera3Device::AidlHalInterface::switchToOffline(
+ const std::vector<int32_t>& streamsToKeep,
+ /*out*/aidl::android::hardware::camera::device::CameraOfflineSessionInfo*
+ offlineSessionInfo,
+ /*out*/std::shared_ptr<aidl::android::hardware::camera::device::ICameraOfflineSession>*
+ offlineSession,
+ /*out*/camera3::BufferRecords* bufferRecords) {
+ ATRACE_NAME("CameraHal::switchToOffline");
+ if (!valid()) {
+ ALOGE("%s called on invalid camera!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ if (offlineSessionInfo == nullptr || offlineSession == nullptr || bufferRecords == nullptr) {
+ ALOGE("%s: output arguments must not be null!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ auto err = mAidlSession->switchToOffline(streamsToKeep, offlineSessionInfo, offlineSession);
+
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.getMessage());
+ return AidlProviderInfo::mapToStatusT(err);
+ }
+
+ return verifyBufferCaches(offlineSessionInfo, bufferRecords);
+}
+
+AidlCamera3Device::AidlRequestThread::AidlRequestThread(wp<Camera3Device> parent,
+ sp<camera3::StatusTracker> statusTracker,
+ sp<HalInterface> interface,
+ const Vector<int32_t>& sessionParamKeys,
+ bool useHalBufManager,
+ bool supportCameraMute) :
+ RequestThread(parent, statusTracker, interface, sessionParamKeys, useHalBufManager,
+ supportCameraMute) {}
+
+status_t AidlCamera3Device::AidlRequestThread::switchToOffline(
+ const std::vector<int32_t>& streamsToKeep,
+ /*out*/camera::device::CameraOfflineSessionInfo* offlineSessionInfo,
+ /*out*/std::shared_ptr<camera::device::ICameraOfflineSession>* offlineSession,
+ /*out*/camera3::BufferRecords* bufferRecords) {
+ Mutex::Autolock l(mRequestLock);
+ clearRepeatingRequestsLocked(/*lastFrameNumber*/nullptr);
+
+ // Wait until request thread is fully stopped
+ // TBD: check if request thread is being paused by other APIs (shouldn't be)
+
+ // We could also check for mRepeatingRequests.empty(), but the API interface
+ // is serialized by Camera3Device::mInterfaceLock so no one should be able to submit any
+ // new requests during the call; hence skip that check.
+ bool queueEmpty = mNextRequests.empty() && mRequestQueue.empty();
+ while (!queueEmpty) {
+ status_t res = mRequestSubmittedSignal.waitRelative(mRequestLock, kRequestSubmitTimeout);
+ if (res == TIMED_OUT) {
+ ALOGE("%s: request thread failed to submit one request within timeout!", __FUNCTION__);
+ return res;
+ } else if (res != OK) {
+ ALOGE("%s: request thread failed to submit a request: %s (%d)!",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+ queueEmpty = mNextRequests.empty() && mRequestQueue.empty();
+ }
+ return (static_cast<AidlHalInterface *>(mInterface.get()))->switchToOffline(
+ streamsToKeep, offlineSessionInfo, offlineSession, bufferRecords);
+}
+
+status_t AidlCamera3Device::AidlCamera3DeviceInjectionMethods::injectionInitialize(
+ const String8& injectedCamId, sp<CameraProviderManager> manager,
+ const std::shared_ptr<camera::device::ICameraDeviceCallback>&callback) {
+ ATRACE_CALL();
+ Mutex::Autolock lock(mInjectionLock);
+
+ if (manager == nullptr) {
+ ALOGE("%s: manager does not exist!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ sp<Camera3Device> parent = mParent.promote();
+ if (parent == nullptr) {
+ ALOGE("%s: parent does not exist!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ if (parent->getTransportType() != IPCTransport::AIDL) {
+ ALOGE("%s Parent transport not AIDL for injected camera id %s, aborting", __FUNCTION__,
+ injectedCamId.c_str());
+ return INVALID_OPERATION;
+ }
+ mInjectedCamId = injectedCamId;
+ std::shared_ptr<camera::device::ICameraInjectionSession> injectionSession;
+ ATRACE_BEGIN("Injection CameraHal::openSession");
+ status_t res = manager->openAidlInjectionSession(injectedCamId.string(), callback,
+ /*out*/ &injectionSession);
+ ATRACE_END();
+ if (res != OK) {
+ ALOGE("Injection camera could not open camera session: %s (%d)",
+ strerror(-res), res);
+ return res;
+ }
+ std::shared_ptr<camera::device::ICameraDeviceSession> deviceSession = nullptr;
+ auto ret = injectionSession->getCameraDeviceSession(&deviceSession);
+ if (!ret.isOk() || deviceSession == nullptr) {
+ ALOGE("%s Camera injection session couldn't return ICameraDeviceSession", __FUNCTION__);
+ return AidlProviderInfo::mapToStatusT(ret);
+ }
+
+ std::shared_ptr<AidlRequestMetadataQueue> queue;
+ ::aidl::android::hardware::common::fmq::MQDescriptor<
+ int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite> desc;
+
+ ::ndk::ScopedAStatus requestQueueRet = deviceSession->getCaptureRequestMetadataQueue(&desc);
+ if (!requestQueueRet.isOk()) {
+ ALOGE("Injection camera transaction error when getting result metadata queue from camera"
+ " session: %s", requestQueueRet.getMessage());
+ return AidlProviderInfo::mapToStatusT(requestQueueRet);
+ }
+ queue = std::make_unique<AidlRequestMetadataQueue>(desc);
+ if (!queue->isValid() || queue->availableToWrite() <= 0) {
+ ALOGE("HAL returns empty result metadata fmq, not use it");
+ queue = nullptr;
+ // Don't use resQueue onwards.
+ }
+
+ std::unique_ptr<AidlResultMetadataQueue>& resQueue = mInjectionResultMetadataQueue;
+ ::aidl::android::hardware::common::fmq::MQDescriptor<
+ int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite> resDesc;
+ ::ndk::ScopedAStatus resultQueueRet = deviceSession->getCaptureResultMetadataQueue(&resDesc);
+ if (!resultQueueRet.isOk()) {
+ ALOGE("Transaction error when getting result metadata queue from camera session: %s",
+ resultQueueRet.getMessage());
+ return AidlProviderInfo::mapToStatusT(resultQueueRet);
+ }
+ resQueue = std::make_unique<AidlResultMetadataQueue>(resDesc);
+ if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
+ ALOGE("HAL returns empty result metadata fmq, not use it");
+ resQueue = nullptr;
+ // Don't use resQueue onwards.
+ }
+
+ ALOGV("%s: Injection camera interface = new HalInterface()", __FUNCTION__);
+
+ mInjectedCamHalInterface =
+ new AidlHalInterface(deviceSession, injectionSession, queue, parent->mUseHalBufManager,
+ parent->mSupportOfflineProcessing);
+ if (mInjectedCamHalInterface == nullptr) {
+ ALOGE("%s: mInjectedCamHalInterface does not exist!", __FUNCTION__);
+ return DEAD_OBJECT;
+ }
+
+ return OK;
+}
+
+status_t AidlCamera3Device::AidlCamera3DeviceInjectionMethods::replaceHalInterface(
+ sp<HalInterface> newHalInterface, bool keepBackup) {
+ Mutex::Autolock lock(mInjectionLock);
+ if (newHalInterface.get() == nullptr) {
+ ALOGE("%s: The newHalInterface does not exist, to stop replacing.",
+ __FUNCTION__);
+ return DEAD_OBJECT;
+ }
+
+ sp<Camera3Device> parent = mParent.promote();
+ if (parent == nullptr) {
+ ALOGE("%s: parent does not exist!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if (parent->getTransportType() != IPCTransport::AIDL ||
+ newHalInterface->getTransportType() != IPCTransport::AIDL) {
+ ALOGE("%s Parent transport not AIDL for replacing hal interface", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ AidlCamera3Device *aidlParent = static_cast<AidlCamera3Device *>(parent.get());
+ if (keepBackup) {
+ if (mBackupHalInterface == nullptr) {
+ mBackupHalInterface = parent->mInterface;
+ }
+ if (mBackupResultMetadataQueue == nullptr) {
+ mBackupResultMetadataQueue = std::move(aidlParent->mResultMetadataQueue);
+ aidlParent->mResultMetadataQueue = std::move(mInjectionResultMetadataQueue);
+ }
+ } else {
+ mBackupHalInterface = nullptr;
+ aidlParent->mResultMetadataQueue = std::move(mBackupResultMetadataQueue);
+ mBackupResultMetadataQueue = nullptr;
+ }
+ parent->mInterface = newHalInterface;
+ return OK;
+}
+
+status_t AidlCamera3Device::injectionCameraInitialize(const String8 &injectedCamId,
+ sp<CameraProviderManager> manager) {
+ return (static_cast<AidlCamera3DeviceInjectionMethods *>
+ (mInjectionMethods.get()))->injectionInitialize(injectedCamId, manager,
+ std::shared_ptr<camera::device::ICameraDeviceCallback>(mCallbacks));
+};
+
+sp<Camera3Device::RequestThread> AidlCamera3Device::createNewRequestThread(
+ wp<Camera3Device> parent, sp<camera3::StatusTracker> statusTracker,
+ sp<Camera3Device::HalInterface> interface,
+ const Vector<int32_t>& sessionParamKeys,
+ bool useHalBufManager,
+ bool supportCameraMute) {
+ return new AidlRequestThread(parent, statusTracker, interface, sessionParamKeys,
+ useHalBufManager, supportCameraMute);
+};
+
+sp<Camera3Device::Camera3DeviceInjectionMethods>
+AidlCamera3Device::createCamera3DeviceInjectionMethods(wp<Camera3Device> parent) {
+ return new AidlCamera3DeviceInjectionMethods(parent);
+}
+
+}; // namespace android
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h
new file mode 100644
index 0000000..e7a7eec
--- /dev/null
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2022 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_SERVERS_AIDLCAMERA3DEVICE_H
+#define ANDROID_SERVERS_AIDLCAMERA3DEVICE_H
+
+#include "../Camera3Device.h"
+#include "AidlCamera3OutputUtils.h"
+#include <fmq/AidlMessageQueue.h>
+
+#include <aidl/android/hardware/camera/device/BnCameraDeviceCallback.h>
+#include <aidl/android/hardware/camera/device/ICameraDevice.h>
+#include <aidl/android/hardware/camera/device/ICameraInjectionSession.h>
+namespace android {
+
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::android::AidlMessageQueue;
+
+/**
+ * CameraDevice for AIDL HAL devices.
+ */
+class AidlCamera3Device :
+ public Camera3Device {
+ public:
+
+ using AidlRequestMetadataQueue = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
+ class AidlCameraDeviceCallbacks;
+ friend class AidlCameraDeviceCallbacks;
+ explicit AidlCamera3Device(const String8& id, bool overrideForPerfClass,
+ bool legacyClient = false);
+
+ virtual ~AidlCamera3Device() { }
+
+ static aidl::android::hardware::graphics::common::PixelFormat mapToAidlPixelFormat(
+ int frameworkFormat);
+ static aidl::android::hardware::graphics::common::Dataspace mapToAidlDataspace(
+ android_dataspace dataSpace);
+ static aidl::android::hardware::graphics::common::BufferUsage mapToAidlConsumerUsage(
+ uint64_t usage);
+ static aidl::android::hardware::camera::device::StreamRotation
+ mapToAidlStreamRotation(camera_stream_rotation_t rotation);
+
+ static status_t mapToAidlStreamConfigurationMode(
+ camera_stream_configuration_mode_t operationMode,
+ aidl::android::hardware::camera::device::StreamConfigurationMode *mode);
+
+ static int mapToFrameworkFormat(
+ aidl::android::hardware::graphics::common::PixelFormat pixelFormat);
+ static android_dataspace mapToFrameworkDataspace(
+ aidl::android::hardware::graphics::common::Dataspace);
+ static uint64_t mapConsumerToFrameworkUsage(
+ aidl::android::hardware::graphics::common::BufferUsage usage);
+ static uint64_t mapProducerToFrameworkUsage(
+ aidl::android::hardware::graphics::common::BufferUsage usage);
+
+ virtual status_t switchToOffline(const std::vector<int32_t>& /*streamsToKeep*/,
+ /*out*/ sp<CameraOfflineSessionBase>* /*session*/) override;
+
+ status_t initialize(sp<CameraProviderManager> manager, const String8& monitorTags) override;
+ class AidlHalInterface : public Camera3Device::HalInterface {
+ public:
+ AidlHalInterface(std::shared_ptr<
+ aidl::android::hardware::camera::device::ICameraDeviceSession> &session,
+ std::shared_ptr<AidlRequestMetadataQueue> queue,
+ bool useHalBufManager, bool supportOfflineProcessing);
+ AidlHalInterface(
+ std::shared_ptr<aidl::android::hardware::camera::device::ICameraDeviceSession>
+ &deviceSession,
+ std::shared_ptr<
+ aidl::android::hardware::camera::device::ICameraInjectionSession> &injectionSession,
+ std::shared_ptr<AidlRequestMetadataQueue> queue,
+ bool useHalBufManager, bool supportOfflineProcessing);
+
+ virtual IPCTransport getTransportType() {return IPCTransport::AIDL; }
+
+
+ // Returns true if constructed with a valid device or session, and not yet cleared
+ virtual bool valid() override;
+
+ // Reset this HalInterface object (does not call close())
+ virtual void clear() override;
+
+ // Caller takes ownership of requestTemplate
+ virtual status_t constructDefaultRequestSettings(camera_request_template templateId,
+ /*out*/ camera_metadata_t **requestTemplate) override;
+
+ virtual status_t configureStreams(const camera_metadata_t *sessionParams,
+ /*inout*/ camera_stream_configuration_t *config,
+ const std::vector<uint32_t>& bufferSizes) override;
+ // The injection camera configures the streams to hal.
+ virtual status_t configureInjectedStreams(
+ const camera_metadata_t* sessionParams,
+ /*inout*/ camera_stream_configuration_t* config,
+ const std::vector<uint32_t>& bufferSizes,
+ const CameraMetadata& cameraCharacteristics) override;
+
+ // When the call succeeds, the ownership of acquire fences in requests is transferred to
+ // HalInterface. More specifically, the current implementation will send the fence to
+ // HAL process and close the FD in cameraserver process. When the call fails, the ownership
+ // of the acquire fence still belongs to the caller.
+ virtual status_t processBatchCaptureRequests(
+ std::vector<camera_capture_request_t*>& requests,
+ /*out*/uint32_t* numRequestProcessed) override;
+
+ // Calls into the HAL interface
+ virtual status_t flush() override;
+ virtual status_t dump(int fd) override;
+ virtual status_t close() override;
+ virtual void signalPipelineDrain(const std::vector<int>& streamIds) override;
+ virtual bool isReconfigurationRequired(CameraMetadata& oldSessionParams,
+ CameraMetadata& newSessionParams) override;
+
+ virtual status_t repeatingRequestEnd(uint32_t ,
+ const std::vector<int32_t> &) override;
+
+ status_t switchToOffline(
+ const std::vector<int32_t>& streamsToKeep,
+ /*out*/aidl::android::hardware::camera::device::CameraOfflineSessionInfo*
+ offlineSessionInfo,
+ /*out*/std::shared_ptr<aidl::android::hardware::camera::device::ICameraOfflineSession>*
+ offlineSession,
+ /*out*/camera3::BufferRecords* bufferRecords);
+
+ private:
+
+ // Always valid
+ std::shared_ptr<aidl::android::hardware::camera::device::ICameraDeviceSession>
+ mAidlSession = nullptr;
+ //Valid for injection sessions
+ std::shared_ptr<aidl::android::hardware::camera::device::ICameraInjectionSession>
+ mAidlInjectionSession = nullptr;
+
+ status_t wrapAsAidlRequest(camera_capture_request_t* request,
+ /*out*/aidl::android::hardware::camera::device::CaptureRequest* captureRequest,
+ /*out*/std::vector<native_handle_t*>* handlesCreated,
+ /*out*/std::vector<std::pair<int32_t, int32_t>>* inflightBuffers);
+
+ std::shared_ptr<AidlRequestMetadataQueue> mRequestMetadataQueue;
+ }; // class AidlHalInterface
+
+ /**
+ * Implementation of aidl::android::hardware::camera::device::ICameraDeviceCallback
+ */
+ ::ndk::ScopedAStatus processCaptureResult(
+ const std::vector<aidl::android::hardware::camera::device::CaptureResult>& results);
+ ::ndk::ScopedAStatus notify(
+ const std::vector<aidl::android::hardware::camera::device::NotifyMsg>& msgs);
+
+ ::ndk::ScopedAStatus requestStreamBuffers(
+ const std::vector<aidl::android::hardware::camera::device::BufferRequest>& bufReqs,
+ std::vector<aidl::android::hardware::camera::device::StreamBufferRet>* outBuffers,
+ aidl::android::hardware::camera::device::BufferRequestStatus* status);
+
+ ::ndk::ScopedAStatus returnStreamBuffers(
+ const std::vector<aidl::android::hardware::camera::device::StreamBuffer>& buffers);
+
+ class AidlRequestThread : public Camera3Device::RequestThread {
+ public:
+ AidlRequestThread(wp<Camera3Device> parent,
+ sp<camera3::StatusTracker> statusTracker,
+ sp<HalInterface> interface,
+ const Vector<int32_t>& sessionParamKeys,
+ bool useHalBufManager,
+ bool supportCameraMute);
+
+ status_t switchToOffline(
+ const std::vector<int32_t>& streamsToKeep,
+ /*out*/aidl::android::hardware::camera::device::CameraOfflineSessionInfo*
+ offlineSessionInfo,
+ /*out*/std::shared_ptr<
+ aidl::android::hardware::camera::device::ICameraOfflineSession>*
+ offlineSession,
+ /*out*/camera3::BufferRecords* bufferRecords);
+ }; // class AidlRequestThread
+
+ class AidlCamera3DeviceInjectionMethods : public Camera3DeviceInjectionMethods {
+ public:
+ // Initialize the injection camera and generate an hal interface.
+ status_t injectionInitialize(
+ const String8& injectedCamId, sp<CameraProviderManager> manager,
+ const std::shared_ptr<
+ aidl::android::hardware::camera::device::ICameraDeviceCallback>&
+ callback);
+ AidlCamera3DeviceInjectionMethods(wp<Camera3Device> parent) :
+ Camera3DeviceInjectionMethods(parent) { };
+ ~AidlCamera3DeviceInjectionMethods() {}
+ private:
+ // Backup of the original camera hal result FMQ.
+ std::unique_ptr<AidlResultMetadataQueue> mBackupResultMetadataQueue;
+
+ // FMQ writes the result for the injection camera. Must be guarded by
+ // mProcessCaptureResultLock.
+ std::unique_ptr<AidlResultMetadataQueue> mInjectionResultMetadataQueue;
+
+ // Use injection camera hal interface to replace and backup original
+ // camera hal interface.
+ virtual status_t replaceHalInterface(sp<HalInterface> newHalInterface,
+ bool keepBackup) override;
+ };
+
+ // We need a separate class which inherits from AIDL ICameraDeviceCallbacks
+ // since we use the ndk backend for AIDL HAL interfaces. The ndk backend of
+ // ICameraDeviceCallbacks doesn't support sp<> (since it doesn't inherit
+ // from RefBase).
+ // As a result we can't write sp<Camera3Device> = new AidlCamera3Device(...).
+ // It supports std::shared_ptr instead. Other references to
+ // Camera3Device in cameraserver use sp<> widely, so to keep supporting
+ // that, we create a new class which will be managed through std::shared_ptr
+ // internally by AidlCamera3Device.
+ class AidlCameraDeviceCallbacks :
+ public aidl::android::hardware::camera::device::BnCameraDeviceCallback {
+ public:
+
+ AidlCameraDeviceCallbacks(wp<AidlCamera3Device> parent) : mParent(parent) { }
+ ~AidlCameraDeviceCallbacks() { }
+ ::ndk::ScopedAStatus processCaptureResult(
+ const std::vector<
+ aidl::android::hardware::camera::device::CaptureResult>& results) override;
+ ::ndk::ScopedAStatus notify(
+ const std::vector<
+ aidl::android::hardware::camera::device::NotifyMsg>& msgs) override;
+
+ ::ndk::ScopedAStatus requestStreamBuffers(
+ const std::vector<
+ aidl::android::hardware::camera::device::BufferRequest>& bufReqs,
+ std::vector<aidl::android::hardware::camera::device::StreamBufferRet>* outBuffers,
+ aidl::android::hardware::camera::device::BufferRequestStatus* status) override;
+
+ ::ndk::ScopedAStatus returnStreamBuffers(
+ const std::vector<
+ aidl::android::hardware::camera::device::StreamBuffer>& buffers) override;
+ private:
+ wp<AidlCamera3Device> mParent = nullptr;
+ };
+
+ private:
+ virtual status_t injectionCameraInitialize(const String8 &injectCamId,
+ sp<CameraProviderManager> manager) override;
+
+ virtual sp<RequestThread> createNewRequestThread(wp<Camera3Device> parent,
+ sp<camera3::StatusTracker> statusTracker,
+ sp<HalInterface> interface,
+ const Vector<int32_t>& sessionParamKeys,
+ bool useHalBufManager,
+ bool supportCameraMute) override;
+
+ virtual sp<Camera3DeviceInjectionMethods>
+ createCamera3DeviceInjectionMethods(wp<Camera3Device>) override;
+
+ // FMQ to write result on. Must be guarded by mProcessCaptureResultLock.
+ std::unique_ptr<AidlResultMetadataQueue> mResultMetadataQueue = nullptr;
+
+ std::shared_ptr<AidlCameraDeviceCallbacks> mCallbacks = nullptr;
+
+
+}; // class AidlCamera3Device
+
+}; // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp
new file mode 100644
index 0000000..895ce56
--- /dev/null
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2022 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 "AidlCamera3-OffLnSsn"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+//#define LOG_NNDEBUG 0 // Per-frame verbose logging
+
+#ifdef LOG_NNDEBUG
+#define ALOGVV(...) ALOGV(__VA_ARGS__)
+#else
+#define ALOGVV(...) ((void)0)
+#endif
+
+#include <inttypes.h>
+
+#include <utils/Trace.h>
+
+#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
+
+#include "device3/aidl/AidlCamera3OfflineSession.h"
+#include "device3/Camera3OutputStream.h"
+#include "device3/aidl/AidlCamera3OutputUtils.h"
+#include "device3/Camera3InputStream.h"
+#include "device3/Camera3SharedOutputStream.h"
+#include "utils/CameraTraces.h"
+
+using namespace android::camera3;
+using namespace aidl::android::hardware;
+
+namespace android {
+
+
+AidlCamera3OfflineSession::~AidlCamera3OfflineSession() {
+ ATRACE_CALL();
+ ALOGV("%s: Tearing down aidl offline session for camera id %s", __FUNCTION__, mId.string());
+ AidlCamera3OfflineSession::disconnectSession();
+}
+
+status_t AidlCamera3OfflineSession::initialize(wp<NotificationListener> listener) {
+ ATRACE_CALL();
+
+ if (mSession == nullptr) {
+ ALOGE("%s: AIDL session is null!", __FUNCTION__);
+ return DEAD_OBJECT;
+ }
+
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+
+ mListener = listener;
+
+ // setup result FMQ
+ std::unique_ptr<AidlResultMetadataQueue>& resQueue = mResultMetadataQueue;
+ ::aidl::android::hardware::common::fmq::MQDescriptor<
+ int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite> desc;
+ ::ndk::ScopedAStatus resultQueueRet = mSession->getCaptureResultMetadataQueue(&desc);
+ if (!resultQueueRet.isOk()) {
+ ALOGE("Transaction error when getting result metadata queue from camera session: %s",
+ resultQueueRet.getMessage());
+ return DEAD_OBJECT;
+ }
+ resQueue = std::make_unique<AidlResultMetadataQueue>(desc);
+ if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
+ ALOGE("HAL returns empty result metadata fmq, not use it");
+ resQueue = nullptr;
+ // Don't use resQueue onwards.
+ }
+
+ mStatus = STATUS_ACTIVE;
+ }
+
+ mSession->setCallback(mCallbacks);
+
+ return OK;
+}
+
+::ndk::ScopedAStatus AidlCamera3OfflineSession::AidlCameraDeviceCallbacks::processCaptureResult(
+ const std::vector<camera::device::CaptureResult>& results) {
+ sp<AidlCamera3OfflineSession> p = mParent.promote();
+ if (p == nullptr) {
+ ALOGE("%s Parent AidlCameraDevice not alive, can't process callbacks", __FUNCTION__);
+ return ::ndk::ScopedAStatus::ok();
+ }
+ return p->processCaptureResult(results);
+}
+
+::ndk::ScopedAStatus AidlCamera3OfflineSession::processCaptureResult(
+ const std::vector<camera::device::CaptureResult>& results) {
+ sp<NotificationListener> listener;
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mStatus != STATUS_ACTIVE) {
+ ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
+ return ::ndk::ScopedAStatus::ok();
+ }
+ listener = mListener.promote();
+ }
+
+ AidlCaptureOutputStates states {
+ {mId,
+ mOfflineReqsLock, mLastCompletedRegularFrameNumber,
+ mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+ mOfflineReqs, mOutputLock, mResultQueue, mResultSignal,
+ mNextShutterFrameNumber,
+ mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+ mNextResultFrameNumber,
+ mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+ mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+ mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+ mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this,
+ *this, mBufferRecords, /*legacyClient*/ false}, mResultMetadataQueue
+ };
+
+ std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
+ for (const auto& result : results) {
+ processOneCaptureResultLocked(states, result, result.physicalCameraMetadata);
+ }
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus AidlCamera3OfflineSession::AidlCameraDeviceCallbacks::notify(
+ const std::vector<camera::device::NotifyMsg>& msgs) {
+ sp<AidlCamera3OfflineSession> p = mParent.promote();
+ if (p == nullptr) {
+ ALOGE("%s Parent AidlCameraDevice not alive, can't process callbacks", __FUNCTION__);
+ return ::ndk::ScopedAStatus::ok();
+ }
+ return p->notify(msgs);
+}
+
+::ndk::ScopedAStatus AidlCamera3OfflineSession::notify(
+ const std::vector<camera::device::NotifyMsg>& msgs) {
+ sp<NotificationListener> listener;
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mStatus != STATUS_ACTIVE) {
+ ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
+ return ::ndk::ScopedAStatus::ok();
+ }
+ listener = mListener.promote();
+ }
+
+ AidlCaptureOutputStates states {
+ {mId,
+ mOfflineReqsLock, mLastCompletedRegularFrameNumber,
+ mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+ mOfflineReqs, mOutputLock, mResultQueue, mResultSignal,
+ mNextShutterFrameNumber,
+ mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+ mNextResultFrameNumber,
+ mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+ mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+ mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+ mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this,
+ *this, mBufferRecords, /*legacyClient*/ false}, mResultMetadataQueue
+ };
+ for (const auto& msg : msgs) {
+ camera3::notify(states, msg);
+ }
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus AidlCamera3OfflineSession::AidlCameraDeviceCallbacks::requestStreamBuffers(
+ const std::vector<::aidl::android::hardware::camera::device::BufferRequest>& bufReqs,
+ std::vector<::aidl::android::hardware::camera::device::StreamBufferRet>* buffers,
+ ::aidl::android::hardware::camera::device::BufferRequestStatus* status) {
+ sp<AidlCamera3OfflineSession> p = mParent.promote();
+ if (p == nullptr) {
+ ALOGE("%s Parent AidlCameraDevice not alive, can't process callbacks", __FUNCTION__);
+ return ::ndk::ScopedAStatus::ok();
+ }
+ return p->requestStreamBuffers(bufReqs, buffers, status);
+}
+
+::ndk::ScopedAStatus AidlCamera3OfflineSession::requestStreamBuffers(
+ const std::vector<::aidl::android::hardware::camera::device::BufferRequest>& bufReqs,
+ std::vector<::aidl::android::hardware::camera::device::StreamBufferRet>* buffers,
+ ::aidl::android::hardware::camera::device::BufferRequestStatus* status) {
+
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mStatus != STATUS_ACTIVE) {
+ ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
+ return ::ndk::ScopedAStatus::ok();
+ }
+ }
+
+ RequestBufferStates states {
+ mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder,
+ *this, mBufferRecords, *this};
+ camera3::requestStreamBuffers(states, bufReqs, buffers, status);
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus AidlCamera3OfflineSession::AidlCameraDeviceCallbacks::returnStreamBuffers(
+ const std::vector<camera::device::StreamBuffer>& buffers) {
+ sp<AidlCamera3OfflineSession> p = mParent.promote();
+ if (p == nullptr) {
+ ALOGE("%s Parent AidlCameraDevice not alive, can't process callbacks", __FUNCTION__);
+ return ::ndk::ScopedAStatus::ok();
+ }
+ return p->returnStreamBuffers(buffers);
+}
+
+::ndk::ScopedAStatus AidlCamera3OfflineSession::returnStreamBuffers(
+ const std::vector<camera::device::StreamBuffer>& buffers) {
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mStatus != STATUS_ACTIVE) {
+ ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
+ return ::ndk::ScopedAStatus::ok();
+ }
+ }
+
+ ReturnBufferStates states {
+ mId, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder,
+ mBufferRecords};
+
+ camera3::returnStreamBuffers(states, buffers);
+ return ::ndk::ScopedAStatus::ok();
+}
+
+void AidlCamera3OfflineSession::disconnectSession() {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mSession != nullptr) {
+ mSession->close();
+ }
+ mSession.reset();
+}
+
+}; // namespace android
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.h b/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.h
new file mode 100644
index 0000000..ad4a480
--- /dev/null
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2022 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_SERVERS_AIDL_CAMERA3OFFLINESESSION_H
+#define ANDROID_SERVERS_AIDL_CAMERA3OFFLINESESSION_H
+
+#include <memory>
+#include <mutex>
+
+#include <utils/String8.h>
+#include <utils/String16.h>
+
+#include "AidlCamera3OutputUtils.h"
+#include <aidl/android/hardware/camera/device/BnCameraDeviceCallback.h>
+#include <aidl/android/hardware/camera/device/ICameraOfflineSession.h>
+
+#include <fmq/AidlMessageQueue.h>
+
+#include "common/CameraOfflineSessionBase.h"
+
+#include "device3/Camera3BufferManager.h"
+#include "device3/Camera3OfflineSession.h"
+#include "utils/TagMonitor.h"
+#include <camera_metadata_hidden.h>
+
+namespace android {
+
+namespace camera3 {
+
+class Camera3Stream;
+class Camera3OutputStreamInterface;
+class Camera3StreamInterface;
+
+} // namespace camera3
+
+/**
+ * AidlCamera3OfflineSession for offline session defined in AIDL ICameraOfflineSession
+ */
+class AidlCamera3OfflineSession :
+ public Camera3OfflineSession {
+ public:
+
+ virtual ~AidlCamera3OfflineSession();
+
+ virtual status_t initialize(wp<NotificationListener> listener) override;
+
+ /**
+ * Implementation of aidl::android::hardware::camera::device::ICameraDeviceCallback
+ */
+ ::ndk::ScopedAStatus processCaptureResult(
+ const std::vector<aidl::android::hardware::camera::device::CaptureResult>& results);
+ ::ndk::ScopedAStatus notify(
+ const std::vector<aidl::android::hardware::camera::device::NotifyMsg>& msgs);
+ ::ndk::ScopedAStatus requestStreamBuffers(
+ const std::vector<aidl::android::hardware::camera::device::BufferRequest>& bufReqs,
+ std::vector<aidl::android::hardware::camera::device::StreamBufferRet>* outBuffers,
+ aidl::android::hardware::camera::device::BufferRequestStatus* status);
+
+ ::ndk::ScopedAStatus returnStreamBuffers(
+ const std::vector<aidl::android::hardware::camera::device::StreamBuffer>& buffers);
+
+ // See explanation for why we need a separate class for this in
+ // AidlCamera3Device::AidlCameraDeviceCallbacks in AidlCamera3Device.h
+ class AidlCameraDeviceCallbacks :
+ virtual public aidl::android::hardware::camera::device::BnCameraDeviceCallback {
+ public:
+
+ AidlCameraDeviceCallbacks(wp<AidlCamera3OfflineSession> parent) : mParent(parent) { }
+ ~AidlCameraDeviceCallbacks() {}
+ ::ndk::ScopedAStatus processCaptureResult(
+ const std::vector<
+ aidl::android::hardware::camera::device::CaptureResult>& results) override;
+ ::ndk::ScopedAStatus notify(
+ const std::vector<
+ aidl::android::hardware::camera::device::NotifyMsg>& msgs) override;
+
+ ::ndk::ScopedAStatus requestStreamBuffers(
+ const std::vector<
+ aidl::android::hardware::camera::device::BufferRequest>& bufReqs,
+ std::vector<aidl::android::hardware::camera::device::StreamBufferRet>* out_buffers,
+ aidl::android::hardware::camera::device::BufferRequestStatus* _aidl_return
+ ) override;
+
+ ::ndk::ScopedAStatus returnStreamBuffers(
+ const std::vector<
+ aidl::android::hardware::camera::device::StreamBuffer>& buffers) override;
+ private:
+ wp<AidlCamera3OfflineSession> mParent = nullptr;
+ };
+
+ // initialize by Camera3Device.
+ explicit AidlCamera3OfflineSession(const String8& id,
+ const sp<camera3::Camera3Stream>& inputStream,
+ const camera3::StreamSet& offlineStreamSet,
+ camera3::BufferRecords&& bufferRecords,
+ const camera3::InFlightRequestMap& offlineReqs,
+ const Camera3OfflineStates& offlineStates,
+ std::shared_ptr<aidl::android::hardware::camera::device::ICameraOfflineSession>
+ offlineSession) :
+ Camera3OfflineSession(id, inputStream, offlineStreamSet, std::move(bufferRecords),
+ offlineReqs, offlineStates),
+ mSession(offlineSession) { mCallbacks = std::make_shared<AidlCameraDeviceCallbacks>(this);};
+
+ /**
+ * End of CameraOfflineSessionBase interface
+ */
+
+ private:
+ std::shared_ptr<aidl::android::hardware::camera::device::ICameraOfflineSession> mSession;
+ // FMQ to write result on. Must be guarded by mProcessCaptureResultLock.
+ std::unique_ptr<AidlResultMetadataQueue> mResultMetadataQueue;
+
+ std::shared_ptr<AidlCameraDeviceCallbacks> mCallbacks;
+
+ virtual void disconnectSession() override;
+
+}; // class AidlCamera3OfflineSession
+
+}; // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.cpp
new file mode 100644
index 0000000..3809f37
--- /dev/null
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.cpp
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 2022 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 "AidlCamera3-OutputUtils"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+//#define LOG_NNDEBUG 0 // Per-frame verbose logging
+
+#ifdef LOG_NNDEBUG
+#define ALOGVV(...) ALOGV(__VA_ARGS__)
+#else
+#define ALOGVV(...) ((void)0)
+#endif
+
+// Convenience macros for transitioning to the error state
+#define SET_ERR(fmt, ...) states.setErrIntf.setErrorState( \
+ "%s: " fmt, __FUNCTION__, \
+ ##__VA_ARGS__)
+
+#include <inttypes.h>
+
+#include <utils/Log.h>
+#include <utils/SortedVector.h>
+#include <utils/Trace.h>
+
+#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
+#include <aidlcommonsupport/NativeHandle.h>
+
+#include <camera/CameraUtils.h>
+#include <camera_metadata_hidden.h>
+
+#include "device3/aidl/AidlCamera3OutputUtils.h"
+#include "device3/Camera3OutputUtilsTemplated.h"
+
+#include "system/camera_metadata.h"
+
+using namespace android::camera3;
+using namespace android::hardware::camera;
+
+namespace android {
+namespace camera3 {
+
+void processOneCaptureResultLocked(
+ AidlCaptureOutputStates& states,
+ const aidl::android::hardware::camera::device::CaptureResult& result,
+ const std::vector<aidl::android::hardware::camera::device::PhysicalCameraMetadata>
+ &physicalCameraMetadata) {
+ processOneCaptureResultLockedT<AidlCaptureOutputStates,
+ aidl::android::hardware::camera::device::CaptureResult,
+ std::vector<aidl::android::hardware::camera::device::PhysicalCameraMetadata>,
+ std::vector<uint8_t>, AidlResultMetadataQueue,
+ aidl::android::hardware::camera::device::BufferStatus, int8_t>(states, result,
+ physicalCameraMetadata);
+}
+
+void notify(CaptureOutputStates& states,
+ const aidl::android::hardware::camera::device::NotifyMsg& msg) {
+
+ using ErrorCode = aidl::android::hardware::camera::device::ErrorCode;
+ using Tag = aidl::android::hardware::camera::device::NotifyMsg::Tag;
+
+ ATRACE_CALL();
+ camera_notify_msg m;
+
+ switch (msg.getTag()) {
+ case Tag::error:
+ m.type = CAMERA_MSG_ERROR;
+ m.message.error.frame_number = msg.get<Tag::error>().frameNumber;
+ if (msg.get<Tag::error>().errorStreamId >= 0) {
+ sp<Camera3StreamInterface> stream =
+ states.outputStreams.get(msg.get<Tag::error>().errorStreamId);
+ if (stream == nullptr) {
+ ALOGE("%s: Frame %d: Invalid error stream id %d", __FUNCTION__,
+ m.message.error.frame_number, msg.get<Tag::error>().errorStreamId);
+ return;
+ }
+ m.message.error.error_stream = stream->asHalStream();
+ } else {
+ m.message.error.error_stream = nullptr;
+ }
+ switch (msg.get<Tag::error>().errorCode) {
+ case ErrorCode::ERROR_DEVICE:
+ m.message.error.error_code = CAMERA_MSG_ERROR_DEVICE;
+ break;
+ case ErrorCode::ERROR_REQUEST:
+ m.message.error.error_code = CAMERA_MSG_ERROR_REQUEST;
+ break;
+ case ErrorCode::ERROR_RESULT:
+ m.message.error.error_code = CAMERA_MSG_ERROR_RESULT;
+ break;
+ case ErrorCode::ERROR_BUFFER:
+ m.message.error.error_code = CAMERA_MSG_ERROR_BUFFER;
+ break;
+ }
+ break;
+ case Tag::shutter:
+ m.type = CAMERA_MSG_SHUTTER;
+ m.message.shutter.frame_number = msg.get<Tag::shutter>().frameNumber;
+ m.message.shutter.timestamp = msg.get<Tag::shutter>().timestamp;
+ m.message.shutter.readout_timestamp = msg.get<Tag::shutter>().readoutTimestamp;
+ break;
+ }
+ notify(states, &m);
+}
+
+
+// The buffers requested through this call are not tied to any CaptureRequest in
+// particular. They may used by the hal for a particular frame's output buffer
+// or for its internal use as well. In the case that the hal does use any buffer
+// from the requested list here, for a particular frame's output buffer, the
+// buffer will be returned with the processCaptureResult call corresponding to
+// the frame. The other buffers will be returned through returnStreamBuffers.
+// The buffers returned via returnStreamBuffers will not have a valid
+// timestamp(0) and will be dropped by the bufferqueue.
+void requestStreamBuffers(RequestBufferStates& states,
+ const std::vector<aidl::android::hardware::camera::device::BufferRequest>& bufReqs,
+ std::vector<::aidl::android::hardware::camera::device::StreamBufferRet>* outBuffers,
+ ::aidl::android::hardware::camera::device::BufferRequestStatus* status) {
+ using aidl::android::hardware::camera::device::BufferStatus;
+ using aidl::android::hardware::camera::device::StreamBuffer;
+ using aidl::android::hardware::camera::device::BufferRequestStatus;
+ using aidl::android::hardware::camera::device::StreamBufferRet;
+ using aidl::android::hardware::camera::device::StreamBufferRequestError;
+ using Tag = aidl::android::hardware::camera::device::StreamBuffersVal::Tag;
+ if (outBuffers == nullptr || status == nullptr) {
+ ALOGE("%s outBuffers / buffer status nullptr", __FUNCTION__);
+ return;
+ }
+ std::lock_guard<std::mutex> lock(states.reqBufferLock);
+ std::vector<StreamBufferRet> bufRets;
+ outBuffers->clear();
+ if (!states.useHalBufManager) {
+ ALOGE("%s: Camera %s does not support HAL buffer management",
+ __FUNCTION__, states.cameraId.string());
+ *status = BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS;
+ return;
+ }
+
+ SortedVector<int32_t> streamIds;
+ ssize_t sz = streamIds.setCapacity(bufReqs.size());
+ if (sz < 0 || static_cast<size_t>(sz) != bufReqs.size()) {
+ ALOGE("%s: failed to allocate memory for %zu buffer requests",
+ __FUNCTION__, bufReqs.size());
+ *status = BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS;
+ return;
+ }
+
+ if (bufReqs.size() > states.outputStreams.size()) {
+ ALOGE("%s: too many buffer requests (%zu > # of output streams %zu)",
+ __FUNCTION__, bufReqs.size(), states.outputStreams.size());
+ *status = BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS;
+ return;
+ }
+
+ // Check for repeated streamId
+ for (const auto& bufReq : bufReqs) {
+ if (streamIds.indexOf(bufReq.streamId) != NAME_NOT_FOUND) {
+ ALOGE("%s: Stream %d appear multiple times in buffer requests",
+ __FUNCTION__, bufReq.streamId);
+ *status = BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS;
+ return;
+ }
+ streamIds.add(bufReq.streamId);
+ }
+
+ if (!states.reqBufferIntf.startRequestBuffer()) {
+ ALOGE("%s: request buffer disallowed while camera service is configuring",
+ __FUNCTION__);
+ *status = BufferRequestStatus::FAILED_CONFIGURING;
+ return;
+ }
+
+ bufRets.resize(bufReqs.size());
+
+ bool allReqsSucceeds = true;
+ bool oneReqSucceeds = false;
+ for (size_t i = 0; i < bufReqs.size(); i++) {
+ const auto& bufReq = bufReqs[i];
+ auto& bufRet = bufRets[i];
+ int32_t streamId = bufReq.streamId;
+ sp<Camera3OutputStreamInterface> outputStream = states.outputStreams.get(streamId);
+ if (outputStream == nullptr) {
+ ALOGE("%s: Output stream id %d not found!", __FUNCTION__, streamId);
+ std::vector<StreamBufferRet> emptyBufRets;
+ *status = BufferRequestStatus::FAILED_CONFIGURING;
+ states.reqBufferIntf.endRequestBuffer();
+ return;
+ }
+
+ bufRet.streamId = streamId;
+ if (outputStream->isAbandoned()) {
+ bufRet.val.set<Tag::error>(StreamBufferRequestError::STREAM_DISCONNECTED);
+ allReqsSucceeds = false;
+ continue;
+ }
+
+ size_t handOutBufferCount = outputStream->getOutstandingBuffersCount();
+ uint32_t numBuffersRequested = bufReq.numBuffersRequested;
+ size_t totalHandout = handOutBufferCount + numBuffersRequested;
+ uint32_t maxBuffers = outputStream->asHalStream()->max_buffers;
+ if (totalHandout > maxBuffers) {
+ // Not able to allocate enough buffer. Exit early for this stream
+ ALOGE("%s: request too much buffers for stream %d: at HAL: %zu + requesting: %d"
+ " > max: %d", __FUNCTION__, streamId, handOutBufferCount,
+ numBuffersRequested, maxBuffers);
+ bufRet.val.set<Tag::error>(StreamBufferRequestError::MAX_BUFFER_EXCEEDED);
+ allReqsSucceeds = false;
+ continue;
+ }
+
+ std::vector<StreamBuffer> tmpRetBuffers(numBuffersRequested);
+ bool currentReqSucceeds = true;
+ std::vector<camera_stream_buffer_t> streamBuffers(numBuffersRequested);
+ std::vector<buffer_handle_t> newBuffers;
+ size_t numAllocatedBuffers = 0;
+ size_t numPushedInflightBuffers = 0;
+ for (size_t b = 0; b < numBuffersRequested; b++) {
+ camera_stream_buffer_t& sb = streamBuffers[b];
+ // Since this method can run concurrently with request thread
+ // We need to update the wait duration everytime we call getbuffer
+ nsecs_t waitDuration = states.reqBufferIntf.getWaitDuration();
+ status_t res = outputStream->getBuffer(&sb, waitDuration);
+ if (res != OK) {
+ if (res == NO_INIT || res == DEAD_OBJECT) {
+ ALOGV("%s: Can't get output buffer for stream %d: %s (%d)",
+ __FUNCTION__, streamId, strerror(-res), res);
+ bufRet.val.set<Tag::error>(StreamBufferRequestError::STREAM_DISCONNECTED);
+ states.sessionStatsBuilder.stopCounter(streamId);
+ } else {
+ ALOGE("%s: Can't get output buffer for stream %d: %s (%d)",
+ __FUNCTION__, streamId, strerror(-res), res);
+ if (res == TIMED_OUT || res == NO_MEMORY) {
+ bufRet.val.set<Tag::error>(StreamBufferRequestError::NO_BUFFER_AVAILABLE);
+ } else {
+ bufRet.val.set<Tag::error>(StreamBufferRequestError::UNKNOWN_ERROR);
+ }
+ }
+ currentReqSucceeds = false;
+ break;
+ }
+ numAllocatedBuffers++;
+
+ buffer_handle_t *buffer = sb.buffer;
+ auto pair = states.bufferRecordsIntf.getBufferId(*buffer, streamId);
+ bool isNewBuffer = pair.first;
+ uint64_t bufferId = pair.second;
+ StreamBuffer& hBuf = tmpRetBuffers[b];
+
+ hBuf.streamId = streamId;
+ hBuf.bufferId = bufferId;
+
+ hBuf.buffer = (isNewBuffer) ? camera3::dupToAidlIfNotNull(*buffer) :
+ aidl::android::hardware::common::NativeHandle();
+ hBuf.status = BufferStatus::OK;
+ hBuf.releaseFence = aidl::android::hardware::common::NativeHandle();
+ if (isNewBuffer) {
+ newBuffers.push_back(*buffer);
+ }
+
+ native_handle_t *acquireFence = nullptr;
+ if (sb.acquire_fence != -1) {
+ acquireFence = native_handle_create(1,0);
+ acquireFence->data[0] = sb.acquire_fence;
+ }
+ //makeToAidl passes ownership to aidl NativeHandle made. Ownership
+ //is passed : see system/window.h : dequeueBuffer
+ hBuf.acquireFence = makeToAidlIfNotNull(acquireFence);
+ if (acquireFence != nullptr) {
+ native_handle_delete(acquireFence);
+ }
+ hBuf.releaseFence = aidl::android::hardware::common::NativeHandle();
+
+ res = states.bufferRecordsIntf.pushInflightRequestBuffer(bufferId, buffer, streamId);
+ if (res != OK) {
+ ALOGE("%s: Can't get register request buffers for stream %d: %s (%d)",
+ __FUNCTION__, streamId, strerror(-res), res);
+ bufRet.val.set<Tag::error>(StreamBufferRequestError::UNKNOWN_ERROR);
+ currentReqSucceeds = false;
+ break;
+ }
+ numPushedInflightBuffers++;
+ }
+ if (currentReqSucceeds) {
+ bufRet.val.set<Tag::buffers>(std::move(tmpRetBuffers));
+ oneReqSucceeds = true;
+ } else {
+ allReqsSucceeds = false;
+ for (size_t b = 0; b < numPushedInflightBuffers; b++) {
+ StreamBuffer& hBuf = tmpRetBuffers[b];
+ buffer_handle_t* buffer;
+ status_t res = states.bufferRecordsIntf.popInflightRequestBuffer(
+ hBuf.bufferId, &buffer);
+ if (res != OK) {
+ SET_ERR("%s: popInflightRequestBuffer failed for stream %d: %s (%d)",
+ __FUNCTION__, streamId, strerror(-res), res);
+ }
+ }
+ for (size_t b = 0; b < numAllocatedBuffers; b++) {
+ camera_stream_buffer_t& sb = streamBuffers[b];
+ sb.acquire_fence = -1;
+ sb.status = CAMERA_BUFFER_STATUS_ERROR;
+ }
+ returnOutputBuffers(states.useHalBufManager, nullptr,
+ streamBuffers.data(), numAllocatedBuffers, 0,
+ 0, false,
+ 0, states.sessionStatsBuilder);
+ for (auto buf : newBuffers) {
+ states.bufferRecordsIntf.removeOneBufferCache(streamId, buf);
+ }
+ }
+ }
+
+ *status = allReqsSucceeds ? BufferRequestStatus::OK :
+ oneReqSucceeds ? BufferRequestStatus::FAILED_PARTIAL :
+ BufferRequestStatus::FAILED_UNKNOWN,
+ // Transfer ownership of buffer fds to outBuffers
+ *outBuffers = std::move(bufRets);
+
+ states.reqBufferIntf.endRequestBuffer();
+}
+
+void returnStreamBuffers(ReturnBufferStates& states,
+ const std::vector<aidl::android::hardware::camera::device::StreamBuffer>& buffers) {
+ returnStreamBuffersT(states, buffers);
+}
+
+} // camera3
+} // namespace android
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.h b/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.h
new file mode 100644
index 0000000..e795624
--- /dev/null
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2022 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_SERVERS_AIDL_CAMERA3_OUTPUT_UTILS_H
+#define ANDROID_SERVERS_AIDL_CAMERA3_OUTPUT_UTILS_H
+
+#include <memory>
+#include <mutex>
+
+#include <cutils/native_handle.h>
+
+#include <aidlcommonsupport/NativeHandle.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include <common/CameraDeviceBase.h>
+
+#include <aidl/android/hardware/camera/device/ICameraDevice.h>
+#include <aidl/android/hardware/camera/device/ICameraDeviceCallback.h>
+#include "device3/BufferUtils.h"
+#include "device3/InFlightRequest.h"
+#include "device3/Camera3Stream.h"
+#include "device3/Camera3OutputStreamInterface.h"
+#include "device3/Camera3OutputUtils.h"
+#include "utils/SessionStatsBuilder.h"
+#include "utils/TagMonitor.h"
+
+namespace android {
+
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::android::AidlMessageQueue;
+
+using AidlResultMetadataQueue = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
+namespace camera3 {
+ inline aidl::android::hardware::common::NativeHandle dupToAidlIfNotNull(
+ const native_handle_t *nh) {
+ if (nh == nullptr) {
+ return aidl::android::hardware::common::NativeHandle();
+ }
+ return dupToAidl(nh);
+ }
+
+ inline aidl::android::hardware::common::NativeHandle makeToAidlIfNotNull(
+ const native_handle_t *nh) {
+ if (nh == nullptr) {
+ return aidl::android::hardware::common::NativeHandle();
+ }
+ return makeToAidl(nh);
+ }
+
+ /**
+ * Helper methods shared between AidlCamera3Device/AidlCamera3OfflineSession for HAL callbacks
+ */
+
+ // Camera3Device/Camera3OfflineSession internal states used in notify/processCaptureResult
+ // callbacks
+ struct AidlCaptureOutputStates : public CaptureOutputStates {
+ std::unique_ptr<AidlResultMetadataQueue>& fmq;
+ };
+
+ // Handle one capture result. Assume callers hold the lock to serialize all
+ // processCaptureResult calls
+ void processOneCaptureResultLocked(
+ AidlCaptureOutputStates& states,
+ const aidl::android::hardware::camera::device::CaptureResult& result,
+ const std::vector<aidl::android::hardware::camera::device::PhysicalCameraMetadata>
+ &physicalCameraMetadata);
+
+ void notify(CaptureOutputStates& states,
+ const aidl::android::hardware::camera::device::NotifyMsg& msg,
+ bool hasReadoutTime, uint64_t readoutTime);
+
+ void notify(CaptureOutputStates& states,
+ const aidl::android::hardware::camera::device::NotifyMsg& msg);
+
+ void requestStreamBuffers(RequestBufferStates& states,
+ const std::vector<aidl::android::hardware::camera::device::BufferRequest>& bufReqs,
+ std::vector<::aidl::android::hardware::camera::device::StreamBufferRet>* out_buffers,
+ ::aidl::android::hardware::camera::device::BufferRequestStatus* _aidl_return);
+
+ void returnStreamBuffers(ReturnBufferStates& states,
+ const std::vector<aidl::android::hardware::camera::device::StreamBuffer>& buffers);
+
+} // namespace camera3
+
+} // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
new file mode 100644
index 0000000..87cf99a
--- /dev/null
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
@@ -0,0 +1,1901 @@
+/*
+ * Copyright (C) 2022 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 "HidlCamera3-Device"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+//#define LOG_NNDEBUG 0 // Per-frame verbose logging
+
+#ifdef LOG_NNDEBUG
+#define ALOGVV(...) ALOGV(__VA_ARGS__)
+#else
+#define ALOGVV(...) ((void)0)
+#endif
+
+// Convenience macro for transient errors
+#define CLOGE(fmt, ...) ALOGE("Camera %s: %s: " fmt, mId.string(), __FUNCTION__, \
+ ##__VA_ARGS__)
+
+// Convenience macros for transitioning to the error state
+#define SET_ERR(fmt, ...) setErrorState( \
+ "%s: " fmt, __FUNCTION__, \
+ ##__VA_ARGS__)
+#define SET_ERR_L(fmt, ...) setErrorStateLocked( \
+ "%s: " fmt, __FUNCTION__, \
+ ##__VA_ARGS__)
+
+
+#include <inttypes.h>
+
+#include <utility>
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include <utils/Timers.h>
+#include <cutils/properties.h>
+
+#include <android/hardware/camera/device/3.7/ICameraInjectionSession.h>
+#include <android/hardware/camera2/ICameraDeviceUser.h>
+
+#include "device3/hidl/HidlCamera3OutputUtils.h"
+#include "device3/hidl/HidlCamera3OfflineSession.h"
+#include "utils/SessionConfigurationUtils.h"
+#include "utils/TraceHFR.h"
+
+#include "../../common/hidl/HidlProviderInfo.h"
+#include "HidlCamera3Device.h"
+
+#include <algorithm>
+#include <tuple>
+
+using namespace android::camera3;
+using namespace android::hardware::camera;
+using namespace android::hardware::camera::device::V3_2;
+using android::hardware::camera::metadata::V3_6::CameraMetadataEnumAndroidSensorPixelMode;
+using android::hardware::camera::metadata::V3_8::CameraMetadataEnumAndroidScalerAvailableStreamUseCases;
+
+namespace android {
+
+CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap
+HidlCamera3Device::mapToHidlDynamicProfile(int dynamicRangeProfile) {
+ return static_cast<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap>(
+ dynamicRangeProfile);
+}
+
+hardware::graphics::common::V1_0::PixelFormat HidlCamera3Device::mapToPixelFormat(
+ int frameworkFormat) {
+ return (hardware::graphics::common::V1_0::PixelFormat) frameworkFormat;
+}
+
+DataspaceFlags HidlCamera3Device::mapToHidlDataspace(
+ android_dataspace dataSpace) {
+ return dataSpace;
+}
+
+BufferUsageFlags HidlCamera3Device::mapToConsumerUsage(
+ uint64_t usage) {
+ return usage;
+}
+
+StreamRotation HidlCamera3Device::mapToStreamRotation(camera_stream_rotation_t rotation) {
+ switch (rotation) {
+ case CAMERA_STREAM_ROTATION_0:
+ return StreamRotation::ROTATION_0;
+ case CAMERA_STREAM_ROTATION_90:
+ return StreamRotation::ROTATION_90;
+ case CAMERA_STREAM_ROTATION_180:
+ return StreamRotation::ROTATION_180;
+ case CAMERA_STREAM_ROTATION_270:
+ return StreamRotation::ROTATION_270;
+ }
+ ALOGE("%s: Unknown stream rotation %d", __FUNCTION__, rotation);
+ return StreamRotation::ROTATION_0;
+}
+
+status_t HidlCamera3Device::mapToStreamConfigurationMode(
+ camera_stream_configuration_mode_t operationMode, StreamConfigurationMode *mode) {
+ if (mode == nullptr) return BAD_VALUE;
+ if (operationMode < CAMERA_VENDOR_STREAM_CONFIGURATION_MODE_START) {
+ switch(operationMode) {
+ case CAMERA_STREAM_CONFIGURATION_NORMAL_MODE:
+ *mode = StreamConfigurationMode::NORMAL_MODE;
+ break;
+ case CAMERA_STREAM_CONFIGURATION_CONSTRAINED_HIGH_SPEED_MODE:
+ *mode = StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE;
+ break;
+ default:
+ ALOGE("%s: Unknown stream configuration mode %d", __FUNCTION__, operationMode);
+ return BAD_VALUE;
+ }
+ } else {
+ *mode = static_cast<StreamConfigurationMode>(operationMode);
+ }
+ return OK;
+}
+
+int HidlCamera3Device::mapToFrameworkFormat(
+ hardware::graphics::common::V1_0::PixelFormat pixelFormat) {
+ return static_cast<uint32_t>(pixelFormat);
+}
+
+android_dataspace HidlCamera3Device::mapToFrameworkDataspace(
+ DataspaceFlags dataSpace) {
+ return static_cast<android_dataspace>(dataSpace);
+}
+
+uint64_t HidlCamera3Device::mapConsumerToFrameworkUsage(
+ BufferUsageFlags usage) {
+ return usage;
+}
+
+uint64_t HidlCamera3Device::mapProducerToFrameworkUsage(
+ BufferUsageFlags usage) {
+ return usage;
+}
+
+status_t HidlCamera3Device::initialize(sp<CameraProviderManager> manager,
+ const String8& monitorTags) {
+ ATRACE_CALL();
+ Mutex::Autolock il(mInterfaceLock);
+ Mutex::Autolock l(mLock);
+
+ ALOGV("%s: Initializing HIDL device for camera %s", __FUNCTION__, mId.string());
+ if (mStatus != STATUS_UNINITIALIZED) {
+ CLOGE("Already initialized!");
+ return INVALID_OPERATION;
+ }
+ if (manager == nullptr) return INVALID_OPERATION;
+
+ sp<ICameraDeviceSession> session;
+ ATRACE_BEGIN("CameraHal::openSession");
+ status_t res = manager->openHidlSession(mId.string(), this,
+ /*out*/ &session);
+ ATRACE_END();
+ if (res != OK) {
+ SET_ERR_L("Could not open camera session: %s (%d)", strerror(-res), res);
+ return res;
+ }
+
+ res = manager->getCameraCharacteristics(mId.string(), mOverrideForPerfClass, &mDeviceInfo);
+ if (res != OK) {
+ SET_ERR_L("Could not retrieve camera characteristics: %s (%d)", strerror(-res), res);
+ session->close();
+ return res;
+ }
+ mSupportNativeZoomRatio = manager->supportNativeZoomRatio(mId.string());
+
+ std::vector<std::string> physicalCameraIds;
+ bool isLogical = manager->isLogicalCamera(mId.string(), &physicalCameraIds);
+ if (isLogical) {
+ for (auto& physicalId : physicalCameraIds) {
+ // Do not override characteristics for physical cameras
+ res = manager->getCameraCharacteristics(
+ physicalId, /*overrideForPerfClass*/false, &mPhysicalDeviceInfoMap[physicalId]);
+ if (res != OK) {
+ SET_ERR_L("Could not retrieve camera %s characteristics: %s (%d)",
+ physicalId.c_str(), strerror(-res), res);
+ session->close();
+ return res;
+ }
+
+ bool usePrecorrectArray =
+ DistortionMapper::isDistortionSupported(mPhysicalDeviceInfoMap[physicalId]);
+ if (usePrecorrectArray) {
+ res = mDistortionMappers[physicalId].setupStaticInfo(
+ mPhysicalDeviceInfoMap[physicalId]);
+ if (res != OK) {
+ SET_ERR_L("Unable to read camera %s's calibration fields for distortion "
+ "correction", physicalId.c_str());
+ session->close();
+ return res;
+ }
+ }
+
+ mZoomRatioMappers[physicalId] = ZoomRatioMapper(
+ &mPhysicalDeviceInfoMap[physicalId],
+ mSupportNativeZoomRatio, usePrecorrectArray);
+
+ if (SessionConfigurationUtils::isUltraHighResolutionSensor(
+ mPhysicalDeviceInfoMap[physicalId])) {
+ mUHRCropAndMeteringRegionMappers[physicalId] =
+ UHRCropAndMeteringRegionMapper(mPhysicalDeviceInfoMap[physicalId],
+ usePrecorrectArray);
+ }
+ }
+ }
+
+ std::shared_ptr<RequestMetadataQueue> queue;
+ auto requestQueueRet = session->getCaptureRequestMetadataQueue(
+ [&queue](const auto& descriptor) {
+ queue = std::make_shared<RequestMetadataQueue>(descriptor);
+ if (!queue->isValid() || queue->availableToWrite() <= 0) {
+ ALOGE("HAL returns empty request metadata fmq, not use it");
+ queue = nullptr;
+ // don't use the queue onwards.
+ }
+ });
+ if (!requestQueueRet.isOk()) {
+ ALOGE("Transaction error when getting request metadata fmq: %s, not use it",
+ requestQueueRet.description().c_str());
+ return DEAD_OBJECT;
+ }
+
+ std::unique_ptr<ResultMetadataQueue>& resQueue = mResultMetadataQueue;
+ auto resultQueueRet = session->getCaptureResultMetadataQueue(
+ [&resQueue](const auto& descriptor) {
+ resQueue = std::make_unique<ResultMetadataQueue>(descriptor);
+ if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
+ ALOGE("HAL returns empty result metadata fmq, not use it");
+ resQueue = nullptr;
+ // Don't use the resQueue onwards.
+ }
+ });
+ if (!resultQueueRet.isOk()) {
+ ALOGE("Transaction error when getting result metadata queue from camera session: %s",
+ resultQueueRet.description().c_str());
+ return DEAD_OBJECT;
+ }
+ IF_ALOGV() {
+ session->interfaceChain([](
+ ::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) {
+ ALOGV("Session interface chain:");
+ for (const auto& iface : interfaceChain) {
+ ALOGV(" %s", iface.c_str());
+ }
+ });
+ }
+
+ camera_metadata_entry bufMgrMode =
+ mDeviceInfo.find(ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION);
+ if (bufMgrMode.count > 0) {
+ mUseHalBufManager = (bufMgrMode.data.u8[0] ==
+ ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
+ }
+
+ camera_metadata_entry_t capabilities = mDeviceInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+ for (size_t i = 0; i < capabilities.count; i++) {
+ uint8_t capability = capabilities.data.u8[i];
+ if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING) {
+ mSupportOfflineProcessing = true;
+ }
+ }
+
+ mInterface = new HidlHalInterface(session, queue, mUseHalBufManager, mSupportOfflineProcessing);
+
+ std::string providerType;
+ mVendorTagId = manager->getProviderTagIdLocked(mId.string());
+ mTagMonitor.initialize(mVendorTagId);
+ if (!monitorTags.isEmpty()) {
+ mTagMonitor.parseTagsToMonitor(String8(monitorTags));
+ }
+
+ // Metadata tags needs fixup for monochrome camera device version less
+ // than 3.5.
+ hardware::hidl_version maxVersion{0,0};
+ res = manager->getHighestSupportedVersion(mId.string(), &maxVersion);
+ if (res != OK) {
+ ALOGE("%s: Error in getting camera device version id: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+ int deviceVersion = HARDWARE_DEVICE_API_VERSION(
+ maxVersion.get_major(), maxVersion.get_minor());
+
+ bool isMonochrome = false;
+ for (size_t i = 0; i < capabilities.count; i++) {
+ uint8_t capability = capabilities.data.u8[i];
+ if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME) {
+ isMonochrome = true;
+ }
+ }
+ mNeedFixupMonochromeTags = (isMonochrome && deviceVersion < CAMERA_DEVICE_API_VERSION_3_5);
+
+ return initializeCommonLocked();
+}
+
+hardware::Return<void> HidlCamera3Device::requestStreamBuffers(
+ const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
+ requestStreamBuffers_cb _hidl_cb) {
+ RequestBufferStates states {
+ mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder,
+ *this, *mInterface, *this};
+ camera3::requestStreamBuffers(states, bufReqs, _hidl_cb);
+ return hardware::Void();
+}
+
+hardware::Return<void> HidlCamera3Device::returnStreamBuffers(
+ const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers) {
+ ReturnBufferStates states {
+ mId, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder, *mInterface};
+ camera3::returnStreamBuffers(states, buffers);
+ return hardware::Void();
+}
+
+hardware::Return<void> HidlCamera3Device::processCaptureResult_3_4(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_4::CaptureResult>& results) {
+ // Ideally we should grab mLock, but that can lead to deadlock, and
+ // it's not super important to get up to date value of mStatus for this
+ // warning print, hence skipping the lock here
+ if (mStatus == STATUS_ERROR) {
+ // Per API contract, HAL should act as closed after device error
+ // But mStatus can be set to error by framework as well, so just log
+ // a warning here.
+ ALOGW("%s: received capture result in error state.", __FUNCTION__);
+ }
+
+ sp<NotificationListener> listener;
+ {
+ std::lock_guard<std::mutex> l(mOutputLock);
+ listener = mListener.promote();
+ }
+
+ if (mProcessCaptureResultLock.tryLock() != OK) {
+ // This should never happen; it indicates a wrong client implementation
+ // that doesn't follow the contract. But, we can be tolerant here.
+ ALOGE("%s: callback overlapped! waiting 1s...",
+ __FUNCTION__);
+ if (mProcessCaptureResultLock.timedLock(1000000000 /* 1s */) != OK) {
+ ALOGE("%s: cannot acquire lock in 1s, dropping results",
+ __FUNCTION__);
+ // really don't know what to do, so bail out.
+ return hardware::Void();
+ }
+ }
+ HidlCaptureOutputStates states {
+ {
+ mId,
+ mInFlightLock, mLastCompletedRegularFrameNumber,
+ mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+ mInFlightMap, mOutputLock, mResultQueue, mResultSignal,
+ mNextShutterFrameNumber,
+ mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+ mNextResultFrameNumber,
+ mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+ mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+ mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+ mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
+ *mInterface, mLegacyClient}, mResultMetadataQueue
+ };
+
+ //HidlCaptureOutputStates hidlStates {
+ //}
+
+ for (const auto& result : results) {
+ processOneCaptureResultLocked(states, result.v3_2, result.physicalCameraMetadata);
+ }
+ mProcessCaptureResultLock.unlock();
+ return hardware::Void();
+}
+
+// Only one processCaptureResult should be called at a time, so
+// the locks won't block. The locks are present here simply to enforce this.
+hardware::Return<void> HidlCamera3Device::processCaptureResult(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_2::CaptureResult>& results) {
+ hardware::hidl_vec<hardware::camera::device::V3_4::PhysicalCameraMetadata> noPhysMetadata;
+
+ // Ideally we should grab mLock, but that can lead to deadlock, and
+ // it's not super important to get up to date value of mStatus for this
+ // warning print, hence skipping the lock here
+ if (mStatus == STATUS_ERROR) {
+ // Per API contract, HAL should act as closed after device error
+ // But mStatus can be set to error by framework as well, so just log
+ // a warning here.
+ ALOGW("%s: received capture result in error state.", __FUNCTION__);
+ }
+
+ sp<NotificationListener> listener;
+ {
+ std::lock_guard<std::mutex> l(mOutputLock);
+ listener = mListener.promote();
+ }
+
+ if (mProcessCaptureResultLock.tryLock() != OK) {
+ // This should never happen; it indicates a wrong client implementation
+ // that doesn't follow the contract. But, we can be tolerant here.
+ ALOGE("%s: callback overlapped! waiting 1s...",
+ __FUNCTION__);
+ if (mProcessCaptureResultLock.timedLock(1000000000 /* 1s */) != OK) {
+ ALOGE("%s: cannot acquire lock in 1s, dropping results",
+ __FUNCTION__);
+ // really don't know what to do, so bail out.
+ return hardware::Void();
+ }
+ }
+
+ HidlCaptureOutputStates states {
+ {mId,
+ mInFlightLock, mLastCompletedRegularFrameNumber,
+ mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+ mInFlightMap, mOutputLock, mResultQueue, mResultSignal,
+ mNextShutterFrameNumber,
+ mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+ mNextResultFrameNumber,
+ mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+ mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+ mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+ mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
+ *mInterface, mLegacyClient}, mResultMetadataQueue
+ };
+
+ for (const auto& result : results) {
+ processOneCaptureResultLocked(states, result, noPhysMetadata);
+ }
+ mProcessCaptureResultLock.unlock();
+ return hardware::Void();
+}
+
+hardware::Return<void> HidlCamera3Device::notify(
+ const hardware::hidl_vec<hardware::camera::device::V3_2::NotifyMsg>& msgs) {
+ return notifyHelper<hardware::camera::device::V3_2::NotifyMsg>(msgs);
+}
+
+hardware::Return<void> HidlCamera3Device::notify_3_8(
+ const hardware::hidl_vec<hardware::camera::device::V3_8::NotifyMsg>& msgs) {
+ return notifyHelper<hardware::camera::device::V3_8::NotifyMsg>(msgs);
+}
+
+template<typename NotifyMsgType>
+hardware::Return<void> HidlCamera3Device::notifyHelper(
+ const hardware::hidl_vec<NotifyMsgType>& msgs) {
+ // Ideally we should grab mLock, but that can lead to deadlock, and
+ // it's not super important to get up to date value of mStatus for this
+ // warning print, hence skipping the lock here
+ if (mStatus == STATUS_ERROR) {
+ // Per API contract, HAL should act as closed after device error
+ // But mStatus can be set to error by framework as well, so just log
+ // a warning here.
+ ALOGW("%s: received notify message in error state.", __FUNCTION__);
+ }
+
+ sp<NotificationListener> listener;
+ {
+ std::lock_guard<std::mutex> l(mOutputLock);
+ listener = mListener.promote();
+ }
+
+ HidlCaptureOutputStates states {
+ {mId,
+ mInFlightLock, mLastCompletedRegularFrameNumber,
+ mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+ mInFlightMap, mOutputLock, mResultQueue, mResultSignal,
+ mNextShutterFrameNumber,
+ mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+ mNextResultFrameNumber,
+ mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+ mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+ mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+ mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
+ *mInterface, mLegacyClient}, mResultMetadataQueue
+ };
+ for (const auto& msg : msgs) {
+ camera3::notify(states, msg);
+ }
+ return hardware::Void();
+}
+
+status_t HidlCamera3Device::switchToOffline(
+ const std::vector<int32_t>& streamsToKeep,
+ /*out*/ sp<CameraOfflineSessionBase>* session) {
+ ATRACE_CALL();
+ if (session == nullptr) {
+ ALOGE("%s: session must not be null", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock il(mInterfaceLock);
+
+ bool hasInputStream = mInputStream != nullptr;
+ int32_t inputStreamId = hasInputStream ? mInputStream->getId() : -1;
+ bool inputStreamSupportsOffline = hasInputStream ?
+ mInputStream->getOfflineProcessingSupport() : false;
+ auto outputStreamIds = mOutputStreams.getStreamIds();
+ auto streamIds = outputStreamIds;
+ if (hasInputStream) {
+ streamIds.push_back(mInputStream->getId());
+ }
+
+ // Check all streams in streamsToKeep supports offline mode
+ for (auto id : streamsToKeep) {
+ if (std::find(streamIds.begin(), streamIds.end(), id) == streamIds.end()) {
+ ALOGE("%s: Unknown stream ID %d", __FUNCTION__, id);
+ return BAD_VALUE;
+ } else if (id == inputStreamId) {
+ if (!inputStreamSupportsOffline) {
+ ALOGE("%s: input stream %d cannot be switched to offline",
+ __FUNCTION__, id);
+ return BAD_VALUE;
+ }
+ } else {
+ sp<camera3::Camera3OutputStreamInterface> stream = mOutputStreams.get(id);
+ if (!stream->getOfflineProcessingSupport()) {
+ ALOGE("%s: output stream %d cannot be switched to offline",
+ __FUNCTION__, id);
+ return BAD_VALUE;
+ }
+ }
+ }
+ // TODO: block surface sharing and surface group streams until we can support them
+
+ // Stop repeating request, wait until all remaining requests are submitted, then call into
+ // HAL switchToOffline
+ hardware::camera::device::V3_6::CameraOfflineSessionInfo offlineSessionInfo;
+ sp<hardware::camera::device::V3_6::ICameraOfflineSession> offlineSession;
+ camera3::BufferRecords bufferRecords;
+ status_t ret = static_cast<HidlRequestThread *>(mRequestThread.get())->switchToOffline(
+ streamsToKeep, &offlineSessionInfo, &offlineSession, &bufferRecords);
+
+ if (ret != OK) {
+ SET_ERR("Switch to offline failed: %s (%d)", strerror(-ret), ret);
+ return ret;
+ }
+
+ bool succ = mRequestBufferSM.onSwitchToOfflineSuccess();
+ if (!succ) {
+ SET_ERR("HAL must not be calling requestStreamBuffers call");
+ // TODO: block ALL callbacks from HAL till app configured new streams?
+ return UNKNOWN_ERROR;
+ }
+
+ // Verify offlineSessionInfo
+ std::vector<int32_t> offlineStreamIds;
+ offlineStreamIds.reserve(offlineSessionInfo.offlineStreams.size());
+ for (auto offlineStream : offlineSessionInfo.offlineStreams) {
+ // verify stream IDs
+ int32_t id = offlineStream.id;
+ if (std::find(streamIds.begin(), streamIds.end(), id) == streamIds.end()) {
+ SET_ERR("stream ID %d not found!", id);
+ return UNKNOWN_ERROR;
+ }
+
+ // When not using HAL buf manager, only allow streams requested by app to be preserved
+ if (!mUseHalBufManager) {
+ if (std::find(streamsToKeep.begin(), streamsToKeep.end(), id) == streamsToKeep.end()) {
+ SET_ERR("stream ID %d must not be switched to offline!", id);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ offlineStreamIds.push_back(id);
+ sp<Camera3StreamInterface> stream = (id == inputStreamId) ?
+ static_cast<sp<Camera3StreamInterface>>(mInputStream) :
+ static_cast<sp<Camera3StreamInterface>>(mOutputStreams.get(id));
+ // Verify number of outstanding buffers
+ if (stream->getOutstandingBuffersCount() != offlineStream.numOutstandingBuffers) {
+ SET_ERR("Offline stream %d # of remaining buffer mismatch: (%zu,%d) (service/HAL)",
+ id, stream->getOutstandingBuffersCount(), offlineStream.numOutstandingBuffers);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ // Verify all streams to be deleted don't have any outstanding buffers
+ if (hasInputStream && std::find(offlineStreamIds.begin(), offlineStreamIds.end(),
+ inputStreamId) == offlineStreamIds.end()) {
+ if (mInputStream->hasOutstandingBuffers()) {
+ SET_ERR("Input stream %d still has %zu outstanding buffer!",
+ inputStreamId, mInputStream->getOutstandingBuffersCount());
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ for (const auto& outStreamId : outputStreamIds) {
+ if (std::find(offlineStreamIds.begin(), offlineStreamIds.end(),
+ outStreamId) == offlineStreamIds.end()) {
+ auto outStream = mOutputStreams.get(outStreamId);
+ if (outStream->hasOutstandingBuffers()) {
+ SET_ERR("Output stream %d still has %zu outstanding buffer!",
+ outStreamId, outStream->getOutstandingBuffersCount());
+ return UNKNOWN_ERROR;
+ }
+ }
+ }
+
+ InFlightRequestMap offlineReqs;
+ // Verify inflight requests and their pending buffers
+ {
+ std::lock_guard<std::mutex> l(mInFlightLock);
+ for (auto offlineReq : offlineSessionInfo.offlineRequests) {
+ int idx = mInFlightMap.indexOfKey(offlineReq.frameNumber);
+ if (idx == NAME_NOT_FOUND) {
+ SET_ERR("Offline request frame number %d not found!", offlineReq.frameNumber);
+ return UNKNOWN_ERROR;
+ }
+
+ const auto& inflightReq = mInFlightMap.valueAt(idx);
+ // TODO: check specific stream IDs
+ size_t numBuffersLeft = static_cast<size_t>(inflightReq.numBuffersLeft);
+ if (numBuffersLeft != offlineReq.pendingStreams.size()) {
+ SET_ERR("Offline request # of remaining buffer mismatch: (%d,%d) (service/HAL)",
+ inflightReq.numBuffersLeft, offlineReq.pendingStreams.size());
+ return UNKNOWN_ERROR;
+ }
+ offlineReqs.add(offlineReq.frameNumber, inflightReq);
+ }
+ }
+
+ // Create Camera3OfflineSession and transfer object ownership
+ // (streams, inflight requests, buffer caches)
+ camera3::StreamSet offlineStreamSet;
+ sp<camera3::Camera3Stream> inputStream;
+ for (auto offlineStream : offlineSessionInfo.offlineStreams) {
+ int32_t id = offlineStream.id;
+ if (mInputStream != nullptr && id == mInputStream->getId()) {
+ inputStream = mInputStream;
+ } else {
+ offlineStreamSet.add(id, mOutputStreams.get(id));
+ }
+ }
+
+ // TODO: check if we need to lock before copying states
+ // though technically no other thread should be talking to Camera3Device at this point
+ Camera3OfflineStates offlineStates(
+ mTagMonitor, mVendorTagId, mUseHalBufManager, mNeedFixupMonochromeTags,
+ mUsePartialResult, mNumPartialResults, mLastCompletedRegularFrameNumber,
+ mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+ mNextResultFrameNumber, mNextReprocessResultFrameNumber,
+ mNextZslStillResultFrameNumber, mNextShutterFrameNumber,
+ mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+ mDeviceInfo, mPhysicalDeviceInfoMap, mDistortionMappers,
+ mZoomRatioMappers, mRotateAndCropMappers);
+
+ *session = new HidlCamera3OfflineSession(mId, inputStream, offlineStreamSet,
+ std::move(bufferRecords), offlineReqs, offlineStates, offlineSession);
+
+ // Delete all streams that has been transferred to offline session
+ Mutex::Autolock l(mLock);
+ for (auto offlineStream : offlineSessionInfo.offlineStreams) {
+ int32_t id = offlineStream.id;
+ if (mInputStream != nullptr && id == mInputStream->getId()) {
+ mInputStream.clear();
+ } else {
+ mOutputStreams.remove(id);
+ }
+ }
+
+ // disconnect all other streams and switch to UNCONFIGURED state
+ if (mInputStream != nullptr) {
+ ret = mInputStream->disconnect();
+ if (ret != OK) {
+ SET_ERR_L("disconnect input stream failed!");
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ for (auto streamId : mOutputStreams.getStreamIds()) {
+ sp<Camera3StreamInterface> stream = mOutputStreams.get(streamId);
+ ret = stream->disconnect();
+ if (ret != OK) {
+ SET_ERR_L("disconnect output stream %d failed!", streamId);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ mInputStream.clear();
+ mOutputStreams.clear();
+ mNeedConfig = true;
+ internalUpdateStatusLocked(STATUS_UNCONFIGURED);
+ mOperatingMode = NO_MODE;
+ mIsConstrainedHighSpeedConfiguration = false;
+ mRequestThread->clearPreviousRequest();
+
+ return OK;
+ // TO be done by CameraDeviceClient/Camera3OfflineSession
+ // register the offline client to camera service
+ // Setup result passthing threads etc
+ // Initialize offline session so HAL can start sending callback to it (result Fmq)
+ // TODO: check how many onIdle callback will be sent
+ // Java side to make sure the CameraCaptureSession is properly closed
+}
+
+sp<Camera3Device::RequestThread> HidlCamera3Device::createNewRequestThread(
+ wp<Camera3Device> parent, sp<camera3::StatusTracker> statusTracker,
+ sp<Camera3Device::HalInterface> interface,
+ const Vector<int32_t>& sessionParamKeys,
+ bool useHalBufManager,
+ bool supportCameraMute) {
+ return new HidlRequestThread(parent, statusTracker, interface, sessionParamKeys,
+ useHalBufManager, supportCameraMute);
+};
+
+sp<Camera3Device::Camera3DeviceInjectionMethods>
+HidlCamera3Device::createCamera3DeviceInjectionMethods(wp<Camera3Device> parent) {
+ return new HidlCamera3DeviceInjectionMethods(parent);
+}
+
+status_t HidlCamera3Device::injectionCameraInitialize(const String8 &injectedCamId,
+ sp<CameraProviderManager> manager) {
+ return (static_cast<HidlCamera3DeviceInjectionMethods *>(
+ mInjectionMethods.get()))->injectionInitialize(injectedCamId, manager, this);
+};
+
+
+HidlCamera3Device::HidlHalInterface::HidlHalInterface(
+ sp<device::V3_2::ICameraDeviceSession> &session,
+ std::shared_ptr<RequestMetadataQueue> queue,
+ bool useHalBufManager, bool supportOfflineProcessing) :
+ HalInterface(useHalBufManager, supportOfflineProcessing),
+ mHidlSession(session),
+ mRequestMetadataQueue(queue) {
+ // Check with hardware service manager if we can downcast these interfaces
+ // Somewhat expensive, so cache the results at startup
+ auto castResult_3_8 = device::V3_8::ICameraDeviceSession::castFrom(mHidlSession);
+ if (castResult_3_8.isOk()) {
+ mHidlSession_3_8 = castResult_3_8;
+ }
+ auto castResult_3_7 = device::V3_7::ICameraDeviceSession::castFrom(mHidlSession);
+ if (castResult_3_7.isOk()) {
+ mHidlSession_3_7 = castResult_3_7;
+ }
+ auto castResult_3_6 = device::V3_6::ICameraDeviceSession::castFrom(mHidlSession);
+ if (castResult_3_6.isOk()) {
+ mHidlSession_3_6 = castResult_3_6;
+ }
+ auto castResult_3_5 = device::V3_5::ICameraDeviceSession::castFrom(mHidlSession);
+ if (castResult_3_5.isOk()) {
+ mHidlSession_3_5 = castResult_3_5;
+ }
+ auto castResult_3_4 = device::V3_4::ICameraDeviceSession::castFrom(mHidlSession);
+ if (castResult_3_4.isOk()) {
+ mHidlSession_3_4 = castResult_3_4;
+ }
+ auto castResult_3_3 = device::V3_3::ICameraDeviceSession::castFrom(mHidlSession);
+ if (castResult_3_3.isOk()) {
+ mHidlSession_3_3 = castResult_3_3;
+ }
+}
+
+bool HidlCamera3Device::HidlHalInterface::valid() {
+ return (mHidlSession != nullptr);
+}
+
+void HidlCamera3Device::HidlHalInterface::clear() {
+ mHidlSession_3_8.clear();
+ mHidlSession_3_7.clear();
+ mHidlSession_3_6.clear();
+ mHidlSession_3_5.clear();
+ mHidlSession_3_4.clear();
+ mHidlSession_3_3.clear();
+ mHidlSession.clear();
+}
+
+status_t HidlCamera3Device::HidlHalInterface::constructDefaultRequestSettings(
+ camera_request_template_t templateId,
+ /*out*/ camera_metadata_t **requestTemplate) {
+ ATRACE_NAME("CameraHidlHal::constructDefaultRequestSettings");
+ if (!valid()) return INVALID_OPERATION;
+ status_t res = OK;
+
+ common::V1_0::Status status;
+
+ auto requestCallback = [&status, &requestTemplate]
+ (common::V1_0::Status s, const device::V3_2::CameraMetadata& request) {
+ status = s;
+ if (status == common::V1_0::Status::OK) {
+ const camera_metadata *r =
+ reinterpret_cast<const camera_metadata_t*>(request.data());
+ size_t expectedSize = request.size();
+ int ret = validate_camera_metadata_structure(r, &expectedSize);
+ if (ret == OK || ret == CAMERA_METADATA_VALIDATION_SHIFTED) {
+ *requestTemplate = clone_camera_metadata(r);
+ if (*requestTemplate == nullptr) {
+ ALOGE("%s: Unable to clone camera metadata received from HAL",
+ __FUNCTION__);
+ status = common::V1_0::Status::INTERNAL_ERROR;
+ }
+ } else {
+ ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
+ status = common::V1_0::Status::INTERNAL_ERROR;
+ }
+ }
+ };
+ hardware::Return<void> err;
+ RequestTemplate id;
+ switch (templateId) {
+ case CAMERA_TEMPLATE_PREVIEW:
+ id = RequestTemplate::PREVIEW;
+ break;
+ case CAMERA_TEMPLATE_STILL_CAPTURE:
+ id = RequestTemplate::STILL_CAPTURE;
+ break;
+ case CAMERA_TEMPLATE_VIDEO_RECORD:
+ id = RequestTemplate::VIDEO_RECORD;
+ break;
+ case CAMERA_TEMPLATE_VIDEO_SNAPSHOT:
+ id = RequestTemplate::VIDEO_SNAPSHOT;
+ break;
+ case CAMERA_TEMPLATE_ZERO_SHUTTER_LAG:
+ id = RequestTemplate::ZERO_SHUTTER_LAG;
+ break;
+ case CAMERA_TEMPLATE_MANUAL:
+ id = RequestTemplate::MANUAL;
+ break;
+ default:
+ // Unknown template ID, or this HAL is too old to support it
+ return BAD_VALUE;
+ }
+ err = mHidlSession->constructDefaultRequestSettings(id, requestCallback);
+
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+ res = DEAD_OBJECT;
+ } else {
+ res = HidlProviderInfo::mapToStatusT(status);
+ }
+
+ return res;
+}
+
+bool HidlCamera3Device::HidlHalInterface::isReconfigurationRequired(
+ CameraMetadata& oldSessionParams, CameraMetadata& newSessionParams) {
+ // We do reconfiguration by default;
+ bool ret = true;
+ if ((mHidlSession_3_5 != nullptr) && mIsReconfigurationQuerySupported) {
+ android::hardware::hidl_vec<uint8_t> oldParams, newParams;
+ camera_metadata_t* oldSessioMeta = const_cast<camera_metadata_t*>(
+ oldSessionParams.getAndLock());
+ camera_metadata_t* newSessioMeta = const_cast<camera_metadata_t*>(
+ newSessionParams.getAndLock());
+ oldParams.setToExternal(reinterpret_cast<uint8_t*>(oldSessioMeta),
+ get_camera_metadata_size(oldSessioMeta));
+ newParams.setToExternal(reinterpret_cast<uint8_t*>(newSessioMeta),
+ get_camera_metadata_size(newSessioMeta));
+ hardware::camera::common::V1_0::Status callStatus;
+ bool required;
+ auto hidlCb = [&callStatus, &required] (hardware::camera::common::V1_0::Status s,
+ bool requiredFlag) {
+ callStatus = s;
+ required = requiredFlag;
+ };
+ auto err = mHidlSession_3_5->isReconfigurationRequired(oldParams, newParams, hidlCb);
+ oldSessionParams.unlock(oldSessioMeta);
+ newSessionParams.unlock(newSessioMeta);
+ if (err.isOk()) {
+ switch (callStatus) {
+ case hardware::camera::common::V1_0::Status::OK:
+ ret = required;
+ break;
+ case hardware::camera::common::V1_0::Status::METHOD_NOT_SUPPORTED:
+ mIsReconfigurationQuerySupported = false;
+ ret = true;
+ break;
+ default:
+ ALOGV("%s: Reconfiguration query failed: %d", __FUNCTION__, callStatus);
+ ret = true;
+ }
+ } else {
+ ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, err.description().c_str());
+ ret = true;
+ }
+ }
+
+ return ret;
+}
+
+status_t HidlCamera3Device::HidlHalInterface::configureStreams(
+ const camera_metadata_t *sessionParams,
+ camera_stream_configuration *config, const std::vector<uint32_t>& bufferSizes) {
+ ATRACE_NAME("CameraHal::configureStreams");
+ if (!valid()) return INVALID_OPERATION;
+ status_t res = OK;
+
+ if (config->input_is_multi_resolution && mHidlSession_3_7 == nullptr) {
+ ALOGE("%s: Camera device doesn't support multi-resolution input stream", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ // Convert stream config to HIDL
+ std::set<int> activeStreams;
+ device::V3_2::StreamConfiguration requestedConfiguration3_2;
+ device::V3_4::StreamConfiguration requestedConfiguration3_4;
+ device::V3_7::StreamConfiguration requestedConfiguration3_7;
+ device::V3_8::StreamConfiguration requestedConfiguration3_8;
+ requestedConfiguration3_2.streams.resize(config->num_streams);
+ requestedConfiguration3_4.streams.resize(config->num_streams);
+ requestedConfiguration3_7.streams.resize(config->num_streams);
+ requestedConfiguration3_8.streams.resize(config->num_streams);
+ for (size_t i = 0; i < config->num_streams; i++) {
+ device::V3_2::Stream &dst3_2 = requestedConfiguration3_2.streams[i];
+ device::V3_4::Stream &dst3_4 = requestedConfiguration3_4.streams[i];
+ device::V3_7::Stream &dst3_7 = requestedConfiguration3_7.streams[i];
+ device::V3_8::Stream &dst3_8 = requestedConfiguration3_8.streams[i];
+ camera3::camera_stream_t *src = config->streams[i];
+
+ Camera3Stream* cam3stream = Camera3Stream::cast(src);
+ cam3stream->setBufferFreedListener(this);
+ int streamId = cam3stream->getId();
+ StreamType streamType;
+ switch (src->stream_type) {
+ case CAMERA_STREAM_OUTPUT:
+ streamType = StreamType::OUTPUT;
+ break;
+ case CAMERA_STREAM_INPUT:
+ streamType = StreamType::INPUT;
+ break;
+ default:
+ ALOGE("%s: Stream %d: Unsupported stream type %d",
+ __FUNCTION__, streamId, config->streams[i]->stream_type);
+ return BAD_VALUE;
+ }
+ dst3_2.id = streamId;
+ dst3_2.streamType = streamType;
+ dst3_2.width = src->width;
+ dst3_2.height = src->height;
+ dst3_2.usage = mapToConsumerUsage(cam3stream->getUsage());
+ dst3_2.rotation = mapToStreamRotation((camera_stream_rotation_t) src->rotation);
+ // For HidlSession version 3.5 or newer, the format and dataSpace sent
+ // to HAL are original, not the overridden ones.
+ if (mHidlSession_3_5 != nullptr) {
+ dst3_2.format = mapToPixelFormat(cam3stream->isFormatOverridden() ?
+ cam3stream->getOriginalFormat() : src->format);
+ dst3_2.dataSpace = mapToHidlDataspace(cam3stream->isDataSpaceOverridden() ?
+ cam3stream->getOriginalDataSpace() : src->data_space);
+ } else {
+ dst3_2.format = mapToPixelFormat(src->format);
+ dst3_2.dataSpace = mapToHidlDataspace(src->data_space);
+ }
+ dst3_4.v3_2 = dst3_2;
+ dst3_4.bufferSize = bufferSizes[i];
+ if (src->physical_camera_id != nullptr) {
+ dst3_4.physicalCameraId = src->physical_camera_id;
+ }
+ dst3_7.v3_4 = dst3_4;
+ dst3_7.groupId = cam3stream->getHalStreamGroupId();
+ dst3_7.sensorPixelModesUsed.resize(src->sensor_pixel_modes_used.size());
+ size_t j = 0;
+ for (int mode : src->sensor_pixel_modes_used) {
+ dst3_7.sensorPixelModesUsed[j++] =
+ static_cast<CameraMetadataEnumAndroidSensorPixelMode>(mode);
+ }
+ if ((src->dynamic_range_profile !=
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) &&
+ (mHidlSession_3_8 == nullptr)) {
+ ALOGE("%s: Camera device doesn't support non-standard dynamic range profiles: %d",
+ __FUNCTION__, src->dynamic_range_profile);
+ return BAD_VALUE;
+ }
+ if (src->use_case != ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT &&
+ mHidlSession_3_8 == nullptr) {
+ ALOGE("%s: Camera device doesn't support non-default stream use case %d!",
+ __FUNCTION__, src->use_case);
+ return BAD_VALUE;
+ }
+ dst3_8.v3_7 = dst3_7;
+ dst3_8.dynamicRangeProfile = mapToHidlDynamicProfile(src->dynamic_range_profile);
+ dst3_8.useCase =
+ static_cast<CameraMetadataEnumAndroidScalerAvailableStreamUseCases>(src->use_case);
+ activeStreams.insert(streamId);
+ // Create Buffer ID map if necessary
+ mBufferRecords.tryCreateBufferCache(streamId);
+ }
+ // remove BufferIdMap for deleted streams
+ mBufferRecords.removeInactiveBufferCaches(activeStreams);
+
+ StreamConfigurationMode operationMode;
+ res = mapToStreamConfigurationMode(
+ (camera_stream_configuration_mode_t) config->operation_mode,
+ /*out*/ &operationMode);
+ if (res != OK) {
+ return res;
+ }
+ requestedConfiguration3_2.operationMode = operationMode;
+ requestedConfiguration3_4.operationMode = operationMode;
+ requestedConfiguration3_7.operationMode = operationMode;
+ size_t sessionParamSize = get_camera_metadata_size(sessionParams);
+ requestedConfiguration3_4.sessionParams.setToExternal(
+ reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
+ sessionParamSize);
+ requestedConfiguration3_7.sessionParams.setToExternal(
+ reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
+ sessionParamSize);
+ requestedConfiguration3_8.operationMode = operationMode;
+ requestedConfiguration3_8.sessionParams.setToExternal(
+ reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
+ sessionParamSize);
+
+ // Invoke configureStreams
+ device::V3_3::HalStreamConfiguration finalConfiguration;
+ device::V3_4::HalStreamConfiguration finalConfiguration3_4;
+ device::V3_6::HalStreamConfiguration finalConfiguration3_6;
+ common::V1_0::Status status;
+
+ auto configStream34Cb = [&status, &finalConfiguration3_4]
+ (common::V1_0::Status s, const device::V3_4::HalStreamConfiguration& halConfiguration) {
+ finalConfiguration3_4 = halConfiguration;
+ status = s;
+ };
+
+ auto configStream36Cb = [&status, &finalConfiguration3_6]
+ (common::V1_0::Status s, const device::V3_6::HalStreamConfiguration& halConfiguration) {
+ finalConfiguration3_6 = halConfiguration;
+ status = s;
+ };
+
+ auto postprocConfigStream34 = [&finalConfiguration, &finalConfiguration3_4]
+ (hardware::Return<void>& err) -> status_t {
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+ return DEAD_OBJECT;
+ }
+ finalConfiguration.streams.resize(finalConfiguration3_4.streams.size());
+ for (size_t i = 0; i < finalConfiguration3_4.streams.size(); i++) {
+ finalConfiguration.streams[i] = finalConfiguration3_4.streams[i].v3_3;
+ }
+ return OK;
+ };
+
+ auto postprocConfigStream36 = [&finalConfiguration, &finalConfiguration3_6]
+ (hardware::Return<void>& err) -> status_t {
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+ return DEAD_OBJECT;
+ }
+ finalConfiguration.streams.resize(finalConfiguration3_6.streams.size());
+ for (size_t i = 0; i < finalConfiguration3_6.streams.size(); i++) {
+ finalConfiguration.streams[i] = finalConfiguration3_6.streams[i].v3_4.v3_3;
+ }
+ return OK;
+ };
+
+ // See which version of HAL we have
+ if (mHidlSession_3_8 != nullptr) {
+ ALOGV("%s: v3.8 device found", __FUNCTION__);
+ requestedConfiguration3_8.streamConfigCounter = mNextStreamConfigCounter++;
+ requestedConfiguration3_8.multiResolutionInputImage = config->input_is_multi_resolution;
+ auto err = mHidlSession_3_8->configureStreams_3_8(requestedConfiguration3_8,
+ configStream36Cb);
+ res = postprocConfigStream36(err);
+ if (res != OK) {
+ return res;
+ }
+ } else if (mHidlSession_3_7 != nullptr) {
+ ALOGV("%s: v3.7 device found", __FUNCTION__);
+ requestedConfiguration3_7.streamConfigCounter = mNextStreamConfigCounter++;
+ requestedConfiguration3_7.multiResolutionInputImage = config->input_is_multi_resolution;
+ auto err = mHidlSession_3_7->configureStreams_3_7(
+ requestedConfiguration3_7, configStream36Cb);
+ res = postprocConfigStream36(err);
+ if (res != OK) {
+ return res;
+ }
+ } else if (mHidlSession_3_6 != nullptr) {
+ ALOGV("%s: v3.6 device found", __FUNCTION__);
+ device::V3_5::StreamConfiguration requestedConfiguration3_5;
+ requestedConfiguration3_5.v3_4 = requestedConfiguration3_4;
+ requestedConfiguration3_5.streamConfigCounter = mNextStreamConfigCounter++;
+ auto err = mHidlSession_3_6->configureStreams_3_6(
+ requestedConfiguration3_5, configStream36Cb);
+ res = postprocConfigStream36(err);
+ if (res != OK) {
+ return res;
+ }
+ } else if (mHidlSession_3_5 != nullptr) {
+ ALOGV("%s: v3.5 device found", __FUNCTION__);
+ device::V3_5::StreamConfiguration requestedConfiguration3_5;
+ requestedConfiguration3_5.v3_4 = requestedConfiguration3_4;
+ requestedConfiguration3_5.streamConfigCounter = mNextStreamConfigCounter++;
+ auto err = mHidlSession_3_5->configureStreams_3_5(
+ requestedConfiguration3_5, configStream34Cb);
+ res = postprocConfigStream34(err);
+ if (res != OK) {
+ return res;
+ }
+ } else if (mHidlSession_3_4 != nullptr) {
+ // We do; use v3.4 for the call
+ ALOGV("%s: v3.4 device found", __FUNCTION__);
+ auto err = mHidlSession_3_4->configureStreams_3_4(
+ requestedConfiguration3_4, configStream34Cb);
+ res = postprocConfigStream34(err);
+ if (res != OK) {
+ return res;
+ }
+ } else if (mHidlSession_3_3 != nullptr) {
+ // We do; use v3.3 for the call
+ ALOGV("%s: v3.3 device found", __FUNCTION__);
+ auto err = mHidlSession_3_3->configureStreams_3_3(requestedConfiguration3_2,
+ [&status, &finalConfiguration]
+ (common::V1_0::Status s, const device::V3_3::HalStreamConfiguration& halConfiguration) {
+ finalConfiguration = halConfiguration;
+ status = s;
+ });
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+ return DEAD_OBJECT;
+ }
+ } else {
+ // We don't; use v3.2 call and construct a v3.3 HalStreamConfiguration
+ ALOGV("%s: v3.2 device found", __FUNCTION__);
+ HalStreamConfiguration finalConfiguration_3_2;
+ auto err = mHidlSession->configureStreams(requestedConfiguration3_2,
+ [&status, &finalConfiguration_3_2]
+ (common::V1_0::Status s, const HalStreamConfiguration& halConfiguration) {
+ finalConfiguration_3_2 = halConfiguration;
+ status = s;
+ });
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+ return DEAD_OBJECT;
+ }
+ finalConfiguration.streams.resize(finalConfiguration_3_2.streams.size());
+ for (size_t i = 0; i < finalConfiguration_3_2.streams.size(); i++) {
+ finalConfiguration.streams[i].v3_2 = finalConfiguration_3_2.streams[i];
+ finalConfiguration.streams[i].overrideDataSpace =
+ requestedConfiguration3_2.streams[i].dataSpace;
+ }
+ }
+
+ if (status != common::V1_0::Status::OK ) {
+ return HidlProviderInfo::mapToStatusT(status);
+ }
+
+ // And convert output stream configuration from HIDL
+
+ for (size_t i = 0; i < config->num_streams; i++) {
+ camera3::camera_stream_t *dst = config->streams[i];
+ int streamId = Camera3Stream::cast(dst)->getId();
+
+ // Start scan at i, with the assumption that the stream order matches
+ size_t realIdx = i;
+ bool found = false;
+ size_t halStreamCount = finalConfiguration.streams.size();
+ for (size_t idx = 0; idx < halStreamCount; idx++) {
+ if (finalConfiguration.streams[realIdx].v3_2.id == streamId) {
+ found = true;
+ break;
+ }
+ realIdx = (realIdx >= halStreamCount - 1) ? 0 : realIdx + 1;
+ }
+ if (!found) {
+ ALOGE("%s: Stream %d not found in stream configuration response from HAL",
+ __FUNCTION__, streamId);
+ return INVALID_OPERATION;
+ }
+ device::V3_3::HalStream &src = finalConfiguration.streams[realIdx];
+ device::V3_6::HalStream &src_36 = finalConfiguration3_6.streams[realIdx];
+
+ Camera3Stream* dstStream = Camera3Stream::cast(dst);
+ int overrideFormat = mapToFrameworkFormat(src.v3_2.overrideFormat);
+ android_dataspace overrideDataSpace = mapToFrameworkDataspace(src.overrideDataSpace);
+
+ if (mHidlSession_3_6 != nullptr) {
+ dstStream->setOfflineProcessingSupport(src_36.supportOffline);
+ }
+
+ if (dstStream->getOriginalFormat() != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+ dstStream->setFormatOverride(false);
+ dstStream->setDataSpaceOverride(false);
+ if (dst->format != overrideFormat) {
+ ALOGE("%s: Stream %d: Format override not allowed for format 0x%x", __FUNCTION__,
+ streamId, dst->format);
+ }
+ if (dst->data_space != overrideDataSpace) {
+ ALOGE("%s: Stream %d: DataSpace override not allowed for format 0x%x", __FUNCTION__,
+ streamId, dst->format);
+ }
+ } else {
+ bool needFormatOverride =
+ requestedConfiguration3_2.streams[i].format != src.v3_2.overrideFormat;
+ bool needDataspaceOverride =
+ requestedConfiguration3_2.streams[i].dataSpace != src.overrideDataSpace;
+ // Override allowed with IMPLEMENTATION_DEFINED
+ dstStream->setFormatOverride(needFormatOverride);
+ dstStream->setDataSpaceOverride(needDataspaceOverride);
+ dst->format = overrideFormat;
+ dst->data_space = overrideDataSpace;
+ }
+
+ if (dst->stream_type == CAMERA_STREAM_INPUT) {
+ if (src.v3_2.producerUsage != 0) {
+ ALOGE("%s: Stream %d: INPUT streams must have 0 for producer usage",
+ __FUNCTION__, streamId);
+ return INVALID_OPERATION;
+ }
+ dstStream->setUsage(
+ mapConsumerToFrameworkUsage(src.v3_2.consumerUsage));
+ } else {
+ // OUTPUT
+ if (src.v3_2.consumerUsage != 0) {
+ ALOGE("%s: Stream %d: OUTPUT streams must have 0 for consumer usage",
+ __FUNCTION__, streamId);
+ return INVALID_OPERATION;
+ }
+ dstStream->setUsage(
+ mapProducerToFrameworkUsage(src.v3_2.producerUsage));
+ }
+ dst->max_buffers = src.v3_2.maxBuffers;
+ }
+
+ return res;
+}
+
+status_t HidlCamera3Device::HidlHalInterface::configureInjectedStreams(
+ const camera_metadata_t* sessionParams, camera_stream_configuration* config,
+ const std::vector<uint32_t>& bufferSizes,
+ const CameraMetadata& cameraCharacteristics) {
+ ATRACE_NAME("InjectionCameraHal::configureStreams");
+ if (!valid()) return INVALID_OPERATION;
+ status_t res = OK;
+
+ if (config->input_is_multi_resolution) {
+ ALOGE("%s: Injection camera device doesn't support multi-resolution input "
+ "stream", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ // Convert stream config to HIDL
+ std::set<int> activeStreams;
+ device::V3_2::StreamConfiguration requestedConfiguration3_2;
+ device::V3_4::StreamConfiguration requestedConfiguration3_4;
+ device::V3_7::StreamConfiguration requestedConfiguration3_7;
+ requestedConfiguration3_2.streams.resize(config->num_streams);
+ requestedConfiguration3_4.streams.resize(config->num_streams);
+ requestedConfiguration3_7.streams.resize(config->num_streams);
+ for (size_t i = 0; i < config->num_streams; i++) {
+ device::V3_2::Stream& dst3_2 = requestedConfiguration3_2.streams[i];
+ device::V3_4::Stream& dst3_4 = requestedConfiguration3_4.streams[i];
+ device::V3_7::Stream& dst3_7 = requestedConfiguration3_7.streams[i];
+ camera3::camera_stream_t* src = config->streams[i];
+
+ Camera3Stream* cam3stream = Camera3Stream::cast(src);
+ cam3stream->setBufferFreedListener(this);
+ int streamId = cam3stream->getId();
+ StreamType streamType;
+ switch (src->stream_type) {
+ case CAMERA_STREAM_OUTPUT:
+ streamType = StreamType::OUTPUT;
+ break;
+ case CAMERA_STREAM_INPUT:
+ streamType = StreamType::INPUT;
+ break;
+ default:
+ ALOGE("%s: Stream %d: Unsupported stream type %d", __FUNCTION__,
+ streamId, config->streams[i]->stream_type);
+ return BAD_VALUE;
+ }
+ dst3_2.id = streamId;
+ dst3_2.streamType = streamType;
+ dst3_2.width = src->width;
+ dst3_2.height = src->height;
+ dst3_2.usage = mapToConsumerUsage(cam3stream->getUsage());
+ dst3_2.rotation =
+ mapToStreamRotation((camera_stream_rotation_t)src->rotation);
+ // For HidlSession version 3.5 or newer, the format and dataSpace sent
+ // to HAL are original, not the overridden ones.
+ if (mHidlSession_3_5 != nullptr) {
+ dst3_2.format = mapToPixelFormat(cam3stream->isFormatOverridden()
+ ? cam3stream->getOriginalFormat()
+ : src->format);
+ dst3_2.dataSpace =
+ mapToHidlDataspace(cam3stream->isDataSpaceOverridden()
+ ? cam3stream->getOriginalDataSpace()
+ : src->data_space);
+ } else {
+ dst3_2.format = mapToPixelFormat(src->format);
+ dst3_2.dataSpace = mapToHidlDataspace(src->data_space);
+ }
+ dst3_4.v3_2 = dst3_2;
+ dst3_4.bufferSize = bufferSizes[i];
+ if (src->physical_camera_id != nullptr) {
+ dst3_4.physicalCameraId = src->physical_camera_id;
+ }
+ dst3_7.v3_4 = dst3_4;
+ dst3_7.groupId = cam3stream->getHalStreamGroupId();
+ dst3_7.sensorPixelModesUsed.resize(src->sensor_pixel_modes_used.size());
+ size_t j = 0;
+ for (int mode : src->sensor_pixel_modes_used) {
+ dst3_7.sensorPixelModesUsed[j++] =
+ static_cast<CameraMetadataEnumAndroidSensorPixelMode>(mode);
+ }
+ activeStreams.insert(streamId);
+ // Create Buffer ID map if necessary
+ mBufferRecords.tryCreateBufferCache(streamId);
+ }
+ // remove BufferIdMap for deleted streams
+ mBufferRecords.removeInactiveBufferCaches(activeStreams);
+
+ StreamConfigurationMode operationMode;
+ res = mapToStreamConfigurationMode(
+ (camera_stream_configuration_mode_t)config->operation_mode,
+ /*out*/ &operationMode);
+ if (res != OK) {
+ return res;
+ }
+ requestedConfiguration3_7.operationMode = operationMode;
+ size_t sessionParamSize = get_camera_metadata_size(sessionParams);
+ requestedConfiguration3_7.operationMode = operationMode;
+ requestedConfiguration3_7.sessionParams.setToExternal(
+ reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
+ sessionParamSize);
+
+ // See which version of HAL we have
+ if (mHidlSession_3_7 != nullptr) {
+ requestedConfiguration3_7.streamConfigCounter = mNextStreamConfigCounter++;
+ requestedConfiguration3_7.multiResolutionInputImage =
+ config->input_is_multi_resolution;
+
+ const camera_metadata_t* rawMetadata = cameraCharacteristics.getAndLock();
+ ::android::hardware::camera::device::V3_2::CameraMetadata hidlChars = {};
+ hidlChars.setToExternal(
+ reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(rawMetadata)),
+ get_camera_metadata_size(rawMetadata));
+ cameraCharacteristics.unlock(rawMetadata);
+
+ sp<hardware::camera::device::V3_7::ICameraInjectionSession>
+ hidlInjectionSession_3_7;
+ auto castInjectionResult_3_7 =
+ device::V3_7::ICameraInjectionSession::castFrom(mHidlSession_3_7);
+ if (castInjectionResult_3_7.isOk()) {
+ hidlInjectionSession_3_7 = castInjectionResult_3_7;
+ } else {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__,
+ castInjectionResult_3_7.description().c_str());
+ return DEAD_OBJECT;
+ }
+
+ auto err = hidlInjectionSession_3_7->configureInjectionStreams(
+ requestedConfiguration3_7, hidlChars);
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__,
+ err.description().c_str());
+ return DEAD_OBJECT;
+ }
+ } else {
+ ALOGE("%s: mHidlSession_3_7 does not exist, the lowest version of injection "
+ "session is 3.7", __FUNCTION__);
+ return DEAD_OBJECT;
+ }
+
+ return res;
+}
+
+status_t HidlCamera3Device::HidlHalInterface::wrapAsHidlRequest(camera_capture_request_t* request,
+ /*out*/device::V3_2::CaptureRequest* captureRequest,
+ /*out*/std::vector<native_handle_t*>* handlesCreated,
+ /*out*/std::vector<std::pair<int32_t, int32_t>>* inflightBuffers) {
+ ATRACE_CALL();
+ if (captureRequest == nullptr || handlesCreated == nullptr || inflightBuffers == nullptr) {
+ ALOGE("%s: captureRequest (%p), handlesCreated (%p), and inflightBuffers(%p) "
+ "must not be null", __FUNCTION__, captureRequest, handlesCreated, inflightBuffers);
+ return BAD_VALUE;
+ }
+
+ captureRequest->frameNumber = request->frame_number;
+
+ captureRequest->fmqSettingsSize = 0;
+
+ {
+ if (request->input_buffer != nullptr) {
+ int32_t streamId = Camera3Stream::cast(request->input_buffer->stream)->getId();
+ buffer_handle_t buf = *(request->input_buffer->buffer);
+ auto pair = getBufferId(buf, streamId);
+ bool isNewBuffer = pair.first;
+ uint64_t bufferId = pair.second;
+ captureRequest->inputBuffer.streamId = streamId;
+ captureRequest->inputBuffer.bufferId = bufferId;
+ captureRequest->inputBuffer.buffer = (isNewBuffer) ? buf : nullptr;
+ captureRequest->inputBuffer.status = BufferStatus::OK;
+ native_handle_t *acquireFence = nullptr;
+ if (request->input_buffer->acquire_fence != -1) {
+ acquireFence = native_handle_create(1,0);
+ acquireFence->data[0] = request->input_buffer->acquire_fence;
+ handlesCreated->push_back(acquireFence);
+ }
+ captureRequest->inputBuffer.acquireFence = acquireFence;
+ captureRequest->inputBuffer.releaseFence = nullptr;
+
+ mBufferRecords.pushInflightBuffer(captureRequest->frameNumber, streamId,
+ request->input_buffer->buffer);
+ inflightBuffers->push_back(std::make_pair(captureRequest->frameNumber, streamId));
+ } else {
+ captureRequest->inputBuffer.streamId = -1;
+ captureRequest->inputBuffer.bufferId = BUFFER_ID_NO_BUFFER;
+ }
+
+ captureRequest->outputBuffers.resize(request->num_output_buffers);
+ for (size_t i = 0; i < request->num_output_buffers; i++) {
+ const camera_stream_buffer_t *src = request->output_buffers + i;
+ StreamBuffer &dst = captureRequest->outputBuffers[i];
+ int32_t streamId = Camera3Stream::cast(src->stream)->getId();
+ if (src->buffer != nullptr) {
+ buffer_handle_t buf = *(src->buffer);
+ auto pair = getBufferId(buf, streamId);
+ bool isNewBuffer = pair.first;
+ dst.bufferId = pair.second;
+ dst.buffer = isNewBuffer ? buf : nullptr;
+ native_handle_t *acquireFence = nullptr;
+ if (src->acquire_fence != -1) {
+ acquireFence = native_handle_create(1,0);
+ acquireFence->data[0] = src->acquire_fence;
+ handlesCreated->push_back(acquireFence);
+ }
+ dst.acquireFence = acquireFence;
+ } else if (mUseHalBufManager) {
+ // HAL buffer management path
+ dst.bufferId = BUFFER_ID_NO_BUFFER;
+ dst.buffer = nullptr;
+ dst.acquireFence = nullptr;
+ } else {
+ ALOGE("%s: cannot send a null buffer in capture request!", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ dst.streamId = streamId;
+ dst.status = BufferStatus::OK;
+ dst.releaseFence = nullptr;
+
+ // Output buffers are empty when using HAL buffer manager
+ if (!mUseHalBufManager) {
+ mBufferRecords.pushInflightBuffer(
+ captureRequest->frameNumber, streamId, src->buffer);
+ inflightBuffers->push_back(std::make_pair(captureRequest->frameNumber, streamId));
+ }
+ }
+ }
+ return OK;
+}
+
+status_t HidlCamera3Device::HidlHalInterface::flush() {
+ ATRACE_NAME("CameraHal::flush");
+ if (!valid()) return INVALID_OPERATION;
+ status_t res = OK;
+
+ auto err = mHidlSession->flush();
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+ res = DEAD_OBJECT;
+ } else {
+ res = HidlProviderInfo::mapToStatusT(err);
+ }
+
+ return res;
+}
+
+status_t HidlCamera3Device::HidlHalInterface::dump(int /*fd*/) {
+ ATRACE_NAME("CameraHal::dump");
+ if (!valid()) return INVALID_OPERATION;
+
+ // Handled by CameraProviderManager::dump
+
+ return OK;
+}
+
+status_t HidlCamera3Device::HidlHalInterface::repeatingRequestEnd(uint32_t frameNumber,
+ const std::vector<int32_t> &streamIds) {
+ ATRACE_NAME("CameraHal::repeatingRequestEnd");
+ if (!valid()) return INVALID_OPERATION;
+
+ if (mHidlSession_3_8.get() != nullptr) {
+ mHidlSession_3_8->repeatingRequestEnd(frameNumber, streamIds);
+ }
+ return OK;
+}
+
+status_t HidlCamera3Device::HidlHalInterface::close() {
+ ATRACE_NAME("CameraHal::close()");
+ if (!valid()) return INVALID_OPERATION;
+ status_t res = OK;
+
+ auto err = mHidlSession->close();
+ // Interface will be dead shortly anyway, so don't log errors
+ if (!err.isOk()) {
+ res = DEAD_OBJECT;
+ }
+
+ return res;
+}
+
+void HidlCamera3Device::HidlHalInterface::signalPipelineDrain(const std::vector<int>& streamIds) {
+ ATRACE_NAME("CameraHal::signalPipelineDrain");
+ if (!valid() || mHidlSession_3_5 == nullptr) {
+ ALOGE("%s called on invalid camera!", __FUNCTION__);
+ return;
+ }
+
+ auto err = mHidlSession_3_5->signalStreamFlush(streamIds, mNextStreamConfigCounter - 1);
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+ return;
+ }
+}
+
+status_t HidlCamera3Device::HidlHalInterface::processBatchCaptureRequests(
+ std::vector<camera_capture_request_t*>& requests,/*out*/uint32_t* numRequestProcessed) {
+ ATRACE_NAME("CameraHal::processBatchCaptureRequests");
+ if (!valid()) return INVALID_OPERATION;
+
+ sp<device::V3_4::ICameraDeviceSession> hidlSession_3_4;
+ sp<device::V3_7::ICameraDeviceSession> hidlSession_3_7;
+ auto castResult_3_7 = device::V3_7::ICameraDeviceSession::castFrom(mHidlSession);
+ if (castResult_3_7.isOk()) {
+ hidlSession_3_7 = castResult_3_7;
+ }
+ auto castResult_3_4 = device::V3_4::ICameraDeviceSession::castFrom(mHidlSession);
+ if (castResult_3_4.isOk()) {
+ hidlSession_3_4 = castResult_3_4;
+ }
+
+ hardware::hidl_vec<device::V3_2::CaptureRequest> captureRequests;
+ hardware::hidl_vec<device::V3_4::CaptureRequest> captureRequests_3_4;
+ hardware::hidl_vec<device::V3_7::CaptureRequest> captureRequests_3_7;
+ size_t batchSize = requests.size();
+ if (hidlSession_3_7 != nullptr) {
+ captureRequests_3_7.resize(batchSize);
+ } else if (hidlSession_3_4 != nullptr) {
+ captureRequests_3_4.resize(batchSize);
+ } else {
+ captureRequests.resize(batchSize);
+ }
+ std::vector<native_handle_t*> handlesCreated;
+ std::vector<std::pair<int32_t, int32_t>> inflightBuffers;
+
+ status_t res = OK;
+ for (size_t i = 0; i < batchSize; i++) {
+ if (hidlSession_3_7 != nullptr) {
+ res = wrapAsHidlRequest(requests[i], /*out*/&captureRequests_3_7[i].v3_4.v3_2,
+ /*out*/&handlesCreated, /*out*/&inflightBuffers);
+ } else if (hidlSession_3_4 != nullptr) {
+ res = wrapAsHidlRequest(requests[i], /*out*/&captureRequests_3_4[i].v3_2,
+ /*out*/&handlesCreated, /*out*/&inflightBuffers);
+ } else {
+ res = wrapAsHidlRequest(requests[i], /*out*/&captureRequests[i],
+ /*out*/&handlesCreated, /*out*/&inflightBuffers);
+ }
+ if (res != OK) {
+ mBufferRecords.popInflightBuffers(inflightBuffers);
+ cleanupNativeHandles(&handlesCreated);
+ return res;
+ }
+ }
+
+ std::vector<device::V3_2::BufferCache> cachesToRemove;
+ {
+ std::lock_guard<std::mutex> lock(mFreedBuffersLock);
+ for (auto& pair : mFreedBuffers) {
+ // The stream might have been removed since onBufferFreed
+ if (mBufferRecords.isStreamCached(pair.first)) {
+ cachesToRemove.push_back({pair.first, pair.second});
+ }
+ }
+ mFreedBuffers.clear();
+ }
+
+ common::V1_0::Status status = common::V1_0::Status::INTERNAL_ERROR;
+ *numRequestProcessed = 0;
+
+ // Write metadata to FMQ.
+ for (size_t i = 0; i < batchSize; i++) {
+ camera_capture_request_t* request = requests[i];
+ device::V3_2::CaptureRequest* captureRequest;
+ if (hidlSession_3_7 != nullptr) {
+ captureRequest = &captureRequests_3_7[i].v3_4.v3_2;
+ } else if (hidlSession_3_4 != nullptr) {
+ captureRequest = &captureRequests_3_4[i].v3_2;
+ } else {
+ captureRequest = &captureRequests[i];
+ }
+
+ if (request->settings != nullptr) {
+ size_t settingsSize = get_camera_metadata_size(request->settings);
+ if (mRequestMetadataQueue != nullptr && mRequestMetadataQueue->write(
+ reinterpret_cast<const uint8_t*>(request->settings), settingsSize)) {
+ captureRequest->settings.resize(0);
+ captureRequest->fmqSettingsSize = settingsSize;
+ } else {
+ if (mRequestMetadataQueue != nullptr) {
+ ALOGW("%s: couldn't utilize fmq, fallback to hwbinder", __FUNCTION__);
+ }
+ captureRequest->settings.setToExternal(
+ reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(
+ request->settings)),
+ get_camera_metadata_size(request->settings));
+ captureRequest->fmqSettingsSize = 0u;
+ }
+ } else {
+ // A null request settings maps to a size-0 CameraMetadata
+ captureRequest->settings.resize(0);
+ captureRequest->fmqSettingsSize = 0u;
+ }
+
+ // hidl session 3.7 specific handling.
+ if (hidlSession_3_7 != nullptr) {
+ captureRequests_3_7[i].inputWidth = request->input_width;
+ captureRequests_3_7[i].inputHeight = request->input_height;
+ }
+
+ // hidl session 3.7 and 3.4 specific handling.
+ if (hidlSession_3_7 != nullptr || hidlSession_3_4 != nullptr) {
+ hardware::hidl_vec<device::V3_4::PhysicalCameraSetting>& physicalCameraSettings =
+ (hidlSession_3_7 != nullptr) ?
+ captureRequests_3_7[i].v3_4.physicalCameraSettings :
+ captureRequests_3_4[i].physicalCameraSettings;
+ physicalCameraSettings.resize(request->num_physcam_settings);
+ for (size_t j = 0; j < request->num_physcam_settings; j++) {
+ if (request->physcam_settings != nullptr) {
+ size_t settingsSize = get_camera_metadata_size(request->physcam_settings[j]);
+ if (mRequestMetadataQueue != nullptr && mRequestMetadataQueue->write(
+ reinterpret_cast<const uint8_t*>(request->physcam_settings[j]),
+ settingsSize)) {
+ physicalCameraSettings[j].settings.resize(0);
+ physicalCameraSettings[j].fmqSettingsSize = settingsSize;
+ } else {
+ if (mRequestMetadataQueue != nullptr) {
+ ALOGW("%s: couldn't utilize fmq, fallback to hwbinder", __FUNCTION__);
+ }
+ physicalCameraSettings[j].settings.setToExternal(
+ reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(
+ request->physcam_settings[j])),
+ get_camera_metadata_size(request->physcam_settings[j]));
+ physicalCameraSettings[j].fmqSettingsSize = 0u;
+ }
+ } else {
+ physicalCameraSettings[j].fmqSettingsSize = 0u;
+ physicalCameraSettings[j].settings.resize(0);
+ }
+ physicalCameraSettings[j].physicalCameraId = request->physcam_id[j];
+ }
+ }
+ }
+
+ hardware::details::return_status err;
+ auto resultCallback =
+ [&status, &numRequestProcessed] (auto s, uint32_t n) {
+ status = s;
+ *numRequestProcessed = n;
+ };
+ if (hidlSession_3_7 != nullptr) {
+ err = hidlSession_3_7->processCaptureRequest_3_7(captureRequests_3_7, cachesToRemove,
+ resultCallback);
+ } else if (hidlSession_3_4 != nullptr) {
+ err = hidlSession_3_4->processCaptureRequest_3_4(captureRequests_3_4, cachesToRemove,
+ resultCallback);
+ } else {
+ err = mHidlSession->processCaptureRequest(captureRequests, cachesToRemove,
+ resultCallback);
+ }
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+ status = common::V1_0::Status::CAMERA_DISCONNECTED;
+ }
+
+ if (status == common::V1_0::Status::OK && *numRequestProcessed != batchSize) {
+ ALOGE("%s: processCaptureRequest returns OK but processed %d/%zu requests",
+ __FUNCTION__, *numRequestProcessed, batchSize);
+ status = common::V1_0::Status::INTERNAL_ERROR;
+ }
+
+ res = HidlProviderInfo::mapToStatusT(status);
+ if (res == OK) {
+ if (mHidlSession->isRemote()) {
+ // Only close acquire fence FDs when the HIDL transaction succeeds (so the FDs have been
+ // sent to camera HAL processes)
+ cleanupNativeHandles(&handlesCreated, /*closeFd*/true);
+ } else {
+ // In passthrough mode the FDs are now owned by HAL
+ cleanupNativeHandles(&handlesCreated);
+ }
+ } else {
+ mBufferRecords.popInflightBuffers(inflightBuffers);
+ cleanupNativeHandles(&handlesCreated);
+ }
+ return res;
+}
+
+status_t HidlCamera3Device::HidlHalInterface::switchToOffline(
+ const std::vector<int32_t>& streamsToKeep,
+ /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
+ /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
+ /*out*/camera3::BufferRecords* bufferRecords) {
+ ATRACE_NAME("CameraHal::switchToOffline");
+ if (!valid() || mHidlSession_3_6 == nullptr) {
+ ALOGE("%s called on invalid camera!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ if (offlineSessionInfo == nullptr || offlineSession == nullptr || bufferRecords == nullptr) {
+ ALOGE("%s: output arguments must not be null!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ common::V1_0::Status status = common::V1_0::Status::INTERNAL_ERROR;
+ auto resultCallback =
+ [&status, &offlineSessionInfo, &offlineSession] (auto s, auto info, auto session) {
+ status = s;
+ *offlineSessionInfo = info;
+ *offlineSession = session;
+ };
+ auto err = mHidlSession_3_6->switchToOffline(streamsToKeep, resultCallback);
+
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+ return DEAD_OBJECT;
+ }
+
+ status_t ret = HidlProviderInfo::mapToStatusT(status);
+ if (ret != OK) {
+ return ret;
+ }
+
+ return verifyBufferCaches(offlineSessionInfo, bufferRecords);
+}
+
+HidlCamera3Device::HidlRequestThread::HidlRequestThread(wp<Camera3Device> parent,
+ sp<camera3::StatusTracker> statusTracker,
+ sp<HalInterface> interface,
+ const Vector<int32_t>& sessionParamKeys,
+ bool useHalBufManager,
+ bool supportCameraMute) :
+ RequestThread(parent, statusTracker, interface, sessionParamKeys, useHalBufManager,
+ supportCameraMute) {}
+
+status_t HidlCamera3Device::HidlRequestThread::switchToOffline(
+ const std::vector<int32_t>& streamsToKeep,
+ /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
+ /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
+ /*out*/camera3::BufferRecords* bufferRecords) {
+ Mutex::Autolock l(mRequestLock);
+ clearRepeatingRequestsLocked(/*lastFrameNumber*/nullptr);
+
+ // Wait until request thread is fully stopped
+ // TBD: check if request thread is being paused by other APIs (shouldn't be)
+
+ // We could also check for mRepeatingRequests.empty(), but the API interface
+ // is serialized by Camera3Device::mInterfaceLock so no one should be able to submit any
+ // new requests during the call; hence skip that check.
+ bool queueEmpty = mNextRequests.empty() && mRequestQueue.empty();
+ while (!queueEmpty) {
+ status_t res = mRequestSubmittedSignal.waitRelative(mRequestLock, kRequestSubmitTimeout);
+ if (res == TIMED_OUT) {
+ ALOGE("%s: request thread failed to submit one request within timeout!", __FUNCTION__);
+ return res;
+ } else if (res != OK) {
+ ALOGE("%s: request thread failed to submit a request: %s (%d)!",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+ queueEmpty = mNextRequests.empty() && mRequestQueue.empty();
+ }
+ return (static_cast<HidlHalInterface *>(mInterface.get()))->switchToOffline(
+ streamsToKeep, offlineSessionInfo, offlineSession, bufferRecords);
+}
+
+status_t HidlCamera3Device::HidlCamera3DeviceInjectionMethods::injectionInitialize(
+ const String8& injectedCamId, sp<CameraProviderManager> manager,
+ const sp<android::hardware::camera::device::V3_2::ICameraDeviceCallback>&
+ callback) {
+ ATRACE_CALL();
+ Mutex::Autolock lock(mInjectionLock);
+
+ if (manager == nullptr) {
+ ALOGE("%s: manager does not exist!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ sp<Camera3Device> parent = mParent.promote();
+ if (parent == nullptr) {
+ ALOGE("%s: parent does not exist!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ mInjectedCamId = injectedCamId;
+ sp<ICameraDeviceSession> session;
+ ATRACE_BEGIN("Injection CameraHal::openSession");
+ status_t res = manager->openHidlSession(injectedCamId.string(), callback,
+ /*out*/ &session);
+ ATRACE_END();
+ if (res != OK) {
+ ALOGE("Injection camera could not open camera session: %s (%d)",
+ strerror(-res), res);
+ return res;
+ }
+
+ std::shared_ptr<RequestMetadataQueue> queue;
+ auto requestQueueRet =
+ session->getCaptureRequestMetadataQueue([&queue](const auto& descriptor) {
+ queue = std::make_shared<RequestMetadataQueue>(descriptor);
+ if (!queue->isValid() || queue->availableToWrite() <= 0) {
+ ALOGE("Injection camera HAL returns empty request metadata fmq, not "
+ "use it");
+ queue = nullptr;
+ // don't use the queue onwards.
+ }
+ });
+ if (!requestQueueRet.isOk()) {
+ ALOGE("Injection camera transaction error when getting request metadata fmq: "
+ "%s, not use it", requestQueueRet.description().c_str());
+ return DEAD_OBJECT;
+ }
+
+ std::unique_ptr<ResultMetadataQueue>& resQueue = mInjectionResultMetadataQueue;
+ auto resultQueueRet = session->getCaptureResultMetadataQueue(
+ [&resQueue](const auto& descriptor) {
+ resQueue = std::make_unique<ResultMetadataQueue>(descriptor);
+ if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
+ ALOGE("Injection camera HAL returns empty result metadata fmq, not use "
+ "it");
+ resQueue = nullptr;
+ // Don't use the resQueue onwards.
+ }
+ });
+ if (!resultQueueRet.isOk()) {
+ ALOGE("Injection camera transaction error when getting result metadata queue "
+ "from camera session: %s", resultQueueRet.description().c_str());
+ return DEAD_OBJECT;
+ }
+ IF_ALOGV() {
+ session->interfaceChain(
+ [](::android::hardware::hidl_vec<::android::hardware::hidl_string>
+ interfaceChain) {
+ ALOGV("Injection camera session interface chain:");
+ for (const auto& iface : interfaceChain) {
+ ALOGV(" %s", iface.c_str());
+ }
+ });
+ }
+
+ ALOGV("%s: Injection camera interface = new HalInterface()", __FUNCTION__);
+
+ mInjectedCamHalInterface =
+ new HidlHalInterface(session, queue, parent->mUseHalBufManager,
+ parent->mSupportOfflineProcessing);
+ if (mInjectedCamHalInterface == nullptr) {
+ ALOGE("%s: mInjectedCamHalInterface does not exist!", __FUNCTION__);
+ return DEAD_OBJECT;
+ }
+
+ return OK;
+}
+
+status_t HidlCamera3Device::HidlCamera3DeviceInjectionMethods::replaceHalInterface(
+ sp<HalInterface> newHalInterface, bool keepBackup) {
+ Mutex::Autolock lock(mInjectionLock);
+ if (newHalInterface.get() == nullptr) {
+ ALOGE("%s: The newHalInterface does not exist, to stop replacing.",
+ __FUNCTION__);
+ return DEAD_OBJECT;
+ }
+
+ sp<Camera3Device> parent = mParent.promote();
+ if (parent == nullptr) {
+ ALOGE("%s: parent does not exist!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if (newHalInterface->getTransportType() != IPCTransport::HIDL) {
+ ALOGE("%s Replacing HIDL HalInterface with another transport unsupported", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ HidlCamera3Device *hidlParent = static_cast<HidlCamera3Device *>(parent.get());
+ if (keepBackup) {
+ if (mBackupHalInterface == nullptr) {
+ mBackupHalInterface = parent->mInterface;
+ }
+ if (mBackupResultMetadataQueue == nullptr) {
+ mBackupResultMetadataQueue = std::move(hidlParent->mResultMetadataQueue);
+ hidlParent->mResultMetadataQueue = std::move(mInjectionResultMetadataQueue);
+ }
+ } else {
+ mBackupHalInterface = nullptr;
+ hidlParent->mResultMetadataQueue = std::move(mBackupResultMetadataQueue);
+ mBackupResultMetadataQueue = nullptr;
+ }
+ parent->mInterface = newHalInterface;
+
+ return OK;
+}
+
+}; // namespace android
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h
new file mode 100644
index 0000000..a83080b
--- /dev/null
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2022 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_SERVERS_HIDLCAMERA3DEVICE_H
+#define ANDROID_SERVERS_HIDLCAMERA3DEVICE_H
+
+#include "../Camera3Device.h"
+#include "HidlCamera3OutputUtils.h"
+
+namespace android {
+
+using android::hardware::camera::metadata::V3_8::CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap;
+
+/**
+ * CameraDevice for HIDL HAL devices with version CAMERA_DEVICE_API_VERSION_3_0 or higher.
+ */
+class HidlCamera3Device :
+ virtual public hardware::camera::device::V3_8::ICameraDeviceCallback,
+ public Camera3Device {
+ public:
+
+ explicit HidlCamera3Device(const String8& id, bool overrideForPerfClass,
+ bool legacyClient = false) : Camera3Device(id, overrideForPerfClass, legacyClient) { }
+
+ virtual ~HidlCamera3Device() {}
+
+ /**
+ * Helper functions to map between framework and HIDL values
+ */
+ static hardware::graphics::common::V1_0::PixelFormat mapToPixelFormat(int frameworkFormat);
+ static hardware::camera::device::V3_2::DataspaceFlags mapToHidlDataspace(
+ android_dataspace dataSpace);
+ static hardware::camera::device::V3_2::BufferUsageFlags mapToConsumerUsage(uint64_t usage);
+ static CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap mapToHidlDynamicProfile(
+ int dynamicRangeProfile);
+ static hardware::camera::device::V3_2::StreamRotation mapToStreamRotation(
+ camera_stream_rotation_t rotation);
+ // Returns a negative error code if the passed-in operation mode is not valid.
+ static status_t mapToStreamConfigurationMode(camera_stream_configuration_mode_t operationMode,
+ /*out*/ hardware::camera::device::V3_2::StreamConfigurationMode *mode);
+ static int mapToFrameworkFormat(hardware::graphics::common::V1_0::PixelFormat pixelFormat);
+ static android_dataspace mapToFrameworkDataspace(
+ hardware::camera::device::V3_2::DataspaceFlags);
+ static uint64_t mapConsumerToFrameworkUsage(
+ hardware::camera::device::V3_2::BufferUsageFlags usage);
+ static uint64_t mapProducerToFrameworkUsage(
+ hardware::camera::device::V3_2::BufferUsageFlags usage);
+
+ status_t initialize(sp<CameraProviderManager> manager, const String8& monitorTags) override;
+
+ /**
+ * Implementation of android::hardware::camera::device::V3_5::ICameraDeviceCallback
+ */
+
+ hardware::Return<void> processCaptureResult_3_4(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_4::CaptureResult>& results) override;
+ hardware::Return<void> processCaptureResult(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_2::CaptureResult>& results) override;
+ hardware::Return<void> notify(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_2::NotifyMsg>& msgs) override;
+
+ hardware::Return<void> requestStreamBuffers(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_5::BufferRequest>& bufReqs,
+ requestStreamBuffers_cb _hidl_cb) override;
+
+ hardware::Return<void> returnStreamBuffers(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_2::StreamBuffer>& buffers) override;
+
+ hardware::Return<void> notify_3_8(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_8::NotifyMsg>& msgs) override;
+
+ // Handle one notify message
+ void notify(const hardware::camera::device::V3_2::NotifyMsg& msg);
+
+ status_t switchToOffline(const std::vector<int32_t>& streamsToKeep,
+ /*out*/ sp<CameraOfflineSessionBase>* session) override;
+
+ using RequestMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
+
+ class HidlHalInterface : public Camera3Device::HalInterface {
+ public:
+ HidlHalInterface(sp<hardware::camera::device::V3_2::ICameraDeviceSession> &session,
+ std::shared_ptr<RequestMetadataQueue> queue,
+ bool useHalBufManager, bool supportOfflineProcessing);
+
+ virtual IPCTransport getTransportType() override { return IPCTransport::HIDL; }
+ // Returns true if constructed with a valid device or session, and not yet cleared
+ virtual bool valid() override;
+
+ // Reset this HalInterface object (does not call close())
+ virtual void clear() override;
+
+ // Calls into the HAL interface
+
+ // Caller takes ownership of requestTemplate
+ virtual status_t constructDefaultRequestSettings(camera_request_template templateId,
+ /*out*/ camera_metadata_t **requestTemplate) override;
+
+ virtual status_t configureStreams(const camera_metadata_t *sessionParams,
+ /*inout*/ camera_stream_configuration_t *config,
+ const std::vector<uint32_t>& bufferSizes) override;
+
+ // The injection camera configures the streams to hal.
+ virtual status_t configureInjectedStreams(
+ const camera_metadata_t* sessionParams,
+ /*inout*/ camera_stream_configuration_t* config,
+ const std::vector<uint32_t>& bufferSizes,
+ const CameraMetadata& cameraCharacteristics) override;
+
+ // When the call succeeds, the ownership of acquire fences in requests is transferred to
+ // HalInterface. More specifically, the current implementation will send the fence to
+ // HAL process and close the FD in cameraserver process. When the call fails, the ownership
+ // of the acquire fence still belongs to the caller.
+ virtual status_t processBatchCaptureRequests(
+ std::vector<camera_capture_request_t*>& requests,
+ /*out*/uint32_t* numRequestProcessed) override;
+ virtual status_t flush() override;
+ virtual status_t dump(int fd) override;
+ virtual status_t close() override;
+
+ virtual void signalPipelineDrain(const std::vector<int>& streamIds) override;
+ virtual bool isReconfigurationRequired(CameraMetadata& oldSessionParams,
+ CameraMetadata& newSessionParams) override;
+
+ virtual status_t repeatingRequestEnd(uint32_t frameNumber,
+ const std::vector<int32_t> &streamIds) override;
+
+ status_t switchToOffline(
+ const std::vector<int32_t>& streamsToKeep,
+ /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
+ /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
+ /*out*/camera3::BufferRecords* bufferRecords);
+
+ private:
+
+ // Always valid
+ sp<hardware::camera::device::V3_2::ICameraDeviceSession> mHidlSession;
+ // Valid if ICameraDeviceSession is @3.3 or newer
+ sp<hardware::camera::device::V3_3::ICameraDeviceSession> mHidlSession_3_3;
+ // Valid if ICameraDeviceSession is @3.4 or newer
+ sp<hardware::camera::device::V3_4::ICameraDeviceSession> mHidlSession_3_4;
+ // Valid if ICameraDeviceSession is @3.5 or newer
+ sp<hardware::camera::device::V3_5::ICameraDeviceSession> mHidlSession_3_5;
+ // Valid if ICameraDeviceSession is @3.6 or newer
+ sp<hardware::camera::device::V3_6::ICameraDeviceSession> mHidlSession_3_6;
+ // Valid if ICameraDeviceSession is @3.7 or newer
+ sp<hardware::camera::device::V3_7::ICameraDeviceSession> mHidlSession_3_7;
+ // Valid if ICameraDeviceSession is @3.7 or newer
+ sp<hardware::camera::device::V3_8::ICameraDeviceSession> mHidlSession_3_8;
+
+ std::shared_ptr<RequestMetadataQueue> mRequestMetadataQueue;
+
+ // The output HIDL request still depends on input camera_capture_request_t
+ // Do not free input camera_capture_request_t before output HIDL request
+ status_t wrapAsHidlRequest(camera_capture_request_t* in,
+ /*out*/hardware::camera::device::V3_2::CaptureRequest* out,
+ /*out*/std::vector<native_handle_t*>* handlesCreated,
+ /*out*/std::vector<std::pair<int32_t, int32_t>>* inflightBuffers);
+ }; // class HidlHalInterface
+
+ class HidlRequestThread : public Camera3Device::RequestThread {
+ public:
+ HidlRequestThread(wp<Camera3Device> parent,
+ sp<camera3::StatusTracker> statusTracker,
+ sp<HalInterface> interface,
+ const Vector<int32_t>& sessionParamKeys,
+ bool useHalBufManager,
+ bool supportCameraMute);
+
+ status_t switchToOffline(
+ const std::vector<int32_t>& streamsToKeep,
+ /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
+ /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
+ /*out*/camera3::BufferRecords* bufferRecords);
+ }; // class HidlRequestThread
+
+ class HidlCamera3DeviceInjectionMethods : public Camera3DeviceInjectionMethods {
+ public:
+ // Initialize the injection camera and generate an hal interface.
+ status_t injectionInitialize(
+ const String8& injectedCamId, sp<CameraProviderManager> manager,
+ const sp<
+ android::hardware::camera::device::V3_2 ::ICameraDeviceCallback>&
+ callback);
+ HidlCamera3DeviceInjectionMethods(wp<Camera3Device> parent) :
+ Camera3DeviceInjectionMethods(parent) { };
+ ~HidlCamera3DeviceInjectionMethods() {}
+ private:
+ // Backup of the original camera hal result FMQ.
+ std::unique_ptr<ResultMetadataQueue> mBackupResultMetadataQueue;
+
+ // FMQ writes the result for the injection camera. Must be guarded by
+ // mProcessCaptureResultLock.
+ std::unique_ptr<ResultMetadataQueue> mInjectionResultMetadataQueue;
+
+ // Use injection camera hal interface to replace and backup original
+ // camera hal interface.
+ virtual status_t replaceHalInterface(sp<HalInterface> newHalInterface,
+ bool keepBackup) override;
+ };
+
+ private:
+ template<typename NotifyMsgType>
+ hardware::Return<void> notifyHelper(
+ const hardware::hidl_vec<NotifyMsgType>& msgs);
+
+ virtual status_t injectionCameraInitialize(const String8 &injectCamId,
+ sp<CameraProviderManager> manager) override;
+
+ virtual sp<RequestThread> createNewRequestThread(wp<Camera3Device> parent,
+ sp<camera3::StatusTracker> statusTracker,
+ sp<HalInterface> interface,
+ const Vector<int32_t>& sessionParamKeys,
+ bool useHalBufManager,
+ bool supportCameraMute) override;
+
+ virtual sp<Camera3DeviceInjectionMethods>
+ createCamera3DeviceInjectionMethods(wp<Camera3Device>) override;
+
+ // FMQ to write result on. Must be guarded by mProcessCaptureResultLock.
+ std::unique_ptr<ResultMetadataQueue> mResultMetadataQueue;
+
+}; // class HidlCamera3Device
+
+}; // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp b/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp
new file mode 100644
index 0000000..d517c8d
--- /dev/null
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2022 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 "Hidl-Camera3-OffLnSsn"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <inttypes.h>
+
+#include <utils/Trace.h>
+
+#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
+
+#include "device3/hidl/HidlCamera3OfflineSession.h"
+#include "device3/Camera3OutputStream.h"
+#include "device3/hidl/HidlCamera3OutputUtils.h"
+#include "device3/Camera3InputStream.h"
+#include "device3/Camera3SharedOutputStream.h"
+#include "utils/CameraTraces.h"
+
+using namespace android::camera3;
+using namespace android::hardware::camera;
+
+namespace android {
+
+HidlCamera3OfflineSession::~HidlCamera3OfflineSession() {
+ ATRACE_CALL();
+ ALOGV("%s: Tearing down hidl offline session for camera id %s", __FUNCTION__, mId.string());
+ HidlCamera3OfflineSession::disconnectSession();
+}
+
+status_t HidlCamera3OfflineSession::initialize(wp<NotificationListener> listener) {
+ ATRACE_CALL();
+
+ if (mSession == nullptr) {
+ ALOGE("%s: HIDL session is null!", __FUNCTION__);
+ return DEAD_OBJECT;
+ }
+
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+
+ mListener = listener;
+
+ // setup result FMQ
+ std::unique_ptr<ResultMetadataQueue>& resQueue = mResultMetadataQueue;
+ auto resultQueueRet = mSession->getCaptureResultMetadataQueue(
+ [&resQueue](const auto& descriptor) {
+ resQueue = std::make_unique<ResultMetadataQueue>(descriptor);
+ if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
+ ALOGE("HAL returns empty result metadata fmq, not use it");
+ resQueue = nullptr;
+ // Don't use resQueue onwards.
+ }
+ });
+ if (!resultQueueRet.isOk()) {
+ ALOGE("Transaction error when getting result metadata queue from camera session: %s",
+ resultQueueRet.description().c_str());
+ return DEAD_OBJECT;
+ }
+ mStatus = STATUS_ACTIVE;
+ }
+
+ mSession->setCallback(this);
+
+ return OK;
+}
+
+hardware::Return<void> HidlCamera3OfflineSession::processCaptureResult_3_4(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_4::CaptureResult>& results) {
+ sp<NotificationListener> listener;
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mStatus != STATUS_ACTIVE) {
+ ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
+ return hardware::Void();
+ }
+ listener = mListener.promote();
+ }
+
+ HidlCaptureOutputStates states {
+ {mId,
+ mOfflineReqsLock, mLastCompletedRegularFrameNumber,
+ mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+ mOfflineReqs, mOutputLock, mResultQueue, mResultSignal,
+ mNextShutterFrameNumber,
+ mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+ mNextResultFrameNumber,
+ mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+ mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+ mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+ mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
+ mBufferRecords, /*legacyClient*/ false}, mResultMetadataQueue
+ };
+
+ std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
+ for (const auto& result : results) {
+ processOneCaptureResultLocked(states, result.v3_2, result.physicalCameraMetadata);
+ }
+ return hardware::Void();
+}
+
+hardware::Return<void> HidlCamera3OfflineSession::processCaptureResult(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_2::CaptureResult>& results) {
+ // TODO: changed impl to call into processCaptureResult_3_4 instead?
+ // might need to figure how to reduce copy though.
+ sp<NotificationListener> listener;
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mStatus != STATUS_ACTIVE) {
+ ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
+ return hardware::Void();
+ }
+ listener = mListener.promote();
+ }
+
+ hardware::hidl_vec<hardware::camera::device::V3_4::PhysicalCameraMetadata> noPhysMetadata;
+
+ HidlCaptureOutputStates states {
+ {mId,
+ mOfflineReqsLock, mLastCompletedRegularFrameNumber,
+ mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+ mOfflineReqs, mOutputLock, mResultQueue, mResultSignal,
+ mNextShutterFrameNumber,
+ mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+ mNextResultFrameNumber,
+ mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+ mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+ mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+ mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
+ mBufferRecords, /*legacyClient*/ false}, mResultMetadataQueue
+ };
+
+ std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
+ for (const auto& result : results) {
+ processOneCaptureResultLocked(states, result, noPhysMetadata);
+ }
+ return hardware::Void();
+}
+
+hardware::Return<void> HidlCamera3OfflineSession::notify(
+ const hardware::hidl_vec<hardware::camera::device::V3_2::NotifyMsg>& msgs) {
+ sp<NotificationListener> listener;
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mStatus != STATUS_ACTIVE) {
+ ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
+ return hardware::Void();
+ }
+ listener = mListener.promote();
+ }
+
+ HidlCaptureOutputStates states {
+ {mId,
+ mOfflineReqsLock, mLastCompletedRegularFrameNumber,
+ mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+ mOfflineReqs, mOutputLock, mResultQueue, mResultSignal,
+ mNextShutterFrameNumber,
+ mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+ mNextResultFrameNumber,
+ mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+ mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+ mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+ mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
+ mBufferRecords, /*legacyClient*/ false}, mResultMetadataQueue
+ };
+ for (const auto& msg : msgs) {
+ camera3::notify(states, msg);
+ }
+ return hardware::Void();
+}
+
+hardware::Return<void> HidlCamera3OfflineSession::requestStreamBuffers(
+ const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
+ requestStreamBuffers_cb _hidl_cb) {
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mStatus != STATUS_ACTIVE) {
+ ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
+ return hardware::Void();
+ }
+ }
+
+ RequestBufferStates states {
+ mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder,
+ *this, mBufferRecords, *this};
+ camera3::requestStreamBuffers(states, bufReqs, _hidl_cb);
+ return hardware::Void();
+}
+
+hardware::Return<void> HidlCamera3OfflineSession::returnStreamBuffers(
+ const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers) {
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mStatus != STATUS_ACTIVE) {
+ ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
+ return hardware::Void();
+ }
+ }
+
+ ReturnBufferStates states {
+ mId, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder, mBufferRecords};
+
+ camera3::returnStreamBuffers(states, buffers);
+ return hardware::Void();
+}
+
+void HidlCamera3OfflineSession::disconnectSession() {
+ // TODO: Make sure this locking is correct.
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mSession != nullptr) {
+ mSession->close();
+ }
+ mSession.clear();
+}
+
+}; // namespace android
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.h b/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.h
new file mode 100644
index 0000000..597cc5d
--- /dev/null
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2022 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_SERVERS_HIDL_CAMERA3OFFLINESESSION_H
+#define ANDROID_SERVERS_HIDL_CAMERA3OFFLINESESSION_H
+
+#include <memory>
+#include <mutex>
+
+#include <utils/String8.h>
+#include <utils/String16.h>
+
+#include <android/hardware/camera/device/3.6/ICameraOfflineSession.h>
+
+#include <fmq/MessageQueue.h>
+
+#include "HidlCamera3OutputUtils.h"
+#include "common/CameraOfflineSessionBase.h"
+
+#include "device3/Camera3BufferManager.h"
+#include "device3/Camera3OfflineSession.h"
+#include "device3/InFlightRequest.h"
+
+namespace android {
+
+namespace camera3 {
+
+class Camera3Stream;
+class Camera3OutputStreamInterface;
+class Camera3StreamInterface;
+
+} // namespace camera3
+
+/**
+ * HidlCamera3OfflineSession for offline session defined in HIDL ICameraOfflineSession@3.6 or higher
+ */
+class HidlCamera3OfflineSession :
+ public Camera3OfflineSession,
+ virtual public hardware::camera::device::V3_5::ICameraDeviceCallback {
+ public:
+
+ // initialize by Camera3Device.
+ explicit HidlCamera3OfflineSession(const String8& id,
+ const sp<camera3::Camera3Stream>& inputStream,
+ const camera3::StreamSet& offlineStreamSet,
+ camera3::BufferRecords&& bufferRecords,
+ const camera3::InFlightRequestMap& offlineReqs,
+ const Camera3OfflineStates& offlineStates,
+ sp<hardware::camera::device::V3_6::ICameraOfflineSession> offlineSession) :
+ Camera3OfflineSession(id, inputStream, offlineStreamSet, std::move(bufferRecords),
+ offlineReqs, offlineStates),
+ mSession(offlineSession) {};
+
+ virtual ~HidlCamera3OfflineSession();
+
+ virtual status_t initialize(wp<NotificationListener> listener) override;
+
+ /**
+ * HIDL ICameraDeviceCallback interface
+ * Implementation of android::hardware::camera::device::V3_5::ICameraDeviceCallback
+ */
+
+ hardware::Return<void> processCaptureResult_3_4(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_4::CaptureResult>& results) override;
+ hardware::Return<void> processCaptureResult(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_2::CaptureResult>& results) override;
+ hardware::Return<void> notify(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_2::NotifyMsg>& msgs) override;
+
+ hardware::Return<void> requestStreamBuffers(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_5::BufferRequest>& bufReqs,
+ requestStreamBuffers_cb _hidl_cb) override;
+
+ hardware::Return<void> returnStreamBuffers(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_2::StreamBuffer>& buffers) override;
+
+ /**
+ * End of CameraOfflineSessionBase interface
+ */
+
+ private:
+ sp<hardware::camera::device::V3_6::ICameraOfflineSession> mSession;
+ // FMQ to write result on. Must be guarded by mProcessCaptureResultLock.
+ std::unique_ptr<ResultMetadataQueue> mResultMetadataQueue;
+
+ virtual void disconnectSession() override;
+}; // class Camera3OfflineSession
+
+}; // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3OutputUtils.cpp b/services/camera/libcameraservice/device3/hidl/HidlCamera3OutputUtils.cpp
new file mode 100644
index 0000000..1563dcf
--- /dev/null
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3OutputUtils.cpp
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2022 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 "HidlCamera3-OutputUtils"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+// Convenience macros for transitioning to the error state
+#define SET_ERR(fmt, ...) states.setErrIntf.setErrorState( \
+ "%s: " fmt, __FUNCTION__, \
+ ##__VA_ARGS__)
+
+#include <inttypes.h>
+
+#include <utils/Log.h>
+#include <utils/SortedVector.h>
+#include <utils/Trace.h>
+
+#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
+
+#include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
+
+#include <camera/CameraUtils.h>
+#include <camera_metadata_hidden.h>
+
+#include "device3/hidl/HidlCamera3OutputUtils.h"
+#include "device3/aidl/AidlCamera3OutputUtils.h"
+#include "device3/Camera3Device.h"
+#include "device3/Camera3OutputUtilsTemplated.h"
+
+#include "system/camera_metadata.h"
+
+using namespace android::camera3;
+using namespace android::hardware::camera;
+
+namespace android {
+namespace camera3 {
+
+void processOneCaptureResultLocked(
+ HidlCaptureOutputStates& states,
+ const hardware::camera::device::V3_2::CaptureResult& result,
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_4::PhysicalCameraMetadata> &physicalCameraMetadata) {
+ processOneCaptureResultLockedT<HidlCaptureOutputStates,
+ hardware::camera::device::V3_2::CaptureResult,
+ hardware::hidl_vec<hardware::camera::device::V3_4::PhysicalCameraMetadata>,
+ hardware::hidl_vec<uint8_t>, ResultMetadataQueue,
+ hardware::camera::device::V3_2::BufferStatus>(states, result, physicalCameraMetadata);
+}
+
+void notify(CaptureOutputStates& states,
+ const hardware::camera::device::V3_8::NotifyMsg& msg) {
+ using android::hardware::camera::device::V3_2::MsgType;
+
+ hardware::camera::device::V3_2::NotifyMsg msg_3_2;
+ msg_3_2.type = msg.type;
+ bool hasReadoutTime = false;
+ uint64_t readoutTime = 0;
+ switch (msg.type) {
+ case MsgType::ERROR:
+ msg_3_2.msg.error = msg.msg.error;
+ break;
+ case MsgType::SHUTTER:
+ msg_3_2.msg.shutter = msg.msg.shutter.v3_2;
+ hasReadoutTime = true;
+ readoutTime = msg.msg.shutter.readoutTimestamp;
+ break;
+ }
+ notify(states, msg_3_2, hasReadoutTime, readoutTime);
+}
+
+void notify(CaptureOutputStates& states,
+ const hardware::camera::device::V3_2::NotifyMsg& msg,
+ bool hasReadoutTime, uint64_t readoutTime) {
+
+ using android::hardware::camera::device::V3_2::MsgType;
+ using android::hardware::camera::device::V3_2::ErrorCode;
+
+ ATRACE_CALL();
+ camera_notify_msg m;
+ switch (msg.type) {
+ case MsgType::ERROR:
+ m.type = CAMERA_MSG_ERROR;
+ m.message.error.frame_number = msg.msg.error.frameNumber;
+ if (msg.msg.error.errorStreamId >= 0) {
+ sp<Camera3StreamInterface> stream =
+ states.outputStreams.get(msg.msg.error.errorStreamId);
+ if (stream == nullptr) {
+ ALOGE("%s: Frame %d: Invalid error stream id %d", __FUNCTION__,
+ m.message.error.frame_number, msg.msg.error.errorStreamId);
+ return;
+ }
+ m.message.error.error_stream = stream->asHalStream();
+ } else {
+ m.message.error.error_stream = nullptr;
+ }
+ switch (msg.msg.error.errorCode) {
+ case ErrorCode::ERROR_DEVICE:
+ m.message.error.error_code = CAMERA_MSG_ERROR_DEVICE;
+ break;
+ case ErrorCode::ERROR_REQUEST:
+ m.message.error.error_code = CAMERA_MSG_ERROR_REQUEST;
+ break;
+ case ErrorCode::ERROR_RESULT:
+ m.message.error.error_code = CAMERA_MSG_ERROR_RESULT;
+ break;
+ case ErrorCode::ERROR_BUFFER:
+ m.message.error.error_code = CAMERA_MSG_ERROR_BUFFER;
+ break;
+ }
+ break;
+ case MsgType::SHUTTER:
+ m.type = CAMERA_MSG_SHUTTER;
+ m.message.shutter.frame_number = msg.msg.shutter.frameNumber;
+ m.message.shutter.timestamp = msg.msg.shutter.timestamp;
+ m.message.shutter.readout_timestamp = hasReadoutTime ?
+ readoutTime : m.message.shutter.timestamp;
+ break;
+ }
+ notify(states, &m);
+}
+
+static void convertToAidl(
+ const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& hidlBufReqs,
+ std::vector<aidl::android::hardware::camera::device::BufferRequest> &aidlBufReqs) {
+ size_t i = 0;
+ aidlBufReqs.resize(hidlBufReqs.size());
+ for (const auto &hidlBufReq : hidlBufReqs) {
+ aidlBufReqs[i].streamId = hidlBufReq.streamId;
+ aidlBufReqs[i].numBuffersRequested = hidlBufReq.numBuffersRequested;
+ i++;
+ }
+}
+
+static hardware::camera::device::V3_5::StreamBufferRequestError
+convertToHidl(aidl::android::hardware::camera::device::StreamBufferRequestError aError) {
+ using AError = aidl::android::hardware::camera::device::StreamBufferRequestError;
+ using HError = hardware::camera::device::V3_5::StreamBufferRequestError;
+
+ switch(aError) {
+ case AError::NO_BUFFER_AVAILABLE:
+ return HError::NO_BUFFER_AVAILABLE;
+ case AError::MAX_BUFFER_EXCEEDED:
+ return HError::MAX_BUFFER_EXCEEDED;
+ case AError::STREAM_DISCONNECTED:
+ return HError::STREAM_DISCONNECTED;
+ default:
+ return HError::UNKNOWN_ERROR;
+ }
+}
+
+static hardware::camera::device::V3_5::BufferRequestStatus
+convertToHidl(const aidl::android::hardware::camera::device::BufferRequestStatus &aBufStatus) {
+ using AStatus = aidl::android::hardware::camera::device::BufferRequestStatus;
+ using HStatus = hardware::camera::device::V3_5::BufferRequestStatus;
+ switch (aBufStatus) {
+ case AStatus::OK:
+ return HStatus::OK;
+ case AStatus::FAILED_PARTIAL:
+ return HStatus::FAILED_PARTIAL;
+ case AStatus::FAILED_CONFIGURING:
+ return HStatus::FAILED_CONFIGURING;
+ case AStatus::FAILED_ILLEGAL_ARGUMENTS:
+ return HStatus::FAILED_ILLEGAL_ARGUMENTS;
+ case AStatus::FAILED_UNKNOWN:
+ return HStatus::FAILED_UNKNOWN;
+ }
+ return HStatus::FAILED_UNKNOWN;
+}
+
+static hardware::camera::device::V3_2::BufferStatus
+convertToHidl(const aidl::android::hardware::camera::device::BufferStatus &aBufStatus) {
+ using AStatus = aidl::android::hardware::camera::device::BufferStatus;
+ using HStatus = hardware::camera::device::V3_2::BufferStatus;
+ switch (aBufStatus) {
+ case AStatus::OK:
+ return HStatus::OK;
+ case AStatus::ERROR:
+ return HStatus::ERROR;
+ }
+ return HStatus::ERROR;
+}
+
+static native_handle_t *convertToHidl(const aidl::android::hardware::common::NativeHandle &ah,
+ std::vector<native_handle_t *> &handlesCreated) {
+ if (isHandleNull(ah)) {
+ return nullptr;
+ }
+ native_handle_t *nh = makeFromAidl(ah);
+ handlesCreated.emplace_back(nh);
+ return nh;
+}
+
+static void convertToHidl(
+ const std::vector<aidl::android::hardware::camera::device::StreamBuffer> &aBuffers,
+ hardware::camera::device::V3_5::StreamBuffersVal &hBuffersVal,
+ std::vector<native_handle_t *> &handlesCreated) {
+ using HStreamBuffer = hardware::camera::device::V3_2::StreamBuffer;
+ hardware::hidl_vec<HStreamBuffer> tmpBuffers(aBuffers.size());
+ size_t i = 0;
+ for (const auto &aBuf : aBuffers) {
+ tmpBuffers[i].status = convertToHidl(aBuf.status);
+ tmpBuffers[i].streamId = aBuf.streamId;
+ tmpBuffers[i].bufferId = aBuf.bufferId;
+ tmpBuffers[i].buffer = convertToHidl(aBuf.buffer, handlesCreated);
+ tmpBuffers[i].acquireFence = convertToHidl(aBuf.acquireFence, handlesCreated);
+ tmpBuffers[i].releaseFence = convertToHidl(aBuf.releaseFence, handlesCreated);
+ }
+ hBuffersVal.buffers(std::move(tmpBuffers));
+}
+
+static void convertToHidl(
+ const std::vector<aidl::android::hardware::camera::device::StreamBufferRet> &aidlBufRets,
+ hardware::hidl_vec<hardware::camera::device::V3_5::StreamBufferRet> &hidlBufRets,
+ std::vector<native_handle_t *> &handlesCreated) {
+ size_t i = 0;
+ using Tag = aidl::android::hardware::camera::device::StreamBuffersVal::Tag;
+ hidlBufRets.resize(aidlBufRets.size());
+ for (const auto &aidlBufRet : aidlBufRets) {
+ auto &hidlBufRet = hidlBufRets[i];
+ hidlBufRet.streamId = aidlBufRet.streamId;
+ switch(aidlBufRet.val.getTag()) {
+ case Tag::error:
+ hidlBufRet.val.error(convertToHidl(aidlBufRet.val.get<Tag::error>()));
+ break;
+ case Tag::buffers:
+ convertToHidl(aidlBufRet.val.get<Tag::buffers>(), hidlBufRet.val, handlesCreated);
+ break;
+ }
+ i++;
+ }
+}
+
+// The buffers requested through this call are not tied to any CaptureRequest in
+// particular. They may used by the hal for a particular frame's output buffer
+// or for its internal use as well. In the case that the hal does use any buffer
+// from the requested list here, for a particular frame's output buffer, the
+// buffer will be returned with the processCaptureResult call corresponding to
+// the frame. The other buffers will be returned through returnStreamBuffers.
+// The buffers returned via returnStreamBuffers will not have a valid
+// timestamp(0) and will be dropped by the bufferqueue.
+void requestStreamBuffers(RequestBufferStates& states,
+ const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
+ hardware::camera::device::V3_5::ICameraDeviceCallback::requestStreamBuffers_cb _hidl_cb) {
+ using android::hardware::camera::device::V3_2::BufferStatus;
+ using android::hardware::camera::device::V3_2::StreamBuffer;
+ using android::hardware::camera::device::V3_5::BufferRequestStatus;
+ using android::hardware::camera::device::V3_5::StreamBufferRet;
+ using android::hardware::camera::device::V3_5::StreamBufferRequestError;
+ std::vector<aidl::android::hardware::camera::device::BufferRequest> aidlBufReqs;
+ hardware::hidl_vec<hardware::camera::device::V3_5::StreamBufferRet> hidlBufRets;
+ convertToAidl(bufReqs, aidlBufReqs);
+ std::vector<::aidl::android::hardware::camera::device::StreamBufferRet> aidlBufRets;
+ ::aidl::android::hardware::camera::device::BufferRequestStatus aidlBufRetStatus;
+
+ requestStreamBuffers(states, aidlBufReqs, &aidlBufRets, &aidlBufRetStatus);
+ std::vector<native_handle_t *> handlesCreated;
+ convertToHidl(aidlBufRets, hidlBufRets, handlesCreated);
+ _hidl_cb(convertToHidl(aidlBufRetStatus), hidlBufRets);
+ Camera3Device::cleanupNativeHandles(&handlesCreated);
+}
+
+void returnStreamBuffers(ReturnBufferStates& states,
+ const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers) {
+ returnStreamBuffersT(states, buffers);
+}
+
+} // camera3
+} // namespace android
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3OutputUtils.h b/services/camera/libcameraservice/device3/hidl/HidlCamera3OutputUtils.h
new file mode 100644
index 0000000..583d738
--- /dev/null
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3OutputUtils.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2022 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_SERVERS_HIDL_CAMERA3_OUTPUT_UTILS_H
+#define ANDROID_SERVERS_HIDL_CAMERA3_OUTPUT_UTILS_H
+
+#include <memory>
+#include <mutex>
+
+#include <cutils/native_handle.h>
+
+#include <fmq/MessageQueue.h>
+
+#include <common/CameraDeviceBase.h>
+
+#include <android/hardware/camera/device/3.8/ICameraDeviceCallback.h>
+
+#include "device3/BufferUtils.h"
+//#include "device3/DistortionMapper.h"
+//#include "device3/ZoomRatioMapper.h"
+//#include "device3/RotateAndCropMapper.h"
+#include "device3/InFlightRequest.h"
+#include "device3/Camera3Stream.h"
+//#include "device3/Camera3OutputStreamInterface.h"
+#include "device3/Camera3OutputUtils.h"
+//#include "utils/SessionStatsBuilder.h"
+//#include "utils/TagMonitor.h"
+
+namespace android {
+
+using ResultMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
+
+namespace camera3 {
+
+ /**
+ * Helper methods shared between HidlCamera3Device/HidlCamera3OfflineSession for HAL callbacks
+ */
+ // Camera3Device/Camera3OfflineSession internal states used in notify/processCaptureResult
+ // callbacks
+ struct HidlCaptureOutputStates : public CaptureOutputStates {
+ std::unique_ptr<ResultMetadataQueue>& fmq;
+ };
+
+ // Handle one capture result. Assume callers hold the lock to serialize all
+ // processCaptureResult calls
+ void processOneCaptureResultLocked(
+ HidlCaptureOutputStates& states,
+ const hardware::camera::device::V3_2::CaptureResult& result,
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_4::PhysicalCameraMetadata>
+ &physicalCameraMetadata);
+
+ // Handle one notify message
+ void notify(CaptureOutputStates& states,
+ const hardware::camera::device::V3_2::NotifyMsg& msg,
+ bool hasReadoutTime = false, uint64_t readoutTime = 0LL);
+ void notify(CaptureOutputStates& states,
+ const hardware::camera::device::V3_8::NotifyMsg& msg);
+
+ void requestStreamBuffers(RequestBufferStates& states,
+ const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
+ hardware::camera::device::V3_5::ICameraDeviceCallback::requestStreamBuffers_cb
+ _hidl_cb);
+ void returnStreamBuffers(ReturnBufferStates& states,
+ const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers);
+
+} // namespace camera3
+
+} // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp b/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
index ca73e4c..3c98a5e 100644
--- a/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
+++ b/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
@@ -52,6 +52,7 @@
"android.hardware.camera.provider@2.5",
"android.hardware.camera.provider@2.6",
"android.hardware.camera.provider@2.7",
+ "android.hardware.camera.provider-V1-ndk",
"android.hardware.camera.device@1.0",
"android.hardware.camera.device@3.2",
"android.hardware.camera.device@3.3",
diff --git a/services/camera/libcameraservice/tests/Android.bp b/services/camera/libcameraservice/tests/Android.bp
index c3f0620..4928faf 100644
--- a/services/camera/libcameraservice/tests/Android.bp
+++ b/services/camera/libcameraservice/tests/Android.bp
@@ -44,6 +44,7 @@
"android.hardware.camera.provider@2.5",
"android.hardware.camera.provider@2.6",
"android.hardware.camera.provider@2.7",
+ "android.hardware.camera.provider-V1-ndk",
"android.hardware.camera.device@1.0",
"android.hardware.camera.device@3.2",
"android.hardware.camera.device@3.4",
diff --git a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
index c8a6b32..e9f6979 100644
--- a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
+++ b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
@@ -212,7 +212,7 @@
* Simple test version of the interaction proxy, to use to inject onRegistered calls to the
* CameraProviderManager
*/
-struct TestInteractionProxy : public CameraProviderManager::ServiceInteractionProxy {
+struct TestInteractionProxy : public CameraProviderManager::HidlServiceInteractionProxy {
sp<hidl::manager::V1_0::IServiceNotification> mManagerNotificationInterface;
sp<TestICameraProvider> mTestCameraProvider;
@@ -269,13 +269,13 @@
~TestStatusListener() {}
void onDeviceStatusChanged(const String8 &,
- hardware::camera::common::V1_0::CameraDeviceStatus) override {}
+ CameraDeviceStatus) override {}
void onDeviceStatusChanged(const String8 &, const String8 &,
- hardware::camera::common::V1_0::CameraDeviceStatus) override {}
+ CameraDeviceStatus) override {}
void onTorchStatusChanged(const String8 &,
- hardware::camera::common::V1_0::TorchModeStatus) override {}
+ TorchModeStatus) override {}
void onTorchStatusChanged(const String8 &,
- hardware::camera::common::V1_0::TorchModeStatus, SystemCameraKind) override {}
+ TorchModeStatus, SystemCameraKind) override {}
void onNewProviderRegistered() override {}
};
diff --git a/services/camera/libcameraservice/utils/IPCTransport.h b/services/camera/libcameraservice/utils/IPCTransport.h
new file mode 100644
index 0000000..b8e80ac
--- /dev/null
+++ b/services/camera/libcameraservice/utils/IPCTransport.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2022 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_SERVERS_IPC_H_
+#define ANDROID_SERVERS_IPC_H_
+
+enum class IPCTransport : uint32_t {
+ HIDL = 0,
+ AIDL = 1,
+ INVALID = 2
+};
+
+#endif
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
index a35e6f3..ddcbdee 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
@@ -21,8 +21,10 @@
#include "../api2/HeicCompositeStream.h"
#include "android/hardware/camera/metadata/3.8/types.h"
#include "common/CameraDeviceBase.h"
+#include "common/HalConversionsTemplated.h"
#include "../CameraService.h"
-#include "device3/Camera3Device.h"
+#include "device3/aidl/AidlCamera3Device.h"
+#include "device3/hidl/HidlCamera3Device.h"
#include "device3/Camera3OutputStream.h"
#include "system/graphics-base-v1.1.h"
@@ -31,6 +33,7 @@
using android::hardware::camera2::ICameraDeviceUser;
using android::hardware::camera::metadata::V3_6::CameraMetadataEnumAndroidSensorPixelMode;
using android::hardware::camera::metadata::V3_8::CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap;
+using android::hardware::camera::metadata::V3_8::CameraMetadataEnumAndroidScalerAvailableStreamUseCases;
namespace android {
namespace camera3 {
@@ -310,11 +313,30 @@
}
}
+bool isStreamUseCaseSupported(int streamUseCase,
+ const CameraMetadata &deviceInfo) {
+ camera_metadata_ro_entry_t availableStreamUseCases =
+ deviceInfo.find(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES);
+
+ if (availableStreamUseCases.count == 0 &&
+ streamUseCase == ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT) {
+ return true;
+ }
+
+ for (size_t i = 0; i < availableStreamUseCases.count; i++) {
+ if (availableStreamUseCases.data.i32[i] == streamUseCase) {
+ return true;
+ }
+ }
+ return false;
+}
+
binder::Status createSurfaceFromGbp(
OutputStreamInfo& streamInfo, bool isStreamInfoValid,
sp<Surface>& surface, const sp<IGraphicBufferProducer>& gbp,
const String8 &logicalCameraId, const CameraMetadata &physicalCameraMetadata,
- const std::vector<int32_t> &sensorPixelModesUsed, int dynamicRangeProfile){
+ const std::vector<int32_t> &sensorPixelModesUsed, int dynamicRangeProfile,
+ int streamUseCase, int timestampBase, int mirrorMode) {
// bufferProducer must be non-null
if (gbp == nullptr) {
String8 msg = String8::format("Camera %s: Surface is NULL", logicalCameraId.string());
@@ -427,6 +449,27 @@
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
+ if (!SessionConfigurationUtils::isStreamUseCaseSupported(streamUseCase,
+ physicalCameraMetadata)) {
+ String8 msg = String8::format("Camera %s: stream use case %d not supported,"
+ " failed to create output stream", logicalCameraId.string(), streamUseCase);
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ }
+ if (timestampBase < OutputConfiguration::TIMESTAMP_BASE_DEFAULT ||
+ timestampBase > OutputConfiguration::TIMESTAMP_BASE_CHOREOGRAPHER_SYNCED) {
+ String8 msg = String8::format("Camera %s: invalid timestamp base %d",
+ logicalCameraId.string(), timestampBase);
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ }
+ if (mirrorMode < OutputConfiguration::MIRROR_MODE_AUTO ||
+ mirrorMode > OutputConfiguration::MIRROR_MODE_V) {
+ String8 msg = String8::format("Camera %s: invalid mirroring mode %d",
+ logicalCameraId.string(), mirrorMode);
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ }
if (!isStreamInfoValid) {
streamInfo.width = width;
@@ -436,6 +479,9 @@
streamInfo.consumerUsage = consumerUsage;
streamInfo.sensorPixelModesUsed = overriddenSensorPixelModes;
streamInfo.dynamicRangeProfile = dynamicRangeProfile;
+ streamInfo.streamUseCase = streamUseCase;
+ streamInfo.timestampBase = timestampBase;
+ streamInfo.mirrorMode = mirrorMode;
return binder::Status::ok();
}
if (width != streamInfo.width) {
@@ -478,6 +524,296 @@
void mapStreamInfo(const OutputStreamInfo &streamInfo,
camera3::camera_stream_rotation_t rotation, String8 physicalId,
+ int32_t groupId, aidl::android::hardware::camera::device::Stream *stream /*out*/) {
+ if (stream == nullptr) {
+ return;
+ }
+
+ stream->streamType = aidl::android::hardware::camera::device::StreamType::OUTPUT;
+ stream->width = streamInfo.width;
+ stream->height = streamInfo.height;
+ stream->format = AidlCamera3Device::mapToAidlPixelFormat(streamInfo.format);
+ auto u = streamInfo.consumerUsage;
+ camera3::Camera3OutputStream::applyZSLUsageQuirk(streamInfo.format, &u);
+ stream->usage = AidlCamera3Device::mapToAidlConsumerUsage(u);
+ stream->dataSpace = AidlCamera3Device::mapToAidlDataspace(streamInfo.dataSpace);
+ stream->rotation = AidlCamera3Device::mapToAidlStreamRotation(rotation);
+ stream->id = -1; // Invalid stream id
+ stream->physicalCameraId = std::string(physicalId.string());
+ stream->bufferSize = 0;
+ stream->groupId = groupId;
+ stream->sensorPixelModesUsed.resize(streamInfo.sensorPixelModesUsed.size());
+ size_t idx = 0;
+ using SensorPixelMode = aidl::android::hardware::camera::metadata::SensorPixelMode;
+ for (auto mode : streamInfo.sensorPixelModesUsed) {
+ stream->sensorPixelModesUsed[idx++] =
+ static_cast<SensorPixelMode>(mode);
+ }
+ using DynamicRangeProfile =
+ aidl::android::hardware::camera::metadata::RequestAvailableDynamicRangeProfilesMap;
+ stream->dynamicRangeProfile = static_cast<DynamicRangeProfile>(streamInfo.dynamicRangeProfile);
+ using StreamUseCases =
+ aidl::android::hardware::camera::metadata::ScalerAvailableStreamUseCases;
+ stream->useCase = static_cast<StreamUseCases>(streamInfo.streamUseCase);
+}
+
+status_t
+convertAidlToHidl38StreamCombination(
+ const aidl::android::hardware::camera::device::StreamConfiguration &aidl,
+ hardware::camera::device::V3_8::StreamConfiguration &hidl) {
+ hidl.operationMode =
+ static_cast<hardware::camera::device::V3_2::StreamConfigurationMode>(aidl.operationMode);
+ if (aidl.streamConfigCounter < 0) {
+ return BAD_VALUE;
+ }
+ hidl.streamConfigCounter = static_cast<uint32_t>(aidl.streamConfigCounter);
+ hidl.multiResolutionInputImage = aidl.multiResolutionInputImage;
+ hidl.sessionParams = aidl.sessionParams.metadata;
+ hidl.streams.resize(aidl.streams.size());
+ size_t i = 0;
+ for (const auto &stream : aidl.streams) {
+ //hidlv3_8
+ hidl.streams[i].dynamicRangeProfile =
+ static_cast<
+ CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap>
+ (stream.dynamicRangeProfile);
+ hidl.streams[i].useCase =
+ static_cast<
+ CameraMetadataEnumAndroidScalerAvailableStreamUseCases>
+ (stream.useCase);
+
+ // hidl v3_7
+ hidl.streams[i].v3_7.groupId = stream.groupId;
+ hidl.streams[i].v3_7.sensorPixelModesUsed.resize(stream.sensorPixelModesUsed.size());
+ size_t j = 0;
+ for (const auto &mode : stream.sensorPixelModesUsed) {
+ hidl.streams[i].v3_7.sensorPixelModesUsed[j] =
+ static_cast<CameraMetadataEnumAndroidSensorPixelMode>(mode);
+ j++;
+ }
+
+ //hidl v3_4
+ hidl.streams[i].v3_7.v3_4.physicalCameraId = stream.physicalCameraId;
+
+ if (stream.bufferSize < 0) {
+ return BAD_VALUE;
+ }
+ hidl.streams[i].v3_7.v3_4.bufferSize = static_cast<uint32_t>(stream.bufferSize);
+
+ // hild v3_2
+ hidl.streams[i].v3_7.v3_4.v3_2.id = stream.id;
+ hidl.streams[i].v3_7.v3_4.v3_2.format =
+ static_cast<hardware::graphics::common::V1_0::PixelFormat>(stream.format);
+
+ if (stream.width < 0 || stream.height < 0) {
+ return BAD_VALUE;
+ }
+ hidl.streams[i].v3_7.v3_4.v3_2.width = static_cast<uint32_t>(stream.width);
+ hidl.streams[i].v3_7.v3_4.v3_2.height = static_cast<uint32_t>(stream.height);
+ hidl.streams[i].v3_7.v3_4.v3_2.usage =
+ static_cast<hardware::camera::device::V3_2::BufferUsageFlags>(stream.usage);
+ hidl.streams[i].v3_7.v3_4.v3_2.streamType =
+ static_cast<hardware::camera::device::V3_2::StreamType>(stream.streamType);
+ hidl.streams[i].v3_7.v3_4.v3_2.dataSpace =
+ static_cast<hardware::camera::device::V3_2::DataspaceFlags>(stream.dataSpace);
+ hidl.streams[i].v3_7.v3_4.v3_2.rotation =
+ static_cast<hardware::camera::device::V3_2::StreamRotation>(stream.rotation);
+ i++;
+ }
+ return OK;
+}
+
+binder::Status
+convertToHALStreamCombination(
+ const SessionConfiguration& sessionConfiguration,
+ const String8 &logicalCameraId, const CameraMetadata &deviceInfo,
+ metadataGetter getMetadata, const std::vector<std::string> &physicalCameraIds,
+ aidl::android::hardware::camera::device::StreamConfiguration &streamConfiguration,
+ bool overrideForPerfClass, bool *earlyExit) {
+ using SensorPixelMode = aidl::android::hardware::camera::metadata::SensorPixelMode;
+ auto operatingMode = sessionConfiguration.getOperatingMode();
+ binder::Status res = checkOperatingMode(operatingMode, deviceInfo, logicalCameraId);
+ if (!res.isOk()) {
+ return res;
+ }
+
+ if (earlyExit == nullptr) {
+ String8 msg("earlyExit nullptr");
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ }
+ *earlyExit = false;
+ auto ret = AidlCamera3Device::mapToAidlStreamConfigurationMode(
+ static_cast<camera_stream_configuration_mode_t> (operatingMode),
+ /*out*/ &streamConfiguration.operationMode);
+ if (ret != OK) {
+ String8 msg = String8::format(
+ "Camera %s: Failed mapping operating mode %d requested: %s (%d)",
+ logicalCameraId.string(), operatingMode, strerror(-ret), ret);
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+ msg.string());
+ }
+
+ bool isInputValid = (sessionConfiguration.getInputWidth() > 0) &&
+ (sessionConfiguration.getInputHeight() > 0) &&
+ (sessionConfiguration.getInputFormat() > 0);
+ auto outputConfigs = sessionConfiguration.getOutputConfigurations();
+ size_t streamCount = outputConfigs.size();
+ streamCount = isInputValid ? streamCount + 1 : streamCount;
+ streamConfiguration.streams.resize(streamCount);
+ size_t streamIdx = 0;
+ if (isInputValid) {
+ std::vector<SensorPixelMode> defaultSensorPixelModes;
+ defaultSensorPixelModes.resize(1);
+ defaultSensorPixelModes[0] =
+ static_cast<SensorPixelMode>(ANDROID_SENSOR_PIXEL_MODE_DEFAULT);
+ aidl::android::hardware::camera::device::Stream stream;
+ stream.id = 0;
+ stream.streamType = aidl::android::hardware::camera::device::StreamType::INPUT;
+ stream.width = static_cast<uint32_t> (sessionConfiguration.getInputWidth());
+ stream.height = static_cast<uint32_t> (sessionConfiguration.getInputHeight());
+ stream.format =
+ AidlCamera3Device::AidlCamera3Device::mapToAidlPixelFormat(
+ sessionConfiguration.getInputFormat());
+ stream.usage = static_cast<aidl::android::hardware::graphics::common::BufferUsage>(0);
+ stream.dataSpace =
+ static_cast<aidl::android::hardware::graphics::common::Dataspace>(
+ HAL_DATASPACE_UNKNOWN);
+ stream.rotation = aidl::android::hardware::camera::device::StreamRotation::ROTATION_0;
+ stream.bufferSize = 0;
+ stream.groupId = -1;
+ stream.sensorPixelModesUsed = defaultSensorPixelModes;
+ streamConfiguration.streams[streamIdx++] = stream;
+ streamConfiguration.multiResolutionInputImage =
+ sessionConfiguration.inputIsMultiResolution();
+ }
+
+ for (const auto &it : outputConfigs) {
+ const std::vector<sp<IGraphicBufferProducer>>& bufferProducers =
+ it.getGraphicBufferProducers();
+ bool deferredConsumer = it.isDeferred();
+ String8 physicalCameraId = String8(it.getPhysicalCameraId());
+
+ int dynamicRangeProfile = it.getDynamicRangeProfile();
+ std::vector<int32_t> sensorPixelModesUsed = it.getSensorPixelModesUsed();
+ const CameraMetadata &physicalDeviceInfo = getMetadata(physicalCameraId,
+ overrideForPerfClass);
+ const CameraMetadata &metadataChosen =
+ physicalCameraId.size() > 0 ? physicalDeviceInfo : deviceInfo;
+
+ size_t numBufferProducers = bufferProducers.size();
+ bool isStreamInfoValid = false;
+ int32_t groupId = it.isMultiResolution() ? it.getSurfaceSetID() : -1;
+ OutputStreamInfo streamInfo;
+
+ res = checkSurfaceType(numBufferProducers, deferredConsumer, it.getSurfaceType());
+ if (!res.isOk()) {
+ return res;
+ }
+ res = checkPhysicalCameraId(physicalCameraIds, physicalCameraId,
+ logicalCameraId);
+ if (!res.isOk()) {
+ return res;
+ }
+
+ int streamUseCase = it.getStreamUseCase();
+ int timestampBase = it.getTimestampBase();
+ int mirrorMode = it.getMirrorMode();
+ if (deferredConsumer) {
+ streamInfo.width = it.getWidth();
+ streamInfo.height = it.getHeight();
+ streamInfo.format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+ streamInfo.dataSpace = android_dataspace_t::HAL_DATASPACE_UNKNOWN;
+ auto surfaceType = it.getSurfaceType();
+ streamInfo.consumerUsage = GraphicBuffer::USAGE_HW_TEXTURE;
+ if (surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW) {
+ streamInfo.consumerUsage |= GraphicBuffer::USAGE_HW_COMPOSER;
+ }
+ streamInfo.dynamicRangeProfile = it.getDynamicRangeProfile();
+ if (checkAndOverrideSensorPixelModesUsed(sensorPixelModesUsed,
+ streamInfo.format, streamInfo.width,
+ streamInfo.height, metadataChosen, false /*flexibleConsumer*/,
+ &streamInfo.sensorPixelModesUsed) != OK) {
+ ALOGE("%s: Deferred surface sensor pixel modes not valid",
+ __FUNCTION__);
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+ "Deferred surface sensor pixel modes not valid");
+ }
+ streamInfo.streamUseCase = streamUseCase;
+ mapStreamInfo(streamInfo, camera3::CAMERA_STREAM_ROTATION_0, physicalCameraId, groupId,
+ &streamConfiguration.streams[streamIdx++]);
+ isStreamInfoValid = true;
+
+ if (numBufferProducers == 0) {
+ continue;
+ }
+ }
+
+ for (auto& bufferProducer : bufferProducers) {
+ sp<Surface> surface;
+ res = createSurfaceFromGbp(streamInfo, isStreamInfoValid, surface, bufferProducer,
+ logicalCameraId, metadataChosen, sensorPixelModesUsed, dynamicRangeProfile,
+ streamUseCase, timestampBase, mirrorMode);
+
+ if (!res.isOk())
+ return res;
+
+ if (!isStreamInfoValid) {
+ bool isDepthCompositeStream =
+ camera3::DepthCompositeStream::isDepthCompositeStream(surface);
+ bool isHeicCompositeStream =
+ camera3::HeicCompositeStream::isHeicCompositeStream(surface);
+ if (isDepthCompositeStream || isHeicCompositeStream) {
+ // We need to take in to account that composite streams can have
+ // additional internal camera streams.
+ std::vector<OutputStreamInfo> compositeStreams;
+ if (isDepthCompositeStream) {
+ // TODO: Take care of composite streams.
+ ret = camera3::DepthCompositeStream::getCompositeStreamInfo(streamInfo,
+ deviceInfo, &compositeStreams);
+ } else {
+ ret = camera3::HeicCompositeStream::getCompositeStreamInfo(streamInfo,
+ deviceInfo, &compositeStreams);
+ }
+ if (ret != OK) {
+ String8 msg = String8::format(
+ "Camera %s: Failed adding composite streams: %s (%d)",
+ logicalCameraId.string(), strerror(-ret), ret);
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ }
+
+ if (compositeStreams.size() == 0) {
+ // No internal streams means composite stream not
+ // supported.
+ *earlyExit = true;
+ return binder::Status::ok();
+ } else if (compositeStreams.size() > 1) {
+ streamCount += compositeStreams.size() - 1;
+ streamConfiguration.streams.resize(streamCount);
+ }
+
+ for (const auto& compositeStream : compositeStreams) {
+ mapStreamInfo(compositeStream,
+ static_cast<camera_stream_rotation_t> (it.getRotation()),
+ physicalCameraId, groupId,
+ &streamConfiguration.streams[streamIdx++]);
+ }
+ } else {
+ mapStreamInfo(streamInfo,
+ static_cast<camera_stream_rotation_t> (it.getRotation()),
+ physicalCameraId, groupId, &streamConfiguration.streams[streamIdx++]);
+ }
+ isStreamInfoValid = true;
+ }
+ }
+ }
+ return binder::Status::ok();
+}
+
+void mapStreamInfo(const OutputStreamInfo &streamInfo,
+ camera3::camera_stream_rotation_t rotation, String8 physicalId,
int32_t groupId, hardware::camera::device::V3_8::Stream *stream /*out*/) {
if (stream == nullptr) {
return;
@@ -486,17 +822,18 @@
stream->v3_7.v3_4.v3_2.streamType = hardware::camera::device::V3_2::StreamType::OUTPUT;
stream->v3_7.v3_4.v3_2.width = streamInfo.width;
stream->v3_7.v3_4.v3_2.height = streamInfo.height;
- stream->v3_7.v3_4.v3_2.format = Camera3Device::mapToPixelFormat(streamInfo.format);
+ stream->v3_7.v3_4.v3_2.format = HidlCamera3Device::mapToPixelFormat(streamInfo.format);
auto u = streamInfo.consumerUsage;
camera3::Camera3OutputStream::applyZSLUsageQuirk(streamInfo.format, &u);
- stream->v3_7.v3_4.v3_2.usage = Camera3Device::mapToConsumerUsage(u);
- stream->v3_7.v3_4.v3_2.dataSpace = Camera3Device::mapToHidlDataspace(streamInfo.dataSpace);
- stream->v3_7.v3_4.v3_2.rotation = Camera3Device::mapToStreamRotation(rotation);
+ stream->v3_7.v3_4.v3_2.usage = HidlCamera3Device::mapToConsumerUsage(u);
+ stream->v3_7.v3_4.v3_2.dataSpace = HidlCamera3Device::mapToHidlDataspace(streamInfo.dataSpace);
+ stream->v3_7.v3_4.v3_2.rotation = HidlCamera3Device::mapToStreamRotation(rotation);
stream->v3_7.v3_4.v3_2.id = -1; // Invalid stream id
stream->v3_7.v3_4.physicalCameraId = std::string(physicalId.string());
stream->v3_7.v3_4.bufferSize = 0;
stream->v3_7.groupId = groupId;
stream->v3_7.sensorPixelModesUsed.resize(streamInfo.sensorPixelModesUsed.size());
+
size_t idx = 0;
for (auto mode : streamInfo.sensorPixelModesUsed) {
stream->v3_7.sensorPixelModesUsed[idx++] =
@@ -505,6 +842,8 @@
stream->dynamicRangeProfile =
static_cast<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap> (
streamInfo.dynamicRangeProfile);
+ stream->useCase = static_cast<CameraMetadataEnumAndroidScalerAvailableStreamUseCases>(
+ streamInfo.streamUseCase);
}
binder::Status checkPhysicalCameraId(
@@ -586,172 +925,22 @@
metadataGetter getMetadata, const std::vector<std::string> &physicalCameraIds,
hardware::camera::device::V3_8::StreamConfiguration &streamConfiguration,
bool overrideForPerfClass, bool *earlyExit) {
-
- auto operatingMode = sessionConfiguration.getOperatingMode();
- binder::Status res = checkOperatingMode(operatingMode, deviceInfo, logicalCameraId);
- if (!res.isOk()) {
- return res;
+ aidl::android::hardware::camera::device::StreamConfiguration aidlStreamConfiguration;
+ auto ret = convertToHALStreamCombination(sessionConfiguration, logicalCameraId, deviceInfo,
+ getMetadata, physicalCameraIds, aidlStreamConfiguration, overrideForPerfClass,
+ earlyExit);
+ if (!ret.isOk()) {
+ return ret;
+ }
+ if (earlyExit != nullptr && *earlyExit) {
+ return binder::Status::ok();
}
- if (earlyExit == nullptr) {
- String8 msg("earlyExit nullptr");
- ALOGE("%s: %s", __FUNCTION__, msg.string());
- return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
- }
- *earlyExit = false;
- auto ret = Camera3Device::mapToStreamConfigurationMode(
- static_cast<camera_stream_configuration_mode_t> (operatingMode),
- /*out*/ &streamConfiguration.operationMode);
- if (ret != OK) {
- String8 msg = String8::format(
- "Camera %s: Failed mapping operating mode %d requested: %s (%d)",
- logicalCameraId.string(), operatingMode, strerror(-ret), ret);
- ALOGE("%s: %s", __FUNCTION__, msg.string());
+ if (convertAidlToHidl38StreamCombination(aidlStreamConfiguration, streamConfiguration) != OK) {
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
- msg.string());
+ "Invalid AIDL->HIDL3.8 conversion");
}
- bool isInputValid = (sessionConfiguration.getInputWidth() > 0) &&
- (sessionConfiguration.getInputHeight() > 0) &&
- (sessionConfiguration.getInputFormat() > 0);
- auto outputConfigs = sessionConfiguration.getOutputConfigurations();
- size_t streamCount = outputConfigs.size();
- streamCount = isInputValid ? streamCount + 1 : streamCount;
- streamConfiguration.streams.resize(streamCount);
- size_t streamIdx = 0;
- if (isInputValid) {
- hardware::hidl_vec<CameraMetadataEnumAndroidSensorPixelMode> defaultSensorPixelModes;
- defaultSensorPixelModes.resize(1);
- defaultSensorPixelModes[0] =
- static_cast<CameraMetadataEnumAndroidSensorPixelMode>(
- ANDROID_SENSOR_PIXEL_MODE_DEFAULT);
- streamConfiguration.streams[streamIdx++].v3_7 = {{{/*streamId*/0,
- hardware::camera::device::V3_2::StreamType::INPUT,
- static_cast<uint32_t> (sessionConfiguration.getInputWidth()),
- static_cast<uint32_t> (sessionConfiguration.getInputHeight()),
- Camera3Device::mapToPixelFormat(sessionConfiguration.getInputFormat()),
- /*usage*/ 0, HAL_DATASPACE_UNKNOWN,
- hardware::camera::device::V3_2::StreamRotation::ROTATION_0},
- /*physicalId*/ nullptr, /*bufferSize*/0}, /*groupId*/-1, defaultSensorPixelModes};
- streamConfiguration.multiResolutionInputImage =
- sessionConfiguration.inputIsMultiResolution();
- }
-
- for (const auto &it : outputConfigs) {
- const std::vector<sp<IGraphicBufferProducer>>& bufferProducers =
- it.getGraphicBufferProducers();
- bool deferredConsumer = it.isDeferred();
- String8 physicalCameraId = String8(it.getPhysicalCameraId());
-
- int dynamicRangeProfile = it.getDynamicRangeProfile();
- std::vector<int32_t> sensorPixelModesUsed = it.getSensorPixelModesUsed();
- const CameraMetadata &physicalDeviceInfo = getMetadata(physicalCameraId,
- overrideForPerfClass);
- const CameraMetadata &metadataChosen =
- physicalCameraId.size() > 0 ? physicalDeviceInfo : deviceInfo;
-
- size_t numBufferProducers = bufferProducers.size();
- bool isStreamInfoValid = false;
- int32_t groupId = it.isMultiResolution() ? it.getSurfaceSetID() : -1;
- OutputStreamInfo streamInfo;
-
- res = checkSurfaceType(numBufferProducers, deferredConsumer, it.getSurfaceType());
- if (!res.isOk()) {
- return res;
- }
- res = checkPhysicalCameraId(physicalCameraIds, physicalCameraId,
- logicalCameraId);
- if (!res.isOk()) {
- return res;
- }
-
- if (deferredConsumer) {
- streamInfo.width = it.getWidth();
- streamInfo.height = it.getHeight();
- streamInfo.format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
- streamInfo.dataSpace = android_dataspace_t::HAL_DATASPACE_UNKNOWN;
- auto surfaceType = it.getSurfaceType();
- streamInfo.consumerUsage = GraphicBuffer::USAGE_HW_TEXTURE;
- if (surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW) {
- streamInfo.consumerUsage |= GraphicBuffer::USAGE_HW_COMPOSER;
- }
- streamInfo.dynamicRangeProfile = it.getDynamicRangeProfile();
- if (checkAndOverrideSensorPixelModesUsed(sensorPixelModesUsed,
- streamInfo.format, streamInfo.width,
- streamInfo.height, metadataChosen, false /*flexibleConsumer*/,
- &streamInfo.sensorPixelModesUsed) != OK) {
- ALOGE("%s: Deferred surface sensor pixel modes not valid",
- __FUNCTION__);
- return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
- "Deferred surface sensor pixel modes not valid");
- }
- mapStreamInfo(streamInfo, camera3::CAMERA_STREAM_ROTATION_0, physicalCameraId, groupId,
- &streamConfiguration.streams[streamIdx++]);
- isStreamInfoValid = true;
-
- if (numBufferProducers == 0) {
- continue;
- }
- }
-
- for (auto& bufferProducer : bufferProducers) {
- sp<Surface> surface;
- res = createSurfaceFromGbp(streamInfo, isStreamInfoValid, surface, bufferProducer,
- logicalCameraId, metadataChosen, sensorPixelModesUsed, dynamicRangeProfile);
-
- if (!res.isOk())
- return res;
-
- if (!isStreamInfoValid) {
- bool isDepthCompositeStream =
- camera3::DepthCompositeStream::isDepthCompositeStream(surface);
- bool isHeicCompositeStream =
- camera3::HeicCompositeStream::isHeicCompositeStream(surface);
- if (isDepthCompositeStream || isHeicCompositeStream) {
- // We need to take in to account that composite streams can have
- // additional internal camera streams.
- std::vector<OutputStreamInfo> compositeStreams;
- if (isDepthCompositeStream) {
- // TODO: Take care of composite streams.
- ret = camera3::DepthCompositeStream::getCompositeStreamInfo(streamInfo,
- deviceInfo, &compositeStreams);
- } else {
- ret = camera3::HeicCompositeStream::getCompositeStreamInfo(streamInfo,
- deviceInfo, &compositeStreams);
- }
- if (ret != OK) {
- String8 msg = String8::format(
- "Camera %s: Failed adding composite streams: %s (%d)",
- logicalCameraId.string(), strerror(-ret), ret);
- ALOGE("%s: %s", __FUNCTION__, msg.string());
- return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
- }
-
- if (compositeStreams.size() == 0) {
- // No internal streams means composite stream not
- // supported.
- *earlyExit = true;
- return binder::Status::ok();
- } else if (compositeStreams.size() > 1) {
- streamCount += compositeStreams.size() - 1;
- streamConfiguration.streams.resize(streamCount);
- }
-
- for (const auto& compositeStream : compositeStreams) {
- mapStreamInfo(compositeStream,
- static_cast<camera_stream_rotation_t> (it.getRotation()),
- physicalCameraId, groupId,
- &streamConfiguration.streams[streamIdx++]);
- }
- } else {
- mapStreamInfo(streamInfo,
- static_cast<camera_stream_rotation_t> (it.getRotation()),
- physicalCameraId, groupId, &streamConfiguration.streams[streamIdx++]);
- }
- isStreamInfoValid = true;
- }
- }
- }
return binder::Status::ok();
}
@@ -850,6 +1039,11 @@
// image
return false;
}
+ if (static_cast<int32_t>(streamConfigV38.streams[i].useCase) !=
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT) {
+ // ICameraDevice older than 3.8 doesn't support stream use case
+ return false;
+ }
streamConfigV37.streams[i] = streamConfigV38.streams[i].v3_7;
}
streamConfigV37.operationMode = streamConfigV38.operationMode;
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
index c05b59b..7027dfe 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
@@ -22,6 +22,7 @@
#include <camera/camera2/SessionConfiguration.h>
#include <camera/camera2/SubmitInfo.h>
#include <android/hardware/camera/device/3.8/types.h>
+#include <aidl/android/hardware/camera/device/ICameraDevice.h>
#include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
#include <android/hardware/camera/device/3.7/ICameraDeviceSession.h>
#include <android/hardware/camera/device/3.8/ICameraDeviceSession.h>
@@ -94,13 +95,15 @@
// Create a Surface from an IGraphicBufferProducer. Returns error if
// IGraphicBufferProducer's property doesn't match with streamInfo
binder::Status createSurfaceFromGbp(
-camera3::OutputStreamInfo& streamInfo, bool isStreamInfoValid,
-sp<Surface>& surface, const sp<IGraphicBufferProducer>& gbp,
-const String8 &logicalCameraId, const CameraMetadata &physicalCameraMetadata,
-const std::vector<int32_t> &sensorPixelModesUsed, int dynamicRangeProfile);
+ camera3::OutputStreamInfo& streamInfo, bool isStreamInfoValid,
+ sp<Surface>& surface, const sp<IGraphicBufferProducer>& gbp,
+ const String8 &logicalCameraId, const CameraMetadata &physicalCameraMetadata,
+ const std::vector<int32_t> &sensorPixelModesUsed, int dynamicRangeProfile,
+ int streamUseCase, int timestampBase, int mirrorMode);
+
void mapStreamInfo(const camera3::OutputStreamInfo &streamInfo,
camera3::camera_stream_rotation_t rotation, String8 physicalId, int32_t groupId,
- hardware::camera::device::V3_7::Stream *stream /*out*/);
+ hardware::camera::device::V3_8::Stream *stream /*out*/);
//check if format is 10-bit output compatible
bool is10bitCompatibleFormat(int32_t format);
@@ -111,6 +114,12 @@
// Check if the device supports a given dynamicRangeProfile
bool isDynamicRangeProfileSupported(int dynamicRangeProfile, const CameraMetadata& staticMeta);
+bool isStreamUseCaseSupported(int streamUseCase, const CameraMetadata &deviceInfo);
+
+void mapStreamInfo(const OutputStreamInfo &streamInfo,
+ camera3::camera_stream_rotation_t rotation, String8 physicalId,
+ int32_t groupId, aidl::android::hardware::camera::device::Stream *stream /*out*/);
+
// Check that the physicalCameraId passed in is spported by the camera
// device.
binder::Status checkPhysicalCameraId(
@@ -138,8 +147,16 @@
// V3_7::StreamConfiguration. Return false if the original V3_8 configuration cannot
// be used by older version HAL.
bool convertHALStreamCombinationFromV38ToV37(
- hardware::camera::device::V3_7::StreamConfiguration &streamConfigV34,
- const hardware::camera::device::V3_8::StreamConfiguration &streamConfigV37);
+ hardware::camera::device::V3_7::StreamConfiguration &streamConfigV37,
+ const hardware::camera::device::V3_8::StreamConfiguration &streamConfigV38);
+
+binder::Status
+convertToHALStreamCombination(
+ const SessionConfiguration& sessionConfiguration,
+ const String8 &logicalCameraId, const CameraMetadata &deviceInfo,
+ metadataGetter getMetadata, const std::vector<std::string> &physicalCameraIds,
+ aidl::android::hardware::camera::device::StreamConfiguration &streamConfiguration,
+ bool overrideForPerfClass, bool *earlyExit);
// Utility function to convert a V3_7::StreamConfiguration to
// V3_4::StreamConfiguration. Return false if the original V3_7 configuration cannot
diff --git a/services/mediacodec/Android.bp b/services/mediacodec/Android.bp
index bf4d524..4488efb 100644
--- a/services/mediacodec/Android.bp
+++ b/services/mediacodec/Android.bp
@@ -19,6 +19,7 @@
name: "mediaswcodec",
vendor_available: true,
min_sdk_version: "29",
+ apex_available: ["com.android.media.swcodec"],
srcs: [
"main_swcodecservice.cpp",
diff --git a/services/mediacodec/registrant/Android.bp b/services/mediacodec/registrant/Android.bp
index d10e339..12cc32a 100644
--- a/services/mediacodec/registrant/Android.bp
+++ b/services/mediacodec/registrant/Android.bp
@@ -10,6 +10,12 @@
cc_library {
name: "libmedia_codecserviceregistrant",
vendor_available: true,
+ min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
+
srcs: [
"CodecServiceRegistrant.cpp",
],
diff --git a/services/mediametrics/Android.bp b/services/mediametrics/Android.bp
index c98d5fc..11534bb 100644
--- a/services/mediametrics/Android.bp
+++ b/services/mediametrics/Android.bp
@@ -181,15 +181,22 @@
"libstatssocket",
],
+ // within the library, we use "xxx.h"
+ local_include_dirs: [
+ "include/mediametricsservice",
+ ],
+
+ // external parties use <mediametricsservice/xxx.h>
+ export_include_dirs: [
+ "include",
+ ],
+
static_libs: [
"libplatformprotos",
],
header_libs: [
"libaaudio_headers",
- ],
-
- include_dirs: [
- "system/media/audio_utils/include",
+ "libaudioutils_headers",
],
}
diff --git a/services/mediametrics/AudioAnalytics.cpp b/services/mediametrics/AudioAnalytics.cpp
index 0e4dfcf..ade54d0 100644
--- a/services/mediametrics/AudioAnalytics.cpp
+++ b/services/mediametrics/AudioAnalytics.cpp
@@ -175,14 +175,29 @@
"log_session_id",
};
+static constexpr const char * const AudioRecordStatusFields[] {
+ "mediametrics_audiorecordstatus_reported",
+ "status",
+ "debug_message",
+ "status_subcode",
+ "uid",
+ "event",
+ "input_flags",
+ "source",
+ "encoding",
+ "channel_mask",
+ "buffer_frame_count",
+ "sample_rate",
+};
+
static constexpr const char * const AudioTrackStatusFields[] {
"mediametrics_audiotrackstatus_reported",
"status",
"debug_message",
- "sub_code",
+ "status_subcode",
"uid",
"event",
- "flags",
+ "output_flags",
"content_type",
"usage",
"encoding",
@@ -535,15 +550,97 @@
// the types of errors and the frequency of errors.
mHeatMap.add(prefixKey, suffixKey, eventStr, statusString, uid, message, subCode);
- // Certain keys/event pairs are sent to statsd.
+ // Certain keys/event pairs are sent to statsd. If we get a match (true) we return early.
+ if (reportAudioRecordStatus(item, key, eventStr, statusString, uid, message, subCode)) return;
+ if (reportAudioTrackStatus(item, key, eventStr, statusString, uid, message, subCode)) return;
+}
+
+bool AudioAnalytics::reportAudioRecordStatus(
+ const std::shared_ptr<const mediametrics::Item>& item,
+ const std::string& key, const std::string& eventStr,
+ const std::string& statusString, uid_t uid, const std::string& message,
+ int32_t subCode) const
+{
// Note that the prefixes often end with a '.' so we use startsWith.
- if (startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
- && eventStr == AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE) {
+ if (!startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD)) return false;
+ if (eventStr == AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE) {
const int atom_status = types::lookup<types::STATUS, int32_t>(statusString);
// currently we only send create status events.
- const int32_t event =
- android::util::MEDIAMETRICS_AUDIO_TRACK_STATUS_REPORTED__EVENT__EVENT_CREATE;
+ const int32_t event = android::util::
+ MEDIAMETRICS_AUDIO_RECORD_STATUS_REPORTED__EVENT__AUDIO_RECORD_EVENT_CREATE;
+
+ // The following fields should all be present in a create event.
+ std::string flagsStr;
+ ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ORIGINALFLAGS, &flagsStr),
+ "%s: %s missing %s field", __func__,
+ AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_ORIGINALFLAGS);
+ const auto flags = types::lookup<types::INPUT_FLAG, int32_t>(flagsStr);
+
+ // AMEDIAMETRICS_PROP_SESSIONID omitted from atom
+
+ std::string sourceStr;
+ ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SOURCE, &sourceStr),
+ "%s: %s missing %s field",
+ __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_SOURCE);
+ const int32_t source = types::lookup<types::SOURCE_TYPE, int32_t>(sourceStr);
+
+ // AMEDIAMETRICS_PROP_SELECTEDDEVICEID omitted from atom
+
+ std::string encodingStr;
+ ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ENCODING, &encodingStr),
+ "%s: %s missing %s field",
+ __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_ENCODING);
+ const auto encoding = types::lookup<types::ENCODING, int32_t>(encodingStr);
+
+ int32_t channelMask = 0;
+ ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask),
+ "%s: %s missing %s field",
+ __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_CHANNELMASK);
+ int32_t frameCount = 0;
+ ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount),
+ "%s: %s missing %s field",
+ __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_FRAMECOUNT);
+ int32_t sampleRate = 0;
+ ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate),
+ "%s: %s missing %s field",
+ __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_SAMPLERATE);
+
+ const auto [ result, str ] = sendToStatsd(AudioRecordStatusFields,
+ CONDITION(android::util::MEDIAMETRICS_AUDIORECORDSTATUS_REPORTED)
+ , atom_status
+ , message.c_str()
+ , subCode
+ , uid
+ , event
+ , flags
+ , source
+ , encoding
+ , (int64_t)channelMask
+ , frameCount
+ , sampleRate
+ );
+ ALOGV("%s: statsd %s", __func__, str.c_str());
+ mStatsdLog->log(android::util::MEDIAMETRICS_AUDIORECORDSTATUS_REPORTED, str);
+ return true;
+ }
+ return false;
+}
+
+bool AudioAnalytics::reportAudioTrackStatus(
+ const std::shared_ptr<const mediametrics::Item>& item,
+ const std::string& key, const std::string& eventStr,
+ const std::string& statusString, uid_t uid, const std::string& message,
+ int32_t subCode) const
+{
+ // Note that the prefixes often end with a '.' so we use startsWith.
+ if (!startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)) return false;
+ if (eventStr == AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE) {
+ const int atom_status = types::lookup<types::STATUS, int32_t>(statusString);
+
+ // currently we only send create status events.
+ const int32_t event = android::util::
+ MEDIAMETRICS_AUDIO_TRACK_STATUS_REPORTED__EVENT__AUDIO_TRACK_EVENT_CREATE;
// The following fields should all be present in a create event.
std::string flagsStr;
@@ -589,11 +686,13 @@
double speed = 0.f; // default is 1.f
ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &speed),
"%s: %s missing %s field",
- __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_PLAYBACK_SPEED);
+ __func__,
+ AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_PLAYBACK_SPEED);
double pitch = 0.f; // default is 1.f
ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &pitch),
"%s: %s missing %s field",
- __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_PLAYBACK_PITCH);
+ __func__,
+ AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_PLAYBACK_PITCH);
const auto [ result, str ] = sendToStatsd(AudioTrackStatusFields,
CONDITION(android::util::MEDIAMETRICS_AUDIOTRACKSTATUS_REPORTED)
, atom_status
@@ -613,7 +712,9 @@
);
ALOGV("%s: statsd %s", __func__, str.c_str());
mStatsdLog->log(android::util::MEDIAMETRICS_AUDIOTRACKSTATUS_REPORTED, str);
+ return true;
}
+ return false;
}
// HELPER METHODS
diff --git a/services/mediametrics/AudioPowerUsage.cpp b/services/mediametrics/AudioPowerUsage.cpp
index ab74c8e..5787e9e 100644
--- a/services/mediametrics/AudioPowerUsage.cpp
+++ b/services/mediametrics/AudioPowerUsage.cpp
@@ -45,6 +45,10 @@
#define AUDIO_POWER_USAGE_PROP_DURATION_NS "durationNs" // int64
#define AUDIO_POWER_USAGE_PROP_TYPE "type" // int32
#define AUDIO_POWER_USAGE_PROP_VOLUME "volume" // double
+#define AUDIO_POWER_USAGE_PROP_MIN_VOLUME_DURATION_NS "minVolumeDurationNs" // int64
+#define AUDIO_POWER_USAGE_PROP_MIN_VOLUME "minVolume" // double
+#define AUDIO_POWER_USAGE_PROP_MAX_VOLUME_DURATION_NS "maxVolumeDurationNs" // int64
+#define AUDIO_POWER_USAGE_PROP_MAX_VOLUME "maxVolume" // double
namespace android::mediametrics {
@@ -141,13 +145,34 @@
double volume;
if (!item->getDouble(AUDIO_POWER_USAGE_PROP_VOLUME, &volume)) return;
+ int64_t min_volume_duration_ns;
+ if (!item->getInt64(AUDIO_POWER_USAGE_PROP_MIN_VOLUME_DURATION_NS, &min_volume_duration_ns)) {
+ return;
+ }
+
+ double min_volume;
+ if (!item->getDouble(AUDIO_POWER_USAGE_PROP_MIN_VOLUME, &min_volume)) return;
+
+ int64_t max_volume_duration_ns;
+ if (!item->getInt64(AUDIO_POWER_USAGE_PROP_MAX_VOLUME_DURATION_NS, &max_volume_duration_ns)) {
+ return;
+ }
+
+ double max_volume;
+ if (!item->getDouble(AUDIO_POWER_USAGE_PROP_MAX_VOLUME, &max_volume)) return;
+
const int32_t duration_secs = (int32_t)(duration_ns / NANOS_PER_SECOND);
- const float average_volume = (float)volume;
+ const int32_t min_volume_duration_secs = (int32_t)(min_volume_duration_ns / NANOS_PER_SECOND);
+ const int32_t max_volume_duration_secs = (int32_t)(max_volume_duration_ns / NANOS_PER_SECOND);
const int result = android::util::stats_write(android::util::AUDIO_POWER_USAGE_DATA_REPORTED,
audio_device,
duration_secs,
- average_volume,
- type);
+ (float)volume,
+ type,
+ min_volume_duration_secs,
+ (float)min_volume,
+ max_volume_duration_secs,
+ (float)max_volume);
std::stringstream log;
log << "result:" << result << " {"
@@ -155,17 +180,43 @@
<< android::util::AUDIO_POWER_USAGE_DATA_REPORTED
<< " audio_device:" << audio_device
<< " duration_secs:" << duration_secs
- << " average_volume:" << average_volume
+ << " average_volume:" << (float)volume
<< " type:" << type
+ << " min_volume_duration_secs:" << min_volume_duration_secs
+ << " min_volume:" << (float)min_volume
+ << " max_volume_duration_secs:" << max_volume_duration_secs
+ << " max_volume:" << (float)max_volume
<< " }";
mStatsdLog->log(android::util::AUDIO_POWER_USAGE_DATA_REPORTED, log.str());
}
+void AudioPowerUsage::updateMinMaxVolumeAndDuration(
+ const int64_t cur_max_volume_duration_ns, const double cur_max_volume,
+ const int64_t cur_min_volume_duration_ns, const double cur_min_volume,
+ int64_t& f_max_volume_duration_ns, double& f_max_volume,
+ int64_t& f_min_volume_duration_ns, double& f_min_volume)
+{
+ if (f_min_volume > cur_min_volume) {
+ f_min_volume = cur_min_volume;
+ f_min_volume_duration_ns = cur_min_volume_duration_ns;
+ } else if (f_min_volume == cur_min_volume) {
+ f_min_volume_duration_ns += cur_min_volume_duration_ns;
+ }
+ if (f_max_volume < cur_max_volume) {
+ f_max_volume = cur_max_volume;
+ f_max_volume_duration_ns = cur_max_volume_duration_ns;
+ } else if (f_max_volume == cur_max_volume) {
+ f_max_volume_duration_ns += cur_max_volume_duration_ns;
+ }
+}
+
bool AudioPowerUsage::saveAsItem_l(
- int32_t device, int64_t duration_ns, int32_t type, double average_vol)
+ int32_t device, int64_t duration_ns, int32_t type, double average_vol,
+ int64_t max_volume_duration_ns, double max_volume,
+ int64_t min_volume_duration_ns, double min_volume)
{
ALOGV("%s: (%#x, %d, %lld, %f)", __func__, device, type,
- (long long)duration_ns, average_vol );
+ (long long)duration_ns, average_vol);
if (duration_ns == 0) {
return true; // skip duration 0 usage
}
@@ -193,10 +244,36 @@
item->setDouble(AUDIO_POWER_USAGE_PROP_VOLUME, final_volume);
item->setTimestamp(systemTime(SYSTEM_TIME_REALTIME));
- ALOGV("%s: update (%#x, %d, %lld, %f) --> (%lld, %f)", __func__,
+ // Update the max/min volume and duration
+ int64_t final_min_volume_duration_ns;
+ int64_t final_max_volume_duration_ns;
+ double final_min_volume;
+ double final_max_volume;
+
+ item->getInt64(AUDIO_POWER_USAGE_PROP_MIN_VOLUME_DURATION_NS,
+ &final_min_volume_duration_ns);
+ item->getDouble(AUDIO_POWER_USAGE_PROP_MIN_VOLUME, &final_min_volume);
+ item->getInt64(AUDIO_POWER_USAGE_PROP_MAX_VOLUME_DURATION_NS,
+ &final_max_volume_duration_ns);
+ item->getDouble(AUDIO_POWER_USAGE_PROP_MAX_VOLUME, &final_max_volume);
+ updateMinMaxVolumeAndDuration(max_volume_duration_ns, max_volume,
+ min_volume_duration_ns, min_volume,
+ final_max_volume_duration_ns, final_max_volume,
+ final_min_volume_duration_ns, final_min_volume);
+ item->setInt64(AUDIO_POWER_USAGE_PROP_MIN_VOLUME_DURATION_NS,
+ final_min_volume_duration_ns);
+ item->setDouble(AUDIO_POWER_USAGE_PROP_MIN_VOLUME, final_min_volume);
+ item->setInt64(AUDIO_POWER_USAGE_PROP_MAX_VOLUME_DURATION_NS,
+ final_max_volume_duration_ns);
+ item->setDouble(AUDIO_POWER_USAGE_PROP_MAX_VOLUME, final_max_volume);
+
+ ALOGV("%s: update (%#x, %d, %lld, %f) --> (%lld, %f) min(%lld, %f) max(%lld, %f)",
+ __func__,
device, type,
(long long)item_duration_ns, item_volume,
- (long long)final_duration_ns, final_volume);
+ (long long)final_duration_ns, final_volume,
+ (long long)final_min_volume_duration_ns, final_min_volume,
+ (long long)final_max_volume_duration_ns, final_max_volume);
return true;
}
@@ -208,12 +285,18 @@
sitem->setInt64(AUDIO_POWER_USAGE_PROP_DURATION_NS, duration_ns);
sitem->setInt32(AUDIO_POWER_USAGE_PROP_TYPE, type);
sitem->setDouble(AUDIO_POWER_USAGE_PROP_VOLUME, average_vol);
+ sitem->setInt64(AUDIO_POWER_USAGE_PROP_MIN_VOLUME_DURATION_NS, min_volume_duration_ns);
+ sitem->setDouble(AUDIO_POWER_USAGE_PROP_MIN_VOLUME, min_volume);
+ sitem->setInt64(AUDIO_POWER_USAGE_PROP_MAX_VOLUME_DURATION_NS, max_volume_duration_ns);
+ sitem->setDouble(AUDIO_POWER_USAGE_PROP_MAX_VOLUME, max_volume);
mItems.emplace_back(sitem);
return true;
}
bool AudioPowerUsage::saveAsItems_l(
- int32_t device, int64_t duration_ns, int32_t type, double average_vol)
+ int32_t device, int64_t duration_ns, int32_t type, double average_vol,
+ int64_t max_volume_duration, double max_volume,
+ int64_t min_volume_duration, double min_volume)
{
ALOGV("%s: (%#x, %d, %lld, %f)", __func__, device, type,
(long long)duration_ns, average_vol );
@@ -232,7 +315,9 @@
int32_t tmp_device = device_bits & -device_bits; // get lowest bit
device_bits ^= tmp_device; // clear lowest bit
tmp_device |= input_bit; // restore input bit
- ret = saveAsItem_l(tmp_device, duration_ns, type, average_vol);
+ ret = saveAsItem_l(tmp_device, duration_ns, type, average_vol,
+ max_volume_duration, max_volume,
+ min_volume_duration, min_volume);
ALOGV("%s: device %#x recorded, remaining device_bits = %#x", __func__,
tmp_device, device_bits);
@@ -250,9 +335,28 @@
return;
}
double deviceVolume = 1.;
- if (isTrack && !item->getDouble(AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume)) {
- return;
+ int64_t maxVolumeDurationNs = 0;
+ double maxVolume = AMEDIAMETRICS_INITIAL_MAX_VOLUME;
+ int64_t minVolumeDurationNs = 0;
+ double minVolume = AMEDIAMETRICS_INITIAL_MIN_VOLUME;
+ if (isTrack) {
+ if (!item->getDouble(AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume)) {
+ return;
+ }
+ if (!item->getInt64(AMEDIAMETRICS_PROP_DEVICEMAXVOLUMEDURATIONNS, &maxVolumeDurationNs)) {
+ return;
+ }
+ if (!item->getDouble(AMEDIAMETRICS_PROP_DEVICEMAXVOLUME, &maxVolume)) {
+ return;
+ }
+ if (!item->getInt64(AMEDIAMETRICS_PROP_DEVICEMINVOLUMEDURATIONNS, &minVolumeDurationNs)) {
+ return;
+ }
+ if (!item->getDouble(AMEDIAMETRICS_PROP_DEVICEMINVOLUME, &minVolume)) {
+ return;
+ }
}
+
int32_t type = 0;
std::string type_string;
if ((isTrack && mAudioAnalytics->mAnalyticsState->timeMachine().get(
@@ -285,7 +389,8 @@
ALOGV("device = %s => %d", device_strings.c_str(), device);
}
std::lock_guard l(mLock);
- saveAsItems_l(device, deviceTimeNs, type, deviceVolume);
+ saveAsItems_l(device, deviceTimeNs, type, deviceVolume,
+ maxVolumeDurationNs, maxVolume, minVolumeDurationNs, minVolume);
}
void AudioPowerUsage::checkMode(const std::shared_ptr<const mediametrics::Item>& item)
@@ -299,10 +404,17 @@
if (mMode == "AUDIO_MODE_IN_CALL") { // leaving call mode
const int64_t endCallNs = item->getTimestamp();
const int64_t durationNs = endCallNs - mDeviceTimeNs;
+ const int64_t volumeDurationNs = endCallNs - mVolumeTimeNs;
if (durationNs > 0) {
mDeviceVolume = (mDeviceVolume * double(mVolumeTimeNs - mDeviceTimeNs) +
- mVoiceVolume * double(endCallNs - mVolumeTimeNs)) / (double)durationNs;
- saveAsItems_l(mPrimaryDevice, durationNs, VOICE_CALL_TYPE, mDeviceVolume);
+ mVoiceVolume * double(volumeDurationNs)) / (double)durationNs;
+ updateMinMaxVolumeAndDuration(volumeDurationNs, mVoiceVolume,
+ volumeDurationNs, mVoiceVolume,
+ mMaxVoiceVolumeDurationNs, mMaxVoiceVolume,
+ mMinVoiceVolumeDurationNs, mMinVoiceVolume);
+ saveAsItems_l(mPrimaryDevice, durationNs, VOICE_CALL_TYPE, mDeviceVolume,
+ mMaxVoiceVolumeDurationNs, mMaxVoiceVolume,
+ mMinVoiceVolumeDurationNs, mMinVoiceVolume);
}
} else if (mode == "AUDIO_MODE_IN_CALL") { // entering call mode
mStartCallNs = item->getTimestamp(); // advisory only
@@ -327,10 +439,15 @@
if (mMode == "AUDIO_MODE_IN_CALL") {
const int64_t timeNs = item->getTimestamp();
const int64_t durationNs = timeNs - mDeviceTimeNs;
+ const int64_t volumeDurationNs = timeNs - mVolumeTimeNs;
if (durationNs > 0) {
mDeviceVolume = (mDeviceVolume * double(mVolumeTimeNs - mDeviceTimeNs) +
- mVoiceVolume * double(timeNs - mVolumeTimeNs)) / (double)durationNs;
+ mVoiceVolume * double(volumeDurationNs)) / (double)durationNs;
mVolumeTimeNs = timeNs;
+ updateMinMaxVolumeAndDuration(volumeDurationNs, mVoiceVolume,
+ volumeDurationNs, mVoiceVolume,
+ mMaxVoiceVolumeDurationNs, mMaxVoiceVolume,
+ mMinVoiceVolumeDurationNs, mMinVoiceVolume);
}
}
ALOGV("%s: new voice volume:%lf old voice volume:%lf", __func__, voiceVolume, mVoiceVolume);
@@ -358,15 +475,26 @@
// Save statistics
const int64_t endDeviceNs = item->getTimestamp();
const int64_t durationNs = endDeviceNs - mDeviceTimeNs;
+ const int64_t volumeDurationNs = endDeviceNs - mVolumeTimeNs;
if (durationNs > 0) {
mDeviceVolume = (mDeviceVolume * double(mVolumeTimeNs - mDeviceTimeNs) +
- mVoiceVolume * double(endDeviceNs - mVolumeTimeNs)) / (double)durationNs;
- saveAsItems_l(mPrimaryDevice, durationNs, VOICE_CALL_TYPE, mDeviceVolume);
+ mVoiceVolume * double(volumeDurationNs)) / (double)durationNs;
+ updateMinMaxVolumeAndDuration(volumeDurationNs, mVoiceVolume,
+ volumeDurationNs, mVoiceVolume,
+ mMaxVoiceVolumeDurationNs, mMaxVoiceVolume,
+ mMinVoiceVolumeDurationNs, mMinVoiceVolume);
+ saveAsItems_l(mPrimaryDevice, durationNs, VOICE_CALL_TYPE, mDeviceVolume,
+ mMaxVoiceVolumeDurationNs, mMaxVoiceVolume,
+ mMinVoiceVolumeDurationNs, mMinVoiceVolume);
}
// reset statistics
mDeviceVolume = 0;
mDeviceTimeNs = endDeviceNs;
mVolumeTimeNs = endDeviceNs;
+ mMaxVoiceVolume = AMEDIAMETRICS_INITIAL_MAX_VOLUME;
+ mMinVoiceVolume = AMEDIAMETRICS_INITIAL_MIN_VOLUME;
+ mMaxVoiceVolumeDurationNs = 0;
+ mMinVoiceVolumeDurationNs = 0;
}
ALOGV("%s: new primary device:%#x old primary device:%#x", __func__, device, mPrimaryDevice);
mPrimaryDevice = device;
diff --git a/services/mediametrics/AudioTypes.cpp b/services/mediametrics/AudioTypes.cpp
index 7e406cc..594809c 100644
--- a/services/mediametrics/AudioTypes.cpp
+++ b/services/mediametrics/AudioTypes.cpp
@@ -196,9 +196,9 @@
// DO NOT MODIFY VALUES(OK to add new ones).
static std::unordered_map<std::string, int32_t> map {
{"",
- util::MEDIAMETRICS_AUDIO_TRACK_STATUS_REPORTED__STATUS__OK},
+ util::MEDIAMETRICS_AUDIO_TRACK_STATUS_REPORTED__STATUS__NO_ERROR},
{AMEDIAMETRICS_PROP_STATUS_VALUE_OK,
- util::MEDIAMETRICS_AUDIO_TRACK_STATUS_REPORTED__STATUS__OK},
+ util::MEDIAMETRICS_AUDIO_TRACK_STATUS_REPORTED__STATUS__NO_ERROR},
{AMEDIAMETRICS_PROP_STATUS_VALUE_ARGUMENT,
util::MEDIAMETRICS_AUDIO_TRACK_STATUS_REPORTED__STATUS__ERROR_ARGUMENT},
{AMEDIAMETRICS_PROP_STATUS_VALUE_IO,
diff --git a/services/mediametrics/fuzzer/Android.bp b/services/mediametrics/fuzzer/Android.bp
index 9da7282..84d494e 100644
--- a/services/mediametrics/fuzzer/Android.bp
+++ b/services/mediametrics/fuzzer/Android.bp
@@ -59,9 +59,8 @@
"packagemanager_aidl-cpp",
],
- include_dirs: [
- "frameworks/av/services/mediametrics",
- "system/media/audio_utils/include",
+ header_libs: [
+ "libaudioutils_headers",
],
fuzz_config: {
diff --git a/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp b/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp
index 06ab16e..433332c 100644
--- a/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp
+++ b/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp
@@ -19,15 +19,14 @@
*/
#include <fuzzer/FuzzedDataProvider.h>
#include <media/MediaMetricsItem.h>
+#include <mediametricsservice/AudioTypes.h>
+#include <mediametricsservice/MediaMetricsService.h>
+#include <mediametricsservice/StringUtils.h>
#include <stdio.h>
#include <string.h>
#include <utils/Log.h>
#include <algorithm>
-#include "AudioTypes.h"
-#include "MediaMetricsService.h"
-#include "StringUtils.h"
-
using namespace android;
// low water mark
diff --git a/services/mediametrics/AnalyticsActions.h b/services/mediametrics/include/mediametricsservice/AnalyticsActions.h
similarity index 100%
rename from services/mediametrics/AnalyticsActions.h
rename to services/mediametrics/include/mediametricsservice/AnalyticsActions.h
diff --git a/services/mediametrics/AnalyticsState.h b/services/mediametrics/include/mediametricsservice/AnalyticsState.h
similarity index 100%
rename from services/mediametrics/AnalyticsState.h
rename to services/mediametrics/include/mediametricsservice/AnalyticsState.h
diff --git a/services/mediametrics/AudioAnalytics.h b/services/mediametrics/include/mediametricsservice/AudioAnalytics.h
similarity index 93%
rename from services/mediametrics/AudioAnalytics.h
rename to services/mediametrics/include/mediametricsservice/AudioAnalytics.h
index 9b54cf3..a44fcc1 100644
--- a/services/mediametrics/AudioAnalytics.h
+++ b/services/mediametrics/include/mediametricsservice/AudioAnalytics.h
@@ -122,6 +122,19 @@
*/
void processStatus(const std::shared_ptr<const mediametrics::Item>& item);
+ // Specific reporting methods
+ bool reportAudioRecordStatus(
+ const std::shared_ptr<const mediametrics::Item>& item,
+ const std::string& key, const std::string& eventStr,
+ const std::string& statusString, uid_t uid, const std::string& message,
+ int32_t subCode) const;
+
+ bool reportAudioTrackStatus(
+ const std::shared_ptr<const mediametrics::Item>& item,
+ const std::string& key, const std::string& eventStr,
+ const std::string& statusString, uid_t uid, const std::string& message,
+ int32_t subCode) const;
+
// HELPER METHODS
/**
* Return the audio thread associated with an audio track name.
diff --git a/services/mediametrics/AudioPowerUsage.h b/services/mediametrics/include/mediametricsservice/AudioPowerUsage.h
similarity index 80%
rename from services/mediametrics/AudioPowerUsage.h
rename to services/mediametrics/include/mediametricsservice/AudioPowerUsage.h
index 7021902..b7215e6 100644
--- a/services/mediametrics/AudioPowerUsage.h
+++ b/services/mediametrics/include/mediametricsservice/AudioPowerUsage.h
@@ -26,6 +26,7 @@
namespace android::mediametrics {
+
class AudioAnalytics;
class AudioPowerUsage {
@@ -83,13 +84,21 @@
static bool deviceFromString(const std::string& device_string, int32_t& device);
static int32_t deviceFromStringPairs(const std::string& device_strings);
private:
- bool saveAsItem_l(int32_t device, int64_t duration, int32_t type, double average_vol)
- REQUIRES(mLock);
+ bool saveAsItem_l(int32_t device, int64_t duration, int32_t type, double average_vol,
+ int64_t max_volume_duration, double max_volume,
+ int64_t min_volume_duration, double min_volume)
+ REQUIRES(mLock);
void sendItem(const std::shared_ptr<const mediametrics::Item>& item) const;
void collect();
- bool saveAsItems_l(int32_t device, int64_t duration, int32_t type, double average_vol)
- REQUIRES(mLock);
-
+ bool saveAsItems_l(int32_t device, int64_t duration, int32_t type, double average_vol,
+ int64_t max_volume_duration, double max_volume,
+ int64_t min_volume_duration, double min_volume)
+ REQUIRES(mLock);
+ void updateMinMaxVolumeAndDuration(
+ const int64_t cur_max_volume_duration_ns, const double cur_max_volume,
+ const int64_t cur_min_volume_duration_ns, const double cur_min_volume,
+ int64_t& f_max_volume_duration_ns, double& f_max_volume,
+ int64_t& f_min_volume_duration_ns, double& f_min_volume);
AudioAnalytics * const mAudioAnalytics;
const std::shared_ptr<StatsdLog> mStatsdLog; // mStatsdLog is internally locked
const bool mDisabled;
@@ -100,6 +109,10 @@
double mVoiceVolume GUARDED_BY(mLock) = 0.;
double mDeviceVolume GUARDED_BY(mLock) = 0.;
+ double mMaxVoiceVolume GUARDED_BY(mLock) = AMEDIAMETRICS_INITIAL_MAX_VOLUME;
+ double mMinVoiceVolume GUARDED_BY(mLock) = AMEDIAMETRICS_INITIAL_MIN_VOLUME;
+ int64_t mMaxVoiceVolumeDurationNs GUARDED_BY(mLock) = 0;
+ int64_t mMinVoiceVolumeDurationNs GUARDED_BY(mLock) = 0;
int64_t mStartCallNs GUARDED_BY(mLock) = 0; // advisory only
int64_t mVolumeTimeNs GUARDED_BY(mLock) = 0;
int64_t mDeviceTimeNs GUARDED_BY(mLock) = 0;
diff --git a/services/mediametrics/AudioTypes.h b/services/mediametrics/include/mediametricsservice/AudioTypes.h
similarity index 100%
rename from services/mediametrics/AudioTypes.h
rename to services/mediametrics/include/mediametricsservice/AudioTypes.h
diff --git a/services/mediametrics/HeatMap.h b/services/mediametrics/include/mediametricsservice/HeatMap.h
similarity index 100%
rename from services/mediametrics/HeatMap.h
rename to services/mediametrics/include/mediametricsservice/HeatMap.h
diff --git a/services/mediametrics/LruSet.h b/services/mediametrics/include/mediametricsservice/LruSet.h
similarity index 100%
rename from services/mediametrics/LruSet.h
rename to services/mediametrics/include/mediametricsservice/LruSet.h
diff --git a/services/mediametrics/MediaMetricsService.h b/services/mediametrics/include/mediametricsservice/MediaMetricsService.h
similarity index 100%
rename from services/mediametrics/MediaMetricsService.h
rename to services/mediametrics/include/mediametricsservice/MediaMetricsService.h
diff --git a/services/mediametrics/StatsdLog.h b/services/mediametrics/include/mediametricsservice/StatsdLog.h
similarity index 100%
rename from services/mediametrics/StatsdLog.h
rename to services/mediametrics/include/mediametricsservice/StatsdLog.h
diff --git a/services/mediametrics/StringUtils.h b/services/mediametrics/include/mediametricsservice/StringUtils.h
similarity index 100%
rename from services/mediametrics/StringUtils.h
rename to services/mediametrics/include/mediametricsservice/StringUtils.h
diff --git a/services/mediametrics/TimeMachine.h b/services/mediametrics/include/mediametricsservice/TimeMachine.h
similarity index 100%
rename from services/mediametrics/TimeMachine.h
rename to services/mediametrics/include/mediametricsservice/TimeMachine.h
diff --git a/services/mediametrics/TimedAction.h b/services/mediametrics/include/mediametricsservice/TimedAction.h
similarity index 100%
rename from services/mediametrics/TimedAction.h
rename to services/mediametrics/include/mediametricsservice/TimedAction.h
diff --git a/services/mediametrics/TransactionLog.h b/services/mediametrics/include/mediametricsservice/TransactionLog.h
similarity index 100%
rename from services/mediametrics/TransactionLog.h
rename to services/mediametrics/include/mediametricsservice/TransactionLog.h
diff --git a/services/mediametrics/ValidateId.h b/services/mediametrics/include/mediametricsservice/ValidateId.h
similarity index 100%
rename from services/mediametrics/ValidateId.h
rename to services/mediametrics/include/mediametricsservice/ValidateId.h
diff --git a/services/mediametrics/Wrap.h b/services/mediametrics/include/mediametricsservice/Wrap.h
similarity index 100%
rename from services/mediametrics/Wrap.h
rename to services/mediametrics/include/mediametricsservice/Wrap.h
diff --git a/services/mediametrics/cleaner.h b/services/mediametrics/include/mediametricsservice/cleaner.h
similarity index 100%
rename from services/mediametrics/cleaner.h
rename to services/mediametrics/include/mediametricsservice/cleaner.h
diff --git a/services/mediametrics/iface_statsd.h b/services/mediametrics/include/mediametricsservice/iface_statsd.h
similarity index 100%
rename from services/mediametrics/iface_statsd.h
rename to services/mediametrics/include/mediametricsservice/iface_statsd.h
diff --git a/services/mediametrics/main_mediametrics.cpp b/services/mediametrics/main_mediametrics.cpp
index 3a66538..455d67a 100644
--- a/services/mediametrics/main_mediametrics.cpp
+++ b/services/mediametrics/main_mediametrics.cpp
@@ -18,11 +18,10 @@
//#define LOG_NDEBUG 0
#include <utils/Log.h>
-#include "MediaMetricsService.h"
-
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
+#include <mediametricsservice/MediaMetricsService.h>
#include <mediautils/LimitProcessMemory.h>
int main(int argc __unused, char **argv)
diff --git a/services/mediametrics/statsd_codec.cpp b/services/mediametrics/statsd_codec.cpp
index 8581437..17a3a5f 100644
--- a/services/mediametrics/statsd_codec.cpp
+++ b/services/mediametrics/statsd_codec.cpp
@@ -390,6 +390,48 @@
}
AStatsEvent_writeInt32(event, qpBMaxOri);
+ // int32_t configColorStandard = -1;
+ // if (item->getInt32("android.media.mediacodec.config-color-standard", &configColorStandard)) {
+ // metrics_proto.set_config_color_standard(configColorStandard);
+ // }
+ // AStatsEvent_writeInt32(event, configColorStandard);
+
+ // int32_t configColorRange = -1;
+ // if (item->getInt32("android.media.mediacodec.config-color-range", &configColorRange)) {
+ // metrics_proto.set_config_color_range(configColorRange);
+ // }
+ // AStatsEvent_writeInt32(event, configColorRange);
+
+ // int32_t configColorTransfer = -1;
+ // if (item->getInt32("android.media.mediacodec.config-color-transfer", &configColorTransfer)) {
+ // metrics_proto.set_config_color_transfer(configColorTransfer);
+ // }
+ // AStatsEvent_writeInt32(event, configColorTransfer);
+
+ // int32_t parsedColorStandard = -1;
+ // if (item->getInt32("android.media.mediacodec.parsed-color-standard", &parsedColorStandard)) {
+ // metrics_proto.set_parsed_color_standard(parsedColorStandard);
+ // }
+ // AStatsEvent_writeInt32(event, parsedColorStandard);
+
+ // int32_t parsedColorRange = -1;
+ // if (item->getInt32("android.media.mediacodec.parsed-color-range", &parsedColorRange)) {
+ // metrics_proto.set_parsed_color_range(parsedColorRange);
+ // }
+ // AStatsEvent_writeInt32(event, parsedColorRange);
+
+ // int32_t parsedColorTransfer = -1;
+ // if (item->getInt32("android.media.mediacodec.parsed-color-transfer", &parsedColorTransfer)) {
+ // metrics_proto.set_parsed_color_transfer(parsedColorTransfer);
+ // }
+ // AStatsEvent_writeInt32(event, parsedColorTransfer);
+
+ // int32_t hdrMetadataFlags = -1;
+ // if (item->getInt32("android.media.mediacodec.hdr-metadata-flags", &hdrMetadataFlags)) {
+ // metrics_proto.set_hdr_metadata_flags(hdrMetadataFlags);
+ // }
+ // AStatsEvent_writeInt32(event, hdrMetadataFlags);
+
int err = AStatsEvent_write(event);
if (err < 0) {
ALOGE("Failed to write codec metrics to statsd (%d)", err);
diff --git a/services/mediametrics/tests/mediametrics_tests.cpp b/services/mediametrics/tests/mediametrics_tests.cpp
index 102700a..bc7b47b 100644
--- a/services/mediametrics/tests/mediametrics_tests.cpp
+++ b/services/mediametrics/tests/mediametrics_tests.cpp
@@ -17,19 +17,18 @@
#define LOG_TAG "mediametrics_tests"
#include <utils/Log.h>
-#include "MediaMetricsService.h"
#include <stdio.h>
#include <unordered_set>
#include <gtest/gtest.h>
#include <media/MediaMetricsItem.h>
+#include <mediametricsservice/AudioTypes.h>
+#include <mediametricsservice/MediaMetricsService.h>
+#include <mediametricsservice/StringUtils.h>
+#include <mediametricsservice/ValidateId.h>
#include <system/audio.h>
-#include "AudioTypes.h"
-#include "StringUtils.h"
-#include "ValidateId.h"
-
using namespace android;
static size_t countNewlines(const char *s) {
diff --git a/services/mediaresourcemanager/IMediaResourceMonitor.h b/services/mediaresourcemanager/IMediaResourceMonitor.h
index f92d557..4dd87e1 100644
--- a/services/mediaresourcemanager/IMediaResourceMonitor.h
+++ b/services/mediaresourcemanager/IMediaResourceMonitor.h
@@ -32,6 +32,7 @@
enum {
TYPE_VIDEO_CODEC = 0,
TYPE_AUDIO_CODEC = 1,
+ TYPE_IMAGE_CODEC = 2,
};
virtual void notifyResourceGranted(/*in*/ int32_t pid, /*in*/ const int32_t type) = 0;
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 953686b..57be435 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -51,8 +51,8 @@
class DeathNotifier : public RefBase {
public:
- DeathNotifier(const std::shared_ptr<ResourceManagerService> &service,
- int pid, int64_t clientId);
+ DeathNotifier(const std::shared_ptr<ResourceManagerService> &service, int pid,
+ int64_t clientId);
virtual ~DeathNotifier() {}
@@ -130,27 +130,48 @@
return itemsStr;
}
-static bool hasResourceType(MediaResource::Type type, const ResourceList& resources) {
+static bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
+ MediaResourceParcel resource) {
+ if (type != resource.type) {
+ return false;
+ }
+ switch (type) {
+ // Codec subtypes (e.g. video vs. audio) are each considered separate resources, so
+ // compare the subtypes as well.
+ case MediaResource::Type::kSecureCodec:
+ case MediaResource::Type::kNonSecureCodec:
+ if (resource.subType == subType) {
+ return true;
+ }
+ break;
+ // Non-codec resources are not segregated by the subtype (e.g. video vs. audio).
+ default:
+ return true;
+ }
+ return false;
+}
+
+static bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
+ const ResourceList& resources) {
for (auto it = resources.begin(); it != resources.end(); it++) {
- if (it->second.type == type) {
+ if (hasResourceType(type, subType, it->second)) {
return true;
}
}
return false;
}
-static bool hasResourceType(MediaResource::Type type, const ResourceInfos& infos) {
+static bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
+ const ResourceInfos& infos) {
for (size_t i = 0; i < infos.size(); ++i) {
- if (hasResourceType(type, infos[i].resources)) {
+ if (hasResourceType(type, subType, infos[i].resources)) {
return true;
}
}
return false;
}
-static ResourceInfos& getResourceInfosForEdit(
- int pid,
- PidResourceInfosMap& map) {
+static ResourceInfos& getResourceInfosForEdit(int pid, PidResourceInfosMap& map) {
ssize_t index = map.indexOfKey(pid);
if (index < 0) {
// new pid
@@ -161,11 +182,8 @@
return map.editValueFor(pid);
}
-static ResourceInfo& getResourceInfoForEdit(
- uid_t uid,
- int64_t clientId,
- const std::shared_ptr<IResourceManagerClient>& client,
- ResourceInfos& infos) {
+static ResourceInfo& getResourceInfoForEdit(uid_t uid, int64_t clientId,
+ const std::shared_ptr<IResourceManagerClient>& client, ResourceInfos& infos) {
ssize_t index = infos.indexOfKey(clientId);
if (index < 0) {
@@ -188,17 +206,24 @@
if (binder != NULL) {
sp<IMediaResourceMonitor> service = interface_cast<IMediaResourceMonitor>(binder);
for (size_t i = 0; i < resources.size(); ++i) {
- if (resources[i].subType == MediaResource::SubType::kAudioCodec) {
- service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_AUDIO_CODEC);
- } else if (resources[i].subType == MediaResource::SubType::kVideoCodec) {
- service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_VIDEO_CODEC);
+ switch (resources[i].subType) {
+ case MediaResource::SubType::kAudioCodec:
+ service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_AUDIO_CODEC);
+ break;
+ case MediaResource::SubType::kVideoCodec:
+ service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_VIDEO_CODEC);
+ break;
+ case MediaResource::SubType::kImageCodec:
+ service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_IMAGE_CODEC);
+ break;
+ case MediaResource::SubType::kUnspecifiedSubType:
+ break;
}
}
}
}
-binder_status_t ResourceManagerService::dump(
- int fd, const char** /*args*/, uint32_t /*numArgs*/) {
+binder_status_t ResourceManagerService::dump(int fd, const char** /*args*/, uint32_t /*numArgs*/) {
String8 result;
if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
@@ -275,8 +300,7 @@
return OK;
}
-struct SystemCallbackImpl :
- public ResourceManagerService::SystemCallbackInterface {
+struct SystemCallbackImpl : public ResourceManagerService::SystemCallbackInterface {
SystemCallbackImpl() : mClientToken(new BBinder()) {}
virtual void noteStartVideo(int uid) override {
@@ -303,8 +327,7 @@
ResourceManagerService::ResourceManagerService()
: ResourceManagerService(new ProcessInfo(), new SystemCallbackImpl()) {}
-ResourceManagerService::ResourceManagerService(
- const sp<ProcessInfoInterface> &processInfo,
+ResourceManagerService::ResourceManagerService(const sp<ProcessInfoInterface> &processInfo,
const sp<SystemCallbackInterface> &systemResource)
: mProcessInfo(processInfo),
mSystemCB(systemResource),
@@ -362,8 +385,8 @@
return Status::ok();
}
-void ResourceManagerService::onFirstAdded(
- const MediaResourceParcel& resource, const ResourceInfo& clientInfo) {
+void ResourceManagerService::onFirstAdded(const MediaResourceParcel& resource,
+ const ResourceInfo& clientInfo) {
// first time added
if (resource.type == MediaResource::Type::kCpuBoost
&& resource.subType == MediaResource::SubType::kUnspecifiedSubType) {
@@ -380,8 +403,8 @@
}
}
-void ResourceManagerService::onLastRemoved(
- const MediaResourceParcel& resource, const ResourceInfo& clientInfo) {
+void ResourceManagerService::onLastRemoved(const MediaResourceParcel& resource,
+ const ResourceInfo& clientInfo) {
if (resource.type == MediaResource::Type::kCpuBoost
&& resource.subType == MediaResource::SubType::kUnspecifiedSubType
&& mCpuBoostCount > 0) {
@@ -394,8 +417,8 @@
}
}
-void ResourceManagerService::mergeResources(
- MediaResourceParcel& r1, const MediaResourceParcel& r2) {
+void ResourceManagerService::mergeResources(MediaResourceParcel& r1,
+ const MediaResourceParcel& r2) {
// The resource entry on record is maintained to be in [0,INT64_MAX].
// Clamp if merging in the new resource value causes it to go out of bound.
// Note that the new resource value could be negative, eg.DrmSession, the
@@ -411,10 +434,7 @@
}
}
-Status ResourceManagerService::addResource(
- int32_t pid,
- int32_t uid,
- int64_t clientId,
+Status ResourceManagerService::addResource(int32_t pid, int32_t uid, int64_t clientId,
const std::shared_ptr<IResourceManagerClient>& client,
const std::vector<MediaResourceParcel>& resources) {
String8 log = String8::format("addResource(pid %d, clientId %lld, resources %s)",
@@ -422,11 +442,11 @@
mServiceLog->add(log);
Mutex::Autolock lock(mLock);
- if (!mProcessInfo->isValidPid(pid)) {
+ if (!mProcessInfo->isPidUidTrusted(pid, uid)) {
pid_t callingPid = IPCThreadState::self()->getCallingPid();
uid_t callingUid = IPCThreadState::self()->getCallingUid();
- ALOGW("%s called with untrusted pid %d, using calling pid %d, uid %d", __FUNCTION__,
- pid, callingPid, callingUid);
+ ALOGW("%s called with untrusted pid %d or uid %d, using calling pid %d, uid %d",
+ __FUNCTION__, pid, uid, callingPid, callingUid);
pid = callingPid;
uid = callingUid;
}
@@ -473,15 +493,14 @@
return Status::ok();
}
-Status ResourceManagerService::removeResource(
- int32_t pid, int64_t clientId,
+Status ResourceManagerService::removeResource(int32_t pid, int64_t clientId,
const std::vector<MediaResourceParcel>& resources) {
String8 log = String8::format("removeResource(pid %d, clientId %lld, resources %s)",
pid, (long long) clientId, getString(resources).string());
mServiceLog->add(log);
Mutex::Autolock lock(mLock);
- if (!mProcessInfo->isValidPid(pid)) {
+ if (!mProcessInfo->isPidTrusted(pid)) {
pid_t callingPid = IPCThreadState::self()->getCallingPid();
ALOGW("%s called with untrusted pid %d, using calling pid %d", __FUNCTION__,
pid, callingPid);
@@ -549,7 +568,7 @@
mServiceLog->add(log);
Mutex::Autolock lock(mLock);
- if (checkValid && !mProcessInfo->isValidPid(pid)) {
+ if (checkValid && !mProcessInfo->isPidTrusted(pid)) {
pid_t callingPid = IPCThreadState::self()->getCallingPid();
ALOGW("%s called with untrusted pid %d, using calling pid %d", __FUNCTION__,
pid, callingPid);
@@ -583,22 +602,19 @@
return Status::ok();
}
-void ResourceManagerService::getClientForResource_l(
- int callingPid, const MediaResourceParcel *res,
+void ResourceManagerService::getClientForResource_l(int callingPid, const MediaResourceParcel *res,
Vector<std::shared_ptr<IResourceManagerClient>> *clients) {
if (res == NULL) {
return;
}
std::shared_ptr<IResourceManagerClient> client;
- if (getLowestPriorityBiggestClient_l(callingPid, res->type, &client)) {
+ if (getLowestPriorityBiggestClient_l(callingPid, res->type, res->subType, &client)) {
clients->push_back(client);
}
}
-Status ResourceManagerService::reclaimResource(
- int32_t callingPid,
- const std::vector<MediaResourceParcel>& resources,
- bool* _aidl_return) {
+Status ResourceManagerService::reclaimResource(int32_t callingPid,
+ const std::vector<MediaResourceParcel>& resources, bool* _aidl_return) {
String8 log = String8::format("reclaimResource(callingPid %d, resources %s)",
callingPid, getString(resources).string());
mServiceLog->add(log);
@@ -607,7 +623,7 @@
Vector<std::shared_ptr<IResourceManagerClient>> clients;
{
Mutex::Autolock lock(mLock);
- if (!mProcessInfo->isValidPid(callingPid)) {
+ if (!mProcessInfo->isPidTrusted(callingPid)) {
pid_t actualCallingPid = IPCThreadState::self()->getCallingPid();
ALOGW("%s called with untrusted pid %d, using actual calling pid %d", __FUNCTION__,
callingPid, actualCallingPid);
@@ -618,34 +634,43 @@
const MediaResourceParcel *graphicMemory = NULL;
const MediaResourceParcel *drmSession = NULL;
for (size_t i = 0; i < resources.size(); ++i) {
- MediaResource::Type type = resources[i].type;
- if (resources[i].type == MediaResource::Type::kSecureCodec) {
- secureCodec = &resources[i];
- } else if (type == MediaResource::Type::kNonSecureCodec) {
- nonSecureCodec = &resources[i];
- } else if (type == MediaResource::Type::kGraphicMemory) {
- graphicMemory = &resources[i];
- } else if (type == MediaResource::Type::kDrmSession) {
- drmSession = &resources[i];
+ switch (resources[i].type) {
+ case MediaResource::Type::kSecureCodec:
+ secureCodec = &resources[i];
+ break;
+ case MediaResource::Type::kNonSecureCodec:
+ nonSecureCodec = &resources[i];
+ break;
+ case MediaResource::Type::kGraphicMemory:
+ graphicMemory = &resources[i];
+ break;
+ case MediaResource::Type::kDrmSession:
+ drmSession = &resources[i];
+ break;
+ default:
+ break;
}
}
// first pass to handle secure/non-secure codec conflict
if (secureCodec != NULL) {
if (!mSupportsMultipleSecureCodecs) {
- if (!getAllClients_l(callingPid, MediaResource::Type::kSecureCodec, &clients)) {
+ if (!getAllClients_l(callingPid, MediaResource::Type::kSecureCodec,
+ secureCodec->subType, &clients)) {
return Status::ok();
}
}
if (!mSupportsSecureWithNonSecureCodec) {
- if (!getAllClients_l(callingPid, MediaResource::Type::kNonSecureCodec, &clients)) {
+ if (!getAllClients_l(callingPid, MediaResource::Type::kNonSecureCodec,
+ secureCodec->subType, &clients)) {
return Status::ok();
}
}
}
if (nonSecureCodec != NULL) {
if (!mSupportsSecureWithNonSecureCodec) {
- if (!getAllClients_l(callingPid, MediaResource::Type::kSecureCodec, &clients)) {
+ if (!getAllClients_l(callingPid, MediaResource::Type::kSecureCodec,
+ nonSecureCodec->subType, &clients)) {
return Status::ok();
}
}
@@ -681,11 +706,11 @@
}
}
- *_aidl_return = reclaimInternal(clients);
+ *_aidl_return = reclaimUnconditionallyFrom(clients);
return Status::ok();
}
-bool ResourceManagerService::reclaimInternal(
+bool ResourceManagerService::reclaimUnconditionallyFrom(
const Vector<std::shared_ptr<IResourceManagerClient>> &clients) {
if (clients.size() == 0) {
return false;
@@ -732,9 +757,7 @@
return false;
}
-Status ResourceManagerService::overridePid(
- int originalPid,
- int newPid) {
+Status ResourceManagerService::overridePid(int originalPid, int newPid) {
String8 log = String8::format("overridePid(originalPid %d, newPid %d)",
originalPid, newPid);
mServiceLog->add(log);
@@ -763,9 +786,7 @@
}
Status ResourceManagerService::overrideProcessInfo(
- const std::shared_ptr<IResourceManagerClient>& client,
- int pid,
- int procState,
+ const std::shared_ptr<IResourceManagerClient>& client, int pid, int procState,
int oomScore) {
String8 log = String8::format("overrideProcessInfo(pid %d, procState %d, oomScore %d)",
pid, procState, oomScore);
@@ -799,8 +820,8 @@
return Status::ok();
}
-uintptr_t ResourceManagerService::addCookieAndLink_l(
- ::ndk::SpAIBinder binder, const sp<DeathNotifier>& notifier) {
+uintptr_t ResourceManagerService::addCookieAndLink_l(::ndk::SpAIBinder binder,
+ const sp<DeathNotifier>& notifier) {
std::scoped_lock lock{sCookieLock};
uintptr_t cookie;
@@ -813,8 +834,7 @@
return cookie;
}
-void ResourceManagerService::removeCookieAndUnlink_l(
- ::ndk::SpAIBinder binder, uintptr_t cookie) {
+void ResourceManagerService::removeCookieAndUnlink_l(::ndk::SpAIBinder binder, uintptr_t cookie) {
std::scoped_lock lock{sCookieLock};
AIBinder_unlinkToDeath(binder.get(), mDeathRecipient.get(), (void*)cookie);
sCookieToDeathNotifierMap.erase(cookie);
@@ -846,7 +866,7 @@
mServiceLog->add(log);
Mutex::Autolock lock(mLock);
- if (!mProcessInfo->isValidPid(pid)) {
+ if (!mProcessInfo->isPidTrusted(pid)) {
pid_t callingPid = IPCThreadState::self()->getCallingPid();
ALOGW("%s called with untrusted pid %d, using calling pid %d", __FUNCTION__,
pid, callingPid);
@@ -878,7 +898,7 @@
Vector<std::shared_ptr<IResourceManagerClient>> clients;
{
Mutex::Autolock lock(mLock);
- if (!mProcessInfo->isValidPid(pid)) {
+ if (!mProcessInfo->isPidTrusted(pid)) {
pid_t callingPid = IPCThreadState::self()->getCallingPid();
ALOGW("%s called with untrusted pid %d, using calling pid %d", __FUNCTION__,
pid, callingPid);
@@ -889,16 +909,34 @@
MediaResource::Type::kNonSecureCodec,
MediaResource::Type::kGraphicMemory,
MediaResource::Type::kDrmSession}) {
- std::shared_ptr<IResourceManagerClient> client;
- if (getBiggestClient_l(pid, type, &client, true /* pendingRemovalOnly */)) {
- clients.add(client);
- break;
+ switch (type) {
+ // Codec resources are segregated by audio, video and image domains.
+ case MediaResource::Type::kSecureCodec:
+ case MediaResource::Type::kNonSecureCodec:
+ for (MediaResource::SubType subType : {MediaResource::SubType::kAudioCodec,
+ MediaResource::SubType::kVideoCodec,
+ MediaResource::SubType::kImageCodec}) {
+ std::shared_ptr<IResourceManagerClient> client;
+ if (getBiggestClientPendingRemoval_l(pid, type, subType, &client)) {
+ clients.add(client);
+ continue;
+ }
+ }
+ break;
+ // Non-codec resources are shared by audio, video and image codecs (no subtype).
+ default:
+ std::shared_ptr<IResourceManagerClient> client;
+ if (getBiggestClientPendingRemoval_l(pid, type,
+ MediaResource::SubType::kUnspecifiedSubType, &client)) {
+ clients.add(client);
+ }
+ break;
}
}
}
if (!clients.empty()) {
- reclaimInternal(clients);
+ reclaimUnconditionallyFrom(clients);
}
return Status::ok();
}
@@ -915,14 +953,13 @@
return mProcessInfo->getPriority(newPid, priority);
}
-bool ResourceManagerService::getAllClients_l(
- int callingPid, MediaResource::Type type,
- Vector<std::shared_ptr<IResourceManagerClient>> *clients) {
+bool ResourceManagerService::getAllClients_l(int callingPid, MediaResource::Type type,
+ MediaResource::SubType subType, 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) {
- if (hasResourceType(type, infos[j].resources)) {
+ if (hasResourceType(type, subType, infos[j].resources)) {
if (!isCallingPriorityHigher_l(callingPid, mMap.keyAt(i))) {
// some higher/equal priority process owns the resource,
// this request can't be fulfilled.
@@ -942,8 +979,8 @@
return true;
}
-bool ResourceManagerService::getLowestPriorityBiggestClient_l(
- int callingPid, MediaResource::Type type,
+bool ResourceManagerService::getLowestPriorityBiggestClient_l(int callingPid,
+ MediaResource::Type type, MediaResource::SubType subType,
std::shared_ptr<IResourceManagerClient> *client) {
int lowestPriorityPid;
int lowestPriority;
@@ -951,7 +988,7 @@
// Before looking into other processes, check if we have clients marked for
// pending removal in the same process.
- if (getBiggestClient_l(callingPid, type, client, true /* pendingRemovalOnly */)) {
+ if (getBiggestClientPendingRemoval_l(callingPid, type, subType, client)) {
return true;
}
if (!getPriority_l(callingPid, &callingPriority)) {
@@ -959,7 +996,7 @@
callingPid);
return false;
}
- if (!getLowestPriorityPid_l(type, &lowestPriorityPid, &lowestPriority)) {
+ if (!getLowestPriorityPid_l(type, subType, &lowestPriorityPid, &lowestPriority)) {
return false;
}
if (lowestPriority <= callingPriority) {
@@ -968,14 +1005,14 @@
return false;
}
- if (!getBiggestClient_l(lowestPriorityPid, type, client)) {
+ if (!getBiggestClient_l(lowestPriorityPid, type, subType, client)) {
return false;
}
return true;
}
-bool ResourceManagerService::getLowestPriorityPid_l(
- MediaResource::Type type, int *lowestPriorityPid, int *lowestPriority) {
+bool ResourceManagerService::getLowestPriorityPid_l(MediaResource::Type type,
+ MediaResource::SubType subType, int *lowestPriorityPid, int *lowestPriority) {
int pid = -1;
int priority = -1;
for (size_t i = 0; i < mMap.size(); ++i) {
@@ -983,7 +1020,7 @@
// no client on this process.
continue;
}
- if (!hasResourceType(type, mMap.valueAt(i))) {
+ if (!hasResourceType(type, subType, mMap.valueAt(i))) {
// doesn't have the requested resource type
continue;
}
@@ -1021,8 +1058,13 @@
return (callingPidPriority < priority);
}
-bool ResourceManagerService::getBiggestClient_l(
- int pid, MediaResource::Type type, std::shared_ptr<IResourceManagerClient> *client,
+bool ResourceManagerService::getBiggestClientPendingRemoval_l(int pid, MediaResource::Type type,
+ MediaResource::SubType subType, std::shared_ptr<IResourceManagerClient> *client) {
+ return getBiggestClient_l(pid, type, subType, client, true /* pendingRemovalOnly */);
+}
+
+bool ResourceManagerService::getBiggestClient_l(int pid, MediaResource::Type type,
+ MediaResource::SubType subType, std::shared_ptr<IResourceManagerClient> *client,
bool pendingRemovalOnly) {
ssize_t index = mMap.indexOfKey(pid);
if (index < 0) {
@@ -1041,7 +1083,7 @@
}
for (auto it = resources.begin(); it != resources.end(); it++) {
const MediaResourceParcel &resource = it->second;
- if (resource.type == type) {
+ if (hasResourceType(type, subType, resource)) {
if (resource.value > largestValue) {
largestValue = resource.value;
clientTemp = infos[i].client;
@@ -1052,8 +1094,8 @@
if (clientTemp == NULL) {
ALOGE_IF(!pendingRemovalOnly,
- "getBiggestClient_l: can't find resource type %s for pid %d",
- asString(type), pid);
+ "getBiggestClient_l: can't find resource type %s and subtype %s for pid %d",
+ asString(type), asString(subType), pid);
return false;
}
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index 9c2636e..6551371 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -77,26 +77,19 @@
int /*fd*/, const char** /*args*/, uint32_t /*numArgs*/);
ResourceManagerService();
- explicit ResourceManagerService(
- const sp<ProcessInfoInterface> &processInfo,
+ explicit ResourceManagerService(const sp<ProcessInfoInterface> &processInfo,
const sp<SystemCallbackInterface> &systemResource);
virtual ~ResourceManagerService();
- void setObserverService(
- const std::shared_ptr<ResourceObserverService>& observerService);
+ void setObserverService(const std::shared_ptr<ResourceObserverService>& observerService);
// IResourceManagerService interface
Status config(const std::vector<MediaResourcePolicyParcel>& policies) override;
- Status addResource(
- int32_t pid,
- int32_t uid,
- int64_t clientId,
+ Status addResource(int32_t pid, int32_t uid, int64_t clientId,
const std::shared_ptr<IResourceManagerClient>& client,
const std::vector<MediaResourceParcel>& resources) override;
- Status removeResource(
- int32_t pid,
- int64_t clientId,
+ Status removeResource(int32_t pid, int64_t clientId,
const std::vector<MediaResourceParcel>& resources) override;
Status removeClient(int32_t pid, int64_t clientId) override;
@@ -104,20 +97,13 @@
// Tries to reclaim resource from processes with lower priority than the calling process
// according to the requested resources.
// Returns true if any resource has been reclaimed, otherwise returns false.
- Status reclaimResource(
- int32_t callingPid,
- const std::vector<MediaResourceParcel>& resources,
+ Status reclaimResource(int32_t callingPid, const std::vector<MediaResourceParcel>& resources,
bool* _aidl_return) override;
- Status overridePid(
- int originalPid,
- int newPid) override;
+ Status overridePid(int originalPid, int newPid) override;
- Status overrideProcessInfo(
- const std::shared_ptr<IResourceManagerClient>& client,
- int pid,
- int procState,
- int oomScore) override;
+ Status overrideProcessInfo(const std::shared_ptr<IResourceManagerClient>& client, int pid,
+ int procState, int oomScore) override;
Status markClientForPendingRemoval(int32_t pid, int64_t clientId) override;
@@ -132,30 +118,34 @@
// Reclaims resources from |clients|. Returns true if reclaim succeeded
// for all clients.
- bool reclaimInternal(
- const Vector<std::shared_ptr<IResourceManagerClient>> &clients);
+ bool reclaimUnconditionallyFrom(const Vector<std::shared_ptr<IResourceManagerClient>> &clients);
// Gets the list of all the clients who own the specified resource type.
// 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,
+ bool getAllClients_l(int callingPid, MediaResource::Type type, MediaResource::SubType subType,
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,
- std::shared_ptr<IResourceManagerClient> *client);
+ MediaResource::SubType subType, 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.
- bool getLowestPriorityPid_l(MediaResource::Type type, int *pid, int *priority);
+ bool getLowestPriorityPid_l(MediaResource::Type type, MediaResource::SubType subType, int *pid,
+ int *priority);
// 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,
+ // Returns false with no change to client if there are no clients holdiing resources of thisi
+ // type.
+ bool getBiggestClient_l(int pid, MediaResource::Type type, MediaResource::SubType subType,
std::shared_ptr<IResourceManagerClient> *client,
bool pendingRemovalOnly = false);
+ // Same method as above, but with pendingRemovalOnly as true.
+ bool getBiggestClientPendingRemoval_l(int pid, MediaResource::Type type,
+ MediaResource::SubType subType, std::shared_ptr<IResourceManagerClient> *client);
bool isCallingPriorityHigher_l(int callingPid, int pid);
diff --git a/services/mediaresourcemanager/aidl/android/media/MediaResourceSubType.aidl b/services/mediaresourcemanager/aidl/android/media/MediaResourceSubType.aidl
index af2ba68..72a0551 100644
--- a/services/mediaresourcemanager/aidl/android/media/MediaResourceSubType.aidl
+++ b/services/mediaresourcemanager/aidl/android/media/MediaResourceSubType.aidl
@@ -26,4 +26,5 @@
kUnspecifiedSubType = 0,
kAudioCodec = 1,
kVideoCodec = 2,
+ kImageCodec = 3,
}
diff --git a/services/mediaresourcemanager/fuzzer/mediaresourcemanager_fuzzer.cpp b/services/mediaresourcemanager/fuzzer/mediaresourcemanager_fuzzer.cpp
index 6690b16..8f25ee6 100644
--- a/services/mediaresourcemanager/fuzzer/mediaresourcemanager_fuzzer.cpp
+++ b/services/mediaresourcemanager/fuzzer/mediaresourcemanager_fuzzer.cpp
@@ -71,7 +71,8 @@
return true;
}
- virtual bool isValidPid(int /* pid */) { return true; }
+ virtual bool isPidTrusted(int /* pid */) { return true; }
+ virtual bool isPidUidTrusted(int /* pid */, int /* uid */) { return true; }
virtual bool overrideProcessInfo(int /* pid */, int /*procState*/, int /*oomScore*/) {
return true;
}
diff --git a/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
index 8e29312..5bf44ce 100644
--- a/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
+++ b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
@@ -46,7 +46,11 @@
return true;
}
- virtual bool isValidPid(int /* pid */) {
+ virtual bool isPidTrusted(int /* pid */) {
+ return true;
+ }
+
+ virtual bool isPidUidTrusted(int /* pid */, int /* uid */) {
return true;
}
@@ -119,11 +123,11 @@
struct TestClient : public BnResourceManagerClient {
TestClient(int pid, const std::shared_ptr<ResourceManagerService> &service)
- : mReclaimed(false), mPid(pid), mService(service) {}
+ : mPid(pid), mService(service) {}
Status reclaimResource(bool* _aidl_return) override {
mService->removeClient(mPid, getId(ref<TestClient>()));
- mReclaimed = true;
+ mWasReclaimResourceCalled = true;
*_aidl_return = true;
return Status::ok();
}
@@ -133,18 +137,16 @@
return Status::ok();
}
- bool reclaimed() const {
- return mReclaimed;
- }
-
- void reset() {
- mReclaimed = false;
+ bool checkIfReclaimedAndReset() {
+ bool wasReclaimResourceCalled = mWasReclaimResourceCalled;
+ mWasReclaimResourceCalled = false;
+ return wasReclaimResourceCalled;
}
virtual ~TestClient() {}
private:
- bool mReclaimed;
+ bool mWasReclaimResourceCalled = false;
int mPid;
std::shared_ptr<ResourceManagerService> mService;
DISALLOW_EVIL_CONSTRUCTORS(TestClient);
@@ -166,14 +168,30 @@
return lhs.type == rhs.type && lhs.arg == rhs.arg;
}
-#define CHECK_STATUS_TRUE(condition) \
- EXPECT_TRUE((condition).isOk() && (result))
+// The condition is expected to return a status but also update the local
+// result variable.
+#define CHECK_STATUS_TRUE(conditionThatUpdatesResult) \
+ do { \
+ bool result = false; \
+ EXPECT_TRUE((conditionThatUpdatesResult).isOk()); \
+ EXPECT_TRUE(result); \
+ } while(false)
-#define CHECK_STATUS_FALSE(condition) \
- EXPECT_TRUE((condition).isOk() && !(result))
+// The condition is expected to return a status but also update the local
+// result variable.
+#define CHECK_STATUS_FALSE(conditionThatUpdatesResult) \
+ do { \
+ bool result = true; \
+ EXPECT_TRUE((conditionThatUpdatesResult).isOk()); \
+ EXPECT_FALSE(result); \
+ } while(false)
class ResourceManagerServiceTestBase : public ::testing::Test {
public:
+ static TestClient* toTestClient(std::shared_ptr<IResourceManagerClient> testClient) {
+ return static_cast<TestClient*>(testClient.get());
+ }
+
ResourceManagerServiceTestBase()
: mSystemCB(new TestSystemCallback()),
mService(::ndk::SharedRefBase::make<ResourceManagerService>(
@@ -183,6 +201,10 @@
mTestClient3(::ndk::SharedRefBase::make<TestClient>(kTestPid2, mService)) {
}
+ std::shared_ptr<IResourceManagerClient> createTestClient(int pid) {
+ return ::ndk::SharedRefBase::make<TestClient>(pid, mService);
+ }
+
sp<TestSystemCallback> mSystemCB;
std::shared_ptr<ResourceManagerService> mService;
std::shared_ptr<IResourceManagerClient> mTestClient1;
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index a029d45..8739c3b 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -25,22 +25,60 @@
namespace android {
class ResourceManagerServiceTest : public ResourceManagerServiceTestBase {
+private:
+ static MediaResource createSecureVideoCodecResource(int amount = 1) {
+ return MediaResource(MediaResource::Type::kSecureCodec,
+ MediaResource::SubType::kVideoCodec, amount);
+ }
+
+ static MediaResource createNonSecureVideoCodecResource(int amount = 1) {
+ return MediaResource(MediaResource::Type::kNonSecureCodec,
+ MediaResource::SubType::kVideoCodec, amount);
+ }
+
+ static MediaResource createSecureAudioCodecResource(int amount = 1) {
+ return MediaResource(MediaResource::Type::kSecureCodec,
+ MediaResource::SubType::kAudioCodec, amount);
+ }
+
+ static MediaResource createNonSecureAudioCodecResource(int amount = 1) {
+ return MediaResource(MediaResource::Type::kNonSecureCodec,
+ MediaResource::SubType::kAudioCodec, amount);
+ }
+
+ static MediaResource createSecureImageCodecResource(int amount = 1) {
+ return MediaResource(MediaResource::Type::kSecureCodec,
+ MediaResource::SubType::kImageCodec, amount);
+ }
+
+ static MediaResource createNonSecureImageCodecResource(int amount = 1) {
+ return MediaResource(MediaResource::Type::kNonSecureCodec,
+ MediaResource::SubType::kImageCodec, amount);
+ }
+
+ static MediaResource createGraphicMemoryResource(int amount = 1) {
+ return MediaResource(MediaResource::Type::kGraphicMemory,
+ MediaResource::SubType::kUnspecifiedSubType, amount);
+ }
+
+ static MediaResource createDrmSessionResource(int amount = 1) {
+ return MediaResource(MediaResource::Type::kDrmSession,
+ MediaResource::SubType::kUnspecifiedSubType, amount);
+ }
+
+ static MediaResource createBatteryResource() {
+ return MediaResource(MediaResource::Type::kBattery,
+ MediaResource::SubType::kUnspecifiedSubType, 1);
+ }
+
+ static MediaResource createCpuBoostResource() {
+ return MediaResource(MediaResource::Type::kCpuBoost,
+ MediaResource::SubType::kUnspecifiedSubType, 1);
+ }
+
public:
ResourceManagerServiceTest() : ResourceManagerServiceTestBase() {}
- void verifyClients(bool c1, bool c2, bool c3) {
- TestClient *client1 = static_cast<TestClient*>(mTestClient1.get());
- TestClient *client2 = static_cast<TestClient*>(mTestClient2.get());
- TestClient *client3 = static_cast<TestClient*>(mTestClient3.get());
-
- EXPECT_EQ(c1, client1->reclaimed());
- EXPECT_EQ(c2, client2->reclaimed());
- EXPECT_EQ(c3, client3->reclaimed());
-
- client1->reset();
- client2->reset();
- client3->reset();
- }
// test set up
// ---------------------------------------------------------------------------------
@@ -268,7 +306,6 @@
void testOverridePid() {
- bool result;
std::vector<MediaResourceParcel> resources;
resources.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
resources.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 150));
@@ -293,8 +330,6 @@
}
void testMarkClientForPendingRemoval() {
- bool result;
-
{
addResource();
mService->mSupportsSecureWithNonSecureCodec = true;
@@ -307,13 +342,17 @@
// no lower priority client
CHECK_STATUS_FALSE(mService->reclaimResource(kTestPid2, resources, &result));
- verifyClients(false /* c1 */, false /* c2 */, false /* c3 */);
+ EXPECT_EQ(false, toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_EQ(false, toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_EQ(false, toTestClient(mTestClient3)->checkIfReclaimedAndReset());
mService->markClientForPendingRemoval(kTestPid2, getId(mTestClient2));
// client marked for pending removal from the same process got reclaimed
CHECK_STATUS_TRUE(mService->reclaimResource(kTestPid2, resources, &result));
- verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+ EXPECT_EQ(false, toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_EQ(true, toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_EQ(false, toTestClient(mTestClient3)->checkIfReclaimedAndReset());
// clean up client 3 which still left
mService->removeClient(kTestPid2, getId(mTestClient3));
@@ -331,11 +370,15 @@
// client marked for pending removal from the same process got reclaimed
// first, even though there are lower priority process
CHECK_STATUS_TRUE(mService->reclaimResource(kTestPid2, resources, &result));
- verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+ EXPECT_EQ(false, toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_EQ(true, toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_EQ(false, toTestClient(mTestClient3)->checkIfReclaimedAndReset());
// lower priority client got reclaimed
CHECK_STATUS_TRUE(mService->reclaimResource(kTestPid2, resources, &result));
- verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
+ EXPECT_EQ(true, toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_EQ(false, toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_EQ(false, toTestClient(mTestClient3)->checkIfReclaimedAndReset());
// clean up client 3 which still left
mService->removeClient(kTestPid2, getId(mTestClient3));
@@ -349,17 +392,23 @@
// client marked for pending removal got reclaimed
EXPECT_TRUE(mService->reclaimResourcesFromClientsPendingRemoval(kTestPid2).isOk());
- verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+ EXPECT_EQ(false, toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_EQ(true, toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_EQ(false, toTestClient(mTestClient3)->checkIfReclaimedAndReset());
// No more clients marked for removal
EXPECT_TRUE(mService->reclaimResourcesFromClientsPendingRemoval(kTestPid2).isOk());
- verifyClients(false /* c1 */, false /* c2 */, false /* c3 */);
+ EXPECT_EQ(false, toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_EQ(false, toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_EQ(false, toTestClient(mTestClient3)->checkIfReclaimedAndReset());
mService->markClientForPendingRemoval(kTestPid2, getId(mTestClient3));
// client marked for pending removal got reclaimed
EXPECT_TRUE(mService->reclaimResourcesFromClientsPendingRemoval(kTestPid2).isOk());
- verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
+ EXPECT_EQ(false, toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_EQ(false, toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_EQ(true, toTestClient(mTestClient3)->checkIfReclaimedAndReset());
// clean up client 1 which still left
mService->removeClient(kTestPid1, getId(mTestClient1));
@@ -384,14 +433,15 @@
void testGetAllClients() {
addResource();
-
MediaResource::Type type = MediaResource::Type::kSecureCodec;
+ MediaResource::SubType subType = MediaResource::SubType::kUnspecifiedSubType;
+
Vector<std::shared_ptr<IResourceManagerClient> > clients;
- EXPECT_FALSE(mService->getAllClients_l(kLowPriorityPid, type, &clients));
+ EXPECT_FALSE(mService->getAllClients_l(kLowPriorityPid, type, subType, &clients));
// some higher priority process (e.g. kTestPid2) owns the resource, so getAllClients_l
// will fail.
- EXPECT_FALSE(mService->getAllClients_l(kMidPriorityPid, type, &clients));
- EXPECT_TRUE(mService->getAllClients_l(kHighPriorityPid, type, &clients));
+ EXPECT_FALSE(mService->getAllClients_l(kMidPriorityPid, type, subType, &clients));
+ EXPECT_TRUE(mService->getAllClients_l(kHighPriorityPid, type, subType, &clients));
EXPECT_EQ(2u, clients.size());
// (OK to require ordering in clients[], as the pid map is sorted)
@@ -400,7 +450,6 @@
}
void testReclaimResourceSecure() {
- bool result;
std::vector<MediaResourceParcel> resources;
resources.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
resources.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 150));
@@ -417,11 +466,15 @@
// reclaim all secure codecs
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
- verifyClients(true /* c1 */, false /* c2 */, true /* c3 */);
+ EXPECT_TRUE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_TRUE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
// call again should reclaim one largest graphic memory from lowest process
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
- verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+ EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
// nothing left
CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
@@ -439,7 +492,9 @@
// reclaim all secure and non-secure codecs
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
- verifyClients(true /* c1 */, true /* c2 */, true /* c3 */);
+ EXPECT_TRUE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_TRUE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
// nothing left
CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
@@ -458,15 +513,21 @@
// reclaim all non-secure codecs
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
- verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+ EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
// call again should reclaim one largest graphic memory from lowest process
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
- verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
+ EXPECT_TRUE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
// call again should reclaim another largest graphic memory from lowest process
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
- verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
+ EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_TRUE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
// nothing left
CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
@@ -483,15 +544,21 @@
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
// one largest graphic memory from lowest process got reclaimed
- verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
+ EXPECT_TRUE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
// call again should reclaim another graphic memory from lowest process
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
- verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+ EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
// call again should reclaim another graphic memory from lowest process
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
- verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
+ EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_TRUE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
// nothing left
CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
@@ -508,20 +575,25 @@
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
// secure codec from lowest process got reclaimed
- verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
+ EXPECT_TRUE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
// call again should reclaim another secure codec from lowest process
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
- verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
+ EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_TRUE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
// no more secure codec, non-secure codec will be reclaimed.
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
- verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+ EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
}
}
void testReclaimResourceNonSecure() {
- bool result;
std::vector<MediaResourceParcel> resources;
resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
resources.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 150));
@@ -537,11 +609,15 @@
// reclaim all secure codecs
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
- verifyClients(true /* c1 */, false /* c2 */, true /* c3 */);
+ EXPECT_TRUE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_TRUE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
// call again should reclaim one graphic memory from lowest process
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
- verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+ EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
// nothing left
CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
@@ -558,15 +634,21 @@
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
// one largest graphic memory from lowest process got reclaimed
- verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
+ EXPECT_TRUE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
// call again should reclaim another graphic memory from lowest process
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
- verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+ EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
// call again should reclaim another graphic memory from lowest process
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
- verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
+ EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_TRUE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
// nothing left
CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
@@ -582,11 +664,15 @@
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
// one non secure codec from lowest process got reclaimed
- verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+ EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
// no more non-secure codec, secure codec from lowest priority process will be reclaimed
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
- verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
+ EXPECT_TRUE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
// clean up client 3 which still left
mService->removeClient(kTestPid2, getId(mTestClient3));
@@ -595,13 +681,17 @@
void testGetLowestPriorityBiggestClient() {
MediaResource::Type type = MediaResource::Type::kGraphicMemory;
+ MediaResource::SubType subType = MediaResource::SubType::kUnspecifiedSubType;
std::shared_ptr<IResourceManagerClient> client;
- EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(kHighPriorityPid, type, &client));
+ EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(kHighPriorityPid, type, subType,
+ &client));
addResource();
- EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(kLowPriorityPid, type, &client));
- EXPECT_TRUE(mService->getLowestPriorityBiggestClient_l(kHighPriorityPid, type, &client));
+ EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(kLowPriorityPid, type, subType,
+ &client));
+ EXPECT_TRUE(mService->getLowestPriorityBiggestClient_l(kHighPriorityPid, type, subType,
+ &client));
// kTestPid1 is the lowest priority process with MediaResource::Type::kGraphicMemory.
// mTestClient1 has the largest MediaResource::Type::kGraphicMemory within kTestPid1.
@@ -614,35 +704,25 @@
TestProcessInfo processInfo;
MediaResource::Type type = MediaResource::Type::kGraphicMemory;
- EXPECT_FALSE(mService->getLowestPriorityPid_l(type, &pid, &priority));
+ MediaResource::SubType subType = MediaResource::SubType::kUnspecifiedSubType;
+ EXPECT_FALSE(mService->getLowestPriorityPid_l(type, subType, &pid, &priority));
addResource();
- EXPECT_TRUE(mService->getLowestPriorityPid_l(type, &pid, &priority));
+ EXPECT_TRUE(mService->getLowestPriorityPid_l(type, subType, &pid, &priority));
EXPECT_EQ(kTestPid1, pid);
int priority1;
processInfo.getPriority(kTestPid1, &priority1);
EXPECT_EQ(priority1, priority);
type = MediaResource::Type::kNonSecureCodec;
- EXPECT_TRUE(mService->getLowestPriorityPid_l(type, &pid, &priority));
+ EXPECT_TRUE(mService->getLowestPriorityPid_l(type, subType, &pid, &priority));
EXPECT_EQ(kTestPid2, pid);
int priority2;
processInfo.getPriority(kTestPid2, &priority2);
EXPECT_EQ(priority2, priority);
}
- void testGetBiggestClient() {
- MediaResource::Type type = MediaResource::Type::kGraphicMemory;
- std::shared_ptr<IResourceManagerClient> client;
- EXPECT_FALSE(mService->getBiggestClient_l(kTestPid2, type, &client));
-
- addResource();
-
- EXPECT_TRUE(mService->getBiggestClient_l(kTestPid2, type, &client));
- EXPECT_EQ(mTestClient2, client);
- }
-
void testIsCallingPriorityHigher() {
EXPECT_FALSE(mService->isCallingPriorityHigher_l(101, 100));
EXPECT_FALSE(mService->isCallingPriorityHigher_l(100, 100));
@@ -725,6 +805,361 @@
EXPECT_EQ(4u, mSystemCB->eventCount());
EXPECT_EQ(EventType::CPUSET_DISABLE, mSystemCB->lastEventType());
}
+
+ void testReclaimResources_withVideoCodec_reclaimsOnlyVideoCodec() {
+ const std::shared_ptr<IResourceManagerClient>& audioImageTestClient = mTestClient1;
+ const std::shared_ptr<IResourceManagerClient>& videoTestClient = mTestClient2;
+
+ // Create an audio and image codec resource
+ std::vector<MediaResourceParcel> audioImageResources;
+ audioImageResources.push_back(createNonSecureAudioCodecResource());
+ audioImageResources.push_back(createNonSecureImageCodecResource());
+ mService->addResource(kLowPriorityPid, kTestUid1, getId(audioImageTestClient),
+ audioImageTestClient, audioImageResources);
+
+ // Fail to reclaim a video codec resource
+ std::vector<MediaResourceParcel> reclaimResources;
+ reclaimResources.push_back(createNonSecureVideoCodecResource());
+ CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, reclaimResources, &result));
+
+ // Now add a video codec resource
+ std::vector<MediaResourceParcel> videoResources;
+ videoResources.push_back(createNonSecureVideoCodecResource());
+ mService->addResource(kLowPriorityPid, kTestUid1, getId(videoTestClient), videoTestClient,
+ videoResources);
+
+ // Verify that the newly-created video codec resource can be reclaimed
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, reclaimResources, &result));
+
+ // Verify that the audio and image resources are untouched
+ EXPECT_FALSE(toTestClient(audioImageTestClient)->checkIfReclaimedAndReset());
+ // But the video resource was reclaimed
+ EXPECT_TRUE(toTestClient(videoTestClient)->checkIfReclaimedAndReset());
+ }
+
+ void testReclaimResources_withAudioCodec_reclaimsOnlyAudioCodec() {
+ const auto & videoImageTestClient = mTestClient1;
+ const auto & audioTestClient = mTestClient2;
+
+ // Create a video and audio codec resource
+ std::vector<MediaResourceParcel> videoImageResources;
+ videoImageResources.push_back(createNonSecureVideoCodecResource());
+ videoImageResources.push_back(createNonSecureImageCodecResource());
+ mService->addResource(kLowPriorityPid, kTestUid1, getId(videoImageTestClient),
+ videoImageTestClient, videoImageResources);
+
+ // Fail to reclaim an audio codec resource
+ std::vector<MediaResourceParcel> reclaimResources;
+ reclaimResources.push_back(createNonSecureAudioCodecResource());
+ CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, reclaimResources, &result));
+
+ // Now add an audio codec resource
+ std::vector<MediaResourceParcel> audioResources;
+ audioResources.push_back(createNonSecureAudioCodecResource());
+ mService->addResource(kLowPriorityPid, kTestUid2, getId(audioTestClient), audioTestClient,
+ audioResources);
+
+ // Verify that the newly-created audio codec resource can be reclaimed
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, reclaimResources, &result));
+
+ // Verify that the video and image resources are untouched
+ EXPECT_FALSE(toTestClient(videoImageTestClient)->checkIfReclaimedAndReset());
+ // But the audio resource was reclaimed
+ EXPECT_TRUE(toTestClient(audioTestClient)->checkIfReclaimedAndReset());
+ }
+
+ void testReclaimResources_withImageCodec_reclaimsOnlyImageCodec() {
+ const auto & videoAudioTestClient = mTestClient1;
+ const auto & imageTestClient = mTestClient2;
+
+ // Create a video and audio codec resource
+ std::vector<MediaResourceParcel> videoAudioResources;
+ videoAudioResources.push_back(createNonSecureVideoCodecResource());
+ videoAudioResources.push_back(createNonSecureAudioCodecResource());
+ mService->addResource(kLowPriorityPid, kTestUid1, getId(videoAudioTestClient),
+ videoAudioTestClient, videoAudioResources);
+
+ // Fail to reclaim an image codec resource
+ std::vector<MediaResourceParcel> reclaimResources;
+ reclaimResources.push_back(createNonSecureImageCodecResource());
+ CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, reclaimResources, &result));
+
+ // Now add an image codec resource
+ std::vector<MediaResourceParcel> imageResources;
+ imageResources.push_back(createNonSecureImageCodecResource());
+ mService->addResource(kLowPriorityPid, kTestUid2, getId(imageTestClient), imageTestClient,
+ imageResources);
+
+ // Verify that the newly-created image codec resource can be reclaimed
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, reclaimResources, &result));
+
+ // Verify that the video and audio resources are untouched
+ EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ // But the image resource was reclaimed
+ EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ }
+
+ void testReclaimResources_whenPartialResourceMatch_reclaims() {
+ const int onlyUid = kTestUid1;
+ const auto onlyClient = createTestClient(kLowPriorityPid);
+
+ std::vector<MediaResourceParcel> ownedResources;
+ ownedResources.push_back(createNonSecureVideoCodecResource());
+ ownedResources.push_back(createGraphicMemoryResource(100));
+ mService->addResource(kLowPriorityPid, onlyUid, getId(onlyClient), onlyClient,
+ ownedResources);
+
+ // Reclaim an image codec instead of the video codec that is owned, but also reclaim
+ // graphics memory, which will trigger the reclaim.
+ std::vector<MediaResourceParcel> reclaimResources;
+ reclaimResources.push_back(createNonSecureImageCodecResource());
+ reclaimResources.push_back(createGraphicMemoryResource(100));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, reclaimResources, &result));
+
+ // Verify that the video codec resources (including the needed graphic memory) is reclaimed
+ EXPECT_TRUE(toTestClient(onlyClient)->checkIfReclaimedAndReset());
+ }
+
+ void testReclaimResourcesFromMarkedClients_removesBiggestMarkedClientForSomeResources() {
+ // this test only uses one pid and one uid
+ const int onlyPid = kTestPid1;
+ const int onlyUid = kTestUid1;
+
+ // secure video codec
+ const auto smallSecureVideoMarkedClient = createTestClient(onlyPid);
+ const auto largeSecureVideoMarkedClient = createTestClient(onlyPid);
+ const auto largestSecureVideoActiveClient = createTestClient(onlyPid);
+ {
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(createSecureVideoCodecResource(1));
+ mService->addResource(onlyPid, onlyUid, getId(smallSecureVideoMarkedClient),
+ smallSecureVideoMarkedClient, resources);
+ resources.clear();
+ resources.push_back(createSecureVideoCodecResource(2));
+ mService->addResource(onlyPid, onlyUid, getId(largeSecureVideoMarkedClient),
+ largeSecureVideoMarkedClient, resources);
+ resources.clear();
+ resources.push_back(createSecureVideoCodecResource(3));
+ mService->addResource(onlyPid, onlyUid, getId(largestSecureVideoActiveClient),
+ largestSecureVideoActiveClient, resources);
+ }
+ mService->markClientForPendingRemoval(onlyPid, getId(smallSecureVideoMarkedClient));
+ mService->markClientForPendingRemoval(onlyPid, getId(largeSecureVideoMarkedClient));
+ // don't mark the largest client
+
+ // non-secure video codec
+ const auto smallNonSecureVideoMarkedClient = createTestClient(onlyPid);
+ const auto largeNonSecureVideoMarkedClient = createTestClient(onlyPid);
+ const auto largestNonSecureVideoActiveClient = createTestClient(onlyPid);
+ {
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(createNonSecureVideoCodecResource(1));
+ mService->addResource(onlyPid, onlyUid, getId(smallNonSecureVideoMarkedClient),
+ smallNonSecureVideoMarkedClient, resources);
+ resources.clear();
+ resources.push_back(createNonSecureVideoCodecResource(2));
+ mService->addResource(onlyPid, onlyUid, getId(largeNonSecureVideoMarkedClient),
+ largeNonSecureVideoMarkedClient, resources);
+ resources.clear();
+ resources.push_back(createNonSecureVideoCodecResource(3));
+ mService->addResource(onlyPid, onlyUid, getId(largestNonSecureVideoActiveClient),
+ largestNonSecureVideoActiveClient, resources);
+ }
+ mService->markClientForPendingRemoval(onlyPid, getId(smallNonSecureVideoMarkedClient));
+ mService->markClientForPendingRemoval(onlyPid, getId(largeNonSecureVideoMarkedClient));
+ // don't mark the largest client
+
+ // secure audio codec
+ const auto smallSecureAudioMarkedClient = createTestClient(onlyPid);
+ const auto largeSecureAudioMarkedClient = createTestClient(onlyPid);
+ const auto largestSecureAudioActiveClient = createTestClient(onlyPid);
+ {
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(createSecureAudioCodecResource(1));
+ mService->addResource(onlyPid, onlyUid, getId(smallSecureAudioMarkedClient),
+ smallSecureAudioMarkedClient, resources);
+ resources.clear();
+ resources.push_back(createSecureAudioCodecResource(2));
+ mService->addResource(onlyPid, onlyUid, getId(largeSecureAudioMarkedClient),
+ largeSecureAudioMarkedClient, resources);
+ resources.clear();
+ resources.push_back(createSecureAudioCodecResource(3));
+ mService->addResource(onlyPid, onlyUid, getId(largestSecureVideoActiveClient),
+ largestSecureVideoActiveClient, resources);
+ }
+ mService->markClientForPendingRemoval(onlyPid, getId(smallSecureAudioMarkedClient));
+ mService->markClientForPendingRemoval(onlyPid, getId(largeSecureAudioMarkedClient));
+ // don't mark the largest client
+
+ // non-secure audio codec
+ const auto smallNonSecureAudioMarkedClient = createTestClient(onlyPid);
+ const auto largeNonSecureAudioMarkedClient = createTestClient(onlyPid);
+ const auto largestNonSecureAudioActiveClient = createTestClient(onlyPid);
+ {
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(createNonSecureAudioCodecResource(1));
+ mService->addResource(onlyPid, onlyUid, getId(smallNonSecureAudioMarkedClient),
+ smallNonSecureAudioMarkedClient, resources);
+ resources.clear();
+ resources.push_back(createNonSecureAudioCodecResource(2));
+ mService->addResource(onlyPid, onlyUid, getId(largeNonSecureAudioMarkedClient),
+ largeNonSecureAudioMarkedClient, resources);
+ resources.clear();
+ resources.push_back(createNonSecureAudioCodecResource(3));
+ mService->addResource(onlyPid, onlyUid, getId(largestNonSecureAudioActiveClient),
+ largestNonSecureAudioActiveClient, resources);
+ }
+ mService->markClientForPendingRemoval(onlyPid, getId(smallNonSecureAudioMarkedClient));
+ mService->markClientForPendingRemoval(onlyPid, getId(largeNonSecureAudioMarkedClient));
+ // don't mark the largest client
+
+ // secure image codec
+ const auto smallSecureImageMarkedClient = createTestClient(onlyPid);
+ const auto largeSecureImageMarkedClient = createTestClient(onlyPid);
+ const auto largestSecureImageActiveClient = createTestClient(onlyPid);
+ {
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(createSecureImageCodecResource(1));
+ mService->addResource(onlyPid, onlyUid, getId(smallSecureImageMarkedClient),
+ smallSecureImageMarkedClient, resources);
+ resources.clear();
+ resources.push_back(createSecureImageCodecResource(2));
+ mService->addResource(onlyPid, onlyUid, getId(largeSecureImageMarkedClient),
+ largeSecureImageMarkedClient, resources);
+ resources.clear();
+ resources.push_back(createSecureImageCodecResource(3));
+ mService->addResource(onlyPid, onlyUid, getId(largestSecureImageActiveClient),
+ largestSecureImageActiveClient, resources);
+ }
+ mService->markClientForPendingRemoval(onlyPid, getId(smallSecureImageMarkedClient));
+ mService->markClientForPendingRemoval(onlyPid, getId(largeSecureImageMarkedClient));
+ // don't mark the largest client
+
+ // non-secure image codec
+ const auto smallNonSecureImageMarkedClient = createTestClient(onlyPid);
+ const auto largeNonSecureImageMarkedClient = createTestClient(onlyPid);
+ const auto largestNonSecureImageActiveClient = createTestClient(onlyPid);
+ {
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(createNonSecureImageCodecResource(1));
+ mService->addResource(onlyPid, onlyUid, getId(smallNonSecureImageMarkedClient),
+ smallNonSecureImageMarkedClient, resources);
+ resources.clear();
+ resources.push_back(createNonSecureImageCodecResource(2));
+ mService->addResource(onlyPid, onlyUid, getId(largeNonSecureImageMarkedClient),
+ largeNonSecureImageMarkedClient, resources);
+ resources.clear();
+ resources.push_back(createNonSecureImageCodecResource(3));
+ mService->addResource(onlyPid, onlyUid, getId(largestNonSecureImageActiveClient),
+ largestNonSecureImageActiveClient, resources);
+ }
+ mService->markClientForPendingRemoval(onlyPid, getId(smallNonSecureImageMarkedClient));
+ mService->markClientForPendingRemoval(onlyPid, getId(largeNonSecureImageMarkedClient));
+ // don't mark the largest client
+
+ // graphic memory
+ const auto smallGraphicMemoryMarkedClient = createTestClient(onlyPid);
+ const auto largeGraphicMemoryMarkedClient = createTestClient(onlyPid);
+ const auto largestGraphicMemoryActiveClient = createTestClient(onlyPid);
+ {
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(createGraphicMemoryResource(100));
+ mService->addResource(onlyPid, onlyUid, getId(smallGraphicMemoryMarkedClient),
+ smallGraphicMemoryMarkedClient, resources);
+ resources.clear();
+ resources.push_back(createGraphicMemoryResource(200));
+ mService->addResource(onlyPid, onlyUid, getId(largeGraphicMemoryMarkedClient),
+ largeGraphicMemoryMarkedClient, resources);
+ resources.clear();
+ resources.push_back(createGraphicMemoryResource(300));
+ mService->addResource(onlyPid, onlyUid, getId(largestGraphicMemoryActiveClient),
+ largestGraphicMemoryActiveClient, resources);
+ }
+ mService->markClientForPendingRemoval(onlyPid, getId(smallGraphicMemoryMarkedClient));
+ mService->markClientForPendingRemoval(onlyPid, getId(largeGraphicMemoryMarkedClient));
+ // don't mark the largest client
+
+ // DRM session
+ const auto smallDrmSessionMarkedClient = createTestClient(onlyPid);
+ const auto largeDrmSessionMarkedClient = createTestClient(onlyPid);
+ const auto largestDrmSessionActiveClient = createTestClient(onlyPid);
+ {
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(createDrmSessionResource(1));
+ mService->addResource(onlyPid, onlyUid, getId(smallDrmSessionMarkedClient),
+ smallDrmSessionMarkedClient, resources);
+ resources.clear();
+ resources.push_back(createDrmSessionResource(2));
+ mService->addResource(onlyPid, onlyUid, getId(largeDrmSessionMarkedClient),
+ largeDrmSessionMarkedClient, resources);
+ resources.clear();
+ resources.push_back(createDrmSessionResource(3));
+ mService->addResource(onlyPid, onlyUid, getId(largestDrmSessionActiveClient),
+ largestDrmSessionActiveClient, resources);
+ }
+ mService->markClientForPendingRemoval(onlyPid, getId(smallDrmSessionMarkedClient));
+ mService->markClientForPendingRemoval(onlyPid, getId(largeDrmSessionMarkedClient));
+ // don't mark the largest client
+
+ // battery
+ const auto batteryMarkedClient = createTestClient(onlyPid);
+ {
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(createBatteryResource());
+ mService->addResource(onlyPid, onlyUid, getId(batteryMarkedClient),
+ batteryMarkedClient, resources);
+ }
+ mService->markClientForPendingRemoval(onlyPid, getId(batteryMarkedClient));
+
+ // CPU boost
+ const auto cpuBoostMarkedClient = createTestClient(onlyPid);
+ {
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(createCpuBoostResource());
+ mService->addResource(onlyPid, onlyUid, getId(cpuBoostMarkedClient),
+ cpuBoostMarkedClient, resources);
+ }
+ mService->markClientForPendingRemoval(onlyPid, getId(cpuBoostMarkedClient));
+
+ // now we expect that we only reclaim resources from the biggest marked client
+ EXPECT_TRUE(mService->reclaimResourcesFromClientsPendingRemoval(onlyPid).isOk());
+ // secure video codec
+ EXPECT_FALSE(toTestClient(smallSecureVideoMarkedClient)->checkIfReclaimedAndReset());
+ EXPECT_TRUE(toTestClient(largeSecureVideoMarkedClient)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(largestSecureVideoActiveClient)->checkIfReclaimedAndReset());
+ // non-secure video codec
+ EXPECT_FALSE(toTestClient(smallNonSecureVideoMarkedClient)->checkIfReclaimedAndReset());
+ EXPECT_TRUE(toTestClient(largeNonSecureVideoMarkedClient)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(largestNonSecureVideoActiveClient)->checkIfReclaimedAndReset());
+ // secure audio codec
+ EXPECT_FALSE(toTestClient(smallSecureAudioMarkedClient)->checkIfReclaimedAndReset());
+ EXPECT_TRUE(toTestClient(largeSecureAudioMarkedClient)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(largestSecureAudioActiveClient)->checkIfReclaimedAndReset());
+ // non-secure audio codec
+ EXPECT_FALSE(toTestClient(smallNonSecureAudioMarkedClient)->checkIfReclaimedAndReset());
+ EXPECT_TRUE(toTestClient(largeNonSecureAudioMarkedClient)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(largestNonSecureAudioActiveClient)->checkIfReclaimedAndReset());
+ // secure image codec
+ EXPECT_FALSE(toTestClient(smallSecureImageMarkedClient)->checkIfReclaimedAndReset());
+ EXPECT_TRUE(toTestClient(largeSecureImageMarkedClient)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(largestSecureImageActiveClient)->checkIfReclaimedAndReset());
+ // non-secure image codec
+ EXPECT_FALSE(toTestClient(smallNonSecureImageMarkedClient)->checkIfReclaimedAndReset());
+ EXPECT_TRUE(toTestClient(largeNonSecureImageMarkedClient)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(largestNonSecureImageActiveClient)->checkIfReclaimedAndReset());
+ // graphic memory
+ EXPECT_FALSE(toTestClient(smallGraphicMemoryMarkedClient)->checkIfReclaimedAndReset());
+ EXPECT_TRUE(toTestClient(largeGraphicMemoryMarkedClient)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(largestGraphicMemoryActiveClient)->checkIfReclaimedAndReset());
+ // DRM session
+ EXPECT_FALSE(toTestClient(smallDrmSessionMarkedClient)->checkIfReclaimedAndReset());
+ EXPECT_TRUE(toTestClient(largeDrmSessionMarkedClient)->checkIfReclaimedAndReset());
+ EXPECT_FALSE(toTestClient(largestDrmSessionActiveClient)->checkIfReclaimedAndReset());
+ // battery is not expected to be reclaimed when marked as pending removal
+ EXPECT_FALSE(toTestClient(batteryMarkedClient)->checkIfReclaimedAndReset());
+ // CPU boost is not expected to be reclaimed when marked as pending removal
+ EXPECT_FALSE(toTestClient(cpuBoostMarkedClient)->checkIfReclaimedAndReset());
+ }
};
TEST_F(ResourceManagerServiceTest, config) {
@@ -768,19 +1203,15 @@
testGetLowestPriorityPid();
}
-TEST_F(ResourceManagerServiceTest, getBiggestClient_l) {
- testGetBiggestClient();
-}
-
TEST_F(ResourceManagerServiceTest, isCallingPriorityHigher_l) {
testIsCallingPriorityHigher();
}
-TEST_F(ResourceManagerServiceTest, testBatteryStats) {
+TEST_F(ResourceManagerServiceTest, batteryStats) {
testBatteryStats();
}
-TEST_F(ResourceManagerServiceTest, testCpusetBoost) {
+TEST_F(ResourceManagerServiceTest, cpusetBoost) {
testCpusetBoost();
}
@@ -792,4 +1223,25 @@
testMarkClientForPendingRemoval();
}
+TEST_F(ResourceManagerServiceTest, reclaimResources_withVideoCodec_reclaimsOnlyVideoCodec) {
+ testReclaimResources_withVideoCodec_reclaimsOnlyVideoCodec();
+}
+
+TEST_F(ResourceManagerServiceTest, reclaimResources_withAudioCodec_reclaimsOnlyAudioCodec) {
+ testReclaimResources_withAudioCodec_reclaimsOnlyAudioCodec();
+}
+
+TEST_F(ResourceManagerServiceTest, reclaimResources_withImageCodec_reclaimsOnlyImageCodec) {
+ testReclaimResources_withImageCodec_reclaimsOnlyImageCodec();
+}
+
+TEST_F(ResourceManagerServiceTest, reclaimResources_whenPartialResourceMatch_reclaims) {
+ testReclaimResources_whenPartialResourceMatch_reclaims();
+}
+
+TEST_F(ResourceManagerServiceTest,
+ reclaimResourcesFromMarkedClients_removesBiggestMarkedClientForSomeResources) {
+ testReclaimResourcesFromMarkedClients_removesBiggestMarkedClientForSomeResources();
+}
+
} // namespace android
diff --git a/services/mediaresourcemanager/test/ResourceObserverService_test.cpp b/services/mediaresourcemanager/test/ResourceObserverService_test.cpp
index acd9df1..003569d 100644
--- a/services/mediaresourcemanager/test/ResourceObserverService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceObserverService_test.cpp
@@ -116,6 +116,26 @@
const EventTracker::Event EventTracker::NoEvent;
+static MediaResource createSecureVideoCodecResource(int amount = 1) {
+ return MediaResource(MediaResource::Type::kSecureCodec,
+ MediaResource::SubType::kVideoCodec, amount);
+}
+
+static MediaResource createNonSecureVideoCodecResource(int amount = 1) {
+ return MediaResource(MediaResource::Type::kNonSecureCodec,
+ MediaResource::SubType::kVideoCodec, amount);
+}
+
+static MediaResource createSecureAudioCodecResource(int amount = 1) {
+ return MediaResource(MediaResource::Type::kSecureCodec,
+ MediaResource::SubType::kAudioCodec, amount);
+}
+
+static MediaResource createNonSecureAudioCodecResource(int amount = 1) {
+ return MediaResource(MediaResource::Type::kNonSecureCodec,
+ MediaResource::SubType::kAudioCodec, amount);
+}
+
// Operators for GTest macros.
bool operator==(const EventTracker::Event& lhs, const EventTracker::Event& rhs) {
return lhs.type == rhs.type && lhs.uid == rhs.uid && lhs.pid == rhs.pid &&
@@ -233,30 +253,30 @@
std::vector<MediaResourceParcel> resources;
// Add secure video codec.
- resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/)};
+ resources = {createSecureVideoCodecResource()};
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources);
EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid1, kTestPid1, observables1));
EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid1, kTestPid1, observables1));
// Add non-secure video codec.
- resources = {MediaResource::CodecResource(0 /*secure*/, 1 /*video*/)};
+ resources = {createNonSecureVideoCodecResource()};
mService->addResource(kTestPid2, kTestUid2, getId(mTestClient2), mTestClient2, resources);
EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
EXPECT_EQ(mTestObserver2->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
// Add secure & non-secure video codecs.
- resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
- MediaResource::CodecResource(0 /*secure*/, 1 /*video*/)};
+ resources = {createSecureVideoCodecResource(),
+ createNonSecureVideoCodecResource()};
mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources);
EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables1));
EXPECT_EQ(mTestObserver2->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables3));
// Add additional audio codecs, should be ignored.
- resources.push_back(MediaResource::CodecResource(1 /*secure*/, 0 /*video*/));
- resources.push_back(MediaResource::CodecResource(0 /*secure*/, 0 /*video*/));
+ resources.push_back(createSecureAudioCodecResource());
+ resources.push_back(createNonSecureAudioCodecResource());
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources);
EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid1, kTestPid1, observables1));
EXPECT_EQ(mTestObserver2->pop(), EventTracker::Busy(kTestUid1, kTestPid1, observables2));
@@ -276,9 +296,9 @@
// Add multiple secure & non-secure video codecs.
// Multiple entries of the same type should be merged, count should be propagated correctly.
- resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
- MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
- MediaResource::CodecResource(0 /*secure*/, 1 /*video*/, 3 /*count*/)};
+ resources = {createSecureVideoCodecResource(),
+ createSecureVideoCodecResource(),
+ createNonSecureVideoCodecResource(3)};
observables1 = {{MediaObservableType::kVideoSecureCodec, 2}};
observables2 = {{MediaObservableType::kVideoNonSecureCodec, 3}};
observables3 = {{MediaObservableType::kVideoSecureCodec, 2},
@@ -300,7 +320,7 @@
std::vector<MediaResourceParcel> resources;
// Add secure video codec to client1.
- resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/)};
+ resources = {createSecureVideoCodecResource()};
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources);
EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid1, kTestPid1, observables1));
EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
@@ -322,7 +342,7 @@
EXPECT_EQ(mTestObserver3->pop(), EventTracker::NoEvent);
// Add non-secure video codec to client2.
- resources = {MediaResource::CodecResource(0 /*secure*/, 1 /*video*/)};
+ resources = {createNonSecureVideoCodecResource()};
mService->addResource(kTestPid2, kTestUid2, getId(mTestClient2), mTestClient2, resources);
EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
EXPECT_EQ(mTestObserver2->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
@@ -344,24 +364,24 @@
EXPECT_EQ(mTestObserver3->pop(), EventTracker::NoEvent);
// Add secure & non-secure video codecs, plus audio codecs (that's ignored).
- resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
- MediaResource::CodecResource(0 /*secure*/, 1 /*video*/),
- MediaResource::CodecResource(1 /*secure*/, 0 /*video*/),
- MediaResource::CodecResource(0 /*secure*/, 0 /*video*/)};
+ resources = {createSecureVideoCodecResource(),
+ createNonSecureVideoCodecResource(),
+ createSecureAudioCodecResource(),
+ createNonSecureAudioCodecResource()};
mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources);
EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables1));
EXPECT_EQ(mTestObserver2->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables3));
// Remove one audio codec, should have no event.
- resources = {MediaResource::CodecResource(1 /*secure*/, 0 /*video*/)};
+ resources = {createSecureAudioCodecResource()};
mService->removeResource(kTestPid2, getId(mTestClient3), resources);
EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
EXPECT_EQ(mTestObserver3->pop(), EventTracker::NoEvent);
// Remove the other audio codec and the secure video codec, only secure video codec
// removal should be reported.
- resources = {MediaResource::CodecResource(0 /*secure*/, 0 /*video*/),
- MediaResource::CodecResource(1 /*secure*/, 1 /*video*/)};
+ resources = {createNonSecureAudioCodecResource(),
+ createSecureVideoCodecResource()};
mService->removeResource(kTestPid2, getId(mTestClient3), resources);
EXPECT_EQ(mTestObserver1->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables1));
EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
@@ -386,10 +406,10 @@
// Add multiple secure & non-secure video codecs, plus audio codecs (that's ignored).
// (ResourceManager will merge these internally.)
- resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
- MediaResource::CodecResource(0 /*secure*/, 1 /*video*/, 4 /*count*/),
- MediaResource::CodecResource(1 /*secure*/, 0 /*video*/),
- MediaResource::CodecResource(0 /*secure*/, 0 /*video*/)};
+ resources = {createSecureVideoCodecResource(),
+ createNonSecureVideoCodecResource(4),
+ createSecureAudioCodecResource(),
+ createNonSecureAudioCodecResource()};
mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources);
observables1 = {{MediaObservableType::kVideoSecureCodec, 1}};
observables2 = {{MediaObservableType::kVideoNonSecureCodec, 4}};
@@ -400,10 +420,10 @@
EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables3));
// Remove one audio codec, 2 secure video codecs and 2 non-secure video codecs.
// 1 secure video codec removal and 2 non-secure video codec removals should be reported.
- resources = {MediaResource::CodecResource(0 /*secure*/, 0 /*video*/),
- MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
- MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
- MediaResource::CodecResource(0 /*secure*/, 1 /*video*/, 2 /*count*/)};
+ resources = {createNonSecureAudioCodecResource(),
+ createSecureVideoCodecResource(),
+ createSecureVideoCodecResource(),
+ createNonSecureVideoCodecResource(2)};
mService->removeResource(kTestPid2, getId(mTestClient3), resources);
observables1 = {{MediaObservableType::kVideoSecureCodec, 1}};
observables2 = {{MediaObservableType::kVideoNonSecureCodec, 2}};
@@ -443,8 +463,8 @@
std::vector<MediaResourceParcel> resources;
// Add secure & non-secure video codecs.
- resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
- MediaResource::CodecResource(0 /*secure*/, 1 /*video*/)};
+ resources = {createSecureVideoCodecResource(),
+ createNonSecureVideoCodecResource()};
mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources);
EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables1));
EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
diff --git a/services/minijail/Android.bp b/services/minijail/Android.bp
index 038197f..decc5fe 100644
--- a/services/minijail/Android.bp
+++ b/services/minijail/Android.bp
@@ -28,6 +28,11 @@
defaults: ["libavservices_minijail_defaults"],
vendor_available: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
+
export_include_dirs: ["."],
}
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index 390cd5c..b55b601 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -60,7 +60,8 @@
result << " Sample Rate: " << getSampleRate() << "\n";
result << " Channel Count: " << getSamplesPerFrame() << "\n";
result << " Channel Mask: 0x" << std::hex << getChannelMask() << std::dec << "\n";
- result << " Format: " << getFormat() << "\n";
+ result << " Format: " << getFormat()
+ << " (" << audio_format_to_string(getFormat()) << ")\n";
result << " Frames Per Burst: " << mFramesPerBurst << "\n";
result << " Usage: " << getUsage() << "\n";
result << " ContentType: " << getContentType() << "\n";
diff --git a/services/oboeservice/AAudioServiceEndpointCapture.cpp b/services/oboeservice/AAudioServiceEndpointCapture.cpp
index bc769f0..95bd4bb 100644
--- a/services/oboeservice/AAudioServiceEndpointCapture.cpp
+++ b/services/oboeservice/AAudioServiceEndpointCapture.cpp
@@ -66,8 +66,7 @@
getFramesPerBurst(), timeoutNanos);
if (result == AAUDIO_ERROR_DISCONNECTED) {
ALOGD("%s() read() returned AAUDIO_ERROR_DISCONNECTED", __func__);
- // We do not need the returned vector.
- (void) AAudioServiceEndpointShared::disconnectRegisteredStreams();
+ AAudioServiceEndpointShared::handleDisconnectRegisteredStreamsAsync();
break;
} else if (result != getFramesPerBurst()) {
ALOGW("callbackLoop() read %d / %d",
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index a266d5b..3f18b95 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -183,10 +183,13 @@
? AAUDIO_SESSION_ID_NONE
: (aaudio_session_id_t) sessionId;
setSessionId(actualSessionId);
- ALOGD("%s() deviceId = %d, sessionId = %d", __func__, getDeviceId(), getSessionId());
+
+ ALOGD("%s(format = 0x%X) deviceId = %d, sessionId = %d",
+ __func__, audioFormat, getDeviceId(), getSessionId());
// Create MMAP/NOIRQ buffer.
- if (createMmapBuffer(&mAudioDataFileDescriptor) != AAUDIO_OK) {
+ result = createMmapBuffer(&mAudioDataFileDescriptor);
+ if (result != AAUDIO_OK) {
goto error;
}
@@ -206,12 +209,13 @@
mTimestampGracePeriodMs = ((int64_t) kTimestampGraceBurstCount * mFramesPerBurst
* AAUDIO_MILLIS_PER_SECOND) / getSampleRate();
- ALOGD("%s() actual rate = %d, channels = %d channelMask = %#x, deviceId = %d, capacity = %d\n",
+ ALOGD("%s() got rate = %d, channels = %d channelMask = %#x, deviceId = %d, capacity = %d\n",
__func__, getSampleRate(), getSamplesPerFrame(), getChannelMask(),
deviceId, getBufferCapacity());
- ALOGD("%s() format = 0x%08x, frame size = %d, burst size = %d",
- __func__, getFormat(), calculateBytesPerFrame(), mFramesPerBurst);
+ ALOGD("%s() got format = 0x%X = %s, frame size = %d, burst size = %d",
+ __func__, getFormat(), audio_format_to_string(getFormat()),
+ calculateBytesPerFrame(), mFramesPerBurst);
return result;
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp
index f590fc8..2a5939f 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.cpp
+++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp
@@ -147,8 +147,7 @@
getFramesPerBurst(), timeoutNanos);
if (result == AAUDIO_ERROR_DISCONNECTED) {
ALOGD("%s() write() returned AAUDIO_ERROR_DISCONNECTED", __func__);
- // We do not need the returned vector.
- (void) AAudioServiceEndpointShared::disconnectRegisteredStreams();
+ AAudioServiceEndpointShared::handleDisconnectRegisteredStreamsAsync();
break;
} else if (result != getFramesPerBurst()) {
ALOGW("callbackLoop() wrote %d / %d",
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index 5af0a91..dd421fe 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -214,3 +214,12 @@
}
return result;
}
+
+void AAudioServiceEndpointShared::handleDisconnectRegisteredStreamsAsync() {
+ android::sp<AAudioServiceEndpointShared> holdEndpoint(this);
+ std::thread asyncTask([holdEndpoint]() {
+ // We do not need the returned vector.
+ holdEndpoint->disconnectRegisteredStreams();
+ });
+ asyncTask.detach();
+}
diff --git a/services/oboeservice/AAudioServiceEndpointShared.h b/services/oboeservice/AAudioServiceEndpointShared.h
index 8357567..3e760c4 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.h
+++ b/services/oboeservice/AAudioServiceEndpointShared.h
@@ -69,6 +69,8 @@
aaudio_result_t stopSharingThread();
+ void handleDisconnectRegisteredStreamsAsync();
+
// An MMAP stream that is shared by multiple clients.
android::sp<AudioStreamInternal> mStreamInternal;
diff --git a/services/tuner/TunerFilter.cpp b/services/tuner/TunerFilter.cpp
index fb5bfa3..e8c7767 100644
--- a/services/tuner/TunerFilter.cpp
+++ b/services/tuner/TunerFilter.cpp
@@ -337,6 +337,9 @@
}
}
+ if (mFilterCallback != nullptr) {
+ mFilterCallback->detachCallbacks();
+ }
auto res = mFilter->close();
mFilter = nullptr;
mStarted = false;
@@ -470,6 +473,12 @@
}
}
+void TunerFilter::FilterCallback::detachCallbacks() {
+ Mutex::Autolock _l(mCallbackLock);
+ mOriginalCallback = nullptr;
+ mTunerFilterCallback = nullptr;
+}
+
} // namespace tuner
} // namespace tv
} // namespace media
diff --git a/services/tuner/TunerFilter.h b/services/tuner/TunerFilter.h
index 529c191..93d8898 100644
--- a/services/tuner/TunerFilter.h
+++ b/services/tuner/TunerFilter.h
@@ -67,6 +67,7 @@
void sendSharedFilterStatus(int32_t status);
void attachSharedFilterCallback(const shared_ptr<ITunerFilterCallback>& in_cb);
void detachSharedFilterCallback();
+ void detachCallbacks();
private:
shared_ptr<ITunerFilterCallback> mTunerFilterCallback;
diff --git a/services/tuner/TunerFrontend.cpp b/services/tuner/TunerFrontend.cpp
index a5ef2bb..5116305 100644
--- a/services/tuner/TunerFrontend.cpp
+++ b/services/tuner/TunerFrontend.cpp
@@ -174,6 +174,28 @@
return mFrontend->getHardwareInfo(_aidl_return);
}
+::ndk::ScopedAStatus TunerFrontend::removeOutputPid(int32_t in_pid) {
+ if (mFrontend == nullptr) {
+ ALOGD("IFrontend is not initialized");
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::UNAVAILABLE));
+ }
+
+ return mFrontend->removeOutputPid(in_pid);
+}
+
+::ndk::ScopedAStatus TunerFrontend::getFrontendStatusReadiness(
+ const std::vector<FrontendStatusType>& in_statusTypes,
+ std::vector<FrontendStatusReadiness>* _aidl_return) {
+ if (mFrontend == nullptr) {
+ ALOGD("IFrontend is not initialized");
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::UNAVAILABLE));
+ }
+
+ return mFrontend->getFrontendStatusReadiness(in_statusTypes, _aidl_return);
+}
+
/////////////// FrontendCallback ///////////////////////
::ndk::ScopedAStatus TunerFrontend::FrontendCallback::onEvent(FrontendEventType frontendEventType) {
ALOGV("FrontendCallback::onEvent, type=%d", frontendEventType);
diff --git a/services/tuner/TunerFrontend.h b/services/tuner/TunerFrontend.h
index 418a751..da471fb 100644
--- a/services/tuner/TunerFrontend.h
+++ b/services/tuner/TunerFrontend.h
@@ -30,6 +30,7 @@
using ::aidl::android::hardware::tv::tuner::FrontendScanType;
using ::aidl::android::hardware::tv::tuner::FrontendSettings;
using ::aidl::android::hardware::tv::tuner::FrontendStatus;
+using ::aidl::android::hardware::tv::tuner::FrontendStatusReadiness;
using ::aidl::android::hardware::tv::tuner::FrontendStatusType;
using ::aidl::android::hardware::tv::tuner::IFrontend;
using ::aidl::android::hardware::tv::tuner::IFrontendCallback;
@@ -63,6 +64,10 @@
vector<FrontendStatus>* _aidl_return) override;
::ndk::ScopedAStatus getFrontendId(int32_t* _aidl_return) override;
::ndk::ScopedAStatus getHardwareInfo(std::string* _aidl_return) override;
+ ::ndk::ScopedAStatus removeOutputPid(int32_t in_pid) override;
+ ::ndk::ScopedAStatus getFrontendStatusReadiness(
+ const std::vector<FrontendStatusType>& in_statusTypes,
+ std::vector<FrontendStatusReadiness>* _aidl_return) override;
struct FrontendCallback : public BnFrontendCallback {
FrontendCallback(const shared_ptr<ITunerFrontendCallback> tunerFrontendCallback)
diff --git a/services/tuner/aidl/android/media/tv/tuner/ITunerFrontend.aidl b/services/tuner/aidl/android/media/tv/tuner/ITunerFrontend.aidl
index 96f285f..0493f05 100644
--- a/services/tuner/aidl/android/media/tv/tuner/ITunerFrontend.aidl
+++ b/services/tuner/aidl/android/media/tv/tuner/ITunerFrontend.aidl
@@ -19,6 +19,7 @@
import android.hardware.tv.tuner.FrontendScanType;
import android.hardware.tv.tuner.FrontendSettings;
import android.hardware.tv.tuner.FrontendStatus;
+import android.hardware.tv.tuner.FrontendStatusReadiness;
import android.hardware.tv.tuner.FrontendStatusType;
import android.media.tv.tuner.ITunerFrontendCallback;
import android.media.tv.tuner.ITunerLnb;
@@ -99,4 +100,14 @@
* Request hardware information about the frontend.
*/
String getHardwareInfo();
+
+ /**
+ * Filter out unnecessary PID from frontend output.
+ */
+ void removeOutputPid(int pid);
+
+ /**
+ * Gets FrontendStatus’ readiness statuses for given status types.
+ */
+ FrontendStatusReadiness[] getFrontendStatusReadiness(in FrontendStatusType[] statusTypes);
}
diff --git a/services/tuner/hidl/TunerHidlFilter.cpp b/services/tuner/hidl/TunerHidlFilter.cpp
index a5bbf39..6d8ae03 100644
--- a/services/tuner/hidl/TunerHidlFilter.cpp
+++ b/services/tuner/hidl/TunerHidlFilter.cpp
@@ -510,6 +510,9 @@
}
}
+ if (mFilterCallback != nullptr) {
+ mFilterCallback->detachCallbacks();
+ }
HidlResult res = mFilter->close();
mFilter = nullptr;
mFilter_1_1 = nullptr;
@@ -970,6 +973,12 @@
}
}
+void TunerHidlFilter::FilterCallback::detachCallbacks() {
+ Mutex::Autolock _l(mCallbackLock);
+ mOriginalCallback = nullptr;
+ mTunerFilterCallback = nullptr;
+}
+
/////////////// FilterCallback Helper Methods ///////////////////////
void TunerHidlFilter::FilterCallback::getAidlFilterEvent(
const vector<HidlDemuxFilterEvent::Event>& events,
diff --git a/services/tuner/hidl/TunerHidlFilter.h b/services/tuner/hidl/TunerHidlFilter.h
index b8fad22..63c7a1b 100644
--- a/services/tuner/hidl/TunerHidlFilter.h
+++ b/services/tuner/hidl/TunerHidlFilter.h
@@ -129,6 +129,7 @@
void sendSharedFilterStatus(int32_t status);
void attachSharedFilterCallback(const shared_ptr<ITunerFilterCallback>& in_cb);
void detachSharedFilterCallback();
+ void detachCallbacks();
private:
void getAidlFilterEvent(const vector<HidlDemuxFilterEvent::Event>& events,
diff --git a/services/tuner/hidl/TunerHidlFrontend.cpp b/services/tuner/hidl/TunerHidlFrontend.cpp
index 057f24a..03957f3 100644
--- a/services/tuner/hidl/TunerHidlFrontend.cpp
+++ b/services/tuner/hidl/TunerHidlFrontend.cpp
@@ -428,6 +428,19 @@
static_cast<int32_t>(Result::UNAVAILABLE));
}
+::ndk::ScopedAStatus TunerHidlFrontend::removeOutputPid(int32_t /* in_pid */) {
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::UNAVAILABLE));
+}
+
+::ndk::ScopedAStatus TunerHidlFrontend::getFrontendStatusReadiness(
+ const std::vector<FrontendStatusType>& /* in_statusTypes */,
+ std::vector<FrontendStatusReadiness>* _aidl_return) {
+ _aidl_return->clear();
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::UNAVAILABLE));
+}
+
void TunerHidlFrontend::setLna(bool bEnable) {
if (mFrontend == nullptr) {
ALOGD("IFrontend is not initialized");
diff --git a/services/tuner/hidl/TunerHidlFrontend.h b/services/tuner/hidl/TunerHidlFrontend.h
index 7ff278c..f698655 100644
--- a/services/tuner/hidl/TunerHidlFrontend.h
+++ b/services/tuner/hidl/TunerHidlFrontend.h
@@ -32,6 +32,7 @@
using ::aidl::android::hardware::tv::tuner::FrontendScanType;
using ::aidl::android::hardware::tv::tuner::FrontendSettings;
using ::aidl::android::hardware::tv::tuner::FrontendStatus;
+using ::aidl::android::hardware::tv::tuner::FrontendStatusReadiness;
using ::aidl::android::hardware::tv::tuner::FrontendStatusType;
using ::android::sp;
using ::android::hardware::hidl_vec;
@@ -83,6 +84,10 @@
vector<FrontendStatus>* _aidl_return) override;
::ndk::ScopedAStatus getFrontendId(int32_t* _aidl_return) override;
::ndk::ScopedAStatus getHardwareInfo(std::string* _aidl_return) override;
+ ::ndk::ScopedAStatus removeOutputPid(int32_t in_pid) override;
+ ::ndk::ScopedAStatus getFrontendStatusReadiness(
+ const std::vector<FrontendStatusType>& in_statusTypes,
+ std::vector<FrontendStatusReadiness>* _aidl_return) override;
void setLna(bool in_bEnable);