#include #include #include #include #include #include "TerminalDevice.h" #include "PhoneDevice.h" #include "PhoneDevice2.h" #include #include #include #include #ifdef USING_BREAK_PAD #include "client/linux/handler/exception_handler.h" #include "client/linux/handler/minidump_descriptor.h" #endif #include #include #include "Camera.h" #include "Camera2Reader.h" #include "GPIOControl.h" #ifdef USING_BREAK_PAD bool DumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded) { LOGE("Dump path: %s\n", descriptor.path()); return succeeded; } #endif #ifdef USING_NRSEC #include #endif static jmethodID mRegisterTimerMid = 0; static jmethodID mRegisterHeartbeatMid = 0; static jmethodID mUnregisterTimerMid = 0; static jmethodID mUpdateTimeMid = 0; static jmethodID mRequestWakelockMid = 0; static jmethodID mReleaseWakelockMid = 0; static jmethodID mGetSystemInfoMid = 0; static jmethodID mRebootMid = 0; static jmethodID mEnableGpsMid = 0; static jmethodID mRequestPositionMid = 0; static jmethodID mWriteLogMid = 0; void posix_signal_handler(int sig, siginfo_t *siginfo, void *context) { (void)context; switch(sig) { case SIGSEGV: fputs("Caught SIGSEGV: Segmentation Fault\n", stderr); break; case SIGINT: fputs("Caught SIGINT: Interactive attention signal, (usually ctrl+c)\n", stderr); break; case SIGFPE: switch(siginfo->si_code) { case FPE_INTDIV: fputs("Caught SIGFPE: (integer divide by zero)\n", stderr); break; case FPE_INTOVF: fputs("Caught SIGFPE: (integer overflow)\n", stderr); break; case FPE_FLTDIV: fputs("Caught SIGFPE: (floating-point divide by zero)\n", stderr); break; case FPE_FLTOVF: fputs("Caught SIGFPE: (floating-point overflow)\n", stderr); break; case FPE_FLTUND: fputs("Caught SIGFPE: (floating-point underflow)\n", stderr); break; case FPE_FLTRES: fputs("Caught SIGFPE: (floating-point inexact result)\n", stderr); break; case FPE_FLTINV: fputs("Caught SIGFPE: (floating-point invalid operation)\n", stderr); break; case FPE_FLTSUB: fputs("Caught SIGFPE: (subscript out of range)\n", stderr); break; default: fputs("Caught SIGFPE: Arithmetic Exception\n", stderr); break; } case SIGILL: switch(siginfo->si_code) { case ILL_ILLOPC: fputs("Caught SIGILL: (illegal opcode)\n", stderr); break; case ILL_ILLOPN: fputs("Caught SIGILL: (illegal operand)\n", stderr); break; case ILL_ILLADR: fputs("Caught SIGILL: (illegal addressing mode)\n", stderr); break; case ILL_ILLTRP: fputs("Caught SIGILL: (illegal trap)\n", stderr); break; case ILL_PRVOPC: fputs("Caught SIGILL: (privileged opcode)\n", stderr); break; case ILL_PRVREG: fputs("Caught SIGILL: (privileged register)\n", stderr); break; case ILL_COPROC: fputs("Caught SIGILL: (coprocessor error)\n", stderr); break; case ILL_BADSTK: fputs("Caught SIGILL: (internal stack error)\n", stderr); break; default: fputs("Caught SIGILL: Illegal Instruction\n", stderr); break; } break; case SIGTERM: fputs("Caught SIGTERM: a termination request was sent to the program\n", stderr); break; case SIGABRT: fputs("Caught SIGABRT: usually caused by an abort() or assert()\n", stderr); break; default: break; } _Exit(1); } class Runner { public: static void RequestCapture(CTerminal* pTerminal, unsigned int channel, unsigned int preset, unsigned int type, unsigned long scheduleTime); }; void Runner::RequestCapture(CTerminal* pTerminal, unsigned int channel, unsigned int preset, unsigned int type, unsigned long scheduleTime) { pTerminal->RequestCapture(channel, preset, type, scheduleTime); } jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env = NULL; jint result = -1; #if defined(JNI_VERSION_1_6) if (result==-1 && vm->GetEnv((void**)&env, JNI_VERSION_1_6) == JNI_OK) { result = JNI_VERSION_1_6; } #endif #if defined(JNI_VERSION_1_4) if (result==-1 && vm->GetEnv((void**)&env, JNI_VERSION_1_4) == JNI_OK) { result = JNI_VERSION_1_4; } #endif #if defined(JNI_VERSION_1_2) if (result==-1 && vm->GetEnv((void**)&env, JNI_VERSION_1_2) == JNI_OK) { result = JNI_VERSION_1_2; } #endif if(result == -1 || env == NULL) { return JNI_FALSE; } #ifdef USING_BREAK_PAD google_breakpad::MinidumpDescriptor descriptor("/sdcard/Android/data/com.xypower.mpapp/files/logs/"); google_breakpad::ExceptionHandler eh(descriptor, NULL, DumpCallback, NULL, true, -1); #endif { struct sigaction sig_action = {}; sig_action.sa_sigaction = posix_signal_handler; sigemptyset(&sig_action.sa_mask); #ifdef __APPLE__ /* for some reason we backtrace() doesn't work on osx when we use an alternate stack */ sig_action.sa_flags = SA_SIGINFO; #else sig_action.sa_flags = SA_SIGINFO | SA_ONSTACK; #endif if (sigaction(SIGSEGV, &sig_action, NULL) != 0) { // err(1, "sigaction"); int aa = 0; } } const char* className = "com/xypower/mpapp/MicroPhotoService"; jclass clazz = (env)->FindClass(className); // if((env)->RegisterNatives(clazz, gMethods, 1)< 0) { // return -1; // } env->DeleteLocalRef(clazz); return result; } bool GetJniEnv(JavaVM *vm, JNIEnv **env, bool& didAttachThread) { didAttachThread = false; *env = nullptr; // Check if the current thread is attached to the VM auto get_env_result = vm->GetEnv((void**)env, JNI_VERSION_1_6); if (get_env_result == JNI_EDETACHED) { get_env_result = vm->AttachCurrentThread(env, NULL); if (get_env_result == JNI_OK) { didAttachThread = true; } else { // Failed to attach thread. Throw an exception if you want to. } } else if (get_env_result == JNI_EVERSION) { // Unsupported JNI version. Throw an exception if you want to. } return get_env_result == JNI_OK; } extern "C" JNIEXPORT jboolean JNICALL Java_com_xypower_mpapp_MainActivity_takePhoto( JNIEnv* env, jobject pThis, jint channel, jint preset, jstring path, jstring fileName) { if (channel < 1 || channel > 0xFF) { return JNI_FALSE; } unsigned char id = (unsigned char)channel - 1; Camera2Reader *camera = new Camera2Reader(id); const char *pathStr = env->GetStringUTFChars(path, 0); const char *fileNameStr = env->GetStringUTFChars(fileName, 0); camera->Open(pathStr, fileNameStr); env->ReleaseStringUTFChars(fileName, fileNameStr); env->ReleaseStringUTFChars(path, pathStr); camera->start(); return JNI_TRUE; } extern "C" JNIEXPORT jlong JNICALL Java_com_xypower_mpapp_MicroPhotoService_init( JNIEnv* env, jobject pThis, jstring appPath, jstring ip, jint port, jstring cmdid, jint protocol, jint networkProtocol, jint encryptData, jlong netHandle, jint signalLevel, jint versionCode, jlong buildTime, jstring simcard) { /* google_breakpad::MinidumpDescriptor descriptor("."); google_breakpad::ExceptionHandler eh(descriptor, NULL, NULL, NULL, true, -1); */ if (netHandle != NETID_UNSET) { net_handle_t nh = (net_handle_t)netHandle; android_setprocnetwork(nh); } char model[PROP_VALUE_MAX] = { 0 }; __system_property_get("ro.product.model", model); jclass classService = env->GetObjectClass(pThis); jfieldID fieldId = env->GetFieldID(classService, "mModelName", "Ljava/lang/String;"); env->DeleteLocalRef(classService); jstring modelName = env->NewStringUTF(model); env->SetObjectField(pThis, fieldId, modelName); bool udpOrTcp = (networkProtocol != 0); // 0: tcp const char *appPathStr = env->GetStringUTFChars(appPath, 0); const char *ipStr = env->GetStringUTFChars(ip, 0); const char *cmdidStr = env->GetStringUTFChars(cmdid, 0); const char *simcardStr = env->GetStringUTFChars(simcard, 0); JavaVM* vm = NULL; jint ret = env->GetJavaVM(&vm); // const string& appPath, const string& termId, const string& server, unsigned short port, const string& bindIp // CTerminal* pTerminal = reinterpret_cast(handler); // CTerminalDevice* device = new CTerminalDevice(vm, pThis); // CPhoneDevice2* device = new CPhoneDevice2(vm, pThis); CTerminal* pTerminal = NewTerminal(protocol); CPhoneDevice* device = new CPhoneDevice(vm, pThis, appPathStr, NETID_UNSET, versionCode); device->SetListener(pTerminal); device->UpdateSignalLevel(signalLevel); device->SetBuildTime(buildTime / 1000); device->UpdateSimcard(simcardStr); pTerminal->InitServerInfo(appPathStr, cmdidStr, ipStr, port, udpOrTcp, encryptData); // pTerminal->SetPacketSize(1 * 1024); // 1K #ifdef USING_NRSEC pTerminal->InitEncryptionInfo(simcardStr, "/dev/spidev0.0", ""); #endif bool res = pTerminal->Startup(device); env->ReleaseStringUTFChars(appPath, appPathStr); env->ReleaseStringUTFChars(ip, ipStr); env->ReleaseStringUTFChars(cmdid, cmdidStr); env->ReleaseStringUTFChars(simcard, simcardStr); if (!res) { delete pTerminal; pTerminal = NULL; } return reinterpret_cast(pTerminal); } extern "C" JNIEXPORT jboolean JNICALL Java_com_xypower_mpapp_MicroPhotoService_notifyToTakePhoto( JNIEnv* env, jobject pThis, jlong handler, jint channel, jint preset, jlong scheduleTime, jboolean photoOrVideo) { if (channel < 1 || channel > 0xFF) { return JNI_FALSE; } CTerminal* pTerminal = reinterpret_cast(handler); if (pTerminal == NULL) { return JNI_FALSE; } unsigned char type = photoOrVideo ? 0 : 1; // std::thread th(&Runner::RequestCapture, pTerminal, (unsigned int)channel, (unsigned int)preset, type, (unsigned long)scheduleTime, 0, true); // th.detach(); pTerminal->RequestCapture((unsigned int)channel, (unsigned int)preset, type, (unsigned long)scheduleTime, 0, true); return JNI_TRUE; } extern "C" JNIEXPORT jboolean JNICALL Java_com_xypower_mpapp_MicroPhotoService_sendHeartbeat( JNIEnv* env, jobject pThis, jlong handler, jint signalLevel) { CTerminal* pTerminal = reinterpret_cast(handler); if (pTerminal == NULL) { return JNI_FALSE; } CPhoneDevice* device = (CPhoneDevice*)pTerminal->GetDevice(); if (device != NULL) { device->UpdateSignalLevel(signalLevel); } pTerminal->SendHeartbeat(); return JNI_TRUE; } extern "C" JNIEXPORT void JNICALL Java_com_xypower_mpapp_MicroPhotoService_updatePosition( JNIEnv* env, jobject pThis, jlong handler, jdouble lon, jdouble lat, jdouble radius, jlong ts) { if (handler == 0) { return; } CTerminal* pTerminal = reinterpret_cast(handler); IDevice* dev = pTerminal->GetDevice(); if (dev == NULL) { return; } CPhoneDevice* phoneDevice = (CPhoneDevice *)dev; phoneDevice->UpdatePosition(lon, lat, radius, ts); } extern "C" JNIEXPORT jboolean JNICALL Java_com_xypower_mpapp_MicroPhotoService_uninit( JNIEnv* env, jobject pThis, jlong handler) { CTerminal* pTerminal = reinterpret_cast(handler); if (pTerminal == NULL) { return JNI_FALSE; } IDevice* dev = pTerminal->GetDevice(); if (dev != NULL) { ((CPhoneDevice *)dev)->CloseCamera(); } pTerminal->SignalExit(); pTerminal->Shutdown(); delete pTerminal; return JNI_TRUE; } extern "C" JNIEXPORT jlong JNICALL Java_com_xypower_mpapp_MicroPhotoService_getHeartbeatDuration( JNIEnv* env, jobject pThis, jlong handler) { CTerminal* pTerminal = reinterpret_cast(handler); if (pTerminal == NULL) { return DEFAULT_HEARTBEAT_DURATION; } return pTerminal->GetHeartbeatDuration(); } extern "C" JNIEXPORT jlongArray JNICALL Java_com_xypower_mpapp_MicroPhotoService_getPhotoTimeData2( JNIEnv* env, jobject pThis, jlong handler) { CTerminal* pTerminal = reinterpret_cast(handler); if (pTerminal == NULL) { return NULL; } map> photoTime; if (!pTerminal->GetPhotoTime(photoTime) || photoTime.empty()) { return NULL; } size_t numberOfData = photoTime.size() * photoTime.begin()->second.size(); if (numberOfData == 0) { return NULL; } vector dataArray; dataArray.reserve(numberOfData); unsigned long val = 0; jint channel = 0; for (map>::const_iterator it = photoTime.cbegin(); it != photoTime.cend(); ++it) { if (it->second.empty()) { continue; } channel = (jint)((unsigned short)it->first); // dataArray.push_back(channel); // val = (jint)it->second.size(); // dataArray.push_back(val); for (vector::const_iterator it2 = it->second.cbegin(); it2 != it->second.cend(); ++it2) { // time val = ((unsigned long)((*it2) & 0xFFFFFF00)) << 24; // channel val |= ((unsigned long)channel) << 16; // preset val |= ((unsigned long)((*it2) & 0xFF)) << 8; dataArray.push_back((jlong)val); } } std::sort(dataArray.begin(), dataArray.end()); jlongArray data = env->NewLongArray(dataArray.size()); if (data == NULL) { return NULL; } env->SetLongArrayRegion(data, 0, dataArray.size(), &dataArray[0]); return data; } extern "C" JNIEXPORT jlongArray JNICALL Java_com_xypower_mpapp_MicroPhotoService_getPhotoTimeData( JNIEnv* env, jobject pThis, jlong handler, jlong startTime) { CTerminal* pTerminal = reinterpret_cast(handler); if (pTerminal == NULL) { return NULL; } unsigned int scheduleTime = 0; time_t zeroPointTime = 0; std::vector > channelsAndPresets; if (!pTerminal->GetAndRefreshLatestScheduleTime(startTime, zeroPointTime, scheduleTime, channelsAndPresets)) { return NULL; } if (channelsAndPresets.empty()) { return NULL; } vector dataArray; dataArray.reserve(channelsAndPresets.size() + 3); dataArray.push_back((jlong)zeroPointTime); dataArray.push_back((jlong)scheduleTime); dataArray.push_back((jlong)channelsAndPresets.size()); unsigned long val = 0; for (std::vector >::const_iterator it = channelsAndPresets.cbegin(); it != channelsAndPresets.cend(); ++it) { val = (unsigned long)scheduleTime << 24; // channel val |= ((unsigned long)(it->first)) << 16; // preset val |= ((unsigned long)(it->second)) << 8; dataArray.push_back((jlong)val); } jlongArray data = env->NewLongArray(dataArray.size()); if (data == NULL) { return NULL; } env->SetLongArrayRegion(data, 0, dataArray.size(), &dataArray[0]); return data; } /* extern "C" JNIEXPORT jlongArray JNICALL Java_com_xypower_mpapp_MicroPhotoService_getNextScheduleItem( JNIEnv* env, jobject pThis, jlong handler) { CTerminal* pTerminal = reinterpret_cast(handler); if (pTerminal == NULL) { return NULL; } map> photoTime; if (!pTerminal->GetPhotoTime(photoTime) || photoTime.empty()) { return NULL; } size_t numberOfData = photoTime.size() * photoTime.begin()->second.size(); if (numberOfData == 0) { return NULL; } vector dataArray; dataArray.reserve(numberOfData); unsigned long val = 0; jint channel = 0; for (map>::const_iterator it = photoTime.cbegin(); it != photoTime.cend(); ++it) { if (it->second.empty()) { continue; } channel = (jint)((unsigned short)it->first); // dataArray.push_back(channel); // val = (jint)it->second.size(); // dataArray.push_back(val); for (vector::const_iterator it2 = it->second.cbegin(); it2 != it->second.cend(); ++it2) { // time val = ((unsigned long)((*it2) & 0xFFFFFF00)) << 24; // channel val |= ((unsigned long)channel) << 16; // preset val |= ((unsigned long)((*it2) & 0xFF)) << 8; dataArray.push_back((jlong)val); } } std::sort(dataArray.begin(), dataArray.end()); jlongArray data = env->NewLongArray(dataArray.size()); if (data == NULL) { return NULL; } env->SetLongArrayRegion(data, 0, dataArray.size(), &dataArray[0]); return data; } */ extern "C" JNIEXPORT void JNICALL Java_com_xypower_mpapp_MicroPhotoService_recordingFinished( JNIEnv* env, jobject pThis, jlong handler, jboolean result, jstring path, jlong videoId) { CTerminal* pTerminal = reinterpret_cast(handler); if (pTerminal == NULL) { return; } IDevice* dev = pTerminal->GetDevice(); if (dev != NULL) { const char *pathStr = NULL; if (path != NULL) { pathStr = env->GetStringUTFChars(path, 0); } // camera->Open(pathStr, fileNameStr); unsigned long photoId = videoId; ((CPhoneDevice *)dev)->OnVideoReady(result != JNI_FALSE, pathStr, photoId); if (path != NULL) { env->ReleaseStringUTFChars(path, pathStr); } } } extern "C" JNIEXPORT void JNICALL Java_com_xypower_mpapp_MicroPhotoService_reloadConfigs( JNIEnv* env, jobject pThis, jlong handler) { CTerminal* pTerminal = reinterpret_cast(handler); if (pTerminal == NULL) { return; } pTerminal->LoadAppConfigs(); } extern "C" JNIEXPORT void JNICALL Java_com_xypower_mpapp_MicroPhotoService_setOtgState( JNIEnv* env, jclass cls, jboolean enabled) { GpioControl::setOtgState(enabled != JNI_FALSE); } extern "C" JNIEXPORT void JNICALL Java_com_xypower_mpapp_MicroPhotoService_setCam3V3Enable( JNIEnv* env, jclass cls, jboolean enabled) { GpioControl::setCam3V3Enable(enabled != JNI_FALSE); } extern "C" JNIEXPORT jstring JNICALL Java_com_xypower_mpapp_MicroPhotoService_getSerialNumber( JNIEnv* env, jclass cls) { char value[PROP_VALUE_MAX] = { 0 }; __system_property_get("ro.serialno", value); return env->NewStringUTF(value); } extern "C" JNIEXPORT jboolean JNICALL Java_com_xypower_mpapp_MicroPhotoService_importPublicKeyFile( JNIEnv* env, jclass cls, jint index, jstring path, jstring md5) { #ifdef USING_NRSEC NrsecPort nrsec; // NrsecSpiPort spi("/dev/mtkgpioctrl"); // NrsecSpiPort spi("/dev/spidevSE"); // const char *port = "/dev/mtkgpioctrl"; const char *port = "/dev/spidev0.0"; if (!nrsec.Open(port)) { return JNI_FALSE; } const char *pathStr = env->GetStringUTFChars(path, 0); const char *md5Str = env->GetStringUTFChars(md5, 0); bool res = false; std::vector data; if (readFile(pathStr, data) && !data.empty()) { res = nrsec.SM2ImportPublicKey(1, &data[0]); } nrsec.Close(); env->ReleaseStringUTFChars(path, pathStr); env->ReleaseStringUTFChars(md5, md5Str); return res ? JNI_TRUE : JNI_FALSE; #endif } extern "C" JNIEXPORT jboolean JNICALL Java_com_xypower_mpapp_MicroPhotoService_importPublicKey( JNIEnv* env, jclass cls, jint index, jbyteArray cert) { #ifdef USING_NRSEC NrsecPort nrsec; // const char *port = "/dev/mtkgpioctrl"; const char *port = "/dev/spidev0.0"; int byteCertLen = env->GetArrayLength(cert); if (byteCertLen <= 0) { return JNI_FALSE; } if (!nrsec.Open(port)) { return JNI_FALSE; } std::string version = nrsec.Version(); char buf[128] = { 0 }; strcpy(buf, version.c_str()); jbyte* byteCert = env->GetByteArrayElements(cert, 0); bool res = nrsec.SM2ImportPublicKey(index, (const uint8_t*)byteCert); nrsec.Close(); env->ReleaseByteArrayElements(cert, byteCert, JNI_ABORT); return res ? JNI_TRUE : JNI_FALSE; #endif } extern "C" JNIEXPORT jboolean JNICALL Java_com_xypower_mpapp_MicroPhotoService_genKeys( JNIEnv* env, jclass cls, jint index) { #ifdef USING_NRSEC // GpioControl::setRS485Enable(true); GpioControl::setSpiMode(SPI_MODE_3); GpioControl::setSpiBitsPerWord(8); GpioControl::setSpiMaxSpeedHz(33000000); const char *port = "/dev/mtkgpioctrl"; // const char *port = "/dev/spidevSE"; NrsecPort nrsec; if (!nrsec.Open(port)) { return JNI_FALSE; } std::string version = nrsec.Version(); char buf[128] = { 0 }; strcpy(buf, version.c_str()); bool res = nrsec.SM2keypair(index) == 0; nrsec.Close(); return res ? JNI_TRUE : JNI_FALSE; #endif }