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 String BOGUS_MARSHMALLOW_ADDR = "02:00:00:00:00:00";
private static final int MAX_PACKET_LEN = 4 * 1024; private static final int MAX_PACKET_LEN = 4 * 1024;
private static int CONNECT_SLEEP_MS = 2500; 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 { private enum BTCmd {
BAD_PROTO, BAD_PROTO,
@ -69,14 +72,14 @@ public class BTUtils {
SCAN, SCAN,
INVITE, INVITE,
INVITE_ACCPT, INVITE_ACCPT,
INVITE_DECL, // unused _INVITE_DECL, // unused
INVITE_DUPID, INVITE_DUPID,
INVITE_FAILED, // generic error _INVITE_FAILED, // generic error, and unused
MESG_SEND, MESG_SEND,
MESG_ACCPT, MESG_ACCPT,
MESG_DECL, // unused _MESG_DECL, // unused
MESG_GAMEGONE, MESG_GAMEGONE,
REMOVE_FOR, // unused _REMOVE_FOR, // unused
INVITE_DUP_INVITE, 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 ) static void init( Context context, String appName, UUID uuid )
{ {
Log.d( TAG, "init()" ); Log.d( TAG, "init()" );
@ -151,7 +166,7 @@ public class BTUtils {
public static boolean isBogusAddr( String addr ) public static boolean isBogusAddr( String addr )
{ {
boolean result = BOGUS_MARSHMALLOW_ADDR.equals( 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; return result;
} }
@ -177,7 +192,7 @@ public class BTUtils {
public static void setAmForeground() public static void setAmForeground()
{ {
sBackUser.set(false); sBackUser.set( false );
} }
private static String nameForAddr( BluetoothAdapter adapter, String btAddr ) private static String nameForAddr( BluetoothAdapter adapter, String btAddr )
@ -197,8 +212,7 @@ public class BTUtils {
int nSent = -1; int nSent = -1;
String name = targetAddr.bt_hostName; String name = targetAddr.bt_hostName;
if ( isActivePeer( name ) ) { if ( isActivePeer( name ) ) {
String btAddr = getSafeAddr(targetAddr); getPA( getSafeAddr(targetAddr) ).addMsg( gameID, buf, msgID );
getPA( btAddr ).addMsg( gameID, buf, msgID );
} else { } else {
Log.d( TAG, "sendPacket(): addressee %s unknown so dropping", name ); Log.d( TAG, "sendPacket(): addressee %s unknown so dropping", name );
} }
@ -221,7 +235,6 @@ public class BTUtils {
getPA( btAddr ).addInvite( nli ); getPA( btAddr ).addInvite( nli );
} }
private static Set<ScanListener> sListeners = new HashSet<>();
public static void addScanListener( ScanListener listener ) public static void addScanListener( ScanListener listener )
{ {
synchronized ( sListeners ) { synchronized ( sListeners ) {
@ -238,7 +251,6 @@ public class BTUtils {
private static void callListeners( BluetoothDevice dev ) private static void callListeners( BluetoothDevice dev )
{ {
Log.d( TAG, "callListeners(%s)", dev.getName() );
synchronized ( sListeners ) { synchronized ( sListeners ) {
for ( ScanListener listener : sListeners ) { for ( ScanListener listener : sListeners ) {
listener.onDeviceScanned( dev ); listener.onDeviceScanned( dev );
@ -248,7 +260,6 @@ public class BTUtils {
public static int scan( Context context, int timeoutMS ) public static int scan( Context context, int timeoutMS )
{ {
Log.e( TAG, "scan(): not implemented" );
Set<BluetoothDevice> devs = getCandidates(); Set<BluetoothDevice> devs = getCandidates();
int count = devs.size(); int count = devs.size();
if ( 0 < count ) { if ( 0 < count ) {
@ -257,18 +268,6 @@ public class BTUtils {
return count; 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 ) private static boolean isActivePeer( String devName )
{ {
boolean result = false; boolean result = false;
@ -280,10 +279,13 @@ public class BTUtils {
break; break;
} }
} }
Log.d( TAG, "isActivePeer(%s) => %b", devName, result ); if ( !result ) {
Log.d( TAG, "isActivePeer(%s) => FALSE", devName );
}
return result; return result;
} }
private static boolean sHaveLogged = false;
static Set<BluetoothDevice> getCandidates() static Set<BluetoothDevice> getCandidates()
{ {
Set<BluetoothDevice> result = new HashSet<>(); Set<BluetoothDevice> result = new HashSet<>();
@ -299,10 +301,15 @@ public class BTUtils {
case Major.PERIPHERAL: case Major.PERIPHERAL:
break; break;
default: default:
if ( ! sHaveLogged ) {
Log.d( TAG, "getCandidates(): adding %s of type %d",
dev.getName(), clazz );
}
result.add( dev ); result.add( dev );
break; break;
} }
} }
sHaveLogged = true;
} }
return result; return result;
} }
@ -325,7 +332,7 @@ public class BTUtils {
{ {
Assert.assertTrue( !TextUtils.isEmpty(addr) ); Assert.assertTrue( !TextUtils.isEmpty(addr) );
PacketAccumulator pa = getSenderFor( addr ).wake(); PacketAccumulator pa = getSenderFor( addr ).wake();
return pa; // .setService( this ); return pa;
} }
private static void removeSenderFor( PacketAccumulator 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 ) private static PacketAccumulator getSenderFor( String addr )
{ {
return getSenderFor( addr, true ); return getSenderFor( addr, true );
@ -361,8 +367,54 @@ public class BTUtils {
return result; 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 { private static class ScanThread extends Thread {
static ScanThread[] sInstance = {null}; private static Thread[] sInstance = {null};
private int mTimeoutMS; private int mTimeoutMS;
private Set<BluetoothDevice> mDevs; 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 ) private ScanThread( int timeoutMS, Set<BluetoothDevice> devs )
{ {
mTimeoutMS = timeoutMS; mTimeoutMS = timeoutMS;
@ -414,6 +452,8 @@ public class BTUtils {
pas.put( dev, pa ); pas.put( dev, pa );
} }
// PENDING: figure out how to let these send results the minute
// they have one!!!
for ( BluetoothDevice dev : pas.keySet() ) { for ( BluetoothDevice dev : pas.keySet() ) {
PacketAccumulator pa = pas.get( dev ); PacketAccumulator pa = pas.get( dev );
try { 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 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 { private static class MsgElem {
BTCmd mCmd; BTCmd mCmd;
String mMsgID; String mMsgID;
@ -545,16 +602,6 @@ public class BTUtils {
return this; return this;
} }
// synchronized PacketAccumulator setService( BTService service )
// {
// Assert.assertNotNull( service );
// mService = service;
// notifyAll();
// return this;
// }
PacketAccumulator setExitWhenEmpty() PacketAccumulator setExitWhenEmpty()
{ {
mExitWhenEmpty = true; 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; return result;
} }
@ -775,7 +822,7 @@ public class BTUtils {
updateStatusOut( false ); updateStatusOut( false );
} else { } else {
Log.d( TAG, "PacketAccumulator.run(): connect(%s) => %s", Log.d( TAG, "PacketAccumulator.run(): connect(%s) => %s",
getBTName(), dos ); mName, dos );
nDone += writeAndCheck( socket, dos ); nDone += writeAndCheck( socket, dos );
updateStatusOut( true ); updateStatusOut( true );
} }
@ -875,7 +922,7 @@ public class BTUtils {
updateStatusOut( true ); updateStatusOut( true );
} }
return nDone; return nDone;
} } // writeAndCheck()
private void handleReply( DataInputStream inStream, BTCmd cmd, int gameID, private void handleReply( DataInputStream inStream, BTCmd cmd, int gameID,
BTCmd reply ) throws IOException BTCmd reply ) throws IOException
@ -965,27 +1012,7 @@ public class BTUtils {
return dos; return dos;
} }
// private long figureWait() private void setNoHost()
// {
// 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()
{ {
try ( DeadlockWatch dw = new DeadlockWatch( this ) ) { try ( DeadlockWatch dw = new DeadlockWatch( this ) ) {
synchronized ( this ) { synchronized ( this ) {
@ -1021,53 +1048,10 @@ public class BTUtils {
return sb.append('}').toString(); return sb.append('}').toString();
} }
} } // class PacketAccumulator
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;
}
private static class ListenThread extends Thread { private static class ListenThread extends Thread {
private static ListenThread[] sInstance = {null}; private static Thread[] sInstance = {null};
private BluetoothAdapter mAdapter; private BluetoothAdapter mAdapter;
private ListenThread( BluetoothAdapter adapter ) private ListenThread( BluetoothAdapter adapter )
@ -1082,6 +1066,7 @@ public class BTUtils {
BluetoothServerSocket serverSocket; BluetoothServerSocket serverSocket;
try { try {
Assert.assertTrueNR( null != sAppName && null != sUUID );
serverSocket = mAdapter serverSocket = mAdapter
.listenUsingRfcommWithServiceRecord( sAppName, sUUID ); .listenUsingRfcommWithServiceRecord( sAppName, sUUID );
} catch ( IOException ioe ) { } catch ( IOException ioe ) {
@ -1101,14 +1086,14 @@ public class BTUtils {
try { try {
BluetoothSocket socket = serverSocket.accept(); // blocks BluetoothSocket socket = serverSocket.accept(); // blocks
Log.d( TAG, "%s.run(): accept() returned", this ); Log.d( TAG, "%s.run(): accept() returned", this );
ReadThread.read( socket ); ReadThread.handle( socket );
} catch ( IOException ioe ) { } catch ( IOException ioe ) {
Log.ex( TAG, ioe ); Log.ex( TAG, ioe );
break; serverSocket = null;
} }
} }
clearInstance( this ); clearInstance( sInstance, this );
Log.d( TAG, "ListenThread: %s.run() exiting", this ); Log.d( TAG, "ListenThread: %s.run() exiting", this );
} }
@ -1118,7 +1103,7 @@ public class BTUtils {
BluetoothAdapter adapter = getAdapterIf(); BluetoothAdapter adapter = getAdapterIf();
if ( null != adapter ) { if ( null != adapter ) {
synchronized (sInstance) { synchronized (sInstance) {
result = sInstance[0]; result = (ListenThread)sInstance[0];
if ( null == result ) { if ( null == result ) {
sInstance[0] = result = new ListenThread( adapter ); sInstance[0] = result = new ListenThread( adapter );
result.start(); result.start();
@ -1127,27 +1112,20 @@ public class BTUtils {
} }
return result; 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 class ReadThread extends Thread {
private static ReadThread[] sInstance = {null}; private static Thread[] sInstance = {null};
private LinkedBlockingQueue<BluetoothSocket> mQueue; private LinkedBlockingQueue<BluetoothSocket> mQueue;
private BTMsgSink mBTMsgSink; private BTMsgSink mBTMsgSink;
static void handle( BluetoothSocket incoming )
{
Log.d( TAG, "read(%s)", incoming );
ReadThread self = getOrStart();
self.enqueue( incoming );
}
private ReadThread() private ReadThread()
{ {
mQueue = new LinkedBlockingQueue<>(); mQueue = new LinkedBlockingQueue<>();
@ -1181,7 +1159,8 @@ public class BTUtils {
Log.ex( TAG, ioe ); Log.ex( TAG, ioe );
} }
} }
clearInstance( this );
clearInstance( sInstance, this );
Log.d( TAG, "ReadThread: %s.run() exiting", this ); Log.d( TAG, "ReadThread: %s.run() exiting", this );
} }
@ -1333,18 +1312,11 @@ public class BTUtils {
mQueue.add( socket ); mQueue.add( socket );
} }
static void read( BluetoothSocket incoming )
{
Log.d( TAG, "read(%s)", incoming );
ReadThread self = getOrStart();
self.enqueue( incoming );
}
private static ReadThread getOrStart() private static ReadThread getOrStart()
{ {
ReadThread result; ReadThread result;
synchronized (sInstance) { synchronized ( sInstance ) {
result = sInstance[0]; result = (ReadThread)sInstance[0];
if ( null == result ) { if ( null == result ) {
sInstance[0] = result = new ReadThread(); sInstance[0] = result = new ReadThread();
result.start(); result.start();
@ -1352,20 +1324,6 @@ public class BTUtils {
} }
return result; 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 { private static class BTMsgSink extends MultiMsgSink {

View file

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