背景

之前给手机淘宝做了个准点提醒的中间件,类似闹铃提醒,使用sqlite和alarmManager两个组件实现,最近发现在MIUI上大量用户反馈提醒收不到,所以查了两天原因,把这个问题总结下以备后人参考。

场景再现

在说这个问题之前,先来说下MIUI奇葩的清理机制,没错,MIUI用户长按home键的那个清理过程,执行的是forceStopPackage操作。那么执行forcestop之后,android对于我们的app执行了什么操作呢,我们这里探究一下:

app 被forceStop以后,dalvik会调用ActivityManagerService的forceStopPackageLocked()方法,我们来看下这个方法:

private void forceStopPackageLocked(final String packageName, int uid) {forceStopPackageLocked(packageName, uid, false, false, true, false);Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,Uri.fromParts("package", packageName, null));if (!mProcessesReady) {intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);}intent.putExtra(Intent.EXTRA_UID, uid);
broadcastIntentLocked(null, null, intent,null, null, 0, null, null, null,false, false, MY_PID, Process.SYSTEM_UID);}

代码里面发送了一个广播:ACTION_PACKAGE_RESTARTED,这个广播大有文章。在android3.1以后的版本中,如果程序被强制停止后应用状态会被标记为STOPPED,同时发送该广播,进入一种冻结状态。

影响

1、对于Receiver的影响

在冻结状态下,应用无法收到其他应用的广播(就算监听系统的开机启动等广播也不行),要等到应用再开启一次,将STOPPED去掉以后才可以。

那是不是被冻结的应用除了被用户手动开启就再也没有办法启动了呢?不是的。

解决办法:

在广播发发送方发送广播时需要设置Intent.FLAG_INCLUDE_STOPPED_PACKAGES

Intent intent = new Intent();
intent.setAction("com.taobao.test");
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB_MR1) {intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);/
}
sendBroadcast(intent);

android 3.1以后有一类package 叫做stopped package, 它们就是那种安装了但是从来没有启动过的apk,或者被用户在程序管理里面force stop了的apk,intent中新加了一组flag(FLAG_INCLUDE_STOPPED_PACKAGES和FLAG_EXCLUDE_STOPPED_PACKAGES),带有FLAG_EXCLUDE_STOPPED_PACKAGES的 intent对stopped package是不起作用的。系统对所有的广播intent都加了flag:FLAG_EXCLUDE_STOPPED_PACKAGES,当然boot complete广播也不例外。默认Intent也都是FLAG_EXCLUDE_STOPPED_PACKAGES的

2、对于alarmManager的影响

我们先来看看AlarmManagerService.java的代码,可以看一个内部类UninstallReceiver

