利用Andriod死亡通知机制告诉service,client被kill了

本文介绍了Android中使用DeathRecipient接口在不同进程间进行通讯的方法,特别是当客户端进程被kill时,服务端进程能够接收到死亡通知,从而及时释放因绑定分配的资源。通过示例代码演示了如何在客户端和服务端实现这一功能。


Android提供了一种叫做死亡通知的机制,用于满足某些应用的特定需求:

    某个process需要知道另外一个process是否存活;或者当某个进程被kill的时候,另外一个进程期望知道这件事情;


   一般来讲是某个bound service关心其client是否被kill

  可能有人会问,为什么service会关系client是否被kill呢


应用场景:

 比如:一个bound service可能会为bind过来的client分配一些资源,当client调用release或者unbind的时候则会释放资源,但是

           在某个时候client确被kill了,此时如果service不知道,则为其分配的资源则不会被释放。


Android提供了一个名为DeathRecipient 的接口,

1.在client中new 一个Binder,然后传给另外一个进程,通常是一个Bound service

2.你只需在关心另外一个进程死亡信息的进程中(通常是一个service)实现DeathRecipient

3.调用client传过来的binder的linkToDeath方法


public abstract void linkToDeath (IBinder.DeathRecipient recipient, int flags)
Added in  API level 1

Register the recipient for a notification if this binder goes away. If this binder object unexpectedly goes away (typically because its hosting process has been killed), then the given IBinder.DeathRecipient's DeathRecipient.binderDied() method will be called.

You will only receive death notifications for remote binders, as local binders by definition can't die without you dying as well.

Throws
RemoteException if the target IBinder's process has already died.

DeathRecipient is an interface for receiving a callback when the process hosting an IBinder has gone away.


关于DeathRecipient的介绍可以参考官网文档:

http://developer.android.com/reference/android/os/IBinder.DeathRecipient.html


-------------------------------------------


测试步骤,启动app,点击start,然后用adb shell ps 查看com.example.testservice进程ID,然后用adb shell kill pid,将client kill掉,检查log

Log.d(TAG, "client has died");是否有print出来


Sample code:

//Client  TestActivity.java

public class TestActivity extends Activity {

    private String TAG = "TestService";
    private Button mStartBtn;
    private Button mStopBtn;
    private Button mBindBtn;
    private Button mUnbindBtn;
    ClickListener mClickListener = new ClickListener();
    private Intent mIntent = new Intent("com.example.action.TEST");
    private IBinder mBinder = new Binder();
    private ITest mTest = null;
    private ServiceConnection mServiceConnection = new ServiceConnection() {
        
        @Override
        public void onServiceDisconnected(ComponentName name) {
            // TODO Auto-generated method stub
            Log.d(TAG, "onServiceDisconnected");
           
        }
        
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // TODO Auto-generated method stub
            Log.d(TAG, "onServiceConnected:" + name);
            mTest = ITest.Stub.asInterface(service);
            try {
                mTest.setBinder(mBinder);
            } catch (RemoteException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test_service);
        mStartBtn = (Button)findViewById(R.id.start);
        mStopBtn = (Button)findViewById(R.id.stop);
        mBindBtn = (Button)findViewById(R.id.bind);
        mUnbindBtn = (Button)findViewById(R.id.unbind);
        mStartBtn.setOnClickListener(mClickListener);
        mStopBtn.setOnClickListener(mClickListener);
        mBindBtn.setOnClickListener(mClickListener);
        mUnbindBtn.setOnClickListener(mClickListener);
        
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_test_service, menu);
        return true;
    }
    
    private class ClickListener implements OnClickListener{


        @Override
        public void onClick(View v) {
            int id = v.getId();
            if(id == R.id.start){
                startService(mIntent);
                
            }else if(id == R.id.stop){
                stopService(mIntent);
            }else if(id == R.id.bind){
                bindService(mIntent, mServiceConnection,  Context.BIND_AUTO_CREATE);
            }else if(id == R.id.unbind){
                unbindService(mServiceConnection);
            }
            
        }
        
    }


}


// ITest .aidl
package com.example.testservice;



/** Example service interface */
interface ITest {

    int getPid();

    void setBinder(IBinder client);    
}



//TestService.java

public class TestService extends Service{
    private String TAG = "TestService";
    
    private TestApi mTestApi = new TestApi();
    
    private IBinder mClient = null;

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "Onbind() action=" + intent.getAction());
        return mTestApi;
    }
    
    private class TestDeathRecipient implements DeathRecipient{


        @Override
        public void binderDied() {
            Log.d(TAG, "client has died");
        }
        
    }
    
    private class TestApi extends ITest.Stub{
        @Override
        public int getPid() throws RemoteException {
            return (int)Thread.currentThread().getId();
        }


        @Override
        public void setBinder(IBinder client) throws RemoteException {
            mClient = client;
            mClient.linkToDeath(new TestDeathRecipient(), 0);
        }
        
    }

}


//AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.testservice"
    android:versionCode="1"
    android:versionName="1.0" >


    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />


    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.testservice.TestActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />


                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        
        <service android:name="com.example.testservice.TestService"
            android:process=":service">
            <intent-filter>
                <action android:name="com.example.action.TEST" />
            </intent-filter>
        </service>
    </application>

</manifest>


//activity_test_service.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".TestActivity" >


    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="@string/hello_world" />


    <Button
        android:id="@+id/start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_toLeftOf="@+id/stop"
        android:text="start" />


    <Button
        android:id="@+id/bind"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/start"
        android:layout_below="@+id/start"
        android:layout_marginTop="23dp"
        android:text="Bind" />


    <Button
        android:id="@+id/stop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignRight="@+id/textView1"
        android:text="stop" />


    <Button
        android:id="@+id/unbind"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/button1"
        android:layout_toRightOf="@+id/button1"
        android:text="Unbind" />


</RelativeLayout>

<think>好的,用户想理解am_proc_start事件日志的意义,特别是解析包含“com.android.carrierconfig”和“bindService”的日志。首先,我需要回顾am_proc_start的基本信息,它通常在Android的ActivityManagerService中生成,用于记录进程启动的事件。根据引用[2],am_proc_start是在ActivityManagerService的startProcessLocked方法内生成的,参数包括用户ID、进程ID、UID、进程名等。用户提到的日志还涉及bindService,这可能与进程启动的原因有关。 接下来,要分析日志的具体内容。用户提供的示例是“com.android.carrierconfig bindService”,这表示进程com.android.carrierconfig因绑定服务而被启动。根据引用[3],am_proc_start可以追踪进程创建、进程号、进程名,以及启动的原因。这里的bindService说明该进程的启动是为了绑定某个服务,可能是另一个组件请求绑定该服务,导致系统启动该进程。 然后,需要结合Android组件启动机制。当某个组件通过bindService请求服务时,如果目标服务的进程未运行,系统会先启动该进程。因此,日志中的bindService是触发进程启动的原因。引用[1]提到在Binder通信中,Client端和ServiceManager端的proc和thread信息不同,这可能与进程间通信有关,但此处更直接的是ActivityManagerService处理进程启动的逻辑。 另外,用户可能想通过日志分析问题,比如进程启动是否正常,或者是否有延迟。根据引用[3],分析am_proc_start可以帮助追踪进程创建的时间和参数,进而判断是否存在启动失败或性能问题。例如,如果频繁出现某个进程的启动日志,可能提示有异常或资源泄露。 最后,用户可能需要知道如何查看这些日志。可以使用adb logcat或分析bugreport文件,搜索am_proc_start条目,结合其他日志如Binder通信或服务绑定相关的信息,全面了解进程启动的上下文。例如,查看是否有权限问题或服务未正确注册导致进程重复启动。</think>### am_proc_start 事件日志解析 在 Android 系统中,`am_proc_start` 是 **ActivityManagerService(AMS)** 生成的日志事件,用于记录进程启动的关键信息[^2][^3]。当您看到包含 `com.android.carrierconfig` 和 `bindService` 的日志时,其含义可拆解如下: --- #### 1. **日志结构解析** 典型的 `am_proc_start` 日志格式如下: ``` EventLog.writeEvent(EventLogTags.AM_PROC_START, UserHandle.getUserId(uid), // 用户ID startResult.pid, // 进程ID uid, // 用户唯一标识 app.processName, // 进程名(如 com.android.carrierconfig) hostingType, // 进程启动原因(如 bindService) hostingNameStr // 关联组件名(如服务名) ); ``` - **进程名 (`app.processName`)**:此处为 `com.android.carrierconfig`,表示启动的是运营商配置服务进程。 - **启动原因 (`hostingType`)**:`bindService` 表示进程因绑定服务而启动。 - **关联组件 (`hostingNameStr`)**:通常是被绑定的服务名称(如未显示则为空)。 --- #### 2. **具体场景分析** 在日志 `com.android.carrierconfig bindService` 中: - **触发条件**:当系统或其他组件通过 `bindService()` 方法请求绑定 `com.android.carrierconfig` 提供的服务时,若该进程未运行,AMS 会启动该进程。 - **实际意义**:此日志表明系统正在初始化运营商配置服务(如 SIM 卡配置、网络设置等)。 --- #### 3. **关联机制** - **Binder 通信**:`bindService` 涉及 Binder IPC 机制。发起端(Client)通过 `binder_thread_write` 发送请求,接收端(ServiceManager)通过 `binder_thread_read` 处理请求[^1]。 - **进程管理**:AMS 通过 `startProcessLocked` 方法创建进程,并在过程中记录 `am_proc_start` 事件。 --- #### 4. **调试应用** 1. **查看完整日志链**:结合 `am_create_activity`、`am_pause_activity` 等事件,分析进程生命周期。 2. **分析进程状态**:若进程频繁重启,可能涉及崩溃或资源泄漏,需检查 `am_kill` 日志[^3]。 3. **提取内核配置**:通过 `/proc/config.gz` 验证内核是否支持相关调试功能[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值