Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ActivityAttribute.MainActivity should set exported=true #6196

Closed
jonpryor opened this issue Aug 18, 2021 · 7 comments · Fixed by #6212
Closed

ActivityAttribute.MainActivity should set exported=true #6196

jonpryor opened this issue Aug 18, 2021 · 7 comments · Fixed by #6212
Assignees
Labels
Area: App+Library Build Issues when building Library projects or Application projects. needs-triage Issues that need to be assigned.

Comments

@jonpryor
Copy link
Member

Context: https://aster.cloud/2021/02/23/lets-be-explicit-about-our-intent-filters/

An important change is coming to Android 12 that improves both app and platform security. This change affects all apps that target Android 12.

Activities, services, and broadcast receivers with declared intent-filters now must explicitly declare whether they should be exported or not.

The short version is that many apps may need to update their [Activity] attribute usage to explicitly set ActivityAttribute.Exported.

However, we added ActivityAttribute.MainLauncher, which is also used in our templates:

https://github.com/xamarin/xamarin-android/blob/f7d32102cc3ada67aa12cc0beed2cf97226f41b3/src/Microsoft.Android.Templates/android/MainActivity.cs#L8

We should update our AndroidManifest.xml generation & related code so that when MainLauncher=true, we also automatically set exported=true.

@jonpryor jonpryor added Area: App+Library Build Issues when building Library projects or Application projects. needs-triage Issues that need to be assigned. labels Aug 18, 2021
jonathanpeppers added a commit to jonathanpeppers/xamarin-android that referenced this issue Aug 20, 2021
…ctivities

Context: https://aster.cloud/2021/02/23/lets-be-explicit-about-our-intent-filters/
Fixes: dotnet#6196

> An important change is coming to Android 12 that improves both app
> and platform security. This change affects all apps that target
> Android 12.
>
> Activities, services, and broadcast receivers with declared
> intent-filters now must explicitly declare whether they should be
> exported or not.

For example:

    <activity android:icon="@mipmap/icon" android:label="HelloWorld" android:name="example.MainActivity">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>

Should become:

    <activity android:icon="@mipmap/icon" android:label="HelloWorld" android:name="example.MainActivity">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" android:exported="true" />
        <category android:name="android.intent.category.LAUNCHER" android:exported="true" />
      </intent-filter>
    </activity>

Update our `AndroidManifest.xml` generation & related code so that
when `MainLauncher=true`, we also automatically set `exported=true`.

I updated a test to verify the contents of the generated
`AndroidManifest.xml`.
jonathanpeppers added a commit to jonathanpeppers/xamarin-android that referenced this issue Aug 20, 2021
…ctivities

Context: https://aster.cloud/2021/02/23/lets-be-explicit-about-our-intent-filters/
Fixes: dotnet#6196

> An important change is coming to Android 12 that improves both app
> and platform security. This change affects all apps that target
> Android 12.
>
> Activities, services, and broadcast receivers with declared
> intent-filters now must explicitly declare whether they should be
> exported or not.

For example:

    <activity android:icon="@mipmap/icon" android:label="HelloWorld" android:name="example.MainActivity">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>

Should become:

    <activity android:exported="true" android:icon="@mipmap/icon" android:label="HelloWorld" android:name="example.MainActivity">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>

Update our `AndroidManifest.xml` generation & related code so that
when `MainLauncher=true`, we also automatically set `exported=true`.

I updated a test to verify the contents of the generated
`AndroidManifest.xml`.
jonpryor pushed a commit that referenced this issue Aug 21, 2021
…6212)

Fixes: #6196

Context: https://aster.cloud/2021/02/23/lets-be-explicit-about-our-intent-filters/

> An important change is coming to Android 12 that improves both app
> and platform security. This change affects all apps that target
> Android 12.
>
> Activities, services, and broadcast receivers with declared
> intent-filters now must explicitly declare whether they should be
> exported or not.

For example:

	<activity android:icon="@mipmap/icon" android:label="HelloWorld" android:name="example.MainActivity">
	  <intent-filter>
	    <action android:name="android.intent.action.MAIN" />
	    <category android:name="android.intent.category.LAUNCHER" />
	  </intent-filter>
	</activity>

Should become:

	<activity android:exported="true" android:icon="@mipmap/icon" android:label="HelloWorld" android:name="example.MainActivity">
	  <intent-filter>
	    <action android:name="android.intent.action.MAIN" />
	    <category android:name="android.intent.category.LAUNCHER" />
	  </intent-filter>
	</activity>

Update our `AndroidManifest.xml` generation & related code so that
when `MainLauncher=true`, we also automatically set `exported=true`.

I updated a test to verify the contents of the generated
`AndroidManifest.xml`.
jonathanpeppers added a commit that referenced this issue Aug 24, 2021
…6212)

Fixes: #6196

