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