diff options
author | Philip P. Moltmann <moltmann@google.com> | 2020-07-17 16:39:54 -0700 |
---|---|---|
committer | Nate Myren <ntmyren@google.com> | 2021-03-11 08:40:40 -0800 |
commit | fece2436d418c0c0c5509a5b1d24a901a39b0340 (patch) | |
tree | 95b466bd3236f185ed51c6e682d8dee7e7bb8b80 | |
parent | 50f0175f3ed82670ca5d0b8f0da1f510217771b4 (diff) |
Add attributionTag to audio-recordings
... by switching from packageName/uid/pid to the Identity class.
This allows up to track which parts of the app trigger audio-recordings.
Test: atest CtsAppOpsTestCases
CtsNativeMediaAAudioTestCases
Fixes: 160150145
Change-Id: I0913a336a862e4a1cb38b9d967cfbdc490513ab0
25 files changed, 333 insertions, 84 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 922d8116d9fb..ece6ede4ec08 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -20565,6 +20565,7 @@ package android.media { method @NonNull public android.media.AudioRecord.Builder setAudioPlaybackCaptureConfig(@NonNull android.media.AudioPlaybackCaptureConfiguration); method public android.media.AudioRecord.Builder setAudioSource(int) throws java.lang.IllegalArgumentException; method public android.media.AudioRecord.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException; + method @NonNull public android.media.AudioRecord.Builder setContext(@NonNull android.content.Context); method @NonNull public android.media.AudioRecord.Builder setPrivacySensitive(boolean); } @@ -22739,7 +22740,8 @@ package android.media { } public class MediaRecorder implements android.media.AudioRecordingMonitor android.media.AudioRouting android.media.MicrophoneDirection { - ctor public MediaRecorder(); + ctor @Deprecated public MediaRecorder(); + ctor public MediaRecorder(@NonNull android.content.Context); method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler); method protected void finalize(); method public java.util.List<android.media.MicrophoneInfo> getActiveMicrophones() throws java.io.IOException; diff --git a/core/jni/Android.bp b/core/jni/Android.bp index d6d33873adaa..3c1b6f99aafd 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -1,4 +1,3 @@ - package { default_applicable_licenses: ["frameworks_base_core_jni_license"], } @@ -218,6 +217,7 @@ cc_library_shared { "fd_utils.cpp", "android_hardware_input_InputWindowHandle.cpp", "android_hardware_input_InputApplicationHandle.cpp", + "permission_utils.cpp", ], static_libs: [ @@ -236,6 +236,7 @@ cc_library_shared { "audioflinger-aidl-cpp", "av-types-aidl-cpp", "android.hardware.camera.device@3.2", + "media_permission-aidl-cpp", "libandroidicu", "libbpf_android", "libnetdbpf", diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index ddd861380fab..60d2db6efed8 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -97,6 +97,7 @@ extern int register_android_media_AudioVolumeGroupChangeHandler(JNIEnv *env); extern int register_android_media_MicrophoneInfo(JNIEnv *env); extern int register_android_media_ToneGenerator(JNIEnv *env); extern int register_android_media_midi(JNIEnv *env); +extern int register_android_media_permission_Identity(JNIEnv* env); namespace android { @@ -1562,6 +1563,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_media_RemoteDisplay), REG_JNI(register_android_media_ToneGenerator), REG_JNI(register_android_media_midi), + REG_JNI(register_android_media_permission_Identity), REG_JNI(register_android_opengl_classes), REG_JNI(register_android_server_NetworkManagementSocketTagger), diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp index 0e0f98ec1fc4..7d3febbd5d14 100644 --- a/core/jni/android_media_AudioRecord.cpp +++ b/core/jni/android_media_AudioRecord.cpp @@ -22,6 +22,7 @@ #include <jni.h> #include <nativehelper/JNIHelp.h> #include "core_jni_helpers.h" +#include "permission_utils.h" #include <utils/Log.h> #include <media/AudioRecord.h> @@ -39,6 +40,9 @@ // ---------------------------------------------------------------------------- +using android::media::permission::convertIdentity; +using android::media::permission::Identity; + using namespace android; // ---------------------------------------------------------------------------- @@ -181,12 +185,11 @@ static sp<AudioRecord> setAudioRecord(JNIEnv* env, jobject thiz, const sp<AudioR } // ---------------------------------------------------------------------------- -static jint -android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this, - jobject jaa, jintArray jSampleRate, jint channelMask, jint channelIndexMask, - jint audioFormat, jint buffSizeInBytes, jintArray jSession, jstring opPackageName, - jlong nativeRecordInJavaObj) -{ +static jint android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this, + jobject jaa, jintArray jSampleRate, jint channelMask, + jint channelIndexMask, jint audioFormat, + jint buffSizeInBytes, jintArray jSession, + jobject jIdentity, jlong nativeRecordInJavaObj) { //ALOGV(">> Entering android_media_AudioRecord_setup"); //ALOGV("sampleRate=%d, audioFormat=%d, channel mask=%x, buffSizeInBytes=%d " // "nativeRecordInJavaObj=0x%llX", @@ -262,10 +265,8 @@ android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this, size_t frameSize = channelCount * bytesPerSample; size_t frameCount = buffSizeInBytes / frameSize; - ScopedUtfChars opPackageNameStr(env, opPackageName); - // create an uninitialized AudioRecord object - lpRecorder = new AudioRecord(String16(opPackageNameStr.c_str())); + lpRecorder = new AudioRecord(convertIdentity(env, jIdentity)); // read the AudioAttributes values auto paa = JNIAudioAttributeHelper::makeUnique(); @@ -373,8 +374,6 @@ native_init_failure: return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED; } - - // ---------------------------------------------------------------------------- static jint android_media_AudioRecord_start(JNIEnv *env, jobject thiz, jint event, jint triggerSession) @@ -893,9 +892,11 @@ static jint android_media_AudioRecord_get_port_id(JNIEnv *env, jobject thiz) { // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- static const JNINativeMethod gMethods[] = { + // name, signature, funcPtr {"native_start", "(II)I", (void *)android_media_AudioRecord_start}, {"native_stop", "()V", (void *)android_media_AudioRecord_stop}, - {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILjava/lang/String;J)I", + {"native_setup", + "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILandroid/media/permission/Identity;J)I", (void *)android_media_AudioRecord_setup}, {"native_finalize", "()V", (void *)android_media_AudioRecord_finalize}, {"native_release", "()V", (void *)android_media_AudioRecord_release}, diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp index cae6db57e99c..62767a676e8b 100644 --- a/core/jni/android_media_AudioTrack.cpp +++ b/core/jni/android_media_AudioTrack.cpp @@ -48,6 +48,7 @@ using namespace android; using ::android::media::VolumeShaper; +using ::android::media::permission::Identity; // ---------------------------------------------------------------------------- static const char* const kClassPathName = "android/media/AudioTrack"; @@ -328,7 +329,10 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we // create the native AudioTrack object ScopedUtfChars opPackageNameStr(env, opPackageName); - lpTrack = new AudioTrack(opPackageNameStr.c_str()); + // TODO b/182469354: make consistent with AudioRecord + Identity identity = Identity(); + identity.packageName = std::string(opPackageNameStr.c_str()); + lpTrack = new AudioTrack(identity); // read the AudioAttributes values auto paa = JNIAudioAttributeHelper::makeUnique(); @@ -390,8 +394,8 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we sessionId, // audio session ID offload ? AudioTrack::TRANSFER_SYNC_NOTIF_CALLBACK : AudioTrack::TRANSFER_SYNC, - (offload || encapsulationMode) ? &offloadInfo : NULL, -1, - -1, // default uid, pid values + (offload || encapsulationMode) ? &offloadInfo : NULL, + Identity(), // default uid, pid values paa.get()); break; @@ -416,8 +420,8 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we true, // thread can call Java sessionId, // audio session ID AudioTrack::TRANSFER_SHARED, - NULL, // default offloadInfo - -1, -1, // default uid, pid values + NULL, // default offloadInfo + Identity(), // default uid, pid values paa.get()); break; diff --git a/core/jni/permission_utils.cpp b/core/jni/permission_utils.cpp new file mode 100644 index 000000000000..2b7ef9999491 --- /dev/null +++ b/core/jni/permission_utils.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "permission_utils.h" +#include "core_jni_helpers.h" + +static struct { + jfieldID fieldUid; // Identity.uid + jfieldID fieldPid; // Identity.pid + jfieldID fieldPackageName; // Identity.packageName + jfieldID fieldAttributionTag; // Identity.attributionTag +} javaIdentityFields; + +static const JNINativeMethod method_table[] = { + // no static methods, currently +}; + +int register_android_media_permission_Identity(JNIEnv* env) { + jclass identityClass = android::FindClassOrDie(env, "android/media/permission/Identity"); + javaIdentityFields.fieldUid = android::GetFieldIDOrDie(env, identityClass, "uid", "I"); + javaIdentityFields.fieldPid = android::GetFieldIDOrDie(env, identityClass, "pid", "I"); + javaIdentityFields.fieldPackageName = + android::GetFieldIDOrDie(env, identityClass, "packageName", "Ljava/lang/String;"); + javaIdentityFields.fieldAttributionTag = + android::GetFieldIDOrDie(env, identityClass, "attributionTag", "Ljava/lang/String;"); + + return android::RegisterMethodsOrDie(env, "android/media/permission/Identity", method_table, + NELEM(method_table)); +} + +namespace android::media::permission { + +Identity convertIdentity(JNIEnv* env, const jobject& jIdentity) { + Identity identity; + + identity.uid = env->GetIntField(jIdentity, javaIdentityFields.fieldUid); + identity.pid = env->GetIntField(jIdentity, javaIdentityFields.fieldPid); + + jstring packageNameStr = static_cast<jstring>( + env->GetObjectField(jIdentity, javaIdentityFields.fieldPackageName)); + if (packageNameStr == nullptr) { + identity.packageName = std::nullopt; + } else { + identity.packageName = std::string(ScopedUtfChars(env, packageNameStr).c_str()); + } + + jstring attributionTagStr = static_cast<jstring>( + env->GetObjectField(jIdentity, javaIdentityFields.fieldAttributionTag)); + if (attributionTagStr == nullptr) { + identity.attributionTag = std::nullopt; + } else { + identity.attributionTag = std::string(ScopedUtfChars(env, attributionTagStr).c_str()); + } + + return identity; +} + +} // namespace android::media::permission diff --git a/core/jni/permission_utils.h b/core/jni/permission_utils.h new file mode 100644 index 000000000000..d625bb6ba30a --- /dev/null +++ b/core/jni/permission_utils.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <android/media/permission/Identity.h> +#include <jni.h> + +namespace android::media::permission { + +Identity convertIdentity(JNIEnv* env, const jobject& jIdentity); +} + +int register_android_media_permission_Identity(JNIEnv* env); diff --git a/media/Android.bp b/media/Android.bp index 9268b22a929a..a66236e6f4ea 100644 --- a/media/Android.bp +++ b/media/Android.bp @@ -27,6 +27,9 @@ aidl_interface { aidl_interface { name: "media_permission-aidl", unstable: true, + host_supported: true, + vendor_available: true, + double_loadable: true, local_include_dir: "aidl", srcs: [ "aidl/android/media/permission/Identity.aidl", diff --git a/media/aidl/android/media/permission/Identity.aidl b/media/aidl/android/media/permission/Identity.aidl index 361497d59ea9..36389047cee8 100644 --- a/media/aidl/android/media/permission/Identity.aidl +++ b/media/aidl/android/media/permission/Identity.aidl @@ -22,11 +22,11 @@ package android.media.permission; */ parcelable Identity { /** Linux user ID. */ - int uid; + int uid = -1; /** Linux process ID. */ - int pid; + int pid = -1; /** Package name. If null, the first package owned by the given uid will be assumed. */ - @nullable String packageName; + @nullable @utf8InCpp String packageName; /** Attribution tag. Mostly used for diagnostic purposes. */ - @nullable String attributionTag; + @nullable @utf8InCpp String attributionTag; } diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index bf04b660425b..d7112d6dfa63 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -16,6 +16,8 @@ package android.media; +import static android.media.permission.PermissionUtil.myIdentity; + import android.annotation.CallbackExecutor; import android.annotation.FloatRange; import android.annotation.IntDef; @@ -26,9 +28,11 @@ import android.annotation.SystemApi; import android.annotation.TestApi; import android.app.ActivityThread; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Context; import android.media.MediaRecorder.Source; import android.media.audiopolicy.AudioMix; import android.media.audiopolicy.AudioPolicy; +import android.media.permission.Identity; import android.media.projection.MediaProjection; import android.os.Binder; import android.os.Build; @@ -54,6 +58,7 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Objects; import java.util.concurrent.Executor; /** @@ -352,6 +357,32 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes, int sessionId) throws IllegalArgumentException { + this(attributes, format, bufferSizeInBytes, sessionId, ActivityThread.currentApplication()); + } + + /** + * @hide + * Class constructor with {@link AudioAttributes} and {@link AudioFormat}. + * @param attributes a non-null {@link AudioAttributes} instance. Use + * {@link AudioAttributes.Builder#setCapturePreset(int)} for configuring the audio + * source for this instance. + * @param format a non-null {@link AudioFormat} instance describing the format of the data + * that will be recorded through this AudioRecord. See {@link AudioFormat.Builder} for + * configuring the audio format parameters such as encoding, channel mask and sample rate. + * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written + * to during the recording. New audio data can be read from this buffer in smaller chunks + * than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum + * required buffer size for the successful creation of an AudioRecord instance. Using values + * smaller than getMinBufferSize() will result in an initialization failure. + * @param sessionId ID of audio session the AudioRecord must be attached to, or + * {@link AudioManager#AUDIO_SESSION_ID_GENERATE} if the session isn't known at construction + * time. See also {@link AudioManager#generateAudioSessionId()} to obtain a session ID before + * construction. + * @param context An optional context to pull an attribution tag from. + * @throws IllegalArgumentException + */ + private AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes, + int sessionId, @Nullable Context context) throws IllegalArgumentException { mRecordingState = RECORDSTATE_STOPPED; if (attributes == null) { @@ -414,15 +445,21 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, audioBuffSizeCheck(bufferSizeInBytes); + Identity identity = myIdentity(context); + if (identity.packageName == null) { + // Command line utility + identity.packageName = "uid:" + Binder.getCallingUid(); + } + int[] sampleRate = new int[] {mSampleRate}; int[] session = new int[1]; session[0] = sessionId; //TODO: update native initialization when information about hardware init failure // due to capture device already open is available. - int initResult = native_setup( new WeakReference<AudioRecord>(this), + int initResult = native_setup(new WeakReference<AudioRecord>(this), mAudioAttributes, sampleRate, mChannelMask, mChannelIndexMask, mAudioFormat, mNativeBufferSizeInBytes, - session, getCurrentOpPackageName(), 0 /*nativeRecordInJavaObj*/); + session, identity, 0 /*nativeRecordInJavaObj*/); if (initResult != SUCCESS) { loge("Error code "+initResult+" when initializing native AudioRecord object."); return; // with mState == STATE_UNINITIALIZED @@ -434,15 +471,6 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, mState = STATE_INITIALIZED; } - private String getCurrentOpPackageName() { - String opPackageName = ActivityThread.currentOpPackageName(); - if (opPackageName != null) { - return opPackageName; - } - // Command line utility - return "uid:" + Binder.getCallingUid(); - } - /** * A constructor which explicitly connects a Native (C++) AudioRecord. For use by * the AudioRecordRoutingProxy subclass. @@ -492,7 +520,7 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, 0 /*mAudioFormat*/, 0 /*mNativeBufferSizeInBytes*/, session, - ActivityThread.currentOpPackageName(), + myIdentity(null), nativeRecordInJavaObj); if (initResult != SUCCESS) { loge("Error code "+initResult+" when initializing native AudioRecord object."); @@ -548,6 +576,7 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, private AudioPlaybackCaptureConfiguration mAudioPlaybackCaptureConfiguration; private AudioAttributes mAttributes; private AudioFormat mFormat; + private Context mContext; private int mBufferSizeInBytes; private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE; private int mPrivacySensitive = PRIVACY_SENSITIVE_DEFAULT; @@ -583,6 +612,18 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, } /** + * Sets the context the record belongs to. + * @param context a non-null {@link Context} instance + * @return the same Builder instance. + */ + public @NonNull Builder setContext(@NonNull Context context) { + Objects.requireNonNull(context); + // keep reference, we only copy the data when building + mContext = context; + return this; + } + + /** * @hide * To be only used by system components. Allows specifying non-public capture presets * @param attributes a non-null {@link AudioAttributes} instance that contains the capture @@ -793,7 +834,7 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, * mFormat.getBytesPerSample(mFormat.getEncoding()); } final AudioRecord record = new AudioRecord( - mAttributes, mFormat, mBufferSizeInBytes, mSessionId); + mAttributes, mFormat, mBufferSizeInBytes, mSessionId, mContext); if (record.getState() == STATE_UNINITIALIZED) { // release is not necessary throw new UnsupportedOperationException("Cannot create AudioRecord"); @@ -2035,15 +2076,32 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, // Native methods called from the Java side //-------------------- - @UnsupportedAppUsage - private native final int native_setup(Object audiorecord_this, + /** + * @deprecated Use native_setup that takes an Identity object + * @return + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, + publicAlternatives = "{@code AudioRecord.Builder}") + @Deprecated + private int native_setup(Object audiorecordThis, Object /*AudioAttributes*/ attributes, int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat, int buffSizeInBytes, int[] sessionId, String opPackageName, - long nativeRecordInJavaObj); + long nativeRecordInJavaObj) { + Identity identity = myIdentity(null); + identity.packageName = opPackageName; + + return native_setup(audiorecordThis, attributes, sampleRate, channelMask, channelIndexMask, + audioFormat, buffSizeInBytes, sessionId, identity, nativeRecordInJavaObj); + } + + private native int native_setup(Object audiorecordThis, + Object /*AudioAttributes*/ attributes, + int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat, + int buffSizeInBytes, int[] sessionId, Identity identity, long nativeRecordInJavaObj); // TODO remove: implementation calls directly into implementation of native_release() - private native final void native_finalize(); + private native void native_finalize(); /** * @hide diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 9176dae8609f..3de78bb9ef9f 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -18,6 +18,7 @@ package android.media; import static android.Manifest.permission.BIND_IMS_SERVICE; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.media.permission.PermissionUtil.myIdentity; import android.annotation.CallbackExecutor; import android.annotation.IntDef; @@ -34,6 +35,7 @@ import android.content.res.AssetFileDescriptor; import android.graphics.SurfaceTexture; import android.media.SubtitleController.Anchor; import android.media.SubtitleTrack.RenderingWidget; +import android.media.permission.Identity; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -53,6 +55,7 @@ import android.provider.Settings; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; +import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; import android.util.Pair; @@ -684,11 +687,14 @@ public class MediaPlayer extends PlayerBase mTimeProvider = new TimeProvider(this); mOpenSubtitleSources = new Vector<InputStream>(); + Identity identity = myIdentity(null); + // set the package name to empty if it was null + identity.packageName = TextUtils.emptyIfNull(identity.packageName); + /* Native setup requires a weak reference to our object. * It's easier to create it here than in C++. */ - native_setup(new WeakReference<MediaPlayer>(this), - getCurrentOpPackageName()); + native_setup(new WeakReference<MediaPlayer>(this), identity); baseRegisterPlayer(sessionId); } @@ -2471,7 +2477,7 @@ public class MediaPlayer extends PlayerBase private native final int native_setMetadataFilter(Parcel request); private static native final void native_init(); - private native void native_setup(Object mediaplayerThis, @NonNull String opPackageName); + private native void native_setup(Object mediaplayerThis, @NonNull Identity identity); private native final void native_finalize(); /** diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java index 49a4cc6239bb..87e1e5bdb9ce 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -16,6 +16,8 @@ package android.media; +import static android.media.permission.PermissionUtil.myIdentity; + import android.annotation.CallbackExecutor; import android.annotation.FloatRange; import android.annotation.IntDef; @@ -25,7 +27,9 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.app.ActivityThread; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Context; import android.hardware.Camera; +import android.media.permission.Identity; import android.os.Build; import android.os.Handler; import android.os.Looper; @@ -48,6 +52,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.concurrent.Executor; /** @@ -127,9 +132,21 @@ public class MediaRecorder implements AudioRouting, /** * Default constructor. + * + * @deprecated Use {@link #MediaRecorder(Context)} instead */ + @Deprecated public MediaRecorder() { + this(ActivityThread.currentApplication()); + } + /** + * Default constructor. + * + * @param context Context the recorder belongs to + */ + public MediaRecorder(@NonNull Context context) { + Objects.requireNonNull(context); Looper looper; if ((looper = Looper.myLooper()) != null) { mEventHandler = new EventHandler(this, looper); @@ -140,12 +157,11 @@ public class MediaRecorder implements AudioRouting, } mChannelCount = 1; - String packageName = ActivityThread.currentPackageName(); /* Native setup requires a weak reference to our object. * It's easier to create it here than in C++. */ - native_setup(new WeakReference<MediaRecorder>(this), packageName, - ActivityThread.currentOpPackageName()); + native_setup(new WeakReference<MediaRecorder>(this), + ActivityThread.currentPackageName(), myIdentity(context)); } /** @@ -1740,12 +1756,22 @@ public class MediaRecorder implements AudioRouting, @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private static native final void native_init(); - @UnsupportedAppUsage - private native final void native_setup(Object mediarecorder_this, - String clientName, String opPackageName) throws IllegalStateException; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, + publicAlternatives = "{@link MediaRecorder}") + private void native_setup(Object mediarecorderThis, + String clientName, String opPackageName) throws IllegalStateException { + Identity identity = myIdentity(null); + identity.packageName = opPackageName; + + native_setup(mediarecorderThis, clientName, identity); + } + + private native void native_setup(Object mediarecorderThis, + String clientName, Identity identity) + throws IllegalStateException; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) - private native final void native_finalize(); + private native void native_finalize(); @UnsupportedAppUsage private native void setParameter(String nameValuePair); diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java index 67a4a4b1f851..fd3c4057ad21 100644 --- a/media/java/android/media/audiofx/AudioEffect.java +++ b/media/java/android/media/audiofx/AudioEffect.java @@ -16,6 +16,8 @@ package android.media.audiofx; +import static android.media.permission.PermissionUtil.myIdentity; + import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -23,11 +25,11 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.app.ActivityThread; import android.compat.annotation.UnsupportedAppUsage; import android.media.AudioDeviceAttributes; import android.media.AudioDeviceInfo; import android.media.AudioSystem; +import android.media.permission.Identity; import android.os.Build; import android.os.Handler; import android.os.Looper; @@ -515,10 +517,11 @@ public class AudioEffect { } // native initialization + // TODO b/182469354: Make consistent with AudioRecord int initResult = native_setup(new WeakReference<AudioEffect>(this), type.toString(), uuid.toString(), priority, audioSession, deviceType, deviceAddress, - id, desc, ActivityThread.currentOpPackageName(), probe); + id, desc, myIdentity(null), probe); if (initResult != SUCCESS && initResult != ALREADY_EXISTS) { Log.e(TAG, "Error code " + initResult + " when initializing AudioEffect."); @@ -1385,7 +1388,7 @@ public class AudioEffect { private native final int native_setup(Object audioeffect_this, String type, String uuid, int priority, int audioSession, int deviceType, String deviceAddress, int[] id, Object[] desc, - String opPackageName, boolean probe); + Identity identity, boolean probe); private native final void native_finalize(); diff --git a/media/java/android/media/audiofx/Visualizer.java b/media/java/android/media/audiofx/Visualizer.java index a5da648cf14a..58c9e650bb90 100644 --- a/media/java/android/media/audiofx/Visualizer.java +++ b/media/java/android/media/audiofx/Visualizer.java @@ -16,8 +16,10 @@ package android.media.audiofx; -import android.app.ActivityThread; +import static android.media.permission.PermissionUtil.myIdentity; + import android.compat.annotation.UnsupportedAppUsage; +import android.media.permission.Identity; import android.os.Handler; import android.os.Looper; import android.util.Log; @@ -217,9 +219,11 @@ public class Visualizer { synchronized (mStateLock) { mState = STATE_UNINITIALIZED; + // native initialization + // TODO b/182469354: make consistent with AudioRecord int result = native_setup(new WeakReference<Visualizer>(this), audioSession, id, - ActivityThread.currentOpPackageName()); + myIdentity(null)); if (result != SUCCESS && result != ALREADY_EXISTS) { Log.e(TAG, "Error code "+result+" when initializing Visualizer."); switch (result) { @@ -686,7 +690,7 @@ public class Visualizer { private native final int native_setup(Object audioeffect_this, int audioSession, int[] id, - String opPackageName); + Identity identity); @GuardedBy("mStateLock") private native final void native_finalize(); diff --git a/media/java/android/media/permission/PermissionUtil.java b/media/java/android/media/permission/PermissionUtil.java index 315ee4f1e998..92fe8820570c 100644 --- a/media/java/android/media/permission/PermissionUtil.java +++ b/media/java/android/media/permission/PermissionUtil.java @@ -17,9 +17,12 @@ package android.media.permission; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.ActivityThread; import android.content.Context; import android.content.PermissionChecker; import android.os.Binder; +import android.os.Process; import java.util.Objects; @@ -49,6 +52,25 @@ import java.util.Objects; */ public class PermissionUtil { /** + * Create an identity for the current process and the passed context. + * + * @param context The process the identity is for. If {@code null}, the process's default + * identity is chosen. + * @return The identity for the current process and context + */ + public static @NonNull Identity myIdentity(@Nullable Context context) { + Identity identity = new Identity(); + + identity.pid = Process.myPid(); + identity.uid = Process.myUid(); + identity.packageName = context != null ? context.getOpPackageName() + : ActivityThread.currentOpPackageName(); + identity.attributionTag = context != null ? context.getAttributionTag() : null; + + return identity; + } + + /** * Authenticate an originator, where the binder call is coming from a middleman. * * The middleman is expected to hold a special permission to act as such, or else a diff --git a/media/jni/Android.bp b/media/jni/Android.bp index ce4550492740..f09dcde1ee28 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -84,6 +84,7 @@ cc_library_shared { "android.hardware.drm@1.4", "android.hidl.memory@1.0", "android.hidl.token@1.0-utils", + "media_permission-aidl-cpp", ], header_libs: [ @@ -182,7 +183,7 @@ cc_library_shared { "libnativehelper", "libutils", "tv_tuner_aidl_interface-ndk_platform", - "tv_tuner_resource_manager_aidl_interface-ndk_platform" + "tv_tuner_resource_manager_aidl_interface-ndk_platform", ], static_libs: [ @@ -212,4 +213,3 @@ cc_library_shared { "-Wunreachable-code", ], } - diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index 98ac5b983098..a3607597f05e 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -17,6 +17,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "MediaPlayer-JNI" +#include "permission_utils.h" #include "utils/Log.h" #include <media/mediaplayer.h> @@ -79,6 +80,8 @@ static StateExceptionFields gStateExceptionFields; using namespace android; using media::VolumeShaper; +using media::permission::Identity; +using media::permission::convertIdentity; // ---------------------------------------------------------------------------- @@ -946,11 +949,11 @@ android_media_MediaPlayer_native_init(JNIEnv *env) static void android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this, - jstring opPackageName) + jobject jIdentity) { ALOGV("native_setup"); - ScopedUtfChars opPackageNameStr(env, opPackageName); - sp<MediaPlayer> mp = new MediaPlayer(opPackageNameStr.c_str()); + + sp<MediaPlayer> mp = new MediaPlayer(convertIdentity(env, jIdentity)); if (mp == NULL) { jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); return; @@ -1406,7 +1409,7 @@ static const JNINativeMethod gMethods[] = { {"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_setMetadataFilter}, {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_getMetadata}, {"native_init", "()V", (void *)android_media_MediaPlayer_native_init}, - {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;)V",(void *)android_media_MediaPlayer_native_setup}, + {"native_setup", "(Ljava/lang/Object;Landroid/media/permission/Identity;)V",(void *)android_media_MediaPlayer_native_setup}, {"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize}, {"getAudioSessionId", "()I", (void *)android_media_MediaPlayer_get_audio_session_id}, {"native_setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer_set_audio_session_id}, diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp index f99dc012be95..66411233216f 100644 --- a/media/jni/android_media_MediaRecorder.cpp +++ b/media/jni/android_media_MediaRecorder.cpp @@ -24,6 +24,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "MediaRecorderJNI" +#include "permission_utils.h" #include <utils/Log.h> #include <gui/Surface.h> @@ -50,6 +51,8 @@ using namespace android; +using android::media::permission::convertIdentity; + // ---------------------------------------------------------------------------- // helper function to extract a native Camera object from a Camera Java object @@ -617,13 +620,12 @@ android_media_MediaRecorder_native_init(JNIEnv *env) static void android_media_MediaRecorder_native_setup(JNIEnv *env, jobject thiz, jobject weak_this, - jstring packageName, jstring opPackageName) + jstring packageName, jobject jIdentity) { ALOGV("setup"); - ScopedUtfChars opPackageNameStr(env, opPackageName); + sp<MediaRecorder> mr = new MediaRecorder(convertIdentity(env, jIdentity)); - sp<MediaRecorder> mr = new MediaRecorder(String16(opPackageNameStr.c_str())); if (mr == NULL) { jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); return; @@ -869,7 +871,7 @@ static const JNINativeMethod gMethods[] = { {"native_reset", "()V", (void *)android_media_MediaRecorder_native_reset}, {"release", "()V", (void *)android_media_MediaRecorder_release}, {"native_init", "()V", (void *)android_media_MediaRecorder_native_init}, - {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V", + {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Landroid/media/permission/Identity;)V", (void *)android_media_MediaRecorder_native_setup}, {"native_finalize", "()V", (void *)android_media_MediaRecorder_native_finalize}, {"native_setInputSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaRecorder_setInputSurface }, diff --git a/media/jni/audioeffect/Android.bp b/media/jni/audioeffect/Android.bp index c2fc91d5cfea..bfed983c8bce 100644 --- a/media/jni/audioeffect/Android.bp +++ b/media/jni/audioeffect/Android.bp @@ -27,6 +27,11 @@ cc_library_shared { "libaudioclient", "libaudioutils", "libaudiofoundation", + "media_permission-aidl-cpp", + ], + + export_shared_lib_headers: [ + "media_permission-aidl-cpp", ], version_script: "exports.lds", diff --git a/media/jni/audioeffect/Visualizer.cpp b/media/jni/audioeffect/Visualizer.cpp index a74ae5307a36..8a52456849f0 100644 --- a/media/jni/audioeffect/Visualizer.cpp +++ b/media/jni/audioeffect/Visualizer.cpp @@ -34,8 +34,8 @@ namespace android { // --------------------------------------------------------------------------- -Visualizer::Visualizer (const String16& opPackageName) - : AudioEffect(opPackageName) +Visualizer::Visualizer (const Identity& identity) + : AudioEffect(identity) { } diff --git a/media/jni/audioeffect/Visualizer.h b/media/jni/audioeffect/Visualizer.h index 8b6a62f25638..3ee91f0f8b1e 100644 --- a/media/jni/audioeffect/Visualizer.h +++ b/media/jni/audioeffect/Visualizer.h @@ -20,6 +20,9 @@ #include <media/AudioEffect.h> #include <system/audio_effects/effect_visualizer.h> #include <utils/Thread.h> +#include "android/media/permission/Identity.h" + +using namespace android::media::permission; /** * The Visualizer class enables application to retrieve part of the currently playing audio for @@ -65,7 +68,7 @@ public: /* Constructor. * See AudioEffect constructor for details on parameters. */ - explicit Visualizer(const String16& opPackageName); + explicit Visualizer(const Identity& identity); ~Visualizer(); diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp index 0d53ab152129..953b7e01c983 100644 --- a/media/jni/audioeffect/android_media_AudioEffect.cpp +++ b/media/jni/audioeffect/android_media_AudioEffect.cpp @@ -25,6 +25,7 @@ #include <nativehelper/JNIHelp.h> #include <android_runtime/AndroidRuntime.h> #include "media/AudioEffect.h" +#include "permission_utils.h" #include <nativehelper/ScopedUtfChars.h> @@ -34,6 +35,8 @@ using namespace android; +using media::permission::convertIdentity; + #define AUDIOEFFECT_SUCCESS 0 #define AUDIOEFFECT_ERROR (-1) #define AUDIOEFFECT_ERROR_ALREADY_EXISTS (-2) @@ -270,7 +273,7 @@ static jint android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_this, jstring type, jstring uuid, jint priority, jint sessionId, jint deviceType, jstring deviceAddress, - jintArray jId, jobjectArray javadesc, jstring opPackageName, jboolean probe) + jintArray jId, jobjectArray javadesc, jobject jIdentity, jboolean probe) { ALOGV("android_media_AudioEffect_native_setup"); AudioEffectJniStorage* lpJniStorage = NULL; @@ -283,8 +286,6 @@ android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_t jobject jdesc; AudioDeviceTypeAddr device; - ScopedUtfChars opPackageNameStr(env, opPackageName); - setAudioEffect(env, thiz, 0); if (type != NULL) { @@ -337,7 +338,7 @@ android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_t } // create the native AudioEffect object - lpAudioEffect = new AudioEffect(String16(opPackageNameStr.c_str())); + lpAudioEffect = new AudioEffect(convertIdentity(env, jIdentity)); if (lpAudioEffect == 0) { ALOGE("Error creating AudioEffect"); goto setup_failure; @@ -773,7 +774,7 @@ android_media_AudioEffect_native_queryPreProcessings(JNIEnv *env, jclass clazz _ // Dalvik VM type signatures static const JNINativeMethod gMethods[] = { {"native_init", "()V", (void *)android_media_AudioEffect_native_init}, - {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;IIILjava/lang/String;[I[Ljava/lang/Object;Ljava/lang/String;Z)I", + {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;IIILjava/lang/String;[I[Ljava/lang/Object;Landroid/media/permission/Identity;Z)I", (void *)android_media_AudioEffect_native_setup}, {"native_finalize", "()V", (void *)android_media_AudioEffect_native_finalize}, {"native_release", "()V", (void *)android_media_AudioEffect_native_release}, diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp index 4c5970a30a05..439715cbb811 100644 --- a/media/jni/audioeffect/android_media_Visualizer.cpp +++ b/media/jni/audioeffect/android_media_Visualizer.cpp @@ -25,6 +25,7 @@ #include <android_runtime/AndroidRuntime.h> #include <utils/threads.h> #include "Visualizer.h" +#include "permission_utils.h" #include <nativehelper/ScopedUtfChars.h> @@ -347,7 +348,7 @@ static void android_media_visualizer_effect_callback(int32_t event, static jint android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this, - jint sessionId, jintArray jId, jstring opPackageName) + jint sessionId, jintArray jId, jobject jIdentity) { ALOGV("android_media_visualizer_native_setup"); VisualizerJniStorage* lpJniStorage = NULL; @@ -355,8 +356,6 @@ android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_th sp<Visualizer> lpVisualizer; jint* nId = NULL; - ScopedUtfChars opPackageNameStr(env, opPackageName); - setVisualizer(env, thiz, 0); lpJniStorage = new VisualizerJniStorage(); @@ -382,7 +381,7 @@ android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_th } // create the native Visualizer object - lpVisualizer = new Visualizer(String16(opPackageNameStr.c_str())); + lpVisualizer = new Visualizer(convertIdentity(env, jIdentity)); if (lpVisualizer == 0) { ALOGE("Error creating Visualizer"); goto setup_failure; @@ -679,7 +678,7 @@ android_media_setPeriodicCapture(JNIEnv *env, jobject thiz, jint rate, jboolean // Dalvik VM type signatures static const JNINativeMethod gMethods[] = { {"native_init", "()V", (void *)android_media_visualizer_native_init}, - {"native_setup", "(Ljava/lang/Object;I[ILjava/lang/String;)I", + {"native_setup", "(Ljava/lang/Object;I[ILandroid/media/permission/Identity;)I", (void *)android_media_visualizer_native_setup}, {"native_finalize", "()V", (void *)android_media_visualizer_native_finalize}, {"native_release", "()V", (void *)android_media_visualizer_native_release}, diff --git a/media/jni/soundpool/Android.bp b/media/jni/soundpool/Android.bp index b3406cd89046..4227cd8cbb29 100644 --- a/media/jni/soundpool/Android.bp +++ b/media/jni/soundpool/Android.bp @@ -63,7 +63,7 @@ tidy_errors = [ // Remove some pedantic stylistic requirements. "-google-readability-casting", // C++ casts not always necessary and may be verbose - "-google-readability-todo", // do not require TODO(info) + "-google-readability-todo", // do not require TODO(info) "-google-build-using-namespace", // Reenable and fix later. "-google-explicit-constructor", // found in StreamManager.h @@ -100,7 +100,7 @@ cc_defaults { tidy_checks: tidy_errors, tidy_checks_as_errors: tidy_errors, tidy_flags: [ - "-format-style=file", + "-format-style=file", ], } @@ -135,6 +135,7 @@ cc_library_shared { "libaudioclient", "libmediandk", "libbinder", + "media_permission-aidl-cpp", ], cflags: [ diff --git a/media/jni/soundpool/Stream.cpp b/media/jni/soundpool/Stream.cpp index 73e319a5902e..abb0f1208bc2 100644 --- a/media/jni/soundpool/Stream.cpp +++ b/media/jni/soundpool/Stream.cpp @@ -17,6 +17,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "SoundPool::Stream" #include <utils/Log.h> +#include<android/media/permission/Identity.h> #include "Stream.h" @@ -24,6 +25,8 @@ namespace android::soundpool { +using media::permission::Identity; + Stream::~Stream() { ALOGV("%s(%p)", __func__, this); @@ -326,15 +329,17 @@ void Stream::play_l(const std::shared_ptr<Sound>& sound, int32_t nextStreamID, // do not create a new audio track if current track is compatible with sound parameters + Identity identity = Identity(); + identity.packageName = mStreamManager->getOpPackageName(); + // TODO b/182469354 make consistent with AudioRecord, add util for native source newTrack = new AudioTrack(streamType, sampleRate, sound->getFormat(), channelMask, sound->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, staticCallback, userData, 0 /*default notification frames*/, AUDIO_SESSION_ALLOCATE, AudioTrack::TRANSFER_DEFAULT, - nullptr /*offloadInfo*/, -1 /*uid*/, -1 /*pid*/, + nullptr /*offloadInfo*/, identity, mStreamManager->getAttributes(), - false /*doNotReconnect*/, 1.0f /*maxRequiredSpeed*/, - mStreamManager->getOpPackageName()); + false /*doNotReconnect*/, 1.0f /*maxRequiredSpeed*/); // Set caller name so it can be logged in destructor. // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_SOUNDPOOL newTrack->setCallerName("soundpool"); |