Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import com.smartdevicelink.protocol.SdlPacket;
import com.smartdevicelink.transport.enums.TransportType;
import com.smartdevicelink.transport.utl.TransportRecord;
import com.smartdevicelink.util.DebugTool;

import java.io.IOException;
import java.io.InputStream;
Expand Down Expand Up @@ -815,7 +816,9 @@ public void run() {
}
} catch (IOException|NullPointerException e) { // NPE is ONLY to catch error on mmInStream
Log.e(TAG, "Lost connection in the Connected Thread");
e.printStackTrace();
if(DebugTool.isDebugEnabled()){
e.printStackTrace();
}
connectionLost();
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import com.smartdevicelink.R;
import com.smartdevicelink.transport.RouterServiceValidator.TrustedListCallback;
import com.smartdevicelink.transport.enums.TransportType;
import com.smartdevicelink.transport.utl.SdlDeviceListener;
import com.smartdevicelink.util.AndroidTools;
import com.smartdevicelink.util.DebugTool;
import com.smartdevicelink.util.SdlAppInfo;
Expand Down Expand Up @@ -85,6 +86,8 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver{
private static final Object QUEUED_SERVICE_LOCK = new Object();
private static ComponentName queuedService = null;
private static Thread.UncaughtExceptionHandler foregroundExceptionHandler = null;
private static final Object DEVICE_LISTENER_LOCK = new Object();
private static SdlDeviceListener sdlDeviceListener;

public int getRouterServiceVersion(){
return SdlRouterService.ROUTER_SERVICE_VERSION_NUMBER;
Expand Down Expand Up @@ -190,9 +193,6 @@ public void onListObtained(boolean successful) {
});
}

}else{
//This was previously not hooked up, so let's leave it commented out
//onSdlDisabled(context);
}
return;
}else if(intent.getBooleanExtra(TransportConstants.PING_ROUTER_SERVICE_EXTRA, false)){
Expand Down Expand Up @@ -223,52 +223,101 @@ public void onListObtained(boolean successful) {
}
}

/**
* This method will attempt to start the router service.
* @param context to be used to start the service and send broadcasts
* @param componentName the router service that should be started
* @param altTransportWake if the alt transport flag should be set. Only used in debug
* @param device the connected bluetooth device
*/
private static void startRouterService(Context context, ComponentName componentName, boolean altTransportWake, BluetoothDevice device, boolean confirmedDevice) {
if (componentName == null) {
return;
}

Intent serviceIntent = new Intent();
serviceIntent.setComponent(componentName);

if (altTransportWake) {
serviceIntent.setAction(TransportConstants.BIND_REQUEST_TYPE_ALT_TRANSPORT);
}

if (device != null) {
serviceIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
}

if (confirmedDevice) {
serviceIntent.putExtra(TransportConstants.CONFIRMED_SDL_DEVICE, confirmedDevice);
}

try {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
context.startService(serviceIntent);
} else {
serviceIntent.putExtra(FOREGROUND_EXTRA, true);
DebugTool.logInfo("Attempting to startForegroundService - " + System.currentTimeMillis());
setForegroundExceptionHandler(); //Prevent ANR in case the OS takes too long to start the service
context.startForegroundService(serviceIntent);

}
//Make sure to send this out for old apps to close down
SdlRouterService.LocalRouterService self = SdlRouterService.getLocalRouterService(serviceIntent, serviceIntent.getComponent());
Intent restart = new Intent(SdlRouterService.REGISTER_NEWER_SERVER_INSTANCE_ACTION);
restart.putExtra(LOCAL_ROUTER_SERVICE_EXTRA, self);
restart.putExtra(LOCAL_ROUTER_SERVICE_DID_START_OWN, true);
context.sendBroadcast(restart);

} catch (SecurityException e) {
Log.e(TAG, "Security exception, process is bad");
}
}

