Merge changes from topic "invert-capture-rvc" into rvc-dev am: 40ee6ffa32 am: 6e9eb7aa0b
Change-Id: Ie267f6ede2f9b2fd7daf3232c2fb646e98d56c7d
This commit is contained in:
@@ -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
|
* For simplicity, there is currently no way to stop the tracker. This is possible to add if the
|
||||||
* need ever arises.
|
* need ever arises.
|
||||||
*/
|
*/
|
||||||
public class ExternalCaptureStateTracker {
|
class ExternalCaptureStateTracker {
|
||||||
private static final String TAG = "CaptureStateTracker";
|
private static final String TAG = "CaptureStateTracker";
|
||||||
/** Our client's listener. */
|
/** Our client's listener. */
|
||||||
private final Consumer<Boolean> mListener;
|
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. */
|
/** This semaphore will get a permit every time we need to reconnect. */
|
||||||
private final Semaphore mNeedToConnect = new Semaphore(1);
|
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.
|
* 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
|
||||||
* @param listener A client provided listener that will be called on state
|
* changes. May be
|
||||||
* changes. May be
|
* called multiple consecutive times with the same value. Never
|
||||||
* called multiple consecutive times with the same value. Never
|
* called
|
||||||
* called
|
* concurrently.
|
||||||
* concurrently.
|
|
||||||
*/
|
*/
|
||||||
public ExternalCaptureStateTracker(String audioPolicyServiceName,
|
ExternalCaptureStateTracker(Consumer<Boolean> listener) {
|
||||||
Consumer<Boolean> listener) {
|
|
||||||
mAudioPolicyServiceName = audioPolicyServiceName;
|
|
||||||
mListener = listener;
|
mListener = listener;
|
||||||
new Thread(this::run).start();
|
new Thread(this::run).start();
|
||||||
}
|
}
|
||||||
@@ -80,78 +63,29 @@ public class ExternalCaptureStateTracker {
|
|||||||
private void run() {
|
private void run() {
|
||||||
while (true) {
|
while (true) {
|
||||||
mNeedToConnect.acquireUninterruptibly();
|
mNeedToConnect.acquireUninterruptibly();
|
||||||
connectWithRetry();
|
connect();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Try to connect. Retry in case of RemoteException.
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect to the service, install listener and death notifier.
|
* Connect to the service, install listener and death notifier.
|
||||||
*
|
|
||||||
* @throws RemoteException In case of a binder issue.
|
|
||||||
*/
|
*/
|
||||||
private void connect() throws RemoteException, ServiceManager.ServiceNotFoundException {
|
private native void connect();
|
||||||
Log.d(TAG, "Connecting to audio policy service: " + mAudioPolicyServiceName);
|
|
||||||
mService = ServiceManager.getServiceOrThrow(mAudioPolicyServiceName);
|
|
||||||
|
|
||||||
synchronized (mListenerLock) {
|
/**
|
||||||
boolean active = registerSoundTriggerCaptureStateListener(mService, mSyncListener);
|
* Called by native code to invoke the client listener.
|
||||||
mListener.accept(active);
|
*
|
||||||
}
|
* @param active true when external capture is active.
|
||||||
|
*/
|
||||||
mService.linkToDeath(() -> {
|
private void setCaptureState(boolean active) {
|
||||||
Log.w(TAG, "Audio policy service died");
|
mListener.accept(active);
|
||||||
mNeedToConnect.release();
|
|
||||||
}, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Since the audio policy service does not have an AIDL interface, this method does the
|
* Called by native code when the remote service died.
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
private boolean registerSoundTriggerCaptureStateListener(IBinder service,
|
private void binderDied() {
|
||||||
ICaptureStateListener listener) throws RemoteException {
|
Log.w(TAG, "Audio policy service died");
|
||||||
Parcel request = Parcel.obtain();
|
mNeedToConnect.release();
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ public class SoundTriggerMiddlewareService extends ISoundTriggerMiddlewareServic
|
|||||||
*/
|
*/
|
||||||
private SoundTriggerMiddlewareService(@NonNull ISoundTriggerMiddlewareInternal delegate) {
|
private SoundTriggerMiddlewareService(@NonNull ISoundTriggerMiddlewareInternal delegate) {
|
||||||
mDelegate = Objects.requireNonNull(delegate);
|
mDelegate = Objects.requireNonNull(delegate);
|
||||||
new ExternalCaptureStateTracker("media.audio_policy", active -> {
|
new ExternalCaptureStateTracker(active -> {
|
||||||
try {
|
try {
|
||||||
mDelegate.setCaptureState(active);
|
mDelegate.setCaptureState(active);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ cc_library_static {
|
|||||||
"com_android_server_security_VerityUtils.cpp",
|
"com_android_server_security_VerityUtils.cpp",
|
||||||
"com_android_server_SerialService.cpp",
|
"com_android_server_SerialService.cpp",
|
||||||
"com_android_server_soundtrigger_middleware_AudioSessionProviderImpl.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_stats_pull_StatsPullAtomService.cpp",
|
||||||
"com_android_server_storage_AppFuseBridge.cpp",
|
"com_android_server_storage_AppFuseBridge.cpp",
|
||||||
"com_android_server_SystemServer.cpp",
|
"com_android_server_SystemServer.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
|
||||||
@@ -58,6 +58,8 @@ int register_android_server_am_CachedAppOptimizer(JNIEnv* env);
|
|||||||
int register_android_server_am_LowMemDetector(JNIEnv* env);
|
int register_android_server_am_LowMemDetector(JNIEnv* env);
|
||||||
int register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(
|
int register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(
|
||||||
JNIEnv* env);
|
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_com_android_server_pm_PackageManagerShellCommandDataLoader(JNIEnv* env);
|
||||||
int register_android_server_stats_pull_StatsPullAtomService(JNIEnv* env);
|
int register_android_server_stats_pull_StatsPullAtomService(JNIEnv* env);
|
||||||
int register_android_server_AdbDebuggingManager(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_android_server_am_LowMemDetector(env);
|
||||||
register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(
|
register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(
|
||||||
env);
|
env);
|
||||||
|
register_com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker(
|
||||||
|
env);
|
||||||
register_android_server_com_android_server_pm_PackageManagerShellCommandDataLoader(env);
|
register_android_server_com_android_server_pm_PackageManagerShellCommandDataLoader(env);
|
||||||
register_android_server_stats_pull_StatsPullAtomService(env);
|
register_android_server_stats_pull_StatsPullAtomService(env);
|
||||||
register_android_server_AdbDebuggingManager(env);
|
register_android_server_AdbDebuggingManager(env);
|
||||||
|
|||||||
Reference in New Issue
Block a user