Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 25bd52cf authored by Ytai Ben-tsvi's avatar Ytai Ben-tsvi Committed by Automerger Merge Worker
Browse files

Merge changes from topic "invert-capture-rvc" into rvc-dev am: 40ee6ffa am:...

Merge changes from topic "invert-capture-rvc" into rvc-dev am: 40ee6ffa am: 6e9eb7aa am: f6362e87

Change-Id: I2b025374d9b8dfb5bad3c5d97f51fb034385258a
parents 5dc53ef3 f6362e87
Loading
Loading
Loading
Loading
+18 −84
Original line number Diff line number Diff line
@@ -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.
     */
    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);
    private void setCaptureState(boolean active) {
        mListener.accept(active);
    }

        mService.linkToDeath(() -> {
            Log.w(TAG, "Audio policy service died");
            mNeedToConnect.release();
        }, 0);
    }

    /**
     * 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();
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -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) {
+1 −0
Original line number Diff line number Diff line
@@ -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",
+93 −0
Original line number Diff line number Diff line
/*
 * 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
+4 −0
Original line number Diff line number Diff line
@@ -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);