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.State; 26 import com.android.internal.util.StateMachine; 27 28 import java.util.concurrent.Executor; 29 import java.util.concurrent.TimeUnit; 30 31 /** 32 * This class represents the common information of both IkeSessionStateMachine and 33 * ChildSessionStateMachine 34 */ 35 abstract class AbstractSessionStateMachine extends StateMachine { 36 private static final int CMD_SHARED_BASE = 0; 37 protected static final int CMD_CATEGORY_SIZE = 100; 38 39 /** 40 * Commands of Child local request that will be used in both IkeSessionStateMachine and 41 * ChildSessionStateMachine. 42 */ 43 protected static final int CMD_CHILD_LOCAL_REQUEST_BASE = CMD_SHARED_BASE; 44 45 @VisibleForTesting 46 static final int CMD_LOCAL_REQUEST_CREATE_CHILD = CMD_CHILD_LOCAL_REQUEST_BASE + 1; 47 48 @VisibleForTesting 49 static final int CMD_LOCAL_REQUEST_DELETE_CHILD = CMD_CHILD_LOCAL_REQUEST_BASE + 2; 50 51 @VisibleForTesting 52 static final int CMD_LOCAL_REQUEST_REKEY_CHILD = CMD_CHILD_LOCAL_REQUEST_BASE + 3; 53 54 @VisibleForTesting 55 static final int CMD_LOCAL_REQUEST_REKEY_CHILD_MOBIKE = CMD_CHILD_LOCAL_REQUEST_BASE + 4; 56 57 /** Timeout commands. */ 58 protected static final int CMD_TIMEOUT_BASE = CMD_SHARED_BASE + CMD_CATEGORY_SIZE; 59 /** Timeout when the remote side fails to send a Rekey-Delete request. */ 60 @VisibleForTesting static final int TIMEOUT_REKEY_REMOTE_DELETE = CMD_TIMEOUT_BASE + 1; 61 62 /** Commands for testing only */ 63 protected static final int CMD_TEST_BASE = CMD_SHARED_BASE + 2 * CMD_CATEGORY_SIZE; 64 /** Force state machine to a target state for testing purposes. */ 65 @VisibleForTesting static final int CMD_FORCE_TRANSITION = CMD_TEST_BASE + 1; 66 67 /** Private commands for subclasses */ 68 protected static final int CMD_PRIVATE_BASE = CMD_SHARED_BASE + 3 * CMD_CATEGORY_SIZE; 69 70 protected static final SparseArray<String> SHARED_CMD_TO_STR; 71 72 static { 73 SHARED_CMD_TO_STR = new SparseArray<>(); SHARED_CMD_TO_STR.put(CMD_LOCAL_REQUEST_CREATE_CHILD, "Create Child")74 SHARED_CMD_TO_STR.put(CMD_LOCAL_REQUEST_CREATE_CHILD, "Create Child"); SHARED_CMD_TO_STR.put(CMD_LOCAL_REQUEST_DELETE_CHILD, "Delete Child")75 SHARED_CMD_TO_STR.put(CMD_LOCAL_REQUEST_DELETE_CHILD, "Delete Child"); SHARED_CMD_TO_STR.put(CMD_LOCAL_REQUEST_REKEY_CHILD, "Rekey Child")76 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)")77 SHARED_CMD_TO_STR.put(CMD_LOCAL_REQUEST_REKEY_CHILD_MOBIKE, "Rekey Child (MOBIKE)"); SHARED_CMD_TO_STR.put(TIMEOUT_REKEY_REMOTE_DELETE, "Timout rekey remote delete")78 SHARED_CMD_TO_STR.put(TIMEOUT_REKEY_REMOTE_DELETE, "Timout rekey remote delete"); SHARED_CMD_TO_STR.put(CMD_FORCE_TRANSITION, "Force transition")79 SHARED_CMD_TO_STR.put(CMD_FORCE_TRANSITION, "Force transition"); 80 } 81 82 // Use a value greater than the retransmit-failure timeout. 83 static final long REKEY_DELETE_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(180L); 84 85 // Default delay time for retrying a request 86 static final long RETRY_INTERVAL_MS = TimeUnit.SECONDS.toMillis(15L); 87 88 protected final Executor mUserCbExecutor; 89 private final String mLogTag; 90 AbstractSessionStateMachine(String name, Looper looper, Executor userCbExecutor)91 protected AbstractSessionStateMachine(String name, Looper looper, Executor userCbExecutor) { 92 super(name, looper); 93 mLogTag = name; 94 mUserCbExecutor = userCbExecutor; 95 } 96 97 /** 98 * Top level state for handling uncaught exceptions for all subclasses. 99 * 100 * <p>All other state in SessionStateMachine MUST extend this state. 101 * 102 * <p>Only errors this state should catch are unexpected internal failures. Since this may be 103 * run in critical processes, it must never take down the process if it fails 104 */ 105 protected abstract class ExceptionHandlerBase extends State { 106 @Override enter()107 public final void enter() { 108 try { 109 enterState(); 110 } catch (RuntimeException e) { 111 cleanUpAndQuit(e); 112 } 113 } 114 115 @Override processMessage(Message message)116 public final boolean processMessage(Message message) { 117 try { 118 String cmdName = SHARED_CMD_TO_STR.get(message.what); 119 if (cmdName == null) { 120 cmdName = getCmdString(message.what); 121 } 122 123 // Unrecognized message will be logged by super class(Android StateMachine) 124 if (cmdName != null) logd("processStateMessage: " + cmdName); 125 126 return processStateMessage(message); 127 } catch (RuntimeException e) { 128 cleanUpAndQuit(e); 129 return HANDLED; 130 } 131 } 132 133 @Override exit()134 public final void exit() { 135 try { 136 exitState(); 137 } catch (RuntimeException e) { 138 cleanUpAndQuit(e); 139 } 140 } 141 enterState()142 protected void enterState() { 143 // Do nothing. Subclasses MUST override it if they care. 144 } 145 processStateMessage(Message message)146 protected boolean processStateMessage(Message message) { 147 return NOT_HANDLED; 148 } 149 exitState()150 protected void exitState() { 151 // Do nothing. Subclasses MUST override it if they care. 152 } 153 cleanUpAndQuit(RuntimeException e)154 protected abstract void cleanUpAndQuit(RuntimeException e); 155 getCmdString(int cmd)156 protected abstract String getCmdString(int cmd); 157 } 158 executeUserCallback(Runnable r)159 protected void executeUserCallback(Runnable r) { 160 try { 161 mUserCbExecutor.execute(r); 162 } catch (Exception e) { 163 logd("Callback execution failed", e); 164 } 165 } 166 167 @Override log(String s)168 protected void log(String s) { 169 getIkeLog().d(mLogTag, s); 170 } 171 172 @Override logd(String s)173 protected void logd(String s) { 174 getIkeLog().d(mLogTag, s); 175 } 176 logd(String s, Throwable e)177 protected void logd(String s, Throwable e) { 178 getIkeLog().d(mLogTag, s, e); 179 } 180 181 @Override logv(String s)182 protected void logv(String s) { 183 getIkeLog().v(mLogTag, s); 184 } 185 186 @Override logi(String s)187 protected void logi(String s) { 188 getIkeLog().i(mLogTag, s); 189 } 190 logi(String s, Throwable cause)191 protected void logi(String s, Throwable cause) { 192 getIkeLog().i(mLogTag, s, cause); 193 } 194 195 @Override logw(String s)196 protected void logw(String s) { 197 getIkeLog().w(mLogTag, s); 198 } 199 200 @Override loge(String s)201 protected void loge(String s) { 202 getIkeLog().e(mLogTag, s); 203 } 204 205 @Override loge(String s, Throwable e)206 protected void loge(String s, Throwable e) { 207 getIkeLog().e(mLogTag, s, e); 208 } 209 logWtf(String s)210 protected void logWtf(String s) { 211 getIkeLog().wtf(mLogTag, s); 212 } 213 logWtf(String s, Throwable e)214 protected void logWtf(String s, Throwable e) { 215 getIkeLog().wtf(mLogTag, s, e); 216 } 217 } 218