From ae49534733bd232e17824df06c8468ddd11b4d80 Mon Sep 17 00:00:00 2001 From: BlueMatthew Date: Tue, 9 Jan 2024 13:07:42 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=96=B0=E5=AE=9E=E7=8E=B0Timer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/cpp/MicroPhoto.cpp | 3 +- app/src/main/cpp/PhoneDevice.cpp | 155 +++++++++++------- app/src/main/cpp/PhoneDevice.h | 19 ++- .../com/xypower/mpapp/MicroPhotoService.java | 63 ++++--- 4 files changed, 153 insertions(+), 87 deletions(-) diff --git a/app/src/main/cpp/MicroPhoto.cpp b/app/src/main/cpp/MicroPhoto.cpp index 15a6da53..68970995 100644 --- a/app/src/main/cpp/MicroPhoto.cpp +++ b/app/src/main/cpp/MicroPhoto.cpp @@ -265,7 +265,8 @@ Java_com_xypower_mpapp_MicroPhotoService_fireTimeout( } CPhoneDevice* phoneDevice = (CPhoneDevice *)dev; - return phoneDevice->FireTimer((IDevice::timer_uid_t)uid, static_cast(times)) ? JNI_TRUE : JNI_FALSE; + return JNI_FALSE; + // return phoneDevice->FireTimer((IDevice::timer_uid_t)uid, static_cast(times)) ? JNI_TRUE : JNI_FALSE; } extern "C" JNIEXPORT void JNICALL diff --git a/app/src/main/cpp/PhoneDevice.cpp b/app/src/main/cpp/PhoneDevice.cpp index 4d997799..c42cd660 100644 --- a/app/src/main/cpp/PhoneDevice.cpp +++ b/app/src/main/cpp/PhoneDevice.cpp @@ -162,6 +162,8 @@ CPhoneDevice::CPhoneDevice(JavaVM* vm, jobject service, const std::string& appPa m_sysApiClass = NULL; + RegisterHandlerForSignal(SIGUSR2); + m_vm = vm; JNIEnv* env = NULL; bool didAttachThread = false; @@ -518,57 +520,121 @@ bool CPhoneDevice::RequestPosition() return (ret == JNI_TRUE); } -IDevice::timer_uid_t CPhoneDevice::RegisterTimer(unsigned int timerType, unsigned int timeout, unsigned long times/* = 0*/) +void CPhoneDevice::handleSignal(int sig, siginfo_t *si, void *uc) { - IDevice::timer_uid_t uid = m_timerUidFeed.fetch_add(1); - - ALOGI("NDK RegTimer: uid=%lld Type=%u timeout=%u", uid, timerType, timeout); + TIMER_CONTEXT* context = (TIMER_CONTEXT*)(si->si_value.sival_ptr); + context->device->handleTimerImpl(context); +} - JNIEnv* env = NULL; - bool didAttachThread = false; - bool res = GetJniEnv(m_vm, &env, didAttachThread); - if (!res) +bool CPhoneDevice::RegisterHandlerForSignal(int sig) +{ + return true; + // Establish handler for timer signal + struct sigaction sa; + sigset_t mask; + + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = CPhoneDevice::handleSignal; + sigemptyset(&sa.sa_mask); + if (sigaction(sig, &sa, NULL) == -1) { - ALOGE("Failed to get JNI Env"); - return 0; + return false; } - jboolean ret = env->CallBooleanMethod(m_javaService, mRegisterTimerMid, (jlong)uid, (jint)timeout, (jlong)times); - if (didAttachThread) + + return true; + // Block timer signal temporarily + + // printf("Blocking signal %d\n", SIG); + sigemptyset(&mask); + sigaddset(&mask, sig); + if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1) { - m_vm->DetachCurrentThread(); + return false; } - if (ret == JNI_TRUE) + return true; +} + +void CPhoneDevice::handleTimer(union sigval v) +{ + TIMER_CONTEXT* context = (TIMER_CONTEXT*)(v.sival_ptr); + context->device->handleTimerImpl(context); +} + +void CPhoneDevice::handleTimerImpl(CPhoneDevice::TIMER_CONTEXT* context) +{ + context->times++; + if (context->expectedTimes == 0 || context->times <= context->expectedTimes) { - unsigned long val = timerType; - mTimers.insert(mTimers.end(), std::pair(uid, val)); - return uid; + if (m_listener != NULL) + { + m_listener->OnTimeout(context->uid, context->timerType, context->times); + } } - return 0; } -bool CPhoneDevice::UnregisterTimer(IDevice::timer_uid_t uid) +IDevice::timer_uid_t CPhoneDevice::RegisterTimer(unsigned int timerType, unsigned int timeout, unsigned long times/* = 0*/) { - jboolean ret = JNI_FALSE; - JNIEnv* env = NULL; - bool didAttachThread = false; - bool res = GetJniEnv(m_vm, &env, didAttachThread); - if (!res) + struct sigevent evp = { 0 }; + struct itimerspec ts = { 0 }; + timer_t timer; + int ret; + + TIMER_CONTEXT* context = new TIMER_CONTEXT(); + context->device = this; + context->timerType = timerType; + context->expectedTimes = times; + + evp.sigev_value.sival_ptr = context; + evp.sigev_notify = SIGEV_THREAD; //SIGEV_THREAD_ID; + evp.sigev_notify_function = CPhoneDevice::handleTimer; + // evp.sigev_notify_thread_id = gettid(); + // evp.sigev_notify = SIGEV_SIGNAL; + // evp.sigev_signo = SIGUSR2; + + ret = timer_create(CLOCK_REALTIME, &evp, &timer); + if( ret) { - ALOGE("Failed to get JNI Env"); - return false; + int err = errno; + delete context; + return INVALID_TIMER_UID; } - ret = env->CallBooleanMethod(m_javaService, mUnregisterTimerMid, (jlong)uid); - if (didAttachThread) + + context->uid = (unsigned long)timer; + ts.it_value.tv_sec = (timeout / 1000); + ts.it_value.tv_nsec = (timeout % 1000) * 1000; + if (times != 1) { - m_vm->DetachCurrentThread(); + ts.it_interval.tv_sec = ts.it_value.tv_sec; + ts.it_interval.tv_nsec = ts.it_value.tv_nsec; } - if (ret == JNI_TRUE) + ret = timer_settime(timer, 0, &ts, NULL); + + if(ret) { - mTimers.erase(uid); + timer_delete(timer); + delete context; + return INVALID_TIMER_UID; + } + + mTimers.insert(mTimers.end(), std::pair((IDevice::timer_uid_t)timer, context)); + return (IDevice::timer_uid_t)timer; +} + +bool CPhoneDevice::UnregisterTimer(IDevice::timer_uid_t uid) +{ + timer_t timer = (timer_t)uid; + int res = timer_delete(timer); + + std::map::iterator it = mTimers.find(uid); + if (it != mTimers.end()) + { + delete it->second; + mTimers.erase(it); return true; } + return false; } @@ -632,33 +698,6 @@ bool CPhoneDevice::ReleaseWakelock(unsigned long wakelock) return true; } -bool CPhoneDevice::FireTimer(timer_uid_t uid, unsigned long times) -{ - std::map::iterator it = mTimers.find(uid); - if (it == mTimers.end()) - { - return false; - } - - unsigned long timerType = it->second & 0xFFFFFFFF; - unsigned long ntimes = (it->second & 0xFFFFFFFF00000000) >> 32; - ntimes++; - - if (timerType != 100) - { - // int aa = 0; - } - it->second = timerType | (ntimes << 32); - if (m_listener == NULL) - { - return false; - } - - m_listener->OnTimeout(uid, timerType, ntimes); - - return true; -} - IDevice::timer_uid_t CPhoneDevice::RegisterHeartbeat(unsigned int timerType, unsigned int timeout) { mHeartbeatStartTime = time(NULL); diff --git a/app/src/main/cpp/PhoneDevice.h b/app/src/main/cpp/PhoneDevice.h index 6b35a687..41504c4b 100644 --- a/app/src/main/cpp/PhoneDevice.h +++ b/app/src/main/cpp/PhoneDevice.h @@ -162,6 +162,15 @@ public: CPhoneDevice* m_dev; }; + struct TIMER_CONTEXT + { + CPhoneDevice* device; + unsigned int timerType; + unsigned long times; + unsigned long expectedTimes; + unsigned long uid; + }; + CPhoneDevice(JavaVM* vm, jobject service, const std::string& appPath, unsigned int netId); virtual ~CPhoneDevice(); @@ -182,8 +191,6 @@ public: virtual unsigned long RequestWakelock(unsigned long timeout); virtual bool ReleaseWakelock(unsigned long wakelock); - virtual bool FireTimer(timer_uid_t uid, unsigned long times); - bool GetNextScheduleItem(uint32_t tsBasedZero, uint32_t scheduleTime, vector& items); void UpdatePosition(double lon, double lat, time_t ts); @@ -220,7 +227,6 @@ protected: void QueryPowerInfo(std::map& powerInfo); std::string QueryCpuTemperature(); - bool OnImageReady(cv::Mat& mat); void onError(const std::string& msg); @@ -232,6 +238,11 @@ protected: void TurnOnOtg(JNIEnv* env); void TurnOffOtg(JNIEnv* env); + static void handleSignal(int sig, siginfo_t *si, void *uc); + bool RegisterHandlerForSignal(int sig); + void static handleTimer(union sigval v); + void handleTimerImpl(TIMER_CONTEXT* context); + protected: JavaVM* m_vm; @@ -266,7 +277,7 @@ protected: atomic_ulong m_timerUidFeed; atomic_ulong m_wakelockIdFeed; - std::map mTimers; + std::map mTimers; mutable CPhoneCamera* mCamera; diff --git a/app/src/main/java/com/xypower/mpapp/MicroPhotoService.java b/app/src/main/java/com/xypower/mpapp/MicroPhotoService.java index a6a741dc..f13ccb32 100644 --- a/app/src/main/java/com/xypower/mpapp/MicroPhotoService.java +++ b/app/src/main/java/com/xypower/mpapp/MicroPhotoService.java @@ -40,6 +40,7 @@ import android.os.PowerManager; import android.os.RemoteException; import android.os.SystemClock; +import androidx.annotation.RequiresApi; import androidx.core.app.NotificationCompat; import androidx.core.content.FileProvider; import androidx.localbroadcastmanager.content.LocalBroadcastManager; @@ -485,43 +486,24 @@ public class MicroPhotoService extends Service { // private HashMap mTimers = new HashMap(); public boolean registerTimer(long uid, int timeout, long times) { + Context context = getApplicationContext(); // 创建延迟意图 Intent alarmIntent = new Intent(); alarmIntent.setAction(ACTION_TIMEOUT); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + alarmIntent.setIdentifier(Long.toString(uid)); + } alarmIntent.putExtra(EXTRA_PARAM_TIMER_UID, uid); alarmIntent.putExtra(EXTRA_PARAM_TIMEOUT, timeout); alarmIntent.putExtra(EXTRA_PARAM_TIMES, times); alarmIntent.putExtra(EXTRA_PARAM_ELASPED_TIMES, 0L); - PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT); mTimers.put(Long.valueOf(uid), pendingIntent); return registerTimer(pendingIntent, uid, timeout); } - private void setDefaultDataSubId(int subId) { - SubscriptionManager subscriptionManager = (SubscriptionManager) getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); - try { - Method method = subscriptionManager.getClass().getDeclaredMethod("setDefaultDataSubId", int.class); - method.invoke(subscriptionManager, subId); - TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); - Method method1 = telephonyManager.getClass().getDeclaredMethod("setDataEnabled", boolean.class); - method1.invoke(telephonyManager, true); - } catch (Exception e) { - Log.e(TAG, "wjz debug setDefaultDataSubId: error is " + e.getMessage()); - } - } - private int getDefaultDataSubId() { - SubscriptionManager subscriptionManager = (SubscriptionManager) getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); - try { - Method method = subscriptionManager.getClass().getDeclaredMethod("getDefaultDataSubscriptionId"); - return (int) method.invoke(subscriptionManager); - } catch (Exception e) { - Log.e(TAG, "wjz debug getDefaultDataSubId: error is " + e.getMessage()); - } - return 0; - } - public boolean registerTimer(PendingIntent pendingIntent, long uid, int timeout) { AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); @@ -534,8 +516,18 @@ public class MicroPhotoService extends Service { public boolean unregisterTimer(long uid) { + /* + Context context = getApplicationContext(); + + AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + PendingIntent pendingIntent = PendingIntent.getService(context, 0, pendingIntent., PendingIntent.FLAG_NO_CREATE); + if (pendingIntent != null && alarmManager != null) { + alarmManager.cancel(pendingIntent); + } + */ Long uidObj = Long.valueOf(uid); PendingIntent pendingIntent = mTimers.get(uidObj); + if (pendingIntent != null) { AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); @@ -1201,4 +1193,27 @@ cellSignalStrengthGsm.getDbm(); }; ////////////////////////GPS//////////////////// + + private void setDefaultDataSubId(int subId) { + SubscriptionManager subscriptionManager = (SubscriptionManager) getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); + try { + Method method = subscriptionManager.getClass().getDeclaredMethod("setDefaultDataSubId", int.class); + method.invoke(subscriptionManager, subId); + TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); + Method method1 = telephonyManager.getClass().getDeclaredMethod("setDataEnabled", boolean.class); + method1.invoke(telephonyManager, true); + } catch (Exception e) { + Log.e(TAG, "wjz debug setDefaultDataSubId: error is " + e.getMessage()); + } + } + private int getDefaultDataSubId() { + SubscriptionManager subscriptionManager = (SubscriptionManager) getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); + try { + Method method = subscriptionManager.getClass().getDeclaredMethod("getDefaultDataSubscriptionId"); + return (int) method.invoke(subscriptionManager); + } catch (Exception e) { + Log.e(TAG, "wjz debug getDefaultDataSubId: error is " + e.getMessage()); + } + return 0; + } } \ No newline at end of file