diff options
5 files changed, 117 insertions, 85 deletions
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ExternalCaptureStateTracker.java b/services/core/java/com/android/server/soundtrigger_middleware/ExternalCaptureStateTracker.java index c341df392621..7977e931c37f 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/ExternalCaptureStateTracker.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/ExternalCaptureStateTracker.java @@ -36,40 +36,23 @@ import java.util.function.Consumer; * For simplicity, there is currently no way to stop the tracker. This is possible to add if the * need ever arises. */ -public class ExternalCaptureStateTracker { +class ExternalCaptureStateTracker { private static final String TAG = "CaptureStateTracker"; /** Our client's listener. */ private final Consumer<Boolean> mListener; - /** A lock used to ensure synchronized access to mListener. */ - private final Object mListenerLock = new Object(); - /** - * The binder listener that we're providing to the audio policy service. Ensures synchronized - * access to mListener. - */ - private final Listener mSyncListener = new Listener(); - /** The name of the audio policy service. */ - private final String mAudioPolicyServiceName; /** This semaphore will get a permit every time we need to reconnect. */ private final Semaphore mNeedToConnect = new Semaphore(1); - /** - * We must hold a reference to the APM service, even though we're not actually using it after - * installing the callback. Otherwise, binder silently un-links our death listener. - */ - private IBinder mService; /** * Constructor. Will start a background thread to do the work. * - * @param audioPolicyServiceName The name of the audio policy service to connect to. - * @param listener A client provided listener that will be called on state - * changes. May be - * called multiple consecutive times with the same value. Never - * called - * concurrently. + * @param listener A client provided listener that will be called on state + * changes. May be + * called multiple consecutive times with the same value. Never + * called + * concurrently. */ - public ExternalCaptureStateTracker(String audioPolicyServiceName, - Consumer<Boolean> listener) { - mAudioPolicyServiceName = audioPolicyServiceName; + ExternalCaptureStateTracker(Consumer<Boolean> listener) { mListener = listener; new Thread(this::run).start(); } @@ -80,78 +63,29 @@ public class ExternalCaptureStateTracker { private void run() { while (true) { mNeedToConnect.acquireUninterruptibly(); - connectWithRetry(); + connect(); } } /** - * Try to connect. Retry in case of RemoteException. + * Connect to the service, install listener and death notifier. */ - private void connectWithRetry() { - while (true) { - try { - connect(); - return; - } catch (RemoteException e) { - Log.w(TAG, "Exception caught trying to connect", e); - } catch (ServiceManager.ServiceNotFoundException e) { - Log.w(TAG, "Service not yet available, waiting", e); - try { - Thread.sleep(1000); - } catch (InterruptedException ex) { - } - } catch (Exception e) { - Log.e(TAG, "Unexpected exception caught trying to connect", e); - throw e; - } - } - } + private native void connect(); /** - * Connect to the service, install listener and death notifier. + * Called by native code to invoke the client listener. * - * @throws RemoteException In case of a binder issue. + * @param active true when external capture is active. */ - private void connect() throws RemoteException, ServiceManager.ServiceNotFoundException { - Log.d(TAG, "Connecting to audio policy service: " + mAudioPolicyServiceName); - mService = ServiceManager.getServiceOrThrow(mAudioPolicyServiceName); - - synchronized (mListenerLock) { - boolean active = registerSoundTriggerCaptureStateListener(mService, mSyncListener); - mListener.accept(active); - } - - mService.linkToDeath(() -> { - Log.w(TAG, "Audio policy service died"); - mNeedToConnect.release(); - }, 0); + private void setCaptureState(boolean active) { + mListener.accept(active); } /** - * Since the audio policy service does not have an AIDL interface, this method does the - * necessary manual marshalling. - * - * @param service The service binder object. - * @param listener The listener binder object to register. - * @return The active state at the time of registration. + * Called by native code when the remote service died. */ - private boolean registerSoundTriggerCaptureStateListener(IBinder service, - ICaptureStateListener listener) throws RemoteException { - Parcel request = Parcel.obtain(); - Parcel response = Parcel.obtain(); - request.writeInterfaceToken("android.media.IAudioPolicyService"); - request.writeStrongBinder(listener.asBinder()); - service.transact(82 /* REGISTER_SOUNDTRIGGER_CAPTURE_STATE_LISTENER */, request, response, - 0); - return response.readBoolean(); - } - - private class Listener extends ICaptureStateListener.Stub { - @Override - public void setCaptureState(boolean active) { - synchronized (mListenerLock) { - mListener.accept(active); - } - } + private void binderDied() { + Log.w(TAG, "Audio policy service died"); + mNeedToConnect.release(); } } diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java index 33b21416b23f..929d92f56c44 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java @@ -71,7 +71,7 @@ public class SoundTriggerMiddlewareService extends ISoundTriggerMiddlewareServic */ private SoundTriggerMiddlewareService(@NonNull ISoundTriggerMiddlewareInternal delegate) { mDelegate = Objects.requireNonNull(delegate); - new ExternalCaptureStateTracker("media.audio_policy", active -> { + new ExternalCaptureStateTracker(active -> { try { mDelegate.setCaptureState(active); } catch (RemoteException e) { diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index 74982c6918a2..4c3f73d2d129 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -40,6 +40,7 @@ cc_library_static { "com_android_server_security_VerityUtils.cpp", "com_android_server_SerialService.cpp", "com_android_server_soundtrigger_middleware_AudioSessionProviderImpl.cpp", + "com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker.cpp", "com_android_server_stats_pull_StatsPullAtomService.cpp", "com_android_server_storage_AppFuseBridge.cpp", "com_android_server_SystemServer.cpp", diff --git a/services/core/jni/com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker.cpp b/services/core/jni/com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker.cpp new file mode 100644 index 000000000000..ae6cb187fa47 --- /dev/null +++ b/services/core/jni/com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2020 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 <sstream> + +#define LOG_TAG "ExternalCaptureStateTracker" + +#include "core_jni_helpers.h" +#include <log/log.h> +#include <media/AudioSystem.h> + +namespace android { +namespace { + +#define PACKAGE "com/android/server/soundtrigger_middleware" +#define CLASSNAME PACKAGE "/ExternalCaptureStateTracker" + +jclass gExternalCaptureStateTrackerClassId; +jmethodID gSetCaptureStateMethodId; +jmethodID gBinderDiedMethodId; + +void PopulateIds(JNIEnv* env) { + gExternalCaptureStateTrackerClassId = + (jclass) env->NewGlobalRef(FindClassOrDie(env, CLASSNAME)); + gSetCaptureStateMethodId = GetMethodIDOrDie(env, + gExternalCaptureStateTrackerClassId, + "setCaptureState", + "(Z)V"); + gBinderDiedMethodId = GetMethodIDOrDie(env, + gExternalCaptureStateTrackerClassId, + "binderDied", + "()V"); +} + +class Listener : public AudioSystem::CaptureStateListener { +public: + Listener(JNIEnv* env, jobject obj) : mObj(env->NewGlobalRef(obj)) {} + + ~Listener() { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->DeleteGlobalRef(mObj); + } + + void onStateChanged(bool active) override { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->CallVoidMethod(mObj, gSetCaptureStateMethodId, active); + } + + void onServiceDied() override { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->CallVoidMethod(mObj, gBinderDiedMethodId); + } + +private: + jobject mObj; +}; + +void connect(JNIEnv* env, jobject obj) { + sp<AudioSystem::CaptureStateListener> listener(new Listener(env, obj)); + status_t status = + AudioSystem::registerSoundTriggerCaptureStateListener(listener); + LOG_ALWAYS_FATAL_IF(status != NO_ERROR); +} + +const JNINativeMethod gMethods[] = { + {"connect", "()V", reinterpret_cast<void*>(connect)}, +}; + +} // namespace + +int register_com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker( + JNIEnv* env) { + PopulateIds(env); + return RegisterMethodsOrDie(env, + CLASSNAME, + gMethods, + NELEM(gMethods)); +} + +} // namespace android diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index eb486fea0116..b988bd45d786 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -58,6 +58,8 @@ int register_android_server_am_CachedAppOptimizer(JNIEnv* env); int register_android_server_am_LowMemDetector(JNIEnv* env); int register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl( JNIEnv* env); +int register_com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker( + JNIEnv* env); int register_android_server_com_android_server_pm_PackageManagerShellCommandDataLoader(JNIEnv* env); int register_android_server_stats_pull_StatsPullAtomService(JNIEnv* env); int register_android_server_AdbDebuggingManager(JNIEnv* env); @@ -112,6 +114,8 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_am_LowMemDetector(env); register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl( env); + register_com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker( + env); register_android_server_com_android_server_pm_PackageManagerShellCommandDataLoader(env); register_android_server_stats_pull_StatsPullAtomService(env); register_android_server_AdbDebuggingManager(env); |