• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 package com.android.internal.net.ipsec.ike;
17 
18 import static android.net.ipsec.ike.IkeManager.getIkeLog;
19 
20 import android.os.Looper;
21 import android.os.Message;
22 import android.util.SparseArray;
23 
24 import com.android.internal.annotations.VisibleForTesting;
25 import com.android.internal.util.IState;
26 import com.android.internal.util.State;
27 import com.android.internal.util.StateMachine;
28 
29 import java.util.concurrent.Executor;
30 import java.util.concurrent.TimeUnit;
31 
32 /**
33  * This class represents the common information of both IkeSessionStateMachine and
34  * ChildSessionStateMachine
35  */
36 abstract class AbstractSessionStateMachine extends StateMachine {
37     private static final int CMD_SHARED_BASE = 0;
38     protected static final int CMD_CATEGORY_SIZE = 100;
39 
40     /**
41      * Commands of Child local request that will be used in both IkeSessionStateMachine and
42      * ChildSessionStateMachine.
43      */
44     protected static final int CMD_CHILD_LOCAL_REQUEST_BASE = CMD_SHARED_BASE;
45 
46     @VisibleForTesting
47     static final int CMD_LOCAL_REQUEST_CREATE_CHILD = CMD_CHILD_LOCAL_REQUEST_BASE + 1;
48 
49     @VisibleForTesting
50     static final int CMD_LOCAL_REQUEST_DELETE_CHILD = CMD_CHILD_LOCAL_REQUEST_BASE + 2;
51 
52     @VisibleForTesting
53     static final int CMD_LOCAL_REQUEST_REKEY_CHILD = CMD_CHILD_LOCAL_REQUEST_BASE + 3;
54 
55     @VisibleForTesting
56     static final int CMD_LOCAL_REQUEST_REKEY_CHILD_MOBIKE = CMD_CHILD_LOCAL_REQUEST_BASE + 4;
57 
58     /** Timeout commands. */
59     protected static final int CMD_TIMEOUT_BASE = CMD_SHARED_BASE + CMD_CATEGORY_SIZE;
60     /** Timeout when the remote side fails to send a Rekey-Delete request. */
61     @VisibleForTesting static final int TIMEOUT_REKEY_REMOTE_DELETE = CMD_TIMEOUT_BASE + 1;
62 
63     /** Commands for generic usages */
64     protected static final int CMD_GENERIC_BASE = CMD_SHARED_BASE + 2 * CMD_CATEGORY_SIZE;
65     /** Force state machine to a target state for testing purposes. */
66     @VisibleForTesting static final int CMD_FORCE_TRANSITION = CMD_GENERIC_BASE + 1;
67     /** Force close the session. */
68     @VisibleForTesting static final int CMD_KILL_SESSION = CMD_GENERIC_BASE + 2;
69 
70     /** Private commands for subclasses */
71     protected static final int CMD_PRIVATE_BASE = CMD_SHARED_BASE + 3 * CMD_CATEGORY_SIZE;
72 
73     protected static final SparseArray<String> SHARED_CMD_TO_STR;
74 
75     static {
76         SHARED_CMD_TO_STR = new SparseArray<>();
SHARED_CMD_TO_STR.put(CMD_LOCAL_REQUEST_CREATE_CHILD, "Create Child")77         SHARED_CMD_TO_STR.put(CMD_LOCAL_REQUEST_CREATE_CHILD, "Create Child");
SHARED_CMD_TO_STR.put(CMD_LOCAL_REQUEST_DELETE_CHILD, "Delete Child")78         SHARED_CMD_TO_STR.put(CMD_LOCAL_REQUEST_DELETE_CHILD, "Delete Child");
SHARED_CMD_TO_STR.put(CMD_LOCAL_REQUEST_REKEY_CHILD, "Rekey Child")79         SHARED_CMD_TO_STR.put(CMD_LOCAL_REQUEST_REKEY_CHILD, "Rekey Child");
SHARED_CMD_TO_STR.put(CMD_LOCAL_REQUEST_REKEY_CHILD_MOBIKE, "Rekey Child (MOBIKE)")80         SHARED_CMD_TO_STR.put(CMD_LOCAL_REQUEST_REKEY_CHILD_MOBIKE, "Rekey Child (MOBIKE)");
SHARED_CMD_TO_STR.put(CMD_KILL_SESSION, "Kill session")81         SHARED_CMD_TO_STR.put(CMD_KILL_SESSION, "Kill session");
SHARED_CMD_TO_STR.put(TIMEOUT_REKEY_REMOTE_DELETE, "Timout rekey remote delete")82         SHARED_CMD_TO_STR.put(TIMEOUT_REKEY_REMOTE_DELETE, "Timout rekey remote delete");
SHARED_CMD_TO_STR.put(CMD_FORCE_TRANSITION, "Force transition")83         SHARED_CMD_TO_STR.put(CMD_FORCE_TRANSITION, "Force transition");
84     }
85 
86     // Use a value greater than the retransmit-failure timeout.
87     static final long REKEY_DELETE_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(180L);
88 
89     // Default delay time for retrying a request
90     static final long RETRY_INTERVAL_MS = TimeUnit.SECONDS.toMillis(15L);
91 
92     protected final Executor mUserCbExecutor;
93     private final String mLogTag;
94 
95     protected volatile boolean mIsClosing = false;
96 
AbstractSessionStateMachine(String name, Looper looper, Executor userCbExecutor)97     protected AbstractSessionStateMachine(String name, Looper looper, Executor userCbExecutor) {
98         super(name, looper);
99         mLogTag = name;
100         mUserCbExecutor = userCbExecutor;
101     }
102 
103     /**
104      * Top level state for handling uncaught exceptions for all subclasses.
105      *
106      * <p>All other state in SessionStateMachine MUST extend this state.
107      *
108      * <p>Only errors this state should catch are unexpected internal failures. Since this may be
109      * run in critical processes, it must never take down the process if it fails
110      */
111     protected abstract class ExceptionHandlerBase extends State {
112         @Override
enter()113         public final void enter() {
114             try {
115                 enterState();
116             } catch (RuntimeException e) {
117                 cleanUpAndQuit(e);
118             }
119         }
120 
getCmdStr(int cmd)121         private String getCmdStr(int cmd) {
122             String cmdName = SHARED_CMD_TO_STR.get(cmd);
123             if (cmdName != null) {
124                 return cmdName;
125             }
126 
127             cmdName = getCmdString(cmd);
128             if (cmdName != null) {
129                 return cmdName;
130             }
131 
132             // Unrecognized message
133             return Integer.toString(cmd);
134         }
135 
136         @Override
processMessage(Message message)137         public final boolean processMessage(Message message) {
138             try {
139                 if (mIsClosing && message.what != CMD_KILL_SESSION) {
140                     logd(
141                             "Ignore "
142                                     + getCmdStr(message.what)
143                                     + " since this session is going to be closed");
144                     return HANDLED;
145                 } else {
146                     logd("processStateMessage: " + getCmdStr(message.what));
147                     return processStateMessage(message);
148                 }
149             } catch (RuntimeException e) {
150                 cleanUpAndQuit(e);
151                 return HANDLED;
152             }
153         }
154 
155         @Override
exit()156         public final void exit() {
157             try {
158                 exitState();
159             } catch (RuntimeException e) {
160                 cleanUpAndQuit(e);
161             }
162         }
163 
enterState()164         protected void enterState() {
165             // Do nothing. Subclasses MUST override it if they care.
166         }
167 
processStateMessage(Message message)168         protected boolean processStateMessage(Message message) {
169             return NOT_HANDLED;
170         }
171 
exitState()172         protected void exitState() {
173             // Do nothing. Subclasses MUST override it if they care.
174         }
175 
cleanUpAndQuit(RuntimeException e)176         protected abstract void cleanUpAndQuit(RuntimeException e);
177 
getCmdString(int cmd)178         protected abstract String getCmdString(int cmd);
179     }
180 
executeUserCallback(Runnable r)181     protected void executeUserCallback(Runnable r) {
182         try {
183             mUserCbExecutor.execute(r);
184         } catch (Exception e) {
185             logd("Callback execution failed", e);
186         }
187     }
188 
189     /** Forcibly close this session. */
killSession()190     public void killSession() {
191         log("killSession");
192 
193         mIsClosing = true;
194         sendMessage(CMD_KILL_SESSION);
195     }
196 
197     /**
198      * Quit SessionStateMachine immediately.
199      *
200      * <p>This method pushes SM_QUIT_CMD in front of the message queue and mark mIsClosing as true.
201      * All currently queued messages will be discarded.
202      *
203      * <p>Subclasses MUST call this method instead of quitNow()
204      */
205     // quitNow() is a public final method in the base class. Thus there is no good way to prevent
206     // caller from calling it within the current inheritance structure.
quitSessionNow()207     protected void quitSessionNow() {
208         mIsClosing = true;
209         quitNow();
210     }
211 
getCurrentStateName()212     protected String getCurrentStateName() {
213         final IState state = getCurrentState();
214         if (state != null) {
215             return state.getName();
216         }
217 
218         return "Null State";
219     }
220 
221     @Override
log(String s)222     protected void log(String s) {
223         getIkeLog().d(mLogTag, s);
224     }
225 
226     @Override
logd(String s)227     protected void logd(String s) {
228         getIkeLog().d(mLogTag, s);
229     }
230 
logd(String s, Throwable e)231     protected void logd(String s, Throwable e) {
232         getIkeLog().d(mLogTag, s, e);
233     }
234 
235     @Override
logv(String s)236     protected void logv(String s) {
237         getIkeLog().v(mLogTag, s);
238     }
239 
240     @Override
logi(String s)241     protected void logi(String s) {
242         getIkeLog().i(mLogTag, s);
243     }
244 
logi(String s, Throwable cause)245     protected void logi(String s, Throwable cause) {
246         getIkeLog().i(mLogTag, s, cause);
247     }
248 
249     @Override
logw(String s)250     protected void logw(String s) {
251         getIkeLog().w(mLogTag, s);
252     }
253 
254     @Override
loge(String s)255     protected void loge(String s) {
256         getIkeLog().e(mLogTag, s);
257     }
258 
259     @Override
loge(String s, Throwable e)260     protected void loge(String s, Throwable e) {
261         getIkeLog().e(mLogTag, s, e);
262     }
263 
logWtf(String s)264     protected void logWtf(String s) {
265         getIkeLog().wtf(mLogTag, s);
266     }
267 
logWtf(String s, Throwable e)268     protected void logWtf(String s, Throwable e) {
269         getIkeLog().wtf(mLogTag, s, e);
270     }
271 }
272