gpt4 book ai didi

ios - 是否可以使用NSTimer将越狱的iPhone从深度 sleep 中唤醒?

转载 作者:可可西里 更新时间:2023-11-01 06:20:55 26 4
gpt4 key购买 nike

注意:在编辑的更下方,有简单的代码可以生成问题,而没有我的原始程序的全部复杂性。

我正在尝试为越狱的iOS编写一个闹钟应用程序。我已将UI设置为用于调度警报的独立应用程序,然后将警报信息保存到磁盘。保存文件由始终运行的启动守护程序读取,该守护程序实际处理警报。

我这样安排警报(在守护程序中编辑:)(NSDate *fireDate较早计算):

NSTimer *singleTimer = [[NSTimer alloc] initWithFireDate:fireDate
interval:0
target:self
selector:@selector(soundAlarm:)
userInfo:alarm
repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:singleTimer
forMode:NSRunLoopCommonModes];
[self.timers addObject:singleTimer];
[singleTimer release];

编辑:上面的代码在称为 createTimers的方法中运行,该方法由 reloadData调用。 reloadData从共享的保存文件中读取有关计时器的信息,并在 AMMQRDaemonManager的init函数中以及管理器每当收到通知(带有 notify_post)UI应用程序已更新保存文件的调用时,该信息就会被调用。
soundAlarm:方法(编辑:也在守护程序中)是:
- (void)soundAlarm:(NSTimer *)theTimer {
NSLog(@"qralarmdaemon: sounding alarm");

extern CFStringRef kCFUserNotificationAlertTopMostKey;

CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionaryAddValue(dict, kCFUserNotificationAlertTopMostKey, kCFBooleanTrue);
CFDictionaryAddValue(dict, kCFUserNotificationAlertHeaderKey, CFSTR("Title"));
CFDictionaryAddValue(dict,kCFUserNotificationDefaultButtonTitleKey, CFSTR("OK"));

SInt32 err = 0;
CFUserNotificationRef notif = CFUserNotificationCreate(NULL,
0, kCFUserNotificationPlainAlertLevel, &err, dict);

CFOptionFlags response;
if((err) || (CFUserNotificationReceiveResponse(notif, 0, &response))) {
// do stuff
} else if((response & 0x3) == kCFUserNotificationDefaultResponse) {
// do stuff
}
CFRelease(dict);
CFRelease(notif);

// Do some other stuff
}

这可以很好地工作,并且会在手机处于解锁状态或锁定状态时显示警报。但是,如果手机被锁定足够长的时间才能进入深度 sleep 状态,则计时器将无法启动。

我不需要打开屏幕(虽然那会很好),因为除了显示警报外,我还将播放声音,但是我确实需要启动计时器,这样我才能知道何时启动声音。

有任何想法吗?

编辑:这是守护程序的 main函数。
int main(int argc, char **argv, char **envp) {

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

NSLog(@"qralarmdaemon: launched");

AMMQRDaemonManager *manager = [[AMMQRDaemonManager alloc] init];

NSTimer *keepRunningTimer = [[NSTimer alloc] initWithFireDate:[NSDate distantFuture]
interval:1000
target:manager
selector:@selector(keepRunning:)
userInfo:nil
repeats:YES];

[[NSRunLoop currentRunLoop] addTimer:keepRunningTimer
forMode:NSRunLoopCommonModes];

// Execute run loop
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop run];

[manager release];

NSLog(@"qralarmdaemon: exiting");

[pool release];

return 0;
}

(不包括用于注册来自主应用程序的通知以知道何时读取保存文件等的代码,但我认为这无关紧要)。

编辑(再次):我向运行循环添加了一个计时器,该计时器在 [NSDate distantFuture]处触发。这似乎可以将计时器保留的时间更长(预定时间在手机锁定后1分45秒关闭的计时器,然后唤醒电话),但不会无限期地保存(预定时间在手机锁定后30分30秒的计时器没有关闭) )。

编辑:我构造了以下玩具示例来说明问题,而不必担心与代码其他部分的交互。

我编译了此代码,通过SSH登录并运行了它,然后锁定了我的手机。如果将 dateByAddingTimeInterval:480更改为 dateByAddingTimeInterval:30,则会得到以下输出:
2013-03-31 12:21:25.555 daemontimertest[6160:707] daemon-timer-test: launched
2013-03-31 12:21:56.265 daemontimertest[6160:707] daemon-timer-test: timer fired

