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