Android手机上安装的很多应用都会自启动,占用资源越来越多,造成系统卡顿等现象。良好的自启动管理方案管理后台自启动和开机自启动,这样就可以节约内存、优化系统流畅性等。
AutoRun.apk的自定义类BootBroadcastReceiver接收到AutoRunCore.apk发过来的广播后,开启线程设置禁止自启动列表和允许自启动列表;从R.array.security_boot_run_applist数组中获取允许自启动列表,定义为白名单,白名单中保存的均是非系统应用;从R.array.security_boot_forbidrun_applist数组中获取禁止自启动的列表,定义为黑名单,黑名单中保存的均是系统应用。最终调用系统接口将禁止自启动的应用(包括黑名单中的系统应用、不在白名单中的非系统应用)全部写到/data/system/forbidden_autorun_packages.xml文件中。
关键代码如下:
1、注册广播接收器
2、接收到广播后处理方法
@Override
public void onReceive(final Context context, Intent intent) {
action = intent.getAction();
if((action != null)&&(action.equals("android.intent.action.security.BOOT_COMPLETED"))){
action = ACTION_BOOT_COMPLETED;
}
......
if(BOOT_AUTO_RUN && ACTION_BOOT_COMPLETED.equals(action)) {
Log.d("forbid auto run");
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
SharedPreferences preferences = context.getSharedPreferences(
"forbidrun_appList", Context.MODE_PRIVATE);
boolean isInit = preferences.getBoolean("initflag", false);
long lastModif = preferences.getLong("fileModif", 0);
long fileModif = 0;
File config = new File("data/system/seccenter/"
+ APPAUTORUN_CONFIG_FILE);//APPAUTORUN_CONFIG_FILE = "seccenter_appautorun_applist.xml"
pm = context.getPackageManager();
List autorun_appList = new ArrayList();
if (config.exists()) {
fileModif = config.lastModified();
}
if (!isInit || (fileModif > lastModif)) {
if (config.exists()) {
try {
autorun_appList = parseXML(config);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
autorun_appList = Arrays.asList(context.getResources()
.getStringArray(R.array.security_boot_run_applist));
}
List forbidrun_appList = Arrays.asList(context.getResources()
.getStringArray(R.array.security_boot_forbidrun_applist));
List allAppInfo = pm.getInstalledApplications(0);
for (ApplicationInfo appInfo : allAppInfo) {
if (!Util.isSystemApp(appInfo)
&& !autorun_appList.contains(appInfo.packageName)) {
SystemApiUtil.fobidAutoRun(context,appInfo.packageName, true);
} else if (Util.isSystemApp(appInfo)
&& forbidrun_appList.contains(appInfo.packageName)) {
SystemApiUtil.fobidAutoRun(context,appInfo.packageName, true);
}
}
SharedPreferences preference = context.getSharedPreferences("forbidrun_appList",
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = preference.edit();
editor.putBoolean("initflag", true);
editor.putLong("fileModif", fileModif);
editor.commit();
}
}
}, "btReForbidRun").start();
}
在上面的处理方法中使用的几个封装的方法,下面逐一看下。先看parseXML()方法,
public List parseXML(File xmlFile) throws Exception {
List appList = new ArrayList();
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(xmlFile);
NodeList nodeList = doc.getElementsByTagName("appname");
Node fatherNode = nodeList.item(0);
NodeList childNodes = fatherNode.getChildNodes();
for (int j = 0; j < childNodes.getLength(); j++) {
Node childNode = childNodes.item(j);
if (childNode instanceof Element) {
appList.add(childNode.getFirstChild().getNodeValue());
}
}
return appList;
}
接着看下Util.isSystemApp()方法,
public static boolean isSystemApp(ApplicationInfo appInfo) {
boolean flag = false;
if (appInfo != null
&& ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 || (appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0)) {
flag = true;
}
return flag;
}
再接着看下forbitAutorun()方法,这里是通过反射方式调用ActivityManager中的方法。
private static Method mSetStopAutoStart = null;
private static Method mgetStopAutoStart = null;
public static void fobidAutoRun(Context context, String pkg, boolean isFobid) {
if (isForceStopAutoStartMethodExist(context)) {
try {
ActivityManager am = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
mSetStopAutoStart.invoke(am, pkg,
isFobid);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
public static boolean isForceStopAutoStartMethodExist(Context context) {
synchronized (SystemApiUtil.class) {
if (mSetStopAutoStart == null) {
try {
ActivityManager am = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
mSetStopAutoStart = am.getClass().getMethod(
"setForbiddenAutorunPackages", String.class,
boolean.class);
mgetStopAutoStart = am.getClass()
.getMethod("getForbiddenAutorunPackages");
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (mSetStopAutoStart == null || mgetStopAutoStart == null) {
return false;
} else {
return true;
}
}
}
流程图如下:
(1)、AutoRun通过调用ActivityManagerService封装的getForbiddenAutoRunPackages()方法获取禁止自启动的应用列表。该方法从/data/system/forbidden_autorun_packages.xml文件中读取应用,保存到mPackagesForbiddenAutoRun全局变量中,同时也把应用包含的服务加入mServicesForbiddenAutoRun中。
(2)、security_autorun_notdisplayed_whitelist 数组表示允许自启动不显示白名单,即不显示在自启动管理界面上的应用白名单。
如果这个白名单中的应用包含getForbiddenAutoRunPackages方法返回的数组中的应用,该应用取消禁止自启动(允许自启动),并且不会显示在自启动管理界面。
取消禁止自启动的处理方法就是通过ActivityManagerService封装的setForbiddenAutoRunPackages()方法实现的。
注意:
1、第三方应用默认禁止自启动,会设置一个自启动的白名单(R.array.security_boot_run_applist),白名单里的应用就会允许自启动。
2、系统应用默认允许自启动,会设置一个禁止自启动的黑名单(R.array.security_boot_forbidrun_applist),黑名单里的应用会被禁止自启动。
具体代码如下:
public void onResume() {
super.onResume();
checkedItemCount = 0;//设置选中的个数
refreshList();
}
private void refreshList() {
......
new Thread(new InitViewRunable()).start();
}
class InitViewRunable implements Runnable {
@Override
public void run() {
initData();
Message.obtain(mHandler, MSG_INIT_DATA_COMPLETED).sendToTarget();
}
}
private synchronized void initData() {
applicationList.clear();//清空列表
forbidAutoRunList = speedLogic.getForbidAutoRunList(true);//获取禁止自启动应用列表
SharedPreferences preferences = mContext.getSharedPreferences(
"forbidrun_appList", Context.MODE_PRIVATE);
boolean isInit = preferences.getBoolean("isInit", false);
// remove the package from the forbidAutoRunList whith need to autorun
if (!isInit) {//第一次初始化
if (isAdded() && forbidAutoRunList != null) {
List autorun_whiteList = Arrays.asList(mContext
.getResources().getStringArray(
R.array.security_autorun_applist));//从数组中读取允许自启动的列表
for (String string : autorun_whiteList) {//security_autorun_applist数组中包含禁止自启动的应用,设置为允许自启动
if (forbidAutoRunList.contains(string)) {
forbidAutoRunList.remove(string);
SystemApiUtil.fobidAutoRun(mContext, string, false);//更新禁止自启动数据,重新设置下xml文件
}
}
}
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("isInit", true);
editor.commit();
}
canAutoRunMap = speedLogic.getCanAutoRunList(false);//获得允许自启动应用列表,返回已封装的对象
if (canAutoRunMap.size() != 0) {
Map tmpAutoRunMap = new HashMap();
tmpAutoRunMap.putAll(canAutoRunMap);
Iterator iter = tmpAutoRunMap.entrySet().iterator();//将canAutoRunMap保存到临时Map对象中,并迭代
ApplicationInfo appInfo;
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
String pkgName = (String) entry.getKey();//取出包名
ListBean bean = new ListBean();
bean.setPkgName(pkgName);//设置ListBean对象的包名
try {
appInfo = pm.getApplicationInfo(pkgName, 0);//根据包名获取对应的ApplicationInfo对象
String packageName = appInfo.packageName;
Bitmap icon = Util.getIcon(mContext, packageName, null);//获取图标
if (isAdded()) {//设置ListBean对象的icon
if (null == icon) {
bean.setListIcon(appInfo.loadIcon(pm));
} else {
bean.setListIcon(new BitmapDrawable(icon));
}
}
bean.setListTitle((String) appInfo.loadLabel(pm));
bean.setBoot((Boolean) entry.getValue());//设置是否禁止自启动
if (forbidAutoRunList != null
&& forbidAutoRunList.contains(pkgName)) {
bean.setChecked(true);//如果包含在禁止自启动名单里,设置勾选状态
}
if (type == SYSTEM && Util.isSystemApp(appInfo)) {
if (bean.isChecked) {
checkedItemCount++;
}
applicationList.add(bean);
Log.d("forbidAutoRunList of SystemApp" + pkgName);
} else if (type == PERSONAL && !Util.isSystemApp(appInfo)) {
if (bean.isChecked) {
checkedItemCount++;
}
applicationList.add(bean);
Log.d("forbidAutoRunList of PersonalApp" + pkgName);
}
} catch (NameNotFoundException e) {
e.printStackTrace();
}
}
}
}
initData()完毕后,发送消息更新界面。在initData()方法中用到了几个封装的方法,分别看下。
public List getForbidAutoRunList(boolean forceFresh) {
if (forbidAutoRunList == null || forceFresh) {
forbidAutoRunList = SystemApiUtil.getForbiddenAutorunPackages(mContext);//调用系统接口
if (forbidAutoRunList != null) {
List autorun_whiteList = Arrays.asList(mContext.getResources()
.getStringArray(R.array.security_autorun_notdisplayed_whitelist));
for (String string : autorun_whiteList) {//如果从xml文件中获取的禁止自启动列表中,包含允许自启动不显示数组中的应用,则设置该应用允许自启动
if (forbidAutoRunList.contains(string)) {
Log.d("set autorun packageName:" + string);
SystemApiUtil.fobidAutoRun(mContext, string, false);//设置允许自启动,并自动更新xml文件中的应用
}
}
}
}
return forbidAutoRunList;
}
getAutoRunList()方法获取允许自启动列表。
public Map getCanAutoRunList(boolean forceFresh) {
SharedPreferences pref = mContext.getSharedPreferences(PRE_NAME, Context.MODE_PRIVATE);
Editor editor = pref.edit();
boolean hasApkInstalled = pref.getBoolean("hasApkInstalled", false);
if (autoRunMap.size() == 0 || forceFresh || hasApkInstalled) {
editor.putBoolean("hasApkInstalled",false);
editor.commit();
autoRunMap = new HashMap();
List forbidList = getForbidAutoRunList(forceFresh);//获取最新状态的禁止自启动列表
List allAppInfo = null;
try {
allAppInfo = mPm.getInstalledApplications(0);//获取安装的第三方应用
} catch (Exception e) {
e.printStackTrace();
}
if (allAppInfo != null) {
for (ApplicationInfo appInfo : allAppInfo) {
boolean isContains = false;
if (forbidList != null
&& forbidList.contains(appInfo.packageName)) {
// That is in forbidden list
isContains = true;//如果在禁止自启动列表中,设置isContains为true。
}
if (isExcludeForAutoBoot(appInfo, isContains)) {//过滤掉launcher、白名单(security_autorun_notdisplayed_whitelist)中的应用。
continue;
}
if (isPackageHasReceivers(appInfo.packageName)) {//判断是否注册了广播接收器
Boolean isBoot = false;
if (isPackageHasReceiverPermission(appInfo.packageName,
Manifest.permission.RECEIVE_BOOT_COMPLETED)) {
isBoot = true;//注册了开机广播
}
autoRunMap.put(appInfo.packageName, isBoot);
}
}
}
}
return autoRunMap;
}
我们再看下isExcludeForAutoBoot()方法,该方法排除掉launcher应用,排除掉白名单(security_autorun_notdisplayed_whitelist)中的应用。
private boolean isExcludeForAutoBoot(ApplicationInfo appInfo, Boolean isContains) {
if (appInfo == null) {
return true;
}
if (Util.isSystemApp(appInfo)) {//系统应用
List launcherPkgs = SpeedUtil.getLauncherPkgs(mContext);//获取launcher应用
// not contain launcher icon ,not list it
if (!launcherPkgs.contains(appInfo.packageName)) {
return true;
}//过滤掉launcher应用。
}
// judge whether contain in white list,if it is ,do not list it
if (isInAutoBootWhiteList(appInfo)) {//这里再过滤一次是否在白名单中
if (isContains) {//如果设置了禁止自启动,则设置为允许自启动
Log.d("i donot think will come in.");
SystemApiUtil.fobidAutoRun(mContext, appInfo.packageName, false);
}
return true;
} else {
return false;
}
}
再看下isPackageHasReceivers()方法,判断是否注册了广播接收器。
private boolean isPackageHasReceivers(String packageName) {
if (mPm == null) {
mPm = mContext.getPackageManager();
}
boolean hasReceivers = true;
try {
PackageInfo packinfo = mPm.getPackageInfo(packageName, PackageManager.GET_RECEIVERS);
if (packinfo.receivers == null || packinfo.receivers.length <= 0) {
hasReceivers = false;
}
} catch (NameNotFoundException e) {
hasReceivers = false;
e.printStackTrace();
}
return hasReceivers;
}
看下封装的isPackageHasReceiverPermission()方法,判断是否有接收开机广播的权限。
public boolean isPackageHasReceiverPermission(String packageName, String permissionName) {
boolean isReceiverFunctionEnable = true;
if (mPm == null) {
mPm = mContext.getPackageManager();
}
if (permissionName != null
&& PackageManager.PERMISSION_GRANTED != mPm.checkPermission(permissionName,
packageName)) {
isReceiverFunctionEnable = false;
}
return isReceiverFunctionEnable;
}
流程图如下:
禁止自启动:调用系统接口ActivityManagerService类封装的setForbiddenAutorunPackages(final StringpackageName, boolean bAdd),此时bAdd参数为true,将指定的包名添加到禁止自启动列表mPackagesForbiddenAutoRun中,将应用包含的服务添加到禁止自启动服务列表mServicesForbiddenAutoRun中,最后将禁止自启动列表中的数据重新更新到/data/system/forbidden_autorun_packages.xml文件中。
具体代码如下:
/**
* @hide
*/
public boolean setForbiddenAutorunPackages(final String packageName,
boolean bAdd) {
boolean bResult = false;
if (Feature.FEATURE_FORBID_APP_AUTORUN) {
// Slog.v(TAG, "ctl packagename=" + packageName + "bAdd=" + bAdd);
synchronized (this) {
if ((null != packageName) && (null != mPackagesForbiddenAutoRun)
&& (null != mServicesForbiddenAutoRun)) {
final PackageManager pm = mContext.getPackageManager();
PackageInfo pi = null;
try {
pi = pm.getPackageInfo(packageName,
PackageManager.GET_SERVICES);
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
int temp_size = mPackagesForbiddenAutoRun.size();
if (bAdd) {
if (mPackagesForbiddenAutoRun.indexOfKey(packageName.hashCode())<0) {
mPackagesForbiddenAutoRun.append(packageName.hashCode(),packageName);
bResult = temp_size!=mPackagesForbiddenAutoRun.size();
if (pi != null && null != pi.services) {
for (ServiceInfo service : pi.services) {
if (0>mServicesForbiddenAutoRun.indexOfKey(service.processName.hashCode())) {
Slog.i(TAG, "ADD forbid autorun service: "+ service.processName);
mServicesForbiddenAutoRun.append(service.processName.hashCode(), service.processName);
}
}
}
}
} else {
mPackagesForbiddenAutoRun.delete(packageName.hashCode());
bResult = mPackagesForbiddenAutoRun.size()!=temp_size;
if (pi != null && pi.services != null) {
for (ServiceInfo service : pi.services) {
mServicesForbiddenAutoRun.delete(service.processName.hashCode());
}
}
}
}
writeFilterPackages();
}
}
return bResult;
}
void writeFilterPackages(){
if ( mFileFilter == null) {
return ;
}
if (mFileFilter.exists()) {
mFileFilter.delete();
}
try {
FileOutputStream fstr = new FileOutputStream(mFileFilter);
BufferedOutputStream str = new BufferedOutputStream(fstr);
//XmlSerializer serializer = XmlUtils.serializerInstance();
XmlSerializer serializer = new FastXmlSerializer();
serializer.setOutput(str, "utf-8");
serializer.startDocument(null, true);
//serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startTag(null, "packages");
int numPackages = mPackagesForbiddenAutoRun.size();
//Slog.i(TAG, " forbid autorun numPackages := "+ numPackages);
for( int i = 0; i < numPackages; ++i){
serializer.startTag(null, "package");
String apkPackageName = mPackagesForbiddenAutoRun.valueAt(i);
//Slog.i(TAG, "forbid autorun package: "+apkPackageName);
serializer.attribute(null, "name", apkPackageName);
serializer.endTag(null, "package");
}
serializer.endTag(null, "packages");
serializer.endDocument();
str.flush();
FileUtils.sync(fstr);
str.close();
FileUtils.setPermissions(mFileFilter.toString(),
FileUtils.S_IRUSR|FileUtils.S_IWUSR
|FileUtils.S_IRGRP|FileUtils.S_IWGRP
|FileUtils.S_IROTH,
-1, -1);
} catch(java.io.IOException e) {
Slog.w(TAG, "Unable to write broadcast filter, current changes will be lost at reboot", e);
}
}
public List getForbiddenAutorunPackages( ) {
if (Feature.FEATURE_FORBID_APP_AUTORUN) {
// Slog.v(TAG, "ctl packagename YLGetForbiddenAutorunPackages" );
synchronized (this) {
ArrayList res = new ArrayList();
for (int i = 0; i < mPackagesForbiddenAutoRun.size(); i++) {
res.add(mPackagesForbiddenAutoRun.valueAt(i));
}
return res;
}
}
}
流程图如下:
允许自启动:调用系统接口ActivityManagerService类封装的setForbiddenAutorunPackages( final String packageName, boolean bAdd)方法,此时flag参数为false,将设置的应用的包名从全局变量mPackagesForbiddenAutoRun中移除,包括该应用包含的服务从全局变量mServicesForbiddenAutoRun中移除,最后将mPackagesForbiddenAutoRun列表中的数据重新更新到/data/system/forbidden_autorun_packages.xml文件。
流程图如下:
当一个应用安装时,AppInstallReceiver接收到android.intent.action.PACKAGE_ADDED广播,如果该应用不在security_autorun_displayed_whitelist(允许自启动显示白名单)及security_autorun_notdisplayed_whitelist(允许自启动不显示白名单)中,并且该应用又是第三方应用,则将该应用加入禁止自启动列表。
(1)、开机启动过程中,会调用到ActivityManagerService的systemReady()方法,在该方法中读取/data/system/forbidden_autorun_packages.xml文件中的数据,并将其保存到全局数组变量mPackagesForbiddenAutoRun中。
具体代码如下:
if (Feature.FEATURE_FORBID_APP_AUTORUN){
mFileFilter = new File(PATH_PACKAGES_FILTER);
if(!mFileFilter.exists()){
try {
mFileFilter.createNewFile();
} catch (IOException e) {
Slog.d(TAG, "Failed to creat black list file!!!");
}
}
readFilterPackages();
}
readFilterPackages()方法读取禁止自启动列表,完成mPackagesForbiddenAutoRun、mServicesForbiddenAutoRun数组的初始化。
private static final String PATH_PACKAGES_FILTER = "/data/system/forbidden_autorun_packages.xml";
private boolean readFilterPackages(){
FileInputStream str = null;
if ( mFileFilter == null) {
return false;
}
if (!mFileFilter.exists()) {
Log.d(TAG, PATH_PACKAGES_FILTER + "does not exist" );
return false;
}
try {
str = new FileInputStream(mFileFilter);
XmlPullParser parser = Xml.newPullParser();
parser.setInput(str, null);
int type;
while ((type=parser.next()) != XmlPullParser.START_TAG
&& type != XmlPullParser.END_DOCUMENT) {
;
}
if (type != XmlPullParser.START_TAG) {
Log.d(TAG, "No start tag found in in" + PATH_PACKAGES_FILTER );
return false;
}
int outerDepth = parser.getDepth();
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG
|| parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG
|| type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
if (tagName.equals("package")) {
String delPackageName = parser.getAttributeValue(null,"name");
final PackageManager pm = mContext.getPackageManager();
PackageInfo pi = null;
try {
pi = pm.getPackageInfo(delPackageName, PackageManager.GET_SERVICES);
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Slog.i(TAG, "forbid autorun pakacge: "+ delPackageName);
mPackagesForbiddenAutoRun.append(delPackageName.hashCode(),delPackageName);
if (pi != null && null != pi.services) {
for (ServiceInfo service : pi.services) {
if (0>mServicesForbiddenAutoRun.indexOfKey(service.processName.hashCode())) {
Slog.i(TAG, "forbid autorun service: "+ service.processName);
mServicesForbiddenAutoRun.append(service.processName.hashCode(),service.processName);
}
}
}
}else {
Slog.w(TAG, "Unknown element under : "
+ parser.getName());
XmlUtils.skipCurrentTag(parser);
}
}
str.close();
} catch(XmlPullParserException e) {
Slog.e(TAG, "Error reading "+ PATH_PACKAGES_FILTER, e);
} catch(java.io.IOException e) {
Slog.e(TAG, "Error reading "+ PATH_PACKAGES_FILTER, e);
}
return true;
}
(2)、系统在启动过程中会拉起一些重要的应用,而大多数应用是在启动完成之后拉起的。这里解释下mProcessesOnHold,这是一个数组列表,保存ProcessRecord对象,表示暂时挂起的进程列表,这些进程因尝试在系统启动(systemReady)完成之前启动,而被暂时挂起,当系统启动完成之后,会启动该列表中的进程。
我们看下源码解释:
/**
* List of records for processes that someone had tried to start before the
* system was ready. We don't start them at that point, but ensure they
* are started by the time booting is complete.
*/
final ArrayList mProcessesOnHold = new ArrayList();
这部分在启动过程中不能拉起的应用就暂存在mProcessesOnHold列表中。因此,自启动管理在系统启动完成之前将mProcessesOnHold列表中包含的mPackagesForbiddenAutoRun中的应用排除,这样在系统启动完成后,就不会启动mPackagesForbiddenAutoRun中的应用。
在startProcessLocked方法中会调用Process.start方法开启线程,我们要做的就是从mProcessesOnHold中排除禁止自启动的应用,这样就实现开机禁止自启动了。
// If the system is not ready yet, then hold off on starting this
// process until it is.
if (!mProcessesReady
&& !isAllowedWhileBooting(info)
&& !allowWhileBooting
&& !isInBlackList(info)) {
if (!mProcessesOnHold.contains(app)) {
mProcessesOnHold.add(app);
}
if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES,
"System not ready, putting on hold: " + app);
checkTime(startTime, "startProcess: returning with proc on hold");
return app;
}
public boolean isInBlackList(final ApplicationInfo info)
{
boolean ret = (info.flags & ApplicationInfo.FLAG_PERSISTENT) != ApplicationInfo.FLAG_PERSISTENT//revert for debugging crash
|| (info.flags & ApplicationInfo.FLAG_SYSTEM) != ApplicationInfo.FLAG_SYSTEM;
String packageName = info.packageName;
ret = ((mPackagesForbiddenAutoRun.indexOfKey(packageName.hashCode())>=0 ||
mServicesForbiddenAutoRun.indexOfKey(packageName.hashCode())>=0) &&
(mPackagesHasWidgetRun.indexOfKey(packageName.hashCode())<0));
if(ret) Slog.v(TAG, "check isInBlackList:" + packageName + " ret=" + ret);
return ret;
}
com.android.server.am.ActiveServices.bringDownServiceLocked(ActiveServices.java)
com.android.server.am.ActiveServices.killServicesLocked(ActiveServices.java)
com.android.server.am.ActivityManagerService.cleanUpApplicationRecordLocked(ActivityManagerService.java)
com.android.server.am.ActivityManagerService.handleAppDiedLocked(ActivityManagerService.java)
com.android.server.am.ActivityManagerService.appDiedLocked(ActivityManagerService.java)
com.android.server.am.ActivityManagerService$AppDeathRecipient.binderDied(ActivityManagerService.java)
如果服务重启,则在ActiveServices.killServicesLocked方法中调用bringDownServiceLocked方法,不允许重启,直接挂掉。
/**
* Main function for removing an existing process from the activity manager
* as a result of that process going away. Clears out all connections
* to the process.哈哈
*/
private final void handleAppDiedLocked(ProcessRecord app,
boolean restarting, boolean allowRestart) {
int pid = app.pid;
boolean kept = cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1);
if (!kept && !restarting) {
removeLruProcessLocked(app);
if (pid > 0) {
ProcessList.remove(pid);
}
}
if (mProfileProc == app) {
clearProfilerLocked();
}
if (Feature.FEATURE_FORBID_APP_AUTORUN ) {
if (app != null && app.info != null &&
isInBlackList(app.info)) {
IPackageManager pm = AppGlobals.getPackageManager();
try {
pm.setPackageStoppedState(app.info.packageName, true, UserHandle.getUserId(app.uid));
Slog.i(TAG, "forbid restart this app that is contained in forbidden list: " + app.processName + " and remove its alarms & jobs.");
mContext.sendBroadcastAsUser(new Intent(ACTION_APP_KILL).putExtra(Intent.EXTRA_PACKAGES, new String[]{ app.info.packageName }),
UserHandle.ALL, "android.permission.DEVICE_POWER");
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ app.info.packageName + ": " + e);
e.printStackTrace();
}
}
}
......
}
/* optimize memory */
else if (Feature.FEATURE_FORBID_APP_AUTORUN &&
app != null && app.info != null && !isCTSMode() &&
mAm.isInBlackList(app.info)) {
Slog.w(TAG, "Service crashed " + sr.crashCount
+ " times, stopping: " + sr + "forbid restart this app that is contained in forbidden list: " + app.processName);
EventLog.writeEvent(EventLogTags.AM_DESTROY_SERVICE ,
sr.crashCount, sr.shortName, app.pid, app.processName);
bringDownServiceLocked(sr);
}
private class QuickBootReceiver extends BroadcastReceiver {//AlarmManagerService中注册该广播接收器
static final String ACTION_APP_KILL = "org.codeaurora.quickboot.appkilled";
public QuickBootReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_APP_KILL);
getContext().registerReceiver(this, filter,
"android.permission.DEVICE_POWER", null);
}
@Override
public void onReceive(Context context, Intent intent) {
if (Feature.FEATURE_FORBID_APP_AUTORUN) {
Message msg = new Message();
msg.what = ScheduleHandler.REMOVE_DEAD_APP_ALARM_REVEIVE;
msg.obj = intent;
mScheduleHandler.sendMessage(msg);
return ;
}
String action = intent.getAction();
String pkgList[] = null;
if (ACTION_APP_KILL.equals(action)) {
pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
if (pkgList != null && (pkgList.length > 0)) {
for (String pkg : pkgList) {
removeLocked(pkg);
for (int i=mBroadcastStats.size()-1; i>=0; i--) {
ArrayMap uidStats = mBroadcastStats.valueAt(i);
if (uidStats.remove(pkg) != null) {
if (uidStats.size() <= 0) {
mBroadcastStats.removeAt(i);
}
}
}
}
}
}
}
}
case REMOVE_DEAD_APP_ALARM_REVEIVE:
synchronized (mLock) {
removeDeadAppAlarmReceiveLocked((Intent)msg.obj);
}
break;
void removeDeadAppAlarmReceiveLocked(Intent intent) {
Slog.d(TAG, "Receive for remove dead app alarm: " + intent.getAction());
String pkgList[] = null;
pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
if (pkgList != null && (pkgList.length > 0)) {
for (String pkg : pkgList) {
removeLocked(pkg);
for (int i=mBroadcastStats.size()-1; i>=0; i--) {
ArrayMap uidStats = mBroadcastStats.valueAt(i);
if (uidStats.remove(pkg) != null) {
if (uidStats.size() <= 0) {
mBroadcastStats.removeAt(i);
}
}
}
}
}
}
/* For do not send broadcast to the APP in blacklist that not running */
if (Feature.FEATURE_FORBID_APP_AUTORUN &&
info != null && info.activityInfo != null &&
info.activityInfo.packageName!="com.yulong.android.dualmmsetting"&&
mService.isInBlackList(info.activityInfo.applicationInfo)) {
Slog.v(TAG, "Skipping delivery of static ["
+ mQueueName + "] " + r + " for forbiden auto run");
r.receiver = null;
r.curFilter = null;
r.state = BroadcastRecord.IDLE;
scheduleBroadcastsLocked();
return;
}
打开程序或者有程序进入后台时都会执行updateOomAdjLocked()函数。可以在该方法中进行处理。
if (Feature.FEATURE_FORBID_APP_AUTORUN) {
if (isInBlackList(app.info)) {
app.kill("Mem less than " + ProcessList.MIN_MEM_LEVEL/(1024*1024) + "M, kill background!!", true);
}
}