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