IAudioManager.cpp源码解读

IAudioManager.cpp源码如下:
源码路径:https://cs.android.com/android/platform/superproject/main/+/main:frameworks/native/services/audiomanager/IAudioManager.cpp;drc=84410fbd18148d422d3581201c67f1a72a6658c4;l=147?hl=zh-cn

/** Copyright (C) 2016 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.*/#define LOG_TAG "IAudioManager"
//#define LOG_NDEBUG 0
#include <utils/Log.h>#include <stdint.h>
#include <sys/types.h>#include <binder/Parcel.h>
#include <audiomanager/AudioManager.h>
#include <audiomanager/IAudioManager.h>namespace android {class BpAudioManager : public BpInterface<IAudioManager>
{
public:explicit BpAudioManager(const sp<IBinder>& impl): BpInterface<IAudioManager>(impl){}virtual audio_unique_id_t trackPlayer(player_type_t playerType, audio_usage_t usage,audio_content_type_t content, const sp<IBinder>& player, audio_session_t sessionId) {Parcel data, reply;data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());data.writeInt32(1); // non-null PlayerIdCard parcelable// marshall PlayerIdCard datadata.writeInt32((int32_t) playerType);//   write attributes of PlayerIdCarddata.writeInt32((int32_t) usage);data.writeInt32((int32_t) content);data.writeInt32(0 /*source: none here, this is a player*/);data.writeInt32(0 /*flags*/);//   write attributes' tagsdata.writeInt32(1 /*FLATTEN_TAGS*/);data.writeString16(String16("")); // no tags//   write attributes' bundledata.writeInt32(-1977 /*ATTR_PARCEL_IS_NULL_BUNDLE*/); // no bundle//   write IPlayerdata.writeStrongBinder(player);//   write session Iddata.writeInt32((int32_t)sessionId);// get new PIId in replyconst status_t res = remote()->transact(TRACK_PLAYER, data, &reply, 0);if (res != OK || reply.readExceptionCode() != 0) {ALOGE("trackPlayer() failed, piid is %d", PLAYER_PIID_INVALID);return PLAYER_PIID_INVALID;} else {const audio_unique_id_t piid = (audio_unique_id_t) reply.readInt32();ALOGV("trackPlayer() returned piid %d", piid);return piid;}}virtual status_t playerAttributes(audio_unique_id_t piid, audio_usage_t usage,audio_content_type_t content) {Parcel data, reply;data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());data.writeInt32((int32_t) piid);data.writeInt32(1); // non-null AudioAttributes parcelabledata.writeInt32((int32_t) usage);data.writeInt32((int32_t) content);data.writeInt32(0 /*source: none here, this is a player*/);data.writeInt32(0 /*flags*/);//   write attributes' tagsdata.writeInt32(1 /*FLATTEN_TAGS*/);data.writeString16(String16("")); // no tags//   write attributes' bundledata.writeInt32(-1977 /*ATTR_PARCEL_IS_NULL_BUNDLE*/); // no bundlereturn remote()->transact(PLAYER_ATTRIBUTES, data, &reply, IBinder::FLAG_ONEWAY);}virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event,audio_port_handle_t eventId) {Parcel data, reply;data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());data.writeInt32((int32_t) piid);data.writeInt32((int32_t) event);data.writeInt32((int32_t) eventId);return remote()->transact(PLAYER_EVENT, data, &reply, IBinder::FLAG_ONEWAY);}virtual status_t releasePlayer(audio_unique_id_t piid) {Parcel data, reply;data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());data.writeInt32((int32_t) piid);return remote()->transact(RELEASE_PLAYER, data, &reply, IBinder::FLAG_ONEWAY);}virtual audio_unique_id_t trackRecorder(const sp<IBinder>& recorder) {Parcel data, reply;data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());data.writeStrongBinder(recorder);// get new RIId in replyconst status_t res = remote()->transact(TRACK_RECORDER, data, &reply, 0);if (res != OK || reply.readExceptionCode() != 0) {ALOGE("trackRecorder() failed, riid is %d", RECORD_RIID_INVALID);return RECORD_RIID_INVALID;} else {const audio_unique_id_t riid = (audio_unique_id_t) reply.readInt32();ALOGV("trackRecorder() returned riid %d", riid);return riid;}}virtual status_t recorderEvent(audio_unique_id_t riid, recorder_state_t event) {Parcel data, reply;data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());data.writeInt32((int32_t) riid);data.writeInt32((int32_t) event);return remote()->transact(RECORDER_EVENT, data, &reply, IBinder::FLAG_ONEWAY);}virtual status_t releaseRecorder(audio_unique_id_t riid) {Parcel data, reply;data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());data.writeInt32((int32_t) riid);return remote()->transact(RELEASE_RECORDER, data, &reply, IBinder::FLAG_ONEWAY);}virtual status_t playerSessionId(audio_unique_id_t piid, audio_session_t sessionId) {Parcel data, reply;data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());data.writeInt32((int32_t) piid);data.writeInt32((int32_t) sessionId);return remote()->transact(PLAYER_SESSION_ID, data, &reply, IBinder::FLAG_ONEWAY);}virtual status_t portEvent(audio_port_handle_t portId, player_state_t event,const std::unique_ptr<os::PersistableBundle>& extras) {Parcel data, reply;data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());data.writeInt32((int32_t) portId);data.writeInt32((int32_t) event);// TODO: replace PersistableBundle with own structdata.writeNullableParcelable(extras);return remote()->transact(PORT_EVENT, data, &reply, IBinder::FLAG_ONEWAY);}
};IMPLEMENT_META_INTERFACE(AudioManager, "android.media.IAudioService");// ----------------------------------------------------------------------------}; // namespace android

