CTS test spoofed packageName can not bypass BG-FGS restrictions.

Add CTS test case ActivityManagerFgsBgStartTest.java#testSpoofPackageName
to verify framework can stop spoofed packageName from starting FGS
from the background.

Bug: 216695100
Bug: 215003903
Test: atest cts/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java#testSpoofPackageName
Change-Id: I579a3336f3cc9143775540b073558d25f6c08338
Merged-In: I579a3336f3cc9143775540b073558d25f6c08338
BYPASS_INCLUSIVE_LANGUAGE_REASON=legacy API
diff --git a/tests/app/app/src/android/app/stubs/CommandReceiver.java b/tests/app/app/src/android/app/stubs/CommandReceiver.java
index 9fcd4ef..224416d 100644
--- a/tests/app/app/src/android/app/stubs/CommandReceiver.java
+++ b/tests/app/app/src/android/app/stubs/CommandReceiver.java
@@ -17,6 +17,7 @@
 package android.app.stubs;
 
 import android.app.ActivityManager;
+import android.app.IActivityManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -24,8 +25,12 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.os.Binder;
+import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
 
@@ -51,6 +56,7 @@
     public static final int COMMAND_BIND_FOREGROUND_SERVICE = 14;
     public static final int COMMAND_START_FGSL_SERVICE = 15;
     public static final int COMMAND_STOP_FGSL_SERVICE = 16;
+    public static final int COMMAND_START_FOREGROUND_SERVICE_SPOOF_PACKAGE_NAME = 23;
 
     public static final String EXTRA_COMMAND = "android.app.stubs.extra.COMMAND";
     public static final String EXTRA_TARGET_PACKAGE = "android.app.stubs.extra.TARGET_PACKAGE";
@@ -132,6 +138,9 @@
             case COMMAND_STOP_FGSL_SERVICE:
                 doStopService(context, intent, FG_LOCATION_SERVICE_NAME);
                 break;
+            case COMMAND_START_FOREGROUND_SERVICE_SPOOF_PACKAGE_NAME:
+                doStartForegroundServiceSpoofPackageName(context, intent);
+                break;
         }
     }
 
@@ -248,6 +257,53 @@
         }
     }
 
+    /**
+     * Directly call IActivityManager.startService() using a spoofed packageName which is known to
+     * be allowlisted by Android framework to be able to start foreground service
+     * from the background. Framework will disallow the foreground service to start from the
+     * background.
+     * @param context
+     * @param commandIntent
+     */
+    private void doStartForegroundServiceSpoofPackageName(Context context, Intent commandIntent) {
+        String targetPackage = getTargetPackage(commandIntent);
+        Intent fgsIntent = new Intent();
+        fgsIntent.putExtras(commandIntent); // include the fg service type if any.
+        fgsIntent.setComponent(new ComponentName(targetPackage, FG_LOCATION_SERVICE_NAME));
+        int command = LocalForegroundService.COMMAND_START_FOREGROUND_WITH_TYPE;
+        fgsIntent.putExtras(LocalForegroundService.newCommand(new Binder(), command));
+        try {
+            final PackageManager pm = context.getPackageManager();
+            String spoofPackageName = pm.getAttentionServicePackageName();
+            if (TextUtils.isEmpty(spoofPackageName)) {
+                Log.d(TAG, "getAttentionServicePackageName() returns empty");
+                spoofPackageName = pm.getSystemCaptionsServicePackageName();
+            }
+            if (TextUtils.isEmpty(spoofPackageName)) {
+                Log.d(TAG, "getSystemCaptionsServicePackageName() returns empty");
+                spoofPackageName = "android";
+            }
+            Log.d(TAG, "spoofPackageName: " + spoofPackageName);
+            final IBinder activityProxy = android.os.ServiceManager.getService("activity");
+            // Call IActivityManager.startService() directly using a spoofed packageName.
+            IActivityManager.Stub.asInterface(activityProxy).startService(
+                    context.getIApplicationThread(),
+                    fgsIntent,
+                    null,
+                    true,
+                    spoofPackageName,
+                    null,
+                    android.os.Process.myUserHandle().getIdentifier()
+            );
+        } catch (LinkageError e) {
+            // IActivityManager.startService() is a hidden API, access hidden API could get
+            // LinkageError, consider the test as pass if we get LinkageError.
+            Log.d(TAG, "startForegroundService gets an LinkageError", e);
+        } catch (RemoteException e) {
+            Log.d(TAG, "startForegroundService gets an RemoteException", e);
+        }
+    }
+
     private String getTargetPackage(Intent intent) {
         return intent.getStringExtra(EXTRA_TARGET_PACKAGE);
     }
