1 /*
2  * Copyright (C) 2007 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.telephony.cat;
18 
19 import android.compat.annotation.UnsupportedAppUsage;
20 import android.os.Handler;
21 import android.os.Message;
22 import android.telephony.SubscriptionManager;
23 import android.telephony.TelephonyManager;
24 
25 import com.android.internal.telephony.uicc.IccFileHandler;
26 import com.android.internal.telephony.uicc.IccUtils;
27 import com.android.internal.util.State;
28 import com.android.internal.util.StateMachine;
29 
30 /**
31  * Class used for queuing raw ril messages, decoding them into CommanParams
32  * objects and sending the result back to the CAT Service.
33  */
34 class RilMessageDecoder extends StateMachine {
35 
36     // constants
37     private static final int CMD_START = 1;
38     private static final int CMD_PARAMS_READY = 2;
39 
40     // members
41     @UnsupportedAppUsage
42     private CommandParamsFactory mCmdParamsFactory = null;
43     @UnsupportedAppUsage
44     private RilMessage mCurrentRilMessage = null;
45     private Handler mCaller = null;
46     private static int mSimCount = 0;
47     @UnsupportedAppUsage
48     private static RilMessageDecoder[] mInstance = null;
49 
50     // States
51     @UnsupportedAppUsage
52     private StateStart mStateStart = new StateStart();
53     private StateCmdParamsReady mStateCmdParamsReady = new StateCmdParamsReady();
54 
55     /**
56      * Get the singleton instance, constructing if necessary.
57      *
58      * @param caller
59      * @param fh
60      * @return RilMesssageDecoder
61      */
62     @UnsupportedAppUsage
getInstance(Handler caller, IccFileHandler fh, int slotId)63     public static synchronized RilMessageDecoder getInstance(Handler caller, IccFileHandler fh,
64             int slotId) {
65         if (null == mInstance) {
66             mSimCount = TelephonyManager.getDefault().getSupportedModemCount();
67             mInstance = new RilMessageDecoder[mSimCount];
68             for (int i = 0; i < mSimCount; i++) {
69                 mInstance[i] = null;
70             }
71         }
72 
73         if (slotId != SubscriptionManager.INVALID_SIM_SLOT_INDEX && slotId < mSimCount) {
74             if (null == mInstance[slotId]) {
75                 mInstance[slotId] = new RilMessageDecoder(caller, fh);
76             }
77         } else {
78             CatLog.d("RilMessageDecoder", "invaild slot id: " + slotId);
79             return null;
80         }
81 
82         return mInstance[slotId];
83     }
84 
85     /**
86      * Start decoding the message parameters,
87      * when complete MSG_ID_RIL_MSG_DECODED will be returned to caller.
88      *
89      * @param rilMsg
90      */
91     @UnsupportedAppUsage
sendStartDecodingMessageParams(RilMessage rilMsg)92     public void sendStartDecodingMessageParams(RilMessage rilMsg) {
93         Message msg = obtainMessage(CMD_START);
94         msg.obj = rilMsg;
95         sendMessage(msg);
96     }
97 
98     /**
99      * The command parameters have been decoded.
100      *
101      * @param resCode
102      * @param cmdParams
103      */
sendMsgParamsDecoded(ResultCode resCode, CommandParams cmdParams)104     public void sendMsgParamsDecoded(ResultCode resCode, CommandParams cmdParams) {
105         Message msg = obtainMessage(RilMessageDecoder.CMD_PARAMS_READY);
106         msg.arg1 = resCode.value();
107         msg.obj = cmdParams;
108         sendMessage(msg);
109     }
110 
111     @UnsupportedAppUsage
sendCmdForExecution(RilMessage rilMsg)112     private void sendCmdForExecution(RilMessage rilMsg) {
113         Message msg = mCaller.obtainMessage(CatService.MSG_ID_RIL_MSG_DECODED,
114                 new RilMessage(rilMsg));
115         msg.sendToTarget();
116     }
117 
RilMessageDecoder(Handler caller, IccFileHandler fh)118     private RilMessageDecoder(Handler caller, IccFileHandler fh) {
119         super("RilMessageDecoder");
120 
121         addState(mStateStart);
122         addState(mStateCmdParamsReady);
123         setInitialState(mStateStart);
124 
125         mCaller = caller;
126         mCmdParamsFactory = CommandParamsFactory.getInstance(this, fh);
127     }
128 
RilMessageDecoder()129     private RilMessageDecoder() {
130         super("RilMessageDecoder");
131     }
132 
133     private class StateStart extends State {
134         @Override
processMessage(Message msg)135         public boolean processMessage(Message msg) {
136             if (msg.what == CMD_START) {
137                 if (decodeMessageParams((RilMessage)msg.obj)) {
138                     transitionTo(mStateCmdParamsReady);
139                 }
140             } else {
141                 CatLog.d(this, "StateStart unexpected expecting START=" +
142                          CMD_START + " got " + msg.what);
143             }
144             return true;
145         }
146     }
147 
148     private class StateCmdParamsReady extends State {
149         @Override
processMessage(Message msg)150         public boolean processMessage(Message msg) {
151             if (msg.what == CMD_PARAMS_READY) {
152                 mCurrentRilMessage.mResCode = ResultCode.fromInt(msg.arg1);
153                 mCurrentRilMessage.mData = msg.obj;
154                 sendCmdForExecution(mCurrentRilMessage);
155                 transitionTo(mStateStart);
156             } else {
157                 CatLog.d(this, "StateCmdParamsReady expecting CMD_PARAMS_READY="
158                          + CMD_PARAMS_READY + " got " + msg.what);
159                 deferMessage(msg);
160             }
161             return true;
162         }
163     }
164 
decodeMessageParams(RilMessage rilMsg)165     private boolean decodeMessageParams(RilMessage rilMsg) {
166         boolean decodingStarted;
167 
168         mCurrentRilMessage = rilMsg;
169         switch(rilMsg.mId) {
170         case CatService.MSG_ID_SESSION_END:
171         case CatService.MSG_ID_CALL_SETUP:
172             mCurrentRilMessage.mResCode = ResultCode.OK;
173             sendCmdForExecution(mCurrentRilMessage);
174             decodingStarted = false;
175             break;
176         case CatService.MSG_ID_PROACTIVE_COMMAND:
177         case CatService.MSG_ID_EVENT_NOTIFY:
178         case CatService.MSG_ID_REFRESH:
179             byte[] rawData = null;
180             try {
181                 rawData = IccUtils.hexStringToBytes((String) rilMsg.mData);
182             } catch (Exception e) {
183                 // zombie messages are dropped
184                 CatLog.d(this, "decodeMessageParams dropping zombie messages");
185                 decodingStarted = false;
186                 break;
187             }
188             try {
189                 // Start asynch parsing of the command parameters.
190                 mCmdParamsFactory.make(BerTlv.decode(rawData));
191                 decodingStarted = true;
192             } catch (ResultException e) {
193                 // send to Service for proper RIL communication.
194                 CatLog.d(this, "decodeMessageParams: caught ResultException e=" + e);
195                 mCurrentRilMessage.mResCode = e.result();
196                 sendCmdForExecution(mCurrentRilMessage);
197                 decodingStarted = false;
198             }
199             break;
200         default:
201             decodingStarted = false;
202             break;
203         }
204         return decodingStarted;
205     }
206 
dispose()207     public void dispose() {
208         quitNow();
209         mStateStart = null;
210         mStateCmdParamsReady = null;
211         mCmdParamsFactory.dispose();
212         mCmdParamsFactory = null;
213         mCurrentRilMessage = null;
214         mCaller = null;
215         mInstance = null;
216     }
217 }
218