static jlong
loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jstring funcName,
        jobject messageQueue, jstring internalDataDir, jstring obbDir,
        jstring externalDataDir, jint sdkVersion, jobject jAssetMgr,
        jbyteArray savedState, jobject classLoader, jstring libraryPath) {
    if (kLogTrace) {
        ALOGD("loadNativeCode_native");
    }

    const char* pathStr = env->GetStringUTFChars(path, NULL);
    std::unique_ptr<NativeCode> code;
    bool needNativeBridge = false;

    void* handle = OpenNativeLibrary(env, sdkVersion, pathStr, classLoader, libraryPath);
    if (handle == NULL) {
        if (NativeBridgeIsSupported(pathStr)) {
            handle = NativeBridgeLoadLibrary(pathStr, RTLD_LAZY);
            needNativeBridge = true;
        }
    }
    env->ReleaseStringUTFChars(path, pathStr);

    if (handle != NULL) {
        void* funcPtr = NULL;
        const char* funcStr = env->GetStringUTFChars(funcName, NULL);
        if (needNativeBridge) {
            funcPtr = NativeBridgeGetTrampoline(handle, funcStr, NULL, 0);
        } else {
            funcPtr = dlsym(handle, funcStr);
        }

        code.reset(new NativeCode(handle, (ANativeActivity_createFunc*)funcPtr));
        env->ReleaseStringUTFChars(funcName, funcStr);

        if (code->createActivityFunc == NULL) {
            ALOGW("ANativeActivity_onCreate not found");
            return 0;
        }
        
        code->messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueue);
        if (code->messageQueue == NULL) {
            ALOGW("Unable to retrieve native MessageQueue");
            return 0;
        }
        
        int msgpipe[2];
        if (pipe(msgpipe)) {
            ALOGW("could not create pipe: %s", strerror(errno));
            return 0;
        }
        code->mainWorkRead = msgpipe[0];
        code->mainWorkWrite = msgpipe[1];
        int result = fcntl(code->mainWorkRead, F_SETFL, O_NONBLOCK);
        SLOGW_IF(result != 0, "Could not make main work read pipe "
                "non-blocking: %s", strerror(errno));
        result = fcntl(code->mainWorkWrite, F_SETFL, O_NONBLOCK);
        SLOGW_IF(result != 0, "Could not make main work write pipe "
                "non-blocking: %s", strerror(errno));
        code->messageQueue->getLooper()->addFd(
                code->mainWorkRead, 0, ALOOPER_EVENT_INPUT, mainWorkCallback, code.get());
        
        code->ANativeActivity::callbacks = &code->callbacks;
        if (env->GetJavaVM(&code->vm) < 0) {
            ALOGW("NativeActivity GetJavaVM failed");
            return 0;
        }
        code->env = env;
        code->clazz = env->NewGlobalRef(clazz);

        const char* dirStr = env->GetStringUTFChars(internalDataDir, NULL);
        code->internalDataPathObj = dirStr;
        code->internalDataPath = code->internalDataPathObj.string();
        env->ReleaseStringUTFChars(internalDataDir, dirStr);
    
        if (externalDataDir != NULL) {
            dirStr = env->GetStringUTFChars(externalDataDir, NULL);
            code->externalDataPathObj = dirStr;
            env->ReleaseStringUTFChars(externalDataDir, dirStr);
        }
        code->externalDataPath = code->externalDataPathObj.string();

        code->sdkVersion = sdkVersion;
        
        code->assetManager = assetManagerForJavaObject(env, jAssetMgr);

        if (obbDir != NULL) {
            dirStr = env->GetStringUTFChars(obbDir, NULL);
            code->obbPathObj = dirStr;
            env->ReleaseStringUTFChars(obbDir, dirStr);
        }
        code->obbPath = code->obbPathObj.string();

        jbyte* rawSavedState = NULL;
        jsize rawSavedSize = 0;
        if (savedState != NULL) {
            rawSavedState = env->GetByteArrayElements(savedState, NULL);
            rawSavedSize = env->GetArrayLength(savedState);
        }

        code->createActivityFunc(code.get(), rawSavedState, rawSavedSize);

        if (rawSavedState != NULL) {
            env->ReleaseByteArrayElements(savedState, rawSavedState, 0);
        }
    }
    
    return (jlong)code.release();
}
TEST(liblog, SLOG) {
  static const char content[] = "log_system.h";
  static const char content_false[] = "log_system.h false";

// ratelimit content to 10/s to keep away from spam filters
// do not send identical content together to keep away from spam filters

#undef LOG_TAG
#define LOG_TAG "TEST__SLOGV"
  SLOGV(content);
  usleep(100000);
#undef LOG_TAG
#define LOG_TAG "TEST__SLOGD"
  SLOGD(content);
  usleep(100000);
#undef LOG_TAG
#define LOG_TAG "TEST__SLOGI"
  SLOGI(content);
  usleep(100000);
#undef LOG_TAG
#define LOG_TAG "TEST__SLOGW"
  SLOGW(content);
  usleep(100000);
#undef LOG_TAG
#define LOG_TAG "TEST__SLOGE"
  SLOGE(content);
  usleep(100000);
#undef LOG_TAG
#define LOG_TAG "TEST__SLOGV"
  SLOGV_IF(true, content);
  usleep(100000);
  SLOGV_IF(false, content_false);
  usleep(100000);
#undef LOG_TAG
#define LOG_TAG "TEST__SLOGD"
  SLOGD_IF(true, content);
  usleep(100000);
  SLOGD_IF(false, content_false);
  usleep(100000);
#undef LOG_TAG
#define LOG_TAG "TEST__SLOGI"
  SLOGI_IF(true, content);
  usleep(100000);
  SLOGI_IF(false, content_false);
  usleep(100000);
#undef LOG_TAG
#define LOG_TAG "TEST__SLOGW"
  SLOGW_IF(true, content);
  usleep(100000);
  SLOGW_IF(false, content_false);
  usleep(100000);
#undef LOG_TAG
#define LOG_TAG "TEST__SLOGE"
  SLOGE_IF(true, content);
  usleep(100000);
  SLOGE_IF(false, content_false);

#ifdef __ANDROID__
  // give time for content to long-path through logger
  sleep(1);

  std::string buf = android::base::StringPrintf(
      "logcat -b system --pid=%u -d -s"
      " TEST__SLOGV TEST__SLOGD TEST__SLOGI TEST__SLOGW TEST__SLOGE",
      (unsigned)getpid());
  FILE* fp = popen(buf.c_str(), "re");
  int count = 0;
  int count_false = 0;
  if (fp) {
    if (!android::base::ReadFdToString(fileno(fp), &buf)) buf = "";
    pclose(fp);
    for (size_t pos = 0; (pos = buf.find(content, pos)) != std::string::npos;
         ++pos) {
      ++count;
    }
    for (size_t pos = 0;
         (pos = buf.find(content_false, pos)) != std::string::npos; ++pos) {
      ++count_false;
    }
  }
  EXPECT_EQ(0, count_false);
#if LOG_NDEBUG
  ASSERT_EQ(8, count);
#else
  ASSERT_EQ(10, count);
#endif

#else
  GTEST_LOG_(INFO) << "This test does not test end-to-end.\n";
#endif
}