Merge "[DO NOT MERGE] Fix Heap use after free in clearkey getSecureStops" into qt-qpr1-dev
diff --git a/camera/aidl/android/hardware/ICameraServiceListener.aidl b/camera/aidl/android/hardware/ICameraServiceListener.aidl
index e9dcbdb..47580f8 100644
--- a/camera/aidl/android/hardware/ICameraServiceListener.aidl
+++ b/camera/aidl/android/hardware/ICameraServiceListener.aidl
@@ -83,4 +83,12 @@
* can retry after receiving this callback.
*/
oneway void onCameraAccessPrioritiesChanged();
+
+ /**
+ * Notify registered clients about cameras being opened/closed.
+ * Only clients with android.permission.CAMERA_OPEN_CLOSE_LISTENER permission
+ * will receive such callbacks.
+ */
+ oneway void onCameraOpened(String cameraId, String clientPackageId);
+ oneway void onCameraClosed(String cameraId);
}
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
index 8c1da36..28fec82 100644
--- a/camera/ndk/impl/ACameraManager.h
+++ b/camera/ndk/impl/ACameraManager.h
@@ -92,6 +92,12 @@
}
virtual binder::Status onCameraAccessPrioritiesChanged();
+ virtual binder::Status onCameraOpened(const String16&, const String16&) {
+ return binder::Status::ok();
+ }
+ virtual binder::Status onCameraClosed(const String16&) {
+ return binder::Status::ok();
+ }
private:
const wp<CameraManagerGlobal> mCameraManager;
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index 8fe029a..dc5afc5 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -95,6 +95,17 @@
return binder::Status::ok();
}
+ virtual binder::Status onCameraOpened(const String16& /*cameraId*/,
+ const String16& /*clientPackageName*/) {
+ // No op
+ return binder::Status::ok();
+ }
+
+ virtual binder::Status onCameraClosed(const String16& /*cameraId*/) {
+ // No op
+ return binder::Status::ok();
+ }
+
bool waitForNumCameras(size_t num) const {
Mutex::Autolock l(mLock);
diff --git a/drm/libmediadrm/ICrypto.cpp b/drm/libmediadrm/ICrypto.cpp
index a2594aa..8d8d088 100644
--- a/drm/libmediadrm/ICrypto.cpp
+++ b/drm/libmediadrm/ICrypto.cpp
@@ -264,8 +264,12 @@
{
CHECK_INTERFACE(ICrypto, data, reply);
- uint8_t uuid[16];
- data.read(uuid, sizeof(uuid));
+ uint8_t uuid[16] = {0};
+ if (data.read(uuid, sizeof(uuid)) != NO_ERROR) {
+ android_errorWriteLog(0x534e4554, "144767096");
+ reply->writeInt32(BAD_VALUE);
+ return OK;
+ }
size_t opaqueSize = data.readInt32();
void *opaqueData = NULL;
@@ -280,7 +284,11 @@
return NO_MEMORY;
}
- data.read(opaqueData, opaqueSize);
+ if (data.read(opaqueData, opaqueSize) != NO_ERROR) {
+ android_errorWriteLog(0x534e4554, "144767096");
+ reply->writeInt32(BAD_VALUE);
+ return OK;
+ }
reply->writeInt32(createPlugin(uuid, opaqueData, opaqueSize));
free(opaqueData);
diff --git a/drm/mediadrm/plugins/clearkey/default/InitDataParser.cpp b/drm/mediadrm/plugins/clearkey/default/InitDataParser.cpp
index caff393..121a4e2 100644
--- a/drm/mediadrm/plugins/clearkey/default/InitDataParser.cpp
+++ b/drm/mediadrm/plugins/clearkey/default/InitDataParser.cpp
@@ -76,10 +76,21 @@
android::status_t InitDataParser::parsePssh(const Vector<uint8_t>& initData,
Vector<const uint8_t*>* keyIds) {
+ // Description of PSSH format:
+ // https://w3c.github.io/encrypted-media/format-registry/initdata/cenc.html
size_t readPosition = 0;
- // Validate size field
uint32_t expectedSize = initData.size();
+ const char psshIdentifier[4] = {'p', 's', 's', 'h'};
+ const uint8_t psshVersion1[4] = {1, 0, 0, 0};
+ uint32_t keyIdCount = 0;
+ size_t headerSize = sizeof(expectedSize) + sizeof(psshIdentifier) +
+ sizeof(psshVersion1) + kSystemIdSize + sizeof(keyIdCount);
+ if (initData.size() < headerSize) {
+ return android::ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ // Validate size field
expectedSize = htonl(expectedSize);
if (memcmp(&initData[readPosition], &expectedSize,
sizeof(expectedSize)) != 0) {
@@ -88,7 +99,6 @@
readPosition += sizeof(expectedSize);
// Validate PSSH box identifier
- const char psshIdentifier[4] = {'p', 's', 's', 'h'};
if (memcmp(&initData[readPosition], psshIdentifier,
sizeof(psshIdentifier)) != 0) {
return android::ERROR_DRM_CANNOT_HANDLE;
@@ -96,7 +106,6 @@
readPosition += sizeof(psshIdentifier);
// Validate EME version number
- const uint8_t psshVersion1[4] = {1, 0, 0, 0};
if (memcmp(&initData[readPosition], psshVersion1,
sizeof(psshVersion1)) != 0) {
return android::ERROR_DRM_CANNOT_HANDLE;
@@ -110,12 +119,14 @@
readPosition += kSystemIdSize;
// Read key ID count
- uint32_t keyIdCount;
memcpy(&keyIdCount, &initData[readPosition], sizeof(keyIdCount));
keyIdCount = ntohl(keyIdCount);
readPosition += sizeof(keyIdCount);
- if (readPosition + ((uint64_t)keyIdCount * kKeyIdSize) !=
- initData.size() - sizeof(uint32_t)) {
+
+ uint64_t psshSize = 0;
+ if (__builtin_mul_overflow(keyIdCount, kKeyIdSize, &psshSize) ||
+ __builtin_add_overflow(readPosition, psshSize, &psshSize) ||
+ psshSize != initData.size() - sizeof(uint32_t) /* DataSize(0) */) {
return android::ERROR_DRM_CANNOT_HANDLE;
}
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 4a31953..78ddd6d 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -1286,7 +1286,8 @@
{
Mutexed<Config>::Locked config(mConfig);
inputFormat = config->mInputFormat;
- outputFormat = config->mOutputFormat;
+ // start triggers format dup
+ outputFormat = config->mOutputFormat = config->mOutputFormat->dup();
if (config->mInputSurface) {
err2 = config->mInputSurface->start();
}
@@ -1295,6 +1296,8 @@
mCallback->onError(err2, ACTION_CODE_FATAL);
return;
}
+ // We're not starting after flush.
+ (void)mSentConfigAfterResume.test_and_set();
err2 = mChannel->start(inputFormat, outputFormat);
if (err2 != OK) {
mCallback->onError(err2, ACTION_CODE_FATAL);
@@ -1523,18 +1526,26 @@
}
void CCodec::signalResume() {
- auto setResuming = [this] {
+ std::shared_ptr<Codec2Client::Component> comp;
+ auto setResuming = [this, &comp] {
Mutexed<State>::Locked state(mState);
if (state->get() != FLUSHED) {
return UNKNOWN_ERROR;
}
state->set(RESUMING);
+ comp = state->comp;
return OK;
};
if (tryAndReportOnError(setResuming) != OK) {
return;
}
+ mSentConfigAfterResume.clear();
+ {
+ Mutexed<Config>::Locked config(mConfig);
+ config->queryConfiguration(comp);
+ }
+
(void)mChannel->start(nullptr, nullptr);
{
@@ -1730,7 +1741,7 @@
// handle configuration changes in work done
Mutexed<Config>::Locked config(mConfig);
- bool changed = false;
+ bool changed = !mSentConfigAfterResume.test_and_set();
Config::Watcher<C2StreamInitDataInfo::output> initData =
config->watch<C2StreamInitDataInfo::output>();
if (!work->worklets.empty()
@@ -1762,7 +1773,9 @@
++stream;
}
- changed = config->updateConfiguration(updates, config->mOutputDomain);
+ if (config->updateConfiguration(updates, config->mOutputDomain)) {
+ changed = true;
+ }
// copy standard infos to graphic buffers if not already present (otherwise, we
// may overwrite the actual intermediate value with a final value)
diff --git a/media/codec2/sfplugin/CCodec.h b/media/codec2/sfplugin/CCodec.h
index b0b3c4f..a580d1d 100644
--- a/media/codec2/sfplugin/CCodec.h
+++ b/media/codec2/sfplugin/CCodec.h
@@ -17,6 +17,7 @@
#ifndef C_CODEC_H_
#define C_CODEC_H_
+#include <atomic>
#include <chrono>
#include <list>
#include <memory>
@@ -175,6 +176,7 @@
typedef CCodecConfig Config;
Mutexed<Config> mConfig;
Mutexed<std::list<std::unique_ptr<C2Work>>> mWorkDoneQueue;
+ std::atomic_flag mSentConfigAfterResume;
friend class CCodecCallbackImpl;
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 2efb987..4ee6c1c 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -1072,7 +1072,7 @@
} else {
output->buffers.reset(new LinearOutputBuffers(mName));
}
- output->buffers->setFormat(outputFormat->dup());
+ output->buffers->setFormat(outputFormat);
// Try to set output surface to created block pool if given.
@@ -1276,6 +1276,24 @@
std::unique_ptr<C2Work> work,
const sp<AMessage> &outputFormat,
const C2StreamInitDataInfo::output *initData) {
+ if (outputFormat != nullptr) {
+ Mutexed<Output>::Locked output(mOutput);
+ ALOGD("[%s] onWorkDone: output format changed to %s",
+ mName, outputFormat->debugString().c_str());
+ output->buffers->setFormat(outputFormat);
+
+ AString mediaType;
+ if (outputFormat->findString(KEY_MIME, &mediaType)
+ && mediaType == MIMETYPE_AUDIO_RAW) {
+ int32_t channelCount;
+ int32_t sampleRate;
+ if (outputFormat->findInt32(KEY_CHANNEL_COUNT, &channelCount)
+ && outputFormat->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
+ output->buffers->updateSkipCutBuffer(sampleRate, channelCount);
+ }
+ }
+ }
+
if ((work->input.ordinal.frameIndex - mFirstValidFrameIndex.load()).peek() < 0) {
// Discard frames from previous generation.
ALOGD("[%s] Discard frames from previous generation.", mName);
@@ -1453,24 +1471,6 @@
}
}
- if (outputFormat != nullptr) {
- Mutexed<Output>::Locked output(mOutput);
- ALOGD("[%s] onWorkDone: output format changed to %s",
- mName, outputFormat->debugString().c_str());
- output->buffers->setFormat(outputFormat);
-
- AString mediaType;
- if (outputFormat->findString(KEY_MIME, &mediaType)
- && mediaType == MIMETYPE_AUDIO_RAW) {
- int32_t channelCount;
- int32_t sampleRate;
- if (outputFormat->findInt32(KEY_CHANNEL_COUNT, &channelCount)
- && outputFormat->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
- output->buffers->updateSkipCutBuffer(sampleRate, channelCount);
- }
- }
- }
-
int32_t flags = 0;
if (worklet->output.flags & C2FrameData::FLAG_END_OF_STREAM) {
flags |= MediaCodec::BUFFER_FLAG_EOS;
diff --git a/media/extractors/midi/Android.bp b/media/extractors/midi/Android.bp
index 7d42e70..91ce78e 100644
--- a/media/extractors/midi/Android.bp
+++ b/media/extractors/midi/Android.bp
@@ -14,7 +14,9 @@
static_libs: [
"libmedia_midiiowrapper",
"libsonivox",
- "libstagefright_foundation"
+ "libstagefright_foundation",
+ "libwatchdog",
+ "libbase",
],
name: "libmidiextractor",
relative_install_path: "extractors",
@@ -35,5 +37,4 @@
"signed-integer-overflow",
],
},
-
}
diff --git a/media/extractors/midi/MidiExtractor.cpp b/media/extractors/midi/MidiExtractor.cpp
index 9f4f9e6..d0efb2f 100644
--- a/media/extractors/midi/MidiExtractor.cpp
+++ b/media/extractors/midi/MidiExtractor.cpp
@@ -26,6 +26,7 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <libsonivox/eas_reverb.h>
+#include <watchdog/Watchdog.h>
namespace android {
@@ -116,6 +117,7 @@
MediaBufferHelper **outBuffer, const ReadOptions *options)
{
ALOGV("MidiSource::read");
+
MediaBufferHelper *buffer;
// process an optional seek request
int64_t seekTimeUs;
@@ -139,6 +141,8 @@
}
// MidiEngine
+using namespace std::chrono_literals;
+static constexpr auto kTimeout = 10s;
MidiEngine::MidiEngine(CDataSource *dataSource,
AMediaFormat *fileMetadata,
@@ -147,6 +151,8 @@
mEasHandle(NULL),
mEasConfig(NULL),
mIsInitialized(false) {
+ Watchdog watchdog(kTimeout);
+
mIoWrapper = new MidiIoWrapper(dataSource);
// spin up a new EAS engine
EAS_I32 temp;
@@ -186,6 +192,8 @@
}
MidiEngine::~MidiEngine() {
+ Watchdog watchdog(kTimeout);
+
if (mEasHandle) {
EAS_CloseFile(mEasData, mEasHandle);
}
@@ -217,12 +225,16 @@
}
status_t MidiEngine::seekTo(int64_t positionUs) {
+ Watchdog watchdog(kTimeout);
+
ALOGV("seekTo %lld", (long long)positionUs);
EAS_RESULT result = EAS_Locate(mEasData, mEasHandle, positionUs / 1000, false);
return result == EAS_SUCCESS ? OK : UNKNOWN_ERROR;
}
MediaBufferHelper* MidiEngine::readBuffer() {
+ Watchdog watchdog(kTimeout);
+
EAS_STATE state;
EAS_State(mEasData, mEasHandle, &state);
if ((state == EAS_STATE_STOPPED) || (state == EAS_STATE_ERROR)) {
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 9d5890c..14fe0dc 100755
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -5440,16 +5440,12 @@
// apply some sanity (vs strict legality) checks
//
- // clamp the count of entries in the trun box, to avoid spending forever parsing
- // this box. Clamping (vs error) lets us play *something*.
- // 1 million is about 400 msecs on a Pixel3, should be no more than a couple seconds
- // on the slowest devices.
- static constexpr uint32_t kMaxTrunSampleCount = 1000000;
+ static constexpr uint32_t kMaxTrunSampleCount = 10000;
if (sampleCount > kMaxTrunSampleCount) {
- ALOGW("b/123389881 clamp sampleCount(%u) @ kMaxTrunSampleCount(%u)",
+ ALOGW("b/123389881 sampleCount(%u) > kMaxTrunSampleCount(%u)",
sampleCount, kMaxTrunSampleCount);
android_errorWriteLog(0x534e4554, "124389881 count");
-
+ return -EINVAL;
}
}
@@ -5493,7 +5489,12 @@
tmp.duration = sampleDuration;
tmp.compositionOffset = sampleCtsOffset;
memset(tmp.iv, 0, sizeof(tmp.iv));
- mCurrentSamples.add(tmp);
+ if (mCurrentSamples.add(tmp) < 0) {
+ ALOGW("b/123389881 failed saving sample(n=%zu)", mCurrentSamples.size());
+ android_errorWriteLog(0x534e4554, "124389881 allocation");
+ mCurrentSamples.clear();
+ return NO_MEMORY;
+ }
dataOffset += sampleSize;
}
diff --git a/media/libaaudio/src/binding/IAAudioService.cpp b/media/libaaudio/src/binding/IAAudioService.cpp
index 97ad2b0..e017b3a 100644
--- a/media/libaaudio/src/binding/IAAudioService.cpp
+++ b/media/libaaudio/src/binding/IAAudioService.cpp
@@ -237,12 +237,12 @@
status_t BnAAudioService::onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags) {
- aaudio_handle_t streamHandle;
+ aaudio_handle_t streamHandle = 0;
aaudio::AAudioStreamRequest request;
aaudio::AAudioStreamConfiguration configuration;
- pid_t tid;
- int64_t nanoseconds;
- aaudio_result_t result;
+ pid_t tid = 0;
+ int64_t nanoseconds = 0;
+ aaudio_result_t result = AAUDIO_OK;
status_t status = NO_ERROR;
ALOGV("BnAAudioService::onTransact(%i) %i", code, flags);
@@ -285,7 +285,11 @@
case CLOSE_STREAM: {
CHECK_INTERFACE(IAAudioService, data, reply);
- data.readInt32(&streamHandle);
+ status = data.readInt32(&streamHandle);
+ if (status != NO_ERROR) {
+ ALOGE("BnAAudioService::%s(CLOSE_STREAM) streamHandle failed!", __func__);
+ return status;
+ }
result = closeStream(streamHandle);
//ALOGD("BnAAudioService::onTransact CLOSE_STREAM 0x%08X, result = %d",
// streamHandle, result);
@@ -297,6 +301,7 @@
CHECK_INTERFACE(IAAudioService, data, reply);
status = data.readInt32(&streamHandle);
if (status != NO_ERROR) {
+ ALOGE("BnAAudioService::%s(GET_STREAM_DESCRIPTION) streamHandle failed!", __func__);
return status;
}
aaudio::AudioEndpointParcelable parcelable;
@@ -313,7 +318,11 @@
case START_STREAM: {
CHECK_INTERFACE(IAAudioService, data, reply);
- data.readInt32(&streamHandle);
+ status = data.readInt32(&streamHandle);
+ if (status != NO_ERROR) {
+ ALOGE("BnAAudioService::%s(START_STREAM) streamHandle failed!", __func__);
+ return status;
+ }
result = startStream(streamHandle);
ALOGV("BnAAudioService::onTransact START_STREAM 0x%08X, result = %d",
streamHandle, result);
@@ -323,7 +332,11 @@
case PAUSE_STREAM: {
CHECK_INTERFACE(IAAudioService, data, reply);
- data.readInt32(&streamHandle);
+ status = data.readInt32(&streamHandle);
+ if (status != NO_ERROR) {
+ ALOGE("BnAAudioService::%s(PAUSE_STREAM) streamHandle failed!", __func__);
+ return status;
+ }
result = pauseStream(streamHandle);
ALOGV("BnAAudioService::onTransact PAUSE_STREAM 0x%08X, result = %d",
streamHandle, result);
@@ -333,7 +346,11 @@
case STOP_STREAM: {
CHECK_INTERFACE(IAAudioService, data, reply);
- data.readInt32(&streamHandle);
+ status = data.readInt32(&streamHandle);
+ if (status != NO_ERROR) {
+ ALOGE("BnAAudioService::%s(STOP_STREAM) streamHandle failed!", __func__);
+ return status;
+ }
result = stopStream(streamHandle);
ALOGV("BnAAudioService::onTransact STOP_STREAM 0x%08X, result = %d",
streamHandle, result);
@@ -343,7 +360,11 @@
case FLUSH_STREAM: {
CHECK_INTERFACE(IAAudioService, data, reply);
- data.readInt32(&streamHandle);
+ status = data.readInt32(&streamHandle);
+ if (status != NO_ERROR) {
+ ALOGE("BnAAudioService::%s(FLUSH_STREAM) streamHandle failed!", __func__);
+ return status;
+ }
result = flushStream(streamHandle);
ALOGV("BnAAudioService::onTransact FLUSH_STREAM 0x%08X, result = %d",
streamHandle, result);
@@ -353,20 +374,40 @@
case REGISTER_AUDIO_THREAD: {
CHECK_INTERFACE(IAAudioService, data, reply);
- data.readInt32(&streamHandle);
- data.readInt32(&tid);
- data.readInt64(&nanoseconds);
+ status = data.readInt32(&streamHandle);
+ if (status != NO_ERROR) {
+ ALOGE("BnAAudioService::%s(REGISTER_AUDIO_THREAD) streamHandle failed!", __func__);
+ return status;
+ }
+ status = data.readInt32(&tid);
+ if (status != NO_ERROR) {
+ ALOGE("BnAAudioService::%s(REGISTER_AUDIO_THREAD) tid failed!", __func__);
+ return status;
+ }
+ status = data.readInt64(&nanoseconds);
+ if (status != NO_ERROR) {
+ ALOGE("BnAAudioService::%s(REGISTER_AUDIO_THREAD) nanoseconds failed!", __func__);
+ return status;
+ }
result = registerAudioThread(streamHandle, tid, nanoseconds);
- ALOGV("BnAAudioService::onTransact REGISTER_AUDIO_THREAD 0x%08X, result = %d",
- streamHandle, result);
+ ALOGV("BnAAudioService::%s(REGISTER_AUDIO_THREAD) 0x%08X, result = %d",
+ __func__, streamHandle, result);
reply->writeInt32(result);
return NO_ERROR;
} break;
case UNREGISTER_AUDIO_THREAD: {
CHECK_INTERFACE(IAAudioService, data, reply);
- data.readInt32(&streamHandle);
- data.readInt32(&tid);
+ status = data.readInt32(&streamHandle);
+ if (status != NO_ERROR) {
+ ALOGE("BnAAudioService::%s(UNREGISTER_AUDIO_THREAD) streamHandle failed!", __func__);
+ return status;
+ }
+ status = data.readInt32(&tid);
+ if (status != NO_ERROR) {
+ ALOGE("BnAAudioService::%s(UNREGISTER_AUDIO_THREAD) tid failed!", __func__);
+ return status;
+ }
result = unregisterAudioThread(streamHandle, tid);
ALOGV("BnAAudioService::onTransact UNREGISTER_AUDIO_THREAD 0x%08X, result = %d",
streamHandle, result);
diff --git a/media/libstagefright/foundation/OpusHeader.cpp b/media/libstagefright/foundation/OpusHeader.cpp
index 513e41f..f5687e0 100644
--- a/media/libstagefright/foundation/OpusHeader.cpp
+++ b/media/libstagefright/foundation/OpusHeader.cpp
@@ -292,6 +292,10 @@
*opusHeadSize = data_size;
return true;
} else if (memcmp(AOPUS_CSD_MARKER_PREFIX, data, AOPUS_CSD_MARKER_PREFIX_SIZE) == 0) {
+ if (data_size < AOPUS_UNIFIED_CSD_MINSIZE || data_size > AOPUS_UNIFIED_CSD_MAXSIZE) {
+ ALOGD("Unexpected size for unified opus csd %zu", data_size);
+ return false;
+ }
size_t i = 0;
bool found = false;
while (i <= data_size - AOPUS_MARKER_SIZE - AOPUS_LENGTH_SIZE) {
diff --git a/media/libwatchdog/Android.bp b/media/libwatchdog/Android.bp
new file mode 100644
index 0000000..2bdf172
--- /dev/null
+++ b/media/libwatchdog/Android.bp
@@ -0,0 +1,35 @@
+// Copyright 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.
+
+cc_library {
+ name: "libwatchdog",
+ srcs: [
+ "Watchdog.cpp",
+ ],
+ export_include_dirs: ["include"],
+ shared_libs: [
+ "liblog",
+ ],
+ static_libs: [
+ "libbase",
+ ],
+ target: {
+ windows: {
+ enabled: false,
+ },
+ darwin: {
+ enabled: false,
+ },
+ },
+}
diff --git a/media/libwatchdog/Watchdog.cpp b/media/libwatchdog/Watchdog.cpp
new file mode 100644
index 0000000..bb012b9
--- /dev/null
+++ b/media/libwatchdog/Watchdog.cpp
@@ -0,0 +1,63 @@
+/*
+ * 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_TAG "Watchdog"
+
+#include <watchdog/Watchdog.h>
+
+#include <android-base/logging.h>
+#include <android-base/threads.h>
+#include <signal.h>
+#include <time.h>
+#include <cstring>
+#include <utils/Log.h>
+
+namespace android {
+
+Watchdog::Watchdog(::std::chrono::steady_clock::duration timeout) {
+ // Create the timer.
+ struct sigevent sev;
+ sev.sigev_notify = SIGEV_THREAD_ID;
+ sev.sigev_notify_thread_id = base::GetThreadId();
+ sev.sigev_signo = SIGABRT;
+ sev.sigev_value.sival_ptr = &mTimerId;
+ int err = timer_create(CLOCK_MONOTONIC, &sev, &mTimerId);
+ if (err != 0) {
+ PLOG(FATAL) << "Failed to create timer";
+ }
+
+ // Start the timer.
+ struct itimerspec spec;
+ memset(&spec, 0, sizeof(spec));
+ auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(timeout);
+ LOG_ALWAYS_FATAL_IF(timeout.count() <= 0, "Duration must be positive");
+ spec.it_value.tv_sec = ns.count() / 1000000000;
+ spec.it_value.tv_nsec = ns.count() % 1000000000;
+ err = timer_settime(mTimerId, 0, &spec, nullptr);
+ if (err != 0) {
+ PLOG(FATAL) << "Failed to start timer";
+ }
+}
+
+Watchdog::~Watchdog() {
+ // Delete the timer.
+ int err = timer_delete(mTimerId);
+ if (err != 0) {
+ PLOG(FATAL) << "Failed to delete timer";
+ }
+}
+
+} // namespace android
diff --git a/media/libwatchdog/include/watchdog/Watchdog.h b/media/libwatchdog/include/watchdog/Watchdog.h
new file mode 100644
index 0000000..2819f8a
--- /dev/null
+++ b/media/libwatchdog/include/watchdog/Watchdog.h
@@ -0,0 +1,49 @@
+/*
+ * 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_WATCHDOG_H
+#define ANDROID_WATCHDOG_H
+
+#include <chrono>
+#include <time.h>
+
+namespace android {
+
+/*
+ * An RAII-style object, which would crash the process if a timeout expires
+ * before the object is destroyed.
+ * The calling thread would be sent a SIGABORT, which would typically result in
+ * a stack trace.
+ *
+ * Sample usage:
+ * {
+ * Watchdog watchdog(std::chrono::milliseconds(10));
+ * DoSomething();
+ * }
+ * // If we got here, the function completed in time.
+ */
+class Watchdog final {
+public:
+ Watchdog(std::chrono::steady_clock::duration timeout);
+ ~Watchdog();
+
+private:
+ timer_t mTimerId;
+};
+
+} // namespace android
+
+#endif // ANDROID_WATCHDOG_H
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index ca8cb78..dd69496 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -44,6 +44,7 @@
#include "MtpStringBuffer.h"
namespace android {
+static const int SN_EVENT_LOG_ID = 0x534e4554;
static const MtpOperationCode kSupportedOperationCodes[] = {
MTP_OPERATION_GET_DEVICE_INFO,
@@ -961,6 +962,17 @@
if (!parseDateTime(modified, modifiedTime))
modifiedTime = 0;
+ if ((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0) ||
+ (strchr(name, '/') != NULL)) {
+ char errMsg[80];
+
+ snprintf(errMsg, sizeof(errMsg), "Invalid name: %s", (const char *) name);
+ ALOGE("%s (b/130656917)", errMsg);
+ android_errorWriteWithInfoLog(SN_EVENT_LOG_ID, "130656917", -1, errMsg,
+ strlen(errMsg));
+
+ return MTP_RESPONSE_INVALID_PARAMETER;
+ }
if (path[path.size() - 1] != '/')
path.append("/");
path.append(name);
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index c048de3..a984b10 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -5535,7 +5535,10 @@
patchBuilder.addSink(filteredDevice);
}
- installPatch(__func__, patchHandle, outputDesc.get(), patchBuilder.patch(), delayMs);
+ // Add half reported latency to delayMs when muteWaitMs is null in order
+ // to avoid disordered sequence of muting volume and changing devices.
+ installPatch(__func__, patchHandle, outputDesc.get(), patchBuilder.patch(),
+ muteWaitMs == 0 ? (delayMs + (outputDesc->latency() / 2)) : delayMs);
}
// update stream volumes according to new device
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index b20c9a4..670e026 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -118,6 +118,8 @@
// ----------------------------------------------------------------------------
static const String16 sManageCameraPermission("android.permission.MANAGE_CAMERA");
+static const String16 sCameraOpenCloseListenerPermission(
+ "android.permission.CAMERA_OPEN_CLOSE_LISTENER");
// Matches with PERCEPTIBLE_APP_ADJ in ProcessList.java
static constexpr int32_t kVendorClientScore = 200;
@@ -1811,7 +1813,11 @@
}
auto clientUid = CameraThreadState::getCallingUid();
- sp<ServiceListener> serviceListener = new ServiceListener(this, listener, clientUid);
+ auto clientPid = CameraThreadState::getCallingPid();
+ bool openCloseCallbackAllowed = checkPermission(sCameraOpenCloseListenerPermission,
+ clientPid, clientUid);
+ sp<ServiceListener> serviceListener = new ServiceListener(this, listener,
+ clientUid, clientPid, openCloseCallbackAllowed);
auto ret = serviceListener->initialize();
if (ret != NO_ERROR) {
String8 msg = String8::format("Failed to initialize service listener: %s (%d)",
@@ -2515,6 +2521,9 @@
sCameraService->mUidPolicy->registerMonitorUid(mClientUid);
+ // Notify listeners of camera open/close status
+ sCameraService->updateOpenCloseStatus(mCameraIdStr, true/*open*/, mClientPackageName);
+
return OK;
}
@@ -2555,6 +2564,9 @@
sCameraService->mUidPolicy->unregisterMonitorUid(mClientUid);
+ // Notify listeners of camera open/close status
+ sCameraService->updateOpenCloseStatus(mCameraIdStr, false/*open*/, mClientPackageName);
+
return OK;
}
@@ -3311,6 +3323,29 @@
});
}
+void CameraService::updateOpenCloseStatus(const String8& cameraId, bool open,
+ const String16& clientPackageName) {
+ Mutex::Autolock lock(mStatusListenerLock);
+
+ for (const auto& it : mListenerList) {
+ if (!it.second->isOpenCloseCallbackAllowed()) {
+ continue;
+ }
+
+ binder::Status ret;
+ String16 cameraId64(cameraId);
+ if (open) {
+ ret = it.second->getListener()->onCameraOpened(cameraId64, clientPackageName);
+ } else {
+ ret = it.second->getListener()->onCameraClosed(cameraId64);
+ }
+ if (!ret.isOk()) {
+ ALOGE("%s: Failed to trigger onCameraOpened/onCameraClosed callback: %d", __FUNCTION__,
+ ret.exceptionCode());
+ }
+ }
+}
+
template<class Func>
void CameraService::CameraState::updateStatus(StatusInternal status,
const String8& cameraId,
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 22842a1..bcaca9f 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -817,7 +817,9 @@
class ServiceListener : public virtual IBinder::DeathRecipient {
public:
ServiceListener(sp<CameraService> parent, sp<hardware::ICameraServiceListener> listener,
- int uid) : mParent(parent), mListener(listener), mListenerUid(uid) {}
+ int uid, int pid, bool openCloseCallbackAllowed) : mParent(parent),
+ mListener(listener), mListenerUid(uid), mListenerPid(pid),
+ mOpenCloseCallbackAllowed(openCloseCallbackAllowed) {}
status_t initialize() {
return IInterface::asBinder(mListener)->linkToDeath(this);
@@ -831,12 +833,16 @@
}
int getListenerUid() { return mListenerUid; }
+ int getListenerPid() { return mListenerPid; }
sp<hardware::ICameraServiceListener> getListener() { return mListener; }
+ bool isOpenCloseCallbackAllowed() { return mOpenCloseCallbackAllowed; }
private:
wp<CameraService> mParent;
sp<hardware::ICameraServiceListener> mListener;
int mListenerUid;
+ int mListenerPid;
+ bool mOpenCloseCallbackAllowed = false;
};
// Guarded by mStatusListenerMutex
@@ -859,6 +865,13 @@
void updateStatus(StatusInternal status,
const String8& cameraId);
+ /**
+ * Update the opened/closed status of the given camera id.
+ *
+ * This method acqiures mStatusListenerLock.
+ */
+ void updateOpenCloseStatus(const String8& cameraId, bool open, const String16& packageName);
+
// flashlight control
sp<CameraFlashlight> mFlashlight;
// guard mTorchStatusMap
diff --git a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h
index 0f6be79..b9e5857 100644
--- a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h
+++ b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h
@@ -54,6 +54,15 @@
// TODO: no implementation yet.
return binder::Status::ok();
}
+ virtual binder::Status onCameraOpened(const ::android::String16& /*cameraId*/,
+ const ::android::String16& /*clientPackageId*/) {
+ // empty implementation
+ return binder::Status::ok();
+ }
+ virtual binder::Status onCameraClosed(const ::android::String16& /*cameraId*/) {
+ // empty implementation
+ return binder::Status::ok();
+ }
};
} // implementation
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
index 38f9be6..118072e 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
@@ -41,6 +41,9 @@
getgroups32: 1
nanosleep: 1
getrandom: 1
+timer_create: 1
+timer_settime: 1
+timer_delete: 1
# for dynamically loading extractors
pread64: 1
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
index 8fd8787..481e29e 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
@@ -30,6 +30,9 @@
getrlimit: 1
nanosleep: 1
getrandom: 1
+timer_create: 1
+timer_settime: 1
+timer_delete: 1
# for FileSource
readlinkat: 1
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
index 05915d1..15fb24e 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
@@ -39,6 +39,9 @@
getgroups32: 1
nanosleep: 1
getrandom: 1
+timer_create: 1
+timer_settime: 1
+timer_delete: 1
# for dynamically loading extractors
getdents64: 1
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-x86_64.policy b/services/mediaextractor/seccomp_policy/mediaextractor-x86_64.policy
index e6a55d0..4f2646c 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-x86_64.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-x86_64.policy
@@ -34,6 +34,9 @@
getrlimit: 1
nanosleep: 1
getrandom: 1
+timer_create: 1
+timer_settime: 1
+timer_delete: 1
# for dynamically loading extractors
getdents64: 1