Split out DeathRecipient behavior
We can re-use this class to monitor client interface death as well from
the WifiStateMachine.
Bug: 30041062
Test: Can kill wificond underneath the framework with tethering on
and still see tethering taken down.
Test: unittests pass
Change-Id: I4dd60bd8eb674fc06d5eb301b0d8f10218126383
diff --git a/service/java/com/android/server/wifi/SoftApManager.java b/service/java/com/android/server/wifi/SoftApManager.java
index 46ef28f..99a6923 100644
--- a/service/java/com/android/server/wifi/SoftApManager.java
+++ b/service/java/com/android/server/wifi/SoftApManager.java
@@ -218,15 +218,8 @@
private final State mIdleState = new IdleState();
private final State mStartedState = new StartedState();
- private ApInterfaceDeathRecipient mDeathRecipient;
-
- private class ApInterfaceDeathRecipient implements DeathRecipient {
- @Override
- public void binderDied() {
- SoftApStateMachine.this.sendMessage(CMD_AP_INTERFACE_BINDER_DEATH);
- }
- }
-
+ private final StateMachineDeathRecipient mDeathRecipient =
+ new StateMachineDeathRecipient(this, CMD_AP_INTERFACE_BINDER_DEATH);
SoftApStateMachine(Looper looper) {
super(TAG, looper);
@@ -241,44 +234,34 @@
private class IdleState extends State {
@Override
public void enter() {
- if (mDeathRecipient != null) {
- mApInterface.asBinder().unlinkToDeath(mDeathRecipient, 0);
- mDeathRecipient = null;
- }
+ mDeathRecipient.unlinkToDeath();
}
@Override
public boolean processMessage(Message message) {
switch (message.what) {
case CMD_START:
- int result = SUCCESS;
updateApState(WifiManager.WIFI_AP_STATE_ENABLING, 0);
- mDeathRecipient = new ApInterfaceDeathRecipient();
- try {
- mApInterface.asBinder().linkToDeath(mDeathRecipient, 0);
- } catch (RemoteException e) {
- // The remote has already died.
- result = ERROR_GENERIC;
+ if (!mDeathRecipient.linkToDeath(mApInterface.asBinder())) {
+ mDeathRecipient.unlinkToDeath();
+ updateApState(WifiManager.WIFI_AP_STATE_FAILED,
+ WifiManager.SAP_START_FAILURE_GENERAL);
break;
}
- if (result == SUCCESS) {
- result = startSoftAp((WifiConfiguration) message.obj);
- }
- if (result == SUCCESS) {
- updateApState(WifiManager.WIFI_AP_STATE_ENABLED, 0);
- transitionTo(mStartedState);
- } else {
- int reason = WifiManager.SAP_START_FAILURE_GENERAL;
+ int result = startSoftAp((WifiConfiguration) message.obj);
+ if (result != SUCCESS) {
+ int failureReason = WifiManager.SAP_START_FAILURE_GENERAL;
if (result == ERROR_NO_CHANNEL) {
- reason = WifiManager.SAP_START_FAILURE_NO_CHANNEL;
+ failureReason = WifiManager.SAP_START_FAILURE_NO_CHANNEL;
}
- updateApState(WifiManager.WIFI_AP_STATE_FAILED, reason);
- if (mDeathRecipient != null) {
- mApInterface.asBinder().unlinkToDeath(mDeathRecipient, 0);
- mDeathRecipient = null;
- }
+ mDeathRecipient.unlinkToDeath();
+ updateApState(WifiManager.WIFI_AP_STATE_FAILED, failureReason);
+ break;
}
+
+ updateApState(WifiManager.WIFI_AP_STATE_ENABLED, 0);
+ transitionTo(mStartedState);
break;
default:
/* Ignore all other commands. */
diff --git a/service/java/com/android/server/wifi/StateMachineDeathRecipient.java b/service/java/com/android/server/wifi/StateMachineDeathRecipient.java
new file mode 100644
index 0000000..64c4bee
--- /dev/null
+++ b/service/java/com/android/server/wifi/StateMachineDeathRecipient.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi;
+
+import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
+import android.os.RemoteException;
+import com.android.internal.util.StateMachine;
+
+/**
+ * Allows StateMachine instances to subscribe to binder death.
+ *
+ * @hide
+ */
+public class StateMachineDeathRecipient implements DeathRecipient {
+
+ private final StateMachine mStateMachine;
+ private final int mDeathCommand;
+ private IBinder mLinkedBinder;
+
+ /**
+ * Construct a StateMachineDeathRecipient.
+ *
+ * @param sm StateMachine instance to receive a message upon Binder death.
+ * @param command message to send the state machine.
+ */
+ public StateMachineDeathRecipient(StateMachine sm, int command) {
+ mStateMachine = sm;
+ mDeathCommand = command;
+ }
+
+ /**
+ * Listen for the death of a binder.
+ *
+ * This method will unlink from death notifications from any
+ * previously linked IBinder instance.
+ *
+ * @param binder remote object to listen for death.
+ * @return true iff we have successfully subscribed to death notifications of a live
+ * IBinder instance.
+ */
+ public boolean linkToDeath(IBinder binder) {
+ unlinkToDeath();
+ try {
+ binder.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ // The remote has already died.
+ return false;
+ }
+ mLinkedBinder = binder;
+ return true;
+ }
+
+ /**
+ * Unlink from notifications from the last linked IBinder instance.
+ */
+ public void unlinkToDeath() {
+ if (mLinkedBinder == null) {
+ return;
+ }
+ mLinkedBinder.unlinkToDeath(this, 0);
+ mLinkedBinder = null;
+ }
+
+ /**
+ * Called by the binder subsystem upon remote object death.
+ */
+ @Override
+ public void binderDied() {
+ mStateMachine.sendMessage(mDeathCommand);
+ }
+}
\ No newline at end of file