android 关机闹钟

实现关机状态下Android手机的闹钟功能

http://blog.youkuaiyun.com/g_salamander/article/details/8487328


新项目的手机需要实现关机状态下的闹钟,早在刚开始接触 android 的时候都在想为什么 android 不支持关机状态下的一些功能呢?像充电或者闹钟什么的,虽然每个平台的驱动不一样但上层应用是可以提供统一接口的呀,果然在 4.0 的时候支持关机充电了,关机闹钟仍然不在默认支持中。市场上的很多品牌手机也都不支持这个功能,让很多用惯了 Feature Phone 以及担心辐射的用户都不习惯。这次做关机闹钟在一些思路上借鉴了关机充电的实现方法。

整体思路如下:

在 uboot 中通过 PMU 判断开机的原因,如果是 RTC 模块使能开机则在 uboot 中传递启动参数 androidboot.mode=alarm,然后在 init 进程中判断启动模式(当前系统有 3 种启动模式:normal、charger、alarm),如果是 alarm 模式则启动 alarm 服务,alarm 服务与应用程序 alarm关联,因此需要编写应用程序来实现关机闹钟的功能。应用程序主要实现以下几个个方面的功能:1、显示关机闹钟的 UI 以及当前时间;2、播放闹铃;3、读取 input 事件判断用户操作;4、用户可以在 UI 中选择懒人模式、开机或者关机。下面逐个解析这几个功能的实现:

1、UI

在 zygote 没有启动之前完成 UI 显示可以参考 charger 的做法,用 android 的 minui 接口,这些接口实现了图形的描绘以及固定大小的文字显示,函数介绍如下:

  1. int gr_init(void);             /* 初始化图形显示,主要是打开设备、分配内存、初始化一些参数 */  
  2. void gr_exit(void);            /* 注销图形显示,关闭设备并释放内存 */  
  3.   
  4. int gr_fb_width(void);         /* 获取屏幕的宽度 */  
  5. int gr_fb_height(void);        /* 获取屏幕的高度 */  
  6. gr_pixel *gr_fb_data(void);    /* 获取显示数据缓存的地址 */  
  7. void gr_flip(void);            /* 刷新显示内容 */  
  8. void gr_fb_blank(bool blank);  /* 清屏 */  
  9.   
  10. void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a);  /* 设置字体颜色 */  
  11. void gr_fill(int x, int y, int w, int h);  /* 填充矩形区域,参数分别代表起始坐标、矩形区域大小 */  
  12. int gr_text(int x, int y, const char *s);  /* 显示字符串 */  
  13. int gr_measure(const char *s);             /* 获取字符串在默认字库中占用的像素长度 */  
  14. void gr_font_size(int *x, int *y);         /* 获取当前字库一个字符所占的长宽 */  
  15.   
  16. void gr_blit(gr_surface source, int sx, int sy, int w, int h, int dx, int dy);  /* 填充由source指定的图片 */  
  17. unsigned int gr_get_width(gr_surface surface);   /* 获取图片宽度 */  
  18. unsigned int gr_get_height(gr_surface surface);  /* 获取图片高度 */  
  19. /* 根据图片创建显示资源数据,name为图片在mk文件指定的相对路径 */  
  20. int res_create_surface(const char* name, gr_surface* pSurface);  
  21. void res_free_surface(gr_surface surface);       /* 释放资源数据 */  
图片只支持 png 格式,做这个 UI 的图片资源花了不少时间(没做过美工),一般图片的显示先由 res_create_surface 创建资源数据,然后调用 gr_blit 填充,最后调用 gr_flip 刷新显示。在关机闹钟的界面还需要显示当前时间,最开始调用 minui 默认的字库来显示,但是默认字库的字体太小了,只支持 10 x 18 ASIC-II 编码的字符,效果很不好,后来就把时间需要的 10 个数字以及符号以图片的形式显示。

2、闹铃

在这个阶段播放闹铃只能选择 tinyplay,tinyplay 是 android 自带的一款简易播放器,只能播放固定格式的 wav 文件。UI 显示以及播放闹铃分别独占一个线程,以保证各自不被干扰。

