Merge "Retry codec matching without profile check if no matching codec was found."
diff --git a/MainlineFiles.cfg b/MainlineFiles.cfg
index 4e1d3a2..bf39c1a 100644
--- a/MainlineFiles.cfg
+++ b/MainlineFiles.cfg
@@ -30,6 +30,7 @@
media/codec2/hidl/
media/codec2/sfplugin/utils/
media/codec2/vndk/
+media/libstagefright/data/media_codecs_sw.xml
media/module/
services/mediacodec/
diff --git a/camera/tests/fuzzer/Android.bp b/camera/tests/fuzzer/Android.bp
new file mode 100644
index 0000000..3e7c415
--- /dev/null
+++ b/camera/tests/fuzzer/Android.bp
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+cc_defaults {
+ name: "camera_defaults",
+ static_libs: [
+ "libcamera_client",
+ ],
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libutils",
+ "liblog",
+ "libbinder",
+ "libgui",
+ "libcamera_metadata",
+ "libnativewindow",
+ ],
+ fuzz_config: {
+ cc: [
+ "android-media-fuzzing-reports@google.com",
+ ],
+ componentid: 155276,
+ },
+}
+
+cc_fuzz {
+ name: "camera_fuzzer",
+ srcs: [
+ "camera_fuzzer.cpp",
+ ],
+ defaults: [
+ "camera_defaults",
+ ],
+}
+
+cc_fuzz {
+ name: "camera_c2CaptureRequest_fuzzer",
+ srcs: [
+ "camera_c2CaptureRequest_fuzzer.cpp",
+ ],
+ defaults: [
+ "camera_defaults",
+ ],
+}
+
+cc_fuzz {
+ name: "camera_c2ConcurrentCamera_fuzzer",
+ srcs: [
+ "camera_c2ConcurrentCamera_fuzzer.cpp",
+ ],
+ defaults: [
+ "camera_defaults",
+ ],
+}
+
+cc_fuzz {
+ name: "camera_c2SubmitInfo_fuzzer",
+ srcs: [
+ "camera_c2SubmitInfo_fuzzer.cpp",
+ ],
+ defaults: [
+ "camera_defaults",
+ ],
+}
+
+cc_fuzz {
+ name: "camera_c2SessionConfiguration_fuzzer",
+ srcs: [
+ "camera_c2SessionConfiguration_fuzzer.cpp",
+ ],
+ defaults: [
+ "camera_defaults",
+ ],
+}
+
+cc_fuzz {
+ name: "camera_c2OutputConfiguration_fuzzer",
+ srcs: [
+ "camera_c2OutputConfiguration_fuzzer.cpp",
+ ],
+ defaults: [
+ "camera_defaults",
+ ],
+}
+
+cc_fuzz {
+ name: "camera_vendorTagDescriptor_fuzzer",
+ srcs: [
+ "camera_vendorTagDescriptor_fuzzer.cpp",
+ ],
+ defaults: [
+ "camera_defaults",
+ ],
+ include_dirs: [
+ "system/media/camera/tests",
+ "system/media/private/camera/include",
+ ],
+}
+
+cc_fuzz {
+ name: "camera_Parameters_fuzzer",
+ srcs: [
+ "camera_Parameters_fuzzer.cpp",
+ ],
+ defaults: [
+ "camera_defaults",
+ ],
+}
+
+cc_fuzz {
+ name: "camera_SessionStats_fuzzer",
+ srcs: [
+ "camera_SessionStats_fuzzer.cpp",
+ ],
+ defaults: [
+ "camera_defaults",
+ ],
+}
+
+cc_fuzz {
+ name: "camera_captureResult_fuzzer",
+ srcs: [
+ "camera_captureResult_fuzzer.cpp",
+ ],
+ defaults: [
+ "camera_defaults",
+ ],
+}
diff --git a/camera/tests/fuzzer/README.md b/camera/tests/fuzzer/README.md
new file mode 100644
index 0000000..c07ac04
--- /dev/null
+++ b/camera/tests/fuzzer/README.md
@@ -0,0 +1,74 @@
+# Fuzzers for libcamera_client
+
+## Plugin Design Considerations
+The fuzzer plugins for libcamera_client are designed based on the understanding of the
+source code and try to achieve the following:
+
+##### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzers.
+
+libcamera_client supports the following parameters:
+1. Command (parameter name: `cmd`)
+2. Video Buffer Mode (parameter name: `videoBufferMode`)
+3. Preview Callback Flag (parameter name: `previewCallbackFlag`)
+4. Facing (parameter name: `facing`)
+5. Orientation (parameter name: `orientation`)
+6. Format (parameter name: `format`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `cmd` | 0.`CAMERA_CMD_START_SMOOTH_ZOOM` 1.`CAMERA_CMD_STOP_SMOOTH_ZOOM` 3.`CAMERA_CMD_SET_DISPLAY_ORIENTATION` 4.`CAMERA_CMD_ENABLE_SHUTTER_SOUND` 5.`CAMERA_CMD_PLAY_RECORDING_SOUND` 6.`CAMERA_CMD_START_FACE_DETECTION` 7.`CAMERA_CMD_STOP_FACE_DETECTION` 8.`CAMERA_CMD_ENABLE_FOCUS_MOVE_MSG` 9.`CAMERA_CMD_PING` 10.`CAMERA_CMD_SET_VIDEO_BUFFER_COUNT` 11.`CAMERA_CMD_SET_VIDEO_FORMAT`| Value obtained from FuzzedDataProvider|
+| `videoBufferMode` |0. `ICamera::VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV` 1.`ICamera::VIDEO_BUFFER_MODE_DATA_CALLBACK_METADATA` 2.`ICamera::VIDEO_BUFFER_MODE_BUFFER_QUEUE`| Value obtained from FuzzedDataProvider|
+| `previewCallbackFlag` | 0. `CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK` 1.`CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK` 2.`CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK` 3.`CAMERA_FRAME_CALLBACK_FLAG_NOOP` 4.`CAMERA_FRAME_CALLBACK_FLAG_CAMCORDER` 5.`CAMERA_FRAME_CALLBACK_FLAG_CAMERA` 6.`CAMERA_FRAME_CALLBACK_FLAG_BARCODE_SCANNER`| Value obtained from FuzzedDataProvider|
+| `facing` | 0.`android::hardware::CAMERA_FACING_BACK` 1.`android::hardware::CAMERA_FACING_FRONT`| Value obtained from FuzzedDataProvider|
+| `orientation` | 0.`0` 1.`90` 2.`180`3.`270`| Value obtained from FuzzedDataProvider|
+| `format` | 0.`CameraParameters::PIXEL_FORMAT_YUV422SP` 1.`CameraParameters::PIXEL_FORMAT_YUV420SP` 2.`CameraParameters::PIXEL_FORMAT_YUV422I` 3.`CameraParameters::PIXEL_FORMAT_YUV420P` 4.`CameraParameters::PIXEL_FORMAT_RGB565` 5.`CameraParameters::PIXEL_FORMAT_RGBA8888` 6.`CameraParameters::PIXEL_FORMAT_JPEG` 7.`CameraParameters::PIXEL_FORMAT_BAYER_RGGB` 8.`CameraParameters::PIXEL_FORMAT_ANDROID_OPAQUE`| Value obtained from FuzzedDataProvider|
+
+This also ensures that the plugins are always deterministic for any given input.
+
+##### Maximize utilization of input data
+The plugins feed the entire input data to the module.
+This ensures that the plugins tolerate any kind of input (empty, huge,
+malformed, etc) and dont `exit()` on any input and thereby increasing the
+chance of identifying vulnerabilities.
+
+## Build
+
+This describes steps to build camera_fuzzer, camera2CaptureRequest_fuzzer, camera2ConcurrentCamera_fuzzer, camera2SubmitInfo_fuzzer, camera2SessionConfiguration_fuzzer, camera2OutputConfiguration_fuzzer, vendorTagDescriptor_fuzzer, cameraParameters_fuzzer, cameraSessionStats_fuzzer and captureResult_fuzzer binaries
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+ $ mm -j$(nproc) camera_fuzzer
+ $ mm -j$(nproc) camera_c2CaptureRequest_fuzzer
+ $ mm -j$(nproc) camera_c2ConcurrentCamera_fuzzer
+ $ mm -j$(nproc) camera_c2SubmitInfo_fuzzer
+ $ mm -j$(nproc) camera_c2SessionConfiguration_fuzzer
+ $ mm -j$(nproc) camera_c2OutputConfiguration_fuzzer
+ $ mm -j$(nproc) camera_vendorTagDescriptor_fuzzer
+ $ mm -j$(nproc) camera_Parameters_fuzzer
+ $ mm -j$(nproc) camera_SessionStats_fuzzer
+ $ mm -j$(nproc) camera_captureResult_fuzzer
+```
+#### Steps to run
+To run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/${TARGET_ARCH}/camera_fuzzer/camera_fuzzer
+ $ adb shell /data/fuzz/${TARGET_ARCH}/camera_c2CaptureRequest_fuzzer/camera_c2CaptureRequest_fuzzer
+ $ adb shell /data/fuzz/${TARGET_ARCH}/camera_c2ConcurrentCamera_fuzzer/camera_c2ConcurrentCamera_fuzzer
+ $ adb shell /data/fuzz/${TARGET_ARCH}/camera_c2SubmitInfo_fuzzer/camera_c2SubmitInfo_fuzzer
+ $ adb shell /data/fuzz/${TARGET_ARCH}/camera_c2SessionConfiguration_fuzzer/camera_c2SessionConfiguration_fuzzer
+ $ adb shell /data/fuzz/${TARGET_ARCH}/camera_c2OutputConfiguration_fuzzer/camera_c2OutputConfiguration_fuzzer
+ $ adb shell /data/fuzz/${TARGET_ARCH}/camera_vendorTagDescriptor_fuzzer/camera_vendorTagDescriptor_fuzzer
+ $ adb shell /data/fuzz/${TARGET_ARCH}/camera_Parameters_fuzzer/camera_Parameters_fuzzer
+ $ adb shell /data/fuzz/${TARGET_ARCH}/camera_SessionStats_fuzzer/camera_SessionStats_fuzzer
+ $ adb shell /data/fuzz/${TARGET_ARCH}/camera_captureResult_fuzzer/camera_captureResult_fuzzer
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/camera/tests/fuzzer/camera2common.h b/camera/tests/fuzzer/camera2common.h
new file mode 100644
index 0000000..14a1b1b
--- /dev/null
+++ b/camera/tests/fuzzer/camera2common.h
@@ -0,0 +1,55 @@
+/*
+ * 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 CAMERA2COMMON_H
+#define CAMERA2COMMON_H
+
+#include <binder/Parcel.h>
+
+using namespace android;
+
+template <class type>
+void invokeReadWriteNullParcel(type* obj) {
+ Parcel* parcelNull = nullptr;
+ obj->writeToParcel(parcelNull);
+ obj->readFromParcel(parcelNull);
+}
+
+template <class type>
+void invokeReadWriteNullParcelsp(sp<type> obj) {
+ Parcel* parcelNull = nullptr;
+ obj->writeToParcel(parcelNull);
+ obj->readFromParcel(parcelNull);
+}
+
+template <class type>
+void invokeReadWriteParcel(type* obj) {
+ Parcel* parcel = new Parcel();
+ obj->writeToParcel(parcel);
+ parcel->setDataPosition(0);
+ obj->readFromParcel(parcel);
+ delete parcel;
+}
+
+template <class type>
+void invokeReadWriteParcelsp(sp<type> obj) {
+ Parcel* parcel = new Parcel();
+ obj->writeToParcel(parcel);
+ parcel->setDataPosition(0);
+ obj->readFromParcel(parcel);
+ delete parcel;
+}
+
+#endif // CAMERA2COMMON_H
diff --git a/camera/tests/fuzzer/camera_Parameters_fuzzer.cpp b/camera/tests/fuzzer/camera_Parameters_fuzzer.cpp
new file mode 100644
index 0000000..45b3526
--- /dev/null
+++ b/camera/tests/fuzzer/camera_Parameters_fuzzer.cpp
@@ -0,0 +1,163 @@
+/*
+ * 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 <CameraParameters.h>
+#include <CameraParameters2.h>
+#include <fcntl.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <utils/String16.h>
+
+using namespace std;
+using namespace android;
+
+string kValidFormats[] = {
+ CameraParameters::PIXEL_FORMAT_YUV422SP, CameraParameters::PIXEL_FORMAT_YUV420SP,
+ CameraParameters::PIXEL_FORMAT_YUV422I, CameraParameters::PIXEL_FORMAT_YUV420P,
+ CameraParameters::PIXEL_FORMAT_RGB565, CameraParameters::PIXEL_FORMAT_RGBA8888,
+ CameraParameters::PIXEL_FORMAT_JPEG, CameraParameters::PIXEL_FORMAT_BAYER_RGGB,
+ CameraParameters::PIXEL_FORMAT_ANDROID_OPAQUE};
+
+class CameraParametersFuzzer {
+ public:
+ void process(const uint8_t* data, size_t size);
+ ~CameraParametersFuzzer() {
+ delete mCameraParameters;
+ delete mCameraParameters2;
+ }
+
+ private:
+ void invokeCameraParameters();
+ template <class type>
+ void initCameraParameters(type** obj);
+ template <class type>
+ void cameraParametersCommon(type* obj);
+ CameraParameters* mCameraParameters = nullptr;
+ CameraParameters2* mCameraParameters2 = nullptr;
+ FuzzedDataProvider* mFDP = nullptr;
+};
+
+template <class type>
+void CameraParametersFuzzer::initCameraParameters(type** obj) {
+ if (mFDP->ConsumeBool()) {
+ *obj = new type();
+ } else {
+ string params;
+ if (mFDP->ConsumeBool()) {
+ int32_t width = mFDP->ConsumeIntegral<int32_t>();
+ int32_t height = mFDP->ConsumeIntegral<int32_t>();
+ int32_t minFps = mFDP->ConsumeIntegral<int32_t>();
+ int32_t maxFps = mFDP->ConsumeIntegral<int32_t>();
+ params = CameraParameters::KEY_SUPPORTED_VIDEO_SIZES;
+ params += '=' + to_string(width) + 'x' + to_string(height) + ';';
+ if (mFDP->ConsumeBool()) {
+ params += CameraParameters::KEY_PREVIEW_FPS_RANGE;
+ params += '=' + to_string(minFps) + ',' + to_string(maxFps) + ';';
+ }
+ if (mFDP->ConsumeBool()) {
+ params += CameraParameters::KEY_SUPPORTED_PICTURE_SIZES;
+ params += '=' + to_string(width) + 'x' + to_string(height) + ';';
+ }
+ if (mFDP->ConsumeBool()) {
+ params += CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS;
+ params += '=' + mFDP->PickValueInArray(kValidFormats) + ';';
+ }
+ } else {
+ params = mFDP->ConsumeRandomLengthString();
+ }
+ *obj = new type(String8(params.c_str()));
+ }
+}
+
+template <class type>
+void CameraParametersFuzzer::cameraParametersCommon(type* obj) {
+ Vector<Size> supportedPreviewSizes;
+ obj->getSupportedPreviewSizes(supportedPreviewSizes);
+ int32_t previewWidth = mFDP->ConsumeIntegral<int32_t>();
+ int32_t previewHeight = mFDP->ConsumeIntegral<int32_t>();
+ obj->setPreviewSize(previewWidth, previewHeight);
+ obj->getPreviewSize(&previewWidth, &previewHeight);
+
+ Vector<Size> supportedVideoSizes;
+ obj->getSupportedVideoSizes(supportedVideoSizes);
+ if (supportedVideoSizes.size() != 0) {
+ int32_t videoWidth, videoHeight, preferredVideoWidth, preferredVideoHeight;
+ if (mFDP->ConsumeBool()) {
+ int32_t idx = mFDP->ConsumeIntegralInRange<int32_t>(0, supportedVideoSizes.size() - 1);
+ obj->setVideoSize(supportedVideoSizes[idx].width, supportedVideoSizes[idx].height);
+ } else {
+ videoWidth = mFDP->ConsumeIntegral<int32_t>();
+ videoHeight = mFDP->ConsumeIntegral<int32_t>();
+ obj->setVideoSize(videoWidth, videoHeight);
+ }
+ obj->getVideoSize(&videoWidth, &videoHeight);
+ obj->getPreferredPreviewSizeForVideo(&preferredVideoWidth, &preferredVideoHeight);
+ }
+
+ int32_t fps = mFDP->ConsumeIntegral<int32_t>();
+ obj->setPreviewFrameRate(fps);
+ obj->getPreviewFrameRate();
+ string previewFormat = mFDP->ConsumeBool() ? mFDP->PickValueInArray(kValidFormats)
+ : mFDP->ConsumeRandomLengthString();
+ obj->setPreviewFormat(previewFormat.c_str());
+
+ int32_t pictureWidth = mFDP->ConsumeIntegral<int32_t>();
+ int32_t pictureHeight = mFDP->ConsumeIntegral<int32_t>();
+ Vector<Size> supportedPictureSizes;
+ obj->setPictureSize(pictureWidth, pictureHeight);
+ obj->getPictureSize(&pictureWidth, &pictureHeight);
+ obj->getSupportedPictureSizes(supportedPictureSizes);
+ string pictureFormat = mFDP->ConsumeBool() ? mFDP->PickValueInArray(kValidFormats)
+ : mFDP->ConsumeRandomLengthString();
+ obj->setPictureFormat(pictureFormat.c_str());
+ obj->getPictureFormat();
+
+ if (mFDP->ConsumeBool()) {
+ obj->dump();
+ } else {
+ int32_t fd = open("/dev/null", O_CLOEXEC | O_RDWR | O_CREAT);
+ Vector<String16> args = {};
+ obj->dump(fd, args);
+ close(fd);
+ }
+}
+
+void CameraParametersFuzzer::invokeCameraParameters() {
+ initCameraParameters<CameraParameters>(&mCameraParameters);
+ cameraParametersCommon<CameraParameters>(mCameraParameters);
+ initCameraParameters<CameraParameters2>(&mCameraParameters2);
+ cameraParametersCommon<CameraParameters2>(mCameraParameters2);
+
+ int32_t minFPS, maxFPS;
+ mCameraParameters->getPreviewFpsRange(&minFPS, &maxFPS);
+ string format = mFDP->ConsumeBool() ? mFDP->PickValueInArray(kValidFormats)
+ : mFDP->ConsumeRandomLengthString();
+ mCameraParameters->previewFormatToEnum(format.c_str());
+ mCameraParameters->isEmpty();
+ Vector<int32_t> formats;
+ mCameraParameters->getSupportedPreviewFormats(formats);
+}
+
+void CameraParametersFuzzer::process(const uint8_t* data, size_t size) {
+ mFDP = new FuzzedDataProvider(data, size);
+ invokeCameraParameters();
+ delete mFDP;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ CameraParametersFuzzer cameraParametersFuzzer;
+ cameraParametersFuzzer.process(data, size);
+ return 0;
+}
diff --git a/camera/tests/fuzzer/camera_SessionStats_fuzzer.cpp b/camera/tests/fuzzer/camera_SessionStats_fuzzer.cpp
new file mode 100644
index 0000000..1e94d47
--- /dev/null
+++ b/camera/tests/fuzzer/camera_SessionStats_fuzzer.cpp
@@ -0,0 +1,162 @@
+/*
+ * 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 <CameraSessionStats.h>
+#include <binder/Parcel.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include "camera2common.h"
+
+using namespace std;
+using namespace android;
+using namespace android::hardware;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+ CameraStreamStats* cameraStreamStats = nullptr;
+ Parcel parcelCamStreamStats;
+
+ if (fdp.ConsumeBool()) {
+ cameraStreamStats = new CameraStreamStats();
+ } else {
+ int32_t width = fdp.ConsumeIntegral<int32_t>();
+ if (fdp.ConsumeBool()) {
+ parcelCamStreamStats.writeInt32(width);
+ }
+ int32_t height = fdp.ConsumeIntegral<int32_t>();
+ if (fdp.ConsumeBool()) {
+ parcelCamStreamStats.writeInt32(height);
+ }
+ int32_t format = fdp.ConsumeIntegral<int32_t>();
+ if (fdp.ConsumeBool()) {
+ parcelCamStreamStats.writeInt32(format);
+ }
+ float maxPreviewFps = fdp.ConsumeFloatingPoint<float>();
+ if (fdp.ConsumeBool()) {
+ parcelCamStreamStats.writeFloat(maxPreviewFps);
+ }
+ int32_t dataSpace = fdp.ConsumeIntegral<int32_t>();
+ if (fdp.ConsumeBool()) {
+ parcelCamStreamStats.writeInt32(dataSpace);
+ }
+ int64_t usage = fdp.ConsumeIntegral<int64_t>();
+ if (fdp.ConsumeBool()) {
+ parcelCamStreamStats.writeInt64(usage);
+ }
+ int64_t requestCount = fdp.ConsumeIntegral<int64_t>();
+ if (fdp.ConsumeBool()) {
+ parcelCamStreamStats.writeInt64(requestCount);
+ }
+ int64_t errorCount = fdp.ConsumeIntegral<int64_t>();
+ if (fdp.ConsumeBool()) {
+ parcelCamStreamStats.writeInt64(errorCount);
+ }
+ int32_t maxHalBuffers = fdp.ConsumeIntegral<int32_t>();
+ if (fdp.ConsumeBool()) {
+ parcelCamStreamStats.writeInt32(maxHalBuffers);
+ }
+ int32_t maxAppBuffers = fdp.ConsumeIntegral<int32_t>();
+ if (fdp.ConsumeBool()) {
+ parcelCamStreamStats.writeInt32(maxAppBuffers);
+ }
+ int32_t dynamicRangeProfile = fdp.ConsumeIntegral<int32_t>();
+ if (fdp.ConsumeBool()) {
+ parcelCamStreamStats.writeInt32(dynamicRangeProfile);
+ }
+ int32_t streamUseCase = fdp.ConsumeIntegral<int32_t>();
+ if (fdp.ConsumeBool()) {
+ parcelCamStreamStats.writeInt32(streamUseCase);
+ }
+
+ cameraStreamStats = new CameraStreamStats(width, height, format, maxPreviewFps, dataSpace,
+ usage, maxHalBuffers, maxAppBuffers,
+ dynamicRangeProfile, streamUseCase);
+ }
+
+ parcelCamStreamStats.setDataPosition(0);
+ cameraStreamStats->readFromParcel(&parcelCamStreamStats);
+ invokeReadWriteNullParcel<CameraStreamStats>(cameraStreamStats);
+ invokeReadWriteParcel<CameraStreamStats>(cameraStreamStats);
+
+ CameraSessionStats* cameraSessionStats = nullptr;
+ Parcel parcelCamSessionStats;
+
+ if (fdp.ConsumeBool()) {
+ cameraSessionStats = new CameraSessionStats();
+ } else {
+ string camId = fdp.ConsumeRandomLengthString();
+ String16 cameraId(camId.c_str());
+ if (fdp.ConsumeBool()) {
+ parcelCamSessionStats.writeString16(cameraId);
+ }
+ int32_t facing = fdp.ConsumeIntegral<int32_t>();
+ if (fdp.ConsumeBool()) {
+ parcelCamSessionStats.writeInt32(facing);
+ }
+ int32_t newCameraState = fdp.ConsumeIntegral<int32_t>();
+ if (fdp.ConsumeBool()) {
+ parcelCamSessionStats.writeInt32(newCameraState);
+ }
+ string name = fdp.ConsumeRandomLengthString();
+ String16 clientName(name.c_str());
+ if (fdp.ConsumeBool()) {
+ parcelCamSessionStats.writeString16(clientName);
+ }
+ int32_t apiLevel = fdp.ConsumeIntegral<int32_t>();
+ if (fdp.ConsumeBool()) {
+ parcelCamSessionStats.writeInt32(apiLevel);
+ }
+ bool isNdk = fdp.ConsumeBool();
+ if (fdp.ConsumeBool()) {
+ parcelCamSessionStats.writeBool(isNdk);
+ }
+ int32_t latencyMs = fdp.ConsumeIntegral<int32_t>();
+ if (fdp.ConsumeBool()) {
+ parcelCamSessionStats.writeInt32(latencyMs);
+ }
+
+ cameraSessionStats = new CameraSessionStats(cameraId, facing, newCameraState, clientName,
+ apiLevel, isNdk, latencyMs);
+ }
+
+ if (fdp.ConsumeBool()) {
+ int32_t internalReconfigure = fdp.ConsumeIntegral<int32_t>();
+ parcelCamSessionStats.writeInt32(internalReconfigure);
+ }
+
+ if (fdp.ConsumeBool()) {
+ int64_t requestCount = fdp.ConsumeIntegral<int64_t>();
+ parcelCamSessionStats.writeInt64(requestCount);
+ }
+
+ if (fdp.ConsumeBool()) {
+ int64_t resultErrorCount = fdp.ConsumeIntegral<int64_t>();
+ parcelCamSessionStats.writeInt64(resultErrorCount);
+ }
+
+ if (fdp.ConsumeBool()) {
+ bool deviceError = fdp.ConsumeBool();
+ parcelCamSessionStats.writeBool(deviceError);
+ }
+
+ parcelCamSessionStats.setDataPosition(0);
+ cameraSessionStats->readFromParcel(&parcelCamSessionStats);
+ invokeReadWriteNullParcel<CameraSessionStats>(cameraSessionStats);
+ invokeReadWriteParcel<CameraSessionStats>(cameraSessionStats);
+
+ delete cameraStreamStats;
+ delete cameraSessionStats;
+ return 0;
+}
diff --git a/camera/tests/fuzzer/camera_c2CaptureRequest_fuzzer.cpp b/camera/tests/fuzzer/camera_c2CaptureRequest_fuzzer.cpp
new file mode 100644
index 0000000..06215a5
--- /dev/null
+++ b/camera/tests/fuzzer/camera_c2CaptureRequest_fuzzer.cpp
@@ -0,0 +1,128 @@
+/*
+ * 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 <CameraMetadata.h>
+#include <camera2/CaptureRequest.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/view/Surface.h>
+#include "camera2common.h"
+
+using namespace std;
+using namespace android;
+
+constexpr int32_t kNonZeroRangeMin = 0;
+constexpr int32_t kRangeMax = 1000;
+constexpr int32_t kSizeMin = 1;
+constexpr int32_t kSizeMax = 1000;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+
+ sp<CaptureRequest> captureRequest = new CaptureRequest();
+ Parcel parcelCamCaptureReq;
+
+ size_t physicalCameraSettingsSize =
+ fdp.ConsumeIntegralInRange<size_t>(kNonZeroRangeMin, kRangeMax);
+ if (fdp.ConsumeBool()) {
+ parcelCamCaptureReq.writeInt32(physicalCameraSettingsSize);
+ }
+
+ for (size_t idx = 0; idx < physicalCameraSettingsSize; ++idx) {
+ string id = fdp.ConsumeRandomLengthString();
+ if (fdp.ConsumeBool()) {
+ parcelCamCaptureReq.writeString16(String16(id.c_str()));
+ }
+ CameraMetadata cameraMetadata;
+ if (fdp.ConsumeBool()) {
+ cameraMetadata = CameraMetadata();
+ } else {
+ size_t entryCapacity = fdp.ConsumeIntegralInRange<size_t>(kNonZeroRangeMin, kRangeMax);
+ size_t dataCapacity = fdp.ConsumeIntegralInRange<size_t>(kNonZeroRangeMin, kRangeMax);
+ cameraMetadata = CameraMetadata(entryCapacity, dataCapacity);
+ }
+ captureRequest->mPhysicalCameraSettings.push_back({id, cameraMetadata});
+ if (fdp.ConsumeBool()) {
+ cameraMetadata.writeToParcel(&parcelCamCaptureReq);
+ }
+ }
+
+ captureRequest->mIsReprocess = fdp.ConsumeBool();
+ if (fdp.ConsumeBool()) {
+ parcelCamCaptureReq.writeInt32(captureRequest->mIsReprocess);
+ }
+
+ captureRequest->mSurfaceConverted = fdp.ConsumeBool();
+ if (fdp.ConsumeBool() && captureRequest->mSurfaceConverted) {
+ // 0-sized array
+ parcelCamCaptureReq.writeInt32(0);
+ }
+
+ if (!captureRequest->mSurfaceConverted) {
+ size_t surfaceListSize = fdp.ConsumeIntegralInRange<size_t>(kSizeMin, kSizeMax);
+ if (fdp.ConsumeBool()) {
+ parcelCamCaptureReq.writeInt32(surfaceListSize);
+ }
+ for (size_t idx = 0; idx < surfaceListSize; ++idx) {
+ sp<SurfaceComposerClient> composerClient = new SurfaceComposerClient;
+ sp<SurfaceControl> surfaceControl = composerClient->createSurface(
+ static_cast<String8>(fdp.ConsumeRandomLengthString().c_str()) /* name */,
+ fdp.ConsumeIntegral<uint32_t>() /* width */,
+ fdp.ConsumeIntegral<uint32_t>() /* height */,
+ fdp.ConsumeIntegral<int32_t>() /* format */,
+ fdp.ConsumeIntegral<int32_t>() /* flags */);
+ if (surfaceControl) {
+ sp<Surface> surface = surfaceControl->getSurface();
+ captureRequest->mSurfaceList.push_back(surface);
+ if (fdp.ConsumeBool()) {
+ view::Surface surfaceShim;
+ surfaceShim.name = String16((fdp.ConsumeRandomLengthString()).c_str());
+ surfaceShim.graphicBufferProducer = surface->getIGraphicBufferProducer();
+ surfaceShim.writeToParcel(&parcelCamCaptureReq);
+ }
+ surface.clear();
+ }
+ composerClient.clear();
+ surfaceControl.clear();
+ }
+ }
+
+ size_t indexListSize = fdp.ConsumeIntegralInRange<size_t>(kSizeMin, kSizeMax);
+ if (fdp.ConsumeBool()) {
+ parcelCamCaptureReq.writeInt32(indexListSize);
+ }
+
+ for (size_t idx = 0; idx < indexListSize; ++idx) {
+ int32_t streamIdx = fdp.ConsumeIntegral<int32_t>();
+ int32_t surfaceIdx = fdp.ConsumeIntegral<int32_t>();
+ captureRequest->mStreamIdxList.push_back(streamIdx);
+ captureRequest->mSurfaceIdxList.push_back(surfaceIdx);
+ if (fdp.ConsumeBool()) {
+ parcelCamCaptureReq.writeInt32(streamIdx);
+ }
+ if (fdp.ConsumeBool()) {
+ parcelCamCaptureReq.writeInt32(surfaceIdx);
+ }
+ }
+
+ invokeReadWriteParcelsp<CaptureRequest>(captureRequest);
+ invokeReadWriteNullParcelsp<CaptureRequest>(captureRequest);
+ parcelCamCaptureReq.setDataPosition(0);
+ captureRequest->readFromParcel(&parcelCamCaptureReq);
+ captureRequest.clear();
+ return 0;
+}
diff --git a/camera/tests/fuzzer/camera_c2ConcurrentCamera_fuzzer.cpp b/camera/tests/fuzzer/camera_c2ConcurrentCamera_fuzzer.cpp
new file mode 100644
index 0000000..12b5bc3
--- /dev/null
+++ b/camera/tests/fuzzer/camera_c2ConcurrentCamera_fuzzer.cpp
@@ -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.
+ */
+
+#include <camera2/ConcurrentCamera.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include "camera2common.h"
+
+using namespace std;
+using namespace android;
+using namespace android::hardware::camera2::utils;
+
+constexpr int32_t kRangeMin = 0;
+constexpr int32_t kRangeMax = 1000;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+ ConcurrentCameraIdCombination camIdCombination;
+
+ if (fdp.ConsumeBool()) {
+ size_t concurrentCameraIdSize = fdp.ConsumeIntegralInRange<size_t>(kRangeMin, kRangeMax);
+ for (size_t idx = 0; idx < concurrentCameraIdSize; ++idx) {
+ string concurrentCameraId = fdp.ConsumeRandomLengthString();
+ camIdCombination.mConcurrentCameraIds.push_back(concurrentCameraId);
+ }
+ }
+
+ invokeReadWriteNullParcel<ConcurrentCameraIdCombination>(&camIdCombination);
+ invokeReadWriteParcel<ConcurrentCameraIdCombination>(&camIdCombination);
+
+ CameraIdAndSessionConfiguration camIdAndSessionConfig;
+
+ if (fdp.ConsumeBool()) {
+ camIdAndSessionConfig.mCameraId = fdp.ConsumeRandomLengthString();
+ if (fdp.ConsumeBool()) {
+ camIdAndSessionConfig.mSessionConfiguration = SessionConfiguration();
+ } else {
+ int32_t inputWidth = fdp.ConsumeIntegral<int32_t>();
+ int32_t inputHeight = fdp.ConsumeIntegral<int32_t>();
+ int32_t inputFormat = fdp.ConsumeIntegral<int32_t>();
+ int32_t operatingMode = fdp.ConsumeIntegral<int32_t>();
+ camIdAndSessionConfig.mSessionConfiguration =
+ SessionConfiguration(inputWidth, inputHeight, inputFormat, operatingMode);
+ }
+ }
+
+ invokeReadWriteNullParcel<CameraIdAndSessionConfiguration>(&camIdAndSessionConfig);
+ invokeReadWriteParcel<CameraIdAndSessionConfiguration>(&camIdAndSessionConfig);
+ return 0;
+}
diff --git a/camera/tests/fuzzer/camera_c2OutputConfiguration_fuzzer.cpp b/camera/tests/fuzzer/camera_c2OutputConfiguration_fuzzer.cpp
new file mode 100644
index 0000000..51ac4e8
--- /dev/null
+++ b/camera/tests/fuzzer/camera_c2OutputConfiguration_fuzzer.cpp
@@ -0,0 +1,111 @@
+/*
+ * 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 <camera2/OutputConfiguration.h>
+#include <camera2/SessionConfiguration.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include "camera2common.h"
+
+using namespace std;
+using namespace android;
+using namespace android::hardware::camera2::params;
+
+constexpr int32_t kSizeMin = 0;
+constexpr int32_t kSizeMax = 1000;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+
+ OutputConfiguration* outputConfiguration = nullptr;
+
+ if (fdp.ConsumeBool()) {
+ outputConfiguration = new OutputConfiguration();
+ } else {
+ int32_t rotation = fdp.ConsumeIntegral<int32_t>();
+ string phyCameraId = fdp.ConsumeRandomLengthString();
+ String16 physicalCameraId(phyCameraId.c_str());
+ int32_t surfaceSetID = fdp.ConsumeIntegral<int32_t>();
+ bool isShared = fdp.ConsumeBool();
+
+ if (fdp.ConsumeBool()) {
+ sp<IGraphicBufferProducer> iGBP = nullptr;
+ sp<SurfaceComposerClient> composerClient = new SurfaceComposerClient;
+ sp<SurfaceControl> surfaceControl = composerClient->createSurface(
+ static_cast<String8>(fdp.ConsumeRandomLengthString().c_str()) /* name */,
+ fdp.ConsumeIntegral<uint32_t>() /* width */,
+ fdp.ConsumeIntegral<uint32_t>() /* height */,
+ fdp.ConsumeIntegral<int32_t>() /* format */,
+ fdp.ConsumeIntegral<int32_t>() /* flags */);
+ if (surfaceControl) {
+ sp<Surface> surface = surfaceControl->getSurface();
+ iGBP = surface->getIGraphicBufferProducer();
+ }
+ outputConfiguration = new OutputConfiguration(iGBP, rotation, physicalCameraId,
+ surfaceSetID, isShared);
+ iGBP.clear();
+ composerClient.clear();
+ surfaceControl.clear();
+ } else {
+ size_t iGBPSize = fdp.ConsumeIntegralInRange<size_t>(kSizeMin, kSizeMax);
+ vector<sp<IGraphicBufferProducer>> iGBPs;
+ for (size_t idx = 0; idx < iGBPSize; ++idx) {
+ sp<IGraphicBufferProducer> iGBP = nullptr;
+ sp<SurfaceComposerClient> composerClient = new SurfaceComposerClient;
+ sp<SurfaceControl> surfaceControl = composerClient->createSurface(
+ static_cast<String8>(fdp.ConsumeRandomLengthString().c_str()) /* name */,
+ fdp.ConsumeIntegral<uint32_t>() /* width */,
+ fdp.ConsumeIntegral<uint32_t>() /* height */,
+ fdp.ConsumeIntegral<int32_t>() /* format */,
+ fdp.ConsumeIntegral<int32_t>() /* flags */);
+ if (surfaceControl) {
+ sp<Surface> surface = surfaceControl->getSurface();
+ iGBP = surface->getIGraphicBufferProducer();
+ iGBPs.push_back(iGBP);
+ }
+ iGBP.clear();
+ composerClient.clear();
+ surfaceControl.clear();
+ }
+ outputConfiguration = new OutputConfiguration(iGBPs, rotation, physicalCameraId,
+ surfaceSetID, isShared);
+ }
+ }
+
+ outputConfiguration->getRotation();
+ outputConfiguration->getSurfaceSetID();
+ outputConfiguration->getSurfaceType();
+ outputConfiguration->getWidth();
+ outputConfiguration->getHeight();
+ outputConfiguration->isDeferred();
+ outputConfiguration->isShared();
+ outputConfiguration->getPhysicalCameraId();
+
+ OutputConfiguration outputConfiguration2;
+ outputConfiguration->gbpsEqual(outputConfiguration2);
+ outputConfiguration->sensorPixelModesUsedEqual(outputConfiguration2);
+ outputConfiguration->gbpsLessThan(outputConfiguration2);
+ outputConfiguration->sensorPixelModesUsedLessThan(outputConfiguration2);
+ outputConfiguration->getGraphicBufferProducers();
+ sp<IGraphicBufferProducer> gbp;
+ outputConfiguration->addGraphicProducer(gbp);
+ invokeReadWriteNullParcel<OutputConfiguration>(outputConfiguration);
+ invokeReadWriteParcel<OutputConfiguration>(outputConfiguration);
+ delete outputConfiguration;
+ return 0;
+}
diff --git a/camera/tests/fuzzer/camera_c2SessionConfiguration_fuzzer.cpp b/camera/tests/fuzzer/camera_c2SessionConfiguration_fuzzer.cpp
new file mode 100644
index 0000000..b2de95d
--- /dev/null
+++ b/camera/tests/fuzzer/camera_c2SessionConfiguration_fuzzer.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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 <camera2/OutputConfiguration.h>
+#include <camera2/SessionConfiguration.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include "camera2common.h"
+
+using namespace std;
+using namespace android;
+using namespace android::hardware::camera2::params;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+
+ SessionConfiguration* sessionConfiguration = nullptr;
+
+ if (fdp.ConsumeBool()) {
+ sessionConfiguration = new SessionConfiguration();
+ } else {
+ int32_t inputWidth = fdp.ConsumeIntegral<int32_t>();
+ int32_t inputHeight = fdp.ConsumeIntegral<int32_t>();
+ int32_t inputFormat = fdp.ConsumeIntegral<int32_t>();
+ int32_t operatingMode = fdp.ConsumeIntegral<int32_t>();
+ sessionConfiguration =
+ new SessionConfiguration(inputWidth, inputHeight, inputFormat, operatingMode);
+ }
+
+ sessionConfiguration->getInputWidth();
+ sessionConfiguration->getInputHeight();
+ sessionConfiguration->getInputFormat();
+ sessionConfiguration->getOperatingMode();
+
+ OutputConfiguration* outputConfiguration = nullptr;
+
+ if (fdp.ConsumeBool()) {
+ outputConfiguration = new OutputConfiguration();
+ sessionConfiguration->addOutputConfiguration(*outputConfiguration);
+ } else {
+ sp<IGraphicBufferProducer> iGBP = nullptr;
+ sp<SurfaceComposerClient> composerClient = new SurfaceComposerClient;
+ sp<SurfaceControl> surfaceControl = composerClient->createSurface(
+ static_cast<String8>(fdp.ConsumeRandomLengthString().c_str()),
+ fdp.ConsumeIntegral<uint32_t>(), fdp.ConsumeIntegral<uint32_t>(),
+ fdp.ConsumeIntegral<int32_t>(), fdp.ConsumeIntegral<int32_t>());
+ if (surfaceControl) {
+ sp<Surface> surface = surfaceControl->getSurface();
+ iGBP = surface->getIGraphicBufferProducer();
+ surface.clear();
+ }
+ int32_t rotation = fdp.ConsumeIntegral<int32_t>();
+ string phyCameraId = fdp.ConsumeRandomLengthString();
+ String16 physicalCameraId(phyCameraId.c_str());
+ int32_t surfaceSetID = fdp.ConsumeIntegral<int32_t>();
+ bool isShared = fdp.ConsumeBool();
+ outputConfiguration =
+ new OutputConfiguration(iGBP, rotation, physicalCameraId, surfaceSetID, isShared);
+ sessionConfiguration->addOutputConfiguration(*outputConfiguration);
+ }
+
+ sessionConfiguration->getOutputConfigurations();
+ SessionConfiguration sessionConfiguration2;
+ sessionConfiguration->outputsEqual(sessionConfiguration2);
+ sessionConfiguration->outputsLessThan(sessionConfiguration2);
+ sessionConfiguration->inputIsMultiResolution();
+
+ invokeReadWriteNullParcel<SessionConfiguration>(sessionConfiguration);
+ invokeReadWriteParcel<SessionConfiguration>(sessionConfiguration);
+
+ delete sessionConfiguration;
+ delete outputConfiguration;
+ return 0;
+}
diff --git a/camera/tests/fuzzer/camera_c2SubmitInfo_fuzzer.cpp b/camera/tests/fuzzer/camera_c2SubmitInfo_fuzzer.cpp
new file mode 100644
index 0000000..dc40b0f
--- /dev/null
+++ b/camera/tests/fuzzer/camera_c2SubmitInfo_fuzzer.cpp
@@ -0,0 +1,32 @@
+/*
+ * 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 <camera2/SubmitInfo.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include "camera2common.h"
+
+using namespace std;
+using namespace android;
+using namespace android::hardware::camera2::utils;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+ SubmitInfo submitInfo;
+ submitInfo.mRequestId = fdp.ConsumeIntegral<int32_t>();
+ submitInfo.mLastFrameNumber = fdp.ConsumeIntegral<int64_t>();
+ invokeReadWriteParcel<SubmitInfo>(&submitInfo);
+ return 0;
+}
diff --git a/camera/tests/fuzzer/camera_captureResult_fuzzer.cpp b/camera/tests/fuzzer/camera_captureResult_fuzzer.cpp
new file mode 100644
index 0000000..03cf9c4
--- /dev/null
+++ b/camera/tests/fuzzer/camera_captureResult_fuzzer.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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 <CaptureResult.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include "camera2common.h"
+
+using namespace std;
+using namespace android;
+using namespace android::hardware::camera2::impl;
+
+constexpr int32_t kSizeMin = 0;
+constexpr int32_t kSizeMax = 1000;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+ PhysicalCaptureResultInfo* physicalCaptureResultInfo = nullptr;
+
+ if (fdp.ConsumeBool()) {
+ physicalCaptureResultInfo = new PhysicalCaptureResultInfo();
+ } else {
+ string camId = fdp.ConsumeRandomLengthString();
+ String16 cameraId(camId.c_str());
+ CameraMetadata cameraMetadata = CameraMetadata();
+ physicalCaptureResultInfo = new PhysicalCaptureResultInfo(cameraId, cameraMetadata);
+ }
+
+ invokeReadWriteParcel<PhysicalCaptureResultInfo>(physicalCaptureResultInfo);
+
+ CaptureResult* captureResult = new CaptureResult();
+
+ if (fdp.ConsumeBool()) {
+ captureResult->mMetadata = CameraMetadata();
+ }
+ if (fdp.ConsumeBool()) {
+ captureResult->mResultExtras = CaptureResultExtras();
+ string errCamId = fdp.ConsumeRandomLengthString();
+ String16 errCameraId(errCamId.c_str());
+ captureResult->mResultExtras.errorPhysicalCameraId = errCameraId;
+ captureResult->mResultExtras.isValid();
+ invokeReadWriteNullParcel<CaptureResultExtras>(&(captureResult->mResultExtras));
+ }
+ if (fdp.ConsumeBool()) {
+ size_t physicalMetadatasSize = fdp.ConsumeIntegralInRange<size_t>(kSizeMin, kSizeMax);
+ for (size_t idx = 0; idx < physicalMetadatasSize; ++idx) {
+ captureResult->mPhysicalMetadatas.push_back(PhysicalCaptureResultInfo());
+ }
+ }
+
+ invokeReadWriteNullParcel<CaptureResult>(captureResult);
+ invokeReadWriteParcel<CaptureResult>(captureResult);
+ CaptureResult captureResult2(*captureResult);
+ CaptureResult captureResult3(move(captureResult2));
+
+ delete captureResult;
+ delete physicalCaptureResultInfo;
+ return 0;
+}
diff --git a/camera/tests/fuzzer/camera_fuzzer.cpp b/camera/tests/fuzzer/camera_fuzzer.cpp
new file mode 100644
index 0000000..f45500e
--- /dev/null
+++ b/camera/tests/fuzzer/camera_fuzzer.cpp
@@ -0,0 +1,404 @@
+/*
+ * 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 <Camera.h>
+#include <CameraBase.h>
+#include <CameraMetadata.h>
+#include <CameraParameters.h>
+#include <CameraUtils.h>
+#include <VendorTagDescriptor.h>
+#include <binder/IMemory.h>
+#include <binder/MemoryDealer.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <utils/Log.h>
+#include "camera2common.h"
+#include <android/hardware/ICameraService.h>
+
+using namespace std;
+using namespace android;
+using namespace android::hardware;
+
+constexpr int32_t kFrameRateMin = 1;
+constexpr int32_t kFrameRateMax = 120;
+constexpr int32_t kCamIdMin = 0;
+constexpr int32_t kCamIdMax = 1;
+constexpr int32_t kNumMin = 0;
+constexpr int32_t kNumMax = 1024;
+constexpr int32_t kMemoryDealerSize = 1000;
+constexpr int32_t kRangeMin = 0;
+constexpr int32_t kRangeMax = 1000;
+constexpr int32_t kSizeMin = 0;
+constexpr int32_t kSizeMax = 1000;
+
+constexpr int32_t kValidCMD[] = {CAMERA_CMD_START_SMOOTH_ZOOM,
+ CAMERA_CMD_STOP_SMOOTH_ZOOM,
+ CAMERA_CMD_SET_DISPLAY_ORIENTATION,
+ CAMERA_CMD_ENABLE_SHUTTER_SOUND,
+ CAMERA_CMD_PLAY_RECORDING_SOUND,
+ CAMERA_CMD_START_FACE_DETECTION,
+ CAMERA_CMD_STOP_FACE_DETECTION,
+ CAMERA_CMD_ENABLE_FOCUS_MOVE_MSG,
+ CAMERA_CMD_PING,
+ CAMERA_CMD_SET_VIDEO_BUFFER_COUNT,
+ CAMERA_CMD_SET_VIDEO_FORMAT};
+
+constexpr int32_t kValidVideoBufferMode[] = {ICamera::VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV,
+ ICamera::VIDEO_BUFFER_MODE_DATA_CALLBACK_METADATA,
+ ICamera::VIDEO_BUFFER_MODE_BUFFER_QUEUE};
+
+constexpr int32_t kValidPreviewCallbackFlag[] = {
+ CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK, CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK,
+ CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK, CAMERA_FRAME_CALLBACK_FLAG_NOOP,
+ CAMERA_FRAME_CALLBACK_FLAG_CAMCORDER, CAMERA_FRAME_CALLBACK_FLAG_CAMERA,
+ CAMERA_FRAME_CALLBACK_FLAG_BARCODE_SCANNER};
+
+constexpr int32_t kValidFacing[] = {android::hardware::CAMERA_FACING_BACK,
+ android::hardware::CAMERA_FACING_FRONT};
+
+constexpr int32_t kValidOrientation[] = {0, 90, 180, 270};
+
+class TestCameraListener : public CameraListener {
+ public:
+ virtual ~TestCameraListener() = default;
+
+ void notify(int32_t /*msgType*/, int32_t /*ext1*/, int32_t /*ext2*/) override { return; };
+ void postData(int32_t /*msgType*/, const sp<IMemory>& /*dataPtr*/,
+ camera_frame_metadata_t* /*metadata*/) override {
+ return;
+ };
+ void postDataTimestamp(nsecs_t /*timestamp*/, int32_t /*msgType*/,
+ const sp<IMemory>& /*dataPtr*/) override {
+ return;
+ };
+ void postRecordingFrameHandleTimestamp(nsecs_t /*timestamp*/,
+ native_handle_t* /*handle*/) override {
+ return;
+ };
+ void postRecordingFrameHandleTimestampBatch(
+ const std::vector<nsecs_t>& /*timestamps*/,
+ const std::vector<native_handle_t*>& /*handles*/) override {
+ return;
+ };
+};
+
+class CameraFuzzer : public ::android::hardware::BnCameraClient {
+ public:
+ void process(const uint8_t* data, size_t size);
+ ~CameraFuzzer() {
+ delete mCameraMetadata;
+ mComposerClient.clear();
+ mSurfaceControl.clear();
+ mSurface.clear();
+ mCamera.clear();
+ mMemoryDealer.clear();
+ mIMem.clear();
+ mCameraListener.clear();
+ mCameraService.clear();
+ }
+
+ private:
+ bool initCamera();
+ void initCameraMetadata();
+ void invokeCamera();
+ void invokeCameraUtils();
+ void invokeCameraBase();
+ void invokeCameraMetadata();
+ void invokeSetParameters();
+ sp<Camera> mCamera = nullptr;
+ CameraMetadata* mCameraMetadata = nullptr;
+ sp<SurfaceComposerClient> mComposerClient = nullptr;
+ sp<SurfaceControl> mSurfaceControl = nullptr;
+ sp<Surface> mSurface = nullptr;
+ sp<MemoryDealer> mMemoryDealer = nullptr;
+ sp<IMemory> mIMem = nullptr;
+ sp<TestCameraListener> mCameraListener = nullptr;
+ sp<ICameraService> mCameraService = nullptr;
+ sp<ICamera> cameraDevice = nullptr;
+ FuzzedDataProvider* mFDP = nullptr;
+
+ // CameraClient interface
+ void notifyCallback(int32_t, int32_t, int32_t) override { return; };
+ void dataCallback(int32_t, const sp<IMemory>&, camera_frame_metadata_t*) override { return; };
+ void dataCallbackTimestamp(nsecs_t, int32_t, const sp<IMemory>&) override { return; };
+ void recordingFrameHandleCallbackTimestamp(nsecs_t, native_handle_t*) override { return; };
+ void recordingFrameHandleCallbackTimestampBatch(const std::vector<nsecs_t>&,
+ const std::vector<native_handle_t*>&) override {
+ return;
+ };
+};
+
+bool CameraFuzzer::initCamera() {
+ ProcessState::self()->startThreadPool();
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->getService(String16("media.camera"));
+ mCameraService = interface_cast<ICameraService>(binder);
+ mCameraService->connect(this, mFDP->ConsumeIntegral<int32_t>() /* cameraId */,
+ String16("CAMERAFUZZ"), hardware::ICameraService::USE_CALLING_UID,
+ hardware::ICameraService::USE_CALLING_PID,
+ /*targetSdkVersion*/ __ANDROID_API_FUTURE__, &cameraDevice);
+ mCamera = Camera::create(cameraDevice);
+ if (!mCamera) {
+ return false;
+ }
+ return true;
+}
+
+void CameraFuzzer::invokeSetParameters() {
+ String8 s = mCamera->getParameters();
+ CameraParameters params(s);
+ int32_t width = mFDP->ConsumeIntegral<int32_t>();
+ int32_t height = mFDP->ConsumeIntegral<int32_t>();
+ params.setVideoSize(width, height);
+ int32_t frameRate = mFDP->ConsumeIntegralInRange<int32_t>(kFrameRateMin, kFrameRateMax);
+ params.setPreviewFrameRate(frameRate);
+ mCamera->setParameters(params.flatten());
+}
+
+void CameraFuzzer::invokeCamera() {
+ if (!initCamera()) {
+ return;
+ }
+
+ int32_t cameraId = mFDP->ConsumeIntegralInRange<int32_t>(kCamIdMin, kCamIdMax);
+ Camera::getNumberOfCameras();
+ CameraInfo cameraInfo;
+ cameraInfo.facing = mFDP->ConsumeBool() ? mFDP->PickValueInArray(kValidFacing)
+ : mFDP->ConsumeIntegral<int>();
+ cameraInfo.orientation = mFDP->ConsumeBool() ? mFDP->PickValueInArray(kValidOrientation)
+ : mFDP->ConsumeIntegral<int>();
+ Camera::getCameraInfo(cameraId, &cameraInfo);
+ mCamera->reconnect();
+
+ mComposerClient = new SurfaceComposerClient;
+ mSurfaceControl = mComposerClient->createSurface(
+ static_cast<String8>(mFDP->ConsumeRandomLengthString().c_str()) /* name */,
+ mFDP->ConsumeIntegral<uint32_t>() /* width */,
+ mFDP->ConsumeIntegral<uint32_t>() /* height */,
+ mFDP->ConsumeIntegral<int32_t>() /* format */,
+ mFDP->ConsumeIntegral<int32_t>() /* flags */);
+ if (mSurfaceControl) {
+ mSurface = mSurfaceControl->getSurface();
+ mCamera->setPreviewTarget(mSurface->getIGraphicBufferProducer());
+ mCamera->startPreview();
+ mCamera->stopPreview();
+ mCamera->previewEnabled();
+ mCamera->startRecording();
+ mCamera->stopRecording();
+ }
+
+ mCamera->lock();
+ mCamera->unlock();
+ mCamera->autoFocus();
+ mCamera->cancelAutoFocus();
+
+ int32_t msgType = mFDP->ConsumeIntegral<int32_t>();
+ mCamera->takePicture(msgType);
+ invokeSetParameters();
+ int32_t cmd;
+ if (mFDP->ConsumeBool()) {
+ cmd = mFDP->PickValueInArray(kValidCMD);
+ } else {
+ cmd = mFDP->ConsumeIntegral<int32_t>();
+ }
+ int32_t arg1 = mFDP->ConsumeIntegral<int32_t>();
+ int32_t arg2 = mFDP->ConsumeIntegral<int32_t>();
+ mCamera->sendCommand(cmd, arg1, arg2);
+
+ int32_t videoBufferMode = mFDP->PickValueInArray(kValidVideoBufferMode);
+ mCamera->setVideoBufferMode(videoBufferMode);
+ if (mSurfaceControl) {
+ mSurface = mSurfaceControl->getSurface();
+ mCamera->setVideoTarget(mSurface->getIGraphicBufferProducer());
+ }
+ mCameraListener = sp<TestCameraListener>::make();
+ mCamera->setListener(mCameraListener);
+ int32_t previewCallbackFlag;
+ if (mFDP->ConsumeBool()) {
+ previewCallbackFlag = mFDP->PickValueInArray(kValidPreviewCallbackFlag);
+ } else {
+ previewCallbackFlag = mFDP->ConsumeIntegral<int32_t>();
+ }
+ mCamera->setPreviewCallbackFlags(previewCallbackFlag);
+ if (mSurfaceControl) {
+ mSurface = mSurfaceControl->getSurface();
+ mCamera->setPreviewCallbackTarget(mSurface->getIGraphicBufferProducer());
+ }
+
+ mCamera->getRecordingProxy();
+ int32_t mode = mFDP->ConsumeIntegral<int32_t>();
+ mCamera->setAudioRestriction(mode);
+ mCamera->getGlobalAudioRestriction();
+ mCamera->recordingEnabled();
+
+ mMemoryDealer = new MemoryDealer(kMemoryDealerSize);
+ mIMem = mMemoryDealer->allocate(kMemoryDealerSize);
+ mCamera->releaseRecordingFrame(mIMem);
+
+ int32_t numFds = mFDP->ConsumeIntegralInRange<int32_t>(kNumMin, kNumMax);
+ int32_t numInts = mFDP->ConsumeIntegralInRange<int32_t>(kNumMin, kNumMax);
+ native_handle_t* handle = native_handle_create(numFds, numInts);
+ mCamera->releaseRecordingFrameHandle(handle);
+
+ int32_t msgTypeNC = mFDP->ConsumeIntegral<int32_t>();
+ int32_t ext = mFDP->ConsumeIntegral<int32_t>();
+ int32_t ext2 = mFDP->ConsumeIntegral<int32_t>();
+ mCamera->notifyCallback(msgTypeNC, ext, ext2);
+
+ int64_t timestamp = mFDP->ConsumeIntegral<int64_t>();
+ mCamera->dataCallbackTimestamp(timestamp, msgTypeNC, mIMem);
+ mCamera->recordingFrameHandleCallbackTimestamp(timestamp, handle);
+}
+
+void CameraFuzzer::invokeCameraUtils() {
+ CameraMetadata staticMetadata;
+ int32_t orientVal = mFDP->ConsumeBool() ? mFDP->PickValueInArray(kValidOrientation)
+ : mFDP->ConsumeIntegral<int32_t>();
+ uint8_t facingVal = mFDP->ConsumeBool() ? mFDP->PickValueInArray(kValidFacing)
+ : mFDP->ConsumeIntegral<uint8_t>();
+ staticMetadata.update(ANDROID_SENSOR_ORIENTATION, &orientVal, 1);
+ staticMetadata.update(ANDROID_LENS_FACING, &facingVal, 1);
+ int32_t transform = 0;
+ CameraUtils::getRotationTransform(
+ staticMetadata, mFDP->ConsumeIntegral<int32_t>() /* mirrorMode */, &transform /*out*/);
+ CameraUtils::isCameraServiceDisabled();
+}
+
+void CameraFuzzer::invokeCameraBase() {
+ CameraInfo cameraInfo;
+ cameraInfo.facing = mFDP->ConsumeBool() ? mFDP->PickValueInArray(kValidFacing)
+ : mFDP->ConsumeIntegral<int>();
+ cameraInfo.orientation = mFDP->ConsumeBool() ? mFDP->PickValueInArray(kValidOrientation)
+ : mFDP->ConsumeIntegral<int>();
+ invokeReadWriteParcel<CameraInfo>(&cameraInfo);
+
+ CameraStatus* cameraStatus = nullptr;
+
+ if (mFDP->ConsumeBool()) {
+ cameraStatus = new CameraStatus();
+ } else {
+ string cid = mFDP->ConsumeRandomLengthString();
+ String8 id(cid.c_str());
+ int32_t status = mFDP->ConsumeIntegral<int32_t>();
+ size_t unavailSubIdsSize = mFDP->ConsumeIntegralInRange<size_t>(kSizeMin, kSizeMax);
+ vector<String8> unavailSubIds;
+ for (size_t idx = 0; idx < unavailSubIdsSize; ++idx) {
+ string subId = mFDP->ConsumeRandomLengthString();
+ String8 unavailSubId(subId.c_str());
+ unavailSubIds.push_back(unavailSubId);
+ }
+ string clientPkg = mFDP->ConsumeRandomLengthString();
+ String8 clientPackage(clientPkg.c_str());
+ cameraStatus = new CameraStatus(id, status, unavailSubIds, clientPackage);
+ }
+
+ invokeReadWriteParcel<CameraStatus>(cameraStatus);
+ delete cameraStatus;
+}
+
+void CameraFuzzer::initCameraMetadata() {
+ if (mFDP->ConsumeBool()) {
+ mCameraMetadata = new CameraMetadata();
+ } else {
+ size_t entryCapacity = mFDP->ConsumeIntegralInRange<size_t>(kSizeMin, kSizeMax);
+ size_t dataCapacity = mFDP->ConsumeIntegralInRange<size_t>(kSizeMin, kSizeMax);
+ mCameraMetadata = new CameraMetadata(entryCapacity, dataCapacity);
+ }
+}
+
+void CameraFuzzer::invokeCameraMetadata() {
+ initCameraMetadata();
+
+ const camera_metadata_t* metadataBuffer = nullptr;
+ if (mFDP->ConsumeBool()) {
+ metadataBuffer = mCameraMetadata->getAndLock();
+ }
+
+ mCameraMetadata->entryCount();
+ mCameraMetadata->isEmpty();
+ mCameraMetadata->bufferSize();
+ mCameraMetadata->sort();
+
+ uint32_t tag = mFDP->ConsumeIntegral<uint32_t>();
+ uint8_t dataUint8 = mFDP->ConsumeIntegral<uint8_t>();
+ int32_t dataInt32 = mFDP->ConsumeIntegral<int32_t>();
+ int64_t dataInt64 = mFDP->ConsumeIntegral<int64_t>();
+ float dataFloat = mFDP->ConsumeFloatingPoint<float>();
+ double dataDouble = mFDP->ConsumeFloatingPoint<double>();
+ camera_metadata_rational dataRational;
+ dataRational.numerator = mFDP->ConsumeIntegral<int32_t>();
+ dataRational.denominator = mFDP->ConsumeIntegral<int32_t>();
+ string dataStr = mFDP->ConsumeRandomLengthString();
+ String8 dataString(dataStr.c_str());
+ size_t data_count = 1;
+ mCameraMetadata->update(tag, &dataUint8, data_count);
+ mCameraMetadata->update(tag, &dataInt32, data_count);
+ mCameraMetadata->update(tag, &dataFloat, data_count);
+ mCameraMetadata->update(tag, &dataInt64, data_count);
+ mCameraMetadata->update(tag, &dataRational, data_count);
+ mCameraMetadata->update(tag, &dataDouble, data_count);
+ mCameraMetadata->update(tag, dataString);
+
+ uint32_t tagExists = mFDP->ConsumeBool() ? tag : mFDP->ConsumeIntegral<uint32_t>();
+ mCameraMetadata->exists(tagExists);
+
+ uint32_t tagFind = mFDP->ConsumeBool() ? tag : mFDP->ConsumeIntegral<uint32_t>();
+ mCameraMetadata->find(tagFind);
+
+ uint32_t tagErase = mFDP->ConsumeBool() ? tag : mFDP->ConsumeIntegral<uint32_t>();
+ mCameraMetadata->erase(tagErase);
+
+ mCameraMetadata->unlock(metadataBuffer);
+ std::vector<int32_t> tagsRemoved;
+ uint64_t vendorId = mFDP->ConsumeIntegral<uint64_t>();
+ mCameraMetadata->removePermissionEntries(vendorId, &tagsRemoved);
+
+ string name = mFDP->ConsumeRandomLengthString();
+ VendorTagDescriptor vTags;
+ uint32_t tagName = mFDP->ConsumeIntegral<uint32_t>();
+ mCameraMetadata->getTagFromName(name.c_str(), &vTags, &tagName);
+
+ invokeReadWriteNullParcel<CameraMetadata>(mCameraMetadata);
+ invokeReadWriteParcel<CameraMetadata>(mCameraMetadata);
+
+ int32_t fd = open("/dev/null", O_CLOEXEC | O_RDWR | O_CREAT);
+ int32_t verbosity = mFDP->ConsumeIntegralInRange<int32_t>(kRangeMin, kRangeMax);
+ int32_t indentation = mFDP->ConsumeIntegralInRange<int32_t>(kRangeMin, kRangeMax);
+ mCameraMetadata->dump(fd, verbosity, indentation);
+
+ CameraMetadata metadataCopy(mCameraMetadata->release());
+ CameraMetadata otherCameraMetadata;
+ mCameraMetadata->swap(otherCameraMetadata);
+ close(fd);
+}
+
+void CameraFuzzer::process(const uint8_t* data, size_t size) {
+ mFDP = new FuzzedDataProvider(data, size);
+ invokeCamera();
+ invokeCameraUtils();
+ invokeCameraBase();
+ invokeCameraMetadata();
+ delete mFDP;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ sp<CameraFuzzer> cameraFuzzer = new CameraFuzzer();
+ cameraFuzzer->process(data, size);
+ cameraFuzzer.clear();
+ return 0;
+}
diff --git a/camera/tests/fuzzer/camera_vendorTagDescriptor_fuzzer.cpp b/camera/tests/fuzzer/camera_vendorTagDescriptor_fuzzer.cpp
new file mode 100644
index 0000000..e14d9ce
--- /dev/null
+++ b/camera/tests/fuzzer/camera_vendorTagDescriptor_fuzzer.cpp
@@ -0,0 +1,207 @@
+/*
+ * 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 <VendorTagDescriptor.h>
+#include <binder/Parcel.h>
+#include <camera_metadata_tests_fake_vendor.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <system/camera_vendor_tags.h>
+
+#include <camera_metadata_hidden.h>
+#include "camera2common.h"
+
+using namespace std;
+using namespace android;
+
+constexpr int32_t kRangeMin = 0;
+constexpr int32_t kRangeMax = 1000;
+constexpr int32_t kVendorTagDescriptorId = -1;
+
+extern "C" {
+
+static int zero_get_tag_count(const vendor_tag_ops_t*) {
+ return 0;
+}
+
+static int default_get_tag_count(const vendor_tag_ops_t*) {
+ return VENDOR_TAG_COUNT_ERR;
+}
+
+static void default_get_all_tags(const vendor_tag_ops_t*, uint32_t*) {}
+
+static const char* default_get_section_name(const vendor_tag_ops_t*, uint32_t) {
+ return VENDOR_SECTION_NAME_ERR;
+}
+
+static const char* default_get_tag_name(const vendor_tag_ops_t*, uint32_t) {
+ return VENDOR_TAG_NAME_ERR;
+}
+
+static int default_get_tag_type(const vendor_tag_ops_t*, uint32_t) {
+ return VENDOR_TAG_TYPE_ERR;
+}
+
+} /*extern "C"*/
+
+static void FillWithDefaults(vendor_tag_ops_t* vOps) {
+ vOps->get_tag_count = default_get_tag_count;
+ vOps->get_all_tags = default_get_all_tags;
+ vOps->get_section_name = default_get_section_name;
+ vOps->get_tag_name = default_get_tag_name;
+ vOps->get_tag_type = default_get_tag_type;
+}
+
+class VendorTagDescriptorFuzzer {
+ public:
+ void process(const uint8_t* data, size_t size);
+ ~VendorTagDescriptorFuzzer() {
+ mVendorTagDescriptor.clear();
+ mVendorTagDescriptorCache.clear();
+ }
+
+ private:
+ void initVendorTagDescriptor();
+ void invokeVendorTagDescriptor();
+ void invokeVendorTagDescriptorCache();
+ void invokeVendorTagErrorConditions();
+ sp<VendorTagDescriptor> mVendorTagDescriptor = nullptr;
+ sp<VendorTagDescriptorCache> mVendorTagDescriptorCache = nullptr;
+ FuzzedDataProvider* mFDP = nullptr;
+};
+
+void VendorTagDescriptorFuzzer::initVendorTagDescriptor() {
+ if (mFDP->ConsumeBool()) {
+ mVendorTagDescriptor = new VendorTagDescriptor();
+ } else {
+ const vendor_tag_ops_t* vOps = &fakevendor_ops;
+ VendorTagDescriptor::createDescriptorFromOps(vOps, mVendorTagDescriptor);
+ }
+}
+
+void VendorTagDescriptorFuzzer::invokeVendorTagDescriptor() {
+ initVendorTagDescriptor();
+
+ sp<VendorTagDescriptor> vdesc = new VendorTagDescriptor();
+ vdesc->copyFrom(*mVendorTagDescriptor);
+ VendorTagDescriptor::setAsGlobalVendorTagDescriptor(mVendorTagDescriptor);
+ VendorTagDescriptor::getGlobalVendorTagDescriptor();
+
+ int32_t tagCount = mVendorTagDescriptor->getTagCount();
+ if (tagCount > 0) {
+ uint32_t tagArray[tagCount];
+ mVendorTagDescriptor->getTagArray(tagArray);
+ uint32_t tag;
+ for (int32_t i = 0; i < tagCount; ++i) {
+ tag = tagArray[i];
+ get_local_camera_metadata_section_name_vendor_id(tag, kVendorTagDescriptorId);
+ get_local_camera_metadata_tag_name_vendor_id(tag, kVendorTagDescriptorId);
+ get_local_camera_metadata_tag_type_vendor_id(tag, kVendorTagDescriptorId);
+ mVendorTagDescriptor->getSectionIndex(tag);
+ }
+ mVendorTagDescriptor->getAllSectionNames();
+ }
+
+ String8 name((mFDP->ConsumeRandomLengthString()).c_str());
+ String8 section((mFDP->ConsumeRandomLengthString()).c_str());
+ uint32_t lookupTag;
+ mVendorTagDescriptor->lookupTag(name, section, &lookupTag);
+
+ int32_t fd = open("/dev/null", O_CLOEXEC | O_RDWR | O_CREAT);
+ int32_t verbosity = mFDP->ConsumeIntegralInRange<int32_t>(kRangeMin, kRangeMax);
+ int32_t indentation = mFDP->ConsumeIntegralInRange<int32_t>(kRangeMin, kRangeMax);
+ mVendorTagDescriptor->dump(fd, verbosity, indentation);
+
+ invokeReadWriteParcelsp<VendorTagDescriptor>(mVendorTagDescriptor);
+ VendorTagDescriptor::clearGlobalVendorTagDescriptor();
+ vdesc.clear();
+ close(fd);
+}
+
+void VendorTagDescriptorFuzzer::invokeVendorTagDescriptorCache() {
+ mVendorTagDescriptorCache = new VendorTagDescriptorCache();
+ uint64_t id = mFDP->ConsumeIntegral<uint64_t>();
+ initVendorTagDescriptor();
+
+ mVendorTagDescriptorCache->addVendorDescriptor(id, mVendorTagDescriptor);
+ VendorTagDescriptorCache::setAsGlobalVendorTagCache(mVendorTagDescriptorCache);
+ VendorTagDescriptorCache::getGlobalVendorTagCache();
+ sp<VendorTagDescriptor> tagDesc;
+ mVendorTagDescriptorCache->getVendorTagDescriptor(id, &tagDesc);
+
+ int32_t tagCount = mVendorTagDescriptorCache->getTagCount(id);
+ if (tagCount > 0) {
+ uint32_t tagArray[tagCount];
+ mVendorTagDescriptorCache->getTagArray(tagArray, id);
+ uint32_t tag;
+ for (int32_t i = 0; i < tagCount; ++i) {
+ tag = tagArray[i];
+ get_local_camera_metadata_section_name_vendor_id(tag, id);
+ get_local_camera_metadata_tag_name_vendor_id(tag, id);
+ get_local_camera_metadata_tag_type_vendor_id(tag, id);
+ }
+ }
+
+ int32_t fd = open("/dev/null", O_CLOEXEC | O_RDWR | O_CREAT);
+ int32_t verbosity = mFDP->ConsumeIntegralInRange<int>(kRangeMin, kRangeMax);
+ int32_t indentation = mFDP->ConsumeIntegralInRange<int>(kRangeMin, kRangeMax);
+ mVendorTagDescriptorCache->dump(fd, verbosity, indentation);
+
+ invokeReadWriteParcelsp<VendorTagDescriptorCache>(mVendorTagDescriptorCache);
+ VendorTagDescriptorCache::isVendorCachePresent(id);
+ mVendorTagDescriptorCache->getVendorIdsAndTagDescriptors();
+ mVendorTagDescriptorCache->clearGlobalVendorTagCache();
+ tagDesc.clear();
+ close(fd);
+}
+
+void VendorTagDescriptorFuzzer::invokeVendorTagErrorConditions() {
+ sp<VendorTagDescriptor> vDesc;
+ vendor_tag_ops_t vOps;
+ FillWithDefaults(&vOps);
+ vOps.get_tag_count = zero_get_tag_count;
+
+ if (mFDP->ConsumeBool()) {
+ VendorTagDescriptor::createDescriptorFromOps(/*vOps*/ NULL, vDesc);
+ } else {
+ VendorTagDescriptor::createDescriptorFromOps(&vOps, vDesc);
+ int32_t tagCount = vDesc->getTagCount();
+ uint32_t badTag = mFDP->ConsumeIntegral<uint32_t>();
+ uint32_t badTagArray[tagCount + 1];
+ vDesc->getTagArray(badTagArray);
+ vDesc->getSectionName(badTag);
+ vDesc->getTagName(badTag);
+ vDesc->getTagType(badTag);
+ VendorTagDescriptor::clearGlobalVendorTagDescriptor();
+ VendorTagDescriptor::getGlobalVendorTagDescriptor();
+ VendorTagDescriptor::setAsGlobalVendorTagDescriptor(vDesc);
+ invokeReadWriteNullParcelsp<VendorTagDescriptor>(vDesc);
+ vDesc.clear();
+ }
+}
+
+void VendorTagDescriptorFuzzer::process(const uint8_t* data, size_t size) {
+ mFDP = new FuzzedDataProvider(data, size);
+ invokeVendorTagDescriptor();
+ invokeVendorTagDescriptorCache();
+ invokeVendorTagErrorConditions();
+ delete mFDP;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ VendorTagDescriptorFuzzer vendorTagDescriptorFuzzer;
+ vendorTagDescriptorFuzzer.process(data, size);
+ return 0;
+}
diff --git a/media/janitors/media_solutions_OWNERS b/media/janitors/media_solutions_OWNERS
index 69e3a5e..e0c87f7 100644
--- a/media/janitors/media_solutions_OWNERS
+++ b/media/janitors/media_solutions_OWNERS
@@ -1,10 +1,21 @@
# Bug component: 1344
# go/android-fwk-media-solutions for info on areas of ownership.
-# Main owners:
+# MediaRouter and native mirroring only:
adadukin@google.com
aquilescanta@google.com
+bishoygendy@google.com
ivanbuper@google.com
-# In case of emergency:
-andrewlewis@google.com #{LAST_RESORT_SUGGESTION}
+# MediaMuxer, MediaRecorder, and seamless transcoding only:
+andrewlewis@google.com
+claincly@google.com
+
+# Everything in go/android-fwk-media-solutions not covered above:
+bachinger@google.com
+christosts@google.com
+ibaker@google.com
+michaelkatz@google.com
+rohks@google.com
+tianyifeng@google.com
+tonihei@google.com
diff --git a/media/libaudioclient/AudioPolicy.cpp b/media/libaudioclient/AudioPolicy.cpp
index 4d2b6b1..6bb0cbe 100644
--- a/media/libaudioclient/AudioPolicy.cpp
+++ b/media/libaudioclient/AudioPolicy.cpp
@@ -57,6 +57,10 @@
case RULE_EXCLUDE_USERID:
mValue.mUserId = (int) parcel->readInt32();
break;
+ case RULE_MATCH_AUDIO_SESSION_ID:
+ case RULE_EXCLUDE_AUDIO_SESSION_ID:
+ mValue.mAudioSessionId = (audio_session_t) parcel->readInt32();
+ break;
default:
ALOGE("Trying to build AudioMixMatchCriterion from unknown rule %d", mRule);
return BAD_VALUE;
diff --git a/media/libaudioclient/PolicyAidlConversion.cpp b/media/libaudioclient/PolicyAidlConversion.cpp
index 520f09c..4423eb6 100644
--- a/media/libaudioclient/PolicyAidlConversion.cpp
+++ b/media/libaudioclient/PolicyAidlConversion.cpp
@@ -158,6 +158,11 @@
convertIntegral<int>(UNION_GET(aidl, userId).value()));
*rule |= RULE_MATCH_USERID;
return legacy;
+ case media::AudioMixMatchCriterionValue::audioSessionId:
+ legacy.mAudioSessionId = VALUE_OR_RETURN(
+ aidl2legacy_int32_t_audio_session_t(UNION_GET(aidl, audioSessionId).value()));
+ *rule |= RULE_MATCH_AUDIO_SESSION_ID;
+ return legacy;
}
return unexpected(BAD_VALUE);
}
@@ -185,7 +190,10 @@
case RULE_MATCH_USERID:
UNION_SET(aidl, userId, VALUE_OR_RETURN(convertReinterpret<uint32_t>(legacy.mUserId)));
break;
-
+ case RULE_MATCH_AUDIO_SESSION_ID:
+ UNION_SET(aidl, audioSessionId,
+ VALUE_OR_RETURN(legacy2aidl_audio_session_t_int32_t(legacy.mAudioSessionId)));
+ break;
default:
return unexpected(BAD_VALUE);
}
diff --git a/media/libaudioclient/aidl/android/media/AudioMixMatchCriterionValue.aidl b/media/libaudioclient/aidl/android/media/AudioMixMatchCriterionValue.aidl
index 921a93a..0f373a2 100644
--- a/media/libaudioclient/aidl/android/media/AudioMixMatchCriterionValue.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioMixMatchCriterionValue.aidl
@@ -28,4 +28,6 @@
/** Interpreted as uid_t. */
int uid;
int userId;
+ /** Interpreted as audio_session_t. */
+ int audioSessionId;
}
diff --git a/media/libaudioclient/include/media/AudioPolicy.h b/media/libaudioclient/include/media/AudioPolicy.h
index cab476e..61f2069 100644
--- a/media/libaudioclient/include/media/AudioPolicy.h
+++ b/media/libaudioclient/include/media/AudioPolicy.h
@@ -34,11 +34,13 @@
#define RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET (0x1 << 1)
#define RULE_MATCH_UID (0x1 << 2)
#define RULE_MATCH_USERID (0x1 << 3)
+#define RULE_MATCH_AUDIO_SESSION_ID (0x1 << 4)
#define RULE_EXCLUDE_ATTRIBUTE_USAGE (RULE_EXCLUSION_MASK|RULE_MATCH_ATTRIBUTE_USAGE)
#define RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET \
(RULE_EXCLUSION_MASK|RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET)
#define RULE_EXCLUDE_UID (RULE_EXCLUSION_MASK|RULE_MATCH_UID)
#define RULE_EXCLUDE_USERID (RULE_EXCLUSION_MASK|RULE_MATCH_USERID)
+#define RULE_EXCLUDE_AUDIO_SESSION_ID (RULE_EXCLUSION_MASK|RULE_MATCH_AUDIO_SESSION_ID)
#define MIX_TYPE_INVALID (-1)
#define MIX_TYPE_PLAYERS 0
@@ -78,6 +80,7 @@
audio_source_t mSource;
uid_t mUid;
int mUserId;
+ audio_session_t mAudioSessionId;
} mValue;
uint32_t mRule;
};
diff --git a/media/libaudioclient/tests/audioclient_serialization_tests.cpp b/media/libaudioclient/tests/audioclient_serialization_tests.cpp
index 07e53f8..d1e3d16 100644
--- a/media/libaudioclient/tests/audioclient_serialization_tests.cpp
+++ b/media/libaudioclient/tests/audioclient_serialization_tests.cpp
@@ -66,16 +66,16 @@
decltype(audio_stream_type_from_string)>(xsdc_enum_range<xsd::AudioStreamType>{},
audio_stream_type_from_string);
-static const std::vector<uint32_t> kMixMatchRules = {
- RULE_MATCH_ATTRIBUTE_USAGE,
- RULE_EXCLUDE_ATTRIBUTE_USAGE,
- RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET,
- RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET,
- RULE_MATCH_UID,
- RULE_EXCLUDE_UID,
- RULE_MATCH_USERID,
- RULE_EXCLUDE_USERID,
-};
+static const std::vector<uint32_t> kMixMatchRules = {RULE_MATCH_ATTRIBUTE_USAGE,
+ RULE_EXCLUDE_ATTRIBUTE_USAGE,
+ RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET,
+ RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET,
+ RULE_MATCH_UID,
+ RULE_EXCLUDE_UID,
+ RULE_MATCH_USERID,
+ RULE_EXCLUDE_USERID,
+ RULE_MATCH_AUDIO_SESSION_ID,
+ RULE_EXCLUDE_AUDIO_SESSION_ID};
// Generates a random string.
std::string CreateRandomString(size_t n) {
diff --git a/media/libeffects/hapticgenerator/Android.bp b/media/libeffects/hapticgenerator/Android.bp
index 03ce329..ba511fe 100644
--- a/media/libeffects/hapticgenerator/Android.bp
+++ b/media/libeffects/hapticgenerator/Android.bp
@@ -46,10 +46,9 @@
shared_libs: [
"libaudioutils",
"libbase",
- "libbinder",
"liblog",
"libutils",
- "libvibrator",
+ "libvibratorutils",
],
relative_install_path: "soundfx",
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 6ef52c7..ad6e36a 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -3355,8 +3355,8 @@
MediaCodecInfo::Attributes attr = mCodecInfo
? mCodecInfo->getAttributes()
: MediaCodecInfo::Attributes(0);
- if (!(attr & MediaCodecInfo::kFlagIsSoftwareOnly)) {
- // software codec is currently ignored.
+ if (mDomain == DOMAIN_VIDEO || !(attr & MediaCodecInfo::kFlagIsSoftwareOnly)) {
+ // software audio codecs are currently ignored.
mResourceManagerProxy->addResource(MediaResource::CodecResource(
mFlags & kFlagIsSecure, toMediaResourceSubType(mDomain)));
}
diff --git a/media/libstagefright/colorconversion/fuzzer/Android.bp b/media/libstagefright/colorconversion/fuzzer/Android.bp
index 16020bc..76b054a 100644
--- a/media/libstagefright/colorconversion/fuzzer/Android.bp
+++ b/media/libstagefright/colorconversion/fuzzer/Android.bp
@@ -13,6 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+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_media_libstagefright_colorconversion_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: [
+ "frameworks_av_media_libstagefright_colorconversion_license",
+ ],
+}
+
cc_defaults {
name: "libcolorconversion_fuzzer_defaults",
static_libs: [
diff --git a/media/libstagefright/include/media/stagefright/MediaMuxer.h b/media/libstagefright/include/media/stagefright/MediaMuxer.h
index 6dc70bf..33aaf11 100644
--- a/media/libstagefright/include/media/stagefright/MediaMuxer.h
+++ b/media/libstagefright/include/media/stagefright/MediaMuxer.h
@@ -56,10 +56,6 @@
*/
static MediaMuxer* create(int fd, OutputFormat format);
- // Construct the muxer with the file descriptor. Note that the MediaMuxer
- // will close this file at stop().
- MediaMuxer(int fd, OutputFormat format);
-
virtual ~MediaMuxer();
/**
@@ -135,6 +131,11 @@
sp<AMessage> getTrackFormat(size_t idx);
private:
+ // Construct the muxer with the file descriptor. Note that the MediaMuxer
+ // will close this file at stop().
+ // This constructor is made private to ensure that MediaMuxer::create() is used instead.
+ MediaMuxer(int fd, OutputFormat format);
+
const OutputFormat mFormat;
sp<MediaWriter> mWriter;
Vector< sp<MediaAdapter> > mTrackList; // Each track has its MediaAdapter.
diff --git a/media/libstagefright/rtsp/AAVCAssembler.cpp b/media/libstagefright/rtsp/AAVCAssembler.cpp
index ddf797c..88f7be7 100644
--- a/media/libstagefright/rtsp/AAVCAssembler.cpp
+++ b/media/libstagefright/rtsp/AAVCAssembler.cpp
@@ -332,6 +332,11 @@
}
bool AAVCAssembler::dropFramesUntilIframe(const sp<ABuffer> &buffer) {
+ if (buffer->size() == 0) {
+ ALOGE("b/230630526 buffer->size() == 0");
+ android_errorWriteLog(0x534e4554, "230630526");
+ return false;
+ }
const uint8_t *data = buffer->data();
unsigned nalType = data[0] & 0x1f;
if (!mFirstIFrameProvided && nalType < 0x5) {
@@ -624,8 +629,7 @@
int32_t firstSeqNo = buffer->int32Data();
// This only works for FU-A type & non-start sequence
- int32_t nalType = buffer->size() >= 1 ? buffer->data()[0] & 0x1f : -1;
- if (nalType != 28 || (buffer->size() >= 2 && buffer->data()[1] & 0x80)) {
+ if (buffer->size() < 2 || (buffer->data()[0] & 0x1f) != 28 || buffer->data()[1] & 0x80) {
return firstSeqNo;
}
diff --git a/media/libstagefright/rtsp/AHEVCAssembler.cpp b/media/libstagefright/rtsp/AHEVCAssembler.cpp
index bb42d1f..72dd981 100644
--- a/media/libstagefright/rtsp/AHEVCAssembler.cpp
+++ b/media/libstagefright/rtsp/AHEVCAssembler.cpp
@@ -629,13 +629,13 @@
int32_t AHEVCAssembler::pickStartSeq(const Queue *queue,
uint32_t first, int64_t play, int64_t jit) {
+ CHECK(!queue->empty());
// pick the first sequence number has the start bit.
sp<ABuffer> buffer = *(queue->begin());
int32_t firstSeqNo = buffer->int32Data();
// This only works for FU-A type & non-start sequence
- unsigned nalType = buffer->data()[0] & 0x1f;
- if (nalType != 28 || buffer->data()[2] & 0x80) {
+ if (buffer->size() < 3 || (buffer->data()[0] & 0x1f) != 28 || buffer->data()[2] & 0x80) {
return firstSeqNo;
}
@@ -645,7 +645,7 @@
if (rtpTime + jit >= play) {
break;
}
- if ((data[2] & 0x80)) {
+ if (it->size() >= 3 && (data[2] & 0x80)) {
const int32_t seqNo = it->int32Data();
ALOGE("finding [HEAD] pkt. \t Seq# (%d ~ )[%d", firstSeqNo, seqNo);
firstSeqNo = seqNo;
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index ed31c02..b230df5 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -64,6 +64,10 @@
if (untranslated.find(err) == untranslated.end()) {
ALOGE("untranslated sf error code: %d", err);
+ char err_as_string[32];
+ snprintf(err_as_string, sizeof(err_as_string), "%d", err);
+ android_errorWriteWithInfoLog(0x534e4554, "224869524", -1,
+ err_as_string, strlen(err_as_string));
untranslated.insert(err);
}
}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/MuxerTest.java b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/MuxerTest.java
index 21ba957..7fd2752 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/MuxerTest.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/MuxerTest.java
@@ -60,14 +60,12 @@
private static final String mStatsFile =
mContext.getExternalFilesDir(null) + "/Muxer." + System.currentTimeMillis() + ".csv";
private static final String TAG = "MuxerTest";
- private static final Map<String, Integer> mMapFormat = new Hashtable<String, Integer>() {
- {
- put("mp4", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
- put("webm", MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM);
- put("3gpp", MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP);
- put("ogg", MediaMuxer.OutputFormat.MUXER_OUTPUT_OGG);
- }
- };
+ private static final Map<String, Integer> mMapFormat = Map.of(
+ "mp4", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4,
+ "webm", MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM,
+ "3gpp", MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP,
+ "ogg", MediaMuxer.OutputFormat.MUXER_OUTPUT_OGG);
+
private String mInputFileName;
private String mFormat;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index 3b19e52..7530132 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -72,13 +72,16 @@
*/
status_t getOutputForAttr(const audio_attributes_t& attributes,
const audio_config_base_t& config,
- uid_t uid, audio_output_flags_t flags,
+ uid_t uid,
+ audio_session_t session,
+ audio_output_flags_t flags,
sp<AudioPolicyMix> &primaryMix,
std::vector<sp<AudioPolicyMix>> *secondaryMixes);
sp<DeviceDescriptor> getDeviceAndMixForInputSource(const audio_attributes_t& attributes,
const DeviceVector &availableDeviceTypes,
uid_t uid,
+ audio_session_t session,
sp<AudioPolicyMix> *policyMix) const;
/**
@@ -124,11 +127,11 @@
void dump(String8 *dst) const;
private:
- enum class MixMatchStatus { MATCH, NO_MATCH };
- MixMatchStatus mixMatch(const AudioMix* mix, size_t mixIndex,
+ bool mixMatch(const AudioMix* mix, size_t mixIndex,
const audio_attributes_t& attributes,
const audio_config_base_t& config,
- uid_t uid);
+ uid_t uid,
+ audio_session_t session);
};
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 56c0603..3b9a855 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -34,7 +34,8 @@
// same result both for RULE_MATCH_X and RULE_EXCLUDE_X).
bool isCriterionMatched(const AudioMixMatchCriterion& criterion,
const audio_attributes_t& attr,
- const uid_t uid) {
+ const uid_t uid,
+ const audio_session_t session) {
uint32_t ruleWithoutExclusion = criterion.mRule & ~RULE_EXCLUSION_MASK;
switch(ruleWithoutExclusion) {
case RULE_MATCH_ATTRIBUTE_USAGE:
@@ -48,6 +49,8 @@
userid_t userId = multiuser_get_user_id(uid);
return criterion.mValue.mUserId == userId;
}
+ case RULE_MATCH_AUDIO_SESSION_ID:
+ return criterion.mValue.mAudioSessionId == session;
}
ALOGE("Encountered invalid mix rule 0x%x", criterion.mRule);
return false;
@@ -60,10 +63,11 @@
// for the criteria to match.
bool areMixCriteriaMatched(const std::vector<AudioMixMatchCriterion>& criteria,
const audio_attributes_t& attr,
- const uid_t uid) {
+ const uid_t uid,
+ const audio_session_t session) {
// If any of the exclusion criteria are matched the mix doesn't match.
auto isMatchingExcludeCriterion = [&](const AudioMixMatchCriterion& c) {
- return c.isExcludeCriterion() && isCriterionMatched(c, attr, uid);
+ return c.isExcludeCriterion() && isCriterionMatched(c, attr, uid, session);
};
if (std::any_of(criteria.begin(), criteria.end(), isMatchingExcludeCriterion)) {
return false;
@@ -76,7 +80,7 @@
continue;
}
presentPositiveRules |= criterion.mRule;
- if (isCriterionMatched(criterion, attr, uid)) {
+ if (isCriterionMatched(criterion, attr, uid, session)) {
matchedPositiveRules |= criterion.mRule;
}
}
@@ -150,6 +154,9 @@
case RULE_MATCH_USERID:
ruleValue = std::to_string(criterion.mValue.mUserId);
break;
+ case RULE_MATCH_AUDIO_SESSION_ID:
+ ruleValue = std::to_string(criterion.mValue.mAudioSessionId);
+ break;
default:
unknownRule = true;
}
@@ -241,7 +248,8 @@
}
status_t AudioPolicyMixCollection::getOutputForAttr(
- const audio_attributes_t& attributes, const audio_config_base_t& config, uid_t uid,
+ const audio_attributes_t& attributes, const audio_config_base_t& config, const uid_t uid,
+ const audio_session_t session,
audio_output_flags_t flags,
sp<AudioPolicyMix> &primaryMix,
std::vector<sp<AudioPolicyMix>> *secondaryMixes)
@@ -267,7 +275,7 @@
continue; // Primary output already found
}
- if(mixMatch(policyMix.get(), i, attributes, config, uid) == MixMatchStatus::NO_MATCH) {
+ if(!mixMatch(policyMix.get(), i, attributes, config, uid, session)) {
ALOGV("%s: Mix %zu: does not match", __func__, i);
continue; // skip the mix
}
@@ -285,9 +293,9 @@
return NO_ERROR;
}
-AudioPolicyMixCollection::MixMatchStatus AudioPolicyMixCollection::mixMatch(
- const AudioMix* mix, size_t mixIndex, const audio_attributes_t& attributes,
- const audio_config_base_t& config, uid_t uid) {
+bool AudioPolicyMixCollection::mixMatch(const AudioMix* mix, size_t mixIndex,
+ const audio_attributes_t& attributes, const audio_config_base_t& config,
+ uid_t uid, audio_session_t session) {
if (mix->mMixType == MIX_TYPE_PLAYERS) {
// Loopback render mixes are created from a public API and thus restricted
@@ -297,20 +305,20 @@
attributes.usage == AUDIO_USAGE_MEDIA ||
attributes.usage == AUDIO_USAGE_GAME ||
attributes.usage == AUDIO_USAGE_VOICE_COMMUNICATION)) {
- return MixMatchStatus::NO_MATCH;
+ return false;
}
auto hasFlag = [](auto flags, auto flag) { return (flags & flag) == flag; };
if (hasFlag(attributes.flags, AUDIO_FLAG_NO_SYSTEM_CAPTURE)) {
- return MixMatchStatus::NO_MATCH;
+ return false;
}
if (attributes.usage == AUDIO_USAGE_VOICE_COMMUNICATION) {
if (!mix->mVoiceCommunicationCaptureAllowed) {
- return MixMatchStatus::NO_MATCH;
+ return false;
}
} else if (!mix->mAllowPrivilegedMediaPlaybackCapture &&
hasFlag(attributes.flags, AUDIO_FLAG_NO_MEDIA_PROJECTION)) {
- return MixMatchStatus::NO_MATCH;
+ return false;
}
}
@@ -320,7 +328,7 @@
!((audio_is_linear_pcm(config.format) && audio_is_linear_pcm(mix->mFormat.format)) ||
(config.format == mix->mFormat.format)) &&
config.format != AUDIO_CONFIG_BASE_INITIALIZER.format) {
- return MixMatchStatus::NO_MATCH;
+ return false;
}
// if there is an address match, prioritize that match
@@ -329,12 +337,12 @@
mix->mDeviceAddress.string(),
AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) {
ALOGV("\tgetOutputForAttr will use mix %zu", mixIndex);
- return MixMatchStatus::MATCH;
+ return true;
}
- if (areMixCriteriaMatched(mix->mCriteria, attributes, uid)) {
+ if (areMixCriteriaMatched(mix->mCriteria, attributes, uid, session)) {
ALOGV("\tgetOutputForAttr will use mix %zu", mixIndex);
- return MixMatchStatus::MATCH;
+ return true;
}
} else if (mix->mMixType == MIX_TYPE_RECORDERS) {
if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE &&
@@ -342,10 +350,10 @@
strncmp(attributes.tags + strlen("addr="),
mix->mDeviceAddress.string(),
AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) {
- return MixMatchStatus::MATCH;
+ return true;
}
}
- return MixMatchStatus::NO_MATCH;
+ return false;
}
sp<DeviceDescriptor> AudioPolicyMixCollection::getDeviceAndMixForOutput(
@@ -369,6 +377,7 @@
const audio_attributes_t& attributes,
const DeviceVector &availDevices,
uid_t uid,
+ audio_session_t session,
sp<AudioPolicyMix> *policyMix) const
{
for (size_t i = 0; i < size(); i++) {
@@ -376,7 +385,7 @@
if (mix->mMixType != MIX_TYPE_RECORDERS) {
continue;
}
- if (areMixCriteriaMatched(mix->mCriteria, attributes, uid)) {
+ if (areMixCriteriaMatched(mix->mCriteria, attributes, uid, session)) {
// Assuming PolicyMix only for remote submix for input
// so mix->mDeviceType can only be AUDIO_DEVICE_OUT_REMOTE_SUBMIX.
auto mixDevice = availDevices.getDevice(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
diff --git a/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp b/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp
index c5b3546..8a44547 100644
--- a/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp
@@ -56,10 +56,12 @@
MAKE_STRING_FROM_ENUM(RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET),
MAKE_STRING_FROM_ENUM(RULE_MATCH_UID),
MAKE_STRING_FROM_ENUM(RULE_MATCH_USERID),
+ MAKE_STRING_FROM_ENUM(RULE_MATCH_AUDIO_SESSION_ID),
MAKE_STRING_FROM_ENUM(RULE_EXCLUDE_ATTRIBUTE_USAGE),
MAKE_STRING_FROM_ENUM(RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET),
MAKE_STRING_FROM_ENUM(RULE_EXCLUDE_UID),
MAKE_STRING_FROM_ENUM(RULE_EXCLUDE_USERID),
+ MAKE_STRING_FROM_ENUM(RULE_EXCLUDE_AUDIO_SESSION_ID),
TERMINATOR
};
diff --git a/services/audiopolicy/engine/interface/EngineInterface.h b/services/audiopolicy/engine/interface/EngineInterface.h
index 518f86e..70d25fc 100644
--- a/services/audiopolicy/engine/interface/EngineInterface.h
+++ b/services/audiopolicy/engine/interface/EngineInterface.h
@@ -173,10 +173,11 @@
* @param[out] mix to be used if a mix has been installed for the given audio attributes.
* @return selected input device for the audio attributes, may be null if error.
*/
- virtual sp<DeviceDescriptor> getInputDeviceForAttributes(const audio_attributes_t &attr,
- uid_t uid = 0,
- sp<AudioPolicyMix> *mix = nullptr)
- const = 0;
+ virtual sp<DeviceDescriptor> getInputDeviceForAttributes(
+ const audio_attributes_t &attr,
+ uid_t uid = 0,
+ audio_session_t session = AUDIO_SESSION_NONE,
+ sp<AudioPolicyMix> *mix = nullptr) const = 0;
/**
* Get the legacy stream type for a given audio attributes.
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp
index 2831a9b..9d53017 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp
@@ -315,6 +315,7 @@
sp<DeviceDescriptor> Engine::getInputDeviceForAttributes(const audio_attributes_t &attr,
uid_t uid,
+ audio_session_t session,
sp<AudioPolicyMix> *mix) const
{
const auto &policyMixes = getApmObserver()->getAudioPolicyMixCollection();
@@ -336,6 +337,7 @@
device = policyMixes.getDeviceAndMixForInputSource(attr,
availableInputDevices,
uid,
+ session,
mix);
if (device != nullptr) {
return device;
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.h b/services/audiopolicy/engineconfigurable/src/Engine.h
index 4b559f0..6ac20cd 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.h
+++ b/services/audiopolicy/engineconfigurable/src/Engine.h
@@ -63,6 +63,7 @@
sp<DeviceDescriptor> getInputDeviceForAttributes(const audio_attributes_t &attr,
uid_t uid = 0,
+ audio_session_t session = AUDIO_SESSION_NONE,
sp<AudioPolicyMix> *mix = nullptr)
const override;
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index a3a7e15..d96ae21 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -778,6 +778,7 @@
sp<DeviceDescriptor> Engine::getInputDeviceForAttributes(const audio_attributes_t &attr,
uid_t uid,
+ audio_session_t session,
sp<AudioPolicyMix> *mix) const
{
const auto &policyMixes = getApmObserver()->getAudioPolicyMixCollection();
@@ -800,6 +801,7 @@
device = policyMixes.getDeviceAndMixForInputSource(attr,
availableInputDevices,
uid,
+ session,
mix);
if (device != nullptr) {
return device;
diff --git a/services/audiopolicy/enginedefault/src/Engine.h b/services/audiopolicy/enginedefault/src/Engine.h
index 1efdf24..ab556ee 100644
--- a/services/audiopolicy/enginedefault/src/Engine.h
+++ b/services/audiopolicy/enginedefault/src/Engine.h
@@ -64,6 +64,7 @@
sp<DeviceDescriptor> getInputDeviceForAttributes(const audio_attributes_t &attr,
uid_t uid = 0,
+ audio_session_t session = AUDIO_SESSION_NONE,
sp<AudioPolicyMix> *mix = nullptr)
const override;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index c029719..199a1d5 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1169,8 +1169,8 @@
.channel_mask = config->channel_mask,
.format = config->format,
};
- status = mPolicyMixes.getOutputForAttr(*resultAttr, clientConfig, uid, *flags, primaryMix,
- secondaryMixes);
+ status = mPolicyMixes.getOutputForAttr(*resultAttr, clientConfig, uid, session, *flags,
+ primaryMix, secondaryMixes);
if (status != OK) {
return status;
}
@@ -2532,7 +2532,7 @@
} else {
// Prevent from storing invalid requested device id in clients
requestedDeviceId = AUDIO_PORT_HANDLE_NONE;
- device = mEngine->getInputDeviceForAttributes(attributes, uid, &policyMix);
+ device = mEngine->getInputDeviceForAttributes(attributes, uid, session, &policyMix);
ALOGV_IF(device != nullptr, "%s found device type is 0x%X",
__FUNCTION__, device->type());
}
@@ -2939,7 +2939,8 @@
bool close = false;
for (const auto& client : input->clientsList()) {
sp<DeviceDescriptor> device =
- mEngine->getInputDeviceForAttributes(client->attributes(), client->uid());
+ mEngine->getInputDeviceForAttributes(client->attributes(), client->uid(),
+ client->session());
if (!input->supportedDevices().contains(device)) {
close = true;
break;
@@ -6334,7 +6335,7 @@
}
sp<AudioPolicyMix> primaryMix;
status_t status = mPolicyMixes.getOutputForAttr(client->attributes(), client->config(),
- client->uid(), client->flags(), primaryMix, nullptr);
+ client->uid(), client->session(), client->flags(), primaryMix, nullptr);
if (status != OK) {
continue;
}
@@ -6447,7 +6448,7 @@
sp<AudioPolicyMix> primaryMix;
std::vector<sp<AudioPolicyMix>> secondaryMixes;
status_t status = mPolicyMixes.getOutputForAttr(client->attributes(), client->config(),
- client->uid(), client->flags(), primaryMix, &secondaryMixes);
+ client->uid(), client->session(), client->flags(), primaryMix, &secondaryMixes);
std::vector<sp<SwAudioOutputDescriptor>> secondaryDescs;
for (auto &secondaryMix : secondaryMixes) {
sp<SwAudioOutputDescriptor> outputDesc = secondaryMix->getOutput();
@@ -6655,20 +6656,23 @@
// a null sp<>, causing the patch on the input stream to be released.
audio_attributes_t attributes;
uid_t uid;
+ audio_session_t session;
sp<RecordClientDescriptor> topClient = inputDesc->getHighestPriorityClient();
if (topClient != nullptr) {
attributes = topClient->attributes();
uid = topClient->uid();
+ session = topClient->session();
} else {
attributes = { .source = AUDIO_SOURCE_DEFAULT };
uid = 0;
+ session = AUDIO_SESSION_NONE;
}
if (attributes.source == AUDIO_SOURCE_DEFAULT && isInCall()) {
attributes.source = AUDIO_SOURCE_VOICE_COMMUNICATION;
}
if (attributes.source != AUDIO_SOURCE_DEFAULT) {
- device = mEngine->getInputDeviceForAttributes(attributes, uid);
+ device = mEngine->getInputDeviceForAttributes(attributes, uid, session);
}
return device;
@@ -7863,7 +7867,7 @@
// audio routing, only used for duplication for playback capture)
sp<AudioPolicyMix> policyMix;
status_t status = mPolicyMixes.getOutputForAttr(attr, AUDIO_CONFIG_BASE_INITIALIZER,
- 0 /*uid unknown here*/, AUDIO_OUTPUT_FLAG_NONE, policyMix,
+ 0 /*uid unknown here*/, AUDIO_SESSION_NONE, AUDIO_OUTPUT_FLAG_NONE, policyMix,
nullptr /* secondaryMixes */);
if (status != OK) {
return status;
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index d51c57c..e1bf414 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <cstring>
#include <memory>
#include <string>
#include <sys/wait.h>
@@ -66,6 +67,14 @@
return criterion;
}
+AudioMixMatchCriterion createSessionIdCriterion(audio_session_t session, bool exclude = false) {
+ AudioMixMatchCriterion criterion;
+ criterion.mValue.mAudioSessionId = session;
+ criterion.mRule = exclude ?
+ RULE_EXCLUDE_AUDIO_SESSION_ID : RULE_MATCH_AUDIO_SESSION_ID;
+ return criterion;
+}
+
} // namespace
TEST(AudioPolicyManagerTestInit, EngineFailure) {
@@ -151,9 +160,11 @@
audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
audio_io_handle_t *output = nullptr,
audio_port_handle_t *portId = nullptr,
- audio_attributes_t attr = {});
+ audio_attributes_t attr = {},
+ audio_session_t session = AUDIO_SESSION_NONE);
void getInputForAttr(
const audio_attributes_t &attr,
+ audio_session_t session,
audio_unique_id_t riid,
audio_port_handle_t *selectedDeviceId,
audio_format_t format,
@@ -233,7 +244,8 @@
audio_output_flags_t flags,
audio_io_handle_t *output,
audio_port_handle_t *portId,
- audio_attributes_t attr) {
+ audio_attributes_t attr,
+ audio_session_t session) {
audio_io_handle_t localOutput;
if (!output) output = &localOutput;
*output = AUDIO_IO_HANDLE_NONE;
@@ -252,7 +264,7 @@
attributionSource.uid = 0;
attributionSource.token = sp<BBinder>::make();
ASSERT_EQ(OK, mManager->getOutputForAttr(
- &attr, output, AUDIO_SESSION_NONE, &stream, attributionSource, &config, &flags,
+ &attr, output, session, &stream, attributionSource, &config, &flags,
selectedDeviceId, portId, {}, &outputType, &isSpatialized));
ASSERT_NE(AUDIO_PORT_HANDLE_NONE, *portId);
ASSERT_NE(AUDIO_IO_HANDLE_NONE, *output);
@@ -260,6 +272,7 @@
void AudioPolicyManagerTest::getInputForAttr(
const audio_attributes_t &attr,
+ const audio_session_t session,
audio_unique_id_t riid,
audio_port_handle_t *selectedDeviceId,
audio_format_t format,
@@ -281,7 +294,7 @@
attributionSource.uid = 0;
attributionSource.token = sp<BBinder>::make();
ASSERT_EQ(OK, mManager->getInputForAttr(
- &attr, &input, riid, AUDIO_SESSION_NONE, attributionSource, &config, flags,
+ &attr, &input, riid, session, attributionSource, &config, flags,
selectedDeviceId, &inputType, portId));
ASSERT_NE(AUDIO_PORT_HANDLE_NONE, *portId);
}
@@ -914,8 +927,8 @@
audio_source_t source = AUDIO_SOURCE_VOICE_COMMUNICATION;
audio_attributes_t attr = {
AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, source, AUDIO_FLAG_NONE, ""};
- ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, 1, &selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT,
- AUDIO_CHANNEL_IN_MONO, 8000, AUDIO_INPUT_FLAG_VOIP_TX, &mixPortId));
+ ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, AUDIO_SESSION_NONE, 1, &selectedDeviceId,
+ AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 8000, AUDIO_INPUT_FLAG_VOIP_TX, &mixPortId));
std::vector<audio_port_v7> ports;
ASSERT_NO_FATAL_FAILURE(
@@ -1352,19 +1365,45 @@
ASSERT_EQ(INVALID_OPERATION, ret);
}
+struct DPTestParam {
+ DPTestParam(const std::vector<AudioMixMatchCriterion>& mixCriteria,
+ bool expected_match = false)
+ : mixCriteria(mixCriteria), attributes(defaultAttr), session(AUDIO_SESSION_NONE),
+ expected_match(expected_match) {}
+
+ DPTestParam& withUsage(audio_usage_t usage) {
+ attributes.usage = usage;
+ return *this;
+ }
+
+ DPTestParam& withTags(const char *tags) {
+ std::strncpy(attributes.tags, tags, sizeof(attributes.tags));
+ return *this;
+ }
+
+ DPTestParam& withSource(audio_source_t source) {
+ attributes.source = source;
+ return *this;
+ }
+
+ DPTestParam& withSessionId(audio_session_t sessionId) {
+ session = sessionId;
+ return *this;
+ }
+
+ std::vector<AudioMixMatchCriterion> mixCriteria;
+ audio_attributes_t attributes;
+ audio_session_t session;
+ bool expected_match;
+};
+
class AudioPolicyManagerTestDPPlaybackReRouting : public AudioPolicyManagerTestDynamicPolicy,
- public testing::WithParamInterface<audio_attributes_t> {
+ public testing::WithParamInterface<DPTestParam> {
protected:
void SetUp() override;
void TearDown() override;
std::unique_ptr<RecordingActivityTracker> mTracker;
-
- std::vector<AudioMixMatchCriterion> mUsageRules = {
- createUsageCriterion(AUDIO_USAGE_MEDIA),
- createUsageCriterion(AUDIO_USAGE_ALARM)
- };
-
struct audio_port_v7 mInjectionPort;
audio_port_handle_t mPortId = AUDIO_PORT_HANDLE_NONE;
};
@@ -1378,8 +1417,10 @@
audioConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
audioConfig.sample_rate = k48000SamplingRate;
+
+ DPTestParam param = GetParam();
status_t ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_LOOP_BACK,
- AUDIO_DEVICE_OUT_REMOTE_SUBMIX, mMixAddress, audioConfig, mUsageRules);
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX, mMixAddress, audioConfig, param.mixCriteria);
ASSERT_EQ(NO_ERROR, ret);
struct audio_port_v7 extractionPort;
@@ -1392,8 +1433,9 @@
AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, source, AUDIO_FLAG_NONE, ""};
std::string tags = "addr=" + mMixAddress;
strncpy(attr.tags, tags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
- getInputForAttr(attr, mTracker->getRiid(), &selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT,
- AUDIO_CHANNEL_IN_STEREO, k48000SamplingRate, AUDIO_INPUT_FLAG_NONE, &mPortId);
+ getInputForAttr(attr, param.session, mTracker->getRiid(), &selectedDeviceId,
+ AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO, k48000SamplingRate,
+ AUDIO_INPUT_FLAG_NONE, &mPortId);
ASSERT_EQ(NO_ERROR, mManager->startInput(mPortId));
ASSERT_EQ(extractionPort.id, selectedDeviceId);
@@ -1406,152 +1448,160 @@
AudioPolicyManagerTestDynamicPolicy::TearDown();
}
-TEST_F(AudioPolicyManagerTestDPPlaybackReRouting, InitSuccess) {
- // SetUp must finish with no assertions
-}
-
-TEST_F(AudioPolicyManagerTestDPPlaybackReRouting, Dump) {
- dumpToLog();
-}
-
TEST_P(AudioPolicyManagerTestDPPlaybackReRouting, PlaybackReRouting) {
- const audio_attributes_t attr = GetParam();
- const audio_usage_t usage = attr.usage;
+ const DPTestParam param = GetParam();
+ const audio_attributes_t& attr = param.attributes;
audio_port_handle_t playbackRoutedPortId = AUDIO_PORT_HANDLE_NONE;
getOutputForAttr(&playbackRoutedPortId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
k48000SamplingRate, AUDIO_OUTPUT_FLAG_NONE, nullptr /*output*/, nullptr /*portId*/,
- attr);
- if (std::find_if(begin(mUsageRules), end(mUsageRules),
- [&usage](const AudioMixMatchCriterion &c) {
- return c.mRule == RULE_MATCH_ATTRIBUTE_USAGE &&
- c.mValue.mUsage == usage;}) != end(mUsageRules) ||
- (strncmp(attr.tags, "addr=", strlen("addr=")) == 0 &&
- strncmp(attr.tags + strlen("addr="), mMixAddress.c_str(),
- AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0)) {
+ attr, param.session);
+ if (param.expected_match) {
EXPECT_EQ(mInjectionPort.id, playbackRoutedPortId);
} else {
EXPECT_NE(mInjectionPort.id, playbackRoutedPortId);
}
}
-INSTANTIATE_TEST_CASE_P(
- PlaybackReroutingUsageMatch,
- AudioPolicyManagerTestDPPlaybackReRouting,
- testing::Values(
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_MEDIA,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_ALARM,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""}
- )
- );
+const std::vector<AudioMixMatchCriterion> USAGE_MEDIA_ALARM_CRITERIA = {
+ createUsageCriterion(AUDIO_USAGE_MEDIA),
+ createUsageCriterion(AUDIO_USAGE_ALARM)
+};
-INSTANTIATE_TEST_CASE_P(
- PlaybackReroutingAddressPriorityMatch,
- AudioPolicyManagerTestDPPlaybackReRouting,
- testing::Values(
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_MEDIA,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, "addr=remote_submix_media"},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_VOICE_COMMUNICATION,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, "addr=remote_submix_media"},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
- AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, "addr=remote_submix_media"},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_ALARM,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, "addr=remote_submix_media"},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_NOTIFICATION,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, "addr=remote_submix_media"},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
- AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, "addr=remote_submix_media"},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
- AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, "addr=remote_submix_media"},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
- AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, "addr=remote_submix_media"},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
- AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, "addr=remote_submix_media"},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_NOTIFICATION_EVENT,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, "addr=remote_submix_media"},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
- AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, "addr=remote_submix_media"},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
- AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, "addr=remote_submix_media"},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
- AUDIO_USAGE_ASSISTANCE_SONIFICATION,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, "addr=remote_submix_media"},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_GAME,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, "addr=remote_submix_media"},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_VIRTUAL_SOURCE,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, "addr=remote_submix_media"},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_ASSISTANT,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, "addr=remote_submix_media"},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_SPEECH, AUDIO_USAGE_ASSISTANT,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, "addr=remote_submix_media"}
- )
- );
+INSTANTIATE_TEST_SUITE_P(
+ PlaybackReroutingUsageMatch,
+ AudioPolicyManagerTestDPPlaybackReRouting,
+ testing::Values(
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ true)
+ .withUsage(AUDIO_USAGE_MEDIA),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ true)
+ .withUsage(AUDIO_USAGE_MEDIA).withTags("addr=other"),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ true)
+ .withUsage(AUDIO_USAGE_ALARM),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ false)
+ .withUsage(AUDIO_USAGE_VOICE_COMMUNICATION),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ false)
+ .withUsage(AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ false)
+ .withUsage(AUDIO_USAGE_NOTIFICATION),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ false)
+ .withUsage(AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ false)
+ .withUsage(AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ false)
+ .withUsage(AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ false)
+ .withUsage(AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ false)
+ .withUsage(AUDIO_USAGE_NOTIFICATION_EVENT),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ false)
+ .withUsage(AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ false)
+ .withUsage(AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ false)
+ .withUsage(AUDIO_USAGE_ASSISTANCE_SONIFICATION),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ false)
+ .withUsage(AUDIO_USAGE_GAME),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ false)
+ .withUsage(AUDIO_USAGE_ASSISTANT)));
-INSTANTIATE_TEST_CASE_P(
- PlaybackReroutingUnHandledUsages,
- AudioPolicyManagerTestDPPlaybackReRouting,
- testing::Values(
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_VOICE_COMMUNICATION,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
- AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_NOTIFICATION,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
- AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
- AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
- AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
- AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_NOTIFICATION_EVENT,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
- AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
- AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
- AUDIO_USAGE_ASSISTANCE_SONIFICATION,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_GAME,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_ASSISTANT,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_SPEECH, AUDIO_USAGE_ASSISTANT,
- AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""}
- )
- );
+INSTANTIATE_TEST_SUITE_P(
+ PlaybackReroutingAddressPriorityMatch,
+ AudioPolicyManagerTestDPPlaybackReRouting,
+ testing::Values(
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ true)
+ .withUsage(AUDIO_USAGE_MEDIA).withTags("addr=remote_submix_media"),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ true)
+ .withUsage(AUDIO_USAGE_VOICE_COMMUNICATION).withTags("addr=remote_submix_media"),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ true)
+ .withUsage(AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING)
+ .withTags("addr=remote_submix_media"),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ true)
+ .withUsage(AUDIO_USAGE_ALARM)
+ .withTags("addr=remote_submix_media"),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ true)
+ .withUsage(AUDIO_USAGE_NOTIFICATION)
+ .withTags("addr=remote_submix_media"),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ true)
+ .withUsage(AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE)
+ .withTags("addr=remote_submix_media"),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ true)
+ .withUsage(AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST)
+ .withTags("addr=remote_submix_media"),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ true)
+ .withUsage(AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT)
+ .withTags("addr=remote_submix_media"),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ true)
+ .withUsage(AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED)
+ .withTags("addr=remote_submix_media"),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ true)
+ .withUsage(AUDIO_USAGE_NOTIFICATION_EVENT)
+ .withTags("addr=remote_submix_media"),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ true)
+ .withUsage(AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY)
+ .withTags("addr=remote_submix_media"),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ true)
+ .withUsage(AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
+ .withTags("addr=remote_submix_media"),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ true)
+ .withUsage(AUDIO_USAGE_ASSISTANCE_SONIFICATION)
+ .withTags("addr=remote_submix_media"),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ true)
+ .withUsage(AUDIO_USAGE_GAME)
+ .withTags("addr=remote_submix_media"),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ true)
+ .withUsage(AUDIO_USAGE_VIRTUAL_SOURCE)
+ .withTags("addr=remote_submix_media"),
+ DPTestParam(USAGE_MEDIA_ALARM_CRITERIA, /*expected_match=*/ true)
+ .withUsage(AUDIO_USAGE_ASSISTANT)
+ .withTags("addr=remote_submix_media")));
+
+static constexpr audio_session_t TEST_SESSION_ID = static_cast<audio_session_t>(42);
+static constexpr audio_session_t OTHER_SESSION_ID = static_cast<audio_session_t>(77);
+
+INSTANTIATE_TEST_SUITE_P(
+ PlaybackReRoutingWithSessionId,
+ AudioPolicyManagerTestDPPlaybackReRouting,
+ testing::Values(
+ // Mix is matched because the session id matches the one specified by the mix rule.
+ DPTestParam(/*mixCriteria=*/ {createSessionIdCriterion(TEST_SESSION_ID)},
+ /*expected_match=*/ true)
+ .withSessionId(TEST_SESSION_ID),
+ // Mix is not matched because the session id doesn't match the one specified
+ // by the mix rule.
+ DPTestParam(/*mixCriteria=*/ {createSessionIdCriterion(TEST_SESSION_ID)},
+ /*expected_match=*/ false)
+ .withSessionId(OTHER_SESSION_ID),
+ // Mix is matched, the session id doesn't match the one specified by rule,
+ // but there's address specified in the tags which takes precedence.
+ DPTestParam(/*mixCriteria=*/ {createSessionIdCriterion(TEST_SESSION_ID)},
+ /*expected_match=*/ true)
+ .withSessionId(OTHER_SESSION_ID).withTags("addr=remote_submix_media"),
+ // Mix is matched, both the session id and the usage match ones specified by mix rule.
+ DPTestParam(/*mixCriteria=*/ {createSessionIdCriterion(TEST_SESSION_ID),
+ createUsageCriterion(AUDIO_USAGE_MEDIA)},
+ /*expected_match=*/ true)
+ .withSessionId(TEST_SESSION_ID).withUsage(AUDIO_USAGE_MEDIA),
+ // Mix is not matched, the session id matches the one specified by mix rule,
+ // but usage does not.
+ DPTestParam(/*mixCriteria=*/ {createSessionIdCriterion(TEST_SESSION_ID),
+ createUsageCriterion(AUDIO_USAGE_MEDIA)},
+ /*expected_match=*/ false)
+ .withSessionId(TEST_SESSION_ID).withUsage(AUDIO_USAGE_GAME),
+ // Mix is not matched, the usage matches the one specified by mix rule,
+ // but the session id is excluded.
+ DPTestParam(/*mixCriteria=*/ {createSessionIdCriterion(TEST_SESSION_ID, /*exclude=*/ true),
+ createUsageCriterion(AUDIO_USAGE_MEDIA)},
+ /*expected_match=*/ false)
+ .withSessionId(TEST_SESSION_ID).withUsage(AUDIO_USAGE_MEDIA)));
class AudioPolicyManagerTestDPMixRecordInjection : public AudioPolicyManagerTestDynamicPolicy,
- public testing::WithParamInterface<audio_attributes_t> {
+ public testing::WithParamInterface<DPTestParam> {
protected:
void SetUp() override;
void TearDown() override;
std::unique_ptr<RecordingActivityTracker> mTracker;
-
- std::vector<AudioMixMatchCriterion> mSourceRules = {
- createCapturePresetCriterion(AUDIO_SOURCE_CAMCORDER),
- createCapturePresetCriterion(AUDIO_SOURCE_MIC),
- createCapturePresetCriterion(AUDIO_SOURCE_VOICE_COMMUNICATION)
- };
-
struct audio_port_v7 mExtractionPort;
audio_port_handle_t mPortId = AUDIO_PORT_HANDLE_NONE;
};
@@ -1565,8 +1615,10 @@
audioConfig.channel_mask = AUDIO_CHANNEL_IN_STEREO;
audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
audioConfig.sample_rate = k48000SamplingRate;
+
+ DPTestParam param = GetParam();
status_t ret = addPolicyMix(MIX_TYPE_RECORDERS, MIX_ROUTE_FLAG_LOOP_BACK,
- AUDIO_DEVICE_IN_REMOTE_SUBMIX, mMixAddress, audioConfig, mSourceRules);
+ AUDIO_DEVICE_IN_REMOTE_SUBMIX, mMixAddress, audioConfig, param.mixCriteria);
ASSERT_EQ(NO_ERROR, ret);
struct audio_port_v7 injectionPort;
@@ -1593,73 +1645,94 @@
AudioPolicyManagerTestDynamicPolicy::TearDown();
}
-TEST_F(AudioPolicyManagerTestDPMixRecordInjection, InitSuccess) {
- // SetUp mush finish with no assertions.
-}
-
-TEST_F(AudioPolicyManagerTestDPMixRecordInjection, Dump) {
- dumpToLog();
-}
-
TEST_P(AudioPolicyManagerTestDPMixRecordInjection, RecordingInjection) {
- const audio_attributes_t attr = GetParam();
- const audio_source_t source = attr.source;
+ const DPTestParam param = GetParam();
audio_port_handle_t captureRoutedPortId = AUDIO_PORT_HANDLE_NONE;
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
- getInputForAttr(attr, mTracker->getRiid(), &captureRoutedPortId, AUDIO_FORMAT_PCM_16_BIT,
- AUDIO_CHANNEL_IN_STEREO, k48000SamplingRate, AUDIO_INPUT_FLAG_NONE, &portId);
- if (std::find_if(begin(mSourceRules), end(mSourceRules),
- [&source](const AudioMixMatchCriterion &c) {
- return c.mRule == RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET &&
- c.mValue.mSource == source;})
- != end(mSourceRules)) {
+ getInputForAttr(param.attributes, param.session, mTracker->getRiid(), &captureRoutedPortId,
+ AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO, k48000SamplingRate,
+ AUDIO_INPUT_FLAG_NONE, &portId);
+ if (param.expected_match) {
EXPECT_EQ(mExtractionPort.id, captureRoutedPortId);
} else {
EXPECT_NE(mExtractionPort.id, captureRoutedPortId);
}
}
+const std::vector<AudioMixMatchCriterion> SOURCE_CAM_MIC_VOICE_CRITERIA = {
+ createCapturePresetCriterion(AUDIO_SOURCE_CAMCORDER),
+ createCapturePresetCriterion(AUDIO_SOURCE_MIC),
+ createCapturePresetCriterion(AUDIO_SOURCE_VOICE_COMMUNICATION)
+};
+
// No address priority rule for remote recording, address is a "don't care"
INSTANTIATE_TEST_CASE_P(
- RecordInjectionSourceMatch,
+ RecordInjectionSource,
AudioPolicyManagerTestDPMixRecordInjection,
testing::Values(
- (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
- AUDIO_SOURCE_CAMCORDER, AUDIO_FLAG_NONE, ""},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
- AUDIO_SOURCE_CAMCORDER, AUDIO_FLAG_NONE,
- "addr=remote_submix_media"},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
- AUDIO_SOURCE_MIC, AUDIO_FLAG_NONE,
- "addr=remote_submix_media"},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
- AUDIO_SOURCE_MIC, AUDIO_FLAG_NONE, ""},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
- AUDIO_SOURCE_VOICE_COMMUNICATION, AUDIO_FLAG_NONE, ""},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
- AUDIO_SOURCE_VOICE_COMMUNICATION, AUDIO_FLAG_NONE,
- "addr=remote_submix_media"}
- )
- );
+ DPTestParam(SOURCE_CAM_MIC_VOICE_CRITERIA, /*expected_match=*/ true)
+ .withSource(AUDIO_SOURCE_CAMCORDER),
+ DPTestParam(SOURCE_CAM_MIC_VOICE_CRITERIA, /*expected_match=*/ true)
+ .withSource(AUDIO_SOURCE_CAMCORDER)
+ .withTags("addr=remote_submix_media"),
+ DPTestParam(SOURCE_CAM_MIC_VOICE_CRITERIA, /*expected_match=*/ true)
+ .withSource(AUDIO_SOURCE_MIC),
+ DPTestParam(SOURCE_CAM_MIC_VOICE_CRITERIA, /*expected_match=*/ true)
+ .withSource(AUDIO_SOURCE_MIC)
+ .withTags("addr=remote_submix_media"),
+ DPTestParam(SOURCE_CAM_MIC_VOICE_CRITERIA, /*expected_match=*/ true)
+ .withSource(AUDIO_SOURCE_VOICE_COMMUNICATION),
+ DPTestParam(SOURCE_CAM_MIC_VOICE_CRITERIA, /*expected_match=*/ true)
+ .withSource(AUDIO_SOURCE_VOICE_COMMUNICATION)
+ .withTags("addr=remote_submix_media"),
+ DPTestParam(SOURCE_CAM_MIC_VOICE_CRITERIA, /*expected_match=*/ false)
+ .withSource(AUDIO_SOURCE_VOICE_RECOGNITION),
+ DPTestParam(SOURCE_CAM_MIC_VOICE_CRITERIA, /*expected_match=*/ false)
+ .withSource(AUDIO_SOURCE_VOICE_RECOGNITION)
+ .withTags("addr=remote_submix_media"),
+ DPTestParam(SOURCE_CAM_MIC_VOICE_CRITERIA, /*expected_match=*/ false)
+ .withSource(AUDIO_SOURCE_HOTWORD),
+ DPTestParam(SOURCE_CAM_MIC_VOICE_CRITERIA, /*expected_match=*/ false)
+ .withSource(AUDIO_SOURCE_HOTWORD)
+ .withTags("addr=remote_submix_media")));
-// No address priority rule for remote recording
INSTANTIATE_TEST_CASE_P(
- RecordInjectionSourceNotMatch,
+ RecordInjectionWithSessionId,
AudioPolicyManagerTestDPMixRecordInjection,
testing::Values(
- (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
- AUDIO_SOURCE_VOICE_RECOGNITION, AUDIO_FLAG_NONE, ""},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
- AUDIO_SOURCE_HOTWORD, AUDIO_FLAG_NONE, ""},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
- AUDIO_SOURCE_VOICE_RECOGNITION, AUDIO_FLAG_NONE,
- "addr=remote_submix_media"},
- (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
- AUDIO_SOURCE_HOTWORD, AUDIO_FLAG_NONE,
- "addr=remote_submix_media"}
- )
- );
+ // Mix is matched because the session id matches the one specified by the mix rule.
+ DPTestParam(/*mixCriteria=*/ {createSessionIdCriterion(TEST_SESSION_ID)},
+ /*expected_match=*/ true)
+ .withSessionId(TEST_SESSION_ID),
+ // Mix is not matched because the session id doesn't match the one specified
+ // by the mix rule.
+ DPTestParam(/*mixCriteria=*/ {createSessionIdCriterion(TEST_SESSION_ID)},
+ /*expected_match=*/ false)
+ .withSessionId(OTHER_SESSION_ID),
+ // Mix is not matched, the session id doesn't match the one specified by rule,
+ // but tand address specified in the tags is ignored for recorder mix.
+ DPTestParam(/*mixCriteria=*/ {createSessionIdCriterion(TEST_SESSION_ID)},
+ /*expected_match=*/ false)
+ .withSessionId(OTHER_SESSION_ID).withTags("addr=remote_submix_media"),
+ // Mix is matched, both the session id and the source match ones specified by mix rule
+ DPTestParam(/*mixCriteria=*/ {createSessionIdCriterion(TEST_SESSION_ID),
+ createCapturePresetCriterion(AUDIO_SOURCE_CAMCORDER)},
+ /*expected_match=*/ true)
+ .withSessionId(TEST_SESSION_ID).withSource(AUDIO_SOURCE_CAMCORDER),
+ // Mix is not matched, the session id matches the one specified by mix rule,
+ // but source does not.
+ DPTestParam(/*mixCriteria=*/ {createSessionIdCriterion(TEST_SESSION_ID),
+ createCapturePresetCriterion(AUDIO_SOURCE_CAMCORDER)},
+ /*expected_match=*/ false)
+ .withSessionId(TEST_SESSION_ID).withSource(AUDIO_SOURCE_MIC),
+ // Mix is not matched, the source matches the one specified by mix rule,
+ // but the session id is excluded.
+ DPTestParam(/*mixCriteria=*/ {createSessionIdCriterion(TEST_SESSION_ID,
+ /*exclude=*/ true),
+ createCapturePresetCriterion(AUDIO_SOURCE_MIC)},
+ /*expected_match=*/ false)
+ .withSessionId(TEST_SESSION_ID).withSource(AUDIO_SOURCE_MIC)));
using DeviceConnectionTestParams =
std::tuple<audio_devices_t /*type*/, std::string /*name*/, std::string /*address*/>;
@@ -1762,8 +1835,9 @@
k48000SamplingRate, AUDIO_OUTPUT_FLAG_NONE);
} else if (audio_is_input_device(type)) {
RecordingActivityTracker tracker;
- getInputForAttr({}, tracker.getRiid(), &routedPortId, AUDIO_FORMAT_PCM_16_BIT,
- AUDIO_CHANNEL_IN_STEREO, k48000SamplingRate, AUDIO_INPUT_FLAG_NONE);
+ getInputForAttr({}, AUDIO_SESSION_NONE, tracker.getRiid(), &routedPortId,
+ AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO, k48000SamplingRate,
+ AUDIO_INPUT_FLAG_NONE);
}
ASSERT_EQ(devicePort.id, routedPortId);