这里显示了一个名为 IAudioManager.cpp 的文件,它是一个 C++ 语言的源代码文件,用于实现音频管理器的接口。代码的逻辑如下:

  • 定义了一个 BpAudioManager 类,它继承了 BpInterface 类,用于实现 Binder 通信的代理端。
  • 在 BpAudioManager 类中,实现了 IAudioManager 接口中的各个方法,包括:
    • trackPlayer:用于追踪一个播放器的类型、用途、内容、会话 ID 等信息,并返回一个唯一的播放器 ID。
    • playerAttributes:用于更新一个播放器的用途和内容属性。
    • playerEvent:用于通知一个播放器的状态变化,如开始、暂停、停止等。
    • releasePlayer:用于释放一个播放器的资源。
    • trackRecorder:用于追踪一个录音器的引用,并返回一个唯一的录音器 ID。
    • recorderEvent:用于通知一个录音器的状态变化,如开始、暂停、停止等。
    • releaseRecorder:用于释放一个录音器的资源。
    • playerSessionId:用于更新一个播放器的会话 ID。
    • portEvent:用于通知一个端口的事件,如连接、断开、配置等。
  • 使用 IMPLEMENT_META_INTERFACE 宏来注册 AudioManager 接口的名称和描述。
 explicit BpAudioManager(const sp<IBinder>& impl): BpInterface<IAudioManager>(impl){}

这是是一个 C++ 语言的构造函数,用于创建一个 BpAudioManager 对象。这个构造函数的参数是一个 IBinder 类型的智能指针,用于指向 Binder 通信的远程端。这个构造函数的作用是调用 BpInterface 类的构造函数,将 impl 作为参数传递,从而初始化 BpAudioManager 对象的基类成员变量。这个构造函数没有其他的操作,所以函数体为空。

virtual audio_unique_id_t trackPlayer(player_type_t playerType, audio_usage_t usage,audio_content_type_t content, const sp<IBinder>& player, audio_session_t sessionId) {Parcel data, reply;data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());data.writeInt32(1); // non-null PlayerIdCard parcelable// marshall PlayerIdCard datadata.writeInt32((int32_t) playerType);//   write attributes of PlayerIdCarddata.writeInt32((int32_t) usage);data.writeInt32((int32_t) content);data.writeInt32(0 /*source: none here, this is a player*/);data.writeInt32(0 /*flags*/);//   write attributes' tagsdata.writeInt32(1 /*FLATTEN_TAGS*/);data.writeString16(String16("")); // no tags//   write attributes' bundledata.writeInt32(-1977 /*ATTR_PARCEL_IS_NULL_BUNDLE*/); // no bundle//   write IPlayerdata.writeStrongBinder(player);//   write session Iddata.writeInt32((int32_t)sessionId);// get new PIId in replyconst status_t res = remote()->transact(TRACK_PLAYER, data, &reply, 0);if (res != OK || reply.readExceptionCode() != 0) {ALOGE("trackPlayer() failed, piid is %d", PLAYER_PIID_INVALID);return PLAYER_PIID_INVALID;} else {const audio_unique_id_t piid = (audio_unique_id_t) reply.readInt32();ALOGV("trackPlayer() returned piid %d", piid);return piid;}}

