Android Framework Audio Subsystem(09)ヘッドセットプラグインプロセス分析

記事のマスターリンクのこのシリーズ:テーマ別のサブディレクトリのAndroid Frameworkクラスオーディオ・サブシステム


この章の要点の概要と説明:

この章では主に、上記のマインドマップの左上にあるヘッドセットの接続と取り外しについて説明します。この章では、主にヘッドセットの接続と取り外しのプロセスを分析します。ヘッドセットの接続と取り外しの後で、フレームワークレイヤーでのAndroidの処理方法について説明します。同時に、この章では、比較的簡単に記述できる入力サブシステムを参照しています詳細については、入力サブシステムのトピックリンクを参照してください:トピックサブカテゴリディレクトリAndroidフレームワーク入力サブシステム

ヘッドセットの接続と取り外しには、Androidに2つのモードがあり、入力サブシステムまたは状態開発(uevent)を使用して、接続と接続の操作を報告できます。手順は次のとおりです。

  • 入力サブシステム:キーイベントまたはスイッチイベント(EV_SW)を報告できます。イベントタイプには、ヘッドセット、headPhone、lineOutなどがあります。入力デバイスの場合、同期イベントを生成できるEV_SYNを指定する必要があります。キーイベントの場合、入力サブシステムもキー値の範囲を設定する必要がありますが、スイッチイベントに設定する必要はありません。
  • スイッチクラスサブシステム:ueventを介してユーザースペースにデータを送信するAndroidには、このようなイベントをリッスンするスレッドがあります。スイッチ開発サブシステムを使用する場合、名前を「h2w」に設定する必要があり、Androidシステムは仮想デバイス/ sys /クラス/スイッチ/ h2wをリッスンします。

特定の操作は、config.xmlファイルで次のように定義されている構成値config_useDevInputEventForAudioJackに依存します。

...  
    <!-- When true use the linux /dev/input/event subsystem to detect the switch changes
         on the headphone/microphone jack. When false use the older uevent framework. -->
    <bool name="config_useDevInputEventForAudioJack">false</bool>
...

値がtrueの場合、入力サブシステムが使用され、falseの場合、ueventメカニズムが使用されます。この値は次のファイルで定義されており、後者のファイルが前のファイルを上書きします。

frameworks/base/core/res/res/values/config.xml
device/"平台厂商"/frameworks/base/core/res/res/values/config.xml

次に、2つのモードを分析します。2つのモードの前半は一貫性がなく、後半は同じです。主なプロセスは、そのようなプロセスを分析することです。基盤となるヘッドセットプラグインがレイヤーごとにイベントを報告し、最後にActivityManagerServiceを介してメッセージをブロードキャストする方法です。


1分析の前半(WiredAccessoryManagerのupdateLockedメソッドの2つのモード)

1.1入力サブシステムを使用するプロセス(入力サブシステムからWiredAccessoryManagerのupdateLockedメソッドまで)

入力サブシステムは、イベントの読み取りを開始し、InputReaderを介してそれらを処理します。コードは次のとおりです。

void InputReader::loopOnce() {
    //...
    //获取事件
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
    { // acquire lock
        //...
        //处理事件
        processEventsLocked(mEventBuffer, count);
        //...
    } // release lock

    // Send out a message that the describes the changed input devices.
    if (inputDevicesChanged) {
        mPolicy->notifyInputDevicesChanged(inputDevices);
    }
    mQueuedListener->flush();
}

InputReaderスレッドは、EventHubのgetEventメソッドを使用してドライバーからイベントを取得し、次にprocessEventsLockedを使用して処理を開始します。ProcessEventsLockedは次のように実装されます。

void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
    for (const RawEvent* rawEvent = rawEvents; count;) {
        int32_t type = rawEvent->type;
        size_t batchSize = 1;
        if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
            //...
            processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
        } else {
            //...
        }
        count -= batchSize;
        rawEvent += batchSize;
    }
}

ここでprocessEventsForDeviceLockedの実装の分析を続けます。コードは次のとおりです。

void InputReader::processEventsForDeviceLocked(int32_t deviceId,
        const RawEvent* rawEvents, size_t count) {
    //...
    InputDevice* device = mDevices.valueAt(deviceIndex);
    //...
    device->process(rawEvents, count);
}

InputDeviceプロセスメソッドの分析を続けます。コードは次のとおりです。