但是将其设置为480时,我等待了8分钟以上,只看到第一行:
2013-03-31 12:08:09.331 daemontimertest[6049:707] daemon-timer-test: launched
main.m:
#import "MyClass.h"

int main(int argc, char **argv, char **envp) {

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

NSLog(@"daemon-timer-test: launched");

MyClass *obj = [[MyClass alloc] init];

NSTimer *singleTimer = [[NSTimer alloc] initWithFireDate:[[NSDate date] dateByAddingTimeInterval:480]
interval:0
target:obj
selector:@selector(fireTimer:)
userInfo:nil
repeats:NO];

[[NSRunLoop currentRunLoop] addTimer:singleTimer
forMode:NSRunLoopCommonModes];

// Execute run loop
[[NSRunLoop currentRunLoop] run];

[pool release];

return 0;
}
MyClass.m:
#import "MyClass.h"

@implementation MyClass

- (void)fireTimer:(NSTimer *)theTimer {
NSLog(@"daemon-timer-test: timer fired");
}

@end

编辑(13/31/13 5:50 EDT):我在玩具应用程序代码中添加了以下代码,以结合内特关于使用GCD的 dispatch_after功能的建议,但似乎受到相同的时间限制。作为附加说明,主UI应用程序安装在 /Applications中,守护进程安装在 /usr/bin中。
    double delayInSeconds = 10.0;
NSLog(@"daemon-timer-test: delay is %f",delayInSeconds);
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
NSLog(@"daemon-timer-test: time has passed.");
});

编辑(3/31 5:54 PM):另一个快速说明。在系统日志似乎进入深度 sleep 之前,以下几行(不连续)显示在syslog中,并且在我唤醒电话之前没有更多消息。我选择了看起来可能相关的内容;最后一条消息是深度 sleep 之前发送到syslog的最后一条消息。
Mar 31 17:34:23 Andrew-MacKie-Masons-iPhone lockdownd[50]: 002c1000 -[hostWatcher handleSleepNotification:service:messageArgument:]: <hostWatcher: 0x1cd59890> [CC535EDB-0413-4E5E-A844-4DA035E7217C 169.254.2.141:54757] [fd=13]: kIOMessageCanSystemSleep
Mar 31 17:34:23 Andrew-MacKie-Masons-iPhone lockdownd[50]: 002c1000 -[hostWatcher handleSleepNotification:service:messageArgument:]: <hostWatcher: 0x1cd59890> [CC535EDB-0413-4E5E-A844-4DA035E7217C 169.254.2.141:54757] [fd=13]: kIOMessageSystemWillSleep
...
Mar 31 17:34:29 Andrew-MacKie-Masons-iPhone lockdownd[50]: 00343000 __63-[hostWatcher handleSleepNotification:service:messageArgument:]_block_invoke_0: Allowing Sleep
Mar 31 17:34:29 Andrew-MacKie-Masons-iPhone powerd[42]: PM scheduled RTC wake event: WakeImmediate inDelta=645.40
Mar 31 17:34:29 Andrew-MacKie-Masons-iPhone powerd[42]: Idle Sleep Sleep: Using BATT (Charge:76%)
...
Mar 31 17:34:29 Andrew-MacKie-Masons-iPhone kernel[0]: en0::stopOutputQueues
...
Mar 31 17:34:29 Andrew-MacKie-Masons-iPhone kernel[0]: pmu wake events: menu

最佳答案

简短答案

是的,这是可能的(我已经做到了)。

我尝试了几种不同的方法,但无法按照您所描述的方式将守护程序/NSTimer设置为失败,而失败。但是,我还没有看到定义您的应用程序的所有文件/代码,因此我至少还要担心一件事。

使守护程序保持 Activity 状态

如果您在Apple文档中查找NSRunLoop run:

If no input sources or timers are attached to the run loop, this method exits immediately; otherwise, it runs the receiver in the NSDefaultRunLoopMode by repeatedly invoking runMode:beforeDate:. In other words, this method effectively begins an infinite loop that processes data from the run loop’s input sources and timers.

Manually removing all known input sources and timers from the run loop is not a guarantee that the run loop will exit. OS X can install and remove additional input sources as needed to process requests targeted at the receiver’s thread. Those sources could therefore prevent the run loop from exiting.



在为守护程序的 main程序显示的代码中,您没有(直接)创建任何计时器。当然,我不知道您在 [[AMMQRDaemonManager alloc] init]中做什么,所以也许我错了。然后,您使用:
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop run];