这是一个 C++ 语言的虚函数,用于追踪一个播放器的信息,并返回一个唯一的播放器 ID。这个函数的参数是:

  • playerType:一个枚举类型,表示播放器的类型,如媒体播放器、声音池、硬件编解码器等。
  • usage:一个枚举类型,表示播放器的用途,如闹钟、游戏、通话等。
  • content:一个枚举类型,表示播放器的内容,如音乐、电影、语音等。
  • player:一个 IBinder 类型的智能指针,用于指向播放器的远程接口。
  • sessionId:一个整数类型,表示播放器的会话 ID,用于关联不同的音频流。

这个函数的逻辑如下:

  • 创建一个 Parcel 对象 data,用于存储要发送的数据。
  • 创建一个 Parcel 对象 reply,用于接收返回的数据。
  • 调用 data.writeInterfaceToken() 方法,写入 AudioManager 接口的标识符,用于验证 Binder 通信的有效性。
  • 调用 data.writeInt32() 方法,写入一个整数 1,表示要发送的 PlayerIdCard 对象不为空。
  • 调用 data.writeInt32() 方法,写入 playerType 参数,表示播放器的类型。
  • 调用 data.writeInt32() 方法,依次写入 usage 和 content 参数,表示播放器的用途和内容。
  • 调用 data.writeInt32() 方法,写入两个 0,表示播放器的源和标志为空。
  • 调用 data.writeInt32() 方法,写入一个整数 1,表示要发送的属性标签为 FLATTEN_TAGS。
  • 调用 data.writeString16() 方法,写入一个空字符串,表示没有属性标签。
  • 调用 data.writeInt32() 方法,写入一个整数 -1977,表示要发送的属性包为空。
  • 调用 data.writeStrongBinder() 方法,写入 player 参数,表示播放器的远程接口。
  • 调用 data.writeInt32() 方法,写入 sessionId 参数,表示播放器的会话 ID。
  • 调用 remote()->transact() 方法,将 data 对象发送给远程端,并将返回的数据存储在 reply 对象中。传递的参数是 TRACK_PLAYER,表示要执行的操作是追踪播放器,以及 0,表示不需要阻塞等待返回。
  • 判断返回的状态是否为 OK,以及 reply 对象中是否有异常代码,如果有,则打印错误日志,并返回一个无效的播放器 ID。
  • 如果没有异常,则从 reply 对象中读取一个整数,作为新分配的播放器 ID,并打印日志,然后返回该 ID。

简而言之,这个函数是用于追踪一个播放器的信息,并返回一个唯一的播放器 ID 的 AudioManager 接口的虚函数。

virtual status_t playerAttributes(audio_unique_id_t piid, audio_usage_t usage,audio_content_type_t content) {Parcel data, reply;data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());data.writeInt32((int32_t) piid);data.writeInt32(1); // non-null AudioAttributes parcelabledata.writeInt32((int32_t) usage);data.writeInt32((int32_t) content);data.writeInt32(0 /*source: none here, this is a player*/);data.writeInt32(0 /*flags*/);//   write attributes' tagsdata.writeInt32(1 /*FLATTEN_TAGS*/);data.writeString16(String16("")); // no tags//   write attributes' bundledata.writeInt32(-1977 /*ATTR_PARCEL_IS_NULL_BUNDLE*/); // no bundlereturn remote()->transact(PLAYER_ATTRIBUTES, data, &reply, IBinder::FLAG_ONEWAY);}

这段代码是一个 C++ 语言的虚函数,用于更新一个播放器的用途和内容属性。这个函数的参数是:

  • piid:一个整数类型,表示播放器的唯一 ID。
  • usage:一个枚举类型,表示播放器的用途,如闹钟、游戏、通话等。
  • content:一个枚举类型,表示播放器的内容,如音乐、电影、语音等。

