Merge "Remove references to libc_scudo."
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 818548d..4ad780c 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -49,10 +49,8 @@
path: "aidl",
}
-aidl_interface {
- name: "resourcemanager_aidl_interface",
- unstable: true,
- local_include_dir: "aidl",
+filegroup {
+ name: "resourcemanager_aidl",
srcs: [
"aidl/android/media/IResourceManagerClient.aidl",
"aidl/android/media/IResourceManagerService.aidl",
@@ -61,6 +59,16 @@
"aidl/android/media/MediaResourceParcel.aidl",
"aidl/android/media/MediaResourcePolicyParcel.aidl",
],
+ path: "aidl",
+}
+
+aidl_interface {
+ name: "resourcemanager_aidl_interface",
+ unstable: true,
+ local_include_dir: "aidl",
+ srcs: [
+ ":resourcemanager_aidl",
+ ],
}
cc_library_shared {
diff --git a/media/libmediatranscoding/Android.bp b/media/libmediatranscoding/Android.bp
index b6dca8d..bd6621a 100644
--- a/media/libmediatranscoding/Android.bp
+++ b/media/libmediatranscoding/Android.bp
@@ -48,6 +48,8 @@
"TranscodingClientManager.cpp",
"TranscodingJobScheduler.cpp",
"TranscodingUidPolicy.cpp",
+ "TranscoderWrapper.cpp",
+ "NdkCommon.cpp",
],
shared_libs: [
@@ -57,6 +59,7 @@
"libutils",
"libmediatranscoder",
"libbinder",
+ "libmediandk",
],
export_include_dirs: ["include"],
diff --git a/media/libmediatranscoding/NdkCommon.cpp b/media/libmediatranscoding/NdkCommon.cpp
new file mode 100644
index 0000000..0461a90
--- /dev/null
+++ b/media/libmediatranscoding/NdkCommon.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//#define LOG_NDEBUG 0
+#define LOG_TAG "NdkCommon"
+#include <log/log.h>
+#include <media/NdkCommon.h>
+
+#include <cstdio>
+#include <cstring>
+#include <utility>
+
+/* TODO(b/153592281)
+ * Note: constants used by the native media tests but not available in media ndk api
+ */
+const char* AMEDIA_MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8";
+const char* AMEDIA_MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9";
+const char* AMEDIA_MIMETYPE_VIDEO_AV1 = "video/av01";
+const char* AMEDIA_MIMETYPE_VIDEO_AVC = "video/avc";
+const char* AMEDIA_MIMETYPE_VIDEO_HEVC = "video/hevc";
+const char* AMEDIA_MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es";
+const char* AMEDIA_MIMETYPE_VIDEO_H263 = "video/3gpp";
+
+/* TODO(b/153592281) */
+const char* TBD_AMEDIACODEC_PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync";
+const char* TBD_AMEDIACODEC_PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate";
+const char* TBD_AMEDIACODEC_PARAMETER_KEY_MAX_B_FRAMES = "max-bframes";
+const char* TBD_AMEDIAFORMAT_KEY_BIT_RATE_MODE = "bitrate-mode";
diff --git a/media/libmediatranscoding/TranscoderWrapper.cpp b/media/libmediatranscoding/TranscoderWrapper.cpp
new file mode 100644
index 0000000..86cb86a
--- /dev/null
+++ b/media/libmediatranscoding/TranscoderWrapper.cpp
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "TranscoderWrapper"
+
+#include <aidl/android/media/TranscodingErrorCode.h>
+#include <aidl/android/media/TranscodingRequestParcel.h>
+#include <media/MediaTranscoder.h>
+#include <media/NdkCommon.h>
+#include <media/TranscoderWrapper.h>
+#include <utils/Log.h>
+
+#include <thread>
+
+namespace android {
+using Status = ::ndk::ScopedAStatus;
+using ::aidl::android::media::TranscodingErrorCode;
+using ::aidl::android::media::TranscodingVideoCodecType;
+using ::aidl::android::media::TranscodingVideoTrackFormat;
+
+static TranscodingErrorCode toTranscodingError(media_status_t status) {
+ switch (status) {
+ case AMEDIA_OK:
+ return TranscodingErrorCode::kNoError;
+ case AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE: // FALLTHRU
+ case AMEDIACODEC_ERROR_RECLAIMED:
+ return TranscodingErrorCode::kInsufficientResources;
+ case AMEDIA_ERROR_MALFORMED:
+ return TranscodingErrorCode::kMalformed;
+ case AMEDIA_ERROR_UNSUPPORTED:
+ return TranscodingErrorCode::kUnsupported;
+ case AMEDIA_ERROR_INVALID_OBJECT: // FALLTHRU
+ case AMEDIA_ERROR_INVALID_PARAMETER:
+ return TranscodingErrorCode::kInvalidParameter;
+ case AMEDIA_ERROR_INVALID_OPERATION:
+ return TranscodingErrorCode::kInvalidOperation;
+ case AMEDIA_ERROR_IO:
+ return TranscodingErrorCode::kErrorIO;
+ case AMEDIA_ERROR_UNKNOWN: // FALLTHRU
+ default:
+ return TranscodingErrorCode::kUnknown;
+ }
+}
+
+//static
+const char* TranscoderWrapper::toString(Event::Type type) {
+ switch (type) {
+ case Event::Start:
+ return "Start";
+ case Event::Pause:
+ return "Pause";
+ case Event::Resume:
+ return "Resume";
+ case Event::Stop:
+ return "Stop";
+ case Event::Finish:
+ return "Finish";
+ case Event::Error:
+ return "Error";
+ default:
+ break;
+ }
+ return "(unknown)";
+}
+
+class TranscoderWrapper::CallbackImpl : public MediaTranscoder::CallbackInterface {
+public:
+ CallbackImpl(const std::shared_ptr<TranscoderWrapper>& owner, ClientIdType clientId,
+ JobIdType jobId)
+ : mOwner(owner), mClientId(clientId), mJobId(jobId) {}
+
+ virtual void onFinished(const MediaTranscoder* transcoder __unused) override {
+ auto owner = mOwner.lock();
+ if (owner != nullptr) {
+ owner->onFinish(mClientId, mJobId);
+ }
+ }
+
+ virtual void onError(const MediaTranscoder* transcoder __unused,
+ media_status_t error) override {
+ auto owner = mOwner.lock();
+ if (owner != nullptr) {
+ owner->onError(mClientId, mJobId, toTranscodingError(error));
+ }
+ }
+
+ virtual void onProgressUpdate(const MediaTranscoder* transcoder __unused,
+ int32_t progress) override {
+ ALOGV("%s: job {%lld, %d}, progress %d", __FUNCTION__, (long long)mClientId, mJobId,
+ progress);
+ }
+
+ virtual void onCodecResourceLost(const MediaTranscoder* transcoder __unused,
+ const std::shared_ptr<const Parcelable>& pausedState
+ __unused) override {
+ ALOGV("%s: job {%lld, %d}", __FUNCTION__, (long long)mClientId, mJobId);
+ }
+
+private:
+ std::weak_ptr<TranscoderWrapper> mOwner;
+ ClientIdType mClientId;
+ JobIdType mJobId;
+};
+
+TranscoderWrapper::TranscoderWrapper() : mCurrentClientId(0), mCurrentJobId(-1) {
+ std::thread(&TranscoderWrapper::threadLoop, this).detach();
+}
+
+void TranscoderWrapper::setCallback(const std::shared_ptr<TranscoderCallbackInterface>& cb) {
+ mCallback = cb;
+}
+
+void TranscoderWrapper::start(ClientIdType clientId, JobIdType jobId,
+ const TranscodingRequestParcel& request,
+ const std::shared_ptr<ITranscodingClientCallback>& callback) {
+ queueEvent(Event::Start, clientId, jobId, [=] {
+ TranscodingErrorCode err = handleStart(clientId, jobId, request, callback);
+
+ if (err != TranscodingErrorCode::kNoError) {
+ cleanup();
+
+ auto callback = mCallback.lock();
+ if (callback != nullptr) {
+ callback->onError(clientId, jobId, err);
+ }
+ }
+ });
+}
+
+void TranscoderWrapper::pause(ClientIdType clientId, JobIdType jobId) {
+ queueEvent(Event::Pause, clientId, jobId, [] {});
+}
+
+void TranscoderWrapper::resume(ClientIdType clientId, JobIdType jobId) {
+ queueEvent(Event::Resume, clientId, jobId, [] {});
+}
+
+void TranscoderWrapper::stop(ClientIdType clientId, JobIdType jobId) {
+ queueEvent(Event::Stop, clientId, jobId, [=] {
+ if (clientId != mCurrentClientId || jobId != mCurrentJobId) {
+ ALOGW("Stopping job {%lld, %d} that's not current job {%lld, %d}", (long long)clientId,
+ jobId, (long long)mCurrentClientId, mCurrentJobId);
+ }
+
+ // stop transcoder.
+ media_status_t err = mTranscoder->cancel();
+ if (err != AMEDIA_OK) {
+ ALOGE("failed to stop transcoder: %d", err);
+ } else {
+ ALOGI("transcoder stopped");
+ }
+
+ cleanup();
+ });
+}
+
+void TranscoderWrapper::onFinish(ClientIdType clientId, JobIdType jobId) {
+ queueEvent(Event::Finish, clientId, jobId, [=] {
+ cleanup();
+
+ auto callback = mCallback.lock();
+ if (callback != nullptr) {
+ callback->onFinish(clientId, jobId);
+ }
+ });
+}
+
+void TranscoderWrapper::onError(ClientIdType clientId, JobIdType jobId,
+ TranscodingErrorCode error) {
+ queueEvent(Event::Error, clientId, jobId, [=] {
+ cleanup();
+
+ auto callback = mCallback.lock();
+ if (callback != nullptr) {
+ callback->onError(clientId, jobId, error);
+ }
+ });
+}
+
+static AMediaFormat* getVideoFormat(
+ const char* originalMime,
+ const std::optional<TranscodingVideoTrackFormat>& requestedFormat) {
+ if (requestedFormat == std::nullopt) {
+ return nullptr;
+ }
+
+ AMediaFormat* format = AMediaFormat_new();
+ bool changed = false;
+ if (requestedFormat->codecType == TranscodingVideoCodecType::kHevc
+ && strcmp(originalMime, AMEDIA_MIMETYPE_VIDEO_HEVC)) {
+ AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_HEVC);
+ changed = true;
+ } else if (requestedFormat->codecType == TranscodingVideoCodecType::kAvc
+ && strcmp(originalMime, AMEDIA_MIMETYPE_VIDEO_AVC)) {
+ AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_AVC);
+ changed = true;
+ }
+ if (requestedFormat->bitrateBps > 0) {
+ AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, requestedFormat->bitrateBps);
+ changed = true;
+ }
+ // TODO: translate other fields from requestedFormat to the format for MediaTranscoder.
+ // Also need to determine more settings to expose in TranscodingVideoTrackFormat.
+ if (!changed) {
+ AMediaFormat_delete(format);
+ // Use null format for passthru.
+ format = nullptr;
+ }
+ return format;
+}
+
+TranscodingErrorCode TranscoderWrapper::handleStart(
+ ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& request,
+ const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
+ if (clientCb == nullptr) {
+ ALOGE("client callback is null");
+ return TranscodingErrorCode::kInvalidParameter;
+ }
+
+ if (mTranscoder != nullptr) {
+ ALOGE("transcoder already running");
+ return TranscodingErrorCode::kInvalidOperation;
+ }
+
+ Status status;
+ ::ndk::ScopedFileDescriptor srcFd, dstFd;
+ status = clientCb->openFileDescriptor(request.sourceFilePath, "r", &srcFd);
+ if (!status.isOk() || srcFd.get() < 0) {
+ ALOGE("failed to open source");
+ return TranscodingErrorCode::kErrorIO;
+ }
+
+ status = clientCb->openFileDescriptor(request.destinationFilePath, "w", &dstFd);
+ if (!status.isOk() || dstFd.get() < 0) {
+ ALOGE("failed to open destination");
+ return TranscodingErrorCode::kErrorIO;
+ }
+
+ mCurrentClientId = clientId;
+ mCurrentJobId = jobId;
+ mTranscoderCb = std::make_shared<CallbackImpl>(shared_from_this(), clientId, jobId);
+ mTranscoder = MediaTranscoder::create(mTranscoderCb, nullptr);
+ if (mTranscoder == nullptr) {
+ ALOGE("failed to create transcoder");
+ return TranscodingErrorCode::kUnknown;
+ }
+
+ media_status_t err = mTranscoder->configureSource(srcFd.get());
+ if (err != AMEDIA_OK) {
+ ALOGE("failed to configure source: %d", err);
+ return toTranscodingError(err);
+ }
+
+ std::vector<std::shared_ptr<AMediaFormat>> trackFormats = mTranscoder->getTrackFormats();
+ if (trackFormats.size() == 0) {
+ ALOGE("failed to get track formats!");
+ return TranscodingErrorCode::kMalformed;
+ }
+
+ for (int i = 0; i < trackFormats.size(); ++i) {
+ AMediaFormat* format = nullptr;
+ const char* mime = nullptr;
+ AMediaFormat_getString(trackFormats[i].get(), AMEDIAFORMAT_KEY_MIME, &mime);
+
+ if (!strncmp(mime, "video/", 6)) {
+ format = getVideoFormat(mime, request.requestedVideoTrackFormat);
+ }
+
+ err = mTranscoder->configureTrackFormat(i, format);
+ if (format != nullptr) {
+ AMediaFormat_delete(format);
+ }
+ if (err != AMEDIA_OK) {
+ ALOGE("failed to configure track format for track %d: %d", i, err);
+ return toTranscodingError(err);
+ }
+ }
+
+ err = mTranscoder->configureDestination(dstFd.get());
+ if (err != AMEDIA_OK) {
+ ALOGE("failed to configure dest: %d", err);
+ return toTranscodingError(err);
+ }
+
+ err = mTranscoder->start();
+ if (err != AMEDIA_OK) {
+ ALOGE("failed to start transcoder: %d", err);
+ return toTranscodingError(err);
+ }
+
+ ALOGI("transcoder started");
+ return TranscodingErrorCode::kNoError;
+}
+
+void TranscoderWrapper::cleanup() {
+ mCurrentClientId = 0;
+ mCurrentJobId = -1;
+ mTranscoderCb = nullptr;
+ mTranscoder = nullptr;
+}
+
+void TranscoderWrapper::queueEvent(Event::Type type, ClientIdType clientId, JobIdType jobId,
+ const std::function<void()> runnable) {
+ ALOGV("%s: job {%lld, %d}: %s", __FUNCTION__, (long long)clientId, jobId, toString(type));
+
+ std::scoped_lock lock{mLock};
+
+ mQueue.push_back({type, clientId, jobId, runnable});
+ mCondition.notify_one();
+}
+
+void TranscoderWrapper::threadLoop() {
+ std::unique_lock<std::mutex> lock{mLock};
+ // TranscoderWrapper currently lives in the transcoding service, as long as
+ // MediaTranscodingService itself.
+ while (true) {
+ // Wait for the next event.
+ while (mQueue.empty()) {
+ mCondition.wait(lock);
+ }
+
+ Event event = *mQueue.begin();
+ mQueue.pop_front();
+
+ ALOGD("%s: job {%lld, %d}: %s", __FUNCTION__, (long long)event.clientId, event.jobId,
+ toString(event.type));
+
+ event.runnable();
+ }
+}
+
+} // namespace android
diff --git a/media/libmediatranscoding/TranscodingJobScheduler.cpp b/media/libmediatranscoding/TranscodingJobScheduler.cpp
index d5ae2a3..3256384 100644
--- a/media/libmediatranscoding/TranscodingJobScheduler.cpp
+++ b/media/libmediatranscoding/TranscodingJobScheduler.cpp
@@ -76,7 +76,8 @@
// the topJob now.
if (!mResourceLost) {
if (topJob->state == Job::NOT_STARTED) {
- mTranscoder->start(topJob->key.first, topJob->key.second, topJob->request);
+ mTranscoder->start(topJob->key.first, topJob->key.second, topJob->request,
+ topJob->callback.lock());
} else if (topJob->state == Job::PAUSED) {
mTranscoder->resume(topJob->key.first, topJob->key.second);
}
@@ -349,7 +350,8 @@
{
auto clientCallback = mJobMap[jobKey].callback.lock();
if (clientCallback != nullptr) {
- clientCallback->onTranscodingFinished(jobId, TranscodingResultParcel({jobId, -1 /*actualBitrateBps*/}));
+ clientCallback->onTranscodingFinished(
+ jobId, TranscodingResultParcel({jobId, -1 /*actualBitrateBps*/}));
}
}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingErrorCode.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingErrorCode.aidl
index 7f47fdc..b044d41 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingErrorCode.aidl
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingErrorCode.aidl
@@ -23,11 +23,12 @@
*/
@Backing(type = "int")
enum TranscodingErrorCode {
- kUnknown = 0,
- kUnsupported = 1,
- kDecoderError = 2,
- kEncoderError = 3,
- kExtractorError = 4,
- kMuxerError = 5,
- kInvalidBitstream = 6
+ kNoError = 0,
+ kUnknown = 1,
+ kMalformed = 2,
+ kUnsupported = 3,
+ kInvalidParameter = 4,
+ kInvalidOperation = 5,
+ kErrorIO = 6,
+ kInsufficientResources = 7,
}
\ No newline at end of file
diff --git a/media/libmediatranscoding/include/media/NdkCommon.h b/media/libmediatranscoding/include/media/NdkCommon.h
new file mode 100644
index 0000000..63bee58
--- /dev/null
+++ b/media/libmediatranscoding/include/media/NdkCommon.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_TRANSCODING_NDK_COMMON_H
+#define ANDROID_MEDIA_TRANSCODING_NDK_COMMON_H
+
+#include <media/NdkMediaFormat.h>
+
+extern const char* AMEDIA_MIMETYPE_VIDEO_VP8;
+extern const char* AMEDIA_MIMETYPE_VIDEO_VP9;
+extern const char* AMEDIA_MIMETYPE_VIDEO_AV1;
+extern const char* AMEDIA_MIMETYPE_VIDEO_AVC;
+extern const char* AMEDIA_MIMETYPE_VIDEO_HEVC;
+extern const char* AMEDIA_MIMETYPE_VIDEO_MPEG4;
+extern const char* AMEDIA_MIMETYPE_VIDEO_H263;
+
+// TODO(b/146420990)
+// TODO: make MediaTranscoder use the consts from this header.
+typedef enum {
+ OUTPUT_FORMAT_START = 0,
+ OUTPUT_FORMAT_MPEG_4 = OUTPUT_FORMAT_START,
+ OUTPUT_FORMAT_WEBM = OUTPUT_FORMAT_START + 1,
+ OUTPUT_FORMAT_THREE_GPP = OUTPUT_FORMAT_START + 2,
+ OUTPUT_FORMAT_HEIF = OUTPUT_FORMAT_START + 3,
+ OUTPUT_FORMAT_OGG = OUTPUT_FORMAT_START + 4,
+ OUTPUT_FORMAT_LIST_END = OUTPUT_FORMAT_START + 4,
+} MuxerFormat;
+
+// Color formats supported by encoder - should mirror supportedColorList
+// from MediaCodecConstants.h (are these going to be deprecated)
+static constexpr int COLOR_FormatYUV420SemiPlanar = 21;
+static constexpr int COLOR_FormatYUV420Flexible = 0x7F420888;
+static constexpr int COLOR_FormatSurface = 0x7f000789;
+
+// constants not defined in NDK
+extern const char* TBD_AMEDIACODEC_PARAMETER_KEY_REQUEST_SYNC_FRAME;
+extern const char* TBD_AMEDIACODEC_PARAMETER_KEY_VIDEO_BITRATE;
+extern const char* TBD_AMEDIACODEC_PARAMETER_KEY_MAX_B_FRAMES;
+extern const char* TBD_AMEDIAFORMAT_KEY_BIT_RATE_MODE;
+static constexpr int TBD_AMEDIACODEC_BUFFER_FLAG_KEY_FRAME = 0x1;
+
+static constexpr int kBitrateModeConstant = 2;
+
+#endif // ANDROID_MEDIA_TRANSCODING_NDK_COMMON_H
diff --git a/media/libmediatranscoding/include/media/TranscoderInterface.h b/media/libmediatranscoding/include/media/TranscoderInterface.h
index 97b7126..85e0164 100644
--- a/media/libmediatranscoding/include/media/TranscoderInterface.h
+++ b/media/libmediatranscoding/include/media/TranscoderInterface.h
@@ -17,12 +17,14 @@
#ifndef ANDROID_MEDIA_TRANSCODER_INTERFACE_H
#define ANDROID_MEDIA_TRANSCODER_INTERFACE_H
+#include <aidl/android/media/ITranscodingClientCallback.h>
#include <aidl/android/media/TranscodingErrorCode.h>
#include <aidl/android/media/TranscodingRequestParcel.h>
#include <media/TranscodingDefs.h>
namespace android {
+using ::aidl::android::media::ITranscodingClientCallback;
using ::aidl::android::media::TranscodingErrorCode;
using ::aidl::android::media::TranscodingRequestParcel;
class TranscoderCallbackInterface;
@@ -34,7 +36,8 @@
// For now, always pass in clientId&jobId.
virtual void setCallback(const std::shared_ptr<TranscoderCallbackInterface>& cb) = 0;
virtual void start(ClientIdType clientId, JobIdType jobId,
- const TranscodingRequestParcel& request) = 0;
+ const TranscodingRequestParcel& request,
+ const std::shared_ptr<ITranscodingClientCallback>& clientCallback) = 0;
virtual void pause(ClientIdType clientId, JobIdType jobId) = 0;
virtual void resume(ClientIdType clientId, JobIdType jobId) = 0;
virtual void stop(ClientIdType clientId, JobIdType jobId) = 0;
diff --git a/media/libmediatranscoding/include/media/TranscoderWrapper.h b/media/libmediatranscoding/include/media/TranscoderWrapper.h
new file mode 100644
index 0000000..3da05b2
--- /dev/null
+++ b/media/libmediatranscoding/include/media/TranscoderWrapper.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_TRANSCODER_WRAPPER_H
+#define ANDROID_TRANSCODER_WRAPPER_H
+
+#include <android-base/thread_annotations.h>
+#include <media/TranscoderInterface.h>
+
+#include <list>
+#include <mutex>
+
+namespace android {
+
+class MediaTranscoder;
+
+/*
+ * Wrapper class around MediaTranscoder.
+ * Implements TranscoderInterface for TranscodingJobScheduler to use.
+ */
+class TranscoderWrapper : public TranscoderInterface,
+ public std::enable_shared_from_this<TranscoderWrapper> {
+public:
+ TranscoderWrapper();
+
+ virtual void setCallback(const std::shared_ptr<TranscoderCallbackInterface>& cb) override;
+ virtual void start(ClientIdType clientId, JobIdType jobId,
+ const TranscodingRequestParcel& request,
+ const std::shared_ptr<ITranscodingClientCallback>& clientCallback) override;
+ virtual void pause(ClientIdType clientId, JobIdType jobId) override;
+ virtual void resume(ClientIdType clientId, JobIdType jobId) override;
+ virtual void stop(ClientIdType clientId, JobIdType jobId) override;
+
+private:
+ class CallbackImpl;
+ struct Event {
+ enum Type { NoEvent, Start, Pause, Resume, Stop, Finish, Error } type;
+ ClientIdType clientId;
+ JobIdType jobId;
+ std::function<void()> runnable;
+ };
+ std::shared_ptr<CallbackImpl> mTranscoderCb;
+ std::shared_ptr<MediaTranscoder> mTranscoder;
+ std::weak_ptr<TranscoderCallbackInterface> mCallback;
+ std::mutex mLock;
+ std::condition_variable mCondition;
+ std::list<Event> mQueue; // GUARDED_BY(mLock);
+ ClientIdType mCurrentClientId;
+ JobIdType mCurrentJobId;
+
+ static const char* toString(Event::Type type);
+ void onFinish(ClientIdType clientId, JobIdType jobId);
+ void onError(ClientIdType clientId, JobIdType jobId, TranscodingErrorCode error);
+
+ TranscodingErrorCode handleStart(ClientIdType clientId, JobIdType jobId,
+ const TranscodingRequestParcel& request,
+ const std::shared_ptr<ITranscodingClientCallback>& callback);
+
+ void cleanup();
+ void queueEvent(Event::Type type, ClientIdType clientId, JobIdType jobId,
+ const std::function<void()> runnable);
+ void threadLoop();
+};
+
+} // namespace android
+#endif // ANDROID_TRANSCODER_WRAPPER_H
diff --git a/media/libmediatranscoding/include/media/TranscodingRequest.h b/media/libmediatranscoding/include/media/TranscodingRequest.h
index 6bc9db6..63de1fb 100644
--- a/media/libmediatranscoding/include/media/TranscodingRequest.h
+++ b/media/libmediatranscoding/include/media/TranscodingRequest.h
@@ -38,6 +38,7 @@
sourceFilePath = parcel.sourceFilePath;
destinationFilePath = parcel.destinationFilePath;
transcodingType = parcel.transcodingType;
+ requestedVideoTrackFormat = parcel.requestedVideoTrackFormat;
priority = parcel.priority;
requestProgressUpdate = parcel.requestProgressUpdate;
requestJobEventUpdate = parcel.requestJobEventUpdate;
diff --git a/media/libmediatranscoding/tests/TranscodingJobScheduler_tests.cpp b/media/libmediatranscoding/tests/TranscodingJobScheduler_tests.cpp
index b9bebac..1931a0e 100644
--- a/media/libmediatranscoding/tests/TranscodingJobScheduler_tests.cpp
+++ b/media/libmediatranscoding/tests/TranscodingJobScheduler_tests.cpp
@@ -87,8 +87,8 @@
// TranscoderInterface
void setCallback(const std::shared_ptr<TranscoderCallbackInterface>& /*cb*/) override {}
- void start(ClientIdType clientId, JobIdType jobId,
- const TranscodingRequestParcel& /*request*/) override {
+ void start(ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& /*request*/,
+ const std::shared_ptr<ITranscodingClientCallback>& /*clientCallback*/) override {
mEventQueue.push_back(Start(clientId, jobId));
}
void pause(ClientIdType clientId, JobIdType jobId) override {
@@ -433,9 +433,9 @@
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
// Fail running offline job, and test error code propagation.
- mScheduler->onError(CLIENT(0), JOB(0), TranscodingErrorCode::kInvalidBitstream);
+ mScheduler->onError(CLIENT(0), JOB(0), TranscodingErrorCode::kInvalidOperation);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), JOB(0)));
- EXPECT_EQ(mTranscoder->getLastError(), TranscodingErrorCode::kInvalidBitstream);
+ EXPECT_EQ(mTranscoder->getLastError(), TranscodingErrorCode::kInvalidOperation);
// Duplicate fail for last job, should be ignored.
mScheduler->onError(CLIENT(0), JOB(0), TranscodingErrorCode::kUnknown);
diff --git a/media/libmediatranscoding/transcoder/MediaTranscoder.cpp b/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
index 3db7455..cee3702 100644
--- a/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
@@ -95,8 +95,7 @@
// Transcoding is done and the callback to the client has been sent, so tear down the
// pipeline but do it asynchronously to avoid deadlocks. If an error occurred, client
// should clean up the file.
- std::thread asyncCancelThread{
- [self = shared_from_this()] { self->cancel(); }};
+ std::thread asyncCancelThread{[self = shared_from_this()] { self->cancel(); }};
asyncCancelThread.detach();
}
}
@@ -116,7 +115,7 @@
}
MediaTranscoder::MediaTranscoder(const std::shared_ptr<CallbackInterface>& callbacks)
- : mCallbacks(callbacks) {}
+ : mCallbacks(callbacks) {}
std::shared_ptr<MediaTranscoder> MediaTranscoder::create(
const std::shared_ptr<CallbackInterface>& callbacks,
diff --git a/services/mediatranscoding/Android.bp b/services/mediatranscoding/Android.bp
index 065870a..bfcf01f 100644
--- a/services/mediatranscoding/Android.bp
+++ b/services/mediatranscoding/Android.bp
@@ -10,6 +10,7 @@
shared_libs: [
"libbase",
"libbinder_ndk",
+ "libcutils",
"liblog",
"libmediatranscoding",
"libutils",
diff --git a/services/mediatranscoding/MediaTranscodingService.cpp b/services/mediatranscoding/MediaTranscodingService.cpp
index b843967..2b97c2e 100644
--- a/services/mediatranscoding/MediaTranscodingService.cpp
+++ b/services/mediatranscoding/MediaTranscodingService.cpp
@@ -20,6 +20,8 @@
#include <android/binder_manager.h>
#include <android/binder_process.h>
+#include <cutils/properties.h>
+#include <media/TranscoderWrapper.h>
#include <media/TranscodingClientManager.h>
#include <media/TranscodingJobScheduler.h>
#include <media/TranscodingUidPolicy.h>
@@ -51,19 +53,14 @@
}
}
-MediaTranscodingService::MediaTranscodingService()
- : MediaTranscodingService(std::make_shared<SimulatedTranscoder>(),
- std::make_shared<TranscodingUidPolicy>()) {}
-
MediaTranscodingService::MediaTranscodingService(
- const std::shared_ptr<TranscoderInterface>& transcoder,
- const std::shared_ptr<UidPolicyInterface>& uidPolicy)
- : mJobScheduler(new TranscodingJobScheduler(transcoder, uidPolicy)),
+ const std::shared_ptr<TranscoderInterface>& transcoder)
+ : mUidPolicy(new TranscodingUidPolicy()),
+ mJobScheduler(new TranscodingJobScheduler(transcoder, mUidPolicy)),
mClientManager(new TranscodingClientManager(mJobScheduler)) {
ALOGV("MediaTranscodingService is created");
-
transcoder->setCallback(mJobScheduler);
- uidPolicy->setCallback(mJobScheduler);
+ mUidPolicy->setCallback(mJobScheduler);
}
MediaTranscodingService::~MediaTranscodingService() {
@@ -86,8 +83,15 @@
//static
void MediaTranscodingService::instantiate() {
+ std::shared_ptr<TranscoderInterface> transcoder;
+ if (property_get_bool("debug.transcoding.simulated_transcoder", true)) {
+ transcoder = std::make_shared<SimulatedTranscoder>();
+ } else {
+ transcoder = std::make_shared<TranscoderWrapper>();
+ }
+
std::shared_ptr<MediaTranscodingService> service =
- ::ndk::SharedRefBase::make<MediaTranscodingService>();
+ ::ndk::SharedRefBase::make<MediaTranscodingService>(transcoder);
binder_status_t status =
AServiceManager_addService(service->asBinder().get(), getServiceName());
if (status != STATUS_OK) {
diff --git a/services/mediatranscoding/MediaTranscodingService.h b/services/mediatranscoding/MediaTranscodingService.h
index f7ac336..505239c 100644
--- a/services/mediatranscoding/MediaTranscodingService.h
+++ b/services/mediatranscoding/MediaTranscodingService.h
@@ -38,9 +38,7 @@
static constexpr int32_t kInvalidJobId = -1;
static constexpr int32_t kInvalidClientId = -1;
- MediaTranscodingService();
- MediaTranscodingService(const std::shared_ptr<TranscoderInterface>& transcoder,
- const std::shared_ptr<UidPolicyInterface>& uidPolicy);
+ MediaTranscodingService(const std::shared_ptr<TranscoderInterface>& transcoder);
virtual ~MediaTranscodingService();
static void instantiate();
@@ -61,6 +59,7 @@
mutable std::mutex mServiceLock;
+ std::shared_ptr<UidPolicyInterface> mUidPolicy;
std::shared_ptr<TranscodingJobScheduler> mJobScheduler;
std::shared_ptr<TranscodingClientManager> mClientManager;
};
diff --git a/services/mediatranscoding/SimulatedTranscoder.cpp b/services/mediatranscoding/SimulatedTranscoder.cpp
index 380d757..cdced2d 100644
--- a/services/mediatranscoding/SimulatedTranscoder.cpp
+++ b/services/mediatranscoding/SimulatedTranscoder.cpp
@@ -47,8 +47,9 @@
mCallback = cb;
}
-void SimulatedTranscoder::start(ClientIdType clientId, JobIdType jobId,
- const TranscodingRequestParcel& request) {
+void SimulatedTranscoder::start(
+ ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& request,
+ const std::shared_ptr<ITranscodingClientCallback>& /*clientCallback*/) {
if (request.testConfig.processingTotalTimeMs > 0) {
mJobProcessingTimeMs = request.testConfig.processingTotalTimeMs;
}
diff --git a/services/mediatranscoding/SimulatedTranscoder.h b/services/mediatranscoding/SimulatedTranscoder.h
index 0eb74c8..030222b 100644
--- a/services/mediatranscoding/SimulatedTranscoder.h
+++ b/services/mediatranscoding/SimulatedTranscoder.h
@@ -51,8 +51,8 @@
// TranscoderInterface
void setCallback(const std::shared_ptr<TranscoderCallbackInterface>& cb) override;
- void start(ClientIdType clientId, JobIdType jobId,
- const TranscodingRequestParcel& request) override;
+ void start(ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& request,
+ const std::shared_ptr<ITranscodingClientCallback>& clientCallback) override;
void pause(ClientIdType clientId, JobIdType jobId) override;
void resume(ClientIdType clientId, JobIdType jobId) override;
void stop(ClientIdType clientId, JobIdType jobId) override;
diff --git a/services/mediatranscoding/tests/Android.bp b/services/mediatranscoding/tests/Android.bp
index f37b39e..cec2dc1 100644
--- a/services/mediatranscoding/tests/Android.bp
+++ b/services/mediatranscoding/tests/Android.bp
@@ -27,16 +27,24 @@
],
}
-// MediaTranscodingService unit test
+// MediaTranscodingService unit test using simulated transcoder
cc_test {
- name: "mediatranscodingservice_tests",
+ name: "mediatranscodingservice_simulated_tests",
defaults: ["mediatranscodingservice_test_defaults"],
- srcs: ["mediatranscodingservice_tests.cpp"],
+ srcs: ["mediatranscodingservice_simulated_tests.cpp"],
required: [
":TranscodingUidPolicy_TestAppA",
":TranscodingUidPolicy_TestAppB",
":TranscodingUidPolicy_TestAppC",
],
+}
+
+// MediaTranscodingService unit test using real transcoder
+cc_test {
+ name: "mediatranscodingservice_real_tests",
+ defaults: ["mediatranscodingservice_test_defaults"],
+
+ srcs: ["mediatranscodingservice_real_tests.cpp"],
}
\ No newline at end of file
diff --git a/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h b/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h
new file mode 100644
index 0000000..4259f54
--- /dev/null
+++ b/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Unit Test for MediaTranscodingService.
+
+#include <aidl/android/media/BnTranscodingClientCallback.h>
+#include <aidl/android/media/IMediaTranscodingService.h>
+#include <aidl/android/media/ITranscodingClient.h>
+#include <aidl/android/media/ITranscodingClientCallback.h>
+#include <aidl/android/media/TranscodingJobParcel.h>
+#include <aidl/android/media/TranscodingJobPriority.h>
+#include <aidl/android/media/TranscodingRequestParcel.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <binder/PermissionController.h>
+#include <cutils/multiuser.h>
+#include <fcntl.h>
+#include <gtest/gtest.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+
+#include <iostream>
+#include <list>
+
+#include "SimulatedTranscoder.h"
+
+namespace android {
+
+namespace media {
+
+using Status = ::ndk::ScopedAStatus;
+using aidl::android::media::BnTranscodingClientCallback;
+using aidl::android::media::IMediaTranscodingService;
+using aidl::android::media::ITranscodingClient;
+using aidl::android::media::ITranscodingClientCallback;
+using aidl::android::media::TranscodingJobParcel;
+using aidl::android::media::TranscodingJobPriority;
+using aidl::android::media::TranscodingRequestParcel;
+using aidl::android::media::TranscodingVideoTrackFormat;
+
+constexpr int32_t kClientUseCallingPid = IMediaTranscodingService::USE_CALLING_PID;
+
+constexpr uid_t kClientUid = 5000;
+#define UID(n) (kClientUid + (n))
+
+constexpr int32_t kClientId = 0;
+#define CLIENT(n) (kClientId + (n))
+
+constexpr const char* kClientName = "TestClient";
+constexpr const char* kClientPackageA = "com.android.tests.transcoding.testapp.A";
+constexpr const char* kClientPackageB = "com.android.tests.transcoding.testapp.B";
+constexpr const char* kClientPackageC = "com.android.tests.transcoding.testapp.C";
+
+static status_t getUidForPackage(String16 packageName, userid_t userId, /*inout*/ uid_t& uid) {
+ PermissionController pc;
+ uid = pc.getPackageUid(packageName, 0);
+ if (uid <= 0) {
+ ALOGE("Unknown package: '%s'", String8(packageName).string());
+ return BAD_VALUE;
+ }
+
+ if (userId < 0) {
+ ALOGE("Invalid user: %d", userId);
+ return BAD_VALUE;
+ }
+
+ uid = multiuser_get_uid(userId, uid);
+ return NO_ERROR;
+}
+
+struct ShellHelper {
+ static bool RunCmd(const std::string& cmdStr) {
+ int ret = system(cmdStr.c_str());
+ if (ret != 0) {
+ ALOGE("Failed to run cmd: %s, exitcode %d", cmdStr.c_str(), ret);
+ return false;
+ }
+ return true;
+ }
+
+ static bool Start(const char* packageName, const char* activityName) {
+ return RunCmd("am start -W " + std::string(packageName) + std::string(activityName) +
+ " &> /dev/null");
+ }
+
+ static bool Stop(const char* packageName) {
+ return RunCmd("am force-stop " + std::string(packageName));
+ }
+};
+
+struct EventTracker {
+ struct Event {
+ enum { NoEvent, Start, Pause, Resume, Finished, Failed } type;
+ int64_t clientId;
+ int32_t jobId;
+ };
+
+#define DECLARE_EVENT(action) \
+ static Event action(int32_t clientId, int32_t jobId) { \
+ return {Event::action, clientId, jobId}; \
+ }
+
+ DECLARE_EVENT(Start);
+ DECLARE_EVENT(Pause);
+ DECLARE_EVENT(Resume);
+ DECLARE_EVENT(Finished);
+ DECLARE_EVENT(Failed);
+
+ static constexpr Event NoEvent = {Event::NoEvent, 0, 0};
+
+ static std::string toString(const Event& event) {
+ std::string eventStr;
+ switch (event.type) {
+ case Event::Start:
+ eventStr = "Start";
+ break;
+ case Event::Pause:
+ eventStr = "Pause";
+ break;
+ case Event::Resume:
+ eventStr = "Resume";
+ break;
+ case Event::Finished:
+ eventStr = "Finished";
+ break;
+ case Event::Failed:
+ eventStr = "Failed";
+ break;
+ default:
+ return "NoEvent";
+ }
+ return "job {" + std::to_string(event.clientId) + ", " + std::to_string(event.jobId) +
+ "}: " + eventStr;
+ }
+
+ // Pop 1 event from front, wait for up to timeoutUs if empty.
+ const Event& pop(int64_t timeoutUs = 0) {
+ std::unique_lock lock(mLock);
+
+ if (mEventQueue.empty() && timeoutUs > 0) {
+ mCondition.wait_for(lock, std::chrono::microseconds(timeoutUs));
+ }
+
+ if (mEventQueue.empty()) {
+ mPoppedEvent = NoEvent;
+ } else {
+ mPoppedEvent = *mEventQueue.begin();
+ mEventQueue.pop_front();
+ }
+
+ return mPoppedEvent;
+ }
+
+ // Push 1 event to back.
+ void append(const Event& event) {
+ ALOGD("%s", toString(event).c_str());
+
+ std::unique_lock lock(mLock);
+
+ mEventQueue.push_back(event);
+ mCondition.notify_one();
+ }
+
+private:
+ std::mutex mLock;
+ std::condition_variable mCondition;
+ Event mPoppedEvent;
+ std::list<Event> mEventQueue;
+};
+
+// Operators for GTest macros.
+bool operator==(const EventTracker::Event& lhs, const EventTracker::Event& rhs) {
+ return lhs.type == rhs.type && lhs.clientId == rhs.clientId && lhs.jobId == rhs.jobId;
+}
+
+std::ostream& operator<<(std::ostream& str, const EventTracker::Event& v) {
+ str << EventTracker::toString(v);
+ return str;
+}
+
+struct TestClientCallback : public BnTranscodingClientCallback, public EventTracker {
+ TestClientCallback(int32_t id) : mClientId(id) {
+ ALOGI("TestClientCallback %d Created", mClientId);
+ }
+
+ virtual ~TestClientCallback() { ALOGI("TestClientCallback %d destroyed", mClientId); }
+
+ Status openFileDescriptor(const std::string& in_fileUri, const std::string& in_mode,
+ ::ndk::ScopedFileDescriptor* _aidl_return) override {
+ ALOGD("@@@ openFileDescriptor: %s", in_fileUri.c_str());
+ int fd;
+ if (in_mode == "w" || in_mode == "rw") {
+ // Write-only, create file if non-existent, don't overwrite existing file.
+ constexpr int kOpenFlags = O_WRONLY | O_CREAT | O_EXCL;
+ // User R+W permission.
+ constexpr int kFileMode = S_IRUSR | S_IWUSR;
+ fd = open(in_fileUri.c_str(), kOpenFlags, kFileMode);
+ } else {
+ fd = open(in_fileUri.c_str(), O_RDONLY);
+ }
+ _aidl_return->set(fd);
+ return Status::ok();
+ }
+
+ Status onTranscodingStarted(int32_t in_jobId) override {
+ append(EventTracker::Start(mClientId, in_jobId));
+ return Status::ok();
+ }
+
+ Status onTranscodingPaused(int32_t in_jobId) override {
+ append(EventTracker::Pause(mClientId, in_jobId));
+ return Status::ok();
+ }
+
+ Status onTranscodingResumed(int32_t in_jobId) override {
+ append(EventTracker::Resume(mClientId, in_jobId));
+ return Status::ok();
+ }
+
+ Status onTranscodingFinished(
+ int32_t in_jobId,
+ const ::aidl::android::media::TranscodingResultParcel& /* in_result */) override {
+ append(Finished(mClientId, in_jobId));
+ return Status::ok();
+ }
+
+ Status onTranscodingFailed(
+ int32_t in_jobId,
+ ::aidl::android::media::TranscodingErrorCode /* in_errorCode */) override {
+ append(Failed(mClientId, in_jobId));
+ return Status::ok();
+ }
+
+ Status onAwaitNumberOfJobsChanged(int32_t /* in_jobId */, int32_t /* in_oldAwaitNumber */,
+ int32_t /* in_newAwaitNumber */) override {
+ return Status::ok();
+ }
+
+ Status onProgressUpdate(int32_t /* in_jobId */, int32_t /* in_progress */) override {
+ return Status::ok();
+ }
+
+ int32_t mClientId;
+};
+
+class MediaTranscodingServiceTestBase : public ::testing::Test {
+public:
+ MediaTranscodingServiceTestBase() { ALOGI("MediaTranscodingServiceTestBase created"); }
+
+ virtual ~MediaTranscodingServiceTestBase() {
+ ALOGI("MediaTranscodingServiceTestBase destroyed");
+ }
+
+ void SetUp() override {
+ // Need thread pool to receive callbacks, otherwise oneway callbacks are
+ // silently ignored.
+ ABinderProcess_startThreadPool();
+ ::ndk::SpAIBinder binder(AServiceManager_getService("media.transcoding"));
+ mService = IMediaTranscodingService::fromBinder(binder);
+ if (mService == nullptr) {
+ ALOGE("Failed to connect to the media.trascoding service.");
+ return;
+ }
+ mClientCallback1 = ::ndk::SharedRefBase::make<TestClientCallback>(CLIENT(1));
+ mClientCallback2 = ::ndk::SharedRefBase::make<TestClientCallback>(CLIENT(2));
+ mClientCallback3 = ::ndk::SharedRefBase::make<TestClientCallback>(CLIENT(3));
+ }
+
+ std::shared_ptr<ITranscodingClient> registerOneClient(
+ const char* packageName, const std::shared_ptr<TestClientCallback>& callback,
+ uid_t defaultUid) {
+ uid_t uid;
+ if (getUidForPackage(String16(packageName), 0 /*userId*/, uid) != NO_ERROR) {
+ uid = defaultUid;
+ }
+
+ ALOGD("registering %s with uid %d", packageName, uid);
+
+ std::shared_ptr<ITranscodingClient> client;
+ Status status = mService->registerClient(callback, kClientName, packageName, uid,
+ kClientUseCallingPid, &client);
+ return status.isOk() ? client : nullptr;
+ }
+
+ void registerMultipleClients() {
+ // Register 3 clients.
+ mClient1 = registerOneClient(kClientPackageA, mClientCallback1, UID(1));
+ EXPECT_TRUE(mClient1 != nullptr);
+
+ mClient2 = registerOneClient(kClientPackageB, mClientCallback2, UID(2));
+ EXPECT_TRUE(mClient2 != nullptr);
+
+ mClient3 = registerOneClient(kClientPackageC, mClientCallback3, UID(3));
+ EXPECT_TRUE(mClient3 != nullptr);
+
+ // Check the number of clients.
+ int32_t numOfClients;
+ Status status = mService->getNumOfClients(&numOfClients);
+ EXPECT_TRUE(status.isOk());
+ EXPECT_EQ(3, numOfClients);
+ }
+
+ void unregisterMultipleClients() {
+ Status status;
+
+ // Unregister the clients.
+ status = mClient1->unregister();
+ EXPECT_TRUE(status.isOk());
+
+ status = mClient2->unregister();
+ EXPECT_TRUE(status.isOk());
+
+ status = mClient3->unregister();
+ EXPECT_TRUE(status.isOk());
+
+ // Check the number of clients.
+ int32_t numOfClients;
+ status = mService->getNumOfClients(&numOfClients);
+ EXPECT_TRUE(status.isOk());
+ EXPECT_EQ(0, numOfClients);
+ }
+
+ static constexpr bool success = true;
+ static constexpr bool fail = false;
+
+ template <bool expectation = success>
+ bool submit(const std::shared_ptr<ITranscodingClient>& client, int32_t jobId,
+ const char* sourceFilePath, const char* destinationFilePath,
+ TranscodingJobPriority priority = TranscodingJobPriority::kNormal,
+ int bitrateBps = -1) {
+ constexpr bool shouldSucceed = (expectation == success);
+ bool result;
+ TranscodingRequestParcel request;
+ TranscodingJobParcel job;
+
+ request.sourceFilePath = sourceFilePath;
+ request.destinationFilePath = destinationFilePath;
+ request.priority = priority;
+ if (bitrateBps > 0) {
+ request.requestedVideoTrackFormat.emplace(TranscodingVideoTrackFormat());
+ request.requestedVideoTrackFormat->bitrateBps = bitrateBps;
+ }
+ Status status = client->submitRequest(request, &job, &result);
+
+ EXPECT_TRUE(status.isOk());
+ EXPECT_EQ(result, shouldSucceed);
+ if (shouldSucceed) {
+ EXPECT_EQ(job.jobId, jobId);
+ }
+
+ return status.isOk() && (result == shouldSucceed) && (!shouldSucceed || job.jobId == jobId);
+ }
+
+ template <bool expectation = success>
+ bool cancel(const std::shared_ptr<ITranscodingClient>& client, int32_t jobId) {
+ constexpr bool shouldSucceed = (expectation == success);
+ bool result;
+ Status status = client->cancelJob(jobId, &result);
+
+ EXPECT_TRUE(status.isOk());
+ EXPECT_EQ(result, shouldSucceed);
+
+ return status.isOk() && (result == shouldSucceed);
+ }
+
+ template <bool expectation = success>
+ bool getJob(const std::shared_ptr<ITranscodingClient>& client, int32_t jobId,
+ const char* sourceFilePath, const char* destinationFilePath) {
+ constexpr bool shouldSucceed = (expectation == success);
+ bool result;
+ TranscodingJobParcel job;
+ Status status = client->getJobWithId(jobId, &job, &result);
+
+ EXPECT_TRUE(status.isOk());
+ EXPECT_EQ(result, shouldSucceed);
+ if (shouldSucceed) {
+ EXPECT_EQ(job.jobId, jobId);
+ EXPECT_EQ(job.request.sourceFilePath, sourceFilePath);
+ }
+
+ return status.isOk() && (result == shouldSucceed) &&
+ (!shouldSucceed ||
+ (job.jobId == jobId && job.request.sourceFilePath == sourceFilePath &&
+ job.request.destinationFilePath == destinationFilePath));
+ }
+
+ void deleteFile(const char* path) { unlink(path); }
+
+ std::shared_ptr<IMediaTranscodingService> mService;
+ std::shared_ptr<TestClientCallback> mClientCallback1;
+ std::shared_ptr<TestClientCallback> mClientCallback2;
+ std::shared_ptr<TestClientCallback> mClientCallback3;
+ std::shared_ptr<ITranscodingClient> mClient1;
+ std::shared_ptr<ITranscodingClient> mClient2;
+ std::shared_ptr<ITranscodingClient> mClient3;
+ const char* mTestName;
+};
+
+} // namespace media
+} // namespace android
diff --git a/services/mediatranscoding/tests/README.txt b/services/mediatranscoding/tests/README.txt
new file mode 100644
index 0000000..5ee0296
--- /dev/null
+++ b/services/mediatranscoding/tests/README.txt
@@ -0,0 +1,8 @@
+mediatranscodingservice_simulated_tests:
+ Tests media transcoding service with simulated transcoder.
+
+mediatranscodingservice_real_tests:
+ Tests media transcoding service with real transcoder. Uses the same test assets
+ as the MediaTranscoder unit tests. Before running the test, please make sure
+ to push the test assets to /sdcard:
+ adb push $TOP/frameworks/av/media/libmediatranscoding/transcoder/tests/assets /data/local/tmp/TranscoderTestAssets
\ No newline at end of file
diff --git a/services/mediatranscoding/tests/build_and_run_all_unit_tests.sh b/services/mediatranscoding/tests/build_and_run_all_unit_tests.sh
index bdc0394..37a827c 100644
--- a/services/mediatranscoding/tests/build_and_run_all_unit_tests.sh
+++ b/services/mediatranscoding/tests/build_and_run_all_unit_tests.sh
@@ -21,7 +21,19 @@
echo "[==========] waiting for device and sync"
adb wait-for-device remount && adb sync
-adb shell kill -9 `pid media.transcoding`
-#adb shell /data/nativetest64/mediatranscodingservice_tests/mediatranscodingservice_tests
-adb shell /data/nativetest/mediatranscodingservice_tests/mediatranscodingservice_tests
+echo "[==========] running simulated tests"
+adb shell setprop debug.transcoding.simulated_transcoder true
+adb shell kill -9 `pid media.transcoding`
+#adb shell /data/nativetest64/mediatranscodingservice_simulated_tests/mediatranscodingservice_simulated_tests
+adb shell /data/nativetest/mediatranscodingservice_simulated_tests/mediatranscodingservice_simulated_tests
+
+echo "[==========] running real tests"
+adb shell setprop debug.transcoding.simulated_transcoder false
+adb shell kill -9 `pid media.transcoding`
+#adb shell /data/nativetest64/mediatranscodingservice_real_tests/mediatranscodingservice_real_tests
+adb shell /data/nativetest/mediatranscodingservice_real_tests/mediatranscodingservice_real_tests
+
+echo "[==========] removing debug properties"
+adb shell setprop debug.transcoding.simulated_transcoder \"\"
+adb shell kill -9 `pid media.transcoding`
diff --git a/services/mediatranscoding/tests/mediatranscodingservice_real_tests.cpp b/services/mediatranscoding/tests/mediatranscodingservice_real_tests.cpp
new file mode 100644
index 0000000..57a79f7
--- /dev/null
+++ b/services/mediatranscoding/tests/mediatranscodingservice_real_tests.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Unit Test for MediaTranscodingService.
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaTranscodingServiceRealTest"
+
+#include "MediaTranscodingServiceTestHelper.h"
+
+/*
+ * Tests media transcoding service with real transcoder.
+ *
+ * Uses the same test assets as the MediaTranscoder unit tests. Before running the test,
+ * please make sure to push the test assets to /sdcard:
+ *
+ * adb push $TOP/frameworks/av/media/libmediatranscoding/transcoder/tests/assets /data/local/tmp/TranscoderTestAssets
+ */
+namespace android {
+
+namespace media {
+
+constexpr int64_t kPaddingUs = 200000;
+constexpr int64_t kJobWithPaddingUs = 10000000 + kPaddingUs;
+
+constexpr const char* kSrcPath =
+ "/data/local/tmp/TranscoderTestAssets/cubicle_avc_480x240_aac_24KHz.mp4";
+
+class MediaTranscodingServiceRealTest : public MediaTranscodingServiceTestBase {
+public:
+ MediaTranscodingServiceRealTest() {}
+
+ void deleteFile(const char* path) { unlink(path); }
+};
+
+TEST_F(MediaTranscodingServiceRealTest, TestTranscodePassthru) {
+ registerMultipleClients();
+
+ const char* dstPath = "/data/local/tmp/MediaTranscodingService_Passthru.MP4";
+ deleteFile(dstPath);
+
+ // Submit one job.
+ EXPECT_TRUE(submit(mClient1, 0, kSrcPath, dstPath));
+
+ // Wait for job to finish.
+ EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+
+ unregisterMultipleClients();
+}
+
+TEST_F(MediaTranscodingServiceRealTest, TestTranscodeVideo) {
+ registerMultipleClients();
+
+ const char* dstPath = "/data/local/tmp/MediaTranscodingService_Video.MP4";
+ deleteFile(dstPath);
+
+ const int32_t kBitRate = 8 * 1000 * 1000; // 8Mbs
+ // Submit one job.
+ EXPECT_TRUE(submit(mClient1, 0, kSrcPath, dstPath, TranscodingJobPriority::kNormal, kBitRate));
+
+ // Wait for job to finish.
+ EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+
+ // TODO: verify output file format.
+
+ unregisterMultipleClients();
+}
+
+} // namespace media
+} // namespace android
diff --git a/services/mediatranscoding/tests/mediatranscodingservice_simulated_tests.cpp b/services/mediatranscoding/tests/mediatranscodingservice_simulated_tests.cpp
new file mode 100644
index 0000000..309e39d
--- /dev/null
+++ b/services/mediatranscoding/tests/mediatranscodingservice_simulated_tests.cpp
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Unit Test for MediaTranscodingService.
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaTranscodingServiceSimulatedTest"
+
+#include <aidl/android/media/BnTranscodingClientCallback.h>
+#include <aidl/android/media/IMediaTranscodingService.h>
+#include <aidl/android/media/ITranscodingClient.h>
+#include <aidl/android/media/ITranscodingClientCallback.h>
+#include <aidl/android/media/TranscodingJobParcel.h>
+#include <aidl/android/media/TranscodingJobPriority.h>
+#include <aidl/android/media/TranscodingRequestParcel.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <binder/PermissionController.h>
+#include <cutils/multiuser.h>
+#include <gtest/gtest.h>
+#include <utils/Log.h>
+
+#include <iostream>
+#include <list>
+
+#include "MediaTranscodingServiceTestHelper.h"
+#include "SimulatedTranscoder.h"
+
+namespace android {
+
+namespace media {
+
+// Note that -1 is valid and means using calling pid/uid for the service. But only privilege caller could
+// use them. This test is not a privilege caller.
+constexpr int32_t kInvalidClientPid = -5;
+constexpr const char* kInvalidClientName = "";
+constexpr const char* kInvalidClientOpPackageName = "";
+
+constexpr int32_t kClientUseCallingUid = IMediaTranscodingService::USE_CALLING_UID;
+
+constexpr int64_t kPaddingUs = 1000000;
+constexpr int64_t kJobWithPaddingUs = SimulatedTranscoder::kJobDurationUs + kPaddingUs;
+
+constexpr const char* kClientOpPackageName = "TestClientPackage";
+constexpr const char* kTestActivityName = "/com.android.tests.transcoding.MainActivity";
+
+class MediaTranscodingServiceSimulatedTest : public MediaTranscodingServiceTestBase {
+public:
+ MediaTranscodingServiceSimulatedTest() {}
+};
+
+TEST_F(MediaTranscodingServiceSimulatedTest, TestRegisterNullClient) {
+ std::shared_ptr<ITranscodingClient> client;
+
+ // Register the client with null callback.
+ Status status = mService->registerClient(nullptr, kClientName, kClientOpPackageName,
+ kClientUseCallingUid, kClientUseCallingPid, &client);
+ EXPECT_FALSE(status.isOk());
+}
+
+TEST_F(MediaTranscodingServiceSimulatedTest, TestRegisterClientWithInvalidClientPid) {
+ std::shared_ptr<ITranscodingClient> client;
+
+ // Register the client with the service.
+ Status status = mService->registerClient(mClientCallback1, kClientName, kClientOpPackageName,
+ kClientUseCallingUid, kInvalidClientPid, &client);
+ EXPECT_FALSE(status.isOk());
+}
+
+TEST_F(MediaTranscodingServiceSimulatedTest, TestRegisterClientWithInvalidClientName) {
+ std::shared_ptr<ITranscodingClient> client;
+
+ // Register the client with the service.
+ Status status = mService->registerClient(mClientCallback1, kInvalidClientName,
+ kInvalidClientOpPackageName, kClientUseCallingUid,
+ kClientUseCallingPid, &client);
+ EXPECT_FALSE(status.isOk());
+}
+
+TEST_F(MediaTranscodingServiceSimulatedTest, TestRegisterClientWithInvalidClientPackageName) {
+ std::shared_ptr<ITranscodingClient> client;
+
+ // Register the client with the service.
+ Status status =
+ mService->registerClient(mClientCallback1, kClientName, kInvalidClientOpPackageName,
+ kClientUseCallingUid, kClientUseCallingPid, &client);
+ EXPECT_FALSE(status.isOk());
+}
+
+TEST_F(MediaTranscodingServiceSimulatedTest, TestRegisterOneClient) {
+ std::shared_ptr<ITranscodingClient> client;
+
+ Status status = mService->registerClient(mClientCallback1, kClientName, kClientOpPackageName,
+ kClientUseCallingUid, kClientUseCallingPid, &client);
+ EXPECT_TRUE(status.isOk());
+
+ // Validate the client.
+ EXPECT_TRUE(client != nullptr);
+
+ // Check the number of Clients.
+ int32_t numOfClients;
+ status = mService->getNumOfClients(&numOfClients);
+ EXPECT_TRUE(status.isOk());
+ EXPECT_EQ(1, numOfClients);
+
+ // Unregister the client.
+ status = client->unregister();
+ EXPECT_TRUE(status.isOk());
+
+ // Check the number of Clients.
+ status = mService->getNumOfClients(&numOfClients);
+ EXPECT_TRUE(status.isOk());
+ EXPECT_EQ(0, numOfClients);
+}
+
+TEST_F(MediaTranscodingServiceSimulatedTest, TestRegisterClientTwice) {
+ std::shared_ptr<ITranscodingClient> client;
+
+ Status status = mService->registerClient(mClientCallback1, kClientName, kClientOpPackageName,
+ kClientUseCallingUid, kClientUseCallingPid, &client);
+ EXPECT_TRUE(status.isOk());
+
+ // Validate the client.
+ EXPECT_TRUE(client != nullptr);
+
+ // Register the client again and expects failure.
+ std::shared_ptr<ITranscodingClient> client1;
+ status = mService->registerClient(mClientCallback1, kClientName, kClientOpPackageName,
+ kClientUseCallingUid, kClientUseCallingPid, &client1);
+ EXPECT_FALSE(status.isOk());
+
+ // Unregister the client.
+ status = client->unregister();
+ EXPECT_TRUE(status.isOk());
+}
+
+TEST_F(MediaTranscodingServiceSimulatedTest, TestRegisterMultipleClients) {
+ registerMultipleClients();
+ unregisterMultipleClients();
+}
+
+TEST_F(MediaTranscodingServiceSimulatedTest, TestJobIdIndependence) {
+ registerMultipleClients();
+
+ // Submit 2 requests on client1 first.
+ EXPECT_TRUE(submit(mClient1, 0, "test_source_file", "test_destination_file"));
+ EXPECT_TRUE(submit(mClient1, 1, "test_source_file", "test_destination_file"));
+
+ // Submit 2 requests on client2, jobId should be independent for each client.
+ EXPECT_TRUE(submit(mClient2, 0, "test_source_file", "test_destination_file"));
+ EXPECT_TRUE(submit(mClient2, 1, "test_source_file", "test_destination_file"));
+
+ // Cancel all jobs.
+ EXPECT_TRUE(cancel(mClient1, 0));
+ EXPECT_TRUE(cancel(mClient1, 1));
+ EXPECT_TRUE(cancel(mClient2, 0));
+ EXPECT_TRUE(cancel(mClient2, 1));
+
+ unregisterMultipleClients();
+}
+
+TEST_F(MediaTranscodingServiceSimulatedTest, TestSubmitCancelJobs) {
+ registerMultipleClients();
+
+ // Test jobId assignment.
+ EXPECT_TRUE(submit(mClient1, 0, "test_source_file_0", "test_destination_file"));
+ EXPECT_TRUE(submit(mClient1, 1, "test_source_file_1", "test_destination_file"));
+ EXPECT_TRUE(submit(mClient1, 2, "test_source_file_2", "test_destination_file"));
+
+ // Test submit bad request (no valid sourceFilePath) fails.
+ EXPECT_TRUE(submit<fail>(mClient1, 0, "", ""));
+
+ // Test cancel non-existent job fails.
+ EXPECT_TRUE(cancel<fail>(mClient1, 100));
+
+ // Job 0 should start immediately and finish in 2 seconds, followed by Job 1 start.
+ EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+ EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+ EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
+
+ // Test cancel valid jobId in random order.
+ // Test cancel finished job fails.
+ EXPECT_TRUE(cancel(mClient1, 2));
+ EXPECT_TRUE(cancel<fail>(mClient1, 0));
+ EXPECT_TRUE(cancel(mClient1, 1));
+
+ // Test cancel job again fails.
+ EXPECT_TRUE(cancel<fail>(mClient1, 1));
+
+ // Test no more events arriving after cancel.
+ EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::NoEvent);
+
+ unregisterMultipleClients();
+}
+
+TEST_F(MediaTranscodingServiceSimulatedTest, TestGetJobs) {
+ registerMultipleClients();
+
+ // Submit 3 requests.
+ EXPECT_TRUE(submit(mClient1, 0, "test_source_file_0", "test_destination_file_0"));
+ EXPECT_TRUE(submit(mClient1, 1, "test_source_file_1", "test_destination_file_1"));
+ EXPECT_TRUE(submit(mClient1, 2, "test_source_file_2", "test_destination_file_2"));
+
+ // Test get jobs by id.
+ EXPECT_TRUE(getJob(mClient1, 2, "test_source_file_2", "test_destination_file_2"));
+ EXPECT_TRUE(getJob(mClient1, 1, "test_source_file_1", "test_destination_file_1"));
+ EXPECT_TRUE(getJob(mClient1, 0, "test_source_file_0", "test_destination_file_0"));
+
+ // Test get job by invalid id fails.
+ EXPECT_TRUE(getJob<fail>(mClient1, 100, "", ""));
+ EXPECT_TRUE(getJob<fail>(mClient1, -1, "", ""));
+
+ // Test get job after cancel fails.
+ EXPECT_TRUE(cancel(mClient1, 2));
+ EXPECT_TRUE(getJob<fail>(mClient1, 2, "", ""));
+
+ // Job 0 should start immediately and finish in 2 seconds, followed by Job 1 start.
+ EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+ EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+ EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
+
+ // Test get job after finish fails.
+ EXPECT_TRUE(getJob<fail>(mClient1, 0, "", ""));
+
+ // Test get the remaining job 1.
+ EXPECT_TRUE(getJob(mClient1, 1, "test_source_file_1", "test_destination_file_1"));
+
+ // Cancel remaining job 1.
+ EXPECT_TRUE(cancel(mClient1, 1));
+
+ unregisterMultipleClients();
+}
+
+TEST_F(MediaTranscodingServiceSimulatedTest, TestSubmitCancelWithOfflineJobs) {
+ registerMultipleClients();
+
+ // Submit some offline jobs first.
+ EXPECT_TRUE(submit(mClient1, 0, "test_source_file_0", "test_destination_file_0",
+ TranscodingJobPriority::kUnspecified));
+ EXPECT_TRUE(submit(mClient1, 1, "test_source_file_1", "test_destination_file_1",
+ TranscodingJobPriority::kUnspecified));
+
+ // Job 0 should start immediately.
+ EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+
+ // Submit more real-time jobs.
+ EXPECT_TRUE(submit(mClient1, 2, "test_source_file_2", "test_destination_file_2"));
+ EXPECT_TRUE(submit(mClient1, 3, "test_source_file_3", "test_destination_file_3"));
+
+ // Job 0 should pause immediately and job 2 should start.
+ EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Pause(CLIENT(1), 0));
+ EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 2));
+
+ // Job 2 should finish in 2 seconds and job 3 should start.
+ EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 2));
+ EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 3));
+
+ // Cancel job 3 now
+ EXPECT_TRUE(cancel(mClient1, 3));
+
+ // Job 0 should resume and finish in 2 seconds, followed by job 1 start.
+ EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Resume(CLIENT(1), 0));
+ EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+ EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
+
+ // Cancel remaining job 1.
+ EXPECT_TRUE(cancel(mClient1, 1));
+
+ unregisterMultipleClients();
+}
+
+TEST_F(MediaTranscodingServiceSimulatedTest, TestClientUseAfterUnregister) {
+ std::shared_ptr<ITranscodingClient> client;
+
+ // Register a client, then unregister.
+ Status status = mService->registerClient(mClientCallback1, kClientName, kClientOpPackageName,
+ kClientUseCallingUid, kClientUseCallingPid, &client);
+ EXPECT_TRUE(status.isOk());
+
+ status = client->unregister();
+ EXPECT_TRUE(status.isOk());
+
+ // Test various operations on the client, should fail with ERROR_DISCONNECTED.
+ TranscodingJobParcel job;
+ bool result;
+ status = client->getJobWithId(0, &job, &result);
+ EXPECT_EQ(status.getServiceSpecificError(), IMediaTranscodingService::ERROR_DISCONNECTED);
+
+ status = client->cancelJob(0, &result);
+ EXPECT_EQ(status.getServiceSpecificError(), IMediaTranscodingService::ERROR_DISCONNECTED);
+
+ TranscodingRequestParcel request;
+ status = client->submitRequest(request, &job, &result);
+ EXPECT_EQ(status.getServiceSpecificError(), IMediaTranscodingService::ERROR_DISCONNECTED);
+}
+
+TEST_F(MediaTranscodingServiceSimulatedTest, TestTranscodingUidPolicy) {
+ ALOGD("TestTranscodingUidPolicy starting...");
+
+ EXPECT_TRUE(ShellHelper::RunCmd("input keyevent KEYCODE_WAKEUP"));
+ EXPECT_TRUE(ShellHelper::RunCmd("wm dismiss-keyguard"));
+ EXPECT_TRUE(ShellHelper::Stop(kClientPackageA));
+ EXPECT_TRUE(ShellHelper::Stop(kClientPackageB));
+ EXPECT_TRUE(ShellHelper::Stop(kClientPackageC));
+
+ registerMultipleClients();
+
+ ALOGD("Moving app A to top...");
+ EXPECT_TRUE(ShellHelper::Start(kClientPackageA, kTestActivityName));
+
+ // Submit 3 requests.
+ ALOGD("Submitting job to client1 (app A) ...");
+ EXPECT_TRUE(submit(mClient1, 0, "test_source_file_0", "test_destination_file_0"));
+ EXPECT_TRUE(submit(mClient1, 1, "test_source_file_1", "test_destination_file_1"));
+ EXPECT_TRUE(submit(mClient1, 2, "test_source_file_2", "test_destination_file_2"));
+
+ // Job 0 should start immediately.
+ EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+
+ ALOGD("Moving app B to top...");
+ EXPECT_TRUE(ShellHelper::Start(kClientPackageB, kTestActivityName));
+
+ // Job 0 should continue and finish in 2 seconds, then job 1 should start.
+ EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+ EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
+
+ ALOGD("Submitting job to client2 (app B) ...");
+ EXPECT_TRUE(submit(mClient2, 0, "test_source_file_0", "test_destination_file_0"));
+
+ // Client1's job should pause, client2's job should start.
+ EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Pause(CLIENT(1), 1));
+ EXPECT_EQ(mClientCallback2->pop(kPaddingUs), EventTracker::Start(CLIENT(2), 0));
+
+ ALOGD("Moving app A back to top...");
+ EXPECT_TRUE(ShellHelper::Start(kClientPackageA, kTestActivityName));
+
+ // Client2's job should pause, client1's job 1 should resume.
+ EXPECT_EQ(mClientCallback2->pop(kPaddingUs), EventTracker::Pause(CLIENT(2), 0));
+ EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Resume(CLIENT(1), 1));
+
+ // Client2's job 1 should finish in 2 seconds, then its job 2 should start.
+ EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 1));
+ EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 2));
+
+ // After client2's jobs finish, client1's job should resume.
+ EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 2));
+ EXPECT_EQ(mClientCallback2->pop(kPaddingUs), EventTracker::Resume(CLIENT(2), 0));
+
+ unregisterMultipleClients();
+
+ EXPECT_TRUE(ShellHelper::Stop(kClientPackageA));
+ EXPECT_TRUE(ShellHelper::Stop(kClientPackageB));
+ EXPECT_TRUE(ShellHelper::Stop(kClientPackageC));
+
+ ALOGD("TestTranscodingUidPolicy finished.");
+}
+
+} // namespace media
+} // namespace android
diff --git a/services/mediatranscoding/tests/mediatranscodingservice_tests.cpp b/services/mediatranscoding/tests/mediatranscodingservice_tests.cpp
deleted file mode 100644
index 3bc7b15..0000000
--- a/services/mediatranscoding/tests/mediatranscodingservice_tests.cpp
+++ /dev/null
@@ -1,710 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Unit Test for MediaTranscodingService.
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaTranscodingServiceTest"
-
-#include <aidl/android/media/BnTranscodingClientCallback.h>
-#include <aidl/android/media/IMediaTranscodingService.h>
-#include <aidl/android/media/ITranscodingClient.h>
-#include <aidl/android/media/ITranscodingClientCallback.h>
-#include <aidl/android/media/TranscodingJobParcel.h>
-#include <aidl/android/media/TranscodingJobPriority.h>
-#include <aidl/android/media/TranscodingRequestParcel.h>
-#include <android-base/logging.h>
-#include <android/binder_manager.h>
-#include <android/binder_process.h>
-#include <binder/PermissionController.h>
-#include <cutils/multiuser.h>
-#include <gtest/gtest.h>
-#include <utils/Log.h>
-
-#include <iostream>
-#include <list>
-
-#include "SimulatedTranscoder.h"
-
-namespace android {
-
-namespace media {
-
-using Status = ::ndk::ScopedAStatus;
-using aidl::android::media::BnTranscodingClientCallback;
-using aidl::android::media::IMediaTranscodingService;
-using aidl::android::media::ITranscodingClient;
-using aidl::android::media::ITranscodingClientCallback;
-using aidl::android::media::TranscodingJobParcel;
-using aidl::android::media::TranscodingJobPriority;
-using aidl::android::media::TranscodingRequestParcel;
-
-// Note that -1 is valid and means using calling pid/uid for the service. But only privilege caller could
-// use them. This test is not a privilege caller.
-constexpr int32_t kInvalidClientPid = -5;
-constexpr const char* kInvalidClientName = "";
-constexpr const char* kInvalidClientOpPackageName = "";
-
-constexpr int32_t kClientUseCallingPid = IMediaTranscodingService::USE_CALLING_PID;
-constexpr int32_t kClientUseCallingUid = IMediaTranscodingService::USE_CALLING_UID;
-
-constexpr uid_t kClientUid = 5000;
-#define UID(n) (kClientUid + (n))
-
-constexpr int32_t kClientId = 0;
-#define CLIENT(n) (kClientId + (n))
-
-constexpr int64_t kPaddingUs = 1000000;
-constexpr int64_t kJobWithPaddingUs = SimulatedTranscoder::kJobDurationUs + kPaddingUs;
-
-constexpr const char* kClientName = "TestClient";
-constexpr const char* kClientOpPackageName = "TestClientPackage";
-constexpr const char* kClientPackageA = "com.android.tests.transcoding.testapp.A";
-constexpr const char* kClientPackageB = "com.android.tests.transcoding.testapp.B";
-constexpr const char* kClientPackageC = "com.android.tests.transcoding.testapp.C";
-constexpr const char* kTestActivityName = "/com.android.tests.transcoding.MainActivity";
-
-static status_t getUidForPackage(String16 packageName, userid_t userId, /*inout*/ uid_t& uid) {
- PermissionController pc;
- uid = pc.getPackageUid(packageName, 0);
- if (uid <= 0) {
- ALOGE("Unknown package: '%s'", String8(packageName).string());
- return BAD_VALUE;
- }
-
- if (userId < 0) {
- ALOGE("Invalid user: %d", userId);
- return BAD_VALUE;
- }
-
- uid = multiuser_get_uid(userId, uid);
- return NO_ERROR;
-}
-
-struct ShellHelper {
- static bool RunCmd(const std::string& cmdStr) {
- int ret = system(cmdStr.c_str());
- if (ret != 0) {
- ALOGE("Failed to run cmd: %s, exitcode %d", cmdStr.c_str(), ret);
- return false;
- }
- return true;
- }
-
- static bool Start(const char* packageName, const char* activityName) {
- return RunCmd("am start -W " + std::string(packageName) + std::string(activityName) +
- " &> /dev/null");
- }
-
- static bool Stop(const char* packageName) {
- return RunCmd("am force-stop " + std::string(packageName));
- }
-};
-
-struct EventTracker {
- struct Event {
- enum { NoEvent, Start, Pause, Resume, Finished, Failed } type;
- int64_t clientId;
- int32_t jobId;
- };
-
-#define DECLARE_EVENT(action) \
- static Event action(int32_t clientId, int32_t jobId) { \
- return {Event::action, clientId, jobId}; \
- }
-
- DECLARE_EVENT(Start);
- DECLARE_EVENT(Pause);
- DECLARE_EVENT(Resume);
- DECLARE_EVENT(Finished);
- DECLARE_EVENT(Failed);
-
- static constexpr Event NoEvent = {Event::NoEvent, 0, 0};
-
- static std::string toString(const Event& event) {
- std::string eventStr;
- switch (event.type) {
- case Event::Start:
- eventStr = "Start";
- break;
- case Event::Pause:
- eventStr = "Pause";
- break;
- case Event::Resume:
- eventStr = "Resume";
- break;
- case Event::Finished:
- eventStr = "Finished";
- break;
- case Event::Failed:
- eventStr = "Failed";
- break;
- default:
- return "NoEvent";
- }
- return "job {" + std::to_string(event.clientId) + ", " + std::to_string(event.jobId) +
- "}: " + eventStr;
- }
-
- // Pop 1 event from front, wait for up to timeoutUs if empty.
- const Event& pop(int64_t timeoutUs = 0) {
- std::unique_lock lock(mLock);
-
- if (mEventQueue.empty() && timeoutUs > 0) {
- mCondition.wait_for(lock, std::chrono::microseconds(timeoutUs));
- }
-
- if (mEventQueue.empty()) {
- mPoppedEvent = NoEvent;
- } else {
- mPoppedEvent = *mEventQueue.begin();
- mEventQueue.pop_front();
- }
-
- return mPoppedEvent;
- }
-
- // Push 1 event to back.
- void append(const Event& event) {
- ALOGD("%s", toString(event).c_str());
-
- std::unique_lock lock(mLock);
-
- mEventQueue.push_back(event);
- mCondition.notify_one();
- }
-
-private:
- std::mutex mLock;
- std::condition_variable mCondition;
- Event mPoppedEvent;
- std::list<Event> mEventQueue;
-};
-
-// Operators for GTest macros.
-bool operator==(const EventTracker::Event& lhs, const EventTracker::Event& rhs) {
- return lhs.type == rhs.type && lhs.clientId == rhs.clientId && lhs.jobId == rhs.jobId;
-}
-
-std::ostream& operator<<(std::ostream& str, const EventTracker::Event& v) {
- str << EventTracker::toString(v);
- return str;
-}
-
-struct TestClientCallback : public BnTranscodingClientCallback, public EventTracker {
- TestClientCallback(int32_t id) : mClientId(id) {
- ALOGI("TestClientCallback %d Created", mClientId);
- }
-
- virtual ~TestClientCallback() { ALOGI("TestClientCallback %d destroyed", mClientId); }
-
- Status openFileDescriptor(const std::string& /*in_fileUri*/, const std::string& /*in_mode*/,
- ::ndk::ScopedFileDescriptor* /*_aidl_return*/) override {
- return Status::ok();
- }
-
- Status onTranscodingStarted(int32_t in_jobId) override {
- append(Start(mClientId, in_jobId));
- return Status::ok();
- }
-
- Status onTranscodingPaused(int32_t in_jobId) override {
- append(Pause(mClientId, in_jobId));
- return Status::ok();
- }
-
- Status onTranscodingResumed(int32_t in_jobId) override {
- append(Resume(mClientId, in_jobId));
- return Status::ok();
- }
-
- Status onTranscodingFinished(
- int32_t in_jobId,
- const ::aidl::android::media::TranscodingResultParcel& /* in_result */) override {
- append(Finished(mClientId, in_jobId));
- return Status::ok();
- }
-
- Status onTranscodingFailed(
- int32_t in_jobId,
- ::aidl::android::media::TranscodingErrorCode /* in_errorCode */) override {
- append(Failed(mClientId, in_jobId));
- return Status::ok();
- }
-
- Status onAwaitNumberOfJobsChanged(int32_t /* in_jobId */, int32_t /* in_oldAwaitNumber */,
- int32_t /* in_newAwaitNumber */) override {
- return Status::ok();
- }
-
- Status onProgressUpdate(int32_t /*in_jobId*/, int32_t /*in_progress*/) override {
- return Status::ok();
- }
-
- int32_t mClientId;
-};
-
-class MediaTranscodingServiceTest : public ::testing::Test {
-public:
- MediaTranscodingServiceTest() { ALOGI("MediaTranscodingServiceTest created"); }
-
- ~MediaTranscodingServiceTest() { ALOGI("MediaTranscodingingServiceTest destroyed"); }
-
- void SetUp() override {
- // Need thread pool to receive callbacks, otherwise oneway callbacks are
- // silently ignored.
- ABinderProcess_startThreadPool();
- ::ndk::SpAIBinder binder(AServiceManager_getService("media.transcoding"));
- mService = IMediaTranscodingService::fromBinder(binder);
- if (mService == nullptr) {
- ALOGE("Failed to connect to the media.trascoding service.");
- return;
- }
- mClientCallback1 = ::ndk::SharedRefBase::make<TestClientCallback>(CLIENT(1));
- mClientCallback2 = ::ndk::SharedRefBase::make<TestClientCallback>(CLIENT(2));
- mClientCallback3 = ::ndk::SharedRefBase::make<TestClientCallback>(CLIENT(3));
- }
-
- std::shared_ptr<ITranscodingClient> registerOneClient(
- const char* packageName, const std::shared_ptr<TestClientCallback>& callback,
- uid_t defaultUid) {
- uid_t uid;
- if (getUidForPackage(String16(packageName), 0 /*userId*/, uid) != NO_ERROR) {
- uid = defaultUid;
- }
-
- ALOGD("registering %s with uid %d", packageName, uid);
-
- std::shared_ptr<ITranscodingClient> client;
- Status status = mService->registerClient(callback, kClientName, packageName, uid,
- kClientUseCallingPid, &client);
- return status.isOk() ? client : nullptr;
- }
-
- void registerMultipleClients() {
- // Register 3 clients.
- mClient1 = registerOneClient(kClientPackageA, mClientCallback1, UID(1));
- EXPECT_TRUE(mClient1 != nullptr);
-
- mClient2 = registerOneClient(kClientPackageB, mClientCallback2, UID(2));
- EXPECT_TRUE(mClient2 != nullptr);
-
- mClient3 = registerOneClient(kClientPackageC, mClientCallback3, UID(3));
- EXPECT_TRUE(mClient3 != nullptr);
-
- // Check the number of clients.
- int32_t numOfClients;
- Status status = mService->getNumOfClients(&numOfClients);
- EXPECT_TRUE(status.isOk());
- EXPECT_EQ(3, numOfClients);
- }
-
- void unregisterMultipleClients() {
- Status status;
-
- // Unregister the clients.
- status = mClient1->unregister();
- EXPECT_TRUE(status.isOk());
-
- status = mClient2->unregister();
- EXPECT_TRUE(status.isOk());
-
- status = mClient3->unregister();
- EXPECT_TRUE(status.isOk());
-
- // Check the number of clients.
- int32_t numOfClients;
- status = mService->getNumOfClients(&numOfClients);
- EXPECT_TRUE(status.isOk());
- EXPECT_EQ(0, numOfClients);
- }
-
- static constexpr bool success = true;
- static constexpr bool fail = false;
-
- template <bool expectation = success>
- bool submit(const std::shared_ptr<ITranscodingClient>& client, int32_t jobId,
- const char* sourceFilePath, const char* destinationFilePath,
- TranscodingJobPriority priority = TranscodingJobPriority::kNormal) {
- constexpr bool shouldSucceed = (expectation == success);
- bool result;
- TranscodingRequestParcel request;
- TranscodingJobParcel job;
-
- request.sourceFilePath = sourceFilePath;
- request.destinationFilePath = destinationFilePath;
- request.priority = priority;
- Status status = client->submitRequest(request, &job, &result);
-
- EXPECT_TRUE(status.isOk());
- EXPECT_EQ(result, shouldSucceed);
- if (shouldSucceed) {
- EXPECT_EQ(job.jobId, jobId);
- }
-
- return status.isOk() && (result == shouldSucceed) && (!shouldSucceed || job.jobId == jobId);
- }
-
- template <bool expectation = success>
- bool cancel(const std::shared_ptr<ITranscodingClient>& client, int32_t jobId) {
- constexpr bool shouldSucceed = (expectation == success);
- bool result;
- Status status = client->cancelJob(jobId, &result);
-
- EXPECT_TRUE(status.isOk());
- EXPECT_EQ(result, shouldSucceed);
-
- return status.isOk() && (result == shouldSucceed);
- }
-
- template <bool expectation = success>
- bool getJob(const std::shared_ptr<ITranscodingClient>& client, int32_t jobId,
- const char* sourceFilePath, const char* destinationFilePath) {
- constexpr bool shouldSucceed = (expectation == success);
- bool result;
- TranscodingJobParcel job;
- Status status = client->getJobWithId(jobId, &job, &result);
-
- EXPECT_TRUE(status.isOk());
- EXPECT_EQ(result, shouldSucceed);
- if (shouldSucceed) {
- EXPECT_EQ(job.jobId, jobId);
- EXPECT_EQ(job.request.sourceFilePath, sourceFilePath);
- }
-
- return status.isOk() && (result == shouldSucceed) &&
- (!shouldSucceed ||
- (job.jobId == jobId && job.request.sourceFilePath == sourceFilePath &&
- job.request.destinationFilePath == destinationFilePath));
- }
-
- std::shared_ptr<IMediaTranscodingService> mService;
- std::shared_ptr<TestClientCallback> mClientCallback1;
- std::shared_ptr<TestClientCallback> mClientCallback2;
- std::shared_ptr<TestClientCallback> mClientCallback3;
- std::shared_ptr<ITranscodingClient> mClient1;
- std::shared_ptr<ITranscodingClient> mClient2;
- std::shared_ptr<ITranscodingClient> mClient3;
-};
-
-TEST_F(MediaTranscodingServiceTest, TestRegisterNullClient) {
- std::shared_ptr<ITranscodingClient> client;
-
- // Register the client with null callback.
- Status status = mService->registerClient(nullptr, kClientName, kClientOpPackageName,
- kClientUseCallingUid, kClientUseCallingPid, &client);
- EXPECT_FALSE(status.isOk());
-}
-
-TEST_F(MediaTranscodingServiceTest, TestRegisterClientWithInvalidClientPid) {
- std::shared_ptr<ITranscodingClient> client;
-
- // Register the client with the service.
- Status status = mService->registerClient(mClientCallback1, kClientName, kClientOpPackageName,
- kClientUseCallingUid, kInvalidClientPid, &client);
- EXPECT_FALSE(status.isOk());
-}
-
-TEST_F(MediaTranscodingServiceTest, TestRegisterClientWithInvalidClientName) {
- std::shared_ptr<ITranscodingClient> client;
-
- // Register the client with the service.
- Status status = mService->registerClient(mClientCallback1, kInvalidClientName,
- kInvalidClientOpPackageName, kClientUseCallingUid,
- kClientUseCallingPid, &client);
- EXPECT_FALSE(status.isOk());
-}
-
-TEST_F(MediaTranscodingServiceTest, TestRegisterClientWithInvalidClientPackageName) {
- std::shared_ptr<ITranscodingClient> client;
-
- // Register the client with the service.
- Status status =
- mService->registerClient(mClientCallback1, kClientName, kInvalidClientOpPackageName,
- kClientUseCallingUid, kClientUseCallingPid, &client);
- EXPECT_FALSE(status.isOk());
-}
-
-TEST_F(MediaTranscodingServiceTest, TestRegisterOneClient) {
- std::shared_ptr<ITranscodingClient> client;
-
- Status status = mService->registerClient(mClientCallback1, kClientName, kClientOpPackageName,
- kClientUseCallingUid, kClientUseCallingPid, &client);
- EXPECT_TRUE(status.isOk());
-
- // Validate the client.
- EXPECT_TRUE(client != nullptr);
-
- // Check the number of Clients.
- int32_t numOfClients;
- status = mService->getNumOfClients(&numOfClients);
- EXPECT_TRUE(status.isOk());
- EXPECT_EQ(1, numOfClients);
-
- // Unregister the client.
- status = client->unregister();
- EXPECT_TRUE(status.isOk());
-
- // Check the number of Clients.
- status = mService->getNumOfClients(&numOfClients);
- EXPECT_TRUE(status.isOk());
- EXPECT_EQ(0, numOfClients);
-}
-
-TEST_F(MediaTranscodingServiceTest, TestRegisterClientTwice) {
- std::shared_ptr<ITranscodingClient> client;
-
- Status status = mService->registerClient(mClientCallback1, kClientName, kClientOpPackageName,
- kClientUseCallingUid, kClientUseCallingPid, &client);
- EXPECT_TRUE(status.isOk());
-
- // Validate the client.
- EXPECT_TRUE(client != nullptr);
-
- // Register the client again and expects failure.
- std::shared_ptr<ITranscodingClient> client1;
- status = mService->registerClient(mClientCallback1, kClientName, kClientOpPackageName,
- kClientUseCallingUid, kClientUseCallingPid, &client1);
- EXPECT_FALSE(status.isOk());
-
- // Unregister the client.
- status = client->unregister();
- EXPECT_TRUE(status.isOk());
-}
-
-TEST_F(MediaTranscodingServiceTest, TestRegisterMultipleClients) {
- registerMultipleClients();
- unregisterMultipleClients();
-}
-
-TEST_F(MediaTranscodingServiceTest, TestJobIdIndependence) {
- registerMultipleClients();
-
- // Submit 2 requests on client1 first.
- EXPECT_TRUE(submit(mClient1, 0, "test_source_file", "test_destination_file"));
- EXPECT_TRUE(submit(mClient1, 1, "test_source_file", "test_destination_file"));
-
- // Submit 2 requests on client2, jobId should be independent for each client.
- EXPECT_TRUE(submit(mClient2, 0, "test_source_file", "test_destination_file"));
- EXPECT_TRUE(submit(mClient2, 1, "test_source_file", "test_destination_file"));
-
- // Cancel all jobs.
- EXPECT_TRUE(cancel(mClient1, 0));
- EXPECT_TRUE(cancel(mClient1, 1));
- EXPECT_TRUE(cancel(mClient2, 0));
- EXPECT_TRUE(cancel(mClient2, 1));
-
- unregisterMultipleClients();
-}
-
-TEST_F(MediaTranscodingServiceTest, TestSubmitCancelJobs) {
- registerMultipleClients();
-
- // Test jobId assignment.
- EXPECT_TRUE(submit(mClient1, 0, "test_source_file_0", "test_destination_file"));
- EXPECT_TRUE(submit(mClient1, 1, "test_source_file_1", "test_destination_file"));
- EXPECT_TRUE(submit(mClient1, 2, "test_source_file_2", "test_destination_file"));
-
- // Test submit bad request (no valid sourceFilePath) fails.
- EXPECT_TRUE(submit<fail>(mClient1, 0, "", ""));
-
- // Test cancel non-existent job fails.
- EXPECT_TRUE(cancel<fail>(mClient1, 100));
-
- // Job 0 should start immediately and finish in 2 seconds, followed by Job 1 start.
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
- EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
-
- // Test cancel valid jobId in random order.
- // Test cancel finished job fails.
- EXPECT_TRUE(cancel(mClient1, 2));
- EXPECT_TRUE(cancel<fail>(mClient1, 0));
- EXPECT_TRUE(cancel(mClient1, 1));
-
- // Test cancel job again fails.
- EXPECT_TRUE(cancel<fail>(mClient1, 1));
-
- // Test no more events arriving after cancel.
- EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::NoEvent);
-
- unregisterMultipleClients();
-}
-
-TEST_F(MediaTranscodingServiceTest, TestGetJobs) {
- registerMultipleClients();
-
- // Submit 3 requests.
- EXPECT_TRUE(submit(mClient1, 0, "test_source_file_0", "test_destination_file_0"));
- EXPECT_TRUE(submit(mClient1, 1, "test_source_file_1", "test_destination_file_1"));
- EXPECT_TRUE(submit(mClient1, 2, "test_source_file_2", "test_destination_file_2"));
-
- // Test get jobs by id.
- EXPECT_TRUE(getJob(mClient1, 2, "test_source_file_2", "test_destination_file_2"));
- EXPECT_TRUE(getJob(mClient1, 1, "test_source_file_1", "test_destination_file_1"));
- EXPECT_TRUE(getJob(mClient1, 0, "test_source_file_0", "test_destination_file_0"));
-
- // Test get job by invalid id fails.
- EXPECT_TRUE(getJob<fail>(mClient1, 100, "", ""));
- EXPECT_TRUE(getJob<fail>(mClient1, -1, "", ""));
-
- // Test get job after cancel fails.
- EXPECT_TRUE(cancel(mClient1, 2));
- EXPECT_TRUE(getJob<fail>(mClient1, 2, "", ""));
-
- // Job 0 should start immediately and finish in 2 seconds, followed by Job 1 start.
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
- EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
-
- // Test get job after finish fails.
- EXPECT_TRUE(getJob<fail>(mClient1, 0, "", ""));
-
- // Test get the remaining job 1.
- EXPECT_TRUE(getJob(mClient1, 1, "test_source_file_1", "test_destination_file_1"));
-
- // Cancel remaining job 1.
- EXPECT_TRUE(cancel(mClient1, 1));
-
- unregisterMultipleClients();
-}
-
-TEST_F(MediaTranscodingServiceTest, TestSubmitCancelWithOfflineJobs) {
- registerMultipleClients();
-
- // Submit some offline jobs first.
- EXPECT_TRUE(submit(mClient1, 0, "test_source_file_0", "test_destination_file_0",
- TranscodingJobPriority::kUnspecified));
- EXPECT_TRUE(submit(mClient1, 1, "test_source_file_1", "test_destination_file_1",
- TranscodingJobPriority::kUnspecified));
-
- // Job 0 should start immediately.
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
-
- // Submit more real-time jobs.
- EXPECT_TRUE(submit(mClient1, 2, "test_source_file_2", "test_destination_file_2"));
- EXPECT_TRUE(submit(mClient1, 3, "test_source_file_3", "test_destination_file_3"));
-
- // Job 0 should pause immediately and job 2 should start.
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Pause(CLIENT(1), 0));
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 2));
-
- // Job 2 should finish in 2 seconds and job 3 should start.
- EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 2));
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 3));
-
- // Cancel job 3 now
- EXPECT_TRUE(cancel(mClient1, 3));
-
- // Job 0 should resume and finish in 2 seconds, followed by job 1 start.
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Resume(CLIENT(1), 0));
- EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
-
- // Cancel remaining job 1.
- EXPECT_TRUE(cancel(mClient1, 1));
-
- unregisterMultipleClients();
-}
-
-TEST_F(MediaTranscodingServiceTest, TestClientUseAfterUnregister) {
- std::shared_ptr<ITranscodingClient> client;
-
- // Register a client, then unregister.
- Status status = mService->registerClient(mClientCallback1, kClientName, kClientOpPackageName,
- kClientUseCallingUid, kClientUseCallingPid, &client);
- EXPECT_TRUE(status.isOk());
-
- status = client->unregister();
- EXPECT_TRUE(status.isOk());
-
- // Test various operations on the client, should fail with ERROR_DISCONNECTED.
- TranscodingJobParcel job;
- bool result;
- status = client->getJobWithId(0, &job, &result);
- EXPECT_EQ(status.getServiceSpecificError(), IMediaTranscodingService::ERROR_DISCONNECTED);
-
- status = client->cancelJob(0, &result);
- EXPECT_EQ(status.getServiceSpecificError(), IMediaTranscodingService::ERROR_DISCONNECTED);
-
- TranscodingRequestParcel request;
- status = client->submitRequest(request, &job, &result);
- EXPECT_EQ(status.getServiceSpecificError(), IMediaTranscodingService::ERROR_DISCONNECTED);
-}
-
-TEST_F(MediaTranscodingServiceTest, TestTranscodingUidPolicy) {
- ALOGD("TestTranscodingUidPolicy starting...");
-
- EXPECT_TRUE(ShellHelper::RunCmd("input keyevent KEYCODE_WAKEUP"));
- EXPECT_TRUE(ShellHelper::RunCmd("wm dismiss-keyguard"));
- EXPECT_TRUE(ShellHelper::Stop(kClientPackageA));
- EXPECT_TRUE(ShellHelper::Stop(kClientPackageB));
- EXPECT_TRUE(ShellHelper::Stop(kClientPackageC));
-
- registerMultipleClients();
-
- ALOGD("Moving app A to top...");
- EXPECT_TRUE(ShellHelper::Start(kClientPackageA, kTestActivityName));
-
- // Submit 3 requests.
- ALOGD("Submitting job to client1 (app A) ...");
- EXPECT_TRUE(submit(mClient1, 0, "test_source_file_0", "test_destination_file_0"));
- EXPECT_TRUE(submit(mClient1, 1, "test_source_file_1", "test_destination_file_1"));
- EXPECT_TRUE(submit(mClient1, 2, "test_source_file_2", "test_destination_file_2"));
-
- // Job 0 should start immediately.
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
-
- ALOGD("Moving app B to top...");
- EXPECT_TRUE(ShellHelper::Start(kClientPackageB, kTestActivityName));
-
- // Job 0 should continue and finish in 2 seconds, then job 1 should start.
- EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
-
- ALOGD("Submitting job to client2 (app B) ...");
- EXPECT_TRUE(submit(mClient2, 0, "test_source_file_0", "test_destination_file_0"));
-
- // Client1's job should pause, client2's job should start.
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Pause(CLIENT(1), 1));
- EXPECT_EQ(mClientCallback2->pop(kPaddingUs), EventTracker::Start(CLIENT(2), 0));
-
- ALOGD("Moving app A back to top...");
- EXPECT_TRUE(ShellHelper::Start(kClientPackageA, kTestActivityName));
-
- // Client2's job should pause, client1's job 1 should resume.
- EXPECT_EQ(mClientCallback2->pop(kPaddingUs), EventTracker::Pause(CLIENT(2), 0));
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Resume(CLIENT(1), 1));
-
- // Client2's job 1 should finish in 2 seconds, then its job 2 should start.
- EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 1));
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 2));
-
- // After client2's jobs finish, client1's job should resume.
- EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 2));
- EXPECT_EQ(mClientCallback2->pop(kPaddingUs), EventTracker::Resume(CLIENT(2), 0));
-
- unregisterMultipleClients();
-
- EXPECT_TRUE(ShellHelper::Stop(kClientPackageA));
- EXPECT_TRUE(ShellHelper::Stop(kClientPackageB));
- EXPECT_TRUE(ShellHelper::Stop(kClientPackageC));
-
- ALOGD("TestTranscodingUidPolicy finished.");
-}
-
-} // namespace media
-} // namespace android