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

最近工作上遇到了广播接受不到的问题,查看了《Android 开发艺术探索》一书中关于广播的发送和接受的章节(P356-P362)。其中(P358)介绍了从Android 3.1 之后广播的一些区别 。
从 Android 3.1 开始,系统为所有的广播都默认添加了FLAG_EXCLUDE_STOPPED_PACKAGES 标志。所有处于停止状态的应用将无法接受到该标志的广播。注意,只有两种情况下应用才会处于停止状态:
  • 应用安装后未运行
  • 应用被手动(设置-应用-强制停止)或者其他应用强制停止了
如果需要启动处于停止状态的应用,则只要为Intent添加 FLAG_INCLUDE_STOPPED_PACKAGES 标记即可。
技术小黑屋的这个解析的确很完整,但是在问答环节我看到这样一个问题:
提问:如果我的程序没有activity只有一个receiver,我改如何激活才能接收到正常的广播intent呢
回答:实际上,如果是上面所述的情况,该应用在安装之后不是处于停止状态,因为它没有任何用户可以直接点击的行为去将它移除停止状态.你可以正常接收广播intent,除非你人为地将它强制停止.
在页面的最底端我也看到了有人这样留言:
  • 你好,我写了一个只有receiver和service的app,安装后是无法接受系统广播的,后来用了一个自定义的广播启动它过一次后,才开始接受系统广播了
  • 我认为你的那个app安装之后不是处于停止状态(关于验证,你可以查看系统设置中的应用程序,那里面能准确的看出是否为停止状态),另外我感觉你应该确认一下系统广告是否发出,因为你后面的说,自定义的广告可以接收即表明这个程序处于非停止状态。希望可以确认一下哈。
看到这个回答,我的内心是抗拒的。于是我自己写了个Demo测试了一下,非常简单的代码:
AndroidManifest.xml:

[代码]xml代码:

?
1
2
3
4
5
6
< receiver android:name = "com.roger.BroadcastTest.Receiver" android:enabled = "true" android:exported = "true" >
       < intent-filter >
           < action android:name = "android.intent.action.BOOT_COMPLETED" >
           < action android:name = "com.roger.broadcast.test" >
       </ action ></ action ></ intent-filter >
    </ receiver >

JAVA:

[代码]java代码:

?
1
2
3
4
5
6
7
8
public class Receiver extends BroadcastReceiver {
     @Override
     public void onReceive(Context arg0, Intent arg1) {
         // TODO Auto-generated method stub
         Log.i( "Tag" , "receive:" + arg1.getAction());
     }
}

应用中就注册了一个广播接收器,安装后直接重启,果然并没有收到开机成功的广播。然而设置中查看,该应用并没有处于停止状态。所以我猜想,安装后未启动的应用(未启动过该应用中任何四大组件),虽然在设置中显示未停止,但在framework中,应该是处于停止状态的。
来,开始苦逼的看代码之路,我想要搞清楚的有两点:
  • framework中广播分发者如何区分广播接收器是否处于停止状态
  • framework中如何将应用从停止状态切换到非停止状态
开始第一点,对于广播分发的过程
我们从Intent中开始,介绍一个framework源码搜索网站:http://androidxref.com/,我们选4.4的源码,搜索FLAG_INCLUDE_STOPPED_PACKAGES,点击链接跟进到Intent源码中,看到这样一个方法:

[代码]java代码:

?
1
2
3
4
5
/** @hide */
     public boolean isExcludingStopped() {
         return (mFlags&(FLAG_EXCLUDE_STOPPED_PACKAGES|FLAG_INCLUDE_STOPPED_PACKAGES))
                 == FLAG_EXCLUDE_STOPPED_PACKAGES;
     }

很明显,这个方法返回的是发送的广播是否需要包含处于停止状态的应用。再跟进改方法的使用者,跟进到IntentResolver.java中:

[代码]java代码:

?
1
final boolean excludingStopped = intent.isExcludingStopped();

这个变量在哪使用呢?

[代码]java代码:

?
1
2
3
4
5
6
if (excludingStopped && isFilterStopped(filter, userId)) {
                 if (debug) {
                     Slog.v(TAG, "  Filter's target is stopped; skipping" );
                 }
                continue ;
            }