这个函数的逻辑如下:

  • 创建一个 Parcel 对象 data,用于存储要发送的数据。
  • 创建一个 Parcel 对象 reply,用于接收返回的数据。
  • 调用 data.writeInterfaceToken() 方法,写入 AudioManager 接口的标识符,用于验证 Binder 通信的有效性。
  • 调用 data.writeInt32() 方法,写入 piid 参数,表示播放器的唯一 ID。
  • 调用 data.writeInt32() 方法,写入一个整数 1,表示要发送的 AudioAttributes 对象不为空。
  • 调用 data.writeInt32() 方法,依次写入 usage 和 content 参数,表示播放器的用途和内容属性。
  • 调用 data.writeInt32() 方法,写入两个 0,表示播放器的源和标志为空。
  • 调用 data.writeInt32() 方法,写入一个整数 1,表示要发送的属性标签为 FLATTEN_TAGS。
  • 调用 data.writeString16() 方法,写入一个空字符串,表示没有属性标签。
  • 调用 data.writeInt32() 方法,写入一个整数 -1977,表示要发送的属性包为空。
  • 调用 remote()->transact() 方法,将 data 对象发送给远程端,并将返回的数据存储在 reply 对象中。传递的参数是 PLAYER_ATTRIBUTES,表示要执行的操作是更新播放器的属性,以及 IBinder::FLAG_ONEWAY,表示不需要等待返回的结果。

简而言之,这个函数是用于更新一个播放器的用途和内容属性的 AudioManager 接口的虚函数。

virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event,audio_port_handle_t eventId) {Parcel data, reply;data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());data.writeInt32((int32_t) piid);data.writeInt32((int32_t) event);data.writeInt32((int32_t) eventId);return remote()->transact(PLAYER_EVENT, data, &reply, IBinder::FLAG_ONEWAY);}

这段代码是一个 C++ 语言的虚函数,用于通知一个播放器的状态变化。这个函数的参数是:

  • piid:一个整数类型,表示播放器的唯一 ID。
  • event:一个枚举类型,表示播放器的状态,如开始、暂停、停止等。
  • eventId:一个整数类型,表示播放器的事件 ID,用于区分不同的事件。

这个函数的逻辑如下:

  • 创建一个 Parcel 对象 data,用于存储要发送的数据。
  • 创建一个 Parcel 对象 reply,用于接收返回的数据。
  • 调用 data.writeInterfaceToken() 方法,写入 AudioManager 接口的标识符,用于验证 Binder 通信的有效性。
  • 调用 data.writeInt32() 方法,依次写入 piid、event 和 eventId 参数,表示播放器的 ID、状态和事件 ID。
  • 调用 remote()->transact() 方法,将 data 对象发送给远程端,并将返回的数据存储在 reply 对象中。传递的参数是 PLAYER_EVENT,表示要执行的操作是通知播放器的状态变化,以及 IBinder::FLAG_ONEWAY,表示不需要等待返回的结果。

简而言之,这个函数是用于通知一个播放器的状态变化的 AudioManager 接口的虚函数。

virtual status_t releasePlayer(audio_unique_id_t piid) {Parcel data, reply;data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());data.writeInt32((int32_t) piid);return remote()->transact(RELEASE_PLAYER, data, &reply, IBinder::FLAG_ONEWAY);}

这是一个 C++ 语言的虚函数,用于释放一个播放器的资源。这个函数的参数是:

  • piid:一个整数类型,表示播放器的唯一 ID。

这个函数的逻辑如下:

  • 创建一个 Parcel 对象 data,用于存储要发送的数据。
  • 创建一个 Parcel 对象 reply,用于接收返回的数据。
  • 调用 data.writeInterfaceToken() 方法,写入 AudioManager 接口的标识符,用于验证 Binder 通信的有效性。
  • 调用 data.writeInt32() 方法,写入 piid 参数,表示播放器的唯一 ID。
  • 调用 remote()->transact() 方法,将 data 对象发送给远程端,并将返回的数据存储在 reply 对象中。传递的参数是 RELEASE_PLAYER,表示要执行的操作是释放播放器的资源,以及 IBinder::FLAG_ONEWAY,表示不需要等待返回的结果。