Context: https://aster.cloud/2021/02/23/lets-be-explicit-about-our-intent-filters/

> An important change is coming to Android 12 that improves both app
> and platform security. This change affects all apps that target
> Android 12.
>
> Activities, services, and broadcast receivers with declared
> intent-filters now must explicitly declare whether they should be
> exported or not.

For example:

	<activity android:icon="@mipmap/icon" android:label="HelloWorld" android:name="example.MainActivity">
	  <intent-filter>
	    <action android:name="android.intent.action.MAIN" />
	    <category android:name="android.intent.category.LAUNCHER" />
	  </intent-filter>
	</activity>

Should become:

	<activity android:exported="true" android:icon="@mipmap/icon" android:label="HelloWorld" android:name="example.MainActivity">
	  <intent-filter>
	    <action android:name="android.intent.action.MAIN" />
	    <category android:name="android.intent.category.LAUNCHER" />
	  </intent-filter>
	</activity>

Update our `AndroidManifest.xml` generation & related code so that
when `MainLauncher=true`, we also automatically set `exported=true`.

I updated a test to verify the contents of the generated
`AndroidManifest.xml`.
jonpryor pushed a commit to jonpryor/xamarin-android that referenced this issue Aug 25, 2021
…otnet#6212)

Fixes: dotnet#6196

Context: https://aster.cloud/2021/02/23/lets-be-explicit-about-our-intent-filters/

> An important change is coming to Android 12 that improves both app
> and platform security. This change affects all apps that target
> Android 12.
>
> Activities, services, and broadcast receivers with declared
> intent-filters now must explicitly declare whether they should be
> exported or not.

For example:

	<activity android:icon="@mipmap/icon" android:label="HelloWorld" android:name="example.MainActivity">
	  <intent-filter>
	    <action android:name="android.intent.action.MAIN" />
	    <category android:name="android.intent.category.LAUNCHER" />
	  </intent-filter>
	</activity>

Should become:

	<activity android:exported="true" android:icon="@mipmap/icon" android:label="HelloWorld" android:name="example.MainActivity">
	  <intent-filter>
	    <action android:name="android.intent.action.MAIN" />
	    <category android:name="android.intent.category.LAUNCHER" />
	  </intent-filter>
	</activity>

Update our `AndroidManifest.xml` generation & related code so that
when `MainLauncher=true`, we also automatically set `exported=true`.

I updated a test to verify the contents of the generated
`AndroidManifest.xml`.
jonpryor pushed a commit that referenced this issue Aug 26, 2021
…6212)

Fixes: #6196

Context: https://aster.cloud/2021/02/23/lets-be-explicit-about-our-intent-filters/

> An important change is coming to Android 12 that improves both app
> and platform security. This change affects all apps that target
> Android 12.
>
> Activities, services, and broadcast receivers with declared
> intent-filters now must explicitly declare whether they should be
> exported or not.

For example:

	<activity android:icon="@mipmap/icon" android:label="HelloWorld" android:name="example.MainActivity">
	  <intent-filter>
	    <action android:name="android.intent.action.MAIN" />
	    <category android:name="android.intent.category.LAUNCHER" />
	  </intent-filter>
	</activity>

Should become:

	<activity android:exported="true" android:icon="@mipmap/icon" android:label="HelloWorld" android:name="example.MainActivity">
	  <intent-filter>
	    <action android:name="android.intent.action.MAIN" />
	    <category android:name="android.intent.category.LAUNCHER" />
	  </intent-filter>
	</activity>

Update our `AndroidManifest.xml` generation & related code so that
when `MainLauncher=true`, we also automatically set `exported=true`.

I updated a test to verify the contents of the generated
`AndroidManifest.xml`.
@marcelojaf
Copy link

