http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/2f8caedb/weex_core/Source/android/jsengine/multiprocess/ExtendJSApi.cpp ---------------------------------------------------------------------- diff --git a/weex_core/Source/android/jsengine/multiprocess/ExtendJSApi.cpp b/weex_core/Source/android/jsengine/multiprocess/ExtendJSApi.cpp new file mode 100644 index 0000000..4afb185 --- /dev/null +++ b/weex_core/Source/android/jsengine/multiprocess/ExtendJSApi.cpp @@ -0,0 +1,662 @@ +#include <android/base/string/string_utils.h> +#include <base/ViewUtils.h> +#include "ExtendJSApi.h" + +using namespace WeexCore; + +static WeexCore::FunType gCanvasFunc = nullptr; + +static WeexCore::FunTypeT3d t3dFunc = nullptr; + +/** +* This class aim to extend JS Api +**/ +ExtendJSApi::ExtendJSApi() { +} + +void ExtendJSApi::initFunction(IPCHandler *handler) { + handler->registerHandler(static_cast<uint32_t>(IPCProxyMsg::SETJSFVERSION), + handleSetJSVersion); + handler->registerHandler(static_cast<uint32_t>(IPCProxyMsg::REPORTEXCEPTION), + handleReportException); + handler->registerHandler(static_cast<uint32_t>(IPCProxyMsg::CALLNATIVE), + handleCallNative); + handler->registerHandler(static_cast<uint32_t>(IPCProxyMsg::CALLNATIVEMODULE), + handleCallNativeModule); + handler->registerHandler(static_cast<uint32_t>(IPCProxyMsg::CALLNATIVECOMPONENT), + handleCallNativeComponent); + handler->registerHandler(static_cast<uint32_t>(IPCProxyMsg::CALLADDELEMENT), + handleCallAddElement); + handler->registerHandler(static_cast<uint32_t>(IPCProxyMsg::SETTIMEOUT), + handleSetTimeout); + handler->registerHandler(static_cast<uint32_t>(IPCProxyMsg::NATIVELOG), + handleCallNativeLog); + handler->registerHandler(static_cast<uint32_t>(IPCProxyMsg::CALLCREATEBODY), + functionCallCreateBody); + handler->registerHandler(static_cast<uint32_t>(IPCProxyMsg::CALLUPDATEFINISH), + functionCallUpdateFinish); + handler->registerHandler(static_cast<uint32_t>(IPCProxyMsg::CALLCREATEFINISH), + functionCallCreateFinish); + handler->registerHandler(static_cast<uint32_t>(IPCProxyMsg::CALLREFRESHFINISH), + functionCallRefreshFinish); + handler->registerHandler(static_cast<uint32_t>(IPCProxyMsg::CALLUPDATEATTRS), + functionCallUpdateAttrs); + handler->registerHandler(static_cast<uint32_t>(IPCProxyMsg::CALLUPDATESTYLE), + functionCallUpdateStyle); + handler->registerHandler(static_cast<uint32_t>(IPCProxyMsg::CALLREMOVEELEMENT), + functionCallRemoveElement); + handler->registerHandler(static_cast<uint32_t>(IPCProxyMsg::CALLMOVEELEMENT), + functionCallMoveElement); + handler->registerHandler(static_cast<uint32_t>(IPCProxyMsg::CALLADDEVENT), + functionCallAddEvent); + handler->registerHandler(static_cast<uint32_t>(IPCProxyMsg::CALLREMOVEEVENT), + functionCallRemoveEvent); + handler->registerHandler(static_cast<uint32_t>(IPCProxyMsg::SETINTERVAL), + handleSetInterval); + handler->registerHandler(static_cast<uint32_t>(IPCProxyMsg::CLEARINTERVAL), + handleClearInterval); + handler->registerHandler(static_cast<uint32_t>(IPCProxyMsg::CALLGCANVASLINK), + handleCallGCanvasLinkNative); + handler->registerHandler(static_cast<uint32_t>(IPCProxyMsg::CALLT3DLINK), + handleT3DLinkNative); +} + +std::unique_ptr<IPCResult> handleSetJSVersion(IPCArguments *arguments) { + const char* version = getArumentAsCStr(arguments, 0); + LOGA("init JSFrm version %s", version); + Bridge_Impl_Android::getInstance()->setJSVersion(version); + return createVoidResult(); +} + +void reportException(const char* pageId, const char *func, const char *exception_string) { + Bridge_Impl_Android::getInstance()->reportException(pageId, func, exception_string); +} + +std::unique_ptr<IPCResult> handleReportException(IPCArguments *arguments) { + const char *pageId = nullptr; + const char *func = nullptr; + const char *exceptionInfo = nullptr; + + if (arguments->getType(0) == IPCType::BYTEARRAY) { + const IPCByteArray *instanceIDBA = arguments->getByteArray(0); + pageId = instanceIDBA->content; + } + + if (arguments->getType(1) == IPCType::BYTEARRAY) { + const IPCByteArray *funcBA = arguments->getByteArray(1); + func = funcBA->content; + } + + if (arguments->getType(2) == IPCType::BYTEARRAY) { + const IPCByteArray *exceptionInfoBA = arguments->getByteArray(2); + exceptionInfo = exceptionInfoBA->content; + } + + LOGE(" ReportException : %s", exceptionInfo); + reportException(pageId, func, exceptionInfo); + return createVoidResult(); +} + +std::unique_ptr<IPCResult> handle(IPCArguments *arguments) { + const char* str_array = getArumentAsCStr(arguments, 0); + Bridge_Impl_Android::getInstance()->callNativeLog(str_array); + return createInt32Result(static_cast<int32_t>(true)); +} + +std::unique_ptr<IPCResult> handleCallNativeLog(IPCArguments *arguments) { + const char* str_array = getArumentAsCStr(arguments, 0); + Bridge_Impl_Android::getInstance()->callNativeLog(str_array); + return createInt32Result(static_cast<int32_t>(true)); +} + +std::unique_ptr<IPCResult> handleSetTimeout(IPCArguments *arguments) { + char* callbackID = getArumentAsCStr(arguments, 0); + char* time = getArumentAsCStr(arguments, 1); + + if (callbackID == nullptr || time == nullptr) + return createInt32Result(static_cast<int32_t>(false)); + + Bridge_Impl_Android::getInstance()->setTimeout(callbackID, time); + + if (callbackID != nullptr) { + delete[]callbackID; + callbackID = nullptr; + } + if (time != nullptr) { + delete[]time; + time = nullptr; + } + return createInt32Result(static_cast<int32_t>(true)); +} + +std::unique_ptr<IPCResult> handleSetInterval(IPCArguments *arguments) { + const char *pageId = getArumentAsCStr(arguments, 0); + const char *callbackID = getArumentAsCStr(arguments, 1); + const char *_time = getArumentAsCStr(arguments, 2); + if (pageId == nullptr || callbackID == nullptr || _time == nullptr) + return createInt32Result(-1); + + long time_ = atoi(_time); + int _timerId = (atoi(pageId) << 16) | (atoi(callbackID)); + + if (pageId != nullptr) { + delete[]pageId; + pageId = nullptr; + } + if (callbackID != nullptr) { + delete[]callbackID; + callbackID = nullptr; + } + if (_time != nullptr) { + delete[]_time; + _time = nullptr; + } + return createInt32Result(_timerId); +} + +std::unique_ptr<IPCResult> handleClearInterval(IPCArguments *arguments) { + const char *pageId = getArumentAsCStr(arguments, 0); + const char *callbackID = getArumentAsCStr(arguments, 1); + long id = atoi(callbackID); + + if (pageId != nullptr) { + delete[]pageId; + pageId = nullptr; + } + if (callbackID != nullptr) { + delete[]callbackID; + callbackID = nullptr; + } + return createVoidResult(); +} + +std::unique_ptr<IPCResult> handleCallNative(IPCArguments *arguments) { + char* pageId = getArumentAsCStr(arguments, 0); + char* task = getArumentAsCStr(arguments, 1); + char* callback = getArumentAsCStr(arguments, 2); + + if (pageId != nullptr && task != nullptr) { +#if JSAPI_LOG + LOGD("[ExtendJSApi] handleCallNative >>>> pageId: %s, task: %s", pageId, task); +#endif + + if (strcmp(task, "[{\"module\":\"dom\",\"method\":\"createFinish\",\"args\":[]}]") == 0) { + RenderManager::GetInstance()->CreateFinish(pageId) ? 0 : -1; + } else { + Bridge_Impl_Android::getInstance()->callNative(pageId, task, callback); + } + } + + if (pageId != nullptr) { + delete[]pageId; + pageId = nullptr; + } + if (task != nullptr) { + delete[]task; + task = nullptr; + } + if (callback != nullptr) { + delete[]callback; + callback = nullptr; + } + return createInt32Result(0); +} + +static std::unique_ptr<IPCResult> handleCallGCanvasLinkNative(IPCArguments *arguments) { + JNIEnv *env = getJNIEnv(); + jstring jPageId = getArgumentAsJString(env, arguments, 0); + const char *pageId = env->GetStringUTFChars(jPageId, NULL); + int type = getArgumentAsInt32(env, arguments, 1); + jstring val = getArgumentAsJString(env, arguments, 2); + const char *args = env->GetStringUTFChars(val, NULL); + +#if JSAPI_LOG + LOGD("[ExtendJSApi] handleCallGCanvasLinkNative >>>> pageId: %s, type: %d, args: %s", pageId, type, args); +#endif + + const char *retVal = NULL; + if (gCanvasFunc) { + retVal = callGCanvasFun(gCanvasFunc, pageId, type, args); + } + + std::unique_ptr<IPCResult> ret = createVoidResult(); + if (retVal) { + jstring jDataStr = env->NewStringUTF(retVal); + ret = std::move(createStringResult(env, jDataStr)); + env->DeleteLocalRef(jDataStr); + retVal = NULL; + } + env->DeleteLocalRef(jPageId); + env->DeleteLocalRef(val); + return ret; +} + +static std::unique_ptr<IPCResult> handleT3DLinkNative(IPCArguments* arguments) +{ + JNIEnv* env = getJNIEnv(); + int type = getArgumentAsInt32(env, arguments, 0); + jstring val = getArgumentAsJString(env, arguments, 1); + const char* args = env->GetStringUTFChars(val, NULL); + +#if JSAPI_LOG + LOGD("[ExtendJSApi] handleT3DLinkNative >>>> type: %d, args: %s", type, args); +#endif + + const char* retVal = NULL; + if (t3dFunc) { + retVal = WeexCore::weexCallT3dFunc(t3dFunc, type, args); + } + + + + std::unique_ptr<IPCResult> ret = createVoidResult(); + if (retVal) { + jstring jDataStr = env->NewStringUTF(retVal); + ret = std::move(createStringResult(env, jDataStr)); + env->DeleteLocalRef(jDataStr); + retVal = NULL; + } + env->DeleteLocalRef(val); + return ret; +} + +std::unique_ptr<IPCResult> handleCallNativeModule(IPCArguments *arguments) { + char* pageId = getArumentAsCStr(arguments, 0); + char* module = getArumentAsCStr(arguments, 1); + char* method = getArumentAsCStr(arguments, 2); + char* argString = getArumentAsCStr(arguments, 3); + char* optString = getArumentAsCStr(arguments, 4); + + std::unique_ptr<IPCResult> ret = createInt32Result(-1); + + if (pageId != nullptr && module != nullptr && method != nullptr) { +#if JSAPI_LOG + LOGD("[ExtendJSApi] handleCallNativeModule >>>> pageId: %s, module: %s, method: %s, arg: %s, opt: %s", + pageId, module, method, argString, optString); +#endif + + // add for android support + jobject result; + result = Bridge_Impl_Android::getInstance()->callNativeModule(pageId, module, method, + argString, optString); + + if (result == nullptr) + return ret; + + JNIEnv *env = getJNIEnv(); + jfieldID jTypeId = env->GetFieldID(jWXJSObject, "type", "I"); + jint jTypeInt = env->GetIntField(result, jTypeId); + jfieldID jDataId = env->GetFieldID(jWXJSObject, "data", "Ljava/lang/Object;"); + jobject jDataObj = env->GetObjectField(result, jDataId); + if (jTypeInt == 1) { + if (jDoubleValueMethodId == NULL) { + jclass jDoubleClazz = env->FindClass("java/lang/Double"); + jDoubleValueMethodId = env->GetMethodID(jDoubleClazz, "doubleValue", "()D"); + env->DeleteLocalRef(jDoubleClazz); + } + jdouble jDoubleObj = env->CallDoubleMethod(jDataObj, jDoubleValueMethodId); + ret = std::move(createDoubleResult(jDoubleObj)); + + } else if (jTypeInt == 2) { + jstring jDataStr = (jstring) jDataObj; + ret = std::move(createStringResult(env, jDataStr)); + } else if (jTypeInt == 3) { + jstring jDataStr = (jstring) jDataObj; + ret = std::move(createJSONStringResult(env, jDataStr)); + } + env->DeleteLocalRef(jDataObj); + } + + if (pageId != nullptr) { + delete[]pageId; + pageId = nullptr; + } + if (module != nullptr) { + delete[]module; + module = nullptr; + } + if (method != nullptr) { + delete[]method; + method = nullptr; + } + if (argString != nullptr) { + delete[]argString; + argString = nullptr; + } + if (optString != nullptr) { + delete[]optString; + optString = nullptr; + } + return ret; +} + +std::unique_ptr<IPCResult> handleCallNativeComponent(IPCArguments *arguments) { + char* pageId = getArumentAsCStr(arguments, 0); + char* ref = getArumentAsCStr(arguments, 1); + char* method = getArumentAsCStr(arguments, 2); + char* argString = getArumentAsCStr(arguments, 3); + char* optString = getArumentAsCStr(arguments, 4); + + if (pageId != nullptr && ref != nullptr && method != nullptr) { + +#if JSAPI_LOG + LOGD("[ExtendJSApi] handleCallNativeComponent >>>> pageId: %s, ref: %s, method: %s, arg: %s, opt: %s", + pageId, ref, method, argString, optString); +#endif + + Bridge_Impl_Android::getInstance()->callNativeComponent(pageId, ref, method, argString, optString); + } + + if (pageId != nullptr) { + delete[]pageId; + pageId = nullptr; + } + if (ref != nullptr) { + delete[]ref; + ref = nullptr; + } + if (method != nullptr) { + delete[]method; + method = nullptr; + } + if (argString != nullptr) { + delete[]argString; + argString = nullptr; + } + if (optString != nullptr) { + delete[]optString; + optString = nullptr; + } + return createInt32Result(static_cast<int32_t>(true)); +} + +std::unique_ptr<IPCResult> functionCallCreateBody(IPCArguments *arguments) { + + char *pageId = getArumentAsCStr(arguments, 0); + char *domStr = getArumentAsCStr(arguments, 1); + + if (pageId == nullptr || domStr == nullptr) + return createInt32Result(0); + +#if JSAPI_LOG + LOGD("[ExtendJSApi] functionCallCreateBody >>>> pageId: %s, domStr: %s", pageId, domStr); +#endif + + RenderManager::GetInstance()->CreatePage(pageId, domStr) ? 0 : -1; + + delete[]pageId; + delete[]domStr; + return createInt32Result(0); +} + +std::unique_ptr<IPCResult> handleCallAddElement(IPCArguments *arguments) { + + char *pageId = getArumentAsCStr(arguments, 0); + char *parentRef = getArumentAsCStr(arguments, 1); + char *domStr = getArumentAsCStr(arguments, 2); + char *index_cstr = getArumentAsCStr(arguments, 3); + int index = atoi(index_cstr); + + if (pageId == nullptr || parentRef == nullptr || domStr == nullptr || index_cstr == nullptr || + index < -1) + return createInt32Result(0); + +#if JSAPI_LOG + + std::string log = ""; + log.append("pageId: ").append(pageId).append(", parentRef: ").append(parentRef).append(", domStr: ").append(domStr); + int log_index = 0; + int maxLength = 800; + std::string sub; + while (log_index < log.length()) { + if (log.length() <= log_index + maxLength) { + sub = log.substr(log_index); + } else { + sub = log.substr(log_index, maxLength); + } + + + if (log_index == 0) + LOGD("[ExtendJSApi] functionCallAddElement >>>> %s", sub.c_str()); + else + LOGD(" [ExtendJSApi] functionCallAddElement >>>> %s", sub.c_str()); + + log_index += maxLength; + } +#endif + + RenderManager::GetInstance()->AddRenderObject(pageId, parentRef, index, domStr); + + delete[]pageId; + delete[]parentRef; + delete[]domStr; + delete[]index_cstr; + return createInt32Result(0); +} + +std::unique_ptr<IPCResult> functionCallRemoveElement(IPCArguments *arguments) { + + char *pageId = getArumentAsCStr(arguments, 0); + char *ref = getArumentAsCStr(arguments, 1); + + if (pageId == nullptr || ref == nullptr) + return createInt32Result(0); + +#if JSAPI_LOG + LOGD("[ExtendJSApi] functionCallRemoveElement >>>> pageId: %s, ref: %s", pageId, + ref); +#endif + + RenderManager::GetInstance()->RemoveRenderObject(pageId, ref); + + delete[]pageId; + delete[]ref; + return createInt32Result(0); +} + +std::unique_ptr<IPCResult> functionCallMoveElement(IPCArguments *arguments) { + + char *pageId = getArumentAsCStr(arguments, 0); + char *ref = getArumentAsCStr(arguments, 1); + char *parentRef = getArumentAsCStr(arguments, 2); + char *index_str = getArumentAsCStr(arguments, 3); + int index = atoi(index_str); + + if (pageId == nullptr || ref == nullptr || parentRef == nullptr || index_str == nullptr || + index < -1) + return createInt32Result(0); + +#if JSAPI_LOG + LOGD("[ExtendJSApi] functionCallRemoveElement >>>> pageId: %s, ref: %s, parentRef: %s, index: %d", + pageId, ref, parentRef, index); +#endif + + RenderManager::GetInstance()->MoveRenderObject(pageId, ref, parentRef, index); + + delete[]pageId; + delete[]ref; + delete[]parentRef; + delete[]index_str; + return createInt32Result(0); +} + +std::unique_ptr<IPCResult> functionCallAddEvent(IPCArguments *arguments) { + + char *pageId = getArumentAsCStr(arguments, 0); + char *ref = getArumentAsCStr(arguments, 1); + char *event = getArumentAsCStr(arguments, 2); + + if (pageId == nullptr || ref == nullptr || event == nullptr) + return createInt32Result(0); + +#if JSAPI_LOG + LOGD("[ExtendJSApi] functionCallAddEvent >>>> pageId: %s, ref: %s, event: %s", pageId, + ref, event); +#endif + + RenderManager::GetInstance()->AddEvent(pageId, ref, event); + + delete[]pageId; + delete[]ref; + delete[]event; + return createInt32Result(0); +} + +std::unique_ptr<IPCResult> functionCallRemoveEvent(IPCArguments *arguments) { + + char *pageId = getArumentAsCStr(arguments, 0); + char *ref = getArumentAsCStr(arguments, 1); + char *event = getArumentAsCStr(arguments, 2); + + if (pageId == nullptr || ref == nullptr || event == nullptr) + return createInt32Result(0); + +#if JSAPI_LOG + LOGD("[ExtendJSApi] functionCallRemoveEvent >>>> pageId: %s, ref: %s, event: %s", pageId, + ref, event); +#endif + + RenderManager::GetInstance()->RemoveEvent(pageId, ref, event); + + delete[]pageId; + delete[]ref; + delete[]event; + return createInt32Result(0); +} + +std::unique_ptr<IPCResult> functionCallUpdateStyle(IPCArguments *arguments) { + + char *pageId = getArumentAsCStr(arguments, 0); + char *ref = getArumentAsCStr(arguments, 1); + char *data = getArumentAsCStr(arguments, 2); + + if (pageId == nullptr || ref == nullptr || data == nullptr) + return createInt32Result(0); + +#if JSAPI_LOG + LOGD("[ExtendJSApi] functionCallUpdateStyle >>>> pageId: %s, ref: %s, data: %s", pageId, + ref, data); +#endif + + RenderManager::GetInstance()->UpdateStyle(pageId, ref, data); + + delete[] pageId; + delete[] ref; + delete[] data; + return createInt32Result(0); +} + +std::unique_ptr<IPCResult> functionCallUpdateAttrs(IPCArguments *arguments) { + + char *pageId = getArumentAsCStr(arguments, 0); + char *ref = getArumentAsCStr(arguments, 1); + char *data = getArumentAsCStr(arguments, 2); + + if (pageId == nullptr || ref == nullptr || data == nullptr) + return createInt32Result(0); + +#if JSAPI_LOG + LOGD("[ExtendJSApi] functionCallUpdateAttrs >>>> pageId: %s, ref: %s, data: %s", pageId, + ref, data); +#endif + + RenderManager::GetInstance()->UpdateAttr(pageId, ref, data); + + delete[] pageId; + delete[] ref; + delete[] data; + return createInt32Result(0); +} + +std::unique_ptr<IPCResult> functionCallCreateFinish(IPCArguments *arguments) { + + char *pageId = getArumentAsCStr(arguments, 0); + + if (pageId == nullptr) + return createInt32Result(0); + +#if JSAPI_LOG + LOGD("[ExtendJSApi] functionCallCreateFinish >>>> pageId: %s", pageId); +#endif + + RenderManager::GetInstance()->CreateFinish(pageId); + + delete[]pageId; + return createInt32Result(0); +} + +std::unique_ptr<IPCResult> functionCallUpdateFinish(IPCArguments *arguments) { + char *pageId = getArumentAsCStr(arguments, 0); + char *task = getArumentAsCStr(arguments, 1); + char *callback = getArumentAsCStr(arguments, 2); + + int flag = 0; + + if (pageId == nullptr || task == nullptr) + return createInt32Result(flag); + + flag = Bridge_Impl_Android::getInstance()->callUpdateFinish(pageId, task, callback); + + if (pageId != nullptr) { + delete[]pageId; + pageId = nullptr; + } + if (task != nullptr) { + delete[]task; + task = nullptr; + } + if (callback != nullptr) { + delete[]callback; + callback = nullptr; + } + return createInt32Result(flag); +} + +std::unique_ptr<IPCResult> functionCallRefreshFinish(IPCArguments *arguments) { + char *pageId = getArumentAsCStr(arguments, 0); + char *task = getArumentAsCStr(arguments, 1); + char *callback = getArumentAsCStr(arguments, 2); + + int flag = 0; + + if (pageId == nullptr) + return createInt32Result(flag); + + flag = Bridge_Impl_Android::getInstance()->callRefreshFinish(pageId, task, callback); + + if (pageId != nullptr) { + delete[]pageId; + pageId = nullptr; + } + if (task != nullptr) { + delete[]task; + task = nullptr; + } + if (callback != nullptr) { + delete[]callback; + callback = nullptr; + } + return createInt32Result(flag); +} + +namespace WeexCore { + + extern "C" void Inject_GCanvasFunc(FunType fp) { + gCanvasFunc = fp; + LOGE("weexjsc injectGCanvasFunc gCanvasFunc"); + } + + const char *callGCanvasFun(FunType fp, const char *conextId, int x, const char *args) { + return fp(conextId, x, args); + } + + extern "C" void Inject_T3dFunc(FunTypeT3d fp) { + t3dFunc = fp; + LOGE("weexjsc Inject_T3dFunc t3d Func"); + } + +const char* weexCallT3dFunc(FunTypeT3d fp, int x, const char* args) { + return fp(x, args); +} + +}
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/2f8caedb/weex_core/Source/android/jsengine/multiprocess/ExtendJSApi.h ---------------------------------------------------------------------- diff --git a/weex_core/Source/android/jsengine/multiprocess/ExtendJSApi.h b/weex_core/Source/android/jsengine/multiprocess/ExtendJSApi.h new file mode 100644 index 0000000..d23cda1 --- /dev/null +++ b/weex_core/Source/android/jsengine/multiprocess/ExtendJSApi.h @@ -0,0 +1,87 @@ +#ifndef _EXTEND_JSAPI_H_ +#define _EXTEND_JSAPI_H_ + +#include <android/base/log_utils.h> +#include <android/bridge/impl/bridge_impl_android.h> +#include "IPC/IPCHandler.h" +#include "IPC/IPCMessageJS.h" +#include "IPC/IPCResult.h" +#include "IPC/IPCSender.h" +#include "IPC/IPCString.h" +#include "IPC/Serializing/IPCSerializer.h" +#include <core/render/manager/render_manager.h> +#include <jni.h> +#include <sys/types.h> + + +static std::unique_ptr<IPCResult> handleSetJSVersion(IPCArguments *arguments); + +static std::unique_ptr<IPCResult> handleReportException(IPCArguments *arguments); + +static std::unique_ptr<IPCResult> handleCallNative(IPCArguments *arguments); + +static std::unique_ptr<IPCResult> handleCallNativeModule(IPCArguments *arguments); + +static std::unique_ptr<IPCResult> handleCallNativeComponent(IPCArguments *arguments); + +static std::unique_ptr<IPCResult> handleCallAddElement(IPCArguments *arguments); + +static std::unique_ptr<IPCResult> handleSetTimeout(IPCArguments *arguments); + +static std::unique_ptr<IPCResult> handleCallNativeLog(IPCArguments *arguments); + +static std::unique_ptr<IPCResult> functionCallCreateBody(IPCArguments *arguments); + +static std::unique_ptr<IPCResult> functionCallUpdateFinish(IPCArguments *arguments); + +static std::unique_ptr<IPCResult> functionCallCreateFinish(IPCArguments *arguments); + +static std::unique_ptr<IPCResult> functionCallRefreshFinish(IPCArguments *arguments); + +static std::unique_ptr<IPCResult> functionCallUpdateAttrs(IPCArguments *arguments); + +static std::unique_ptr<IPCResult> functionCallUpdateStyle(IPCArguments *arguments); + +static std::unique_ptr<IPCResult> functionCallRemoveElement(IPCArguments *arguments); + +static std::unique_ptr<IPCResult> functionCallMoveElement(IPCArguments *arguments); + +static std::unique_ptr<IPCResult> functionCallAddEvent(IPCArguments *arguments); + +static std::unique_ptr<IPCResult> functionCallRemoveEvent(IPCArguments *arguments); + +static std::unique_ptr<IPCResult> handleSetInterval(IPCArguments *arguments); + +static std::unique_ptr<IPCResult> handleClearInterval(IPCArguments *arguments); + +static std::unique_ptr<IPCResult> handleCallGCanvasLinkNative(IPCArguments *arguments); + +static std::unique_ptr<IPCResult> handleT3DLinkNative(IPCArguments *arguments); + + +static void reportException(const int instanceID, const char *func, const char *exception_string); + +namespace WeexCore { + + typedef const char *(*FunType)(const char *, int, const char *); + + const char *callGCanvasFun(FunType fp, const char *conextId, int x, const char *args); + + extern "C" void Inject_GCanvasFunc(FunType fp); + + typedef const char* (*FunTypeT3d)(int, const char*); + + const char* weexCallT3dFunc(FunTypeT3d fp, int x, const char* args); + + extern "C" void Inject_T3dFunc(FunTypeT3d fp); + + class ExtendJSApi { + public: + ExtendJSApi(); + + void initFunction(IPCHandler *handler); + }; + +} //WeexCore + +#endif // _EXTENSION_JSAPI_H_ \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/2f8caedb/weex_core/Source/android/jsengine/multiprocess/WeexJSConnection.cpp ---------------------------------------------------------------------- diff --git a/weex_core/Source/android/jsengine/multiprocess/WeexJSConnection.cpp b/weex_core/Source/android/jsengine/multiprocess/WeexJSConnection.cpp new file mode 100644 index 0000000..420cbb8 --- /dev/null +++ b/weex_core/Source/android/jsengine/multiprocess/WeexJSConnection.cpp @@ -0,0 +1,411 @@ +#include "WeexJSConnection.h" + +#include "ashmem.h" +#include <dirent.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/mman.h> +#include <vector> +#include <iostream> +#include <fstream> +#include <IPC/IPCFutexPageQueue.h> +#include <IPC/IPCException.h> +#include <IPC/IPCSender.h> +#include <unistd.h> +#include <android/base/log_utils.h> + +extern const char *s_cacheDir; +extern bool s_start_pie; + +static void doExec(int fd, bool traceEnable, bool startupPie = true); + +static int copyFile(const char *SourceFile, const char *NewFile); + +static void closeAllButThis(int fd); + +static void printLogOnFile(const char *log); + +#if PRINT_LOG_CACHEFILE +static std::string logFilePath = "/data/data/com.taobao.taobao/cache"; +#endif + +struct WeexJSConnection::WeexJSConnectionImpl { + std::unique_ptr<IPCSender> serverSender; + std::unique_ptr<IPCFutexPageQueue> futexPageQueue; + pid_t child{0}; +}; + +WeexJSConnection::WeexJSConnection() + : m_impl(new WeexJSConnectionImpl) { +} + +WeexJSConnection::~WeexJSConnection() { + end(); +} + +IPCSender *WeexJSConnection::start(IPCHandler *handler, bool reinit) { + int fd = ashmem_create_region("WEEX_IPC", IPCFutexPageQueue::ipc_size); + if (-1 == fd) { + throw IPCException("failed to create ashmem region: %s", strerror(errno)); + } + void *base = mmap(nullptr, IPCFutexPageQueue::ipc_size, PROT_READ | PROT_WRITE, MAP_SHARED, + fd, 0); + if (base == MAP_FAILED) { + int _errno = errno; + close(fd); + throw IPCException("failed to map ashmem region: %s", strerror(_errno)); + } + std::unique_ptr<IPCFutexPageQueue> futexPageQueue( + new IPCFutexPageQueue(base, IPCFutexPageQueue::ipc_size, 0)); + std::unique_ptr<IPCSender> sender(createIPCSender(futexPageQueue.get(), handler)); + m_impl->serverSender = std::move(sender); + m_impl->futexPageQueue = std::move(futexPageQueue); +#if PRINT_LOG_CACHEFILE + if (s_cacheDir) { + logFilePath = s_cacheDir; + } + logFilePath.append("/jsserver_start.log"); + std::ofstream mcfile; + if (reinit) { + mcfile.open(logFilePath, std::ios::app); + mcfile << "restart fork a process" << std::endl; + } else { + mcfile.open(logFilePath); + mcfile << "start fork a process" << std::endl; + } +#endif + + static bool startupPie = s_start_pie; + LOGE("startupPie :%d", startupPie); + + pid_t child; + if (reinit) { +#if PRINT_LOG_CACHEFILE + mcfile << "reinit is ture use vfork" << std::endl; + mcfile.close(); +#endif + child = vfork(); + } else { +#if PRINT_LOG_CACHEFILE + mcfile << "reinit is false use fork" << std::endl; + mcfile.close(); +#endif + child = fork(); + } + if (child == -1) { + int myerrno = errno; + munmap(base, IPCFutexPageQueue::ipc_size); + close(fd); + throw IPCException("failed to fork: %s", strerror(myerrno)); + } else if (child == 0) { + // the child + closeAllButThis(fd); + // implements close all but handles[1] + // do exec + doExec(fd, true, startupPie); + LOGE("exec Failed completely."); + // failed to exec + _exit(1); + } else { + printLogOnFile("fork success on main process and start m_impl->futexPageQueue->spinWaitPeer()"); + close(fd); + m_impl->child = child; + try { + m_impl->futexPageQueue->spinWaitPeer(); + } catch (IPCException &e) { + LOGE("WeexJSConnection catch: %s", e.msg()); + // TODO throw exception + return nullptr; + } + } + return m_impl->serverSender.get(); +} + +void WeexJSConnection::end() { + m_impl->serverSender.reset(); + m_impl->futexPageQueue.reset(); + if (m_impl->child) { + int wstatus; + pid_t child; + kill(m_impl->child, 9); + while (true) { + child = waitpid(m_impl->child, &wstatus, 0); + if (child != -1) + break; + if (errno != EINTR) + break; + } + } +} + +void printLogOnFile(const char *log) { +#if PRINT_LOG_CACHEFILE + std::ofstream mcfile; + mcfile.open(logFilePath, std::ios::app); + mcfile << log << std::endl; + mcfile.close(); +#endif +} + +static std::string __attribute__((noinline)) findPath(); + +static void findPath(std::string &executablePath, std::string &icuDataPath) { + unsigned long target = reinterpret_cast<unsigned long>(__builtin_return_address(0)); + FILE *f = fopen("/proc/self/maps", "r"); + if (!f) { + return; + } + char buffer[256]; + char *line; + while ((line = fgets(buffer, 256, f))) { + if (icuDataPath.empty() && strstr(line, "icudt")) { + icuDataPath.assign(strstr(line, "/")); + icuDataPath = icuDataPath.substr(0, icuDataPath.length() - 1); + continue; + } + char *end; + unsigned long val; + errno = 0; + val = strtoul(line, &end, 16); + if (errno) + continue; + if (val > target) + continue; + end += 1; + errno = 0; + val = strtoul(end, &end, 16); + if (errno) + continue; + if (val > target) { + executablePath.assign(strstr(end, "/")); + std::size_t found = executablePath.rfind('/'); + if (found != std::string::npos) { + executablePath = executablePath.substr(0, found); + } + } + if (!executablePath.empty() + && !icuDataPath.empty()) { + break; + } + } + fclose(f); + return; +} + +class EnvPBuilder { +public: + EnvPBuilder(); + + ~EnvPBuilder() = default; + + void addNew(const char *n); + + std::unique_ptr<const char *[]> build(); + +private: + std::vector<const char *> m_vec; +}; + +EnvPBuilder::EnvPBuilder() { + for (char **env = environ; *env; env++) { + // fixme:add for ANDROID_ROOT envp + // if cannot find some env, can use such as + // PATH/ANDROID_BOOTLOGO/ANDROID_ASSETS/ANDROID_DATA/ASEC_MOUNTPOINT + // LOOP_MOUNTPOINT/BOOTCLASSPATH and etc + // but don't use LD_LIBRARY_PATH env may cause so cannot be found + const char *android_root_env = "ANDROID_ROOT="; + if (strstr(*env, android_root_env) != nullptr) { + addNew(*env); + break; + } + } +} + +void EnvPBuilder::addNew(const char *n) { + m_vec.emplace_back(n); +} + +std::unique_ptr<const char *[]> EnvPBuilder::build() { + std::unique_ptr<const char *[]> ptr(new const char *[m_vec.size() + 1]); + for (size_t i = 0; i < m_vec.size(); ++i) { + ptr.get()[i] = m_vec[i]; + } + ptr.get()[m_vec.size()] = nullptr; + return ptr; +} + +void doExec(int fd, bool traceEnable, bool startupPie) { + std::string executablePath; + std::string icuDataPath; + findPath(executablePath, icuDataPath); +#if PRINT_LOG_CACHEFILE + std::ofstream mcfile; + mcfile.open(logFilePath, std::ios::app); + mcfile << "jsengine WeexJSConnection::doExec executablePath:" << executablePath << std::endl; + mcfile << "jsengine WeexJSConnection::doExec icuDataPath:" << icuDataPath << std::endl; +#endif + + if (executablePath.empty()) { + LOGE("executablePath is empty"); + +#if PRINT_LOG_CACHEFILE + mcfile << "jsengine WeexJSConnection::doExec executablePath is empty and return" << std::endl; + mcfile.close(); +#endif + + return; + } + if (icuDataPath.empty()) { + LOGE("icuDataPath is empty"); +#if PRINT_LOG_CACHEFILE + mcfile << "jsengine WeexJSConnection::doExec icuDataPath is empty and return" << std::endl; + mcfile.close(); +#endif + return; + } + std::string ldLibraryPathEnv("LD_LIBRARY_PATH="); + std::string icuDataPathEnv("ICU_DATA_PATH="); + std::string crashFilePathEnv("CRASH_FILE_PATH="); + ldLibraryPathEnv.append(executablePath); + icuDataPathEnv.append(icuDataPath); +#if PRINT_LOG_CACHEFILE + mcfile << "jsengine ldLibraryPathEnv:" << ldLibraryPathEnv << " icuDataPathEnv:" << icuDataPathEnv + << std::endl; +#endif + if (!s_cacheDir) { + crashFilePathEnv.append("/data/data/com.taobao.taobao/cache"); + } else { + crashFilePathEnv.append(s_cacheDir); + } + crashFilePathEnv.append("/jsserver_crash"); + char fdStr[16]; + snprintf(fdStr, 16, "%d", fd); + EnvPBuilder envpBuilder; + envpBuilder.addNew(ldLibraryPathEnv.c_str()); + envpBuilder.addNew(icuDataPathEnv.c_str()); + envpBuilder.addNew(crashFilePathEnv.c_str()); + auto envp = envpBuilder.build(); + { + std::string executableName = executablePath + '/' + "libweexjsb64.so"; + chmod(executableName.c_str(), 0755); + const char *argv[] = {executableName.c_str(), fdStr, traceEnable ? "1" : "0", nullptr}; + if (-1 == execve(argv[0], const_cast<char *const *>(&argv[0]), + const_cast<char *const *>(envp.get()))) { + } + } + + std::string start_so = ""; + if (startupPie) { + start_so = "libweexjsb.so"; + } else { + start_so = "libweexjst.so"; + } + + { + std::string executableName = executablePath + '/' + start_so; + chmod(executableName.c_str(), 0755); + int result = access(executableName.c_str(), 01); + +#if PRINT_LOG_CACHEFILE + mcfile << "jsengine WeexJSConnection::doExec file exsist result:" + << result << " startupPie:" << startupPie << std::endl; +#endif + if (result == -1) { + executableName = std::string(s_cacheDir) + '/' + start_so; + int result_cache = access(executableName.c_str(), 00); + if (result_cache == -1) { + std::string sourceSo = executablePath + '/' + start_so; + int ret = copyFile(sourceSo.c_str(), executableName.c_str()); +#if PRINT_LOG_CACHEFILE + mcfile << "jsengine WeexJSConnection::doExec copy so from:" << sourceSo + << " to:" << executableName << ", success: " << ret << std::endl; +#endif + } + chmod(executableName.c_str(), 0755); +#if PRINT_LOG_CACHEFILE + mcfile << "jsengine WeexJSConnection::doExec start path on sdcard, start execve so name:" + << executableName << std::endl; +#endif + const char *argv[] = {executableName.c_str(), fdStr, traceEnable ? "1" : "0", nullptr}; + if (-1 == execve(argv[0], const_cast<char *const *>(&argv[0]), + const_cast<char *const *>(envp.get()))) { +#if PRINT_LOG_CACHEFILE + mcfile << "execve failed11:" << strerror(errno) << std::endl; +#endif + } + } else { + // std::string executableName = executablePath + '/' + "libweexjsb.so"; + chmod(executableName.c_str(), 0755); +#if PRINT_LOG_CACHEFILE + mcfile << "jsengine WeexJSConnection::doExec start execve so name:" << executableName + << std::endl; +#endif + const char *argv[] = {executableName.c_str(), fdStr, traceEnable ? "1" : "0", nullptr}; + if (-1 == execve(argv[0], const_cast<char *const *>(&argv[0]), + const_cast<char *const *>(envp.get()))) { +#if PRINT_LOG_CACHEFILE + mcfile << "execve failed:" << strerror(errno) << std::endl; +#endif + } + } + + } +#if PRINT_LOG_CACHEFILE + mcfile.close(); +#endif +} + +static void closeAllButThis(int exceptfd) { + DIR *dir = opendir("/proc/self/fd"); + if (!dir) { + return; + } + int dirFd = dirfd(dir); + struct dirent *cur; + struct timespec start; + clock_gettime(CLOCK_MONOTONIC, &start); + while ((cur = readdir(dir))) { + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + if ((now.tv_sec - start.tv_sec) > 6) { + break; + } + if (!strcmp(cur->d_name, ".") + || !strcmp(cur->d_name, "..")) { + continue; + } + errno = 0; + unsigned long curFd = strtoul(cur->d_name, nullptr, 10); + if (errno) + continue; + if (curFd <= 2) + continue; + if ((curFd != dirFd) && (curFd != exceptfd)) { + close(curFd); + } + } + closedir(dir); +} + +int copyFile(const char *SourceFile, const char *NewFile) { + std::ifstream in; + std::ofstream out; + in.open(SourceFile, std::ios::binary); + if (in.fail()) { + in.close(); + out.close(); + return 0; + } + out.open(NewFile, std::ios::binary); + if (out.fail()) { + out.close(); + in.close(); + return 0; + } else { + out << in.rdbuf(); + out.close(); + in.close(); + return 1; + } +} http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/2f8caedb/weex_core/Source/android/jsengine/multiprocess/WeexJSConnection.h ---------------------------------------------------------------------- diff --git a/weex_core/Source/android/jsengine/multiprocess/WeexJSConnection.h b/weex_core/Source/android/jsengine/multiprocess/WeexJSConnection.h new file mode 100644 index 0000000..e09a51c --- /dev/null +++ b/weex_core/Source/android/jsengine/multiprocess/WeexJSConnection.h @@ -0,0 +1,25 @@ +#ifndef WEEXJSCONNECTION_H +#define WEEXJSCONNECTION_H + +#include <memory> + +class IPCSender; +class IPCHandler; + +class WeexJSConnection { +public: + WeexJSConnection(); + + ~WeexJSConnection(); + + IPCSender *start(IPCHandler *handler, bool reinit = false); + + void end(); + +private: + struct WeexJSConnectionImpl; + + std::unique_ptr<WeexJSConnectionImpl> m_impl; +}; + +#endif /* WEEXJSCONNECTION_H */ http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/2f8caedb/weex_core/Source/android/jsengine/multiprocess/WeexProxy.cpp ---------------------------------------------------------------------- diff --git a/weex_core/Source/android/jsengine/multiprocess/WeexProxy.cpp b/weex_core/Source/android/jsengine/multiprocess/WeexProxy.cpp new file mode 100644 index 0000000..5bb2a8a --- /dev/null +++ b/weex_core/Source/android/jsengine/multiprocess/WeexProxy.cpp @@ -0,0 +1,690 @@ +// Copyright [2017-12-07] <WeexCore> +#include "WeexProxy.h" + +#include <android/base/log_utils.h> +#include <android/base/string/string_utils.h> +#include <core/config/core_environment.h> +#include <android/jsengine/multiprocess/ExtendJSApi.h> + + +const char *s_cacheDir; +bool s_start_pie = true; + +static IPCSender *sSender; +static std::unique_ptr <IPCHandler> sHandler; +static std::unique_ptr <WeexJSConnection> sConnection; + + +namespace WeexCore { +void WeexProxy::reset() { + sConnection.reset(); + sHandler.reset(); +} + +jint WeexProxy::doInitFramework(JNIEnv *env, jobject object, + jstring script, jobject params, + jstring cacheDir, jboolean pieSupport) { + const char *cache = env->GetStringUTFChars( + reinterpret_cast<jstring>(cacheDir), nullptr); + if (strlen(cache) > 0) { + s_cacheDir = cache; + } + s_start_pie = pieSupport; + return doInitFramework(env, jThis, script, params); +} + +jint WeexProxy::doInitFramework(JNIEnv *env, + jobject object, + jstring script, + jobject params) { + bool reinit = false; + startInitFrameWork: + try { + sHandler = std::move(createIPCHandler()); + sConnection.reset(new WeexJSConnection()); + sSender = sConnection->start(sHandler.get(), reinit); + if (sSender == nullptr) { + LOGE("JSFreamwork init start sender is null"); + if (!reinit) { + reinit = true; + goto startInitFrameWork; + } else { + return false; + } + } else { + // initHandler(sHandler.get()); + ExtendJSApi *pExtensionJSApi = new ExtendJSApi(); + Bridge_Impl_Android::getInstance()->setGlobalRef(jThis); + pExtensionJSApi->initFunction(sHandler.get()); + + // using base::debug::TraceEvent; + // TraceEvent::StartATrace(env); + std::unique_ptr <IPCSerializer> serializer(createIPCSerializer()); + serializer->setMsg(static_cast<uint32_t>(IPCJSMsg::INITFRAMEWORK)); + initFromParam(env, script, params, serializer.get()); + std::unique_ptr <IPCBuffer> buffer = serializer->finish(); + std::unique_ptr <IPCResult> result = sSender->send(buffer.get()); + if (result->getType() != IPCType::INT32) { + LOGE("initFramework Unexpected result type"); + reportException("", "initFramework", + "error, initFramework Unexpected result type"); + return false; + } + return result->get<jint>(); + } + } catch (IPCException &e) { + LOGE("WeexProxy catchï¼%s", e.msg()); + if (!reinit) { + reinit = true; + goto startInitFrameWork; + } else { + LOGE("%s", e.msg()); + reportException("", "initFramework", e.msg()); + return false; + } + } +} + +bool WeexProxy::execJSService(JNIEnv *env, jobject object, jstring script) { + if (!sSender) { + LOGE("have not connected to a js server"); + return false; + } + try { + std::unique_ptr <IPCSerializer> serializer(createIPCSerializer()); + serializer->setMsg(static_cast<uint32_t>(IPCJSMsg::EXECJSSERVICE)); + addString(env, serializer.get(), script); + std::unique_ptr <IPCBuffer> buffer = serializer->finish(); + std::unique_ptr <IPCResult> result = sSender->send(buffer.get()); + if (result->getType() != IPCType::INT32) { + LOGE("execJSService Unexpected result type"); + return false; + } + return result->get<jint>(); + } catch (IPCException &e) { + LOGE("%s", e.msg()); + return false; + } + return true; +} + +bool WeexProxy::execJS(JNIEnv *env, + jobject jthis, + jstring jinstanceid, + jstring jnamespace, + jstring jfunction, + jobjectArray jargs) { + std::string mMessage = ""; + if (!sSender) { + LOGE("have not connected to a js server"); + return false; + } + int length = 0; + if (jargs != NULL) { + length = env->GetArrayLength(jargs); + } + try { + std::unique_ptr <IPCSerializer> serializer(createIPCSerializer()); + serializer->setMsg(static_cast<uint32_t>(IPCJSMsg::EXECJS)); + addString(env, serializer.get(), jinstanceid); + if (jnamespace) { + addString(env, serializer.get(), jnamespace); + } else { + uint16_t tmp = 0; + serializer->add(&tmp, 0); + } + addString(env, serializer.get(), jfunction); + + for (int i = 0; i < length; i++) { + jobject jArg = env->GetObjectArrayElement(jargs, i); + + jfieldID jTypeId = env->GetFieldID(jWXJSObject, "type", "I"); + jint jTypeInt = env->GetIntField(jArg, jTypeId); + + jfieldID jDataId = env->GetFieldID(jWXJSObject, + "data", "Ljava/lang/Object;"); + jobject jDataObj = env->GetObjectField(jArg, jDataId); + if (jTypeInt == 1) { + if (jDoubleValueMethodId == NULL) { + jclass jDoubleClazz = env->FindClass("java/lang/Double"); + jDoubleValueMethodId = env->GetMethodID(jDoubleClazz, + "doubleValue", "()D"); + env->DeleteLocalRef(jDoubleClazz); + } + jdouble jDoubleObj = env->CallDoubleMethod(jDataObj, + jDoubleValueMethodId); + serializer->add(jDoubleObj); + + } else if (jTypeInt == 2) { + jstring jDataStr = (jstring) jDataObj; + addString(env, serializer.get(), jDataStr); + } else if (jTypeInt == 3) { + jstring jDataStr = (jstring) jDataObj; + addJSONString(env, serializer.get(), jDataStr); + } else { + serializer->addJSUndefined(); + } + env->DeleteLocalRef(jDataObj); + env->DeleteLocalRef(jArg); + } + + std::unique_ptr <IPCBuffer> buffer = serializer->finish(); + + std::unique_ptr <IPCResult> result = sSender->send(buffer.get()); + + if (result->getType() != IPCType::INT32) { + LOGE("execJS Unexpected result type"); + return false; + } + + return result->get<jint>(); + } catch (IPCException &e) { + LOGE("%s", e.msg()); + // report crash here + WeexProxy::reportServerCrash(jinstanceid); + return false; + } + return true; +} + + +void WeexProxy::initFromParam(JNIEnv *env, + jstring script, + jobject params, + IPCSerializer *serializer) { + { + ScopedJString scopedString(env, script); + const jchar *chars = scopedString.getChars(); + int charLength = scopedString.getCharsLength(); + serializer->add(chars, charLength); + } +#define ADDSTRING(name) \ + { \ + const char* myname = #name; \ + serializer->add(myname, strlen(myname)); \ + ScopedJStringUTF8 scopedString(env, (jstring)name); \ + const char* chars = scopedString.getChars(); \ + int charLength = strlen(chars); \ + serializer->add(chars, charLength); \ + } + jclass c_params = env->GetObjectClass(params); + + jmethodID m_platform = env->GetMethodID(c_params, + "getPlatform", + "()Ljava/lang/String;"); + jobject platform = env->CallObjectMethod(params, m_platform); + if (!WXCoreEnvironment::getInstance()->SetPlatform( + jString2StrFast(env, reinterpret_cast<jstring &>(platform)))) { + LOGD("setPlatform"); + } + ADDSTRING(platform); + + jmethodID m_osVersion = env->GetMethodID( + c_params, "getOsVersion", "()Ljava/lang/String;"); + jobject osVersion = env->CallObjectMethod(params, m_osVersion); + ADDSTRING(osVersion); + + // use param ti get cacheDir + jmethodID m_cacheMethod = env->GetMethodID( + c_params, "getCacheDir", "()Ljava/lang/String;"); + if (m_cacheMethod != NULL) { + jobject cacheDir = env->CallObjectMethod(params, m_cacheMethod); + if (cacheDir != NULL) { + ADDSTRING(cacheDir); + } + } + + jmethodID m_appVersion = env->GetMethodID( + c_params, "getAppVersion", "()Ljava/lang/String;"); + jobject appVersion = env->CallObjectMethod(params, m_appVersion); + ADDSTRING(appVersion); + + jmethodID m_weexVersion = env->GetMethodID( + c_params, "getWeexVersion", "()Ljava/lang/String;"); + jobject weexVersion = env->CallObjectMethod(params, m_weexVersion); + ADDSTRING(weexVersion); + + jmethodID m_deviceModel = env->GetMethodID( + c_params, "getDeviceModel", "()Ljava/lang/String;"); + jobject deviceModel = env->CallObjectMethod(params, m_deviceModel); + ADDSTRING(deviceModel); + + jmethodID m_appName = env->GetMethodID( + c_params, "getAppName", "()Ljava/lang/String;"); + jobject appName = env->CallObjectMethod(params, m_appName); + ADDSTRING(appName); + + jmethodID m_deviceWidth = env->GetMethodID( + c_params, "getDeviceWidth", "()Ljava/lang/String;"); + jobject deviceWidth = env->CallObjectMethod(params, m_deviceWidth); + if (!WXCoreEnvironment::getInstance()->SetDeviceWidth( + jString2StrFast(env, reinterpret_cast<jstring &>(deviceWidth)))) { + LOGD("setDeviceWidth"); + } + ADDSTRING(deviceWidth); + + jmethodID m_deviceHeight = env->GetMethodID( + c_params, "getDeviceHeight", "()Ljava/lang/String;"); + jobject deviceHeight = env->CallObjectMethod(params, m_deviceHeight); + if (!WXCoreEnvironment::getInstance()->SetDeviceHeight( + jString2StrFast(env, reinterpret_cast<jstring &>(deviceHeight)))) { + LOGD("setDeviceHeight"); + } + ADDSTRING(deviceHeight); + + jmethodID m_options = env->GetMethodID( + c_params, "getOptions", "()Ljava/lang/Object;"); + jobject options = env->CallObjectMethod(params, m_options); + jclass jmapclass = env->FindClass("java/util/HashMap"); + jmethodID jkeysetmid = env->GetMethodID(jmapclass, + "keySet", + "()Ljava/util/Set;"); + jmethodID jgetmid = env->GetMethodID( + jmapclass, + "get", + "(Ljava/lang/Object;)Ljava/lang/Object;"); + jobject jsetkey = env->CallObjectMethod(options, jkeysetmid); + jclass jsetclass = env->FindClass("java/util/Set"); + jmethodID jtoArraymid = env->GetMethodID(jsetclass, + "toArray", + "()[Ljava/lang/Object;"); + jobjectArray jobjArray = + (jobjectArray) env->CallObjectMethod(jsetkey, jtoArraymid); + env->DeleteLocalRef(jsetkey); + if (jobjArray != NULL) { + jsize arraysize = env->GetArrayLength(jobjArray); + for (int i = 0; i < arraysize; i++) { + jstring jkey = (jstring) env->GetObjectArrayElement(jobjArray, i); + jstring jvalue = (jstring) env->CallObjectMethod(options, jgetmid, jkey); + + if (jkey != NULL) { + // const char* c_key = env->GetStringUTFChars(jkey, NULL); + // addString(vm, WXEnvironment, c_key, jString2String(env, jvalue)); + // serializer->add(c_key, strlen(c_key)); + // env->DeleteLocalRef(jkey); + // if (jvalue != NULL) { + // env->DeleteLocalRef(jvalue); + // } + ScopedJStringUTF8 c_key(env, jkey); + ScopedJStringUTF8 c_value(env, jvalue); + const char *c_key_chars = c_key.getChars(); + int c_key_len = strlen(c_key_chars); + const char *c_value_chars = c_value.getChars(); + int c_value_len = strlen(c_value_chars); + serializer->add(c_key_chars, c_key_len); + serializer->add(c_value_chars, c_value_len); + WXCoreEnvironment::getInstance()->AddOption(jString2Str(env, jkey), jString2Str(env, jvalue)); + } + } + env->DeleteLocalRef(jobjArray); + } + env->DeleteLocalRef(options); +} + +void +WeexProxy::reportException(const char *instanceID, + const char *func, + const char *exception_string) { + JNIEnv *env = getJNIEnv(); + jstring jExceptionString = env->NewStringUTF(exception_string); + jstring jInstanceId = env->NewStringUTF(instanceID); + jstring jFunc = env->NewStringUTF(func); + jmethodID tempMethodId = env->GetMethodID( + jBridgeClazz, + "reportJSException", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + env->CallVoidMethod(jThis, + tempMethodId, + jInstanceId, + jFunc, + jExceptionString); + env->DeleteLocalRef(jExceptionString); + env->DeleteLocalRef(jInstanceId); + env->DeleteLocalRef(jFunc); +} + +void WeexProxy::reportServerCrash(jstring jinstanceid) { + JNIEnv *env = getJNIEnv(); + jmethodID reportMethodId; + jstring crashFile; + std::string crashFileStr; + reportMethodId = env->GetMethodID(jBridgeClazz, + "reportServerCrash", + "(Ljava/lang/String;Ljava/lang/String;)V"); + if (!reportMethodId) + goto no_method; + + crashFileStr.assign("/jsserver_crash/jsserver_crash_info.log"); + + crashFile = env->NewStringUTF(crashFileStr.c_str()); + env->CallVoidMethod(jThis, reportMethodId, jinstanceid, crashFile); + env->DeleteLocalRef(crashFile); + no_method: + env->ExceptionClear(); +} + +const char *WeexProxy::getCacheDir(JNIEnv *env) { + jclass activityThreadCls, applicationCls, fileCls; + jobject applicationObj, fileObj, pathStringObj; + jmethodID currentApplicationMethodId, + getCacheDirMethodId, + getAbsolutePathMethodId; + static std::string storage; + const char *tmp; + const char *ret = nullptr; + if (!storage.empty()) { + ret = storage.c_str(); + goto no_empty; + } + activityThreadCls = env->FindClass("android/app/ActivityThread"); + if (!activityThreadCls || env->ExceptionOccurred()) { + goto no_class; + } + currentApplicationMethodId = env->GetStaticMethodID( + activityThreadCls, + "currentApplication", + "()Landroid/app/Application;"); + if (!currentApplicationMethodId || env->ExceptionOccurred()) { + goto no_currentapplication_method; + } + applicationObj = env->CallStaticObjectMethod(activityThreadCls, + currentApplicationMethodId, + nullptr); + if (!applicationObj || env->ExceptionOccurred()) { + goto no_application; + } + applicationCls = env->GetObjectClass(applicationObj); + getCacheDirMethodId = env->GetMethodID(applicationCls, + "getCacheDir", + "()Ljava/io/File;"); + if (!getCacheDirMethodId || env->ExceptionOccurred()) { + goto no_getcachedir_method; + } + fileObj = env->CallObjectMethod(applicationObj, getCacheDirMethodId, nullptr); + if (!fileObj || env->ExceptionOccurred()) { + goto no_file_obj; + } + fileCls = env->GetObjectClass(fileObj); + getAbsolutePathMethodId = env->GetMethodID(fileCls, + "getAbsolutePath", + "()Ljava/lang/String;"); + if (!getAbsolutePathMethodId || env->ExceptionOccurred()) { + goto no_getabsolutepath_method; + } + pathStringObj = env->CallObjectMethod(fileObj, + getAbsolutePathMethodId, + nullptr); + if (!pathStringObj || env->ExceptionOccurred()) { + goto no_path_string; + } + tmp = env->GetStringUTFChars(reinterpret_cast<jstring>(pathStringObj), + nullptr); + storage.assign(tmp); + env->ReleaseStringUTFChars(reinterpret_cast<jstring>(pathStringObj), + tmp); + ret = storage.c_str(); + no_path_string: + no_getabsolutepath_method: + env->DeleteLocalRef(fileCls); + env->DeleteLocalRef(fileObj); + no_file_obj: + no_getcachedir_method: + env->DeleteLocalRef(applicationCls); + env->DeleteLocalRef(applicationObj); + no_application: + no_currentapplication_method: + env->DeleteLocalRef(activityThreadCls); + no_class: + env->ExceptionDescribe(); + env->ExceptionClear(); + no_empty: + return ret; +} + +void WeexProxy::setCacheDir(JNIEnv *env) { + s_cacheDir = getCacheDir(env); +} + +jbyteArray WeexProxy::execJSWithResult(JNIEnv* env, jobject jthis, + jstring jinstanceid, + jstring jnamespace, + jstring jfunction, + jobjectArray jargs) { + if (!sSender) { + LOGE("have not connected to a js server"); + return NULL; + } + if (jfunction == NULL || jinstanceid == NULL) { + LOGE("native_execJS function is NULL"); + return NULL; + } + + int length = 0; + if (jargs != NULL) { + length = env->GetArrayLength(jargs); + } + try { + std::unique_ptr<IPCSerializer> serializer(createIPCSerializer()); + serializer->setMsg(static_cast<uint32_t>(IPCJSMsg::EXECJSWITHRESULT)); + addString(env, serializer.get(), jinstanceid); + if (jnamespace) + addString(env, serializer.get(), jnamespace); + else { + uint16_t tmp = 0; + serializer->add(&tmp, 0); + } + addString(env, serializer.get(), jfunction); + + for (int i = 0; i < length; i++) { + jobject jArg = env->GetObjectArrayElement(jargs, i); + + jfieldID jTypeId = env->GetFieldID(jWXJSObject, "type", "I"); + jint jTypeInt = env->GetIntField(jArg, jTypeId); + + jfieldID jDataId = env->GetFieldID(jWXJSObject, "data", "Ljava/lang/Object;"); + jobject jDataObj = env->GetObjectField(jArg, jDataId); + if (jTypeInt == 1) { + if (jDoubleValueMethodId == NULL) { + jclass jDoubleClazz = env->FindClass("java/lang/Double"); + jDoubleValueMethodId = env->GetMethodID(jDoubleClazz, "doubleValue", "()D"); + env->DeleteLocalRef(jDoubleClazz); + } + jdouble jDoubleObj = env->CallDoubleMethod(jDataObj, jDoubleValueMethodId); + serializer->add(jDoubleObj); + + } else if (jTypeInt == 2) { + jstring jDataStr = (jstring)jDataObj; + addString(env, serializer.get(), jDataStr); + } else if (jTypeInt == 3) { + jstring jDataStr = (jstring)jDataObj; + addJSONString(env, serializer.get(), jDataStr); + } else { + serializer->addJSUndefined(); + } + env->DeleteLocalRef(jDataObj); + env->DeleteLocalRef(jArg); + } + std::unique_ptr<IPCBuffer> buffer = serializer->finish(); + std::unique_ptr<IPCResult> result = sSender->send(buffer.get()); + if (result->getType() != IPCType::BYTEARRAY) { + return NULL; + } + if(result->getByteArrayLength() == 0){ + return NULL; + } + jbyteArray array = env->NewByteArray(result->getByteArrayLength()); + env->SetByteArrayRegion(array, 0, result->getByteArrayLength(), reinterpret_cast<const jbyte*>(result->getByteArrayContent())); + return array; + } catch (IPCException& e) { + LOGE("%s", e.msg()); + // report crash here + reportServerCrash(jinstanceid); + return NULL; + } + return NULL; +} + +void WeexProxy::updateGlobalConfig(JNIEnv *env, jobject jcaller, jstring config) { + if (!sSender) { + LOGE("have not connected to a js server"); + return; + } + if (config == NULL) { + LOGE("native_execJS function is NULL"); + return; + } + try { + std::unique_ptr<IPCSerializer> serializer(createIPCSerializer()); + serializer->setMsg(static_cast<uint32_t>(IPCJSMsg::UPDATEGLOBALCONFIG)); + addString(env, serializer.get(), config); + std::unique_ptr<IPCBuffer> buffer = serializer->finish(); + std::unique_ptr<IPCResult> result = sSender->send(buffer.get()); + } catch (IPCException& e) { + LOGE("%s", e.msg()); + } +} + +static jstring getJsonData(JNIEnv *env, jobjectArray jargs, int index) { + int length = 0; + if (jargs != NULL) { + length = env->GetArrayLength(jargs); + } + jstring ret = NULL; + if (length < (index + 1)) { + return ret; + } + jobject jArg = env->GetObjectArrayElement(jargs, index); + + jfieldID jTypeId = env->GetFieldID(jWXJSObject, "type", "I"); + jint jTypeInt = env->GetIntField(jArg, jTypeId); + jfieldID jDataId = env->GetFieldID(jWXJSObject, "data", "Ljava/lang/Object;"); + jobject jDataObj = env->GetObjectField(jArg, jDataId); + if (jTypeInt == 3) { + ret = (jstring) jDataObj; + } + // env->DeleteLocalRef(jDataObj); + env->DeleteLocalRef(jArg); + return ret; +} + +jint +WeexProxy::createInstanceContext(JNIEnv *env, jobject jcaller, jstring jinstanceid, jstring name, + jstring jfunction, jobjectArray jargs) { + if (!sSender) { + LOGE("have not connected to a js server"); + return false; + } + if (jfunction == NULL || jinstanceid == NULL) { + LOGE("native_createInstanceContext function is NULL"); + return false; + } + + int length = 0; + if (jargs != NULL) { + length = env->GetArrayLength(jargs); + } + if (length < 4) { + LOGE("native_createInstanceContext jargs format error"); + return false; + } + try { + std::unique_ptr<IPCSerializer> serializer(createIPCSerializer()); + serializer->setMsg(static_cast<uint32_t>(IPCJSMsg::CREATEINSTANCE)); + addString(env, serializer.get(), jinstanceid); + addString(env, serializer.get(), jfunction); + + // get temp data, such as js bundle + jobject jArg = env->GetObjectArrayElement(jargs,1); + jfieldID jDataId = env->GetFieldID(jWXJSObject, "data", "Ljava/lang/Object;"); + jobject jDataObj = env->GetObjectField(jArg, jDataId); + jstring jscript = (jstring) jDataObj; + addString(env, serializer.get(), jscript); + jstring opts = getJsonData(env, jargs, 2); + addJSONString(env, serializer.get(), opts); + // init jsonData + jstring initData = getJsonData(env, jargs, 3); + addJSONString(env, serializer.get(), initData); + + // get extend api data, such as rax-api + jArg = env->GetObjectArrayElement(jargs, 4); + jDataObj = env->GetObjectField(jArg, jDataId); + jstring japi = (jstring) jDataObj; + addString(env, serializer.get(), japi); + + std::unique_ptr<IPCBuffer> buffer = serializer->finish(); + std::unique_ptr<IPCResult> result = sSender->send(buffer.get()); + env->DeleteLocalRef(jArg); + env->DeleteLocalRef(jDataObj); + env->DeleteLocalRef(opts); + if (result->getType() != IPCType::INT32) { + LOGE("createInstanceContext Unexpected result type"); + return false; + } + return result->get<jint>(); + } catch (IPCException& e) { + LOGE("%s", e.msg()); + // report crash here + reportServerCrash(jinstanceid); + return false; + } + return true; +} + +jint WeexProxy::destoryInstance(JNIEnv *env, jobject jcaller, jstring jinstanceid, jstring jnamespace, + jstring jfunction, jobjectArray jargs) { + int ret = execJS(env, nullptr, jinstanceid, jnamespace, jfunction, jargs); + if (jfunction == NULL || jinstanceid == NULL) { + LOGE("native_destoryInstance function is NULL"); + return false; + } + try { + std::unique_ptr<IPCSerializer> serializer(createIPCSerializer()); + serializer->setMsg(static_cast<uint32_t>(IPCJSMsg::DESTORYINSTANCE)); + addString(env, serializer.get(), jinstanceid); + + std::unique_ptr<IPCBuffer> buffer = serializer->finish(); + std::unique_ptr<IPCResult> result = sSender->send(buffer.get()); + if (result->getType() != IPCType::INT32) { + LOGE("destoryInstance Unexpected result type"); + return false; + } + return result->get<jint>(); + } catch (IPCException& e) { + LOGE("%s", e.msg()); + // report crash here + reportServerCrash(jinstanceid); + return false; + } + return true; +} + +jstring +WeexProxy::execJSOnInstance(JNIEnv *env, jobject jcaller, jstring instanceId, jstring script, + jint type) { + if (instanceId == NULL || script == NULL) { + return env->NewStringUTF(""); + } + try { + // base::debug::TraceScope traceScope("weex", "native_execJSOnInstance"); + std::unique_ptr<IPCSerializer> serializer(createIPCSerializer()); + serializer->setMsg(static_cast<uint32_t>(IPCJSMsg::EXECJSONINSTANCE)); + + addString(env, serializer.get(), instanceId); + addString(env, serializer.get(), script); + + std::unique_ptr<IPCBuffer> buffer = serializer->finish(); + std::unique_ptr<IPCResult> result = sSender->send(buffer.get()); + if (result->getType() != IPCType::BYTEARRAY) { + // LOGE("native_execJSOnInstance return type error"); + return env->NewStringUTF(""); + } + return env->NewStringUTF(result->getByteArrayContent()); + } catch (IPCException& e) { + LOGE("%s", e.msg()); + // report crash here + reportServerCrash(instanceId); + return env->NewStringUTF(""); + } +} + +} // namespace WeexCore http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/2f8caedb/weex_core/Source/android/jsengine/multiprocess/WeexProxy.h ---------------------------------------------------------------------- diff --git a/weex_core/Source/android/jsengine/multiprocess/WeexProxy.h b/weex_core/Source/android/jsengine/multiprocess/WeexProxy.h new file mode 100644 index 0000000..942f619 --- /dev/null +++ b/weex_core/Source/android/jsengine/multiprocess/WeexProxy.h @@ -0,0 +1,76 @@ +#ifndef _WEEX_PROXY_H_ +#define _WEEX_PROXY_H_ + + +#include <jni.h> +#include <unistd.h> +#include <IPC/Serializing/IPCSerializer.h> +#include <IPC/IPCHandler.h> +#include <android/bridge/impl/bridge_impl_android.h> +#include <IPC/Buffering/IPCBuffer.h> +#include <IPC/IPCArguments.h> +#include <IPC/IPCByteArray.h> +#include <IPC/IPCException.h> +#include <IPC/IPCHandler.h> +#include <IPC/IPCMessageJS.h> +#include <IPC/IPCResult.h> +#include <IPC/IPCSender.h> +#include <IPC/IPCString.h> +#include <IPC/Serializing/IPCSerializer.h> + +namespace WeexCore { + +class WeexProxy { +private: +public: + static void reset(); + + static jint doInitFramework(JNIEnv *env, jobject object, jstring script, jobject params, + jstring cacheDir, jboolean pieSupport); + + static jint doInitFramework(JNIEnv *env, jobject object, jstring script, jobject params); + + static void + initFromParam(JNIEnv *env, jstring script, jobject params, IPCSerializer *serializer); + + static const char *getCacheDir(JNIEnv *env); + + static void setCacheDir(JNIEnv *env); + + static bool execJSService(JNIEnv *env, jobject object, jstring script); + + static bool + execJS(JNIEnv *env, jobject jthis, jstring jinstanceid, jstring jnamespace, jstring jfunction, + jobjectArray jargs); + + static void + reportException(const char *instanceID, const char *func, const char *exception_string); + + static void reportServerCrash(jstring jinstanceid); + + static jbyteArray execJSWithResult(JNIEnv* env, jobject jthis, + jstring jinstanceid, + jstring jnamespace, + jstring jfunction, + jobjectArray jargs); + + static void updateGlobalConfig(JNIEnv* env, jobject jcaller, + jstring config); + static jint createInstanceContext(JNIEnv* env, jobject jcaller, jstring instanceId, + jstring name, + jstring function, + jobjectArray args); + + static jint destoryInstance(JNIEnv* env, jobject jcaller, + jstring instanceId, + jstring name, + jstring function, + jobjectArray args); + + static jstring execJSOnInstance(JNIEnv* env, jobject jcaller, + jstring instanceId, + jstring script, + jint type); +}; +} +#endif //_WEEX_PROXY_H_ http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/2f8caedb/weex_core/Source/base/Compatible.cpp ---------------------------------------------------------------------- diff --git a/weex_core/Source/base/Compatible.cpp b/weex_core/Source/base/Compatible.cpp new file mode 100644 index 0000000..3fb0e5c --- /dev/null +++ b/weex_core/Source/base/Compatible.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <ctype.h> +#include <errno.h> +#include <grp.h> +#include <math.h> +#include <mntent.h> +#include <netdb.h> +#include <pthread.h> +#include <pwd.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +namespace WeexCore { +int sigemptyset(sigset_t *set) { + if (set == NULL) { + errno = EINVAL; + return -1; + } + memset(set, 0, sizeof(sigset_t)); + return 0; +} + +int sigfillset(sigset_t *set) { + if (set == NULL) { + errno = EINVAL; + return -1; + } + memset(set, ~0, sizeof(sigset_t)); + return 0; +} + +int sigaddset(sigset_t *set, int signum) { + int bit = signum - 1; // Signal numbers start at 1, but bit positions start at 0. + unsigned long *local_set = reinterpret_cast<unsigned long *>(set); + if (set == NULL || bit < 0 || bit >= static_cast<int>(8 * sizeof(sigset_t))) { + errno = EINVAL; + return -1; + } + local_set[bit / LONG_BIT] |= 1UL << (bit % LONG_BIT); + return 0; +} + +int sigdelset(sigset_t *set, int signum) { + int bit = signum - 1; // Signal numbers start at 1, but bit positions start at 0. + unsigned long *local_set = reinterpret_cast<unsigned long *>(set); + if (set == NULL || bit < 0 || bit >= static_cast<int>(8 * sizeof(sigset_t))) { + errno = EINVAL; + return -1; + } + local_set[bit / LONG_BIT] &= ~(1UL << (bit % LONG_BIT)); + return 0; +} + +int getpagesize() { + // We dont use sysconf(3) here because that drags in stdio, which makes static binaries fat. + return PAGE_SIZE; +} + +void srandom(unsigned int __s) { srand48(__s); } + +int isinf(double n) { + return __builtin_isinf(n); +} + +int posix_memalign(void **memptr, size_t alignment, size_t bytes) { + if (!memptr) + return EINVAL; + *memptr = memalign(alignment, bytes); + if (!*memptr) + return ENOMEM; + return 0; +} + +int sigismember(const sigset_t *set, int signum) { + int bit = signum - 1; // Signal numbers start at 1, but bit positions start at 0. + const unsigned long *local_set = reinterpret_cast<const unsigned long *>(set); + if (set == NULL || bit < 0 || bit >= static_cast<int>(8 * sizeof(sigset_t))) { + errno = EINVAL; + return -1; + } + return static_cast<int>((local_set[bit / LONG_BIT] >> (bit % LONG_BIT)) & 1); +} + +int abs(int j) { + return (j < 0 ? -j : j); +} + +long labs(long j) { + return (j < 0 ? -j : j); +} + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/2f8caedb/weex_core/Source/base/CoreConstants.h ---------------------------------------------------------------------- diff --git a/weex_core/Source/base/CoreConstants.h b/weex_core/Source/base/CoreConstants.h new file mode 100644 index 0000000..d918a7c --- /dev/null +++ b/weex_core/Source/base/CoreConstants.h @@ -0,0 +1,10 @@ + +#ifndef WEEXV8_CONSTANTSNAME_H +#define WEEXV8_CONSTANTSNAME_H + +#include <string> + +const std::string OS_Android = "android"; +const std::string OS_iOS = "iOS"; + +#endif //WEEXV8_CONSTANTSNAME_H http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/2f8caedb/weex_core/Source/base/TimeUtils.h ---------------------------------------------------------------------- diff --git a/weex_core/Source/base/TimeUtils.h b/weex_core/Source/base/TimeUtils.h new file mode 100644 index 0000000..072d9be --- /dev/null +++ b/weex_core/Source/base/TimeUtils.h @@ -0,0 +1,12 @@ +#ifndef WEEX_PROJECT_TIMEUTILS_H +#define WEEX_PROJECT_TIMEUTILS_H + +#include <sys/time.h> + +static long long getCurrentTime() { + struct timeval tv; + gettimeofday(&tv, NULL); + return (long long) tv.tv_sec * 1000 + (long long) tv.tv_usec / 1000; +} + +#endif //WEEX_PROJECT_TIMEUTILS_H http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/2f8caedb/weex_core/Source/base/ViewUtils.h ---------------------------------------------------------------------- diff --git a/weex_core/Source/base/ViewUtils.h b/weex_core/Source/base/ViewUtils.h new file mode 100644 index 0000000..624c510 --- /dev/null +++ b/weex_core/Source/base/ViewUtils.h @@ -0,0 +1,102 @@ +#ifndef WEEX_PROJECT_VIEWUTILS_H +#define WEEX_PROJECT_VIEWUTILS_H + +#include <core/config/core_environment.h> +#include <cmath> +#include <cstdlib> + +namespace WeexCore { + + const std::string WX("wx"); + const std::string PX("px"); + const std::string UNDEFINE("undefined"); + const std::string SCALE("scale"); + const std::string AUTO_UNIT("auto"); + const std::string NONE("none"); + + inline std::string &Trim(std::string &s) { + if (s.empty()) { + return s; + } + s.erase(0, s.find_first_not_of(" ")); + s.erase(s.find_last_not_of(" ") + 1); + return s; + } + + inline float getFloat(const char* src) { + char *end; + float ret = strtof(src, &end); + if(*end != '\0'){ + ret = NAN; + } + return ret; + } + + inline float getFloat(const float &src, const float &viewport) { + if (isnan(src)) + return NAN; + + float realPx = (src * WXCoreEnvironment::getInstance()->DeviceWidth() / + viewport); + float result = realPx > 0.005 && realPx < 1 ? 1 : rint(realPx); + return result; + } + + inline float getFloat(const std::string &src, const float &viewport) { + float ret = NAN; + if (UNDEFINE == src + || AUTO_UNIT == src + || NONE == src + || src.empty()) { + return ret; + } + float original_value = getFloat(src.c_str()); + ret = getFloat(original_value, viewport); + return ret; + } + + inline bool endWidth(const std::string &src, const std::string &suffix) { + return src.size() > suffix.size() && + src.compare(src.size() - suffix.size(), suffix.size(), suffix) == 0; + } + + inline float transferWx(const std::string &stringWithWXPostfix, const float &viewport) { + std::string temp = stringWithWXPostfix; + if (endWidth(stringWithWXPostfix, WX)) { + temp = stringWithWXPostfix.substr(0, stringWithWXPostfix.size() - WX.size()); + } + float f = getFloat(temp.c_str()); + float density = getFloat(WXCoreEnvironment::getInstance()->GetOption(SCALE).c_str()); + return density * f * viewport / WXCoreEnvironment::getInstance()->DeviceWidth(); + } + + inline static float getFloatByViewport(std::string src, const float &viewport) { + float ret = NAN; + if (UNDEFINE == src + || AUTO_UNIT == src + || NONE == src + || src.empty()) { + return ret; + } + Trim(src); + if (endWidth(src, WX)) { + ret = getFloat(transferWx(src, viewport), viewport); + } else if (endWidth(src, PX)) { + ret = getFloat(src.substr(0, src.size() - PX.size()), viewport); + } else { + ret = getFloat(src, viewport); + } + return ret; + } + + inline static float getWebPxByWidth(float pxValue, float customViewport) { + if (isnan(pxValue)) + return NAN; + + float realPx = (pxValue * customViewport / WXCoreEnvironment::getInstance()->DeviceWidth()); + float result = realPx > 0.005 && realPx < 1 ? 1 : rint(realPx); + return result; + } +} + +#endif //WEEX_PROJECT_VIEWUTILS_H http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/2f8caedb/weex_core/Source/base/fpconv.cpp ---------------------------------------------------------------------- diff --git a/weex_core/Source/base/fpconv.cpp b/weex_core/Source/base/fpconv.cpp new file mode 100755 index 0000000..3fbd55a --- /dev/null +++ b/weex_core/Source/base/fpconv.cpp @@ -0,0 +1,332 @@ +#include <stdbool.h> +#include <string.h> + +#include "fpconv.h" +#include "powers.h" + +#define fracmask 0x000FFFFFFFFFFFFFU +#define expmask 0x7FF0000000000000U +#define hiddenbit 0x0010000000000000U +#define signmask 0x8000000000000000U +#define expbias (1023 + 52) + +#define absv(n) ((n) < 0 ? -(n) : (n)) +#define minv(a, b) ((a) < (b) ? (a) : (b)) + +static uint64_t tens[] = { + 10000000000000000000U, 1000000000000000000U, 100000000000000000U, + 10000000000000000U, 1000000000000000U, 100000000000000U, + 10000000000000U, 1000000000000U, 100000000000U, + 10000000000U, 1000000000U, 100000000U, + 10000000U, 1000000U, 100000U, + 10000U, 1000U, 100U, + 10U, 1U +}; + +static inline uint64_t get_dbits(double d) +{ + union { + double dbl; + uint64_t i; + } dbl_bits = { d }; + + return dbl_bits.i; +} + +static Fp build_fp(double d) +{ + uint64_t bits = get_dbits(d); + + Fp fp; + fp.frac = bits & fracmask; + fp.exp = (bits & expmask) >> 52; + + if(fp.exp) { + fp.frac += hiddenbit; + fp.exp -= expbias; + + } else { + fp.exp = -expbias + 1; + } + + return fp; +} + +static void normalize(Fp* fp) +{ + while ((fp->frac & hiddenbit) == 0) { + fp->frac <<= 1; + fp->exp--; + } + + int shift = 64 - 52 - 1; + fp->frac <<= shift; + fp->exp -= shift; +} + +static void get_normalized_boundaries(Fp* fp, Fp* lower, Fp* upper) +{ + upper->frac = (fp->frac << 1) + 1; + upper->exp = fp->exp - 1; + + while ((upper->frac & (hiddenbit << 1)) == 0) { + upper->frac <<= 1; + upper->exp--; + } + + int u_shift = 64 - 52 - 2; + + upper->frac <<= u_shift; + upper->exp = upper->exp - u_shift; + + + int l_shift = fp->frac == hiddenbit ? 2 : 1; + + lower->frac = (fp->frac << l_shift) - 1; + lower->exp = fp->exp - l_shift; + + + lower->frac <<= lower->exp - upper->exp; + lower->exp = upper->exp; +} + +static Fp multiply(Fp* a, Fp* b) +{ + const uint64_t lomask = 0x00000000FFFFFFFF; + + uint64_t ah_bl = (a->frac >> 32) * (b->frac & lomask); + uint64_t al_bh = (a->frac & lomask) * (b->frac >> 32); + uint64_t al_bl = (a->frac & lomask) * (b->frac & lomask); + uint64_t ah_bh = (a->frac >> 32) * (b->frac >> 32); + + uint64_t tmp = (ah_bl & lomask) + (al_bh & lomask) + (al_bl >> 32); + /* round up */ + tmp += 1U << 31; + + Fp fp = { + ah_bh + (ah_bl >> 32) + (al_bh >> 32) + (tmp >> 32), + a->exp + b->exp + 64 + }; + + return fp; +} + +static void round_digit(char* digits, int ndigits, uint64_t delta, uint64_t rem, uint64_t kappa, uint64_t frac) +{ + while (rem < frac && delta - rem >= kappa && + (rem + kappa < frac || frac - rem > rem + kappa - frac)) { + + digits[ndigits - 1]--; + rem += kappa; + } +} + +static int generate_digits(Fp* fp, Fp* upper, Fp* lower, char* digits, int* K) +{ + uint64_t wfrac = upper->frac - fp->frac; + uint64_t delta = upper->frac - lower->frac; + + Fp one; + one.frac = 1ULL << -upper->exp; + one.exp = upper->exp; + + uint64_t part1 = upper->frac >> -one.exp; + uint64_t part2 = upper->frac & (one.frac - 1); + + int idx = 0, kappa = 10; + uint64_t* divp; + /* 1000000000 */ + for(divp = tens + 10; kappa > 0; divp++) { + + uint64_t div = *divp; + unsigned digit = part1 / div; + + if (digit || idx) { + digits[idx++] = digit + '0'; + } + + part1 -= digit * div; + kappa--; + + uint64_t tmp = (part1 <<-one.exp) + part2; + if (tmp <= delta) { + *K += kappa; + round_digit(digits, idx, delta, tmp, div << -one.exp, wfrac); + + return idx; + } + } + + /* 10 */ + uint64_t* unit = tens + 18; + + while(true) { + part2 *= 10; + delta *= 10; + kappa--; + + unsigned digit = part2 >> -one.exp; + if (digit || idx) { + digits[idx++] = digit + '0'; + } + + part2 &= one.frac - 1; + if (part2 < delta) { + *K += kappa; + round_digit(digits, idx, delta, part2, one.frac, wfrac * *unit); + + return idx; + } + + unit--; + } +} + +static int grisu2(double d, char* digits, int* K) +{ + Fp w = build_fp(d); + + Fp lower, upper; + get_normalized_boundaries(&w, &lower, &upper); + + normalize(&w); + + int k; + Fp cp = find_cachedpow10(upper.exp, &k); + + w = multiply(&w, &cp); + upper = multiply(&upper, &cp); + lower = multiply(&lower, &cp); + + lower.frac++; + upper.frac--; + + *K = -k; + + return generate_digits(&w, &upper, &lower, digits, K); +} + +static int emit_digits(char* digits, int ndigits, char* dest, int K, bool neg) +{ + int exp = absv(K + ndigits - 1); + + /* write plain integer */ + if(K >= 0 && (exp < (ndigits + 7))) { + memcpy(dest, digits, ndigits); + memset(dest + ndigits, '0', K); + + return ndigits + K; + } + + /* write decimal w/o scientific notation */ + if(K < 0 && (K > -7 || exp < 4)) { + int offset = ndigits - absv(K); + /* fp < 1.0 -> write leading zero */ + if(offset <= 0) { + offset = -offset; + dest[0] = '0'; + dest[1] = '.'; + memset(dest + 2, '0', offset); + memcpy(dest + offset + 2, digits, ndigits); + + return ndigits + 2 + offset; + + /* fp > 1.0 */ + } else { + memcpy(dest, digits, offset); + dest[offset] = '.'; + memcpy(dest + offset + 1, digits + offset, ndigits - offset); + + return ndigits + 1; + } + } + + /* write decimal w/ scientific notation */ + ndigits = minv(ndigits, 18 - neg); + + int idx = 0; + dest[idx++] = digits[0]; + + if(ndigits > 1) { + dest[idx++] = '.'; + memcpy(dest + idx, digits + 1, ndigits - 1); + idx += ndigits - 1; + } + + dest[idx++] = 'e'; + + char sign = K + ndigits - 1 < 0 ? '-' : '+'; + dest[idx++] = sign; + + int cent = 0; + + if(exp > 99) { + cent = exp / 100; + dest[idx++] = cent + '0'; + exp -= cent * 100; + } + if(exp > 9) { + int dec = exp / 10; + dest[idx++] = dec + '0'; + exp -= dec * 10; + + } else if(cent) { + dest[idx++] = '0'; + } + + dest[idx++] = exp % 10 + '0'; + + return idx; +} + +static int filter_special(double fp, char* dest) +{ + if(fp == 0.0) { + dest[0] = '0'; + return 1; + } + + uint64_t bits = get_dbits(fp); + + bool nan = (bits & expmask) == expmask; + + if(!nan) { + return 0; + } + + if(bits & fracmask) { + dest[0] = 'n'; dest[1] = 'a'; dest[2] = 'n'; + + } else { + dest[0] = 'i'; dest[1] = 'n'; dest[2] = 'f'; + } + + return 3; +} + +int fpconv_dtoa(double d, char dest[24]) +{ + char digits[18]; + + int str_len = 0; + bool neg = false; + + if(get_dbits(d) & signmask) { + dest[0] = '-'; + str_len++; + neg = true; + } + + int spec = filter_special(d, dest + str_len); + + if(spec) { + return str_len + spec; + } + + int K = 0; + int ndigits = grisu2(d, digits, &K); + + str_len += emit_digits(digits, ndigits, dest + str_len, K, neg); + + return str_len; +} http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/2f8caedb/weex_core/Source/base/fpconv.h ---------------------------------------------------------------------- diff --git a/weex_core/Source/base/fpconv.h b/weex_core/Source/base/fpconv.h new file mode 100755 index 0000000..58bbccc --- /dev/null +++ b/weex_core/Source/base/fpconv.h @@ -0,0 +1,33 @@ +#ifndef FPCONV_H +#define FPCONV_H + +/* Fast and accurate double to string conversion based on Florian Loitsch's + * Grisu-algorithm[1]. + * + * Input: + * fp -> the double to convert, dest -> destination buffer. + * The generated string will never be longer than 24 characters. + * Make sure to pass a pointer to at least 24 bytes of memory. + * The emitted string will not be null terminated. + * + * Output: + * The number of written characters. + * + * Exemplary usage: + * + * void print(double d) + * { + * char buf[24 + 1] // plus null terminator + * int str_len = fpconv_dtoa(d, buf); + * + * buf[str_len] = '\0'; + * printf("%s", buf); + * } + * + */ + +int fpconv_dtoa(double fp, char dest[24]); + +#endif + +/* [1] http://florian.loitsch.com/publications/dtoa-pldi2010.pdf */ http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/2f8caedb/weex_core/Source/base/powers.h ---------------------------------------------------------------------- diff --git a/weex_core/Source/base/powers.h b/weex_core/Source/base/powers.h new file mode 100755 index 0000000..52e5da5 --- /dev/null +++ b/weex_core/Source/base/powers.h @@ -0,0 +1,129 @@ +#include <stdint.h> + +#define npowers 87 +#define steppowers 8 +#define firstpower -348 /* 10 ^ -348 */ + +#define expmax -32 +#define expmin -60 + + +typedef struct Fp { + uint64_t frac; + int exp; +} Fp; + +static Fp powers_ten[] = { + {18054884314459144840U, -1220}, + {13451937075301367670U, -1193}, + {10022474136428063862U, -1166}, + {14934650266808366570U, -1140}, + {11127181549972568877U, -1113}, + {16580792590934885855U, -1087}, + {12353653155963782858U, -1060}, + {18408377700990114895U, -1034}, + {13715310171984221708U, -1007}, + {10218702384817765436U, -980}, + {15227053142812498563U, -954}, + {11345038669416679861U, -927}, + {16905424996341287883U, -901}, + {12595523146049147757U, -874}, + {9384396036005875287U, -847}, + {13983839803942852151U, -821}, + {10418772551374772303U, -794}, + {15525180923007089351U, -768}, + {11567161174868858868U, -741}, + {17236413322193710309U, -715}, + {12842128665889583758U, -688}, + {9568131466127621947U, -661}, + {14257626930069360058U, -635}, + {10622759856335341974U, -608}, + {15829145694278690180U, -582}, + {11793632577567316726U, -555}, + {17573882009934360870U, -529}, + {13093562431584567480U, -502}, + {9755464219737475723U, -475}, + {14536774485912137811U, -449}, + {10830740992659433045U, -422}, + {16139061738043178685U, -396}, + {12024538023802026127U, -369}, + {17917957937422433684U, -343}, + {13349918974505688015U, -316}, + {9946464728195732843U, -289}, + {14821387422376473014U, -263}, + {11042794154864902060U, -236}, + {16455045573212060422U, -210}, + {12259964326927110867U, -183}, + {18268770466636286478U, -157}, + {13611294676837538539U, -130}, + {10141204801825835212U, -103}, + {15111572745182864684U, -77}, + {11258999068426240000U, -50}, + {16777216000000000000U, -24}, + {12500000000000000000U, 3}, + {9313225746154785156U, 30}, + {13877787807814456755U, 56}, + {10339757656912845936U, 83}, + {15407439555097886824U, 109}, + {11479437019748901445U, 136}, + {17105694144590052135U, 162}, + {12744735289059618216U, 189}, + {9495567745759798747U, 216}, + {14149498560666738074U, 242}, + {10542197943230523224U, 269}, + {15709099088952724970U, 295}, + {11704190886730495818U, 322}, + {17440603504673385349U, 348}, + {12994262207056124023U, 375}, + {9681479787123295682U, 402}, + {14426529090290212157U, 428}, + {10748601772107342003U, 455}, + {16016664761464807395U, 481}, + {11933345169920330789U, 508}, + {17782069995880619868U, 534}, + {13248674568444952270U, 561}, + {9871031767461413346U, 588}, + {14708983551653345445U, 614}, + {10959046745042015199U, 641}, + {16330252207878254650U, 667}, + {12166986024289022870U, 694}, + {18130221999122236476U, 720}, + {13508068024458167312U, 747}, + {10064294952495520794U, 774}, + {14996968138956309548U, 800}, + {11173611982879273257U, 827}, + {16649979327439178909U, 853}, + {12405201291620119593U, 880}, + {9242595204427927429U, 907}, + {13772540099066387757U, 933}, + {10261342003245940623U, 960}, + {15290591125556738113U, 986}, + {11392378155556871081U, 1013}, + {16975966327722178521U, 1039}, + {12648080533535911531U, 1066} +}; + +static Fp find_cachedpow10(int exp, int *k) { + const double one_log_ten = 0.30102999566398114; + + int approx = -(exp + npowers) * one_log_ten; + int idx = (approx - firstpower) / steppowers; + + while (1) { + int current = exp + powers_ten[idx].exp + 64; + + if (current < expmin) { + idx++; + continue; + } + + if (current > expmax) { + idx--; + continue; + } + + *k = (firstpower + idx * steppowers); + + return powers_ten[idx]; + } +}