开始运行循环。问题是,如果此时没有 没有计时器,则我不确定您的守护程序是否会继续存在。如果您查看上面的第二段,它也表明它可能仍然存在,所以也许这就是为什么当我尝试使用您的代码时,我的守护进程没有消失的原因。

您的评论说,当警报响起时,您可以看到守护进程还在运行。但是,我想知道您的守护进程是否终止,然后 重新启动。也许您也可以向我们展示您用于启动守护程序的.plist文件(该文件在 /System/Library/LaunchDaemons中)。

一个快速的实验,可能是 而不是自动启动守护程序。只需从 LaunchDaemons文件夹中卸载plist文件,并确保终止该过程即可。然后,从命令行手动启动它,将其插入手机中:

$ /Applications/MyApp.app/MyDaemon

然后,观看命令行。您将看到它是否死亡,并且由于它实际上不是由 launchd运行的,因此即使它死了也不会重新启动。

解决方案?

如果事实证明您 快要死了,那么我将尝试添加一个计时器,该计时器始终在守护程序执行时启动。如果您查看 at my other exampleChris Alvares' daemon tutorial,则显示此内容。在守护程序 main()中,设置一个 NSTimer来触发 run:方法。在该 run:方法中,您可以使用 while循环和 sleep()调用。或者只是安排计时器以某个缓慢的间隔重复。

我也不确定整个应用程序的工作方式。它是仅用于调度( NSTimer)警报的工具吗?如果是这样,则有可能在任何时候都未设置任何警报。也许是另一种解决方案,您可以将守护程序配置为 simply watch a data file,而不是使用 UIApplicationnotify_post()将新计时器传递给守护程序。每当有新计时器时, UIApplication都会写出数据文件。然后,iOS可以唤醒您的守护程序以安排 NSTimer

无论如何,这可能是与原始问题不同的问题,但它可能也是构建闹钟守护程序的更有效方法,因为如果没有 Activity 的闹钟,它实际上并不需要运行。

如果这些想法不能帮助您解决问题,请发布更多信息( [AMMQRDaemonManager init]的正文可能会有所帮助)。

更新

另外两个建议:
  • 确保您的应用程序(守护程序和UI)已安装在/Applications中。这是越狱应用程序的常规位置,但我只是想确保您未将其安装在沙箱区域中。
  • 尝试用GCD块替换NSTimer实现(对于警报,您可以将main()守护程序keepalive计时器保持原状):

  •    // you have used notify_post() to tell the daemon to schedule a new alarm:
    double delayInSeconds = 1000.0;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    // put timer expiration code here
    });

    更新二

    我还注意到,在您的原始 alarm:回调中,您使用无限超时的 CFUserNotificationReceiveResponse()。这意味着,如果用户不关闭弹出窗口,则计时器回调将不会完成,并且我认为这意味着不会触发随后调度的计时器回调。可能您应该将所有 CFUserNotification代码放入其自己的方法(例如 showPopup)中,然后像这样进行计时器回调:
    - (void)soundAlarm:(NSTimer *)theTimer {
    dispatch_async(dispatch_get_main_queue(), ^(void) {
    [self showPopup];
    });
    }

    然后,有一个主程序(在您放入Dropbox的代码中)。我建议将您的主计时器(您直接从 main()调用)更改为重复计时器,间隔相对较小,而不是使用 distantFuture触发日期。如果需要,您什么也不能做。这只是一个心跳。

    main.m:
    NSTimer *singleTimer = [[NSTimer alloc] initWithFireDate:[NSDate date]
    interval:5*60 // 5 minutes
    target:obj
    selector:@selector(heartbeat:)
    userInfo:nil
    repeats:YES];

    [[NSRunLoop currentRunLoop] addTimer:singleTimer
    forMode:NSRunLoopCommonModes];

    MyClass.m:
    - (void)heartbeat:(NSTimer *)theTimer {
    NSLog(@"daemon-timer-test: heartbeat timer fired");
    }

    我的最后一句话是我不使用 syslogd。我想知道您的任何测试是否失败,不是因为计时器未运行,而是因为 NSLog语句未显示在日志文件中。我已经在命令行中实际运行守护程序可执行文件的所有测试中完成了这些操作,然后将它们押入电话中,并且仅在控制台中查看 NSLog输出。从可能的故障点列表中注销...

    关于ios - 是否可以使用NSTimer将越狱的iPhone从深度 sleep 中唤醒?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15723432/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com