diff --git a/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java b/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java
index 502f282..711d0aa 100644
--- a/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java
@@ -40,6 +40,10 @@
 import android.platform.test.annotations.AsbSecurityTest;
 import android.provider.DeviceConfig;
 import android.test.InstrumentationTestCase;
+import android.provider.Settings;
+import android.server.wm.settings.SettingsSession;
+import android.support.test.uiautomator.UiDevice;
+import android.util.Log;
 
 import com.android.compatibility.common.util.SystemUtil;
 
@@ -583,6 +587,58 @@
         }
     }
 
+    /**
+     * IActivityManager.startService() is called directly (does not go through
+     * {@link Context#startForegroundService(Intent)}, a spoofed packageName "com.google.android.as"
+     * is used as callingPackage. Although "com.google.android.as" is allowlisted to start
+     * foreground service from the background, but framework will detect this is a spoofed
+     * packageName and disallow foreground service start from the background.
+     * @throws Exception
+     */
+    @Test
+    public void testSpoofPackageName() throws Exception {
+        ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
+                PACKAGE_NAME_APP1, 0);
+        WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
+                WAITFOR_MSEC);
+        // CommandReceiver.COMMAND_START_FOREGROUND_SERVICE_SPOOF_PACKAGE_NAME needs access
+        // to hidden API PackageManager.getAttentionServicePackageName() and
+        // PackageManager.getSystemCaptionsServicePackageName(), so we need to call
+        // hddenApiSettings.set("*") to exempt the hidden APIs.
+        SettingsSession<String> hiddenApiSettings = new SettingsSession<>(
+                Settings.Global.getUriFor(
+                        Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS),
+                Settings.Global::getString, Settings.Global::putString);
+        hiddenApiSettings.set("*");
+        try {
+            Bundle bundle = new Bundle();
+            bundle.putInt(LocalForegroundServiceLocation.EXTRA_FOREGROUND_SERVICE_TYPE,
+                    ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION);
+            // Package1 is in BG state, start FGSL in package1, it won't get location capability.
+            CommandReceiver.sendCommand(mContext,
+                    CommandReceiver.COMMAND_START_FOREGROUND_SERVICE_SPOOF_PACKAGE_NAME,
+                    PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, bundle);
+
+            // Package1 is in FGS state, but won't get location capability.
+            uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
+                    WatchUidRunner.STATE_FG_SERVICE,
+                    new Integer(PROCESS_CAPABILITY_NONE));
+
+            // stop FGSL
+            CommandReceiver.sendCommand(mContext,
+                    CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE_LOCATION,
+                    PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
+            uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
+                    WatchUidRunner.STATE_CACHED_EMPTY,
+                    new Integer(PROCESS_CAPABILITY_NONE));
+        } finally {
+            uid1Watcher.finish();
+            if (hiddenApiSettings != null) {
+                hiddenApiSettings.close();
+            }
+        }
+    }
+
     private void setFgsStartForegroundTimeout(int timeoutMs) throws Exception {
         runWithShellPermissionIdentity(() -> {
                     DeviceConfig.setProperty("activity_manager",