为了账号安全,请及时绑定邮箱和手机立即绑定

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

标签:
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对系统的保护想要达到的效果。

原文链接:http://www.apkbus.com/blog-705730-60732.html

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消