Fix issue #10378741: configupdater needs to be explicit when it calls startService()

Not enough time to fix everything, so instead we'll make it a warning
in this release and finish up turning it into a target-SDK based
exception in the next release.

Change-Id: I5aae64a1225a145f03ba4162238b53d5e401aba2
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 300424c..0ad0a99 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1453,29 +1453,39 @@
         }
     }
 
+    private void validateServiceIntent(Intent service) {
+        if (service.getComponent() == null && service.getPackage() == null) {
+            if (true || getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.KITKAT) {
+                Log.w(TAG, "Implicit intents with startService are not safe: " + service
+                        + " " + Debug.getCallers(2, 3));
+                //IllegalArgumentException ex = new IllegalArgumentException(
+                //        "Service Intent must be explicit: " + service);
+                //Log.e(TAG, "This will become an error", ex);
+                //throw ex;
+            }
+        }
+    }
+
     @Override
     public ComponentName startService(Intent service) {
         warnIfCallingFromSystemProcess();
-        return startServiceAsUser(service, mUser);
+        return startServiceCommon(service, mUser);
     }
 
     @Override
     public boolean stopService(Intent service) {
         warnIfCallingFromSystemProcess();
-        return stopServiceAsUser(service, mUser);
+        return stopServiceCommon(service, mUser);
     }
 
     @Override
     public ComponentName startServiceAsUser(Intent service, UserHandle user) {
+        return startServiceCommon(service, user);
+    }
+
+    private ComponentName startServiceCommon(Intent service, UserHandle user) {
         try {
-            if (service.getComponent() == null && service.getPackage() == null) {
-                if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.KITKAT) {
-                    IllegalArgumentException ex = new IllegalArgumentException(
-                            "Service Intent must be explicit: " + service);
-                    Log.e(TAG, "This will become an error", ex);
-                    //throw ex;
-                }
-            }
+            validateServiceIntent(service);
             service.prepareToLeaveProcess();
             ComponentName cn = ActivityManagerNative.getDefault().startService(
                 mMainThread.getApplicationThread(), service,
@@ -1499,15 +1509,12 @@
 
     @Override
     public boolean stopServiceAsUser(Intent service, UserHandle user) {
+        return stopServiceCommon(service, user);
+    }
+
+    private boolean stopServiceCommon(Intent service, UserHandle user) {
         try {
-            if (service.getComponent() == null && service.getPackage() == null) {
-                if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.KITKAT) {
-                    IllegalArgumentException ex = new IllegalArgumentException(
-                            "Service Intent must be explicit: " + service);
-                    Log.e(TAG, "This will become an error", ex);
-                    //throw ex;
-                }
-            }
+            validateServiceIntent(service);
             service.prepareToLeaveProcess();
             int res = ActivityManagerNative.getDefault().stopService(
                 mMainThread.getApplicationThread(), service,
@@ -1526,13 +1533,18 @@
     public boolean bindService(Intent service, ServiceConnection conn,
             int flags) {
         warnIfCallingFromSystemProcess();
-        return bindServiceAsUser(service, conn, flags, Process.myUserHandle());
+        return bindServiceCommon(service, conn, flags, Process.myUserHandle());
     }
 
     /** @hide */
     @Override
     public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
             UserHandle user) {
+        return bindServiceCommon(service, conn, flags, user);
+    }
+
+    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
+            UserHandle user) {
         IServiceConnection sd;
         if (conn == null) {
             throw new IllegalArgumentException("connection is null");
@@ -1543,14 +1555,7 @@
         } else {
             throw new RuntimeException("Not supported in system context");
         }
-        if (service.getComponent() == null && service.getPackage() == null) {
-            if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.KITKAT) {
-                IllegalArgumentException ex = new IllegalArgumentException(
-                        "Service Intent must be explicit: " + service);
-                Log.e(TAG, "This will become an error", ex);
-                //throw ex;
-            }
-        }
+        validateServiceIntent(service);
         try {
             IBinder token = getActivityToken();
             if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index ea9fd06..2e3b81d 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -1582,6 +1582,22 @@
     }
 
     /**
+     * Return a string consisting of methods and locations at multiple call stack levels.
+     * @param depth the number of levels to return, starting with the immediate caller.
+     * @return a string describing the call stack.
+     * {@hide}
+     */
+    public static String getCallers(final int start, int depth) {
+        final StackTraceElement[] callStack = Thread.currentThread().getStackTrace();
+        StringBuffer sb = new StringBuffer();
+        depth += start;
+        for (int i = start; i < depth; i++) {
+            sb.append(getCaller(callStack, i)).append(" ");
+        }
+        return sb.toString();
+    }
+
+    /**
      * Like {@link #getCallers(int)}, but each location is append to the string
      * as a new line with <var>linePrefix</var> in front of it.
      * @param depth the number of levels to return, starting with the immediate caller.