void InputDevice::process(const RawEvent* rawEvents, size_t count) {
    size_t numMappers = mMappers.size();
    for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
        if (mDropUntilNextSync) {
            //...
        } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
            //...
        } else {
            for (size_t i = 0; i < numMappers; i++) {
                InputMapper* mapper = mMappers[i];
                mapper->process(rawEvent);
            }
        }
    }
}

swicthイベントの場合、ここのマップはSwitchInputMapperであり、そのプロセス関数は次のように実装されます。

void SwitchInputMapper::process(const RawEvent* rawEvent) {
    switch (rawEvent->type) {
    case EV_SW:
        processSwitch(rawEvent->code, rawEvent->value);
        break;

    case EV_SYN:
        if (rawEvent->code == SYN_REPORT) {
            sync(rawEvent->when);
        }
    }
}

processSwitchの分析を続けます。コードは次のとおりです。

void SwitchInputMapper::processSwitch(int32_t switchCode, int32_t switchValue) {
    if (switchCode >= 0 && switchCode < 32) {
        if (switchValue) {
            mSwitchValues |= 1 << switchCode;
        } else {
            mSwitchValues &= ~(1 << switchCode);
        }
        mUpdatedSwitchMask |= 1 << switchCode;
    }
}

ここでは主にmSwitchValuesの値を通じて状態を保存するために、同期の実装を分析し続けます。コードは次のとおりです。

void SwitchInputMapper::sync(nsecs_t when) {
    if (mUpdatedSwitchMask) {
        uint32_t updatedSwitchValues = mSwitchValues & mUpdatedSwitchMask;
        NotifySwitchArgs args(when, 0, updatedSwitchValues, mUpdatedSwitchMask);
        getListener()->notifySwitch(&args);
        mUpdatedSwitchMask = 0;
    }
}

ここでのgetListener()-> notifySwitch(&args)は、実際にはInputDispatcherのnotifySwitchメソッドですコードの実装は次のとおりです。

void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) {
    uint32_t policyFlags = args->policyFlags;
    policyFlags |= POLICY_FLAG_TRUSTED;
    mPolicy->notifySwitch(args->eventTime,
            args->switchValues, args->switchMask, policyFlags);
}

ここのmPolicy-> notifySwitchは、JNIのコールバック後に、JavaレイヤーのInputManagerServiceのnotifySwitchメソッドを呼び出します。コードは次のとおりです。

// Native callback.
private void notifySwitch(long whenNanos, int switchValues, int switchMask) {
    if ((switchMask & SW_LID_BIT) != 0) {
        final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0);
        mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
    }

    if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) {
        final boolean lensCovered = ((switchValues & SW_CAMERA_LENS_COVER_BIT) != 0);
        mWindowManagerCallbacks.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered);
    }
    //mUseDevInputEventForAudioJack在这里被配置成true,会走该分支
    if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) {
        mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues,
                switchMask);
    }
}

ここで引き続きnotifyWiredAccessoryChangedを分析します。コードの実装は次のとおりです。

@Override
public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask) {
    synchronized (mLock) {
        int headset;
        mSwitchValues = (mSwitchValues & ~switchMask) | switchValues;
        switch (mSwitchValues &
            (SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_LINEOUT_INSERT_BIT)) {
            case 0:
                headset = 0;
                break;

            case SW_HEADPHONE_INSERT_BIT:
                headset = BIT_HEADSET_NO_MIC;
                break;

            case SW_LINEOUT_INSERT_BIT:
                headset = BIT_LINEOUT;
                break;

            case SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT:
                headset = BIT_HEADSET;
                break;

            case SW_MICROPHONE_INSERT_BIT:
                headset = BIT_HEADSET;
                break;

            default:
                headset = 0;
                break;
        }
        updateLocked(NAME_H2W,
            (mHeadsetState & ~(BIT_HEADSET | BIT_HEADSET_NO_MIC | BIT_LINEOUT)) | headset);
    }
}

ここではupdateLockedメソッドが呼び出されます。次の分析は、分析の後半に続きます。

1.2 ueventメカニズムを使用するプロセス(ueventからWiredAccessoryManagerのupdateLockedメソッドまで)

systemserverのstartOtherServicesでのWiredAccessoryManagerの作成と使用は次のとおりです。

private void startOtherServices() {
    final Context context = mSystemContext;
	//...
        if (!disableMedia) {
            try {
                //关键点1
                inputManager.setWiredAccessoryCallbacks(
                        new WiredAccessoryManager(context, inputManager));
            } catch (Throwable e) {
                reportWtf("starting WiredAccessoryManager", e);
            }
        }
	//...
	final InputManagerService inputManagerF = inputManager;
	//...
	try {
		//关键点2
		if (inputManagerF != null) inputManagerF.systemRunning();
	} catch (Throwable e) {
		reportWtf("Notifying InputManagerService running", e);
	}
	//...
}

@ 1 WiredAccessoryManagerが作成されました

WiredAccessoryManagerのコンストラクタコードは次のように実装されます。

public WiredAccessoryManager(Context context, InputManagerService inputManager) {
    //这里涉及三个服务:电源子系统、输入输出子系统、音频子系统
    PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
    mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WiredAccessoryManager");
    mWakeLock.setReferenceCounted(false);
    mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
    mInputManager = inputManager;
    mUseDevInputEventForAudioJack =
            context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
    mObserver = new WiredAccessoryObserver();
}

ここのWiredAccessoryObserverはUEventObserverクラスを継承し、UEventObserverは空で、WiredAccessoryObserverのコンストラクタコードは次のとおりです。

public WiredAccessoryObserver() {
    mUEventInfo = makeObservedUEventList();
}

ここでmakeObservedUEventListのコードは次のように実装されています。

private List<UEventInfo> makeObservedUEventList() {
    List<UEventInfo> retVal = new ArrayList<UEventInfo>();
    UEventInfo uei;

    //这里只监听这三个UEventInfo对应的事件,驱动程序通过uevent上报事件也只能上报这三个事件之一
    // Monitor h2w
    if (!mUseDevInputEventForAudioJack) {
                    //用于监听名为"h2w"这个Switch class驱动中创建的虚拟文件                                     
                    //./devices/virtual/switch/h2w
                    //./class/switch/h2w
        uei = new UEventInfo(NAME_H2W, BIT_HEADSET, BIT_HEADSET_NO_MIC, BIT_LINEOUT);
        if (uei.checkSwitchExists()) {
            retVal.add(uei);
        }
    }

    // Monitor USB
    uei = new UEventInfo(NAME_USB_AUDIO, BIT_USB_HEADSET_ANLG, BIT_USB_HEADSET_DGTL, 0);
    if (uei.checkSwitchExists()) {
        retVal.add(uei);
    } 
    uei = new UEventInfo(NAME_HDMI_AUDIO, BIT_HDMI_AUDIO, 0, 0);
    if (uei.checkSwitchExists()) {
        retVal.add(uei);
    } else {
        uei = new UEventInfo(NAME_HDMI, BIT_HDMI_AUDIO, 0, 0);
        if (uei.checkSwitchExists()) {
            retVal.add(uei);
        }
    }
    return retVal;
}

@ 2 inputManagerFのsystemRunning()関数分析

inputManagerF.systemRunning()コードは次のように実装されます。

public void systemRunning() {
    //...
    if (mWiredAccessoryCallbacks != null) {
        mWiredAccessoryCallbacks.systemReady();
    }
}

ここで、systemReadyコードは次のように実装されています。

@Override
public void systemReady() {
    synchronized (mLock) {
        mWakeLock.acquire();
        Message msg = mHandler.obtainMessage(MSG_SYSTEM_READY, 0, 0, null);
        mHandler.sendMessage(msg);
    }
}

MSG_SYSTEM_READYメッセージを処理するハンドラコードは次のとおりです。

private final Handler mHandler = new Handler(Looper.myLooper(), null, true) {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_NEW_DEVICE_STATE:
                setDevicesState(msg.arg1, msg.arg2, (String)msg.obj);
                mWakeLock.release();
                break;
            case MSG_SYSTEM_READY:
                onSystemReady();
                mWakeLock.release();
                break;
        }
    }
};

ここではonSystemReadyを呼び出します。コードの実装は次のとおりです。

