1d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi/* 2d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi * Copyright (C) 2016 The Android Open Source Project 3d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi * 4d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi * Licensed under the Apache License, Version 2.0 (the "License"); 5d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi * you may not use this file except in compliance with the License. 6d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi * You may obtain a copy of the License at 7d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi * 8d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi * http://www.apache.org/licenses/LICENSE-2.0 9d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi * 10d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi * Unless required by applicable law or agreed to in writing, software 11d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi * distributed under the License is distributed on an "AS IS" BASIS, 12d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi * See the License for the specific language governing permissions and 14d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi * limitations under the License. 15d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi */ 16d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi 17d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivipackage com.android.server.audio; 18d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi 1966ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Triviimport android.content.Context; 2066ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Triviimport android.content.pm.PackageManager; 2133fd8169cdb7e7fa33885b6f892bc4f6df68959bJean-Michel Triviimport android.media.AudioFormat; 22d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Triviimport android.media.AudioManager; 2366ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Triviimport android.media.AudioPlaybackConfiguration; 24598c0c9f659184971e974de6a0184a3000e7900cJean-Michel Triviimport android.media.AudioRecordingConfiguration; 25d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Triviimport android.media.AudioSystem; 26d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Triviimport android.media.IRecordingConfigDispatcher; 27dd2772a33949796cb371f0d45bc0ba86f2007bdeJean-Michel Triviimport android.media.MediaRecorder; 28d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Triviimport android.os.IBinder; 29d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Triviimport android.os.RemoteException; 30d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Triviimport android.util.Log; 31d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi 3266ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Triviimport java.io.PrintWriter; 3366ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Triviimport java.text.DateFormat; 34d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Triviimport java.util.ArrayList; 3566ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Triviimport java.util.Date; 36d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Triviimport java.util.HashMap; 37d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Triviimport java.util.Iterator; 38f04fab160a044e4e7d936c0457a156d7911f924cJean-Michel Triviimport java.util.List; 39d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi 40d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi/** 41d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi * Class to receive and dispatch updates from AudioSystem about recording configurations. 42d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi */ 43d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivipublic final class RecordingActivityMonitor implements AudioSystem.AudioRecordingCallback { 44d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi 45d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi public final static String TAG = "AudioService.RecordingActivityMonitor"; 46d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi 47d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi private ArrayList<RecMonitorClient> mClients = new ArrayList<RecMonitorClient>(); 4866ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi // a public client is one that needs an anonymized version of the playback configurations, we 4966ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi // keep track of whether there is at least one to know when we need to create the list of 5066ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi // playback configurations that do not contain uid/package name information. 5166ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi private boolean mHasPublicClients = false; 52d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi 53598c0c9f659184971e974de6a0184a3000e7900cJean-Michel Trivi private HashMap<Integer, AudioRecordingConfiguration> mRecordConfigs = 54598c0c9f659184971e974de6a0184a3000e7900cJean-Michel Trivi new HashMap<Integer, AudioRecordingConfiguration>(); 55d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi 5666ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi private final PackageManager mPackMan; 5766ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi 5866ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi RecordingActivityMonitor(Context ctxt) { 59d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi RecMonitorClient.sMonitor = this; 6066ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi mPackMan = ctxt.getPackageManager(); 61d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 62d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi 63d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi /** 64d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi * Implementation of android.media.AudioSystem.AudioRecordingCallback 65d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi */ 6666ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi public void onRecordingConfigurationChanged(int event, int uid, int session, int source, 6766ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi int[] recordingInfo, String packName) { 68dd2772a33949796cb371f0d45bc0ba86f2007bdeJean-Michel Trivi if (MediaRecorder.isSystemOnlyAudioSource(source)) { 69dd2772a33949796cb371f0d45bc0ba86f2007bdeJean-Michel Trivi return; 70dd2772a33949796cb371f0d45bc0ba86f2007bdeJean-Michel Trivi } 7166ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi final List<AudioRecordingConfiguration> configsSystem = 7266ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi updateSnapshot(event, uid, session, source, recordingInfo); 7366ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi if (configsSystem != null){ 7466ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi synchronized (mClients) { 7566ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi // list of recording configurations for "public consumption". It is only computed if 7666ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi // there are non-system recording activity listeners. 7766ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi final List<AudioRecordingConfiguration> configsPublic = mHasPublicClients ? 7866ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi anonymizeForPublicConsumption(configsSystem) : 7966ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi new ArrayList<AudioRecordingConfiguration>(); 8028ff76b455d35f99e68bee41b629c11ccf4f46d0Jean-Michel Trivi final Iterator<RecMonitorClient> clientIterator = mClients.iterator(); 81d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi while (clientIterator.hasNext()) { 8266ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi final RecMonitorClient rmc = clientIterator.next(); 83d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi try { 8466ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi if (rmc.mIsPrivileged) { 8566ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi rmc.mDispatcherCb.dispatchRecordingConfigChange(configsSystem); 8666ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi } else { 8766ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi rmc.mDispatcherCb.dispatchRecordingConfigChange(configsPublic); 8866ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi } 89d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } catch (RemoteException e) { 90d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi Log.w(TAG, "Could not call dispatchRecordingConfigChange() on client", e); 91d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 92d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 93d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 94d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 95d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 96d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi 9766ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi protected void dump(PrintWriter pw) { 9866ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi // players 9966ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi pw.println("\nRecordActivityMonitor dump time: " 10066ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi + DateFormat.getTimeInstance().format(new Date())); 10166ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi synchronized(mRecordConfigs) { 10266ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi for (AudioRecordingConfiguration conf : mRecordConfigs.values()) { 10366ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi conf.dump(pw); 10466ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi } 10566ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi } 10612a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi pw.println("\n"); 10712a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi // log 10812a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi sEventLogger.dump(pw); 10966ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi } 11066ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi 11166ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi private ArrayList<AudioRecordingConfiguration> anonymizeForPublicConsumption( 11266ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi List<AudioRecordingConfiguration> sysConfigs) { 11366ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi ArrayList<AudioRecordingConfiguration> publicConfigs = 11466ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi new ArrayList<AudioRecordingConfiguration>(); 11566ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi // only add active anonymized configurations, 11666ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi for (AudioRecordingConfiguration config : sysConfigs) { 11766ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi publicConfigs.add(AudioRecordingConfiguration.anonymizedCopy(config)); 11866ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi } 11966ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi return publicConfigs; 12066ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi } 12166ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi 122d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi void initMonitor() { 123d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi AudioSystem.setRecordingCallback(this); 124d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 125d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi 12666ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi void registerRecordingCallback(IRecordingConfigDispatcher rcdb, boolean isPrivileged) { 127d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi if (rcdb == null) { 128d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi return; 129d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 13066ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi synchronized (mClients) { 13166ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi final RecMonitorClient rmc = new RecMonitorClient(rcdb, isPrivileged); 132d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi if (rmc.init()) { 13366ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi if (!isPrivileged) { 13466ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi mHasPublicClients = true; 13566ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi } 136d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi mClients.add(rmc); 137d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 138d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 139d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 140d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi 141d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi void unregisterRecordingCallback(IRecordingConfigDispatcher rcdb) { 142d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi if (rcdb == null) { 143d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi return; 144d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 14566ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi synchronized (mClients) { 146d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi final Iterator<RecMonitorClient> clientIterator = mClients.iterator(); 14766ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi boolean hasPublicClients = false; 148d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi while (clientIterator.hasNext()) { 149d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi RecMonitorClient rmc = clientIterator.next(); 150d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi if (rcdb.equals(rmc.mDispatcherCb)) { 151d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi rmc.release(); 152d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi clientIterator.remove(); 15366ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi } else { 15466ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi if (!rmc.mIsPrivileged) { 15566ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi hasPublicClients = true; 15666ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi } 157d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 158d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 15966ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi mHasPublicClients = hasPublicClients; 160d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 161d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 162d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi 16366ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi List<AudioRecordingConfiguration> getActiveRecordingConfigurations(boolean isPrivileged) { 164d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi synchronized(mRecordConfigs) { 16566ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi if (isPrivileged) { 16666ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi return new ArrayList<AudioRecordingConfiguration>(mRecordConfigs.values()); 16766ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi } else { 16866ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi final List<AudioRecordingConfiguration> configsPublic = 16966ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi anonymizeForPublicConsumption( 17066ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi new ArrayList<AudioRecordingConfiguration>(mRecordConfigs.values())); 17166ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi return configsPublic; 17266ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi } 173d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 174d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 175d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi 176d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi /** 177d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi * Update the internal "view" of the active recording sessions 178d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi * @param event 179d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi * @param session 180d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi * @param source 18133fd8169cdb7e7fa33885b6f892bc4f6df68959bJean-Michel Trivi * @param recordingFormat see 18233fd8169cdb7e7fa33885b6f892bc4f6df68959bJean-Michel Trivi * {@link AudioSystem.AudioRecordingCallback#onRecordingConfigurationChanged(int, int, int, int[])} 18333fd8169cdb7e7fa33885b6f892bc4f6df68959bJean-Michel Trivi * for the definition of the contents of the array 184f04fab160a044e4e7d936c0457a156d7911f924cJean-Michel Trivi * @return null if the list of active recording sessions has not been modified, a list 18528ff76b455d35f99e68bee41b629c11ccf4f46d0Jean-Michel Trivi * with the current active configurations otherwise. 186d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi */ 18766ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi private List<AudioRecordingConfiguration> updateSnapshot(int event, int uid, int session, 18866ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi int source, int[] recordingInfo) { 18928ff76b455d35f99e68bee41b629c11ccf4f46d0Jean-Michel Trivi final boolean configChanged; 190f04fab160a044e4e7d936c0457a156d7911f924cJean-Michel Trivi final ArrayList<AudioRecordingConfiguration> configs; 191d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi synchronized(mRecordConfigs) { 192d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi switch (event) { 193d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi case AudioManager.RECORD_CONFIG_EVENT_STOP: 194d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi // return failure if an unknown recording session stopped 19528ff76b455d35f99e68bee41b629c11ccf4f46d0Jean-Michel Trivi configChanged = (mRecordConfigs.remove(new Integer(session)) != null); 19612a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi if (configChanged) { 19712a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi sEventLogger.log(new RecordingEvent(event, uid, session, source, null)); 19812a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi } 19928ff76b455d35f99e68bee41b629c11ccf4f46d0Jean-Michel Trivi break; 200d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi case AudioManager.RECORD_CONFIG_EVENT_START: 20133fd8169cdb7e7fa33885b6f892bc4f6df68959bJean-Michel Trivi final AudioFormat clientFormat = new AudioFormat.Builder() 2028ab728093eed85c176822d58a0d2ba1f4ebbb362Jean-Michel Trivi .setEncoding(recordingInfo[0]) 20333fd8169cdb7e7fa33885b6f892bc4f6df68959bJean-Michel Trivi // FIXME this doesn't support index-based masks 2048ab728093eed85c176822d58a0d2ba1f4ebbb362Jean-Michel Trivi .setChannelMask(recordingInfo[1]) 2058ab728093eed85c176822d58a0d2ba1f4ebbb362Jean-Michel Trivi .setSampleRate(recordingInfo[2]) 20633fd8169cdb7e7fa33885b6f892bc4f6df68959bJean-Michel Trivi .build(); 20733fd8169cdb7e7fa33885b6f892bc4f6df68959bJean-Michel Trivi final AudioFormat deviceFormat = new AudioFormat.Builder() 2088ab728093eed85c176822d58a0d2ba1f4ebbb362Jean-Michel Trivi .setEncoding(recordingInfo[3]) 20933fd8169cdb7e7fa33885b6f892bc4f6df68959bJean-Michel Trivi // FIXME this doesn't support index-based masks 2108ab728093eed85c176822d58a0d2ba1f4ebbb362Jean-Michel Trivi .setChannelMask(recordingInfo[4]) 2118ab728093eed85c176822d58a0d2ba1f4ebbb362Jean-Michel Trivi .setSampleRate(recordingInfo[5]) 21233fd8169cdb7e7fa33885b6f892bc4f6df68959bJean-Michel Trivi .build(); 2138ab728093eed85c176822d58a0d2ba1f4ebbb362Jean-Michel Trivi final int patchHandle = recordingInfo[6]; 2148ab728093eed85c176822d58a0d2ba1f4ebbb362Jean-Michel Trivi final Integer sessionKey = new Integer(session); 21566ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi 21666ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi final String[] packages = mPackMan.getPackagesForUid(uid); 21766ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi final String packageName; 21866ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi if (packages != null && packages.length > 0) { 21966ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi packageName = packages[0]; 22066ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi } else { 22166ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi packageName = ""; 22266ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi } 22366ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi final AudioRecordingConfiguration updatedConfig = 22466ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi new AudioRecordingConfiguration(uid, session, source, 22566ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi clientFormat, deviceFormat, patchHandle, packageName); 22666ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi 2278ab728093eed85c176822d58a0d2ba1f4ebbb362Jean-Michel Trivi if (mRecordConfigs.containsKey(sessionKey)) { 2288ab728093eed85c176822d58a0d2ba1f4ebbb362Jean-Michel Trivi if (updatedConfig.equals(mRecordConfigs.get(sessionKey))) { 22928ff76b455d35f99e68bee41b629c11ccf4f46d0Jean-Michel Trivi configChanged = false; 2308ab728093eed85c176822d58a0d2ba1f4ebbb362Jean-Michel Trivi } else { 2318ab728093eed85c176822d58a0d2ba1f4ebbb362Jean-Michel Trivi // config exists but has been modified 2328ab728093eed85c176822d58a0d2ba1f4ebbb362Jean-Michel Trivi mRecordConfigs.remove(sessionKey); 2338ab728093eed85c176822d58a0d2ba1f4ebbb362Jean-Michel Trivi mRecordConfigs.put(sessionKey, updatedConfig); 23428ff76b455d35f99e68bee41b629c11ccf4f46d0Jean-Michel Trivi configChanged = true; 2358ab728093eed85c176822d58a0d2ba1f4ebbb362Jean-Michel Trivi } 236d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } else { 23766ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi mRecordConfigs.put(sessionKey, updatedConfig); 23828ff76b455d35f99e68bee41b629c11ccf4f46d0Jean-Michel Trivi configChanged = true; 239d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 24012a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi if (configChanged) { 24112a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi sEventLogger.log(new RecordingEvent(event, uid, session, source, packageName)); 24212a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi } 24328ff76b455d35f99e68bee41b629c11ccf4f46d0Jean-Michel Trivi break; 244d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi default: 245d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi Log.e(TAG, String.format("Unknown event %d for session %d, source %d", 246d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi event, session, source)); 24728ff76b455d35f99e68bee41b629c11ccf4f46d0Jean-Michel Trivi configChanged = false; 24828ff76b455d35f99e68bee41b629c11ccf4f46d0Jean-Michel Trivi } 24928ff76b455d35f99e68bee41b629c11ccf4f46d0Jean-Michel Trivi if (configChanged) { 250f04fab160a044e4e7d936c0457a156d7911f924cJean-Michel Trivi configs = new ArrayList<AudioRecordingConfiguration>(mRecordConfigs.values()); 25128ff76b455d35f99e68bee41b629c11ccf4f46d0Jean-Michel Trivi } else { 25228ff76b455d35f99e68bee41b629c11ccf4f46d0Jean-Michel Trivi configs = null; 253d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 254d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 25528ff76b455d35f99e68bee41b629c11ccf4f46d0Jean-Michel Trivi return configs; 256d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 257d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi 258d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi /** 259d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi * Inner class to track clients that want to be notified of recording updates 260d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi */ 261d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi private final static class RecMonitorClient implements IBinder.DeathRecipient { 262d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi 263d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi // can afford to be static because only one RecordingActivityMonitor ever instantiated 264d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi static RecordingActivityMonitor sMonitor; 265d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi 266d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi final IRecordingConfigDispatcher mDispatcherCb; 26766ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi final boolean mIsPrivileged; 268d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi 26966ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi RecMonitorClient(IRecordingConfigDispatcher rcdb, boolean isPrivileged) { 270d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi mDispatcherCb = rcdb; 27166ffacf42a7dde6fac867605aaa47d555b960ee4Jean-Michel Trivi mIsPrivileged = isPrivileged; 272d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 273d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi 274d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi public void binderDied() { 275d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi Log.w(TAG, "client died"); 276d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi sMonitor.unregisterRecordingCallback(mDispatcherCb); 277d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 278d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi 279d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi boolean init() { 280d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi try { 281d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi mDispatcherCb.asBinder().linkToDeath(this, 0); 282d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi return true; 283d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } catch (RemoteException e) { 284d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi Log.w(TAG, "Could not link to client death", e); 285d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi return false; 286d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 287d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 288d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi 289d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi void release() { 290d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi mDispatcherCb.asBinder().unlinkToDeath(this, 0); 291d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 292d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi } 29312a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi 29412a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi /** 29512a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi * Inner class for recording event logging 29612a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi */ 29712a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi private static final class RecordingEvent extends AudioEventLogger.Event { 29812a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi private final int mRecEvent; 29912a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi private final int mClientUid; 30012a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi private final int mSession; 30112a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi private final int mSource; 30212a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi private final String mPackName; 30312a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi 30412a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi RecordingEvent(int event, int uid, int session, int source, String packName) { 30512a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi mRecEvent = event; 30612a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi mClientUid = uid; 30712a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi mSession = session; 30812a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi mSource = source; 30912a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi mPackName = packName; 31012a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi } 31112a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi 31212a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi @Override 31312a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi public String eventToString() { 31412a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi return new StringBuilder("rec ").append( 31512a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi mRecEvent == AudioManager.RECORD_CONFIG_EVENT_START ? "start" : "stop ") 31612a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi .append(" uid:").append(mClientUid) 31712a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi .append(" session:").append(mSession) 31812a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi .append(" src:").append(MediaRecorder.toLogFriendlyAudioSource(mSource)) 31912a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi .append(mPackName == null ? "" : " pack:" + mPackName).toString(); 32012a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi } 32112a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi } 32212a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi 32312a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi private static final AudioEventLogger sEventLogger = new AudioEventLogger(50, 32412a8676b0bc7aa418211fed0abe6c098e20fdd45Jean-Michel Trivi "recording activity as reported through AudioSystem.AudioRecordingCallback"); 325d3c71f075b139024e2bea39bbd75e3b976bfb7cbJean-Michel Trivi} 326