private boolean wakeUpRouterService(final Context context, final boolean ping, final boolean altTransportWake, final BluetoothDevice device){
new ServiceFinder(context, context.getPackageName(), new ServiceFinder.ServiceFinderCallback() {
new ServiceFinder(context, context.getPackageName(), new ServiceFinder.ServiceFinderCallback() {
@Override
public void onComplete(Vector<ComponentName> routerServices) {
runningBluetoothServicePackage = new Vector<ComponentName>();
runningBluetoothServicePackage.addAll(routerServices);
if (runningBluetoothServicePackage.isEmpty()) {
//If there isn't a service running we should try to start one
//We will try to sort the SDL enabled apps and find the one that's been installed the longest
Intent serviceIntent;
List<SdlAppInfo> sdlAppInfoList = AndroidTools.querySdlAppInfo(context, new SdlAppInfo.BestRouterComparator());
final List<SdlAppInfo> sdlAppInfoList = AndroidTools.querySdlAppInfo(context, new SdlAppInfo.BestRouterComparator());
synchronized (DEVICE_LISTENER_LOCK) {
final boolean sdlDeviceListenerEnabled = SdlDeviceListener.isFeatureSupported(sdlAppInfoList);
if (sdlDeviceListenerEnabled) {
String myPackage = context.getPackageName();
String routerServicePackage = null;
if (sdlAppInfoList != null && !sdlAppInfoList.isEmpty() && sdlAppInfoList.get(0).getRouterServiceComponentName() != null) {
routerServicePackage = sdlAppInfoList.get(0).getRouterServiceComponentName().getPackageName();
}
DebugTool.logInfo(TAG + ": This app's package: " + myPackage);
DebugTool.logInfo(TAG + ": Router service app's package: " + routerServicePackage);
if (myPackage != null && myPackage.equalsIgnoreCase(routerServicePackage)) {
SdlDeviceListener sdlDeviceListener = getSdlDeviceListener(context, device);
if (!sdlDeviceListener.isRunning()) {
sdlDeviceListener.start();
}
} else {
DebugTool.logInfo(TAG + ": Not the app to start the router service nor device listener");
}
return;
}
}

if (sdlAppInfoList != null && !sdlAppInfoList.isEmpty()) {
serviceIntent = new Intent();
serviceIntent.setComponent(sdlAppInfoList.get(0).getRouterServiceComponentName());
startRouterService(context, sdlAppInfoList.get(0).getRouterServiceComponentName(), altTransportWake, device, false);
} else{
Log.d(TAG, "No SDL Router Services found");
Log.d(TAG, "WARNING: This application has not specified its SdlRouterService correctly in the manifest. THIS WILL THROW AN EXCEPTION IN FUTURE RELEASES!!");
return;
}
if (altTransportWake) {
serviceIntent.setAction(TransportConstants.BIND_REQUEST_TYPE_ALT_TRANSPORT);
}
if(device != null){
serviceIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
}
try {
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
context.startService(serviceIntent);
}else {
serviceIntent.putExtra(FOREGROUND_EXTRA, true);
DebugTool.logInfo("Attempting to startForegroundService - " + System.currentTimeMillis());
setForegroundExceptionHandler(); //Prevent ANR in case the OS takes too long to start the service
context.startForegroundService(serviceIntent);

} else { //There are currently running services
if(DebugTool.isDebugEnabled()){
for(ComponentName service : runningBluetoothServicePackage){
DebugTool.logInfo("Currently running router service: " + service.getPackageName());
}
//Make sure to send this out for old apps to close down
SdlRouterService.LocalRouterService self = SdlRouterService.getLocalRouterService(serviceIntent, serviceIntent.getComponent());
Intent restart = new Intent(SdlRouterService.REGISTER_NEWER_SERVER_INSTANCE_ACTION);
restart.putExtra(LOCAL_ROUTER_SERVICE_EXTRA, self);
restart.putExtra(LOCAL_ROUTER_SERVICE_DID_START_OWN, true);
context.sendBroadcast(restart);

} catch (SecurityException e) {
Log.e(TAG, "Security exception, process is bad");
}
} else {
if (altTransportWake) {
wakeRouterServiceAltTransport(context);
return;
Expand All @@ -281,15 +330,19 @@ public void onComplete(Vector<ComponentName> routerServices) {
}
}
});
return true;
return true;
}

private void wakeRouterServiceAltTransport(Context context){
Intent serviceIntent = new Intent();
serviceIntent.setAction(TransportConstants.BIND_REQUEST_TYPE_ALT_TRANSPORT);
for (ComponentName compName : runningBluetoothServicePackage) {
serviceIntent.setComponent(compName);
context.startService(serviceIntent);
try{
context.startService(serviceIntent);
} catch (Exception e){
DebugTool.logError("Can't start router service for alt transport");
}

}
}
Expand Down Expand Up @@ -329,10 +382,9 @@ public void uncaughtException(Thread t, Throwable e) {
* Determines if an instance of the Router Service is currently running on the device.<p>
* <b>Note:</b> This method no longer works on Android Oreo or newer
* @param context A context to access Android system services through.
* @param pingService Set this to true if you want to make sure the service is up and listening to bluetooth
* @return True if a SDL Router Service is currently running, false otherwise.
*/
private static boolean isRouterServiceRunning(Context context, boolean pingService){
private static boolean isRouterServiceRunning(Context context){
if(context == null){
Log.e(TAG, "Can't look for router service, context supplied was null");
return false;
Expand All @@ -356,17 +408,15 @@ private static boolean isRouterServiceRunning(Context context, boolean pingServi
//Log.d(TAG, "Found Service: "+ service.service.getClassName());
if ((service.service.getClassName()).toLowerCase(Locale.US).contains(SDL_ROUTER_SERVICE_CLASS_NAME) && AndroidTools.isServiceExported(context, service.service)) {
runningBluetoothServicePackage.add(service.service); //Store which instance is running
if (pingService) {
pingRouterService(context, service.service.getPackageName(), service.service.getClassName());
}
}
}
return runningBluetoothServicePackage.size() > 0;

}

/**
* Attempts to ping a running router service
* Attempts to ping a running router service. It does call startForegroundService so it is
* important to only call this as a ping if the service is already started.
* @param context A context to access Android system services through.
* @param packageName Package name for service to ping
* @param className Class name for service to ping
Expand Down Expand Up @@ -431,7 +481,7 @@ private static void requestTransportStatus(Context context, final SdlRouterStatu
}
return;
}
if((!lookForServices || isRouterServiceRunning(context,false)) && !runningBluetoothServicePackage.isEmpty()){ //So there is a service up, let's see if it's connected
if((!lookForServices || isRouterServiceRunning(context)) && !runningBluetoothServicePackage.isEmpty()){ //So there is a service up, let's see if it's connected
final ConcurrentLinkedQueue<ComponentName> list = new ConcurrentLinkedQueue<ComponentName>(runningBluetoothServicePackage);
final SdlRouterStatusProvider.ConnectedStatusCallback sdlBrCallback = new SdlRouterStatusProvider.ConnectedStatusCallback() {

Expand Down Expand Up @@ -471,12 +521,13 @@ public void onListObtained(boolean successful) {
}else{
Log.w(TAG, "Router service isn't running, returning false.");
if(isBluetoothConnected()){
Log.d(TAG, "Bluetooth is connected. Attempting to start Router Service");
Log.d(TAG, "Bluetooth is connected. Attempting to ping Router Service");
Intent serviceIntent = new Intent();
serviceIntent.setAction(TransportConstants.START_ROUTER_SERVICE_ACTION);
serviceIntent.putExtra(TransportConstants.PING_ROUTER_SERVICE_EXTRA, true);
AndroidTools.sendExplicitBroadcast(context,serviceIntent,null);
AndroidTools.sendExplicitBroadcast(context, serviceIntent,null);
}

if(callback!=null){
callback.onConnectionStatusUpdate(false, null,context);
}
Expand All @@ -500,6 +551,49 @@ private static boolean isBluetoothConnected() {
return false;
}


private static SdlDeviceListener getSdlDeviceListener(Context context, BluetoothDevice bluetoothDevice){

synchronized (DEVICE_LISTENER_LOCK){
if (sdlDeviceListener == null){
sdlDeviceListener = new SdlDeviceListener(context, bluetoothDevice, new SdlDeviceListener.Callback() {
@Override
public boolean onTransportConnected(Context context, BluetoothDevice bluetoothDevice) {

synchronized (DEVICE_LISTENER_LOCK){
sdlDeviceListener = null;
if(context != null) {
final List<SdlAppInfo> sdlAppInfoList = AndroidTools.querySdlAppInfo(context, new SdlAppInfo.BestRouterComparator());
if(sdlAppInfoList != null && !sdlAppInfoList.isEmpty()) {
ComponentName routerService = sdlAppInfoList.get(0).getRouterServiceComponentName();
startRouterService(context, routerService, false, bluetoothDevice, true);
}
}
}

return false;
}

@Override
public void onTransportDisconnected(BluetoothDevice bluetoothDevice) {
synchronized (DEVICE_LISTENER_LOCK){
sdlDeviceListener = null;
}
}

@Override
public void onTransportError(BluetoothDevice bluetoothDevice) {
synchronized (DEVICE_LISTENER_LOCK){
sdlDeviceListener = null;
}
}
});
}
}

return sdlDeviceListener;
}

public static ComponentName consumeQueuedRouterService(){
synchronized(QUEUED_SERVICE_LOCK){
ComponentName retVal = queuedService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ public class SdlRouterService extends Service{
/**
* <b> NOTE: DO NOT MODIFY THIS UNLESS YOU KNOW WHAT YOU'RE DOING.</b>
*/
protected static final int ROUTER_SERVICE_VERSION_NUMBER = 12;
protected static final int ROUTER_SERVICE_VERSION_NUMBER = 13;

private static final String ROUTER_SERVICE_PROCESS = "com.smartdevicelink.router";

Expand Down Expand Up @@ -1259,7 +1259,9 @@ public int onStartCommand(Intent intent, int flags, int startId) {
address = device.getAddress();
}
}
int timeout = getNotificationTimeout(address);
boolean confirmedDevice = intent.getBooleanExtra(TransportConstants.CONFIRMED_SDL_DEVICE, false);
int timeout = getNotificationTimeout(address, confirmedDevice);

enterForeground("Waiting for connection...", timeout, false);
resetForegroundTimeOut(timeout);
} else {
Expand Down Expand Up @@ -1383,9 +1385,9 @@ private void notifyAltTransportOfClose(int reason){
* @return the amount of time for a timeout handler to remove the notification.
*/
@SuppressLint("MissingPermission")
private int getNotificationTimeout(String address){
private int getNotificationTimeout(String address, boolean confirmedDevice){
if(address != null){
if(hasSDLConnected(address)){
if(confirmedDevice || hasSDLConnected(address)){
return FOREGROUND_TIMEOUT * 2;
}else if(this.isFirstStatusCheck(address)) {
// If this is the first time the service has ever connected to this device we want
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import com.smartdevicelink.protocol.SdlPacket;
import com.smartdevicelink.protocol.enums.ControlFrameTags;
import com.smartdevicelink.transport.enums.TransportType;
import com.smartdevicelink.transport.utl.SdlDeviceListener;
import com.smartdevicelink.transport.utl.TransportRecord;
import com.smartdevicelink.util.DebugTool;

Expand Down Expand Up @@ -100,7 +101,7 @@ public void onFinishedValidation(boolean valid, ComponentName name) {
if (valid) {
mConfig.service = name;
transport = new TransportBrokerImpl(contextWeakReference.get(), mConfig.appId, mConfig.service);
DebugTool.logInfo("TransportManager start got called; transport=" + transport);
DebugTool.logInfo("TransportManager start was called; transport = " + transport);
if(transport != null){
transport.start();
}
Expand Down Expand Up @@ -302,6 +303,16 @@ public synchronized boolean onHardwareConnected(List<TransportRecord> transports
transportStatus.clear();
transportStatus.addAll(transports);
}
//If a bluetooth device has connected, make sure to save the mac address in the case
//this app is asked to host the router service, the app knows to do so immediately on connection.
if(transports != null && transports.size() > 0) {
for (TransportRecord record : transports) {
if(record != null && TransportType.BLUETOOTH.equals(record.getType())) {
SdlDeviceListener.setSDLConnectedStatus(contextWeakReference.get(), record.getAddress(),true);
}
}
}

transportListener.onTransportConnected(transports);
return true;
}
Expand Down
Loading