private void onSystemReady() {
    if (mUseDevInputEventForAudioJack) {
        int switchValues = 0;
        if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_HEADPHONE_INSERT) == 1) {
            switchValues |= SW_HEADPHONE_INSERT_BIT;
        }
        if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MICROPHONE_INSERT) == 1) {
            switchValues |= SW_MICROPHONE_INSERT_BIT;
        }
        if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_LINEOUT_INSERT) == 1) {
            switchValues |= SW_LINEOUT_INSERT_BIT;
        }
        notifyWiredAccessoryChanged(0, switchValues,
                SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_LINEOUT_INSERT_BIT);
    }
    mObserver.init();
}

mObserverのinit()メソッドを分析し続けると、コードは次のように実装されます。

void init() {
    //...
    for (int i = 0; i < mUEventInfo.size(); ++i) {
        UEventInfo uei = mUEventInfo.get(i);
        startObserving("DEVPATH="+uei.getDevPath());
    }
}

ここでstartObservingの分析を続けます。コードの実装は次のとおりです。

public final void startObserving(String match) {
    final UEventThread t = getThread();
    t.addObserver(match, this);
}

引き続きgetThreadの実装を確認します。コードは次のとおりです。

private static UEventThread getThread() {
    synchronized (UEventObserver.class) {
        if (sThread == null) {
            sThread = new UEventThread();
            sThread.start();
        }
        return sThread;
    }
}

ここでstartが実行されると、UEventThreadのrunメソッドが呼び出され、コードの実装は次のようになります。

public void run() {
    nativeSetup();
    while (true) {
        //...
        //等待事件,native层实现,从系统底层接收消息
        String message = nativeWaitForNextEvent();
        if (message != null) {
            //发送消息
            sendEvent(message);
        }
    }
}

メッセージの送信は次のように実装されています。

private void sendEvent(String message) {
    //...
    if (!mTempObserversToSignal.isEmpty()) {
        final UEvent event = new UEvent(message);
        final int N = mTempObserversToSignal.size();
        for (int i = 0; i < N; i++) {
            final UEventObserver observer = mTempObserversToSignal.get(i);
            observer.onUEvent(event);
        }
        mTempObserversToSignal.clear();
    }
}

空のオブザーバーのonUEvent(...)メソッドの実装を引き続き分析します。ここでは、WiredAccessoryObserverサブクラスの実装が呼び出されます。コードは次のとおりです。

@Override
public void onUEvent(UEventObserver.UEvent event) {
    try {
        String devPath = event.get("DEVPATH");
        String name = event.get("SWITCH_NAME");
        int state = Integer.parseInt(event.get("SWITCH_STATE"));
        synchronized (mLock) {
            updateStateLocked(devPath, name, state);
        }
    } catch (NumberFormatException e) {
        Slog.e(TAG, "Could not parse switch state from event " + event);
    }
}

updateStateLockedの分析を続けます。コードの実装は次のとおりです。

private void updateStateLocked(String devPath, String name, int state) {
    for (int i = 0; i < mUEventInfo.size(); ++i) {
        UEventInfo uei = mUEventInfo.get(i);
        if (devPath.equals(uei.getDevPath())) {
            updateLocked(name, uei.computeNewHeadsetState(mHeadsetState, state));
            return;
        }
    }
}

ここではupdateLockedメソッドが呼び出されます。次の分析は、分析の後半に続きます。


2分析の後半(WiredAccessoryManagerのupdateLockedメソッドから、ブロードキャストを送信するための上位のActivityManagerServiceまで)

WiredAccessoryManagerのupdateLockedコードは次のように実装されます。

private void updateLocked(String newName, int newState) {
    //...
    mWakeLock.acquire();
	//获得并发送message
    Message msg = mHandler.obtainMessage(MSG_NEW_DEVICE_STATE, headsetState,
            mHeadsetState, newName);
    mHandler.sendMessage(msg);
    mHeadsetState = headsetState;
}

ここのハンドラーは、メッセージMSG_NEW_DEVICE_STATEを次のように処理します。

