Merge "AudioService: log changes in OP_PLAY_AUDIO" into oc-mr1-dev am: 8da5c64628
am: 60e09929e7

Change-Id: I0c21870cc808d16076c907a1760bb1940ef0ff87
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index f403988..3b9a5de 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -842,8 +842,8 @@
     @Override
     public String toString () {
         return new String("AudioAttributes:"
-                + " usage=" + mUsage
-                + " content=" + mContentType
+                + " usage=" + usageToString()
+                + " content=" + contentTypeToString()
                 + " flags=0x" + Integer.toHexString(mFlags).toUpperCase()
                 + " tags=" + mFormattedTags
                 + " bundle=" + (mBundle == null ? "null" : mBundle.toString()));
@@ -894,6 +894,19 @@
         }
     }
 
+    /** @hide */
+    public String contentTypeToString() {
+        switch(mContentType) {
+            case CONTENT_TYPE_UNKNOWN:
+                return new String("CONTENT_TYPE_UNKNOWN");
+            case CONTENT_TYPE_SPEECH: return new String("CONTENT_TYPE_SPEECH");
+            case CONTENT_TYPE_MUSIC: return new String("CONTENT_TYPE_MUSIC");
+            case CONTENT_TYPE_MOVIE: return new String("CONTENT_TYPE_MOVIE");
+            case CONTENT_TYPE_SONIFICATION: return new String("CONTENT_TYPE_SONIFICATION");
+            default: return new String("unknown content type " + mContentType);
+        }
+    }
+
     private static int usageForStreamType(int streamType) {
         switch(streamType) {
             case AudioSystem.STREAM_VOICE_CALL:
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 9c138e3..bb6ae98 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -201,5 +201,7 @@
     int dispatchFocusChange(in AudioFocusInfo afi, in int focusChange,
             in IAudioPolicyCallback pcb);
 
+    oneway void playerHasOpPlayAudio(in int piid, in boolean hasOpPlayAudio);
+
     // WARNING: read warning at top of file, it is recommended to add new methods at the end
 }
diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java
index 9bd93aa..4808d7a 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -276,6 +276,7 @@
         // volume used by the player
         try {
             if (oldHasAppOpsPlayAudio != mHasAppOpsPlayAudio) {
+                getService().playerHasOpPlayAudio(mPlayerIId, mHasAppOpsPlayAudio);
                 if (mHasAppOpsPlayAudio) {
                     if (DEBUG_APP_OPS) {
                         Log.v(TAG, "updateAppOpsPlayAudio: unmuting player, vol=" + mLeftVolume
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index f88f779..faf4729 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -6973,6 +6973,10 @@
         mPlaybackMonitor.playerEvent(piid, event, Binder.getCallingUid());
     }
 
+    public void playerHasOpPlayAudio(int piid, boolean hasOpPlayAudio) {
+        mPlaybackMonitor.playerHasOpPlayAudio(piid, hasOpPlayAudio, Binder.getCallingUid());
+    }
+
     public void releasePlayer(int piid) {
         mPlaybackMonitor.releasePlayer(piid, Binder.getCallingUid());
     }
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index c075cdc..3e5eed3 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -214,6 +214,11 @@
         }
     }
 
+    public void playerHasOpPlayAudio(int piid, boolean hasOpPlayAudio, int binderUid) {
+        // no check on UID yet because this is only for logging at the moment
+        mEventLogger.log(new PlayerOpPlayAudioEvent(piid, hasOpPlayAudio, binderUid));
+    }
+
     public void releasePlayer(int piid, int binderUid) {
         if (DEBUG) { Log.v(TAG, "releasePlayer() for piid=" + piid); }
         synchronized(mPlayerLock) {
@@ -702,8 +707,28 @@
 
         @Override
         public String eventToString() {
-            return new String("player piid:" + mPlayerIId + " state:"
-                    + AudioPlaybackConfiguration.toLogFriendlyPlayerState(mState));
+            return new StringBuilder("player piid:").append(mPlayerIId).append(" state:")
+                    .append(AudioPlaybackConfiguration.toLogFriendlyPlayerState(mState)).toString();
+        }
+    }
+
+    private final static class PlayerOpPlayAudioEvent extends AudioEventLogger.Event {
+        // only keeping the player interface ID as it uniquely identifies the player in the event
+        final int mPlayerIId;
+        final boolean mHasOp;
+        final int mUid;
+
+        PlayerOpPlayAudioEvent(int piid, boolean hasOp, int uid) {
+            mPlayerIId = piid;
+            mHasOp = hasOp;
+            mUid = uid;
+        }
+
+        @Override
+        public String eventToString() {
+            return new StringBuilder("player piid:").append(mPlayerIId)
+                    .append(" has OP_PLAY_AUDIO:").append(mHasOp)
+                    .append(" in uid:").append(mUid).toString();
         }
     }