Add (un)linkToDeath to generated interfaces.
(un)linkToDeath is now a part of IBase, and can be
called on any generated HIDL interface. The implementation
is a no-op, except in proxy objects, which are by
definition a different process than the interface they point
to.
Since clients are not aware of the transport implementation, we must
wrap the transport-independent callback in a transport-specific
callback object. In case of binder, that object is a
hidl_binder_death_recipient.
The binder proxy object contains a list of registered death
recipients, as well as a mutex to protect access to the list.
The list is required to allow us to map back transport-independent
callbacks to transport-dependent callbacks in unlinkToDeath().
Bug: 31632518
Test: mma, hidl_test
Change-Id: I5083a8789dd706a886a8a09f8c733031a351a36a
diff --git a/Android.bp b/Android.bp
index 8eae5b5..7f32fcd 100644
--- a/Android.bp
+++ b/Android.bp
@@ -33,6 +33,7 @@
"ArrayType.cpp",
"CompoundType.cpp",
"ConstantExpression.cpp",
+ "DeathRecipientType.cpp",
"EnumType.cpp",
"FQName.cpp",
"HandleType.cpp",
diff --git a/DeathRecipientType.cpp b/DeathRecipientType.cpp
new file mode 100644
index 0000000..952064c
--- /dev/null
+++ b/DeathRecipientType.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+#include "DeathRecipientType.h"
+
+#include <hidl-util/Formatter.h>
+#include <android-base/logging.h>
+
+namespace android {
+
+DeathRecipientType::DeathRecipientType() {}
+
+void DeathRecipientType::addNamedTypesToSet(std::set<const FQName> &) const {
+ // do nothing
+}
+
+std::string DeathRecipientType::getCppType(StorageMode mode,
+ bool specifyNamespaces) const {
+ const std::string base =
+ std::string(specifyNamespaces ? "::android::" : "")
+ + "sp<"
+ + (specifyNamespaces ? "::android::hardware::" : "")
+ + "hidl_death_recipient>";
+
+ switch (mode) {
+ case StorageMode_Stack:
+ return base;
+
+ case StorageMode_Argument:
+ return "const " + base + "&";
+
+ case StorageMode_Result:
+ return "const " + base + "*";
+ }
+}
+
+std::string DeathRecipientType::getJavaType(bool /* forInitializer */) const {
+ return "android.os.IBinder.DeathRecipient";
+}
+
+std::string DeathRecipientType::getVtsType() const {
+ return "TYPE_DEATH_RECIPIENT";
+}
+
+void DeathRecipientType::emitReaderWriter(
+ Formatter& out,
+ const std::string& /* name */,
+ const std::string& /* parcelObj */,
+ bool /* parcelObjIsPointer */,
+ bool /* isReader */,
+ ErrorMode /* mode */) const {
+ out << "LOG_ALWAYS_FATAL(\"DeathRecipient is only supported in passthrough mode\");\n";
+}
+
+bool DeathRecipientType::needsEmbeddedReadWrite() const {
+ return false;
+}
+
+bool DeathRecipientType::resultNeedsDeref() const {
+ return true;
+}
+
+bool DeathRecipientType::isJavaCompatible() const {
+ return true;
+}
+
+void DeathRecipientType::getAlignmentAndSize(size_t *align, size_t *size) const {
+ *align = *size = 0; // this object should only be used in passthrough mode
+}
+
+status_t DeathRecipientType::emitVtsTypeDeclarations(Formatter &out) const {
+ out << "type: " << getVtsType() << "\n";
+ return OK;
+}
+
+} // namespace android
+
diff --git a/DeathRecipientType.h b/DeathRecipientType.h
new file mode 100644
index 0000000..f0e9b6f
--- /dev/null
+++ b/DeathRecipientType.h
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#ifndef DEATH_RECIPIENT_TYPE_H_
+
+#define DEATH_RECIPIENT_TYPE_H_
+
+#include "Type.h"
+
+namespace android {
+
+struct DeathRecipientType : public Type {
+ DeathRecipientType();
+
+ void addNamedTypesToSet(std::set<const FQName> &set) const override;
+
+ std::string getCppType(
+ StorageMode mode,
+ bool specifyNamespaces) const override;
+
+ std::string getJavaType(bool forInitializer) const override;
+
+ std::string getVtsType() const override;
+
+ void emitReaderWriter(
+ Formatter &out,
+ const std::string &name,
+ const std::string &parcelObj,
+ bool parcelObjIsPointer,
+ bool isReader,
+ ErrorMode mode) const override;
+
+ bool needsEmbeddedReadWrite() const override;
+ bool resultNeedsDeref() const override;
+
+ bool isJavaCompatible() const override;
+
+ void getAlignmentAndSize(size_t *align, size_t *size) const override;
+
+ status_t emitVtsTypeDeclarations(Formatter &out) const override;
+};
+
+} // namespace android
+
+#endif // DEATH_RECIPIENT_TYPE_H_
+
diff --git a/Interface.cpp b/Interface.cpp
index 602b221..29afee1 100644
--- a/Interface.cpp
+++ b/Interface.cpp
@@ -17,7 +17,9 @@
#include "Interface.h"
#include "Annotation.h"
+#include "DeathRecipientType.h"
#include "Method.h"
+#include "ScalarType.h"
#include "StringType.h"
#include "VectorType.h"
@@ -46,6 +48,8 @@
FIRST_HIDL_TRANSACTION = 0x00f00000,
HIDL_DESCRIPTOR_CHAIN_TRANSACTION = FIRST_HIDL_TRANSACTION,
HIDL_SYSPROPS_CHANGED_TRANSACTION,
+ HIDL_LINK_TO_DEATH_TRANSACTION,
+ HIDL_UNLINK_TO_DEATH_TRANSACTION,
LAST_HIDL_TRANSACTION = 0x00ffffff,
};
@@ -55,12 +59,132 @@
mIsJavaCompatibleInProgress(false) {
mReservedMethods.push_back(createDescriptorChainMethod());
mReservedMethods.push_back(createSyspropsChangedMethod());
+ mReservedMethods.push_back(createLinkToDeathMethod());
+ mReservedMethods.push_back(createUnlinkToDeathMethod());
}
std::string Interface::typeName() const {
return "interface " + localName();
}
+Method *Interface::createLinkToDeathMethod() const {
+ auto *results = new std::vector<TypedVar *> {
+ new TypedVar("success", new ScalarType(ScalarType::KIND_BOOL)) };
+ auto *args = new std::vector<TypedVar *> {
+ new TypedVar("recipient", new DeathRecipientType()),
+ new TypedVar("cookie", new ScalarType(ScalarType::KIND_UINT64)) };
+
+ return new Method("linkToDeath",
+ args,
+ results,
+ false /*oneway */,
+ new std::vector<Annotation *>(),
+ HIDL_LINK_TO_DEATH_TRANSACTION,
+ {
+ {IMPL_HEADER,
+ [](auto &out) {
+ out << "(void)cookie;\n"
+ << "return (recipient != nullptr);\n";
+ }
+ },
+ {IMPL_PROXY,
+ [](auto &out) {
+ out << "::android::hardware::hidl_binder_death_recipient *binder_recipient"
+ << " = new ::android::hardware::hidl_binder_death_recipient(recipient, cookie, this);\n"
+ << "std::unique_lock<std::mutex> lock(_hidl_mMutex);\n"
+ << "_hidl_mDeathRecipients.push_back(binder_recipient);\n"
+ << "return (remote()->linkToDeath(binder_recipient)"
+ << " == ::android::OK);\n";
+ }
+ },
+ {IMPL_STUB,
+ [](auto &/*out*/) {
+ // Do nothing
+ }
+ }
+ }, /*cppImpl*/
+ {
+ {IMPL_HEADER,
+ [this](auto &out) {
+ out << "return true;";
+ }
+ },
+ {IMPL_PROXY,
+ [this](auto &out) {
+ // TODO (b/31632518)
+ out << "return false;";
+ }
+ },
+ {IMPL_STUB,
+ [this](auto &/*out*/) {
+ // Do nothing
+ }
+ }
+ } /*javaImpl*/
+ );
+}
+
+Method *Interface::createUnlinkToDeathMethod() const {
+ auto *results = new std::vector<TypedVar *> {
+ new TypedVar("success", new ScalarType(ScalarType::KIND_BOOL)) };
+ auto *args = new std::vector<TypedVar *> {
+ new TypedVar("recipient", new DeathRecipientType()) };
+
+ return new Method("unlinkToDeath",
+ args,
+ results,
+ false /*oneway */,
+ new std::vector<Annotation *>(),
+ HIDL_UNLINK_TO_DEATH_TRANSACTION,
+ {
+ {IMPL_HEADER,
+ [](auto &out) {
+ out << "return (recipient != nullptr);\n";
+ }
+ },
+ {IMPL_PROXY,
+ [](auto &out) {
+ out << "std::unique_lock<std::mutex> lock(_hidl_mMutex);\n"
+ << "for (auto it = _hidl_mDeathRecipients.begin();"
+ << "it != _hidl_mDeathRecipients.end();"
+ << "++it) {\n";
+ out.indent([&] {
+ out.sIf("(*it)->getRecipient() == recipient", [&] {
+ out << "::android::status_t status = remote()->unlinkToDeath(*it);\n"
+ << "_hidl_mDeathRecipients.erase(it);\n"
+ << "return status == ::android::OK;\n";
+ });
+ });
+ out << "}\n";
+ out << "return false;\n";
+ }
+ },
+ {IMPL_STUB,
+ [](auto &/*out*/) {
+ // Do nothing
+ }
+ }
+ }, /*cppImpl*/
+ {
+ {IMPL_HEADER,
+ [this](auto &out) {
+ out << "return true;";
+ }
+ },
+ {IMPL_PROXY,
+ [this](auto &out) {
+ // TODO (b/31632518)
+ out << "return false;";
+ }
+ },
+ {IMPL_STUB,
+ [this](auto &/*out*/) {
+ // Do nothing
+ }
+ }
+ } /*javaImpl*/
+ );
+}
Method *Interface::createSyspropsChangedMethod() const {
return new Method("notifySyspropsChanged",
new std::vector<TypedVar *>() /*args */,
@@ -68,13 +192,13 @@
true /*oneway */,
new std::vector<Annotation *>(),
HIDL_SYSPROPS_CHANGED_TRANSACTION,
- [this](auto &out) { /*cppImpl */
+ { { IMPL_HEADER, [this](auto &out) {
out << "::android::report_sysprop_change();\n";
out << "return ::android::hardware::Void();";
- },
- [this](auto &out) { /* javaImpl */
+ } } }, /*cppImpl */
+ { { IMPL_HEADER, [](auto &out) { /* javaImpl */
out << "android.os.SystemProperties.reportSyspropChanged();";
- }
+ } } } /*javaImpl */
);
}
@@ -90,7 +214,7 @@
false /* oneway */,
new std::vector<Annotation *>(),
HIDL_DESCRIPTOR_CHAIN_TRANSACTION,
- [this](auto &out) { /* cppImpl */
+ { { IMPL_HEADER, [this](auto &out) {
std::vector<const Interface *> chain = typeChain();
out << "_hidl_cb(";
out.block([&] {
@@ -100,8 +224,8 @@
});
out << ");\n";
out << "return ::android::hardware::Void();";
- },
- [this](auto &out) { /* javaImpl */
+ } } }, /* cppImpl */
+ { { IMPL_HEADER, [this](auto &out) {
std::vector<const Interface *> chain = typeChain();
out << "return new java.util.ArrayList<String>(java.util.Arrays.asList(\n";
out.indent(); out.indent();
@@ -112,7 +236,8 @@
}
out << "));";
out.unindent(); out.unindent();
- });
+ } } } /* javaImpl */
+ );
}
diff --git a/Interface.h b/Interface.h
index a21a036..8542f18 100644
--- a/Interface.h
+++ b/Interface.h
@@ -106,6 +106,8 @@
mutable bool mIsJavaCompatibleInProgress;
Method *createDescriptorChainMethod() const;
Method *createSyspropsChangedMethod() const;
+ Method *createLinkToDeathMethod() const;
+ Method *createUnlinkToDeathMethod() const;
DISALLOW_COPY_AND_ASSIGN(Interface);
};
diff --git a/Method.cpp b/Method.cpp
index bfd28c9..a085497 100644
--- a/Method.cpp
+++ b/Method.cpp
@@ -71,20 +71,32 @@
return *mAnnotations;
}
-void Method::cppImpl(Formatter &out) const {
+void Method::cppImpl(MethodImplType type, Formatter &out) const {
CHECK(mIsHidlReserved);
- if (mCppImpl) {
- mCppImpl(out);
+ auto it = mCppImpl.find(type);
+ if (it != mCppImpl.end()) {
+ it->second(out);
}
}
-void Method::javaImpl(Formatter &out) const {
+void Method::javaImpl(MethodImplType type, Formatter &out) const {
CHECK(mIsHidlReserved);
- if (mJavaImpl) {
- mJavaImpl(out);
+ auto it = mJavaImpl.find(type);
+ if (it != mJavaImpl.end()) {
+ it->second(out);
}
}
+bool Method::overridesCppImpl(MethodImplType type) const {
+ CHECK(mIsHidlReserved);
+ return mCppImpl.find(type) != mCppImpl.end();
+}
+
+bool Method::overridesJavaImpl(MethodImplType type) const {
+ CHECK(mIsHidlReserved);
+ return mJavaImpl.find(type) != mJavaImpl.end();
+}
+
void Method::setSerialId(size_t serial) {
CHECK(!mIsHidlReserved);
mSerial = serial;
diff --git a/Method.h b/Method.h
index 6981b72..ac681a5 100644
--- a/Method.h
+++ b/Method.h
@@ -21,6 +21,7 @@
#include <android-base/macros.h>
#include <functional>
#include <hidl-util/Formatter.h>
+#include <map>
#include <set>
#include <string>
#include <vector>
@@ -34,7 +35,13 @@
struct TypedVar;
struct TypedVarVector;
-using MethodImpl = std::function<void(Formatter &)>;
+enum MethodImplType {
+ IMPL_HEADER,
+ IMPL_PROXY,
+ IMPL_STUB
+};
+
+using MethodImpl = std::map<MethodImplType, std::function<void(Formatter &)>>;
struct Method {
Method(const char *name,
@@ -55,8 +62,10 @@
const std::vector<TypedVar *> &args() const;
const std::vector<TypedVar *> &results() const;
bool isOneway() const { return mOneway; }
- void cppImpl(Formatter &out) const;
- void javaImpl(Formatter &out) const;
+ bool overridesCppImpl(MethodImplType type) const;
+ bool overridesJavaImpl(MethodImplType type) const;
+ void cppImpl(MethodImplType type, Formatter &out) const;
+ void javaImpl(MethodImplType type, Formatter &out) const;
bool isHidlReserved() const { return mIsHidlReserved; }
const std::vector<Annotation *> &annotations() const;
@@ -86,10 +95,10 @@
std::vector<Annotation *> *mAnnotations;
bool mIsHidlReserved = false;
- // The following fields has no meaning if mIsHidlReserved is false.
+ // The following fields have no meaning if mIsHidlReserved is false.
// hard-coded implementation for HIDL reserved methods.
- MethodImpl mCppImpl = nullptr;
- MethodImpl mJavaImpl = nullptr;
+ MethodImpl mCppImpl;
+ MethodImpl mJavaImpl;
DISALLOW_COPY_AND_ASSIGN(Method);
};
diff --git a/generateCpp.cpp b/generateCpp.cpp
index 7ae94b0..04e8f0b 100644
--- a/generateCpp.cpp
+++ b/generateCpp.cpp
@@ -392,7 +392,7 @@
}
out << " {\n";
out.indent();
- method->cppImpl(out);
+ method->cppImpl(IMPL_HEADER, out);
out.unindent();
out << "\n}\n";
} else {
@@ -829,6 +829,8 @@
out << "#ifndef " << guard << "\n";
out << "#define " << guard << "\n\n";
+ out << "#include <hidl/HidlTransportSupport.h>\n\n";
+
std::vector<std::string> packageComponents;
getPackageAndVersionComponents(
&packageComponents, false /* cpp_compatible */);
@@ -866,6 +868,12 @@
}
out.unindent();
+ out << "private:\n";
+ out.indent();
+ out << "std::mutex _hidl_mMutex;\n"
+ << "std::vector<::android::sp<::android::hardware::hidl_binder_death_recipient>>"
+ << " _hidl_mDeathRecipients;\n";
+ out.unindent();
out << "};\n\n";
enterLeaveNamespace(out, false /* enter */);
@@ -1117,6 +1125,13 @@
out.indent();
+ if (method->isHidlReserved() && method->overridesCppImpl(IMPL_PROXY)) {
+ method->cppImpl(IMPL_PROXY, out);
+ out.unindent();
+ out << "}\n\n";
+ return OK;
+ }
+
if (returnsValue && elidedReturn == nullptr) {
generateCheckNonNull(out, "_hidl_cb");
}
@@ -1431,6 +1446,12 @@
status_t AST::generateStubSourceForMethod(
Formatter &out, const Interface *iface, const Method *method) const {
+ if (method->isHidlReserved() && method->overridesCppImpl(IMPL_STUB)) {
+ method->cppImpl(IMPL_STUB, out);
+ out << "break;\n";
+ return OK;
+ }
+
out << "if (!_hidl_data.enforceInterface(";
out << iface->fqName().cppNamespace()
diff --git a/generateJava.cpp b/generateJava.cpp
index 6faf52d..70ee23e 100644
--- a/generateJava.cpp
+++ b/generateJava.cpp
@@ -315,6 +315,12 @@
out << ") {\n";
out.indent();
+ if (method->isHidlReserved() && method->overridesJavaImpl(IMPL_PROXY)) {
+ method->javaImpl(IMPL_PROXY, out);
+ out.unindent();
+ out << "}\n";
+ continue;
+ }
out << "android.os.HwParcel _hidl_request = new android.os.HwParcel();\n";
out << "_hidl_request.writeInterfaceToken("
<< superInterface->fullJavaName()
@@ -414,9 +420,12 @@
<< resultType
<< " "
<< method->name()
- << "() {\n";
+ << "("
+ << Method::GetJavaArgSignature(method->args())
+ << ") {\n";
+
out.indent();
- method->javaImpl(out);
+ method->javaImpl(IMPL_HEADER, out);
out.unindent();
out << "\n}\n\n";
}
@@ -466,6 +475,13 @@
<< " */:\n{\n";
out.indent();
+ if (method->isHidlReserved() && method->overridesJavaImpl(IMPL_STUB)) {
+ method->javaImpl(IMPL_STUB, out);
+ out.unindent();
+ out << "break;\n";
+ out << "}\n\n";
+ continue;
+ }
out << "_hidl_request.enforceInterface("
<< superInterface->fullJavaName()
diff --git a/hidl-gen_l.ll b/hidl-gen_l.ll
index a65bc9f..e6b4bef 100644
--- a/hidl-gen_l.ll
+++ b/hidl-gen_l.ll
@@ -34,6 +34,7 @@
#include "ArrayType.h"
#include "CompoundType.h"
#include "ConstantExpression.h"
+#include "DeathRecipientType.h"
#include "EnumType.h"
#include "HandleType.h"
#include "MemoryType.h"
@@ -111,6 +112,7 @@
"float" { SCALAR_TYPE(KIND_FLOAT); }
"double" { SCALAR_TYPE(KIND_DOUBLE); }
+"death_recipient" { yylval->type = new DeathRecipientType; return token::TYPE; }
"handle" { yylval->type = new HandleType; return token::TYPE; }
"memory" { yylval->type = new MemoryType; return token::TYPE; }
"pointer" { yylval->type = new PointerType; return token::TYPE; }
diff --git a/hidl-gen_y.yy b/hidl-gen_y.yy
index 9c0e75b..75843c5 100644
--- a/hidl-gen_y.yy
+++ b/hidl-gen_y.yy
@@ -59,8 +59,8 @@
// Inherited names by interfaces from IInterface / IBinder
"onAsBinder", "asBinder", "queryLocalInterface", "getInterfaceDescriptor", "isBinderAlive",
- "pingBinder", "dump", "transact", "linkToDeath", "unlinkToDeath", "checkSubclass",
- "attachObject", "findObject", "detachObject", "localBinder", "remoteBinder", "mImpl",
+ "pingBinder", "dump", "transact", "checkSubclass", "attachObject", "findObject",
+ "detachObject", "localBinder", "remoteBinder", "mImpl",
});
std::string idstr(identifier);
if (std::find(reserved.begin(), reserved.end(), idstr) != reserved.end()) {
diff --git a/test/main.cpp b/test/main.cpp
index 66b3f34..fb0e773 100644
--- a/test/main.cpp
+++ b/test/main.cpp
@@ -97,14 +97,17 @@
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_death_recipient;
using ::android::hardware::hidl_memory;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
+using ::android::hidl::base::V1_0::IBase;
using ::android::hidl::manager::V1_0::IServiceManager;
using ::android::hidl::manager::V1_0::IServiceNotification;
using ::android::hidl::memory::V1_0::IAllocator;
using ::android::hidl::memory::V1_0::IMemory;
using ::android::sp;
+using ::android::wp;
using ::android::to_string;
using ::android::Mutex;
using ::android::MultiDimensionalToString;
@@ -318,6 +321,7 @@
sp<IMemoryTest> memoryTest;
sp<IFetcher> fetcher;
sp<IFoo> foo;
+ sp<IFoo> dyingFoo;
sp<IBar> bar;
sp<IFooCallback> fooCb;
sp<IGraph> graphInterface;
@@ -358,6 +362,10 @@
ASSERT_NE(foo, nullptr);
ASSERT_EQ(foo->isRemote(), gMode == BINDERIZED);
+ dyingFoo = IFoo::getService("dyingFoo", gMode == PASSTHROUGH /* getStub */);
+ ASSERT_NE(foo, nullptr);
+ ASSERT_EQ(foo->isRemote(), gMode == BINDERIZED);
+
bar = IBar::getService("foo", gMode == PASSTHROUGH /* getStub */);
ASSERT_NE(bar, nullptr);
ASSERT_EQ(bar->isRemote(), gMode == BINDERIZED);
@@ -379,13 +387,21 @@
ASSERT_NE(validationPointerInterface, nullptr);
}
+ void killServer(const char *serverName) {
+ for (const auto &pair : mPids) {
+ if (pair.first == serverName) {
+ ::killServer(pair.second, pair.first.c_str());
+ }
+ }
+ }
+
virtual void TearDown() {
// clean up by killing server processes.
ALOGI("Environment tear-down beginning...");
ALOGI("Killing servers...");
size_t i = 0;
for (const auto &pair : mPids) {
- killServer(pair.second, pair.first.c_str());
+ ::killServer(pair.second, pair.first.c_str());
}
ALOGI("Servers all killed.");
ALOGI("Environment tear-down complete.");
@@ -417,6 +433,7 @@
addServer<IParent>("parent");
addServer<IFetcher>("fetcher");
addServer<IBar>("foo");
+ addServer<IFoo>("dyingFoo");
addServer<IFooCallback>("foo callback");
addServer<IGraph>("graph");
addServer<IPointer>("pointer");
@@ -434,12 +451,23 @@
sp<IMemoryTest> memoryTest;
sp<IFetcher> fetcher;
sp<IFoo> foo;
+ sp<IFoo> dyingFoo;
sp<IBar> bar;
sp<IFooCallback> fooCb;
sp<IGraph> graphInterface;
sp<IPointer> pointerInterface;
sp<IPointer> validationPointerInterface;
+ void killServer(const char *serverName) {
+ HidlEnvironmentBase *env;
+ if (gMode == BINDERIZED) {
+ env = gBinderizedEnvironment;
+ } else {
+ env = gPassthroughEnvironment;
+ }
+ env->killServer(serverName);
+ }
+
virtual void SetUp() override {
ALOGI("Test setup beginning...");
HidlEnvironmentBase *env;
@@ -453,6 +481,7 @@
memoryTest = env->memoryTest;
fetcher = env->fetcher;
foo = env->foo;
+ dyingFoo = env->dyingFoo;
bar = env->bar;
fooCb = env->fooCb;
graphInterface = env->graphInterface;
@@ -1154,6 +1183,65 @@
EXPECT_OK(foo->closeHandles());
}
+struct HidlDeathRecipient : hidl_death_recipient {
+ std::mutex mutex;
+ std::condition_variable condition;
+ wp<IBase> who;
+ bool fired = false;
+ uint64_t cookie = 0;
+
+ virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) {
+ std::unique_lock<std::mutex> lock(mutex);
+ fired = true;
+ this->cookie = cookie;
+ this->who = who;
+ condition.notify_one();
+ };
+};
+
+TEST_F(HidlTest, DeathRecipientTest) {
+ // Need a threadpool to receive death calls from the kernel
+ ProcessState::self()->setThreadPoolMaxThreadCount(0);
+ ProcessState::self()->startThreadPool();
+
+ sp<HidlDeathRecipient> recipient = new HidlDeathRecipient();
+ sp<HidlDeathRecipient> recipient2 = new HidlDeathRecipient();
+
+ EXPECT_TRUE(dyingFoo->linkToDeath(recipient, 0x1481));
+ EXPECT_TRUE(dyingFoo->linkToDeath(recipient2, 0x2592));
+ EXPECT_TRUE(dyingFoo->unlinkToDeath(recipient2));
+
+ if (gMode != BINDERIZED) {
+ // Passthrough doesn't fire, nor does it keep state of
+ // registered death recipients (so it won't fail unlinking
+ // the same recipient twice).
+ return;
+ }
+
+ EXPECT_FALSE(dyingFoo->unlinkToDeath(recipient2));
+ killServer("dyingFoo");
+
+ std::unique_lock<std::mutex> lock(recipient->mutex);
+ recipient->condition.wait_for(lock, std::chrono::milliseconds(1000), [&recipient]() {
+ return recipient->fired;
+ });
+ EXPECT_TRUE(recipient->fired);
+ EXPECT_EQ(recipient->cookie, 0x1481u);
+ EXPECT_EQ(recipient->who, dyingFoo);
+ std::unique_lock<std::mutex> lock2(recipient2->mutex);
+ recipient2->condition.wait_for(lock2, std::chrono::milliseconds(1000), [&recipient2]() {
+ return recipient2->fired;
+ });
+ EXPECT_FALSE(recipient2->fired);
+
+ // Verify servicemanager dropped its reference too
+ sp<IFoo> deadFoo = IFoo::getService("dyingFoo", false);
+ if (deadFoo != nullptr) {
+ // Got a passthrough
+ EXPECT_FALSE(deadFoo->isRemote());
+ }
+}
+
TEST_F(HidlTest, BarThisIsNewTest) {
// Now the tricky part, get access to the derived interface.
ALOGI("CLIENT call thisIsNew.");