private final Handler mHandler = new Handler(Looper.myLooper(), null, true) {
@Override
public void handleMessage(Message msg) {
    switch (msg.what) {
        case MSG_NEW_DEVICE_STATE:
            setDevicesState(msg.arg1, msg.arg2, (String)msg.obj);
            mWakeLock.release();
            break;
        case MSG_SYSTEM_READY:
            onSystemReady();
            mWakeLock.release();
            break;
    }
}

ここでsetDevicesStateの実装に焦点を当てると、コードは次のようになります。

private void setDevicesState(
        int headsetState, int prevHeadsetState, String headsetName) {
    synchronized (mLock) {
        int allHeadsets = SUPPORTED_HEADSETS;
        for (int curHeadset = 1; allHeadsets != 0; curHeadset <<= 1) {
            if ((curHeadset & allHeadsets) != 0) {
                setDeviceStateLocked(curHeadset, headsetState, prevHeadsetState, headsetName);
                allHeadsets &= ~curHeadset;
            }
        }
    }
}

ここでは、setDeviceStateLockedの実装について懸念しています。コードは次のとおりです。

private void setDeviceStateLocked(int headset,
        int headsetState, int prevHeadsetState, String headsetName) {
    if ((headsetState & headset) != (prevHeadsetState & headset)) {
        int outDevice = 0;
        int inDevice = 0;
        int state;

        if ((headsetState & headset) != 0) {
            state = 1;
        } else {
            state = 0;
        }

        if (headset == BIT_HEADSET) {
            outDevice = AudioManager.DEVICE_OUT_WIRED_HEADSET;
            inDevice = AudioManager.DEVICE_IN_WIRED_HEADSET;
        } else if (headset == BIT_HEADSET_NO_MIC){
            outDevice = AudioManager.DEVICE_OUT_WIRED_HEADPHONE;
        } else if (headset == BIT_LINEOUT){
            outDevice = AudioManager.DEVICE_OUT_LINE;
        } else if (headset == BIT_USB_HEADSET_ANLG) {
            outDevice = AudioManager.DEVICE_OUT_ANLG_DOCK_HEADSET;
        } else if (headset == BIT_USB_HEADSET_DGTL) {
            outDevice = AudioManager.DEVICE_OUT_DGTL_DOCK_HEADSET;
        } else if (headset == BIT_HDMI_AUDIO) {
            outDevice = AudioManager.DEVICE_OUT_HDMI;
        } else {
            Slog.e(TAG, "setDeviceState() invalid headset type: "+headset);
            return;
        }
        if (outDevice != 0) {
          //进入了Audio系统,设置有线设备的连接状态
          mAudioManager.setWiredDeviceConnectionState(outDevice, state, headsetName);
        }
        if (inDevice != 0) {
          mAudioManager.setWiredDeviceConnectionState(inDevice, state, headsetName);
        }
    }
}

ここでは、mAudioManagerのsetWiredDeviceConnectionStateメソッドの実装に注意してください。コードは次のとおりです。

public void setWiredDeviceConnectionState(int device, int state, String name) {
    IAudioService service = getService();
    try {
        service.setWiredDeviceConnectionState(device, state, name);
    } catch (RemoteException e) {
        Log.e(TAG, "Dead object in setWiredDeviceConnectionState "+e);
    }
}

setWiredDeviceConnectionStateの分析を続けます。コードの実装は次のとおりです。

public void setWiredDeviceConnectionState(int device, int state, String name) {
    synchronized (mConnectedDevices) {
        int delay = checkSendBecomingNoisyIntent(device, state);
        queueMsgUnderWakeLock(mAudioHandler,
                MSG_SET_WIRED_DEVICE_CONNECTION_STATE,device,state,name,delay);
    }
}

ここのqueueMsgUnderWakeLockコードは、次のように実装されます。

private void queueMsgUnderWakeLock(Handler handler, int msg,
        int arg1, int arg2, Object obj, int delay) {
    final long ident = Binder.clearCallingIdentity();
    mAudioEventWakeLock.acquire();
    Binder.restoreCallingIdentity(ident);
    sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
}

ハンドラーはMSG_SET_WIRED_DEVICE_CONNECTION_STATEメッセージを処理します。コードは次のとおりです。

@Override
public void handleMessage(Message msg) {
    switch (msg.what) {
        case MSG_SET_DEVICE_VOLUME:
            setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
            break;
        //...
        case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
            onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj);
            mAudioEventWakeLock.release();
            break;
        //...
    }
}

onSetWiredDeviceConnectionStateのコード実装は次のとおりです。