简而言之,这个函数是用于释放一个播放器的资源的 AudioManager 接口的虚函数。

 virtual audio_unique_id_t trackRecorder(const sp<IBinder>& recorder) {Parcel data, reply;data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());data.writeStrongBinder(recorder);// get new RIId in replyconst status_t res = remote()->transact(TRACK_RECORDER, data, &reply, 0);if (res != OK || reply.readExceptionCode() != 0) {ALOGE("trackRecorder() failed, riid is %d", RECORD_RIID_INVALID);return RECORD_RIID_INVALID;} else {const audio_unique_id_t riid = (audio_unique_id_t) reply.readInt32();ALOGV("trackRecorder() returned riid %d", riid);return riid;}}

这是一个 C++ 语言的虚函数,用于追踪一个录音器的引用,并返回一个唯一的录音器 ID。这个函数的参数是:

  • recorder:一个 IBinder 类型的智能指针,用于指向录音器的远程接口。

这个函数的逻辑如下:

  • 创建一个 Parcel 对象 data,用于存储要发送的数据。
  • 创建一个 Parcel 对象 reply,用于接收返回的数据。
  • 调用 data.writeInterfaceToken() 方法,写入 AudioManager 接口的标识符,用于验证 Binder 通信的有效性。
  • 调用 data.writeStrongBinder() 方法,写入 recorder 参数,表示录音器的远程接口。
  • 调用 remote()->transact() 方法,将 data 对象发送给远程端,并将返回的数据存储在 reply 对象中。传递的参数是 TRACK_RECORDER,表示要执行的操作是追踪录音器,以及 0,表示不需要阻塞等待返回。
  • 判断返回的状态是否为 OK,以及 reply 对象中是否有异常代码,如果有,则打印错误日志,并返回一个无效的录音器 ID。
  • 如果没有异常,则从 reply 对象中读取一个整数,作为新分配的录音器 ID,并打印日志,然后返回该 ID。

简而言之,这个函数是用于追踪一个录音器的引用,并返回一个唯一的录音器 ID 的 AudioManager 接口的虚函数。

virtual status_t recorderEvent(audio_unique_id_t riid, recorder_state_t event) {Parcel data, reply;data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());data.writeInt32((int32_t) riid);data.writeInt32((int32_t) event);return remote()->transact(RECORDER_EVENT, data, &reply, IBinder::FLAG_ONEWAY);}

这段代码是一个 C++ 语言的虚函数,用于通知一个录音器的状态变化。这个函数的参数是:

  • riid:一个整数类型,表示录音器的唯一 ID。
  • event:一个枚举类型,表示录音器的状态,如开始、暂停、停止等。

这个函数的逻辑如下:

  • 创建一个 Parcel 对象 data,用于存储要发送的数据。
  • 创建一个 Parcel 对象 reply,用于接收返回的数据。
  • 调用 data.writeInterfaceToken() 方法,写入 AudioManager 接口的标识符,用于验证 Binder 通信的有效性。
  • 调用 data.writeInt32() 方法,依次写入 riid 和 event 参数,表示录音器的 ID 和状态。
  • 调用 remote()->transact() 方法,将 data 对象发送给远程端,并将返回的数据存储在 reply 对象中。传递的参数是 RECORDER_EVENT,表示要执行的操作是通知录音器的状态变化,以及 IBinder::FLAG_ONEWAY,表示不需要等待返回的结果。

简而言之,这个函数是用于通知一个录音器的状态变化的 AudioManager 接口的虚函数。

   virtual status_t releaseRecorder(audio_unique_id_t riid) {Parcel data, reply;data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());data.writeInt32((int32_t) riid);return remote()->transact(RELEASE_RECORDER, data, &reply, IBinder::FLAG_ONEWAY);}

这是一个 C++ 语言的虚函数,用于释放一个录音器的资源。这个函数的参数是:

  • riid:一个整数类型,表示录音器的唯一 ID。
    这个函数的逻辑如下:
  • 创建一个 Parcel 对象 data,用于存储要发送的数据。
  • 创建一个 Parcel 对象 reply,用于接收返回的数据。
  • 调用 data.writeInterfaceToken() 方法,写入 AudioManager 接口的标识符,用于验证 Binder 通信的有效性。
  • 调用 data.writeInt32() 方法,写入 riid 参数,表示录音器的唯一 ID。
  • 调用 remote()->transact() 方法,将 data 对象发送给远程端,并将返回的数据存储在 reply 对象中。传递的参数是 RELEASE_RECORDER,表示要执行的操作是释放录音器的资源,以及 IBinder::FLAG_ONEWAY,表示不需要等待返回的结果。
    简而言之,这个函数是用于释放一个录音器的资源的 AudioManager 接口的虚函数