3、input evnt

当闹钟开始响后,用户可以通过触摸屏点击选择是否开关机或者进入懒人模式,这里就需要对用户操作做出判断,即在程序中去读取 /dev/input 下面设备的数据。当进入懒人模式后会停止闹铃 5 分钟再响,这个阶段需要关闭 lcd 和 触摸屏,用户可以通过按键提前唤醒。input event 是在进程中循环读取并处理的,示例代码如下:

  1. static int event_loop(void)  
  2. {  
  3.     int i;  
  4.     int ret = 0;  
  5.     int nfds = ALARM_MAX_DEVICE;  
  6.     struct input_event event;  
  7.     const char *device = NULL;  
  8.     const char *device_path = "/dev/input";  
  9.   
  10.     ret = scan_dir(device_path);   /* 扫描该目录下的设备节点,我们只打开触摸屏和按键 */  
  11.     if(ret < 0) {  
  12.         printf("scan dir failed for %s.\n", device_path);  
  13.         return ret;  
  14.     }  
  15.   
  16.     for(;;) {  
  17.         poll(ufds, nfds, -1);      /* 轮询检测是否有触摸屏或者按键事件 */  
  18.   
  19.         for (i = 0; i < nfds; i++) {  
  20.             if(ufds[i].revents) {  /* have valid value. */  
  21.                 if(ufds[i].revents & POLLIN) {  
  22.                     ret = read(ufds[i].fd, &event, sizeof(event));      /* 读取事件 */  
  23.                     if (ret < (int)sizeof(event)) {  
  24.                         printf("could not get event.\n");  
  25.                         continue;  
  26.                     }  
  27.                     handle_event(event.type, event.code, event.value);  /* 处理事件 */  
  28.                 }  
  29.             }  
  30.         }  
  31.     }  
  32.   
  33.     return 0;  
  34. }  

附:android 权限管理机制

这次在编译使用 alarm 的时候遇到了一个权限问题:编译出来的 alarm 可执行程序在 out 目录下面是拥有可执行权限的,但是在烧录到机器后发现没有可执行权限了,最后才发现是 android 的权限管理机制引起的。

1、文件系统中的权限设定

在 android 系统编译完成后会生成后缀为 img 的文件如:system.img、boot.img,包含了许多目录和文件。在编译的时候会用到 mkbootfs 等命令,这些命令将会调用 system/core/include/private/android_filesystem_config.h文件中预定义的权限,来预置这些目录和文件的初始访问权限。关机闹钟的可执行程序就需要在这里预置权限。示例定义如下:

  1. /* 目录的预定义权限 */  
  2. static struct fs_path_config android_dirs[] = {  
  3.     { 00770, AID_SYSTEM, AID_CACHE,  "cache" },  
  4.     { 00771, AID_SYSTEM, AID_SYSTEM, "data/app" },   /* app目录的权限 */  
  5.     { 00771, AID_SYSTEM, AID_SYSTEM, "data/app-private" },  
  6.     ...  
  7.     { 00755, AID_ROOT,   AID_ROOT,   "system/etc/ppp" },  
  8.     { 00777, AID_ROOT,   AID_ROOT,   "sdcard" },     /* sdcard目录的权限 */  
  9.     { 00755, AID_ROOT,   AID_ROOT,   0 },  
  10. };  
  11.   
  12. /* 文件的预定义权限 */  
  13. static struct fs_path_config android_files[] = {  
  14.     { 00440, AID_ROOT,      AID_SHELL,     "system/etc/init.goldfish.rc" },  
  15.     { 00550, AID_ROOT,      AID_SHELL,     "system/etc/init.goldfish.sh" },  
  16.     { 00644, AID_SYSTEM,    AID_SYSTEM,    "data/app/*" },   /* app目录下所有文件的权限 */  
  17.     { 00644, AID_MEDIA_RW,  AID_MEDIA_RW,  "data/media/*" },  
  18.     { 00644, AID_SYSTEM,    AID_SYSTEM,    "data/app-private/*" },  
  19.     { 00644, AID_APP,       AID_APP,       "data/data/*" },  /* data目录下所有文件的权限 */  
  20.     ...  
  21.     { 06750, AID_ROOT,      AID_SHELL,     "system/bin/run-as" },  
  22.     { 00755, AID_ROOT,      AID_SHELL,     "system/bin/*" }, /* 所有系统可执行程序的权限 */  
  23.     { 00755, AID_ROOT,      AID_ROOT,      "system/lib/valgrind/*" },  
  24.     { 00755, AID_ROOT,      AID_SHELL,     "system/xbin/*" },  
  25.     { 00755, AID_ROOT,      AID_SHELL,     "system/xlib/*" },  
  26.     { 00755, AID_ROOT,      AID_SHELL,     "system/vendor/bin/*" },  
  27.     { 00750, AID_ROOT,      AID_SHELL,     "sbin/*" },  
  28.     { 00755, AID_ROOT,      AID_ROOT,      "bin/*" },  
  29.     { 00750, AID_ROOT,      AID_SHELL,     "init*" },  
  30.     { 00750, AID_ROOT,      AID_SHELL,     "charger*" },      /* 关机充电可执行程序的权限 */  
  31.     { 00750, AID_ROOT,      AID_SHELL,     "alarm*" },        /* 关机闹钟可执行程序的权限 */  
  32.     { 00644, AID_ROOT,      AID_ROOT,       0 },  
  33. };  
