modem assert

在展讯的8810智能机平台上,发现一个modem assert发来的信号,它会在状态栏上(StatusBar)的左侧显示出一个海盗图标,这是怎么回事?

1. 

那么就先看看状态栏的左侧图标是如何显示出来的吧?

1.1

查看了相关信息,如果想在状态栏上显示出自定义的图标, 一般是使用如下的流程:

private NotificationManager nm;
private Notification n;
nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
n = new Notification();
n.icon = R.drawable.icon;
n.tickerText = "Test Notification";
n.when = System.currentTimeMillis();
Intent intent = new Intent(MainActivity.this,MainActivity.class);
PendingIntent pi = PendingIntent.getActivity(MainActivity.this,0,intent,0);
n.setLatestEventInfo(MainActivity.this,"My Title","My Content",pi);
Log.d(TAG,"nm.notify....");
nm.notify(1,n);
在调用notify之后, 自定义的图标就会显示到状态栏上的左侧位置。

1.2  

但是整个系统中,调用notify接口的应用非常多, 一下在找不出到底谁在调用notify来显示海盗图标。

因此,考虑在notify这个接口内容加一些log信息来追踪源头。

先找到NotificationManager的notify函数实现如下:
public void notify(String tag, int id, Notification notification)
{
        int[] idOut = new int[1];
        INotificationManager service = getService();
        String pkg = mContext.getPackageName();
        if (localLOGV)  Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
        try {
            service.enqueueNotificationWithTag(pkg, tag, id, notification, idOut);
            if (id != idOut[0]) {
                Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
            }
        } catch (RemoteException e) {
        }
}

注意: if (localLOGV)  Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");

从上面这个打印语句,我们可以得到究竟是哪个package的代码在调用notify接口,这正是我需要的,enable这个log语句,然后再次复现问题,抓取log:
E/ModemClient(  561): Modem Assert!!!!
E/ModemClient(  561): Assert in file TdDspAssert.c at line 142 info=[TD DSP ASSERT ID 0x5010]
V/NotificationManager(  561): com.android.modemassert: notify(1, Notification(vibrate=[0,10000],sound=default,defaults=0x1,flags=0x0))
很高兴,我们很顺利的得到了package的名字: com.android.modemassert, 根据这个信息,我们找到了modemassert.apk, 看到调用notify的代码位于ModemAssert.java中。

1.3  

既然是个apk,那么查看一下Manifest.xml:

<receiver android:name="StartAssert">
       <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
         </intent-filter>
 </receiver>
  <service android:name="com.android.modemassert.ModemAssert"></service>
apk包含一个BroadcastReceiver和一个Service。

1.3.1 

BroadcastReceiver接收到BOOT_COMPLETED消息后会startService。

1.3.2

在service的onCreate()中创建socket:

s = new LocalSocket();
LocalSocket s = null;
LocalSocketAddress l = null;
mSocket = s;
mSocketAddr = l;
mSocket.connect(mSocketAddr);
注意:private static final String MODEM_SOCKET_NAME = "modemd";
通过这个socket,如果接收到发来的Assert信息,就把它显示到statusBar上。
由此可知,modemassert.apk是socket的client端,那么socket的server端是谁呢?  

2.

通过socket_name:"modemd"来搜索,可以找到在modemd.c中有:

#define MODEM_SOCKET_NAME  "modemd"
modemd是一个可执行程序,即一个守护进程,在它的main函数中:

2.1

先开启一个线程,在线程中创建servier socket,与client之间建立链接。

sfd = socket_local_server(MODEM_SOCKET_NAME,0, SOCK_STREAM);
。。。
n=accept(sfd,NULL,NULL);
。。。
client_fd[i]=n;
把已经建立好连接的client socketId 存放在client_fd[]中。

2.2

从“/dev/vbpipe2“中读取数据,如果读到assertinfo,就将它发送给socket的client端。

#define MODEM_PATH    "/dev/vbpipe2"
。。。
modemfd = open(MODEM_PATH, O_RDONLY);
。。。
numRead = read(modemfd, buf, DATA_BUF_SIZE);
。。。
ret = write(client_fd[i], buf, numRead);

看到这里,实际上modem的assertInfo是通过“dev/vbpipe2”读取到的。这个有待进一步分析了。

2.3 

我们还可以在init.rc中看到modemd的启动信息:

service modemd /system/bin/modemd
    socket modemd stream 666 system system
    user system
    group system radio
    oneshot

3.
总的来说,modemassert.apk和modemd守护进程之间构成了socket的client和server交互,最终传送assertinfo到用户界面的状态栏上。
通过命令:adb shell procrank可以看到系统开机后,这两个进程都开启了:
610   16016K   15968K    2092K    1416K  com.android.modemassert
  95     324K            320K      85K      80K      /system/bin/modemd


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值