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
diff --git a/core/api/current.txt b/core/api/current.txt
index 922d811..ece6ede4 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -20565,6 +20565,7 @@
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 @@
}
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 d6d3387..3c1b6f9 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 @@
"fd_utils.cpp",
"android_hardware_input_InputWindowHandle.cpp",
"android_hardware_input_InputApplicationHandle.cpp",
+ "permission_utils.cpp",
],
static_libs: [
@@ -236,6 +236,7 @@
"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 ddd8613..60d2db6 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -97,6 +97,7 @@
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 @@
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 0e0f98e..7d3febb 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 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 @@
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 @@
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 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 cae6db5..62767a6 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 @@
// 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 @@
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 @@
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 0000000..2b7ef99
--- /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 0000000..d625bb6
--- /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 9268b22..a66236e 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -27,6 +27,9 @@
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 361497d..3638904 100644
--- a/media/aidl/android/media/permission/Identity.aidl
+++ b/media/aidl/android/media/permission/Identity.aidl
@@ -22,11 +22,11 @@
*/
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 bf04b66..d7112d6 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.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.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -352,6 +357,32 @@
@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 @@
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 @@
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 @@
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 @@
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 @@
}
/**
+ * 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 @@
* 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 @@
// 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 9176dae..3de78bb 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -18,6 +18,7 @@
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.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.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 @@
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 @@
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 49a4cc6..87e1e5b 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.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.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -127,9 +132,21 @@
/**
* 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 @@
}
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 @@
@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 67a4a4b..fd3c405 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.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 @@
}
// 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 @@
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 a5da648..58c9e65 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 @@
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 @@
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 315ee4f..92fe882 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 @@
*/
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 ce45504..f09dcde 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -84,6 +84,7 @@
"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 @@
"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 @@
"-Wunreachable-code",
],
}
-
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 98ac5b9..a360759 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 @@
using namespace android;
using media::VolumeShaper;
+using media::permission::Identity;
+using media::permission::convertIdentity;
// ----------------------------------------------------------------------------
@@ -946,11 +949,11 @@
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 @@
{"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 f99dc01..6641123 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 @@
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 @@
{"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 c2fc91d..bfed983 100644
--- a/media/jni/audioeffect/Android.bp
+++ b/media/jni/audioeffect/Android.bp
@@ -27,6 +27,11 @@
"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 a74ae53..8a52456 100644
--- a/media/jni/audioeffect/Visualizer.cpp
+++ b/media/jni/audioeffect/Visualizer.cpp
@@ -34,8 +34,8 @@
// ---------------------------------------------------------------------------
-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 8b6a62f..3ee91f0 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 @@
/* 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 0d53ab1..953b7e0 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 @@
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 @@
jobject jdesc;
AudioDeviceTypeAddr device;
- ScopedUtfChars opPackageNameStr(env, opPackageName);
-
setAudioEffect(env, thiz, 0);
if (type != NULL) {
@@ -337,7 +338,7 @@
}
// 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 @@
// 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 4c5970a..439715c 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 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 @@
sp<Visualizer> lpVisualizer;
jint* nId = NULL;
- ScopedUtfChars opPackageNameStr(env, opPackageName);
-
setVisualizer(env, thiz, 0);
lpJniStorage = new VisualizerJniStorage();
@@ -382,7 +381,7 @@
}
// 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 @@
// 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 b3406cd..4227cd8 100644
--- a/media/jni/soundpool/Android.bp
+++ b/media/jni/soundpool/Android.bp
@@ -63,7 +63,7 @@
// 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 @@
tidy_checks: tidy_errors,
tidy_checks_as_errors: tidy_errors,
tidy_flags: [
- "-format-style=file",
+ "-format-style=file",
],
}
@@ -135,6 +135,7 @@
"libaudioclient",
"libmediandk",
"libbinder",
+ "media_permission-aidl-cpp",
],
cflags: [
diff --git a/media/jni/soundpool/Stream.cpp b/media/jni/soundpool/Stream.cpp
index 73e319a..abb0f12 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 @@
// 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");