private void onSetWiredDeviceConnectionState(int device, int state, String name)
{
    synchronized (mConnectedDevices) {
        //...
        //关键点1:声道切换入口
        handleDeviceConnection((state == 1), device, (isUsb ? name : ""));
        if (state != 0) {
            //...
            if ((device & mSafeMediaVolumeDevices) != 0) {
                sendMsg(mAudioHandler,MSG_CHECK_MUSIC_ACTIVE,SENDMSG_REPLACE,0,0,null,MUSIC_ACTIVE_POLL_PERIOD_MS);
            }
            //...
        } else {
            //...
        }
        if (!isUsb && (device != AudioSystem.DEVICE_IN_WIRED_HEADSET)) {
            //关键点2:通过AMS上报intent
            sendDeviceConnectionIntent(device, state, name);
        }
    }
}

ここから、注意すべき2つの重要なポイントがあります。チャネルスイッチエントリのhandleDeviceConnectionと、AMSにインテントを報告するsendDeviceConnectionIntentです。 

@ 1 handleDeviceConnectionの分析を続けます。コードの実装は次のとおりです。

private boolean handleDeviceConnection(boolean connected, int device, String params) {
    synchronized (mConnectedDevices) {
        boolean isConnected = (mConnectedDevices.containsKey(device) &&
                (params.isEmpty() || mConnectedDevices.get(device).equals(params)));

        if (isConnected && !connected) {
            AudioSystem.setDeviceConnectionState(device,
                                          AudioSystem.DEVICE_STATE_UNAVAILABLE,
                                          mConnectedDevices.get(device));
             mConnectedDevices.remove(device);
             return true;
        } else if (!isConnected && connected) {
             AudioSystem.setDeviceConnectionState(device,
                                                  AudioSystem.DEVICE_STATE_AVAILABLE,
                                                  params);
             mConnectedDevices.put(new Integer(device), params);
             return true;
        }
    }
    return false;
}

AudioSystemのsetDeviceConnectionStateメソッドがここで呼び出され、そのJNIマッピング関係は次のとおりです。

{"setDeviceConnectionState", "(IILjava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState}

android_media_AudioSystem_setDeviceConnectionStateの実装の分析を続けます。コードは次のとおりです。

static jint
android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address)
{
    const char *c_address = env->GetStringUTFChars(device_address, NULL);
    int status = check_AudioSystem_Command(AudioSystem::setDeviceConnectionState(static_cast <audio_devices_t>(device),
                                          static_cast <audio_policy_dev_state_t>(state),
                                          c_address));
    env->ReleaseStringUTFChars(device_address, c_address);
    return (jint) status;
}

ここでは、ネイティブレイヤーでのAudioSystemのsetDeviceConnectionStateの分析に焦点を当てますコードの実装は次のとおりです。

status_t AudioSystem::setDeviceConnectionState(audio_devices_t device,
                                               audio_policy_dev_state_t state,
                                               const char *device_address)
{
    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
    const char *address = "";
    //...
    if (device_address != NULL) {
        address = device_address;
    }
    return aps->setDeviceConnectionState(device, state, address);
}

AudioPolicyManagerのsetDeviceConnectionStateメソッドが返されますコードの実装は次のとおりです:

status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device,
                                                          audio_policy_dev_state_t state,
                                                  const char *device_address)
{
    return setDeviceConnectionStateInt(device, state, device_address);
}

ここでは、JavaレイヤーのAudioServiceのhandleDeviceConnectionメソッドが、ネイティブレイヤーのAudioPolicyManagerのsetDeviceConnectionStateIntに直接直接呼び出せることを知っておく必要があります。後で、コードのsetDeviceConnectionStateInt部分を具体的に解釈します。

@ 2 sendDeviceConnectionIntentの分析を続けます。コードの実装は次のとおりです。

private void sendDeviceConnectionIntent(int device, int state, String name)
{
    //构建一个Intent结构,然后向应用程序广播它,注册对这个Intent感兴趣的App就会收到它
    Intent intent = new Intent();
    intent.putExtra("state", state);
    intent.putExtra("name", name);
    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
    //...
    //intent其他处理
    //...
    try {
        
        ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
    } finally {
        //...
    }
}

この時点で、Intent構造を構築し、それをアプリケーションにブロードキャストすることにより、Intentに関心のあるアプリがそれを受け取り、制御がAPPに与えられます。その後、インテントはケースの形式で受信および処理されます。

 

元の記事289件を公開 賞賛された47件 30,000回以上の閲覧

おすすめ

転載: blog.csdn.net/vviccc/article/details/105394043