diff options
author | Steven Moreland <smoreland@google.com> | 2017-10-06 16:06:26 -0700 |
---|---|---|
committer | Steven Moreland <smoreland@google.com> | 2017-10-10 18:20:09 +0000 |
commit | a15479f3601819b4a0e8b20644a0d54615d8022f (patch) | |
tree | 011e166d6de054bf117face3102e3bfc61806524 /transport/HidlTransportSupport.cpp | |
parent | 9104cf247237fb2c00be7fc0df87a05c766544e9 (diff) | |
download | libhidl-a15479f3601819b4a0e8b20644a0d54615d8022f.tar.gz |
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
Diffstat (limited to 'transport/HidlTransportSupport.cpp')
-rw-r--r-- | transport/HidlTransportSupport.cpp | 116 |
1 files changed, 115 insertions, 1 deletions
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 @@ bool setMinSchedulerPolicy(const sp<::android::hidl::base::V1_0::IBase>& service 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 |