android安全:forceStopPackage對android的Alarm的影響

來源:互聯網
上載者:User

原文http://my.oschina.net/lhjtianji/blog/127424

也許一些使用alarmmanager做定時任務的同學遇到過這樣的問題:設定alarm後,進入設定-->應用程式管理-->強行停止app後,定時任務就失效了。

 

簡單的講就是:force stop會導致alarm失效。

 

最典型的例子就是我碰到過的一個bug,使用android手機的時鐘app設定一個鬧鐘,然後進入設定-->應用程式管理裡面,將時鐘這個app force stop掉,結果鬧鐘就不響了。

 

其實這不是bug,這是android系統的新加入的機制。下面我來詳細分析一下來龍去脈。

 

1. 在設定的應用程式管理裡面強行停止app:

    這裡會最終會調用到 ActivityManagerService的forceStopPackageLocked()

原始碼如下:

[java]
<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的這一機制,讓使用者能夠有機會幹掉病毒進程。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

Tags Index: