Add null check for Context and ContextWrapper base
- Besides null Context, non-null ContextWrapper can be problematic when its base
is not set.
- Add assertion so that such mistake from client side can be detected quickly.
Bug: 144931251
Test: boot up and check crash
Change-Id: Ib8d92f67e644929c77554cbb7679b2fc0f7509ab
diff --git a/car-lib/src/android/car/Car.java b/car-lib/src/android/car/Car.java
index 4ca47f8..85afce4 100644
--- a/car-lib/src/android/car/Car.java
+++ b/car-lib/src/android/car/Car.java
@@ -49,6 +49,7 @@
import android.car.vms.VmsSubscriberManager;
import android.content.ComponentName;
import android.content.Context;
+import android.content.ContextWrapper;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
@@ -773,7 +774,9 @@
/**
* A factory method that creates Car instance for all Car API access.
- * @param context
+ * @param context App's Context. This should not be null. If you are passing
+ * {@link ContextWrapper}, make sure that its base Context is non-null as well.
+ * Otherwise it will throw {@link java.lang.NullPointerException}.
* @param serviceConnectionListener listener for monitoring service connection.
* @param handler the handler on which the callback should execute, or null to execute on the
* service's main thread. Note: the service connection listener will be always on the main
@@ -785,6 +788,7 @@
@Deprecated
public static Car createCar(Context context, ServiceConnection serviceConnectionListener,
@Nullable Handler handler) {
+ assertNonNullContext(context);
if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
Log.e(TAG_CAR, "FEATURE_AUTOMOTIVE not declared while android.car is used");
return null;
@@ -826,7 +830,9 @@
/**
* Creates new {@link Car} object which connected synchronously to Car Service and ready to use.
*
- * @param context application's context
+ * @param context App's Context. This should not be null. If you are passing
+ * {@link ContextWrapper}, make sure that its base Context is non-null as well.
+ * Otherwise it will throw {@link java.lang.NullPointerException}.
* @param handler the handler on which the manager's callbacks will be executed, or null to
* execute on the application's main thread.
*
@@ -834,6 +840,7 @@
*/
@Nullable
public static Car createCar(Context context, @Nullable Handler handler) {
+ assertNonNullContext(context);
Car car = null;
IBinder service = null;
boolean started = false;
@@ -911,6 +918,9 @@
* {@link CarServiceLifecycleListener#onLifecycleChanged(Car, boolean)} and avoid the
* needs to check if returned {@link Car} is connected or not from returned {@link Car}.</p>
*
+ * @param context App's Context. This should not be null. If you are passing
+ * {@link ContextWrapper}, make sure that its base Context is non-null as well.
+ * Otherwise it will throw {@link java.lang.NullPointerException}.
* @param handler dispatches all Car*Manager events to this Handler. Exception is
* {@link CarServiceLifecycleListener} which will be always dispatched to main
* thread. Passing null leads into dispatching all Car*Manager callbacks to main
@@ -927,7 +937,7 @@
public static Car createCar(@NonNull Context context,
@Nullable Handler handler, long waitTimeoutMs,
@NonNull CarServiceLifecycleListener statusChangeListener) {
- Preconditions.checkNotNull(context);
+ assertNonNullContext(context);
Preconditions.checkNotNull(statusChangeListener);
Car car = null;
IBinder service = null;
@@ -1008,6 +1018,15 @@
return car;
}
+ private static void assertNonNullContext(Context context) {
+ Preconditions.checkNotNull(context);
+ if (context instanceof ContextWrapper
+ && ((ContextWrapper) context).getBaseContext() == null) {
+ throw new NullPointerException(
+ "ContextWrapper with null base passed as Context, forgot to set base Context?");
+ }
+ }
+
private void dispatchCarReadyToMainThread(boolean isMainThread) {
if (isMainThread) {
mStatusChangeCallback.onLifecycleChanged(this, true);