hi参滴,粉絲朋友們:
背景知識(shí)
針對(duì)hidl中講解到的genarates關(guān)鍵字
https://source.android.google.cn/docs/core/architecture/hidl-cpp/functions
再稍微總結(jié)一下:
針對(duì)有g(shù)enerates關(guān)鍵字的hidl方法聲明如下:
@callflow(next="*")
createVirtualDisplay(uint32_t width,
uint32_t height,
PixelFormat formatHint,
uint32_t outputBufferSlotCount)
generates (Error error,
Display display,
PixelFormat format);
generates就代表返回值部分的回調(diào)末誓,即可以相比return優(yōu)勢(shì)就是可以返回多個(gè)參數(shù),比如這里就可以返回
generates (Error error,
Display display,
PixelFormat format);
中的Error error, Display display,PixelFormat format一共3個(gè)參數(shù),正常return的話一般都是一個(gè)參數(shù)些阅,要返回3個(gè)那得自己包裝對(duì)于的對(duì)象檩咱,或者是吧返回值放到參數(shù)中,指針?lè)绞教钊搿?/p>
但也有另外的:
比如看下面這個(gè)情況:
@callflow(next="*")
getMaxVirtualDisplayCount() generates (uint32_t count);
如果generates返回參數(shù)只有一個(gè)驯绎,而且這個(gè)參數(shù)類型還是基礎(chǔ)數(shù)據(jù)類型完慧,那么就不會(huì)通過(guò)回調(diào)方式返回,而是直接以返回值方式返回剩失。
這一部分的genarates語(yǔ)法都是hidl屈尼,其實(shí)c++代碼肯定沒(méi)有這些genarates關(guān)鍵字,因?yàn)樗械膆idl文件和aidl文件一樣會(huì)在編譯時(shí)候變成c++
問(wèn)題提出:
請(qǐng)問(wèn)這個(gè)genarates的實(shí)現(xiàn)原理是怎么樣的拴孤?上面只是知道了genarates可以實(shí)現(xiàn)多個(gè)返回值脾歧,具體怎么實(shí)現(xiàn)的呢?
針對(duì)這個(gè)多個(gè)返回值問(wèn)題演熟,其實(shí)本質(zhì)上還要看一下相關(guān)的源碼:
system/libhwbinder/BpHwBinder.cpp
status_t BpHwBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags, TransactCallback callback)
{
// Once a binder has died, it will never come back to life.
if (mAlive) {
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == ::android::OK && callback != nullptr) {
callback(*reply);
}
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
這里其實(shí)只可以看到這個(gè)callback其實(shí)是在 IPCThreadState::self()->transact調(diào)用后鞭执,對(duì)于的返回值都在 Parcel* reply中司顿,所以調(diào)用callback就只需要傳入*reply既可以。但是這個(gè)地方明顯好像不對(duì)是吧兄纺,和我們上面看到的多個(gè)返回值對(duì)不上大溜。
哈哈,這個(gè)我們就得看傳入的這個(gè)TransactCallback callback到底是怎么樣的估脆,如果傳入的這個(gè)方法里面有進(jìn)行對(duì)parcel進(jìn)行解析钦奋,然后再回調(diào)是不是就可行了
具體拿一個(gè)hwc中的createVirtualDisplay來(lái)看看它的源碼怎么實(shí)現(xiàn)的:
::android::hardware::Return<void> BpHwComposerClient::_hidl_createVirtualDisplay(::android::hardware::IInterface *_hidl_this, ::android::hardware::details::HidlInstrumentor *_hidl_this_instrumentor, uint32_t width, uint32_t height, ::android::hardware::graphics::common::V1_0::PixelFormat formatHint, uint32_t outputBufferSlotCount, createVirtualDisplay_cb _hidl_cb) {
//省略一部分
//這里開(kāi)始調(diào)用上面的核心BpHwBinder::transact方法,這里傳遞的TransactCallback疙赠,居然是一個(gè)lamada表達(dá)式锨苏,其實(shí)就是處理parcel返回值的一個(gè)回調(diào)方法,所以多個(gè)返回值參數(shù)的秘密都在這個(gè)lamada表達(dá)式的處理中
_hidl_transact_err = ::android::hardware::IInterface::asBinder(_hidl_this)->transact(3 /* createVirtualDisplay */, _hidl_data, &_hidl_reply, 0 /* flags */, [&] (::android::hardware::Parcel& _hidl_reply) {
::android::hardware::graphics::composer::V2_1::Error _hidl_out_error;
uint64_t _hidl_out_display;
::android::hardware::graphics::common::V1_0::PixelFormat _hidl_out_format;
_hidl_err = ::android::hardware::readFromParcel(&_hidl_status, _hidl_reply);
if (_hidl_err != ::android::OK) { return; }
if (!_hidl_status.isOk()) { return; }
_hidl_err = _hidl_reply.readInt32((int32_t *)&_hidl_out_error);
if (_hidl_err != ::android::OK) { return; }
_hidl_err = _hidl_reply.readUint64(&_hidl_out_display);
if (_hidl_err != ::android::OK) { return; }
_hidl_err = _hidl_reply.readInt32((int32_t *)&_hidl_out_format);
if (_hidl_err != ::android::OK) { return; }
//這個(gè)就是核心的回調(diào)多個(gè)返回值
_hidl_cb(_hidl_out_error, _hidl_out_display, _hidl_out_format);
});
if (_hidl_transact_err != ::android::OK) {
_hidl_err = _hidl_transact_err;
goto _hidl_error;
}
if (!_hidl_status.isOk()) { return _hidl_status; }
return ::android::hardware::Return<void>();
_hidl_error:
_hidl_status.setFromStatusT(_hidl_err);
return ::android::hardware::Return<void>(_hidl_status);
}
上面源碼一看是不是就把整個(gè) 多參數(shù)返回值原理給解密了棺聊。
歸納總結(jié)一下:
1伞租、hwbinder的跨進(jìn)程調(diào)用和binder跨進(jìn)程調(diào)用沒(méi)啥區(qū)別,都是調(diào)用了IPCThreadState::self()->transact并沒(méi)有多出啥參數(shù)
2限佩、針對(duì)genarates多參數(shù)返回葵诈,屬于BpHwBinder在接受到了返回值parcel后自己做的一個(gè)包裝解析工作
3、多參數(shù)返回其實(shí)只是自己進(jìn)程跨進(jìn)程后接收到parcel返回后祟同,自己進(jìn)行的一些加工處理返回作喘,并不是說(shuō)多參數(shù)返回值是服務(wù)器端對(duì)客戶端的跨進(jìn)程回調(diào)
服務(wù)端的多參數(shù)返回執(zhí)行
上面都是Bp端對(duì)多參數(shù)返回的一些處理分析,但在分析Bn源碼時(shí)候晕城,也發(fā)現(xiàn)Bn端也有這個(gè)多參數(shù)返回值相關(guān)的回調(diào)參數(shù)傳遞泞坦,上面不是說(shuō)了不是遠(yuǎn)端的回調(diào)嗎?怎么Bn端還需要有這個(gè)砖顷,這里也來(lái)解密一下:
system/libhwbinder/IPCThreadState.cpp
status_t IPCThreadState::executeCommand(int32_t cmd)
{
case BR_TRANSACTION_SEC_CTX:
case BR_TRANSACTION:
{
auto reply_callback = [&] (auto &replyParcel) {
if (reply_sent) {
// Reply was sent earlier, ignore it.
ALOGE("Dropping binder reply, it was sent already.");
return;
}
reply_sent = true;
if ((tr.flags & TF_ONE_WAY) == 0) {
replyParcel.setError(NO_ERROR);
sendReply(replyParcel, (tr.flags & kForwardReplyFlags));
} else {
ALOGE("Not sending reply in one-way transaction");
}
};
if (tr.target.ptr) {
if (reinterpret_cast<RefBase::weakref_type*>(
tr.target.ptr)->attemptIncStrong(this)) {
//這里進(jìn)行BHwBinder::transact調(diào)用贰锁,注意這里面?zhèn)鬟f了reply_callback,reply_callback就上面定義的lamada表達(dá)式
error = reinterpret_cast<BHwBinder*>(tr.cookie)->transact(tr.code, buffer,
&reply, tr.flags, reply_callback);
reinterpret_cast<BHwBinder*>(tr.cookie)->decStrong(this);
} else {
error = UNKNOWN_TRANSACTION;
}
} else {
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags, reply_callback);
}
if ((tr.flags & TF_ONE_WAY) == 0) {
if (!reply_sent) {//一般變成了true滤蝠,因?yàn)樯厦嬗谢卣{(diào)情況
// Should have been a reply but there wasn't, so there
// must have been an error instead.
reply.setError(error);
sendReply(reply, (tr.flags & kForwardReplyFlags));
} else {
if (error != NO_ERROR) {
ALOGE("transact() returned error after sending reply.");
} else {
// Ok, reply sent and transact didn't return an error.
}
}
} else {
// One-way transaction, don't care about return value or reply.
}
}
break;
return result;
}
system/libhwbinder/Binder.cpp
status_t BHwBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags, TransactCallback callback)
{
data.setDataPosition(0);
//這里的核心是調(diào)用onTransact方法豌熄,注意這里也有一個(gè)lamada表達(dá)式傳遞進(jìn)去了
return onTransact(code, data, reply, flags, [&](auto& replyParcel) {
replyParcel.setDataPosition(0);
if (callback != nullptr) {
//這里callback其實(shí)就是執(zhí)行一下上面的IPCThreadState的reply_callback,其實(shí)reply_callback里面沒(méi)有干啥核心事情物咳,就是調(diào)用了sendReply
callback(replyParcel);
}
});
}
來(lái)看看hidl對(duì)于的Bn代碼
::android::status_t BnHwComposerClient::onTransact(
uint32_t _hidl_code,
const ::android::hardware::Parcel &_hidl_data,
::android::hardware::Parcel *_hidl_reply,
uint32_t _hidl_flags,
TransactCallback _hidl_cb) {
::android::status_t _hidl_err = ::android::OK;
switch (_hidl_code) {
case 3 /* createVirtualDisplay */:
{
//調(diào)用到了_hidl_createVirtualDisplay有這個(gè)_hidl_cb
_hidl_err = ::android::hardware::graphics::composer::V2_1::BnHwComposerClient::_hidl_createVirtualDisplay(this, _hidl_data, _hidl_reply, _hidl_cb);
break;
}
}
//_hidl_createVirtualDisplay實(shí)現(xiàn)
::android::status_t BnHwComposerClient::_hidl_createVirtualDisplay(
::android::hidl::base::V1_0::BnHwBase* _hidl_this,
const ::android::hardware::Parcel &_hidl_data,
::android::hardware::Parcel *_hidl_reply,
TransactCallback _hidl_cb) {
bool _hidl_callbackCalled = false;
//注意這里調(diào)用實(shí)現(xiàn)時(shí)候最后一個(gè)參數(shù)就是一個(gè)多個(gè)返回值參數(shù)的lamada表達(dá)是锣险,讓實(shí)現(xiàn)里面吧多個(gè)返回值回調(diào)這個(gè)lamada
::android::hardware::Return<void> _hidl_ret = static_cast<IComposerClient*>(_hidl_this->getImpl().get())->createVirtualDisplay(width, height, formatHint, outputBufferSlotCount, [&](const auto &_hidl_out_error, const auto &_hidl_out_display, const auto &_hidl_out_format) {
_hidl_callbackCalled = true;
::android::hardware::writeToParcel(::android::hardware::Status::ok(), _hidl_reply);
//這里會(huì)_hidl_reply進(jìn)行寫(xiě)入對(duì)于的多個(gè)返回值參數(shù)
_hidl_err = _hidl_reply->writeInt32((int32_t)_hidl_out_error);
if (_hidl_err != ::android::OK) { goto _hidl_error; }
_hidl_err = _hidl_reply->writeUint64(_hidl_out_display);
if (_hidl_err != ::android::OK) { goto _hidl_error; }
_hidl_err = _hidl_reply->writeInt32((int32_t)_hidl_out_format);
if (_hidl_err != ::android::OK) { goto _hidl_error; }
if (_hidl_err != ::android::OK) { return; }
//最后裝好多個(gè)返回值數(shù)據(jù)的parcel進(jìn)行回調(diào)并且?guī)蟨arcel
_hidl_cb(*_hidl_reply);
});
_hidl_ret.assertOk();
if (!_hidl_callbackCalled) {
LOG_ALWAYS_FATAL("createVirtualDisplay: _hidl_cb not called, but must be called once.");
}
return _hidl_err;
}
下面再看看具體實(shí)現(xiàn)static_cast<IComposerClient*>(_hidl_this->getImpl().get())里面的實(shí)現(xiàn):
hardware/interfaces/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h
Return<void> createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat formatHint,
uint32_t outputBufferSlotCount,
IComposerClient::createVirtualDisplay_cb hidl_cb) override {
Display display = 0;
Error err = mHal->createVirtualDisplay(width, height, &formatHint, &display);
if (err == Error::NONE) {
mResources->addVirtualDisplay(display, outputBufferSlotCount);
}
//這里是最開(kāi)始的多參數(shù)回調(diào)
hidl_cb(err, display, formatHint);
return Void();
}
IComposerClient::createVirtualDisplay_cb 其實(shí)也是工具生成的,路徑如下:
/android.hardware.graphics.composer@2.1_genc++_headers/gen/android/hardware/graphics/composer/2.1/IComposerClient.h
using createVirtualDisplay_cb = std::function<void(::android::hardware::graphics::composer::V2_1::Error error, uint64_t display, ::android::hardware::graphics::common::V1_0::PixelFormat format)>
好了上面基本上就清楚了整個(gè)hidl多參數(shù)返回的原理览闰,從bp端到bn端都進(jìn)行了詳細(xì)原理剖析芯肤。
更多framework干貨課程如下(需要的可以私聊馬哥 獲取優(yōu)惠 +V :androidframework007):