如果有新的需要只要把相应的预定义设置添加到相应数组即可。

2、设备文件的权限

android 系统中,kernel 启动后运行的第一个进程为 init,init 进程会打开定义为 NETLINK_KOBJECT_UEVENT的 socket,接收内核发送的添加或删除设备的 uevnet 消息。并通过调用 system/core/init/devices.c文件中的 add_dev_perms 函数完成设备文件的权限初始化,参数来自于 xxx.rc 文件。

其他由 kernel 或 init 及其脚本创建的目录或文件,如果需要修改访问权限,可以通过 init 使用的脚本文件 init.rc 控制,但不建议直接修改 init.rc 文件,而应该集中在和硬件相关的或新增的 init.vendore.rc 脚本文件中修改,这样做的好处是集中管理,便于移植和版本升级。

<think>首先,用户的问题是:“我想查找关于Android系统关机通知的相关信息 请问Android系统关机通知的实现方法及相关信息”。用户提到了Android系统关机通知,我需要基于提供的引用信息来回答。 提供的引用包括: - 引用[1]:讨论了Android系统关机与重启的源码分析,涉及电源管理模块、系统服务(如AMS和PMS)、权限校验和消息传递机制。 - 引用[2]:关于Android实现关机的源码,提到了关机入口(performShutdown())和授权方案(shutdownWithPermission()和shutdownWithRoot())。 - 引用[3]:涉及Android关机闹钟的实现,提到了上层调用setnextalarm和snooze操作。 用户最后说,“上述引用仅供参考,并不是用户真正的需求,请尽可能多的参考用户上一次的问题和你的回答。” 但我没有用户上一次问题的历史记录。系统提示是新的对话,所以这里可能指的是当前上下文。用户的问题是新的,我需要基于当前输入回答。 核心问题是“Android系统关机通知的实现方法及相关信息”。这里“关机通知”可能指的是系统在关机时发送通知,或者是通知用户关机的事件。用户说“关机通知”,可能是一个通知机制,类似于在关机前发送通知给应用程序。 在引用中,没有直接提到“关机通知”。让我检查引用: - 引用[1]:描述了关机和重启的触发机制、消息传递(AMS和PMS协同)、权限校验。 - 引用[2]:具体代码实现关机入口。 - 引用[3]:关机闹钟的实现,涉及闹钟在关机后唤醒设备。 用户问题是“关机通知”,而引用[3]提到“关机闹钟”,这可能相关,因为关机闹钟涉及到在关机状态下设置闹钟,然后设备在闹钟时间开机。但这不是直接关于“通知”的。 我需要推测“关机通知”的意思。可能是指Android系统在即将关机时发送广播通知给应用程序,以便应用可以保存状态或执行清理操作。在Android中,确实有这样的机制。 例如,在Android中,当系统准备关机时,它会发送ACTION_SHUTDOWN意图(Intent),应用程序可以注册接收这个广播来处理关机事件。 基于引用[1],它有提到消息传递机制,特别是AMS(Activity Manager Service)和PMS(Power Manager Service)的协同。所以,我应该从这个角度切入。 回答结构: - 解释Android系统关机通知的概念。 - 描述实现方法,包括相关服务和广播。 - 提供相关信息,如权限、源码参考。 最后,需要生成相关问题作为系统指令要求。 系统指令: - 所有行内数学表达式用$...$格式(但这里可能用不到数学表达式)。 - 独立公式用$$...$$(同样,可能不适用)。 - LaTeX语法正确(在文本中不需要复杂LaTeX)。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾添加引用标识,例如[^1]。 在回答中,我需要引用提供的引用。引用[1], [2], [3]。用户说“参考站内引用”,所以我应该基于这些引用回答。 步骤: 1. 定义Android系统关机通知:这可能是指系统发送广播通知关机事件。 2. 实现方法:基于引用,AMS和PMS处理关机请求。PMS可能涉及发送广播。 例如,在关机过程中,系统会发送Intent.ACTION_SHUTDOWN广播。 3. 相关信息:权限校验(如引用[2]提到的授权方案),关机闹钟的实现(引用[3]可能相关)。 4. 在回答末尾添加引用标识。 生成相关问题。 回答结构: - 先介绍概念。 - 然后详细描述实现方法。 - 最后提供相关信息。 - Générer des questions connexes. 由于用户提到“关机通知”,而从引用看,最相关的可能是ACTION_SHUTDOWN广播。 在Android开发文档中,ACTION_SHUTDOWN是一个广播动作,当设备关闭时发送。应用程序可以注册BroadcastReceiver来监听这个。 基于引用[1],它说“当用户通过UI界面选择关机或重启时,这一操作将通过系统服务传递到system_server进程。...涉及到多级权限校验”。然后,“消息传递机制”部分提到AMS和PMS协同。 所以,我可以推断,在关机过程中,AMS可能会发送一个广播。 引用[3]提到“关机闹钟”,这可能与关机后唤醒相关,但不是直接通知。 回答时,我需要专注于关机通知的实现。 计划回答: 1. **Android系统关机通知概述**:解释什么是关机通知(即系统在关机前发送广播通知)。 2. **实现方法**:描述广播机制,AMS和PMS的角色,权限校验。 - 使用引用[1]的内容。 - 添加代码示例如果有(但有引用[2],它有关机入口)。 3. **相关信息**:提到关机闹钟作为相关主题(引用[3])。 4. **引用标识**:在相关句子末尾加[^1], [^2], [^3]。 最后,生成相关问题。 相关问题示例: 1. 如何注册接收Android关机广播通知? 2. Android关机过程中的权限校验是如何工作的? 3. 关机闹钟是如何实现的?它与关机通知相关吗? 确保语言是中文。 </think>### Android系统关机通知的实现方法及相关信息 在Android系统中,“关机通知”通常是指系统在即将执行关机操作时,向注册的应用程序发送广播通知,允许应用在关机前保存状态、执行清理操作或响应事件。这一机制是Android电源管理的关键部分,涉及到多个系统服务和组件协同工作。以下基于您提供的引用内容,我将详细解释实现方法及相关信息。引用来源包括Android关机与重启的源码分析[^1]、关机实现的具体入口代码[^2],以及关机闹钟的实现[^3]。 #### 1. **Android系统关机通知的实现方法** Android系统关机通知的核心是通过 **广播机制(Broadcast)** 来实现的。当用户触发关机操作(如通过UI界面选择关机)时,系统会发送一个特定的意图(Intent),例如 `Intent.ACTION_SHUTDOWN`,应用程序可以注册接收这个广播来处理关机事件。实现过程涉及以下关键步骤: - **触发关机操作**:关机请求从用户界面(如设置App)发起,通过系统服务(如 `ActivityManagerService` 或 `PowerManagerService`) 传递到 `system_server` 进程。这个过程包括严格的权限校验,确保只有具有系统权限(如 `SHUTDOWN` 权限)的操作才能执行[^1]。引用[2]中提到,关机操作的总入口通常是一个方法如 `performShutdown()`,它会优先尝试授权方案(`shutdownWithPermission()`),如果失败才回退到root方案(`shutdownWithRoot()`)[^2]。 - **消息传递与广播发送**:在关机过程中,`ActivityManagerService` (AMS) 和 `PowerManagerService` (PMS) 协同工作。AMS负责管理应用生命周期,而PMS处理电源状态。当关机请求被验证通过后,PMS会触发一个系统级广播 `ACTION_SHUTDOWN`。这个广播会被发送到所有注册的 `BroadcastReceiver`,应用程序可以在此监听并执行自定义操作(如保存数据或关闭服务)。引用[1]强调了这一协同机制,指出“关机和重启操作的消息传递机制涉及到AMS和PMS在操作中的协同”,确保通知可靠传递[^1]。 - **应用程序注册接收通知**:开发者可以在应用中实现一个 `BroadcastReceiver` 来监听 `ACTION_SHUTDOWN` Intent。例如,在AndroidManifest.xml中声明接收器: ```xml <receiver android:name=".ShutdownReceiver"> <intent-filter> <action android:name="android.intent.action.ACTION_SHUTDOWN" /> </intent-filter> </receiver> ``` 在代码中,接收器可以处理关机事件: ```java public class ShutdownReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_SHUTDOWN.equals(intent.getAction())) { // 执行清理操作,如保存数据或通知用户 Log.d("Shutdown", "系统即将关机,执行应用清理"); } } } ``` 这一机制确保了在关机前,应用有短暂时间(通常几秒)响应,但开发者需注意避免耗时操作以防止关机延迟。 #### 2. **相关信息** - **权限与安全**:发送关机通知需要系统级权限。引用[1]指出“这一过程涉及到多级权限校验”,例如,应用必须声明 `android.permission.SHUTDOWN` 权限(通常只授予系统App),否则无法接收或发送相关广播。普通应用可能需要通过系统签名或root权限来实现类似功能,如引用[2]所述的回退机制[^1][^2]。 - **与其他机制的关联**:关机通知与Android关机闹钟功能相关但不相同。引用[3]提到,“上层调用setnextalarm就行了”,关机闹钟通过设置闹钟在设备关机后唤醒系统(例如使用RTC闹钟),而关机通知则是关机前的广播事件。如果应用需要处理关机后的唤醒(如闹钟),可能需要结合 `AlarmManager` 服务来实现[^3]。 - **源码参考与最佳实践**:在Android源码中(如AOSP),关机通知的实现位于 `frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java` 文件中,具体在关机流程中调用 `sendShutdownBroadcast()` 方法。最佳实践包括: - 优化广播接收器:避免在 `onReceive` 中执行长时间任务,使用异步处理。 - 测试与兼容性:在不同Android版本中验证,因为广播行为可能因OS版本而异(如Android 10+可能对后台广播有限制)。 - 引用[1]和[2]提供的源码分析可作为深入参考,帮助理解底层逻辑[^1][^2]。 - **潜在问题**:如果关机通知未正确处理,可能导致应用状态丢失或系统不稳定。例如,引用[3]提到在关机闹钟实现中“机器启动后会把之前的snooze的操作给清除掉”,这强调了在关机通知中保存持久状态的重要性[^3]。 #### 总结 Android系统关机通知主要通过广播机制实现,由AMS和PMS协同发送 `ACTION_SHUTDOWN` Intent,允许应用响应关机事件。整个过程依赖于权限校验和系统服务,确保安全可靠。相关源码和实践可参考您提供的引用内容。如果您需要更详细的代码示例或特定场景分析,请提供更多细节。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值