summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java31
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java7
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java8
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/util/IntegrationValidator.java224
4 files changed, 246 insertions, 24 deletions
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java b/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java
index a15969d58..5113a9eb5 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java
@@ -41,10 +41,12 @@ import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.hardware.usb.UsbManager;
import android.os.Build;
+import android.os.Debug;
import android.os.Looper;
import android.os.Parcelable;
import android.util.AndroidRuntimeException;
@@ -55,6 +57,7 @@ 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.IntegrationValidator;
import com.smartdevicelink.util.SdlAppInfo;
import com.smartdevicelink.util.ServiceFinder;
@@ -132,30 +135,10 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver{
if (localRouterClass == null){
localRouterClass = defineLocalSdlRouterClass();
// we need to check this again because for USB apps, the returned class can still be null
- if (localRouterClass != null) {
-
- // Check if the service declaration in AndroidManifest has the intent-filter action specified correctly
- boolean serviceFilterHasAction = false;
- String className = localRouterClass.getName();
- List<SdlAppInfo> services = AndroidTools.querySdlAppInfo(context, null);
- for (SdlAppInfo sdlAppInfo : services) {
- if(sdlAppInfo != null && sdlAppInfo.getRouterServiceComponentName() != null && className.equals((sdlAppInfo.getRouterServiceComponentName().getClassName()))){
- serviceFilterHasAction = true;
- break;
- }
- }
- if (!serviceFilterHasAction){
- DebugTool.logError(TAG, "WARNING: This application has not specified its intent-filter for the SdlRouterService. THIS WILL THROW AN EXCEPTION IN FUTURE RELEASES!!");
- }
-
- // Check if the service declaration in AndroidManifest has the router service version metadata specified correctly
- ResolveInfo info = context.getPackageManager().resolveService(new Intent(context, localRouterClass), PackageManager.GET_META_DATA);
- if (info != null) {
- if (info.serviceInfo.metaData == null || !info.serviceInfo.metaData.containsKey(context.getString(R.string.sdl_router_service_version_name))) {
- DebugTool.logError(TAG, "WARNING: This application has not specified its metadata tags for the SdlRouterService. THIS WILL THROW AN EXCEPTION IN FUTURE RELEASES!!");
- }
- } else {
- DebugTool.logError(TAG, "WARNING: This application has not specified its SdlRouterService correctly in the manifest. THIS WILL THROW AN EXCEPTION IN FUTURE RELEASES!!");
+ if (false && AndroidTools.isDebugMode(context)) {
+ IntegrationValidator.ValidationResult result = IntegrationValidator.validate(context, localRouterClass);
+ if(!result.isSuccessful()){
+ throw new RuntimeException(result.getResultText());
}
}
}
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java b/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java
index 24d5ec850..6a0d9ddc1 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java
@@ -95,6 +95,7 @@ import com.smartdevicelink.transport.utl.TransportRecord;
import com.smartdevicelink.util.AndroidTools;
import com.smartdevicelink.util.BitConverter;
import com.smartdevicelink.util.DebugTool;
+import com.smartdevicelink.util.IntegrationValidator;
import com.smartdevicelink.util.SdlAppInfo;
import org.json.JSONException;
@@ -1104,6 +1105,12 @@ public class SdlRouterService extends Service{
@Override
public void onCreate() {
super.onCreate();
+ if (AndroidTools.isDebugMode(getApplicationContext())) {
+ IntegrationValidator.ValidationResult result = IntegrationValidator.validate(getApplicationContext(), this.getClass());
+ if(!result.isSuccessful()) {
+ throw new RuntimeException(result.getResultText());
+ }
+ }
//Add this first to avoid the runtime exceptions for the entire lifecycle of the service
setRouterServiceExceptionHandler();
//This must be done regardless of if this service shuts down or not
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java b/android/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java
index bedc38028..0e75acd77 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java
@@ -36,6 +36,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -191,4 +192,11 @@ public class AndroidTools {
bis.close();
return result;
}
+
+ public static boolean isDebugMode(Context context){
+ if(context != null && context.getApplicationInfo() != null){
+ return 0 != ( context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE );
+ }
+ return false;
+ }
}
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/util/IntegrationValidator.java b/android/sdl_android/src/main/java/com/smartdevicelink/util/IntegrationValidator.java
new file mode 100644
index 000000000..77786a256
--- /dev/null
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/util/IntegrationValidator.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2020 Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.smartdevicelink.util;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Build;
+
+import com.smartdevicelink.R;
+import com.smartdevicelink.transport.TransportConstants;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class IntegrationValidator {
+
+ private static final String TAG = "IntegrationValidator";
+ private static final char CHECK_MARK = 0x2713;
+ private static final char FAIL_MARK = 0x2715;
+
+ public static ValidationResult validate(Context context, Class localRouterClass) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("\n-----------------------------------");
+ builder.append("\n Integration Validator Results: \n");
+ builder.append("-----------------------------------\n");
+ List<ValidationResult> results = new ArrayList<>();
+
+ results.add(checkPermissions(context));
+
+ if (localRouterClass != null) {
+ results.add(checkRoutServiceMetadata(context, localRouterClass));
+ results.add(checkRouterServiceIntent(context, localRouterClass));
+ }else{
+ results.add(new ValidationResult(false, "SdlRouterService is not defined in SdlBroadcastReceiver and therefore some checks were not completed"));
+ }
+
+ results.add( checkBroadcastReceiver(context) );
+
+ boolean success = true;
+ for(ValidationResult result : results) {
+ if(result.successful) {
+ builder.append(CHECK_MARK + " ");
+ } else {
+ success = false;
+ builder.append(FAIL_MARK + " ");
+ }
+ builder.append(result.resultText);
+ builder.append("\n\n");
+
+
+ }
+
+ if(!success) {
+ builder.append("Please see the guides for how to fix these issues at www.smartdevicelink.com");
+ }
+
+ return new ValidationResult(success, builder.toString());
+ }
+
+ private static ValidationResult checkPermissions(Context context) {
+ ValidationResult retVal = new ValidationResult(true,"Permission check passed");
+ List<String> permissionList = new ArrayList<>();
+ permissionList.add(Manifest.permission.BLUETOOTH);
+ permissionList.add(Manifest.permission.INTERNET);
+ permissionList.add(Manifest.permission.ACCESS_NETWORK_STATE);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ permissionList.add(Manifest.permission.FOREGROUND_SERVICE);
+ }
+ try {
+ PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getApplicationContext().getPackageName(), PackageManager.GET_PERMISSIONS);
+ String[] permissionInfos = packageInfo.requestedPermissions;
+
+ if (permissionInfos != null && permissionInfos.length > 0) {
+ String permissionInfo;
+ for (int i = 0; i < permissionInfos.length; i++) {
+ permissionInfo = permissionInfos[i];
+ permissionList.remove(permissionInfo);
+ }
+ }
+ } catch (Exception e) { }
+
+ if (!permissionList.isEmpty()) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("This application is missing permissions: \n");
+ for (String permission : permissionList) {
+ builder.append(" - ");
+ builder.append(permission);
+ builder.append("\n");
+ }
+ retVal.successful = false;
+ retVal.resultText = builder.toString();
+ }
+
+ return retVal;
+ }
+
+ public static ValidationResult checkBroadcastReceiver(Context context) {
+ ValidationResult retVal = new ValidationResult(true,"SdlBroadcastReceiver check passed");
+ try {
+ Intent intent = new Intent();
+ intent.setAction(TransportConstants.START_ROUTER_SERVICE_ACTION);
+ List<ResolveInfo> sdlReceivers = context.getPackageManager().queryBroadcastReceivers(intent, 0);
+ PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_RECEIVERS);
+ ActivityInfo[] receivers = packageInfo.receivers;
+
+ if (receivers != null && receivers.length > 0) {
+ ActivityInfo receiver;
+ for (int i = 0; i < receivers.length; i++) {
+
+ receiver = receivers[i];
+ if (receiver != null) {
+ int j = 0;
+ for (ResolveInfo sdlReceiver : sdlReceivers) {
+ if (receiver.name.equals(sdlReceiver.activityInfo.name)) {
+ return retVal;
+ }
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ retVal.successful = false;
+ retVal.resultText = "This application has not specified its SDL Receiver properly.";
+ return retVal;
+ }
+
+ // Check if the service declaration in AndroidManifest has the router service version metadata specified correctly
+ private static ValidationResult checkRoutServiceMetadata(Context context, Class localRouterClass) {
+ ValidationResult retVal = new ValidationResult(true,"SdlRouterService entry and metadata checks passed");
+
+ ResolveInfo info = context.getPackageManager().resolveService(new Intent(context, localRouterClass), PackageManager.GET_META_DATA);
+ if (info != null) {
+ if (info.serviceInfo.metaData == null || !info.serviceInfo.metaData.containsKey(context.getString(R.string.sdl_router_service_version_name))) {
+ retVal.successful = false;
+ retVal.resultText = "This application has not specified its metadata tags for the SdlRouterService.";
+ }
+ } else {
+ retVal.successful = false;
+ retVal.resultText = "This application has not specified its SdlRouterService correctly in the manifest.";
+ }
+ return retVal;
+ }
+
+ // Check if the service declaration in AndroidManifest has the intent-filter action specified correctly
+ private static ValidationResult checkRouterServiceIntent(Context context, Class localRouterClass) {
+ ValidationResult retVal = new ValidationResult(true,"SdlRouterService intent filter check passed");
+
+ boolean serviceFilterHasAction = false;
+ String className = localRouterClass.getName();
+ List<SdlAppInfo> services = AndroidTools.querySdlAppInfo(context, null);
+ for (SdlAppInfo sdlAppInfo : services) {
+ if (sdlAppInfo != null && sdlAppInfo.getRouterServiceComponentName() != null
+ && className.equals((sdlAppInfo.getRouterServiceComponentName().getClassName()))) {
+ serviceFilterHasAction = true;
+ break;
+ }
+ }
+ if (!serviceFilterHasAction) {
+ retVal.successful = false;
+ retVal.resultText = "This application has not specified its intent-filter for the SdlRouterService.";
+ }
+
+ return retVal;
+ }
+
+ /**
+ * Results from a validation check.
+ * Includes if the check was successful and a human readable string to describe the results.
+ */
+ public static final class ValidationResult {
+ boolean successful;
+ String resultText;
+
+ ValidationResult(boolean successful, String resultText) {
+ this.successful = successful;
+ this.resultText = resultText;
+ }
+
+ public boolean isSuccessful() {
+ return successful;
+ }
+
+ public String getResultText() {
+ return resultText;
+ }
+ }
+}