If you didn't find in your manifest the place where there is an activity without the tag "android: exported = false" then it's likely that it is in your dependencies... in order to pinpoint where exactly, first downgrade "compileSdkVersion" to 30 and "targetSdkVersion" to 30 so it builds.
android {
compileSdkVersion("android-S")
buildToolsVersion "30.0.3"
defaultConfig {
...
minSdkVersion 23
targetSdkVersion("S")
...
}
After that, in the main manifest.xml window there is a tab with "merged manifest". There you can inspect what activity exactly didn't have the "android: exported = false" attribute.
In my case it was because of third-party tools:
File build.gradle (: app):
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7'
//and
debugImplementation "com.github.markzhai:blockcanary-android:1.5.0"
releaseImplementation "com.github.markzhai:blockcanary-no-op:1.5.0"
Also, for services I had to add the attribute:
<service
android:name=".autofillservice.MyAutofillService"
android:exported="true"
android:permission="android.permission.BIND_AUTOFILL">
and
<service
android:name="com.demo.myApp.my_access.MyAccessService"
android:enabled="true"
android:exported="true"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
As my problem was in a third-party dependency and it's not going to be updated soon, I just added a <activity> declaration with the flag android:exported="true" and exported="false" where needed to override the initial declaration, also as I need this dependency in Debug only I added a new AndroidManifest.xml file in src/debug:
For leak_canary:
<?xml version="1.0" encoding="UTF-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<activity
android:name="leakcanary.internal.activity.LeakActivity"
android:exported="true"
android:icon="@mipmap/leak_canary_icon"
android:label="@string/leak_canary_display_activity_label"
android:taskAffinity="com.squareup.leakcanary.${applicationId}"
android:theme="@style/leak_canary_LeakCanary.Base">
<intent-filter android:label="@string/leak_canary_import_hprof_file">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file" />
<data android:scheme="content" />
<data android:mimeType="*/*" />
<data android:host="*" />
<data android:pathPattern=".*\\.hprof" />
<data android:pathPattern=".*\\..*\\.hprof" />
<data android:pathPattern=".*\\..*\\..*\\.hprof" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.hprof" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.hprof" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.hprof" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.hprof" />
</intent-filter>
</activity>
<activity
android:name="leakcanary.internal.RequestStoragePermissionActivity"
android:excludeFromRecents="true"
android:exported="false"
android:icon="@mipmap/leak_canary_icon"
android:label="@string/leak_canary_storage_permission_activity_label"
android:taskAffinity="com.squareup.leakcanary.${applicationId}"
android:theme="@style/leak_canary_Theme.Transparent" />
<receiver
android:name="leakcanary.internal.NotificationReceiver"
android:exported="false" />
</application>
</manifest>
You might as well just use the tools:node="merge" attribute and declare the android:exported=true|false as LeoFarage kindly suggested.