zoukankan      html  css  js  c++  java
  • android安全:forceStopPackage对android的Alarm的影响

    也许一些使用alarmmanager做定时任务的同学遇到过这样的问题:设定alarm后,进入设置-->应用程序管理-->强行停止app后,定时任务就失效了。


    简单的讲就是:force stop会导致alarm失效。


    最典型的例子就是我碰到过的一个bug,使用android手机的时钟app设置一个闹钟,然后进入设置-->应用程序管理里面,将时钟这个app force stop掉,结果闹钟就不响了。

    其实这不是bug,这是android系统的新加入的机制。下面我来详细分析一下来龙去脉。


    1. 在设置的应用程序管理里面强行停止app:

        这里会最终会调用到 ActivityManagerService的forceStopPackageLocked()

    源代码如下:

    <SPAN style="FONT-SIZE: 18px">    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); 
        }</SPAN> 
        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,这个广播大有文章。

    2. 再看看AlarmManagerService.java的代码,可以看一个内部类UninstallReceiver

    源代码如下:

    [java]
    <SPAN style="FONT-SIZE: 18px">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); 
            } 
             
            @Override 
            public 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); 
                        } 
                    } 
                } 
            } 
        }</SPAN> 
    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);
            }
           
            @Override
            public 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()是做什么的呢?继续看源码:
    
    [java]
    <SPAN style="FONT-SIZE: 18px">    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 match  
            Iterator<Alarm> it = alarmList.iterator(); 
             
            while (it.hasNext()) { 
                Alarm alarm = it.next(); 
                if (alarm.operation.getTargetPackage().equals(packageName)) { 
                    it.remove(); 
                } 
            } 
        }</SPAN> 
        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 match
            Iterator<Alarm> it = alarmList.iterator();
           
            while (it.hasNext()) {
                Alarm alarm = it.next();
                if (alarm.operation.getTargetPackage().equals(packageName)) {
                    it.remove();
                }
            }
        }

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

    看到这里大家应该知道为什么自己设置的alarm会不起作用了吧?

    思考:

    为什么google要加入这样的机制呢?

    应该是出于系统安全的考虑,google在4.0系统中在安全方面做了很多努力。

    很多病毒程序都不希望自己的进程被用户强行停止,希望自己的病毒程序可以一直运行,而常见的方式就是通过设置alarm,在病毒进程被杀死后,通过定时发送广播来拉起病毒进程,来实现病毒进程的重新启动。

    google也正是看到了这个一点,所以加入了forceStopPackage的这一机制,让用户能够有机会干掉病毒进程。 

  • 相关阅读:
    补题列表
    task list
    UVa 11809
    UVA 272 TEX Quotes 题解
    莱州一中2016高考加油视频
    POJ2367-Genealogical tree-拓扑排序
    POJ1094-Sorting It All Out-拓扑排序
    POJ3660-Permutations-传递闭包FLOYD
    POJ3687- Labeling Balls-优先队列拓扑排序
    POJ1201-Intervals- 差分约束
  • 原文地址:https://www.cnblogs.com/xiaochao1234/p/3730320.html
Copyright © 2011-2022 走看看