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