概述
NativeDaemonConnector用于socket通信下的消息发送和接受。其中定义了一套私有协议以满足其目的
详情:
注:源码7.1
1.实现接口Runnable, Handler.Callback, Watchdog.Monitor
class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdog.Monitor
2.构造方法
NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket,
int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl,
Looper looper) {
mCallbacks = callbacks;//回调方法
mSocket = socket;//socket名称。在/dev/socket中,可查对应的socket
mResponseQueue = new ResponseQueue(responseQueueSize);//响应对列
mWakeLock = wl;
if (mWakeLock != null) {
mWakeLock.setReferenceCounted(true);
}
mLooper = looper;
mSequenceNumber = new AtomicInteger(0);//原子性对象
TAG = logTag != null ? logTag : "NativeDaemonConnector";
mLocalLog = new LocalLog(maxLogSize);
}
3.run
public void run() {
mCallbackHandler = new Handler(mLooper, this);//创建handler对象,此时,关注handleMessage方法
while (true) {//创建死循环
try {
listenToSocket();//监听socket通信
} catch (Exception e) {//异常之后,也仅仅是休息5秒
loge("Error in NativeDaemonConnector: " + e);
SystemClock.sleep(5000);
}
}
}
private void listenToSocket() throws IOException {
LocalSocket socket = null;
try {
socket = new LocalSocket();
LocalSocketAddress address = determineSocketAddress();
socket.connect(address);//socket建立连接
InputStream inputStream = socket.getInputStream();//获取读数据流对象
synchronized (mDaemonLock) {
mOutputStream = socket.getOutputStream();//获取写数据流对象
}
mCallbacks.onDaemonConnected();//回调告诉socket通信已经建立
FileDescriptor[] fdList = null;
byte[] buffer = new byte[BUFFER_SIZE];
int start = 0;
while (true) {
int count = inputStream.read(buffer, start, BUFFER_SIZE - start);//
if (count < 0) {
loge("got " + count + " reading with start = " + start);
break;
}
fdList = socket.getAncillaryFileDescriptors();
// Add our starting point to the count and reset the start.
count += start;
start = 0;
for (int i = 0; i < count; i++) {
if (buffer[i] == 0) {
// Note - do not log this raw message since it may contain
// sensitive data
final String rawEvent = new String(
buffer, start, i - start, StandardCharsets.UTF_8);//拼接native daemon发送的原始数据
boolean releaseWl = false;
try {
final NativeDaemonEvent event =
NativeDaemonEvent.parseRawEvent(rawEvent, fdList);//将rowEvent转化成我们需要的数据
log("RCV <- {" + event + "}");
if (event.isClassUnsolicited()) {
// TODO: migrate to sending NativeDaemonEvent instances
if (mCallbacks.onCheckHoldWakeLock(event.getCode())
&& mWakeLock != null) {//回调调用方,是否需要hold cpu
mWakeLock.acquire();
releaseWl = true;
}
Message msg = mCallbackHandler.obtainMessage(
event.getCode(), uptimeMillisInt(), 0, event.getRawEvent());
if (mCallbackHandler.sendMessage(msg)) {//关键方法,处理
releaseWl = false;
}
} else {
mResponseQueue.add(event.getCmdNumber(), event);
}
} catch (IllegalArgumentException e) {
log("Problem parsing message " + e);
} finally {
if (releaseWl) {
mWakeLock.release();
}
}
start = i + 1;
}
}
if (start == 0) {
log("RCV incomplete");
}
// We should end at the amount we read. If not, compact then
// buffer and read again.
if (start != count) {
final int remaining = BUFFER_SIZE - start;
System.arraycopy(buffer, start, buffer, 0, remaining);
start = remaining;
} else {
start = 0;
}
}
} catch (IOException ex) {
loge("Communications error: " + ex);
throw ex;
} finally {
synchronized (mDaemonLock) {
if (mOutputStream != null) {
try {
loge("closing stream for " + mSocket);
mOutputStream.close();
} catch (IOException e) {
loge("Failed closing output stream: " + e);
}
mOutputStream = null;
}
}
try {
if (socket != null) {
socket.close();
}
} catch (IOException ex) {
loge("Failed closing socket: " + ex);
}
}
}
4.读处理
public boolean handleMessage(Message msg) {
final String event = (String) msg.obj;
final int start = uptimeMillisInt();
final int sent = msg.arg1;
try {
if (!mCallbacks.onEvent(msg.what, event, NativeDaemonEvent.unescapeArgs(event))) {//回调数据。关键实现类中的onEvent方法
log(String.format("Unhandled event '%s'", event));
}
} catch (Exception e) {
loge("Error handling '" + event + "': " + e);
} finally {
if (mCallbacks.onCheckHoldWakeLock(msg.what) && mWakeLock != null) {
mWakeLock.release();
}
final int end = uptimeMillisInt();
if (start > sent && start - sent > WARN_EXECUTE_DELAY_MS) {
loge(String.format("NDC event {%s} processed too late: %dms", event, start - sent));
}
if (end > start && end - start > WARN_EXECUTE_DELAY_MS) {
loge(String.format("NDC event {%s} took too long: %dms", event, end - start));
}
}
return true;
}
5.写处理。以execute为案例
public NativeDaemonEvent execute(Command cmd) throws NativeDaemonConnectorException {
return execute(cmd.mCmd, cmd.mArguments.toArray());
}
public NativeDaemonEvent execute(String cmd, Object... args)
throws NativeDaemonConnectorException {
return execute(DEFAULT_TIMEOUT, cmd, args);
}
public NativeDaemonEvent execute(long timeoutMs, String cmd, Object... args)
throws NativeDaemonConnectorException {
final NativeDaemonEvent[] events = executeForList(timeoutMs, cmd, args);
if (events.length != 1) {
throw new NativeDaemonConnectorException(
"Expected exactly one response, but received " + events.length);
}
return events[0];
}
public NativeDaemonEvent[] executeForList(long timeoutMs, String cmd, Object... args)
throws NativeDaemonConnectorException {
if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) {
Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
+ Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable());
}
final long startTime = SystemClock.elapsedRealtime();
final ArrayList<NativeDaemonEvent> events = Lists.newArrayList();
final StringBuilder rawBuilder = new StringBuilder();
final StringBuilder logBuilder = new StringBuilder();
final int sequenceNumber = mSequenceNumber.incrementAndGet();
makeCommand(rawBuilder, logBuilder, sequenceNumber, cmd, args);//创建命令
final String rawCmd = rawBuilder.toString();
final String logCmd = logBuilder.toString();
log("SND -> {" + logCmd + "}");
synchronized (mDaemonLock) {
if (mOutputStream == null) {
throw new NativeDaemonConnectorException("missing output stream");
} else {
try {
mOutputStream.write(rawCmd.getBytes(StandardCharsets.UTF_8));//写数据
} catch (IOException e) {
throw new NativeDaemonConnectorException("problem sending command", e);
}
}
}
NativeDaemonEvent event = null;
do {
event = mResponseQueue.remove(sequenceNumber, timeoutMs, logCmd);
if (event == null) {
loge("timed-out waiting for response to " + logCmd);
throw new NativeDaemonTimeoutException(logCmd, event);
}
if (VDBG) log("RMV <- {" + event + "}");
events.add(event);
} while (event.isClassContinue());
final long endTime = SystemClock.elapsedRealtime();
if (endTime - startTime > WARN_EXECUTE_DELAY_MS) {
loge("NDC Command {" + logCmd + "} took too long (" + (endTime - startTime) + "ms)");
}
if (event.isClassClientError()) {
throw new NativeDaemonArgumentException(logCmd, event);
}
if (event.isClassServerError()) {
throw new NativeDaemonFailureException(logCmd, event);
}
return events.toArray(new NativeDaemonEvent[events.size()]);
}
6.案例
NetworkManagementService -- netd通信采用
MountService -- vold通信采用
7.总结
1)NativeDaemonConnector负责通信及数据归一
2)回调类INativeDaemonConnectorCallbacks处理具体业务数据
8.补充亮点
android.util.LocalLog
此工具类承载了日常dump历史数据的处理。实现原理采用一个链表来累计数据
public final class LocalLog {
private LinkedList<String> mLog;
private int mMaxLines;
private long mNow;
public LocalLog(int maxLines) {
mLog = new LinkedList<String>();
mMaxLines = maxLines;
}
public synchronized void log(String msg) {
if (mMaxLines > 0) {
mNow = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
Calendar c = Calendar.getInstance();
c.setTimeInMillis(mNow);
sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c));
mLog.add(sb.toString() + " - " + msg);//将数据放入列表中
while (mLog.size() > mMaxLines) mLog.remove();//设置数据容量上限
}
}
public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Iterator<String> itr = mLog.listIterator(0);
while (itr.hasNext()) {
pw.println(itr.next());//把mLog表的数据,一个一个打印出来
}
}
public synchronized void reverseDump(FileDescriptor fd, PrintWriter pw, String[] args) {
for (int i = mLog.size() - 1; i >= 0; i--) {
pw.println(mLog.get(i));
}
}
public static class ReadOnlyLocalLog {
private final LocalLog mLog;
ReadOnlyLocalLog(LocalLog log) {
mLog = log;
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
mLog.dump(fd, pw, args);
}
}
public ReadOnlyLocalLog readOnlyLocalLog() {
return new ReadOnlyLocalLog(this);//只读工具类
}
}
网友评论