Hi, I have a legacy app that is throwing this exception:
ADB0010: Mono.AndroidTools.InstallFailedException: Unexpected install output: Failure [INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: Failed parse during installPackageLI: /data/app/vmdl1622133712.tmp/base.apk (at Binary XML file line #37): crc64e33e66e9a625e726.PNFirebaseIIDService: Targeting S+ (version 31 and above) requires that an explicit value for android:exported be defined when intent filters are present]

Any tips on how to fix this? I can see the MainLauncher = true on my SplashActivity.cs file. I added Exported = true but wasn't enough.
My Xamarin.Forms version is 5.0.0.2291

@jonathanpeppers
Copy link
Member

The PNFirebaseIIDService probably needs Exported=true.

@marcelojaf if that doesn't fix it, can you file a new issue? Include the contents of obj/Debug/android/AndroidManifest.xml.

@marcelojaf
Copy link

Thank you very much for the answer.
I could not find anything in the Xamarin.Forms app searching for PNFirebaseIIDService, but I could find searching for Firebase and I see it on

MainActivity.cs:

[Activity(Label = "JJJJJJJ ", Icon = "@drawable/icon", MainLauncher = false, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : FormsApplicationActivity
    {
        internal static MainActivity Instance { get; private set; }

        protected override void OnCreate(Bundle bundle)
        {
            //RequestedOrientation = ScreenOrientation.Portrait;

            if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop)
            {
                // Kill status bar underlay added by FormsAppCompatActivity
                // Must be done before calling FormsAppCompatActivity.OnCreate()
                var statusBarHeightInfo =
                    typeof(FormsAppCompatActivity).GetField("statusBarHeight", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
                if (statusBarHeightInfo == null)
                {
                    statusBarHeightInfo =
                        typeof(FormsAppCompatActivity).GetField("_statusBarHeight", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
                }

                statusBarHeightInfo?.SetValue(this, 0);
            }

            base.OnCreate(bundle);

            Xamarin.Forms.Forms.Init(this, bundle);
            Instance = this;
            ZXing.Net.Mobile.Forms.Android.Platform.Init();
            UserDialogs.Init(this);
            Plugin.CurrentActivity.CrossCurrentActivity.Current.Init(this, bundle);
            Xamarin.Essentials.Platform.Init(this, bundle);
            Android.Glide.Forms.Init();

            LoadApplication(new App(false));

            // PUSH
            FirebaseCloudMessagingManager.ProcessIntent(this, Intent);

            if (App.Settings.LockCurrentScreenOrientation)
            {
                RequestedOrientation = ScreenOrientation.Locked;
            }
            else
            {
                RequestedOrientation = ScreenOrientation.Unspecified;
            }

            // Reset soft input mode to adjust with keyboard
            // Must be done after calling FormsAppCompatActivity.OnCreate()
            Window.SetSoftInputMode(SoftInput.AdjustResize);
            Window.DecorView.SystemUiVisibility = StatusBarVisibility.Visible;


        }
        protected override void OnNewIntent(Android.Content.Intent intent)
        {
            base.OnNewIntent(intent);
            FirebaseCloudMessagingManager.ProcessIntent(this, Intent);
        }

        public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
        {
            Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
            ZXing.Net.Mobile.Android.PermissionsHandler.OnRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

and

MainApplication.cs:

//You can specify additional application information in this attribute
[Application]
public class MainApplication : Application
{
	public MainApplication(IntPtr handle, JniHandleOwnership transer)
	  : base(handle, transer)
	{
	}

	public override void OnCreate()
	{
		base.OnCreate();
		CrossCurrentActivity.Current.Init(this);

		//Set the default notification channel for your app when running Android Oreo
		if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
		{
			//Change for your default notification channel id here
			FirebaseCloudMessagingManager.DefaultNotificationChannelId = "DefaultChannel";

			//Change for your default notification channel name here
			FirebaseCloudMessagingManager.DefaultNotificationChannelName = "General";
		}

		// for testing reset the token on each cycle
		// FirebaseCloudMessagingManager.Initialize(this, true);
		FirebaseCloudMessagingManager.Initialize(this, false);

		CrossFirebaseCloudMessaging.Current.OnNotificationReceived += (s, p) =>
		{
			System.Diagnostics.Debug.WriteLine("NOTIFICATION RECEIVED", p.Data);
		};

	}
}

Here's the obj/Debug/android/AndroidManifest.xml content.

<?xml version="1.0" encoding="utf-8"?>
<!--
    This code was generated by a tool.
    It was generated from C:\dev\JLOFT.xPlatform\JLOFT.Droid\Properties\AndroidManifest.xml
    Changes to this file may cause incorrect behavior and will be lost if
    the contents are regenerated.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.jinny.jloft.android" android:installLocation="auto" android:versionCode="20220121" android:versionName="0.9.0.38">
  <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="31" />
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.CAMERA" />
  <uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  <permission android:name="com.jinny.jloft.android.permission.C2D_MESSAGE" android:protectionLevel="signature" />
  <!-- used by connectivity plugin to get speeds -->
  <queries>
    <intent>
      <action android:name="android.media.browse.MediaBrowserService" />
    </intent>
  </queries>
  <uses-permission android:name="android.permission.WAKE_LOCK" />
  <!-- Required by older versions of Google Play services to create IID tokens -->
  <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
  <application android:name="crc646a42351b9329c90d.MainApplication" android:allowBackup="true" android:appComponentFactory="androidx.core.app.CoreComponentFactory" android:debuggable="true" android:extractNativeLibs="true" android:icon="@drawable/icon" android:label="JLOFT Mobile" android:theme="@style/MyTheme">
    <activity android:name="crc646a42351b9329c90d.MainActivity" android:configChanges="orientation|screenSize" android:exported="true" android:icon="@drawable/icon" android:label="JLOFT Mobile" />
    <activity android:name="crc646a42351b9329c90d.SplashActivity" android:configChanges="orientation|screenSize" android:exported="true" android:icon="@drawable/icon" android:label="JLOFT Mobile" android:theme="@style/SplashTheme">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
    <receiver android:name="crc64cea48322b3427ae9.ConnectivityChangeBroadcastReceiver" android:enabled="true" android:exported="false" android:label="Connectivity Plugin Broadcast Receiver" />
    <service android:name="crc64e33e66e9a625e726.PNFirebaseIIDService">
      <intent-filter>
        <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
      </intent-filter>
    </service>
    <service android:name="crc64e33e66e9a625e726.PNFirebaseMessagingService">
      <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
      </intent-filter>
    </service>
    <receiver android:name="crc64e33e66e9a625e726.CloudMessagingActionReceiver" />
    <receiver android:name="crc64e33e66e9a625e726.CloudMessagingDeletedReceiver" />
    <service android:name="crc64396a3fe5f8138e3f.KeepAliveService" />
    <receiver android:name="crc64a0e0a82d0db9a07d.BatteryBroadcastReceiver" android:enabled="true" android:exported="false" android:label="Essentials Battery Broadcast Receiver" />
    <receiver android:name="crc64a0e0a82d0db9a07d.EnergySaverBroadcastReceiver" android:enabled="true" android:exported="false" android:label="Essentials Energy Saver Broadcast Receiver" />
    <receiver android:name="crc64a0e0a82d0db9a07d.ConnectivityBroadcastReceiver" android:enabled="true" android:exported="false" android:label="Essentials Connectivity Broadcast Receiver" />
    <provider android:name="xamarin.essentials.fileProvider" android:authorities="com.jinny.jloft.android.fileProvider" android:exported="false" android:grantUriPermissions="true">
      <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/xamarin_essentials_fileprovider_file_paths" />
    </provider>
    <receiver android:name="crc643f46942d9dd1fff9.PowerSaveModeBroadcastReceiver" android:enabled="true" android:exported="false" />
    <activity android:name="crc6480997b3ef81bf9b2.ZxingActivity" android:configChanges="keyboardHidden|orientation|screenLayout" android:label="Scanner" />
    <provider android:name="mono.MonoRuntimeProvider" android:authorities="com.jinny.jloft.android.mono.MonoRuntimeProvider.__mono_init__" android:exported="false" android:initOrder="1999999999" />
    <provider android:name="com.google.firebase.provider.FirebaseInitProvider" android:authorities="com.jinny.jloft.android.firebaseinitprovider" android:exported="false" android:initOrder="100" />
    <service android:name="com.google.firebase.components.ComponentDiscoveryService" android:exported="false">
      <meta-data android:name="com.google.firebase.components:com.google.firebase.iid.Registrar" android:value="com.google.firebase.components.ComponentRegistrar" />
    </service>
    <receiver android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND">
      <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
      </intent-filter>
    </receiver>
    <!--
             FirebaseInstanceIdService performs security checks at runtime,
             no need for explicit permissions despite exported="true"
        -->
    <service android:name="com.google.firebase.iid.FirebaseInstanceIdService" android:exported="true">
      <intent-filter android:priority="-500">
        <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
      </intent-filter>
    </service>
    <!--
             FirebaseMessagingService performs security checks at runtime,
             no need for explicit permissions despite exported="true"
        -->
    <service android:name="com.google.firebase.messaging.FirebaseMessagingService" android:exported="true">
      <intent-filter android:priority="-500">
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
      </intent-filter>
    </service>
    <activity android:name="com.google.android.gms.common.api.GoogleApiActivity" android:exported="false" android:theme="@android:style/Theme.Translucent.NoTitleBar" />
    <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
  </application>
</manifest>

If I manually include the Exported=true it will work or this is an auto generated file? If not, can you see a solution with the info I posted?

Thank you again

@marcelojaf
Copy link

So, I saw the Microsoft docs for Firebase Cloud Messaging and see that the client is using a NuGet Packkage Plugin.FirebaseCloudMessaging which is not updated since March 2020 and is not on the Microsoft docs. I will fork and try to remove this plugin and use Xamarin.Firebase.Messaging as described on the documentation. I will post the result here in case other fellow developer face the same issue.

@nnovalbos
Copy link

Hi @marcelojaf ,
I have the same problem. Were you able to solve it?

'Exported = true' didn't solve my problem

Thanks

@marcelojaf
Copy link

marcelojaf commented Mar 2, 2022

I followed this guy tip

@nnovalbos
Copy link

Thanks a lot! it works now

@ghost ghost locked as resolved and limited conversation to collaborators Jun 2, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Area: App+Library Build Issues when building Library projects or Application projects. needs-triage Issues that need to be assigned.
Projects
None yet
5 participants