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