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;