在buildResoleList中,Good,看到log我们似乎离成功不远了,那么这个isFilterStopped方法肯定是判断应用是否处于停止状态的,再更进:

[代码]java代码:

?
1
2
3
4
5
6
7
8
/**
  * Returns whether the object associated with the given filter is
  * "stopped," that is whether it should not be included in the result
  * if the intent requests to excluded stopped objects.
  */
protected boolean isFilterStopped(F filter, int userId) {
     return false ;
}

什么鬼~?直接返回false?逗我吗?..再认真看下注释,大概意思是传到这个方法的filter必须已经排除了’stopped’ 的应用,这?应该是被重写了,继续在全局搜索该方法名,果然,在PackageManagerService中,看到了如下代码:

[代码]java代码:

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
@Override
protected boolean isFilterStopped(PackageParser.ActivityIntentInfo filter, int userId) {
     if (!sUserManager.exists(userId)) return true ;
     PackageParser.Package p = filter.activity.owner;
     if (p != null ) {
         PackageSetting ps = (PackageSetting)p.mExtras;
         if (ps != null ) {
             // System apps are never considered stopped for purposes of
             // filtering, because there may be no way for the user to
             // actually re-launch them.
             return (ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0
                     && ps.getStopped(userId);
         }
     }
     return false ;
}

这下无误了吧!再看到380行:

[代码]java代码:

?
01
02
03
04
05
06
07
08
09
10
11
12
13
// All available activities, for your resolving pleasure.
     final ActivityIntentResolver mActivities =
             new ActivityIntentResolver();
     // All available receivers, for your resolving pleasure.
     final ActivityIntentResolver mReceivers =
             new ActivityIntentResolver();
     // All available services, for your resolving pleasure.
     final ServiceIntentResolver mServices = new ServiceIntentResolver();
     // All available providers, for your resolving pleasure.
     final ProviderIntentResolver mProviders = new ProviderIntentResolver();

379行注释:所有有效的receivers都被这个ActivityIntentResolver解析,Good!现在我们看到主要是通过PackageSetting这个类中的getStopped方法来判断应用是否处于停止状态。那么有哪些动作将会对这个值有影响呢?看到PackageSettingBase中关于设定改值的方法:

[代码]java代码:

?
1
2
3
void setStopped( boolean stop, int userId) {
      modifyUserState(userId).stopped = stop;
}

再通过查询调用者,我们会发现主要有以下代码将影响改值:
从停止到非停止状态(成功启动该应用中的四大组件即可)
ActivityStack中

[代码]java代码:

?
1
2
3
4
5
6
// Launching this app's activity, make sure the app is no longer
// considered stopped.
try {
    AppGlobals.getPackageManager().setPackageStoppedState(
             next.packageName, false , next.userId); /* TODO: Verify if correct userid */
}

ActiveServices中

[代码]java代码:

?
01
02
03
04
05
06
07
08
09
10
11
// Service is now being launched, its package can't be stopped.
         try {
             AppGlobals.getPackageManager().setPackageStoppedState(
                     r.packageName, false , r.userId);
         }
ActivityManagerService中
                         // Content provider is now in use, its package can't be stopped.
                         try {
                             AppGlobals.getPackageManager().setPackageStoppedState(
                                     cpr.appInfo.packageName, false , userId);
                         }

BroadcastQueue中

[代码]java代码:

?
1
2
3
4
5
// Broadcast is being executed, its package can't be stopped.
             try {
                 AppGlobals.getPackageManager().setPackageStoppedState(
                         r.curComponent.getPackageName(), false , UserHandle.getUserId(r.callingUid));
             }

从非停止状态到停止状态(初始化以及设置中点击强制停止)
在/frameworks/base/services/java/com/android/server/pm/Settings.java 中 有对 “packages-stopped.xml”文件的读操作,未找到写操作,但我相信在应用安装成功后会加入”packages-stopped.xml”文件中
设置中点击强制停止 /packages/apps/Settings/src/com/android/settings/applications/ProcessStatsDetail.java:

[代码]java代码:

?
1
2
3
4
5
6
private void killProcesses() {
         ActivityManager am = (ActivityManager)getActivity().getSystemService(
                 Context.ACTIVITY_SERVICE);
         am.forceStopPackage(mEntry.mUiPackage);
        checkForceStop();
     }

至此,通过源码我们已经了解,如果新安装的应用,未曾成功启动过四大组件,默认是处于停止状态的,这也是Google对系统的保护想要达到的效果。

Android设置中“强行停止”详解相关推荐

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

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

  2. Android AVD创建及设置中各参数详解

    本文根据如下的模拟器安装做一些解释: 本文环境:Windows XP sp3,最新JAVa环境,android-sdk_r06-windows.zip,android 2.2 API Level 8, ...

  3. Android Studio中Gradle使用详解

    转自:http://www.jianshu.com/p/02cb9a0eb2a0 一)基本配置 build配置 buildscript {repositories {jcenter() }depend ...

  4. android调webview的方法,Android中的WebView详解

    Android中的WebView详解 WebView详解 基本用法 布局文件配置WebView android:id="@+id/wv_news_detail" android:l ...

  5. android中oncreate方法,android开发之onCreate( )方法详解

    这里我们只关注一句话:This is where you should do all of your normal static set up.其中我们只关注normal static, normal ...

  6. Android 中malloc_debug 原理详解

    版本基于:Android R 关联博文: Android 中malloc_debug 使用详解 0. 前言 最近上项目中遇到一个native 可能内存泄漏的问题,曾考虑使用HWASAN,但这个工具是针 ...

  7. Android中mesure过程详解 (结合Android 4.0.4 最新源码)

    如何遍历并绘制View树?之前的文章Android中invalidate() 函数详解(结合Android 4.0.4 最新源码)中提到invalidate()最后会发起一个View树遍历的请求,并通 ...

  8. Android中layout过程详解 (结合Android 4.0.4 最新源码)

    上一篇文章Android中mesure过程详解 (结合Android 4.0.4 最新源码)介绍了View树的measure过程,相对与measure过程,本文介绍的layout过程要简单多了,正如l ...

  9. html里的section可以设置id,html5中section元素详解

    html5中section元素详解 一.总结 一句话总结: section元素 用来定义文章中的章节(通常应该有标题和段落内容) section元素的作用就是给内容分段,给页面分区 1.section ...

最新文章

  1. 学生教育云平台登录入口_湖南省教育云平台登录入口
  2. GDB 调试 Mysql 实战(二)GDB 调试打印
  3. iOS单个应用程序的最大可用内存是多少?
  4. wamp如何更改网站根目录DocumentRoot
  5. 高通平台点亮LCD个人总结
  6. linux下随机数字的生成
  7. VTK:Filtering之Glyph2D
  8. 使用ImitateLogin模拟登录百度
  9. InstallShield 2011新功能试用(9)- 安装包大小压缩
  10. Javascript-Switch
  11. [ACM_几何] F. 3D Triangles (三维三角行相交)
  12. react,react-router,redux+react-redux 构建一个React Demo
  13. Python 父类调用子类方法
  14. 理解Heap Profling名词-Shallow和Retained Sizes
  15. Nodejs ---- 升级到指定版本
  16. 2019年博客之星评选活动之晋级TOP20博主名单
  17. 怎么更改计算机物理地址,修改MAC地址,教您怎么修改MAC地址
  18. AI识别照片是谁,人脸识别face_recognition开源项目安装使用 | 机器学习
  19. MFC应用程序设计(第二版)学习笔记
  20. python html5游戏_25 个超棒的 HTML5 JavaScript 游戏引擎开发库

热门文章

  1. Geomagic Studio 调整模型的倾斜角度
  2. Geomagic Touch(LAN口版本) 环境配置及驱动安装【过程记录】
  3. 华为服务器gpu芯片,GPU云运算服务器方案
  4. Hanselminutes on 9 -Managing People(以及Chris Sells的智慧)
  5. Linux 规定的 4 种文件类型,Linux中的文件类型以及文件属性
  6. c++为什么一定要定义无参构造函数?类中无参构造的作用
  7. java子类要调用父类的无参构造函数
  8. JAVA-JDK配置说明
  9. Android开发简单的ViewGroup——FrameLayout
  10. 什么是云计算解决方案架构师