您的位置:首页 > 移动开发 > Android开发

Android4.2中应用接收开机广播(android.intent.action.BOOT_COMPLETED)失败的原因

2016-09-30 11:01 666 查看
转载:http://blog.csdn.net/sckgenius/article/details/30472463
android4.2系统中是在frameworks/base/services/java/com/Android/server/am/ActivityManagerService.java的finishBooting()方法中发送开机广播。

[java] view
plain copy







final void finishBooting() {

IntentFilter pkgFilter = new IntentFilter();

pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);

pkgFilter.addDataScheme("package");

mContext.registerReceiver(new BroadcastReceiver() {

@Override

public void onReceive(Context context, Intent intent) {

String[] pkgs = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);

if (pkgs != null) {

for (String pkg : pkgs) {

synchronized (ActivityManagerService.this) {

if (forceStopPackageLocked(pkg, -1, false, false, false, false, 0)) {

setResultCode(Activity.RESULT_OK);

return;

}

}

}

}

}

}, pkgFilter);

synchronized (this) {

// Ensure that any processes we had put on hold are now started

// up.

final int NP = mProcessesOnHold.size();

if (NP > 0) {

ArrayList<ProcessRecord> procs =

new ArrayList<ProcessRecord>(mProcessesOnHold);

for (int ip=0; ip<NP; ip++) {

if (DEBUG_PROCESSES) Slog.v(TAG, "Starting process on hold: "

+ procs.get(ip));

startProcessLocked(procs.get(ip), "on-hold", null);

}

}

if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {

// Start looking for apps that are abusing wake locks.

Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);

mHandler.sendMessageDelayed(nmsg, POWER_CHECK_DELAY);

// Tell anyone interested that we are done booting!

SystemProperties.set("sys.boot_completed", "1");

SystemProperties.set("dev.bootcomplete", "1");

for (int i=0; i<mStartedUsers.size(); i++) {

UserStartedState uss = mStartedUsers.valueAt(i);

if (uss.mState == UserStartedState.STATE_BOOTING) {

uss.mState = UserStartedState.STATE_RUNNING;

final int userId = mStartedUsers.keyAt(i);

Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);

intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);

broadcastIntentLocked(null, null, intent,

null, null, 0, null, null,

android.Manifest.permission.RECEIVE_BOOT_COMPLETED,

false, false, MY_PID, Process.SYSTEM_UID, userId);

}

}

}

}

}

最后是通过broadcastIntentLocked()方法发送,broadcastIntentLocked()方法中会为将要发送的intent设置一个flag:

[java] view
plain copy







// By default broadcasts do not go to stopped apps.

intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);

android官方文档中对此flag描述如下:

[java] view
plain copy







public static final int FLAG_EXCLUDE_STOPPED_PACKAGES

Added in API level 12

If set, this intent will not match any components in packages that are currently stopped. If this is not set, then the default behavior is to include such applications in the result.

Constant Value: 16 (0x00000010)

意思是当前处于停止状态的包中的组件无法收到设置了这个flag的Intent。

android3.1的更新文档中有对停止状态进行说明(http://developer.android.com/about/versions/android-3.1.html#launchcontrols):

[java] view
plain copy







Applications are in a stopped state when they are first installed but are not yet launched and when they are manually stopped by the user (in Manage Applications).

当应用第一次被按照但是没有被启动,或者应用在应用管理中被手动停止时,应用处于停止状态。
由上面的分析可知,Android4.2中应用接收开机广播(android.intent.action.BOOT_COMPLETED)失败的原因就在于安装应用后没有先启动。应用需要在安装后启动一次,才能正常接收开机广播。经过验证发现,系统级别的应用,即使不启动,也可以正常接收开机广播。这里的系统级别是指放在/system/app/目录下的应用。
验证过程如下:
1.Eclipse中新建一个ReceiverTest工程,包名为com.example.receivertest。
2.在包com.example.receivertest中新建一个MyReceiver类,继承BroadcastReceiver类。文件内容:

[java] view
plain copy







package com.example.receivertest;

import android.content.BroadcastReceiver;

import android.content.Context;

import android.content.Intent;

import android.media.AudioManager;

import android.util.Log;

public class MyReceiver extends BroadcastReceiver {

private static final String TAG = "ReceiverTest";

@Override

public void onReceive(Context ctx, Intent arg1) {

// TODO Auto-generated method stub

Log.d(TAG,"Volume Test receive Boot_completed!");

final Context context = ctx;

new Thread(new Runnable() {

@Override

public void run() {

// TODO Auto-generated method stub

Log.d(TAG,"Thread start!");

int max ,current;

AudioManager mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);

while(true){

max = mAudioManager.getStreamMaxVolume( AudioManager.STREAM_SYSTEM );

current = mAudioManager.getStreamVolume( AudioManager.STREAM_SYSTEM );

Log.d(TAG, "@@@@@@@@@@@@@@maxVolume : " + max + ", currentVolume : " + current);

try {

Thread.sleep(3000);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}).start();

}

}

3. 在AndroidManifest.xml中注册MyReceiver,并设置其Intent filter,同时注释掉Eclipse自动生成的Activity。内容如下:

[java] view
plain copy







<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="com.example.receivertest"

android:versionCode="1"

android:versionName="1.0" >

<uses-sdk

android:minSdkVersion="8"

android:targetSdkVersion="17" />

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<application

android:allowBackup="true"

android:icon="@drawable/ic_launcher"

android:label="@string/app_name"

android:theme="@style/AppTheme" >

<!--

<activity

android:name="com.example.receivertest.MainActivity"

android:label="@string/app_name" >

<intent-filter>

<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />

</intent-filter>

</activity>

-->

<receiver android:name="com.example.receivertest.MyReceiver" >

<intent-filter>

<action android:name="android.intent.action.BOOT_COMPLETED" />

</intent-filter>

</receiver>

</application>

</manifest>

adb连接上android设备,在Eclipse中Run as Android Application运行此应用。重启android设备,从开机log看应用中的MyReceiver并没有接收到开机广播。卸载应用,通过adb 把工程bin目录中APK push到android设备的/system/app/目录并重启后,开机log上显示MyReceiver成功接收到开机广播。
3.卸载应用,取消AndroidManifest.xml中的注释,重新编译运行应用。Android设备上显示默认的helloworld后重启设备,log显示MyReceiver成功接收到开机广播。

所以对于android3.1以后得系统版本,如果要应用接收开机广播有两种方法:
1.将应用push到/system/app/目录。
2.安装应用后先启动一次,适用于有Activity的应用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android
相关文章推荐