getService should retry if getting nullptr am: 64ba3d7987
am: d5749ed112

Change-Id: I03b98bb48cdfece7fd56b2aeb89d7683448566e6
diff --git a/generateCpp.cpp b/generateCpp.cpp
index 7529460..bc4b859 100644
--- a/generateCpp.cpp
+++ b/generateCpp.cpp
@@ -156,46 +156,98 @@
 
     out << "// static\n"
         << "::android::sp<" << interfaceName << "> " << interfaceName << "::getService("
-        << "const std::string &serviceName, bool getStub) ";
+        << "const std::string &serviceName, const bool getStub) ";
     out.block([&] {
         out << "::android::sp<" << interfaceName << "> iface = nullptr;\n";
         out << "::android::vintf::Transport transport = ::android::hardware::getTransport("
             << interfaceName << "::descriptor, serviceName);\n";
 
-        out.sIf("!getStub && "
-                "(transport == ::android::vintf::Transport::HWBINDER || "
-                "transport == ::android::vintf::Transport::TOGGLED || "
-                "transport == ::android::vintf::Transport::EMPTY)", [&] {
+        // TODO(b/34274385) remove sysprop check
+        out << "const bool vintfHwbinder = (transport == ::android::vintf::Transport::HWBINDER) ||\n"
+            << "                           (transport == ::android::vintf::Transport::TOGGLED &&\n"
+            << "                            ::android::hardware::details::blockingHalBinderizationEnabled());\n"
+            << "const bool vintfPassthru = (transport == ::android::vintf::Transport::PASSTHROUGH) ||\n"
+            << "                           (transport == ::android::vintf::Transport::TOGGLED &&\n"
+            << "                            !::android::hardware::details::blockingHalBinderizationEnabled());\n"
+            << "const bool vintfEmpty    = (transport == ::android::vintf::Transport::EMPTY);\n\n";
+
+        // if (getStub) {
+        //     getPassthroughServiceManager()->get only once.
+        // } else {
+        //     if (vintfHwbinder) {
+        //         while (no alive service) {
+        //             waitForHwService
+        //             defaultServiceManager()->get
+        //         }
+        //     } else if (vintfEmpty) {
+        //         defaultServiceManager()->get only once.
+        //         getPassthroughServiceManager()->get only once.
+        //     } else if (vintfPassthru) {
+        //         getPassthroughServiceManager()->get only once.
+        //     }
+        // }
+
+        out.sFor("bool tried = false; "
+                 "!getStub && (vintfHwbinder || (vintfEmpty && !tried)); "
+                 "tried = true", [&] {
+
+            // Because this is a for loop, a "continue" statement means
+            // setting tried, and hence "break" for vintfEmpty and
+            // "retry" for vintfHwBinder
+
+            out.sIf("tried", [&] {
+                // sleep only after the first trial.
+                out << "ALOGI(\"getService: retrying in 1s...\");\n"
+                    << "sleep(1);\n";
+            }).endl();
+
             out << "const ::android::sp<::android::hidl::manager::V1_0::IServiceManager> sm\n";
             out.indent(2, [&] {
                 out << "= ::android::hardware::defaultServiceManager();\n";
             });
-            out.sIf("sm != nullptr", [&] {
-                // TODO(b/34274385) remove sysprop check
-                out.sIf("transport == ::android::vintf::Transport::HWBINDER ||"
-                         "(transport == ::android::vintf::Transport::TOGGLED &&"
-                         " ::android::hardware::details::blockingHalBinderizationEnabled())", [&]() {
-                    out << "::android::hardware::details::waitForHwService("
-                        << interfaceName << "::descriptor" << ", serviceName);\n";
-                }).endl();
-                out << "::android::hardware::Return<::android::sp<" << gIBaseFqName.cppName() << ">> ret = \n";
-                out.indent(2, [&] {
-                    out << "sm->get(" << interfaceName << "::descriptor" << ", serviceName);\n";
-                });
-                out.sIf("ret.isOk()", [&] {
-                    out << "iface = " << interfaceName << "::castFrom(ret);\n";
-                    out.sIf("iface != nullptr", [&] {
-                        out << "return iface;\n";
-                    }).endl();
-                }).endl();
+            out.sIf("sm == nullptr", [&] {
+                // hwbinder is not available on this device, so future tries
+                // would also be null. I can only "break" here and
+                // (vintfEmpty) try passthrough or (vintfHwbinder) return nullptr.
+                out << "ALOGE(\"getService: defaultServiceManager() is null\");\n"
+                    << "break;\n";
             }).endl();
+
+            out.sIf("vintfHwbinder", [&] {
+                out << "::android::hardware::details::waitForHwService("
+                    << interfaceName << "::descriptor" << ", serviceName);\n";
+            }).endl();
+
+            out << "::android::hardware::Return<::android::sp<"
+                << gIBaseFqName.cppName() << ">> ret = \n";
+            out.indent(2, [&] {
+                out << "sm->get(" << interfaceName << "::descriptor, serviceName);\n";
+            });
+
+            out.sIf("!ret.isOk()", [&] {
+                // hwservicemanager fails
+                out << "ALOGE(\"getService: defaultServiceManager()->get returns %s\", "
+                    << "ret.description().c_str());\n"
+                    << "continue;\n";
+            }).endl();
+
+            out << "iface = " << interfaceName << "::castFrom(ret);\n";
+            out.sIf("iface == nullptr", [&] {
+                // 1. race condition. hwservicemanager drops the service
+                //    from waitForHwService to here
+                // 2. service is dead (castFrom cannot call interfaceChain)
+                // 3. returned service isn't of correct type; this is a bug
+                //    to hwservicemanager or to the service itself (interfaceChain
+                //    is not consistent)
+                // In all cases, try again.
+                out << "ALOGW(\"getService: found null interface\");\n"
+                    << "continue;\n";
+            }).endl();
+
+            out << "return iface;\n";
         }).endl();
 
-        out.sIf("getStub || "
-                "transport == ::android::vintf::Transport::PASSTHROUGH || "
-                "(transport == ::android::vintf::Transport::TOGGLED &&"
-                " !::android::hardware::details::blockingHalBinderizationEnabled()) ||"
-                "transport == ::android::vintf::Transport::EMPTY", [&] {
+        out.sIf("getStub || vintfPassthru || vintfEmpty", [&] {
             out << "const ::android::sp<::android::hidl::manager::V1_0::IServiceManager> pm\n";
             out.indent(2, [&] {
                 out << "= ::android::hardware::getPassthroughServiceManager();\n";
@@ -212,7 +264,7 @@
                     out.sIf("baseInterface != nullptr", [&]() {
                         out << "iface = new " << fqName.getInterfacePassthroughName()
                             << "(" << interfaceName << "::castFrom(baseInterface));\n";
-                    });
+                    }).endl();
                 }).endl();
             }).endl();
         }).endl();
diff --git a/utils/Formatter.cpp b/utils/Formatter.cpp
index db763d9..503d145 100644
--- a/utils/Formatter.cpp
+++ b/utils/Formatter.cpp
@@ -86,6 +86,11 @@
     return this->block(block);
 }
 
+Formatter &Formatter::sFor(const std::string &stmts, std::function<void(void)> block) {
+    (*this) << "for (" << stmts << ") ";
+    return this->block(block);
+}
+
 Formatter &Formatter::sTry(std::function<void(void)> block) {
     (*this) << "try ";
     return this->block(block);
@@ -101,6 +106,11 @@
     return this->block(block);
 }
 
+Formatter &Formatter::sWhile(const std::string &cond, std::function<void(void)> block) {
+    (*this) << "while (" << cond << ") ";
+    return this->block(block);
+}
+
 Formatter &Formatter::operator<<(const std::string &out) {
     const size_t len = out.length();
     size_t start = 0;
diff --git a/utils/include/hidl-util/Formatter.h b/utils/include/hidl-util/Formatter.h
index 7e0c4f9..57fb3b6 100644
--- a/utils/include/hidl-util/Formatter.h
+++ b/utils/include/hidl-util/Formatter.h
@@ -79,6 +79,11 @@
     Formatter &sElseIf(const std::string &cond, std::function<void(void)> block);
     Formatter &sElse(std::function<void(void)> block);
 
+    // out.sFor("int i = 0; i < 10; i++", [&] {
+    //     out << "printf(\"%d\", i);\n";
+    // }).endl();
+    Formatter &sFor(const std::string &stmts, std::function<void(void)> block);
+
     // out.sTry([&] {
     //     out << "throw RemoteException();\n"
     // }).sCatch("RemoteException ex", [&] {
@@ -91,6 +96,11 @@
     Formatter &sCatch(const std::string &exception, std::function<void(void)> block);
     Formatter &sFinally(std::function<void(void)> block);
 
+    // out.sWhile("z < 10", [&] {
+    //     out << "z++;\n";
+    // }).endl();
+    Formatter &sWhile(const std::string &cond, std::function<void(void)> block);
+
     Formatter &operator<<(const std::string &out);
     Formatter &operator<<(size_t n);