Move getService into libhidl.
This function is huge! By moving it out of auto-generated
code, we can do a couple of things:
- decrease the amount of space it takes (no longer not 'all'
templated).
- make it easier to fix bugs like b/67425500
Bug: 67425500
Test: hidl_test, hidl_test_java
Change-Id: Ic8eb93d82e7bf8a6730d14109a36828bfe9d468a
diff --git a/transport/Android.bp b/transport/Android.bp
index 421c7a4..dbbbdaf 100644
--- a/transport/Android.bp
+++ b/transport/Android.bp
@@ -80,5 +80,8 @@
debuggable: {
cflags: ["-DLIBHIDL_TARGET_DEBUGGABLE"],
},
+ treble: {
+ cflags: ["-DLIBHIDL_TARGET_TREBLE"]
+ },
},
}
diff --git a/transport/HidlTransportSupport.cpp b/transport/HidlTransportSupport.cpp
index ea2e32c..0d2f1bf 100644
--- a/transport/HidlTransportSupport.cpp
+++ b/transport/HidlTransportSupport.cpp
@@ -14,7 +14,10 @@
* limitations under the License.
*/
#include <hidl/HidlTransportSupport.h>
+
+#include <android/hidl/manager/1.0/IServiceManager.h>
#include <hidl/HidlBinderSupport.h>
+#include <hidl/ServiceManagement.h>
namespace android {
namespace hardware {
@@ -53,5 +56,116 @@
return true;
}
+namespace details {
+
+sp<::android::hidl::base::V1_0::IBase> getRawServiceInternal(const std::string& descriptor,
+ const std::string& instance,
+ bool retry, bool getStub) {
+ using Transport = ::android::hidl::manager::V1_0::IServiceManager::Transport;
+ using ::android::hidl::base::V1_0::IBase;
+ using ::android::hidl::manager::V1_0::IServiceManager;
+
+ const sp<IServiceManager> sm = defaultServiceManager();
+ if (sm == nullptr) {
+ ALOGE("getService: defaultServiceManager() is null");
+ return nullptr;
+ }
+
+ Return<Transport> transportRet = sm->getTransport(descriptor, instance);
+
+ if (!transportRet.isOk()) {
+ ALOGE("getService: defaultServiceManager()->getTransport returns %s",
+ transportRet.description().c_str());
+ return nullptr;
+ }
+ Transport transport = transportRet;
+ const bool vintfHwbinder = (transport == Transport::HWBINDER);
+ const bool vintfPassthru = (transport == Transport::PASSTHROUGH);
+
+#ifdef LIBHIDL_TARGET_TREBLE
+
+#ifdef LIBHIDL_TARGET_DEBUGGABLE
+ const char* env = std::getenv("TREBLE_TESTING_OVERRIDE");
+ const bool trebleTestingOverride = env && !strcmp(env, "true");
+ const bool vintfLegacy = (transport == Transport::EMPTY) && trebleTestingOverride;
+#else // LIBHIDL_TARGET_TREBLE but not LIBHIDL_TARGET_DEBUGGABLE
+ const bool trebleTestingOverride = false;
+ const bool vintfLegacy = false;
+#endif // LIBHIDL_TARGET_DEBUGGABLE
+
+#else // not LIBHIDL_TARGET_TREBLE
+ const char* env = std::getenv("TREBLE_TESTING_OVERRIDE");
+ const bool trebleTestingOverride = env && !strcmp(env, "true");
+ const bool vintfLegacy = (transport == Transport::EMPTY);
+#endif // LIBHIDL_TARGET_TREBLE
+
+ for (int tries = 0;
+ !getStub && (vintfHwbinder || (vintfLegacy && tries == 0)) && (retry || tries < 1);
+ tries++) {
+ if (tries > 1) {
+ ALOGI("getService: Will do try %d for %s/%s in 1s...", tries, descriptor.c_str(),
+ instance.c_str());
+ sleep(1); // TODO(b/67425500): remove and update waitForHwService function
+ }
+ if (vintfHwbinder && tries > 0) {
+ waitForHwService(descriptor, instance);
+ }
+ Return<sp<IBase>> ret = sm->get(descriptor, instance);
+ if (!ret.isOk()) {
+ ALOGE("getService: defaultServiceManager()->get returns %s for %s/%s.",
+ ret.description().c_str(), descriptor.c_str(), instance.c_str());
+ break;
+ }
+ sp<IBase> base = ret;
+ if (base == nullptr) {
+ if (tries > 0) {
+ ALOGW("getService: found unexpected null hwbinder interface for %s/%s.",
+ descriptor.c_str(), instance.c_str());
+ }
+ continue;
+ }
+
+ Return<bool> canCastRet =
+ details::canCastInterface(base.get(), descriptor.c_str(), true /* emitError */);
+
+ if (!canCastRet.isOk()) {
+ if (canCastRet.isDeadObject()) {
+ ALOGW("getService: found dead hwbinder service for %s/%s.", descriptor.c_str(),
+ instance.c_str());
+ continue;
+ }
+ // TODO(b/67425500): breaks getService == nullptr => hal available assumptions if the
+ // service has a transaction failure (one example of this is if the service's binder
+ // buffer is full). If this isn't here, you get an infinite loop when you don't have
+ // permission to talk to a service.
+ ALOGW("getService: unable to call into hwbinder service for %s/%s.", descriptor.c_str(),
+ instance.c_str());
+ break;
+ }
+
+ if (!canCastRet) {
+ ALOGW("getService: received incompatible service (bug in hwservicemanager?) for %s/%s.",
+ descriptor.c_str(), instance.c_str());
+ break;
+ }
+
+ return base; // still needs to be wrapped by Bp class.
+ }
+
+ if (getStub || vintfPassthru || vintfLegacy) {
+ const sp<IServiceManager> pm = getPassthroughServiceManager();
+ if (pm != nullptr) {
+ sp<IBase> base = pm->get(descriptor, instance).withDefault(nullptr);
+ if (!getStub || trebleTestingOverride) {
+ base = wrapPassthrough(base);
+ }
+ return base;
+ }
+ }
+
+ return nullptr;
}
-}
+
+} // namespace details
+} // namespace hardware
+} // namespace android
diff --git a/transport/include/hidl/HidlTransportSupport.h b/transport/include/hidl/HidlTransportSupport.h
index 18a4036..4c9a881 100644
--- a/transport/include/hidl/HidlTransportSupport.h
+++ b/transport/include/hidl/HidlTransportSupport.h
@@ -19,6 +19,7 @@
#include <android/hidl/base/1.0/IBase.h>
#include <hidl/HidlBinderSupport.h>
+#include <hidl/HidlPassthroughSupport.h>
#include <hidl/HidlSupport.h>
#include <hidl/HidlTransportUtils.h>
@@ -106,10 +107,40 @@
// binderized mode. Got BpChild. grab the remote and wrap it.
return sp<IChild>(new BpChild(toBinder<IParent>(parent)));
}
- // Passthrough mode. Got BnChild and BsChild.
+ // Passthrough mode. Got BnChild or BsChild.
return sp<IChild>(static_cast<IChild *>(parent.get()));
}
+// Returns a service with the following constraints:
+// - retry => service is waited for and returned if available in this process
+// - getStub => internal only. Forces to get the unwrapped (no BsFoo) if available.
+// TODO(b/65843592)
+// If the service is a remote service, this function returns BpBase. If the service is
+// a passthrough service, this function returns the appropriately wrapped Bs child object.
+sp<::android::hidl::base::V1_0::IBase> getRawServiceInternal(const std::string& descriptor,
+ const std::string& instance,
+ bool retry, bool getStub);
+
+template <typename BpType, typename IType = typename BpType::Pure,
+ typename = std::enable_if_t<std::is_same<i_tag, typename IType::_hidl_tag>::value>,
+ typename = std::enable_if_t<std::is_same<bphw_tag, typename BpType::_hidl_tag>::value>>
+sp<IType> getServiceInternal(const std::string& instance, bool retry, bool getStub) {
+ using ::android::hidl::base::V1_0::IBase;
+
+ sp<IBase> base = getRawServiceInternal(IType::descriptor, instance, retry, getStub);
+
+ if (base == nullptr) {
+ return nullptr;
+ }
+
+ if (base->isRemote()) {
+ // getRawServiceInternal guarantees we get the proper class
+ return sp<IType>(new BpType(toBinder<IBase>(base)));
+ }
+
+ return IType::castFrom(base);
+}
+
} // namespace details
} // namespace hardware