virtual status_t playerSessionId(audio_unique_id_t piid, audio_session_t sessionId) {Parcel data, reply;data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());data.writeInt32((int32_t) piid);data.writeInt32((int32_t) sessionId);return remote()->transact(PLAYER_SESSION_ID, data, &reply, IBinder::FLAG_ONEWAY);}

这段代码是一个 C++ 语言的虚函数,用于更新一个播放器的会话 ID。这个函数的参数是:

  • piid:一个整数类型,表示播放器的唯一 ID。
  • sessionId:一个整数类型,表示播放器的会话 ID,用于关联不同的音频流。

这个函数的逻辑如下:

  • 创建一个 Parcel 对象 data,用于存储要发送的数据。
  • 创建一个 Parcel 对象 reply,用于接收返回的数据。
  • 调用 data.writeInterfaceToken() 方法,写入 AudioManager 接口的标识符,用于验证 Binder 通信的有效性。
  • 调用 data.writeInt32() 方法,依次写入 piid 和 sessionId 参数,表示播放器的 ID 和会话 ID。
  • 调用 remote()->transact() 方法,将 data 对象发送给远程端,并将返回的数据存储在 reply 对象中。传递的参数是 PLAYER_SESSION_ID,表示要执行的操作是更新播放器的会话 ID,以及 IBinder::FLAG_ONEWAY,表示不需要等待返回的结果。
    简而言之,这个函数是用于更新一个播放器的会话 ID 的 AudioManager 接口的虚函数。
 virtual status_t portEvent(audio_port_handle_t portId, player_state_t event,const std::unique_ptr<os::PersistableBundle>& extras) {Parcel data, reply;data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());data.writeInt32((int32_t) portId);data.writeInt32((int32_t) event);// TODO: replace PersistableBundle with own structdata.writeNullableParcelable(extras);return remote()->transact(PORT_EVENT, data, &reply, IBinder::FLAG_ONEWAY);}

这段代码是一个 C++ 语言的虚函数,用于通知一个端口的事件。这个函数的参数是:

  • portId:一个整数类型,表示端口的唯一 ID。
  • event:一个枚举类型,表示端口的事件,如连接、断开、配置等。
  • extras:一个智能指针,指向一个 os::PersistableBundle 类型的对象,用于存储额外的信息。

这个函数的逻辑如下:

  • 创建一个 Parcel 对象 data,用于存储要发送的数据。
  • 创建一个 Parcel 对象 reply,用于接收返回的数据。
  • 调用 data.writeInterfaceToken() 方法,写入 AudioManager 接口的标识符,用于验证 Binder 通信的有效性。
  • 调用 data.writeInt32() 方法,依次写入 portId 和 event 参数,表示端口的 ID 和事件。
  • 调用 data.writeNullableParcelable() 方法,写入 extras 参数,表示额外的信息。如果 extras 为空,则写入一个空的 Parcelable 对象。
  • 调用 remote()->transact() 方法,将 data 对象发送给远程端,并将返回的数据存储在 reply 对象中。传递的参数是 PORT_EVENT,表示要执行的操作是通知端口的事件,以及 IBinder::FLAG_ONEWAY,表示不需要等待返回的结果。

简而言之,这个函数是用于通知一个端口的事件的 AudioManager 接口的虚函数。

IMPLEMENT_META_INTERFACE(AudioManager, "android.media.IAudioService");

这是是一个 C++ 语言的宏定义,用于实现 AudioManager 接口的两个方法,分别是:

  • getInterfaceDescriptor():用于返回 AudioManager 接口的标识符,即 “android.media.IAudioService”。
  • asInterface():用于将一个 IBinder 类型的对象转换为一个 IAudioManager 类型的对象,如果该对象是本地对象并且实现了 AudioManager 接口,则返回其实际对象,否则返回一个代理对象。

这个宏定义的参数是:

  • INTERFACE:表示接口的名称,即 AudioManager。
  • NAME:表示接口的标识符,即 “android.media.IAudioService”。

