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

 android4.2系统中是在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java的finishBooting()方法中发送开机广播。

    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:

        // By default broadcasts do not go to stopped apps.
        intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);


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

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):

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类。文件内容:

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。内容如下:

<?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的应用。

 

参考文章:http://blog.csdn.net/leilu2008/article/details/8933869; http://blog.csdn.net/persuit/article/details/7353066

 

 

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值