androidandroid-intent

Android 15 confusing new 'Safer Intents' security policy


Android 15 is introducing new policy on Intents safety: https://developer.android.com/about/versions/15/behavior-changes-15#safer-intents

I have a problem understanding what really changes and how to address those changes since there are no examples or any further reference. I'm specifically talking about this point:

Match target intent-filters: Intents that target specific components must accurately match the target's intent-filter specifications. If you send an intent to launch another app's activity, the target intent component needs to align with the receiving activity's declared intent-filters.

This sounds like you are going to have to kind of mix explicit intents with implicit intents.

If an app component is declared in AndroidManifest like this:

<activity android:name="ShareActivity" android:exported="false">
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <data android:mimeType="text/plain"/>
    </intent-filter>
</activity>

then calling it with an intent like this:

Intent(context, ShareActivity::class.java).apply {
    setData(...)
}

won't suffice and an intent like this would be required:

Intent(context, ShareActivity::class.java).apply {
    setAction(Intent.ACTION_SEND)
    setData(...)
}

This rule would be extrapolated on other intent-filter's aspects listed in the Intent resolution documentation, so that if a component declares all of action, data and category in its intent-filter it all will be required even when targeting that component explicitly.

I am not sure if I understand that requirement right and need clarification or confirmation.


Solution

  • I did some testing on this feature and found the following rules:

    Rule 1: The change must be applied if the component (Activity, Service, or Broadcast) has been declared as exported = true in AndroidManifest.xml (always avoid using that attribute as true) and you are calling it from an external activity.

    <activity
        android:name=".PublicActivity"
        android:exported="true">
        <intent-filter>
            <action android:name="com.example.app.PUBLIC_ACTION"/>
            <category android:name="android.intent.category.DEFAULT"/>
        </intent-filter>
    </activity>
    

    Called from an external component:

    Intent intent = new Intent("com.example.app.PUBLIC_ACTION");
    intent.setClassName("com.example.app", "com.example.app.PublicActivity");
    startActivity(intent)
    

    Rule 2: If the component has been declared as exported = false, then the adjustment is not required.

    <activity
        android:name=".PrivateActivity"
        android:exported="false">
        <intent-filter>
            <action android:name="com.example.app.PRIVATE_ACTION"/>
            <category android:name="android.intent.category.DEFAULT"/>
        </intent-filter>
    </activity>
    

    You can called as:

    Intent intent = new Intent(this, PrivateActivity.class);
    startActivity(intent);
    

    Rule 3: Apps running on Android 15 must verify these changes since even if they are compiled with previous versions (Android 14, 13, etc), it will be necessary to adjust devices with Android 15.