blob: beeb72003d22207aedf591ad227f5fff1242c865 [file] [log] [blame]
/*
* Copyright (C) 2021 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 android.telephony.cts;
import android.app.Instrumentation;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.text.TextUtils;
import android.util.Log;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/** Connects Telephony Framework to MockModemService. */
class MockModemServiceConnector {
private static final String TAG = "MockModemServiceConnector";
private static final String DEFAULT_SERVICE_NAME = MockModemService.class.getClass().getName();
private static final String COMMAND_BASE = "cmd phone ";
private static final String COMMAND_SET_MODEM_SERVICE = "radio set-modem-service ";
private static final String COMMAND_GET_MODEM_SERVICE = "radio get-modem-service ";
private static final String COMMAND_SERVICE_IDENTIFIER = "-s ";
private static final String COMMAND_MODEM_SERVICE_UNKNOWN = "unknown";
private static final String COMMAND_MODEM_SERVICE_DEFAULT = "default";
private static final int BIND_LOCAL_MOCKMODEM_SERVICE_TIMEOUT_MS = 5000;
private static final int BIND_RADIO_INTERFACE_READY_TIMEOUT_MS = 5000;
private class MockModemServiceConnection implements ServiceConnection {
private final CountDownLatch mLatch;
MockModemServiceConnection(CountDownLatch latch) {
mLatch = latch;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
String serviceName;
mMockModemService = ((MockModemService.LocalBinder) service).getService();
serviceName = mMockModemService.getClass().getName();
if (!isDefaultMockModemService(serviceName)) {
updateModemServiceName(serviceName);
}
mLatch.countDown();
Log.d(TAG, "MockModemServiceConnection - " + serviceName + " onServiceConnected");
}
@Override
public void onServiceDisconnected(ComponentName name) {
mMockModemService = null;
Log.d(TAG, "MockModemServiceConnection - onServiceDisconnected");
}
}
private Instrumentation mInstrumentation;
private MockModemService mMockModemService;
private MockModemServiceConnection mMockModemServiceConn;
private boolean mIsServiceOverridden;
private String mModemServiceName;
MockModemServiceConnector(Instrumentation instrumentation) {
mInstrumentation = instrumentation;
}
private boolean setupLocalMockModemService() {
Log.d(TAG, "setupLocalMockModemService");
if (mMockModemService != null) {
return true;
}
CountDownLatch latch = new CountDownLatch(1);
if (mMockModemServiceConn == null) {
mMockModemServiceConn = new MockModemServiceConnection(latch);
}
mInstrumentation
.getContext()
.bindService(
new Intent(mInstrumentation.getContext(), MockModemService.class),
mMockModemServiceConn,
Context.BIND_AUTO_CREATE);
try {
return latch.await(BIND_LOCAL_MOCKMODEM_SERVICE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
return false;
}
}
private String constructSetModemServiceOverrideCommand() {
return COMMAND_BASE
+ COMMAND_SET_MODEM_SERVICE
+ COMMAND_SERVICE_IDENTIFIER
+ mModemServiceName;
}
private String constructGetModemServiceCommand() {
return COMMAND_BASE + COMMAND_GET_MODEM_SERVICE;
}
private String constructClearModemServiceOverrideCommand() {
return COMMAND_BASE + COMMAND_SET_MODEM_SERVICE;
}
private boolean setModemService() throws Exception {
String result =
TelephonyUtils.executeShellCommand(
mInstrumentation, constructSetModemServiceOverrideCommand());
Log.d(TAG, "setModemService result: " + result);
return "true".equals(result);
}
private String getModemService() throws Exception {
String result =
TelephonyUtils.executeShellCommand(
mInstrumentation, constructGetModemServiceCommand());
Log.d(TAG, "getModemService result: " + result);
return result;
}
private boolean clearModemServiceOverride() throws Exception {
String result =
TelephonyUtils.executeShellCommand(
mInstrumentation, constructClearModemServiceOverrideCommand());
Log.d(TAG, "clearModemServiceOverride result: " + result);
return "true".equals(result);
}
private boolean isServiceTheSame(String serviceA, String serviceB) {
if (TextUtils.isEmpty(serviceA) && TextUtils.isEmpty(serviceB)) {
return true;
}
return TextUtils.equals(serviceA, serviceB);
}
private void updateModemServiceName(String serviceName) {
mModemServiceName = serviceName;
}
private boolean overrideModemService() throws Exception {
boolean result = setModemService();
if (result) mIsServiceOverridden = true;
return result;
}
private boolean isDefaultMockModemService(String serviceName) {
return TextUtils.equals(DEFAULT_SERVICE_NAME, serviceName);
}
/**
* Bind to the local implementation of MockModemService.
*
* @return true if this request succeeded, false otherwise.
*/
boolean connectMockModemServiceLocally() {
if (!setupLocalMockModemService()) {
Log.w(TAG, "connectMockModemService: couldn't set up service.");
return false;
}
return true;
}
/**
* Trigger the telephony framework to bind to the local MockModemService implementation.
*
* @return true if this request succeeded, false otherwise.
*/
boolean switchFrameworkConnectionToMockModemService() throws Exception {
boolean isComplete = false;
if (overrideModemService()) {
isComplete =
mMockModemService.waitForLatchCountdown(
MockModemService.LATCH_RADIO_INTERFACES_READY,
BIND_RADIO_INTERFACE_READY_TIMEOUT_MS);
if (isComplete) {
isComplete = mMockModemService.initialize();
}
}
return isComplete;
}
boolean checkDefaultModemServiceConnected(String serviceName) throws Exception {
return isServiceTheSame(COMMAND_MODEM_SERVICE_DEFAULT, serviceName);
}
boolean checkModemServiceOverridden(String serviceName) throws Exception {
return isServiceTheSame(mModemServiceName, serviceName);
}
boolean connectMockModemService() throws Exception {
boolean result = false;
if (!connectMockModemServiceLocally()) return false;
result = checkModemServiceOverridden(getModemService());
if (result) mIsServiceOverridden = true;
else result = switchFrameworkConnectionToMockModemService();
return result;
}
boolean triggerFrameworkDisconnectionFromMockModemService() throws Exception {
boolean result = false;
if (!mIsServiceOverridden) {
Log.d(TAG, "Service didn't override.");
return true;
}
result = clearModemServiceOverride();
if (result) mIsServiceOverridden = false;
return result;
}
boolean disconnectMockModemService() throws Exception {
boolean isComplete;
isComplete = triggerFrameworkDisconnectionFromMockModemService();
if (isComplete) {
// waiting for binding to default modem service
TimeUnit.SECONDS.sleep(5);
String serviceName = getModemService();
isComplete =
(!checkModemServiceOverridden(serviceName)
&& checkDefaultModemServiceConnected(serviceName));
}
// Remove local connection
Log.d(TAG, "disconnectMockModemService");
if (mMockModemServiceConn != null) {
mInstrumentation.getContext().unbindService(mMockModemServiceConn);
mMockModemService = null;
}
return isComplete;
}
MockModemService getMockModemService() {
return mMockModemService;
}
}