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的这一机制,让用户能够有机会干掉病毒进程。

android安全:forceStopPackage对android的Alarm的影响,布布扣,bubuko.com

时间: 2024-08-02 17:14:36

android安全:forceStopPackage对android的Alarm的影响的相关文章

Android 双击 Back 键退出程序(Alarm 机制实现)

====================实现原理======================== 1.重写Back键方法 2.设置退出标识 3.延时重置标识 ====================延时重置======================== 1.继承 BroadcastReceiver (一定要在 Manifest 中注册) 2.使用 AlarmManager 设置延时启动任务(以毫秒为单位) 3.定时自动启动 BroadcastReceiver(重置退出标识) =========

我的Android进阶之旅------&gt;Android使用AlarmManager全局定时器实现定时更换壁纸

该DEMO将会通过AlarmManager来周期的调用ChangeService,从而让系统实现定时更换壁纸的功能. 更换壁纸的API为android.app.WallpaperManager,它提供了clear()方法来清除壁纸,还提供了如下方法来设置壁纸. setResource(int resid)将壁纸设置为resid资源所代表的图片 setBitmap(Bitmap bitmap)将壁纸设置为bitmap所代表的位图 setStream(InputStream data)将壁纸设置为d

Android权限大全(android开发必知)

android权限大全 Ctrl+F可快速查找 访问网络 android.permission.INTERNET,访问网络连接,可能产生GPRS流量 android.permission.CHANGE_WIFI_STATE  Wifi 改变状态 android.permission.ACCESS_WIFI_STATE WiFi 状态 android.permission.ACCESS_NETWORK_STATE 网络状态 录制视频 android.permission.CAMERA androi

Android初级教程:Android中解析方式之pull解析

在安卓中有很多种解析方式.按照大方向有xml解析和json解析.而,细致的分,xml和json解析各有自己的很多解析方式.今天这一篇主要介绍xml解析中的pull解析.对于xml的解析方式,我之前在javaweb一些知识中有写过dom和dom4j等等解析方式.有兴趣的读者可以去javaweb篇里面找相关的内容. 先自定义一个数据源,假设就是访问服务器返回的xml数据文件名称为weather.xml: <?xml version='1.0' encoding='utf-8' standalone=

android studio :com.android.support:appcompat-v7:21.+ 报错

android studio :com.android.support:appcompat-v7:21.+ 报错: 在project——>app——>build.gradle修改: apply plugin: 'com.android.application' android { compileSdkVersion 22 buildToolsVersion "22.0.1" defaultConfig { applicationId "com.example.ri

Android 如何引用com.android.internal.R目录下的资源

Android 如何引用com.android.internal.R目录下的资源 项目需求 有一个资源跟系统上的一个资源相同,想要引用它:frameworks/base/core/res/res/drawable/ic_text_dot.xml 文件名称:ic_text_dot.xml 文件的具体内容: <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2014 The Androi

【Android应用开发】 Android 崩溃日志 本地存储 与 远程保存

示例代码下载 : http://download.csdn.net/detail/han1202012/8638801; 一. 崩溃日志本地存储 1. 保存原理解析 崩溃信息本地保存步骤 : -- 1. 自定义类实现 UncaughtExceptionHandler : public class CrashHandler implements UncaughtExceptionHandler; -- 2. 设置该自定义的 CrashHandler 类为单例模式 : // 单例模式 private

Android的taskAffinity对四种launchMode的影响

在Android系统中,一个application的所有Activity默认有一个相同的affinity(亲密关系,相似之处).也就是说同一个应用程序的的所有Activity倾向于属于同一个task.但是我们并不能说Android里一个应用程序只有一个任务栈.笔者今天针对当taskAffinity不同时,四种launchMode下在打开一个新的Activity时是否会建立一个新的任务栈做了实验. 基本的代码如下: AndroidManifest.xml: MainActivity的代码 pack

我的Android进阶之旅------&gt;Android嵌入图像InsetDrawable的用法

面试题:为一个充满整个屏幕的LinearLayout布局指定背景图,是否可以让背景图不充满屏幕?请用代码描述实现过程. 解决此题,可以使用嵌入(Inset)图像资源来指定图像,然后像使用普通图像资源一样使用嵌入图像资源. 语法如下: <?xml version="1.0" encoding="utf-8"?> <inset xmlns:android="http://schemas.android.com/apk/res/android&