简而言之,这个宏定义是用于实现 AudioManager 接口的两个方法的简化写法。
这里asInterface()在这里面可以看到
https://cs.android.com/android/platform/superproject/main/+/main:frameworks/native/libs/binder/include/binder/IInterface.h;drc=84410fbd18148d422d3581201c67f1a72a6658c4;l=115?hl=zh-cn
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2815174.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

JavaWeb——005 请求响应 分层解耦(Postman、三层架构、IOC、DI、注解)

SpringBootWeb请求响应 这里写目录标题 SpringBootWeb请求响应前言1. 请求1.1 Postman1.1.1 介绍1.1.2 安装 1.2 简单参数1.2.1 原始方式1.2.2 SpringBoot方式1.2.3 参数名不一致 1.3 实体参数1.3.1 简单实体对象1.3.2 复杂实体对象 1.4 数组集合参数1.4.1 数组1.4.2 集合 1.5 …

Linux线程(二)----- 线程控制

目录 前言 一、线程资源区 1.1 线程私有资源 1.2 线程共享资源 1.3 原生线程库 二、线程控制接口 2.1 线程创建 2.1.1 创建一批线程 2.2 线程等待 2.3 终止线程 2.4 线程实战 2.5 其他接口 2.5.1 关闭线程 2.5.2 获取线程ID 2.5.3 线程分离 三、深入理解线程 …

WinCC如何与三菱Q系列PLC进行以太网通讯

本文主要描述人机界面WinCC如何与三菱Q系列PLC进行以太网通讯&#xff0c;主要介绍了CPU自带以太网口和扩展以太网模块两种情况以及分别使用TCP、UDP两种协议进行通讯组态步骤及其注意事项。 一、 说明 WinCC从V7.0 SP2版本开始增加了三菱以太网驱动程序&#xff0c;支持和三…

IPD(集成产品开发)—核心思想

企业发展到一定阶段就会遇到管理瓶颈&#xff0c;IPD流程是一种高度结构化的产品开发流程&#xff0c;它集成了业界很多优秀的产品开发方法论&#xff0c;像搭积木一样的组合成一种非常有效的流程。如果我们能根据企业的规模和行业特点&#xff0c;对全流程的IPD进行合适的裁剪…

数字乡村建设全攻略:从0到1的构建思路与实践

数字乡村建设是推进乡村振兴战略、实现农业农村现代化的重要抓手&#xff0c;其目标是通过数字化手段提升乡村治理效能&#xff0c;优化农村公共服务&#xff0c;推动农业产业升级&#xff0c;助力农民增收致富。 以下是从0到1构建数字乡村的总体思路与实践步骤&#xff1a;一、…

Day03:Web架构OSS存储负载均衡CDN加速反向代理WAF防护

目录 WAF CDN OSS 反向代理 负载均衡 思维导图 章节知识点&#xff1a; 应用架构&#xff1a;Web/APP/云应用/三方服务/负载均衡等 安全产品&#xff1a;CDN/WAF/IDS/IPS/蜜罐/防火墙/杀毒等 渗透命令&#xff1a;文件上传下载/端口服务/Shell反弹等 抓包技术&#xff1a…

STM32实现webserver显示数据及配置参数

之前已经在STM32中移植好了FREERTOSLWIP&#xff0c;要实现webserver配置参数及显示数据&#xff0c;需要使用到httpdcgissi cubeMx中配置以及代码实现参考&#xff1a;ECE471/571 (RTOS) STM32 FreeRTOSLwIP Example - Interactive Web Site 其实提到的将fsdata.c重命名为fs…

【视频编码\VVC】帧间预测编码基础知识

帧间预测编码概述 基本原理 利用时间相关性&#xff0c;使用邻近已编码图像像素值预测当前图像的像素值&#xff0c;能够有效去除时域冗余。目前的视频编码标准中&#xff0c;帧间预测都采用了基于块的运动补偿技术。 运动估计&#xff08;ME&#xff09;&#xff1a;当前图…

Dockerfile(2) - LABEL 指令详解

LABEL 可以为生成的镜像添加元数据标签信息&#xff0c;这些信息可以用来辅助过滤出特定镜像 LABEL <key><value> <key><value> <key><value> ... 栗子一 # key 加了 " LABEL "com.example.vendor""ACME Incorpor…

括号生成(力扣题目22)

题目描述&#xff1a; 数字 n 代表生成括号的对数&#xff0c;请你设计一个函数&#xff0c;用于能够生成所有可能的并且 有效的 括号组合。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;["((()))","(()())","(())()&q…

vue组件中data为什么必须是一个函数

查看本专栏目录 关于作者 还是大剑师兰特&#xff1a;曾是美国某知名大学计算机专业研究生&#xff0c;现为航空航海领域高级前端工程师&#xff1b;CSDN知名博主&#xff0c;GIS领域优质创作者&#xff0c;深耕openlayers、leaflet、mapbox、cesium&#xff0c;canvas&#x…

LeetCode19. 删除链表的倒数第 N 个结点(C++)

LeetCode19. 删除链表的倒数第 N 个结点 题目链接代码 题目链接 https://leetcode.cn/problems/remove-nth-node-from-end-of-list/description/ 代码 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : …

2024年sCrypt编程马拉松即将开幕

BSV区块链的建设者们&#xff0c;你们在哪&#xff1f;2024年sCrypt编程马拉松即将拉开帷幕&#xff01; 2024年3月16日至17日&#xff0c;我们将在旧金山市举办一场以比特币智能合约&#xff08;即 sCrypt&#xff09;和比特币通证&#xff08;如Ordinals&#xff09;相结合为…

Redisson 3.18.0版本解决failover相关问题

前言 Redisson 在历史多个版本都出现了failover期间报错的问题并且目前没有一个版本可以完全解决这个问题&#xff0c;所以在当前使用版本3.18.0基础上做了二次开发&#xff0c;达到降低业务由于redis遇到问题导致不可用。 背景 Redisson 作为业务线使用的Redis 客户端&…

unity学习(41)——创建(create)角色脚本(panel)——UserHandler(收)+CreateClick(发)——创建发包!

1.客户端的程序结构被我精简过&#xff0c;现在去MessageManager.cs中增加一个UserHandler函数&#xff0c;根据收到的包做对应的GameInfo赋值。 2.在Model文件夹下新增一个协议文件UserProtocol&#xff0c;内容很简单。 using System;public class UserProtocol {public co…

使用Rust加速Python程序,让代码飞起来

大家好&#xff0c;作为一种解释型语言&#xff0c;Python在开发速度和灵活性方面具有明显的优势&#xff0c;但在性能方面却不如编译型语言如C或Rust。对于性能要求苛刻的应用程序&#xff0c;如果纯粹使用Python编写可能会运行缓慢&#xff0c;影响用户体验。因此&#xff0c…

揭秘:MyBatis初恋的甜蜜!

&#x1f496;MyBatis的爱情故事&#x1f496; &#x1f339; 第一次遇见官方文档概述为什么需要MyBatis基本介绍MyBatis工作原理学习主线 &#x1f388; 第一次约会需求说明代码实现日志输出-查看SQL课后练习 &#x1f48c; 我们的情书MyBatis整体架构分析搭建MyBatis底层机制…

自由生成各种尺寸大小的占位图片:解决设计与开发中的图片占位问题

title: 自由生成各种尺寸大小的占位图片&#xff1a;解决设计与开发中的图片占位问题 date: 2024/2/28 20:29:11 updated: 2024/2/28 20:29:11 tags: 占位图片尺寸自定义设计效率用户体验响应式设计开发工具测试辅助 在设计与开发的过程中&#xff0c;经常需要使用占位图片来填…

Visio使用笔记

记录一下需要的常用操作 圆角矩形的弧度调整 如果一开始创建的是圆角矩形&#xff0c;可以菜单栏先改为矩形 取消箭头的对齐吸附 alt F9&#xff0c;取消勾选 忘记快捷键&#xff0c;可以菜单栏找到视图&#xff0c;点击视觉帮助右下角的小箭头&#xff0c;引出上面的界面…

leetcode:134.加油站

解题思路&#xff1a;需要注意开始时的编号&#xff0c;有的可以走一圈&#xff0c;有的走不了 模拟过程&#xff1a;for循环主要是用来模拟线性的过程&#xff0c;而在这里它是环状的&#xff1b; 可以用暴力解法&#xff0c;但是在这里我用贪心来解决。 常见疑惑&#xff1…