Home | History | Annotate | Download | only in communication
      1 /*
      2  * Copyright (C) 2010, The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.internal.communication;
     18 
     19 import android.util.Log;
     20 
     21 import com.android.internal.communication.MsgHeader;
     22 import com.android.internal.telephony.RilChannel;
     23 import com.google.protobuf.micro.InvalidProtocolBufferMicroException;
     24 import com.google.protobuf.micro.MessageMicro;
     25 
     26 import java.io.IOException;
     27 import java.nio.ByteBuffer;
     28 import java.nio.ByteOrder;
     29 
     30 /**
     31  * A message
     32  */
     33 public class Msg {
     34     private MsgHeader  mHeader;
     35     private ByteBuffer mData;
     36 
     37     /**
     38      * Send a message header
     39      *
     40      * @param mh is message header to write
     41      * @throws IOException
     42      */
     43     private static void sendHeader(RilChannel rc, MsgHeader mh) throws IOException {
     44         ByteBuffer lenBuffer = ByteBuffer.allocateDirect(4);
     45         lenBuffer.order(ByteOrder.LITTLE_ENDIAN);
     46         lenBuffer.putInt(mh.getSerializedSize());
     47 
     48         ByteBuffer mhBuffer = ByteBuffer.allocateDirect(mh.getCachedSize());
     49         mhBuffer.put(mh.toByteArray());
     50 
     51         rc.rewindSendAll(lenBuffer);
     52         rc.rewindSendAll(mhBuffer);
     53     }
     54 
     55     /**
     56      * Read a message header
     57      *
     58      * @returns message header
     59      * @throws IOException
     60      */
     61     private static MsgHeader recvHeader(RilChannel rc) throws IOException {
     62         ByteBuffer lenBuffer = ByteBuffer.allocate(4);
     63         lenBuffer.order(ByteOrder.LITTLE_ENDIAN);
     64         int lenRead = rc.recvAllRewind(lenBuffer);
     65         int lenHeader = lenBuffer.getInt();
     66 
     67         ByteBuffer mhBuffer = ByteBuffer.allocate(lenHeader);
     68         lenRead = rc.recvAllRewind(mhBuffer);
     69         MsgHeader mh = MsgHeader.parseFrom(mhBuffer.array());
     70         return mh;
     71     }
     72 
     73     /**
     74      * Msg Constructor
     75      */
     76     private Msg() {
     77     }
     78 
     79     /**
     80      * Get a message
     81      */
     82     public static Msg obtain() {
     83         // TODO: Get from a free list
     84         return new Msg();
     85     }
     86 
     87     /**
     88      * Release a message
     89      */
     90     public void release() {
     91         // TODO: place back on free list
     92     }
     93 
     94     /**
     95      * Send a message header followed by the data if present
     96      *
     97      * The length data field will be filled in as appropriate
     98      * @param mh header
     99      * @param data if not null and length > 0 sent after header
    100      * @throws IOException
    101      */
    102     public static final void send(RilChannel rc, MsgHeader mh, ByteBuffer data)
    103             throws IOException {
    104         int lenData;
    105 
    106         if (data == null) {
    107             lenData = 0;
    108         } else {
    109             data.rewind();
    110             lenData = data.remaining();
    111         }
    112         mh.setLengthData(lenData);
    113         sendHeader(rc, mh);
    114         if (lenData > 0) {
    115             rc.sendAll(data);
    116         }
    117     }
    118 
    119     /**
    120      * Send a message with cmd, token, status followed by the data.
    121      *
    122      * The length data field will be filled in as appropriate
    123      * @param cmd for the header
    124      * @param token for the header
    125      * @param status for the header
    126      * @param pb is the protobuf to send
    127      * @throws IOException
    128      */
    129     public static final void send(RilChannel rc, int cmd, long token, int status, MessageMicro pb)
    130             throws IOException {
    131         MsgHeader mh = new MsgHeader();
    132         mh.setCmd(cmd);
    133         mh.setToken(token);
    134         mh.setStatus(status);
    135 
    136         ByteBuffer data;
    137         if (pb != null) {
    138             data = ByteBuffer.wrap(pb.toByteArray());
    139         } else {
    140             data = null;
    141         }
    142         send(rc, mh, data);
    143     }
    144 
    145     /**
    146      * Send a message with cmd, token, status followed by the data.
    147      *
    148      * The length data field will be filled in as appropriate
    149      * @param cmd for the header
    150      * @param token for the header
    151      * @param pb is the protobuf to send
    152      * @throws IOException
    153      */
    154     public static final void send(RilChannel rc, int cmd, long token, MessageMicro pb)
    155             throws IOException {
    156         send(rc, cmd, token, 0, pb);
    157     }
    158 
    159     /**
    160      * Send a message with cmd followed by the data.
    161      *
    162      * The length data field will be filled in as appropriate
    163      * @param cmd for the header
    164      * @param pb is the protobuf to send
    165      * @throws IOException
    166      */
    167     public static final void send(RilChannel rc, int cmd, MessageMicro pb) throws IOException {
    168         send(rc, cmd, 0, 0, pb);
    169     }
    170 
    171     /**
    172      * Send a message with cmd, token and status but no data
    173      *
    174      * The length data field will be filled in as appropriate
    175      * @param cmd for the header
    176      * @param token for the header
    177      * @param status for the header
    178      * @throws IOException
    179      */
    180     public static final void send(RilChannel rc, int cmd, long token, int status)
    181             throws IOException {
    182         send(rc, cmd, token, status, null);
    183     }
    184 
    185     /**
    186      * Send a message with cmd and token but no data
    187      *
    188      * The length data field will be filled in as appropriate
    189      * @param cmd for the header
    190      * @param token for the header
    191      * @throws IOException
    192      */
    193     public static final void send(RilChannel rc, int cmd, long token) throws IOException {
    194         send(rc, cmd, token, 0, null);
    195     }
    196 
    197     /**
    198      * Send a message with cmd but no data
    199      *
    200      * The length data field will be filled in as appropriate
    201      * @param cmd for the header
    202      * @throws IOException
    203      */
    204     public static final void send(RilChannel rc, int cmd) throws IOException {
    205         send(rc, cmd, 0, 0, null);
    206     }
    207 
    208     /**
    209      * Read a message
    210      *
    211      * @return Msg
    212      * @throws IOException
    213      */
    214     public static final Msg recv(RilChannel rc) throws IOException {
    215         Msg msg = Msg.obtain();
    216         msg.read(rc);
    217         return msg;
    218     }
    219 
    220     /**
    221      * Read a message header and data.
    222      *
    223      * @throws IOException
    224      */
    225     public void read(RilChannel rc) throws IOException {
    226         mHeader = recvHeader(rc);
    227         if (mHeader.getLengthData() > 0) {
    228             ByteBuffer bb = ByteBuffer.allocate(mHeader.getLengthData());
    229             rc.recvAllRewind(bb);
    230             mData = bb;
    231         }
    232     }
    233 
    234     /**
    235      * Print the message header.
    236      *
    237      * @param tag for the header
    238      */
    239     public void printHeader(String tag) {
    240         Log.d(tag, " cmd=" + mHeader.getCmd() + " token=" + mHeader.getToken() + " status="
    241                         + mHeader.getStatus() + " lengthData=" + mHeader.getLengthData());
    242     }
    243 
    244     /**
    245      * Set data (for testing purposes only).
    246      */
    247     public void setData(ByteBuffer data) {
    248         mData = data;
    249     }
    250 
    251     /**
    252      * Set header (for testing purposes only).
    253      */
    254     public void setHeader(MsgHeader header) {
    255         mHeader = header;
    256     }
    257 
    258     /**
    259      * @return cmd
    260      */
    261     public int getCmd() {
    262         return mHeader.getCmd();
    263     }
    264 
    265     /**
    266      * @return token
    267      */
    268     public long getToken() {
    269         return mHeader.getToken();
    270     }
    271 
    272     /**
    273      * @return status
    274      */
    275     public int getStatus() {
    276         return mHeader.getStatus();
    277     }
    278 
    279     /**
    280      * @return data ByteBuffer
    281      */
    282     public ByteBuffer getData() {
    283         return mData;
    284     }
    285 
    286     /**
    287      * @return data at index
    288      */
    289     public byte getData(int index) {
    290         return mData.get(index);
    291     }
    292 
    293     /**
    294      * Return data as a Class<T>.
    295      *
    296      * @param <T> a class that extends MessageMicro.
    297      * @param c the T.class to create from the data.
    298      * @param data is the MessageMicro protobuf to be converted.
    299      * @return null if an error occurs.
    300      */
    301     @SuppressWarnings("unchecked")
    302     public static final <T extends MessageMicro> T getAs(Class<T> c, byte[] data) {
    303         Object o = null;
    304         if ((data != null) && (data.length > 0)) {
    305             try {
    306                 o = c.newInstance().mergeFrom(data);
    307             } catch (InvalidProtocolBufferMicroException e) {
    308                 e.printStackTrace();
    309             } catch (InstantiationException e) {
    310                 e.printStackTrace();
    311             } catch (IllegalAccessException e) {
    312                 e.printStackTrace();
    313             }
    314         }
    315         return (T)o;
    316     }
    317 
    318     /**
    319      * Return data as a Class<T>.
    320      *
    321      * @param <T> a class that extends MessageMicro.
    322      * @param c the T.class to create from data.
    323      * @return null if an error occurs
    324      */
    325     @SuppressWarnings("unchecked")
    326     public <T extends MessageMicro> T getDataAs(Class<T> c) {
    327         Object o;
    328 
    329         if ((mData != null) && (mData.remaining() > 0)) {
    330             o = getAs(c, mData.array());
    331         } else {
    332             o = null;
    333         }
    334         return (T)o;
    335     }
    336 }
    337