class UninstallReceiver extends BroadcastReceiver {public UninstallReceiver() {IntentFilter filter = new IntentFilter();filter.addAction(Intent.ACTION_PACKAGE_REMOVED);filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);filter.addDataScheme("package");mContext.registerReceiver(this, filter);// Register for events related to sdcard installation.IntentFilter sdFilter = new IntentFilter();sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);mContext.registerReceiver(this, sdFilter);}@Overridepublic void onReceive(Context context, Intent intent) {synchronized (mLock) {String action = intent.getAction();String pkgList[] = null;if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);for (String packageName : pkgList) {if (lookForPackageLocked(packageName)) {setResultCode(Activity.RESULT_OK);return;}}return;} else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);} else {if (Intent.ACTION_PACKAGE_REMOVED.equals(action)&& intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {// This package is being updated; don't kill its alarms.return;}Uri data = intent.getData();if (data != null) {String pkg = data.getSchemeSpecificPart();if (pkg != null) {pkgList = new String[]{pkg};}}}if (pkgList != null && (pkgList.length > 0)) {for (String pkg : pkgList) {removeLocked(pkg);mBroadcastStats.remove(pkg);}}}}}

可见AlarmManagerService接受了ACTION_PACKAGE_RESTARTED广播,而且执行了removeLocked(pkg)

removeLocked()是做什么的呢?继续看源码:

public void removeLocked(String packageName) {removeLocked(mRtcWakeupAlarms, packageName);removeLocked(mRtcAlarms, packageName);removeLocked(mElapsedRealtimeWakeupAlarms, packageName);removeLocked(mElapsedRealtimeAlarms, packageName);}private void removeLocked(ArrayList<Alarm> alarmList,String packageName) {if (alarmList.size() <= 0) {return;}// iterator over the list removing any it where the intent matchIterator<Alarm> it = alarmList.iterator();while (it.hasNext()) {Alarm alarm = it.next();if (alarm.operation.getTargetPackage().equals(packageName)) {it.remove();}}}

看到这里,大家应该明白了,removeLocked就是将对应package设置的所有类型的alarm都remove掉。

至于为什么google要加入这样的机制呢?我认为应该是出于系统安全的考虑。

android中强行停止(forceStopPackage)对alarmManager、Receiver的影响相关推荐

  1. Android设置中“强行停止”详解

    Android设置中"强行停止"详解 最近工作上遇到了广播接受不到的问题,查看了<Android 开发艺术探索>一书中关于广播的发送和接受的章节(P356-P362). ...

  2. Android设置中“强行停止”设置某个APP

    packages\apps\Settings\src\com\android\settings\applications\appinfo\AppButtonsPreferenceController. ...

  3. Android中设置定时闹钟以及AlarmManager详解

    AlarmManager是提供一种访问系统闹钟服务的方式,允许你去设置在将来的某个时间点去执行你的应用程序.当你的闹钟响起(时间到)时,在它上面注册的一个意图(Intent)将会被系统以广播发出,然后 ...

  4. android中如何停止动画,如何在Android中停止动画

    动画仅移动屏幕上的像素,而不移动对象的位置.为了让你留在它的最后,设置你的 animation.setFillAfter(true); 要实际移动对象的位置,请查看使用以下代码段的修改版本. Marg ...

  5. 谷歌停止对android更新,谷歌停止华为使用安卓系统? 可能影响新系统版本更新?...

    华为或将失去Android系统升级支持,可能影响系统版本更新. 根据路透社的最新消息了解,华为将立即的失去对Android系统的升级,也就是说以后的华为发布新的手机之后,将会有谷歌应用商城等一些谷歌方 ...

  6. android:catation=quot;90quot;,Android中的AlarmManager的使用.htm

    var protocol = window.location.protocol; document.write(' Android中的AlarmManager的使用 - wangxingwu_314的 ...

  7. Android中AlarmManager的使用

    本篇博客的部分内容参考了:https://www.cnblogs.com/ProtectedDream/p/6351447.html 最近在写一个 "抢订羽毛球场地" 的 app, ...

  8. Android中的AlarmManager的使用

    1.AlarmManager,顾名思义,就是"提醒",是Android中常用的一种系统级别的提示服务,在特定的时刻为我们广播一个指定的Intent.简单的说就是我们设定一个时间,然 ...

  9. Android中定时器AlarmManager的用法

    AlarmManager是Android提供的全局定时器,利用系统闹钟定时发送广播.可以实现定时执行代码的目的.只要我们APP在后台运行,那么我们就可以定时执行我们的代码.当然,由于高版本Androi ...

最新文章

  1. web前端开发培训有哪些学习阶段
  2. Linux下基于官方源代码RPM包构建自定义MySQL RPM包
  3. 设计模式:访问者模式(Vistor)
  4. 邹建老大写的经典SQL
  5. 重构 - 美股行情系统APP推送改造
  6. 云原生2.0时代:企业更应了解一下容器安全
  7. python菜鸟教程网-Python JSON
  8. PySide QtCore.Signal帮助手册
  9. Illustrator 教程,如何在 Ai 中创建一个新文档?
  10. python计算器程序设计课程报告_20193120 2019-2020-2 《Python程序设计》实验二报告
  11. lisp ssget 浩辰_lisp程序--AutoCAD和浩辰GstarCAD.pdf
  12. SpringBoot实现QQ邮箱注册和登录
  13. 名帖325 启功 行书《行书帖选》
  14. python的pptx文档remove_Python之pptx实现添加内容与删除(移动)页操作
  15. 程序员钱多多准备应聘拼多多
  16. 讨巧的站点简体/繁体中文切换方法
  17. 金融大亨的十二条人生信条
  18. python读取usb扫码枪数据_PyUsb USB条码扫描
  19. 学生用计算机明细清单,学生电脑配置清单
  20. 模拟电子技术-信号产生电路

热门文章

  1. Camtasia2020官方汉化免费下载录屏软件
  2. 用python 和pyqt5写俄罗斯方块游戏
  3. 从服务器获取文件错误,在尝试获取许可证时出现无法从许可证服器上读取数据的错误信息...
  4. plsql连接oracle18c,plsqloracle10客户端连接oracle18coracle18c导入oracle11gdmp到1
  5. 群晖Video Station刮削器使用指南
  6. 极空间Docker安装Alist套件整合阿里云盘、百度云盘等网盘资源并挂载到本地供极影视刮削播放完整教程
  7. Weka和Mulan的介绍和理解
  8. Directx11基础教程一之Directx11框架
  9. 多线程内使用GetDC的注意问题
  10. 省大连八中2014-2015学年高二上学期期中考试化学