diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index d6e48157063c..919832bd0bfb 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -5990,6 +5990,10 @@ package android.media {
method @NonNull public android.media.HwAudioSource.Builder setAudioDeviceInfo(@NonNull android.media.AudioDeviceInfo);
}
+ public final class MediaCodec {
+ method @NonNull @RequiresPermission("android.permission.MEDIA_RESOURCE_OVERRIDE_PID") public static android.media.MediaCodec createByCodecNameForClient(@NonNull String, int, int) throws java.io.IOException;
+ }
+
public class MediaPlayer implements android.media.AudioRouting android.media.VolumeAutomation {
method @RequiresPermission(android.Manifest.permission.BIND_IMS_SERVICE) public void setOnRtpRxNoticeListener(@NonNull android.content.Context, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaPlayer.OnRtpRxNoticeListener);
}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index b3dcc34d6e93..58a4d3568e17 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -502,6 +502,8 @@ applications that come with the platform
+
+
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 939b679676aa..4563259c31f2 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -16,9 +16,12 @@
package android.media;
+import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.ImageFormat;
import android.graphics.Rect;
@@ -1934,12 +1937,41 @@ final public class MediaCodec {
@NonNull
public static MediaCodec createByCodecName(@NonNull String name)
throws IOException {
- return new MediaCodec(
- name, false /* nameIsType */, false /* unused */);
+ return new MediaCodec(name, false /* nameIsType */, false /* encoder */);
}
- private MediaCodec(
- @NonNull String name, boolean nameIsType, boolean encoder) {
+ /**
+ * This is the same as createByCodecName, but allows for instantiating a codec on behalf of a
+ * client process. This is used for system apps or system services that create MediaCodecs on
+ * behalf of other processes and will reclaim resources as necessary from processes with lower
+ * priority than the client process, rather than processes with lower priority than the system
+ * app or system service. Likely to be used with information obtained from
+ * {@link android.media.MediaCodecList}.
+ * @param name
+ * @param clientPid
+ * @param clientUid
+ * @throws IOException if the codec cannot be created.
+ * @throws IllegalArgumentException if name is not valid.
+ * @throws NullPointerException if name is null.
+ * @throws SecurityException if the MEDIA_RESOURCE_OVERRIDE_PID permission is not granted.
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MEDIA_RESOURCE_OVERRIDE_PID)
+ public static MediaCodec createByCodecNameForClient(@NonNull String name, int clientPid,
+ int clientUid) throws IOException {
+ return new MediaCodec(name, false /* nameIsType */, false /* encoder */, clientPid,
+ clientUid);
+ }
+
+ private MediaCodec(@NonNull String name, boolean nameIsType, boolean encoder) {
+ this(name, nameIsType, encoder, -1 /* pid */, -1 /* uid */);
+ }
+
+ private MediaCodec(@NonNull String name, boolean nameIsType, boolean encoder, int pid,
+ int uid) {
Looper looper;
if ((looper = Looper.myLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
@@ -1957,7 +1989,7 @@ final public class MediaCodec {
// save name used at creation
mNameAtCreation = nameIsType ? null : name;
- native_setup(name, nameIsType, encoder);
+ native_setup(name, nameIsType, encoder, pid, uid);
}
private String mNameAtCreation;
@@ -4991,7 +5023,7 @@ final public class MediaCodec {
private static native final void native_init();
private native final void native_setup(
- @NonNull String name, boolean nameIsType, boolean encoder);
+ @NonNull String name, boolean nameIsType, boolean encoder, int pid, int uid);
private native final void native_finalize();
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index f6944823feb5..c8d2d1ee621f 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -202,7 +202,7 @@ static const void *sRefBaseOwner;
JMediaCodec::JMediaCodec(
JNIEnv *env, jobject thiz,
- const char *name, bool nameIsType, bool encoder)
+ const char *name, bool nameIsType, bool encoder, int pid, int uid)
: mClass(NULL),
mObject(NULL) {
jclass clazz = env->GetObjectClass(thiz);
@@ -220,12 +220,12 @@ JMediaCodec::JMediaCodec(
ANDROID_PRIORITY_VIDEO);
if (nameIsType) {
- mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus);
+ mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus, pid, uid);
if (mCodec == nullptr || mCodec->getName(&mNameAtCreation) != OK) {
mNameAtCreation = "(null)";
}
} else {
- mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus);
+ mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus, pid, uid);
mNameAtCreation = name;
}
CHECK((mCodec != NULL) != (mInitStatus != OK));
@@ -3136,7 +3136,7 @@ static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
static void android_media_MediaCodec_native_setup(
JNIEnv *env, jobject thiz,
- jstring name, jboolean nameIsType, jboolean encoder) {
+ jstring name, jboolean nameIsType, jboolean encoder, int pid, int uid) {
if (name == NULL) {
jniThrowException(env, "java/lang/NullPointerException", NULL);
return;
@@ -3148,24 +3148,33 @@ static void android_media_MediaCodec_native_setup(
return;
}
- sp codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder);
+ sp codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder, pid, uid);
const status_t err = codec->initCheck();
if (err == NAME_NOT_FOUND) {
// fail and do not try again.
jniThrowException(env, "java/lang/IllegalArgumentException",
- String8::format("Failed to initialize %s, error %#x", tmp, err));
+ String8::format("Failed to initialize %s, error %#x (NAME_NOT_FOUND)", tmp, err));
env->ReleaseStringUTFChars(name, tmp);
return;
- } if (err == NO_MEMORY) {
+ }
+ if (err == NO_MEMORY) {
throwCodecException(env, err, ACTION_CODE_TRANSIENT,
- String8::format("Failed to initialize %s, error %#x", tmp, err));
+ String8::format("Failed to initialize %s, error %#x (NO_MEMORY)", tmp, err));
env->ReleaseStringUTFChars(name, tmp);
return;
- } else if (err != OK) {
+ }
+ if (err == PERMISSION_DENIED) {
+ jniThrowException(env, "java/lang/SecurityException",
+ String8::format("Failed to initialize %s, error %#x (PERMISSION_DENIED)", tmp,
+ err));
+ env->ReleaseStringUTFChars(name, tmp);
+ return;
+ }
+ if (err != OK) {
// believed possible to try again
jniThrowException(env, "java/io/IOException",
- String8::format("Failed to find matching codec %s, error %#x", tmp, err));
+ String8::format("Failed to find matching codec %s, error %#x (?)", tmp, err));
env->ReleaseStringUTFChars(name, tmp);
return;
}
@@ -3174,7 +3183,7 @@ static void android_media_MediaCodec_native_setup(
codec->registerSelf();
- setMediaCodec(env,thiz, codec);
+ setMediaCodec(env, thiz, codec);
}
static void android_media_MediaCodec_native_finalize(
@@ -3478,7 +3487,7 @@ static const JNINativeMethod gMethods[] = {
{ "native_init", "()V", (void *)android_media_MediaCodec_native_init },
- { "native_setup", "(Ljava/lang/String;ZZ)V",
+ { "native_setup", "(Ljava/lang/String;ZZII)V",
(void *)android_media_MediaCodec_native_setup },
{ "native_finalize", "()V",
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index ee456c9ba82d..616c31b29157 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -55,7 +55,7 @@ using hardware::cas::native::V1_0::IDescrambler;
struct JMediaCodec : public AHandler {
JMediaCodec(
JNIEnv *env, jobject thiz,
- const char *name, bool nameIsType, bool encoder);
+ const char *name, bool nameIsType, bool encoder, int pid, int uid);
status_t initCheck() const;