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