| /* |
| * Copyright (C) 2010, The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.internal.communication; |
| |
| import android.util.Log; |
| |
| import com.android.internal.communication.MsgHeader; |
| import com.android.internal.telephony.RilChannel; |
| import com.google.protobuf.micro.InvalidProtocolBufferMicroException; |
| import com.google.protobuf.micro.MessageMicro; |
| |
| import java.io.IOException; |
| import java.nio.ByteBuffer; |
| import java.nio.ByteOrder; |
| |
| /** |
| * A message |
| */ |
| public class Msg { |
| private MsgHeader mHeader; |
| private ByteBuffer mData; |
| |
| /** |
| * Send a message header |
| * |
| * @param mh is message header to write |
| * @throws IOException |
| */ |
| private static void sendHeader(RilChannel rc, MsgHeader mh) throws IOException { |
| ByteBuffer lenBuffer = ByteBuffer.allocateDirect(4); |
| lenBuffer.order(ByteOrder.LITTLE_ENDIAN); |
| lenBuffer.putInt(mh.getSerializedSize()); |
| |
| ByteBuffer mhBuffer = ByteBuffer.allocateDirect(mh.getCachedSize()); |
| mhBuffer.put(mh.toByteArray()); |
| |
| rc.rewindSendAll(lenBuffer); |
| rc.rewindSendAll(mhBuffer); |
| } |
| |
| /** |
| * Read a message header |
| * |
| * @returns message header |
| * @throws IOException |
| */ |
| private static MsgHeader recvHeader(RilChannel rc) throws IOException { |
| ByteBuffer lenBuffer = ByteBuffer.allocate(4); |
| lenBuffer.order(ByteOrder.LITTLE_ENDIAN); |
| int lenRead = rc.recvAllRewind(lenBuffer); |
| int lenHeader = lenBuffer.getInt(); |
| |
| ByteBuffer mhBuffer = ByteBuffer.allocate(lenHeader); |
| lenRead = rc.recvAllRewind(mhBuffer); |
| MsgHeader mh = MsgHeader.parseFrom(mhBuffer.array()); |
| return mh; |
| } |
| |
| /** |
| * Msg Constructor |
| */ |
| private Msg() { |
| } |
| |
| /** |
| * Get a message |
| */ |
| public static Msg obtain() { |
| // TODO: Get from a free list |
| return new Msg(); |
| } |
| |
| /** |
| * Release a message |
| */ |
| public void release() { |
| // TODO: place back on free list |
| } |
| |
| /** |
| * Send a message header followed by the data if present |
| * |
| * The length data field will be filled in as appropriate |
| * @param mh header |
| * @param data if not null and length > 0 sent after header |
| * @throws IOException |
| */ |
| public static final void send(RilChannel rc, MsgHeader mh, ByteBuffer data) |
| throws IOException { |
| int lenData; |
| |
| if (data == null) { |
| lenData = 0; |
| } else { |
| data.rewind(); |
| lenData = data.remaining(); |
| } |
| mh.setLengthData(lenData); |
| sendHeader(rc, mh); |
| if (lenData > 0) { |
| rc.sendAll(data); |
| } |
| } |
| |
| /** |
| * Send a message with cmd, token, status followed by the data. |
| * |
| * The length data field will be filled in as appropriate |
| * @param cmd for the header |
| * @param token for the header |
| * @param status for the header |
| * @param pb is the protobuf to send |
| * @throws IOException |
| */ |
| public static final void send(RilChannel rc, int cmd, long token, int status, MessageMicro pb) |
| throws IOException { |
| MsgHeader mh = new MsgHeader(); |
| mh.setCmd(cmd); |
| mh.setToken(token); |
| mh.setStatus(status); |
| |
| ByteBuffer data; |
| if (pb != null) { |
| data = ByteBuffer.wrap(pb.toByteArray()); |
| } else { |
| data = null; |
| } |
| send(rc, mh, data); |
| } |
| |
| /** |
| * Send a message with cmd, token, status followed by the data. |
| * |
| * The length data field will be filled in as appropriate |
| * @param cmd for the header |
| * @param token for the header |
| * @param pb is the protobuf to send |
| * @throws IOException |
| */ |
| public static final void send(RilChannel rc, int cmd, long token, MessageMicro pb) |
| throws IOException { |
| send(rc, cmd, token, 0, pb); |
| } |
| |
| /** |
| * Send a message with cmd followed by the data. |
| * |
| * The length data field will be filled in as appropriate |
| * @param cmd for the header |
| * @param pb is the protobuf to send |
| * @throws IOException |
| */ |
| public static final void send(RilChannel rc, int cmd, MessageMicro pb) throws IOException { |
| send(rc, cmd, 0, 0, pb); |
| } |
| |
| /** |
| * Send a message with cmd, token and status but no data |
| * |
| * The length data field will be filled in as appropriate |
| * @param cmd for the header |
| * @param token for the header |
| * @param status for the header |
| * @throws IOException |
| */ |
| public static final void send(RilChannel rc, int cmd, long token, int status) |
| throws IOException { |
| send(rc, cmd, token, status, null); |
| } |
| |
| /** |
| * Send a message with cmd and token but no data |
| * |
| * The length data field will be filled in as appropriate |
| * @param cmd for the header |
| * @param token for the header |
| * @throws IOException |
| */ |
| public static final void send(RilChannel rc, int cmd, long token) throws IOException { |
| send(rc, cmd, token, 0, null); |
| } |
| |
| /** |
| * Send a message with cmd but no data |
| * |
| * The length data field will be filled in as appropriate |
| * @param cmd for the header |
| * @throws IOException |
| */ |
| public static final void send(RilChannel rc, int cmd) throws IOException { |
| send(rc, cmd, 0, 0, null); |
| } |
| |
| /** |
| * Read a message |
| * |
| * @return Msg |
| * @throws IOException |
| */ |
| public static final Msg recv(RilChannel rc) throws IOException { |
| Msg msg = Msg.obtain(); |
| msg.read(rc); |
| return msg; |
| } |
| |
| /** |
| * Read a message header and data. |
| * |
| * @throws IOException |
| */ |
| public void read(RilChannel rc) throws IOException { |
| mHeader = recvHeader(rc); |
| if (mHeader.getLengthData() > 0) { |
| ByteBuffer bb = ByteBuffer.allocate(mHeader.getLengthData()); |
| rc.recvAllRewind(bb); |
| mData = bb; |
| } |
| } |
| |
| /** |
| * Print the message header. |
| * |
| * @param tag for the header |
| */ |
| public void printHeader(String tag) { |
| Log.d(tag, " cmd=" + mHeader.getCmd() + " token=" + mHeader.getToken() + " status=" |
| + mHeader.getStatus() + " lengthData=" + mHeader.getLengthData()); |
| } |
| |
| /** |
| * Set data (for testing purposes only). |
| */ |
| public void setData(ByteBuffer data) { |
| mData = data; |
| } |
| |
| /** |
| * Set header (for testing purposes only). |
| */ |
| public void setHeader(MsgHeader header) { |
| mHeader = header; |
| } |
| |
| /** |
| * @return cmd |
| */ |
| public int getCmd() { |
| return mHeader.getCmd(); |
| } |
| |
| /** |
| * @return token |
| */ |
| public long getToken() { |
| return mHeader.getToken(); |
| } |
| |
| /** |
| * @return status |
| */ |
| public int getStatus() { |
| return mHeader.getStatus(); |
| } |
| |
| /** |
| * @return data ByteBuffer |
| */ |
| public ByteBuffer getData() { |
| return mData; |
| } |
| |
| /** |
| * @return data at index |
| */ |
| public byte getData(int index) { |
| return mData.get(index); |
| } |
| |
| /** |
| * Return data as a Class<T>. |
| * |
| * @param <T> a class that extends MessageMicro. |
| * @param c the T.class to create from the data. |
| * @param data is the MessageMicro protobuf to be converted. |
| * @return null if an error occurs. |
| */ |
| @SuppressWarnings("unchecked") |
| public static final <T extends MessageMicro> T getAs(Class<T> c, byte[] data) { |
| Object o = null; |
| if ((data != null) && (data.length > 0)) { |
| try { |
| o = c.newInstance().mergeFrom(data); |
| } catch (InvalidProtocolBufferMicroException e) { |
| e.printStackTrace(); |
| } catch (InstantiationException e) { |
| e.printStackTrace(); |
| } catch (IllegalAccessException e) { |
| e.printStackTrace(); |
| } |
| } |
| return (T)o; |
| } |
| |
| /** |
| * Return data as a Class<T>. |
| * |
| * @param <T> a class that extends MessageMicro. |
| * @param c the T.class to create from data. |
| * @return null if an error occurs |
| */ |
| @SuppressWarnings("unchecked") |
| public <T extends MessageMicro> T getDataAs(Class<T> c) { |
| Object o; |
| |
| if ((mData != null) && (mData.remaining() > 0)) { |
| o = getAs(c, mData.array()); |
| } else { |
| o = null; |
| } |
| return (T)o; |
| } |
| } |