cleanup bt code

This commit is contained in:
Eric House 2020-10-25 12:14:46 -07:00
parent 5a8ea0b998
commit f997c88ba4
2 changed files with 122 additions and 166 deletions

View file

@ -61,6 +61,9 @@ public class BTUtils {
private static final String BOGUS_MARSHMALLOW_ADDR = "02:00:00:00:00:00";
private static final int MAX_PACKET_LEN = 4 * 1024;
private static int CONNECT_SLEEP_MS = 2500;
private static Set<ScanListener> sListeners = new HashSet<>();
private static Map<String, PacketAccumulator> sSenders = new HashMap<>();
private static Map<String, String> s_namesToAddrs;
private enum BTCmd {
BAD_PROTO,
@ -69,14 +72,14 @@ public class BTUtils {
SCAN,
INVITE,
INVITE_ACCPT,
INVITE_DECL, // unused
_INVITE_DECL, // unused
INVITE_DUPID,
INVITE_FAILED, // generic error
_INVITE_FAILED, // generic error, and unused
MESG_SEND,
MESG_ACCPT,
MESG_DECL, // unused
_MESG_DECL, // unused
MESG_GAMEGONE,
REMOVE_FOR, // unused
_REMOVE_FOR, // unused
INVITE_DUP_INVITE,
};
@ -115,6 +118,18 @@ public class BTUtils {
}
}
static BluetoothAdapter getAdapterIf()
{
BluetoothAdapter result = null;
// Later this will change to include at least a test whether we're
// running as background user account, a situation in which BT crashes
// a lot inside the OS.
if ( !sBackUser.get() ) {
result = BluetoothAdapter.getDefaultAdapter();
}
return result;
}
static void init( Context context, String appName, UUID uuid )
{
Log.d( TAG, "init()" );
@ -151,7 +166,7 @@ public class BTUtils {
public static boolean isBogusAddr( String addr )
{
boolean result = BOGUS_MARSHMALLOW_ADDR.equals( addr );
Log.d( TAG, "isBogusAddr(%s) => %b", addr, result );
// Log.d( TAG, "isBogusAddr(%s) => %b", addr, result );
return result;
}
@ -177,7 +192,7 @@ public class BTUtils {
public static void setAmForeground()
{
sBackUser.set(false);
sBackUser.set( false );
}
private static String nameForAddr( BluetoothAdapter adapter, String btAddr )
@ -197,8 +212,7 @@ public class BTUtils {
int nSent = -1;
String name = targetAddr.bt_hostName;
if ( isActivePeer( name ) ) {
String btAddr = getSafeAddr(targetAddr);
getPA( btAddr ).addMsg( gameID, buf, msgID );
getPA( getSafeAddr(targetAddr) ).addMsg( gameID, buf, msgID );
} else {
Log.d( TAG, "sendPacket(): addressee %s unknown so dropping", name );
}
@ -221,7 +235,6 @@ public class BTUtils {
getPA( btAddr ).addInvite( nli );
}
private static Set<ScanListener> sListeners = new HashSet<>();
public static void addScanListener( ScanListener listener )
{
synchronized ( sListeners ) {
@ -238,7 +251,6 @@ public class BTUtils {
private static void callListeners( BluetoothDevice dev )
{
Log.d( TAG, "callListeners(%s)", dev.getName() );
synchronized ( sListeners ) {
for ( ScanListener listener : sListeners ) {
listener.onDeviceScanned( dev );
@ -248,7 +260,6 @@ public class BTUtils {
public static int scan( Context context, int timeoutMS )
{
Log.e( TAG, "scan(): not implemented" );
Set<BluetoothDevice> devs = getCandidates();
int count = devs.size();
if ( 0 < count ) {
@ -257,18 +268,6 @@ public class BTUtils {
return count;
}
static BluetoothAdapter getAdapterIf()
{
BluetoothAdapter result = null;
// Later this will change to include at least a test whether we're
// running as background user account, a situation in which BT crashes
// a lot inside the OS.
if ( !sBackUser.get() ) {
result = BluetoothAdapter.getDefaultAdapter();
}
return result;
}
private static boolean isActivePeer( String devName )
{
boolean result = false;
@ -280,10 +279,13 @@ public class BTUtils {
break;
}
}
Log.d( TAG, "isActivePeer(%s) => %b", devName, result );
if ( !result ) {
Log.d( TAG, "isActivePeer(%s) => FALSE", devName );
}
return result;
}
private static boolean sHaveLogged = false;
static Set<BluetoothDevice> getCandidates()
{
Set<BluetoothDevice> result = new HashSet<>();
@ -299,10 +301,15 @@ public class BTUtils {
case Major.PERIPHERAL:
break;
default:
if ( ! sHaveLogged ) {
Log.d( TAG, "getCandidates(): adding %s of type %d",
dev.getName(), clazz );
}
result.add( dev );
break;
}
}
sHaveLogged = true;
}
return result;
}
@ -325,7 +332,7 @@ public class BTUtils {
{
Assert.assertTrue( !TextUtils.isEmpty(addr) );
PacketAccumulator pa = getSenderFor( addr ).wake();
return pa; // .setService( this );
return pa;
}
private static void removeSenderFor( PacketAccumulator pa )
@ -341,7 +348,6 @@ public class BTUtils {
}
}
private static Map<String, PacketAccumulator> sSenders = new HashMap<>();
private static PacketAccumulator getSenderFor( String addr )
{
return getSenderFor( addr, true );
@ -361,8 +367,54 @@ public class BTUtils {
return result;
}
private static String getSafeAddr( CommsAddrRec addr )
{
String btAddr = addr.bt_btAddr;
if ( TextUtils.isEmpty(btAddr) || BOGUS_MARSHMALLOW_ADDR.equals( btAddr ) ) {
final String original = btAddr;
String btName = addr.bt_hostName;
if ( null == s_namesToAddrs ) {
s_namesToAddrs = new HashMap<>();
}
if ( s_namesToAddrs.containsKey( btName ) ) {
btAddr = s_namesToAddrs.get( btName );
} else {
btAddr = null;
}
if ( null == btAddr ) {
Set<BluetoothDevice> devs = getCandidates();
for ( BluetoothDevice dev : devs ) {
// Log.d( TAG, "%s => %s", dev.getName(), dev.getAddress() );
if ( btName.equals( dev.getName() ) ) {
btAddr = dev.getAddress();
s_namesToAddrs.put( btName, btAddr );
break;
}
}
}
Log.d( TAG, "getSafeAddr(\"%s\") => %s", original, btAddr );
}
return btAddr;
}
private static void clearInstance( Thread[] holder, Thread instance )
{
synchronized ( holder ) {
if ( holder[0] == null ) {
// nothing to do
} else if ( holder[0] == instance ) {
holder[0] = null;
} else {
Log.e( TAG, "clearInstance(): cur instance %s not == %s",
holder[0], instance );
}
}
}
private static class ScanThread extends Thread {
static ScanThread[] sInstance = {null};
private static Thread[] sInstance = {null};
private int mTimeoutMS;
private Set<BluetoothDevice> mDevs;
@ -377,20 +429,6 @@ public class BTUtils {
}
}
private static void clearInstance( ScanThread instance )
{
synchronized (sInstance) {
if ( sInstance[0] == null ) {
// nothing to do
} else if ( sInstance[0] == instance ) {
sInstance[0] = null;
} else {
Log.e( TAG, "ScanThread.clearInstance(): cur instance %s not == %s",
sInstance[0], instance );
}
}
}
private ScanThread( int timeoutMS, Set<BluetoothDevice> devs )
{
mTimeoutMS = timeoutMS;
@ -414,6 +452,8 @@ public class BTUtils {
pas.put( dev, pa );
}
// PENDING: figure out how to let these send results the minute
// they have one!!!
for ( BluetoothDevice dev : pas.keySet() ) {
PacketAccumulator pa = pas.get( dev );
try {
@ -426,12 +466,29 @@ public class BTUtils {
}
}
clearInstance( this );
synchronized ( sListeners ) {
for ( ScanListener listener : sListeners ) {
listener.onScanDone();
}
}
clearInstance( sInstance, this );
}
}
private static class PacketAccumulator extends Thread {
private static class OutputPair {
ByteArrayOutputStream bos;
DataOutputStream dos;
OutputPair() {
bos = new ByteArrayOutputStream();
dos = new DataOutputStream( bos );
}
int length() { return bos.toByteArray().length; }
}
private static class MsgElem {
BTCmd mCmd;
String mMsgID;
@ -545,16 +602,6 @@ public class BTUtils {
return this;
}
// synchronized PacketAccumulator setService( BTService service )
// {
// Assert.assertNotNull( service );
// mService = service;
// notifyAll();
// return this;
// }
PacketAccumulator setExitWhenEmpty()
{
mExitWhenEmpty = true;
@ -757,7 +804,7 @@ public class BTUtils {
}
}
}
Log.d( TAG, "%s.figureWait() => %dms", this, result );
// Log.d( TAG, "%s.figureWait() => %dms", this, result );
return result;
}
@ -775,7 +822,7 @@ public class BTUtils {
updateStatusOut( false );
} else {
Log.d( TAG, "PacketAccumulator.run(): connect(%s) => %s",
getBTName(), dos );
mName, dos );
nDone += writeAndCheck( socket, dos );
updateStatusOut( true );
}
@ -875,7 +922,7 @@ public class BTUtils {
updateStatusOut( true );
}
return nDone;
}
} // writeAndCheck()
private void handleReply( DataInputStream inStream, BTCmd cmd, int gameID,
BTCmd reply ) throws IOException
@ -965,27 +1012,7 @@ public class BTUtils {
return dos;
}
// private long figureWait()
// {
// long waitFromNow;
// try ( DeadlockWatch dw = new DeadlockWatch( this ) ) {
// synchronized ( this ) {
// if ( 0 == mElems.size() ) { // nothing to send
// waitFromNow = Long.MAX_VALUE;
// } else if ( 0 == mFailCount ) {
// waitFromNow = 0;
// } else {
// // If we're failing, use a backoff.
// long wait = 1000 * (long)Math.pow( mFailCount, 2 );
// waitFromNow = wait - (System.currentTimeMillis() - mLastFailTime);
// }
// }
// }
// Log.d( TAG, "%s.figureWait() => %dms", this, waitFromNow );
// return waitFromNow;
// }
void setNoHost()
private void setNoHost()
{
try ( DeadlockWatch dw = new DeadlockWatch( this ) ) {
synchronized ( this ) {
@ -1021,53 +1048,10 @@ public class BTUtils {
return sb.append('}').toString();
}
}
private static class OutputPair {
ByteArrayOutputStream bos;
DataOutputStream dos;
OutputPair() {
bos = new ByteArrayOutputStream();
dos = new DataOutputStream( bos );
}
int length() { return bos.toByteArray().length; }
}
private static Map<String, String> s_namesToAddrs;
private static String getSafeAddr( CommsAddrRec addr )
{
String btAddr = addr.bt_btAddr;
if ( TextUtils.isEmpty(btAddr) || BOGUS_MARSHMALLOW_ADDR.equals( btAddr ) ) {
final String original = btAddr;
String btName = addr.bt_hostName;
if ( null == s_namesToAddrs ) {
s_namesToAddrs = new HashMap<>();
}
if ( s_namesToAddrs.containsKey( btName ) ) {
btAddr = s_namesToAddrs.get( btName );
} else {
btAddr = null;
}
if ( null == btAddr ) {
Set<BluetoothDevice> devs = getCandidates();
for ( BluetoothDevice dev : devs ) {
// Log.d( TAG, "%s => %s", dev.getName(), dev.getAddress() );
if ( btName.equals( dev.getName() ) ) {
btAddr = dev.getAddress();
s_namesToAddrs.put( btName, btAddr );
break;
}
}
}
Log.d( TAG, "getSafeAddr(\"%s\") => %s", original, btAddr );
}
return btAddr;
}
} // class PacketAccumulator
private static class ListenThread extends Thread {
private static ListenThread[] sInstance = {null};
private static Thread[] sInstance = {null};
private BluetoothAdapter mAdapter;
private ListenThread( BluetoothAdapter adapter )
@ -1082,6 +1066,7 @@ public class BTUtils {
BluetoothServerSocket serverSocket;
try {
Assert.assertTrueNR( null != sAppName && null != sUUID );
serverSocket = mAdapter
.listenUsingRfcommWithServiceRecord( sAppName, sUUID );
} catch ( IOException ioe ) {
@ -1101,14 +1086,14 @@ public class BTUtils {
try {
BluetoothSocket socket = serverSocket.accept(); // blocks
Log.d( TAG, "%s.run(): accept() returned", this );
ReadThread.read( socket );
ReadThread.handle( socket );
} catch ( IOException ioe ) {
Log.ex( TAG, ioe );
break;
serverSocket = null;
}
}
clearInstance( this );
clearInstance( sInstance, this );
Log.d( TAG, "ListenThread: %s.run() exiting", this );
}
@ -1118,7 +1103,7 @@ public class BTUtils {
BluetoothAdapter adapter = getAdapterIf();
if ( null != adapter ) {
synchronized (sInstance) {
result = sInstance[0];
result = (ListenThread)sInstance[0];
if ( null == result ) {
sInstance[0] = result = new ListenThread( adapter );
result.start();
@ -1127,27 +1112,20 @@ public class BTUtils {
}
return result;
}
private static void clearInstance( ListenThread instance )
{
synchronized (sInstance) {
if ( sInstance[0] == null ) {
// nothing to do
} else if ( sInstance[0] == instance ) {
sInstance[0] = null;
} else {
Log.e( TAG, "clearInstance(): cur instance %s not == %s",
sInstance[0], instance );
}
}
}
}
private static class ReadThread extends Thread {
private static ReadThread[] sInstance = {null};
private static Thread[] sInstance = {null};
private LinkedBlockingQueue<BluetoothSocket> mQueue;
private BTMsgSink mBTMsgSink;
static void handle( BluetoothSocket incoming )
{
Log.d( TAG, "read(%s)", incoming );
ReadThread self = getOrStart();
self.enqueue( incoming );
}
private ReadThread()
{
mQueue = new LinkedBlockingQueue<>();
@ -1181,7 +1159,8 @@ public class BTUtils {
Log.ex( TAG, ioe );
}
}
clearInstance( this );
clearInstance( sInstance, this );
Log.d( TAG, "ReadThread: %s.run() exiting", this );
}
@ -1333,18 +1312,11 @@ public class BTUtils {
mQueue.add( socket );
}
static void read( BluetoothSocket incoming )
{
Log.d( TAG, "read(%s)", incoming );
ReadThread self = getOrStart();
self.enqueue( incoming );
}
private static ReadThread getOrStart()
{
ReadThread result;
synchronized (sInstance) {
result = sInstance[0];
synchronized ( sInstance ) {
result = (ReadThread)sInstance[0];
if ( null == result ) {
sInstance[0] = result = new ReadThread();
result.start();
@ -1352,20 +1324,6 @@ public class BTUtils {
}
return result;
}
private static void clearInstance( ReadThread instance )
{
synchronized (sInstance) {
if ( sInstance[0] == null ) {
// nothing to do
} else if ( sInstance[0] == instance ) {
sInstance[0] = null;
} else {
Log.e( TAG, "clearInstance(): cur instance %s not == %s",
sInstance[0], instance );
}
}
}
}
private static class BTMsgSink extends MultiMsgSink {

View file

@ -820,8 +820,6 @@ public class Utils {
if ( 0 < thisVersion ) {
prefs = context.getSharedPreferences( HIDDEN_PREFS,
Context.MODE_PRIVATE );
prevVersion = prefs.getInt( SHOWN_VERSION_KEY, -1 );
}
boolean newVersion = prevVersion != thisVersion;