explicitly declare foreground service type

This commit is contained in:
Daniel Gultsch 2023-10-17 08:19:31 +02:00
parent 7e5bf623ae
commit 418d6b09a0
No known key found for this signature in database
GPG key ID: F43D18AD2A0982C2
2 changed files with 88 additions and 19 deletions

View file

@ -3,8 +3,13 @@
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="32"
tools:ignore="ScopedStorage" />
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_PROFILE" /> <uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission <uses-permission
@ -40,6 +45,16 @@
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<!-- New permissions required to run as foreground service on Android 14.
SYSTEM_EXEMPTED is used when the app is on the doze allow list. This is normal
and the expected default behaviour. The other two hijack RECORD_AUDIO and CAMERA if they
happen to be granted. -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
<uses-feature <uses-feature
android:name="android.hardware.camera" android:name="android.hardware.camera"
android:required="false" /> android:required="false" />
@ -77,32 +92,40 @@
<application <application
android:allowBackup="true" android:allowBackup="true"
android:appCategory="social" android:appCategory="social"
android:fullBackupContent="@xml/backup_content"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_content"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:icon="@mipmap/new_launcher" android:icon="@mipmap/new_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:largeHeap="true" android:largeHeap="true"
android:localeConfig="@xml/locales_config"
android:networkSecurityConfig="@xml/network_security_configuration" android:networkSecurityConfig="@xml/network_security_configuration"
android:preserveLegacyExternalStorage="true" android:preserveLegacyExternalStorage="true"
android:requestLegacyExternalStorage="true" android:requestLegacyExternalStorage="true"
android:theme="@style/ConversationsTheme" android:theme="@style/ConversationsTheme"
tools:replace="android:label" tools:replace="android:label"
android:localeConfig="@xml/locales_config"
tools:targetApi="tiramisu"> tools:targetApi="tiramisu">
<meta-data <meta-data
android:name="com.google.android.gms.car.application" android:name="com.google.android.gms.car.application"
android:resource="@xml/automotive_app_desc" /> android:resource="@xml/automotive_app_desc" />
<service android:name=".services.XmppConnectionService" /> <service
android:name=".services.XmppConnectionService"
android:exported="false"
android:foregroundServiceType="specialUse|systemExempted|microphone|camera">
<property
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
android:value="im" />
</service>
<receiver <receiver
android:name=".services.EventReceiver" android:name=".services.EventReceiver"
android:exported="false"> android:exported="false">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" <action
android:name="android.net.conn.CONNECTIVITY_CHANGE"
tools:ignore="BatteryLife" /> tools:ignore="BatteryLife" />
<action android:name="android.intent.action.ACTION_SHUTDOWN" /> <action android:name="android.intent.action.ACTION_SHUTDOWN" />
<action android:name="android.media.RINGER_MODE_CHANGED" /> <action android:name="android.media.RINGER_MODE_CHANGED" />
@ -150,7 +173,6 @@
</activity> </activity>
<activity <activity
android:name=".ui.ConversationsActivity" android:name=".ui.ConversationsActivity"
android:label="@string/app_name"
android:launchMode="singleTask" android:launchMode="singleTask"
android:minWidth="300dp" android:minWidth="300dp"
android:minHeight="300dp" android:minHeight="300dp"
@ -162,8 +184,7 @@
android:windowSoftInputMode="stateAlwaysHidden" /> android:windowSoftInputMode="stateAlwaysHidden" />
<activity <activity
android:name=".ui.UriHandlerActivity" android:name=".ui.UriHandlerActivity"
android:exported="true" android:exported="true">
android:label="@string/app_name">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -265,7 +286,6 @@
<activity <activity
android:name=".ui.ShareWithActivity" android:name=".ui.ShareWithActivity"
android:exported="true" android:exported="true"
android:label="@string/app_name"
android:launchMode="singleTop"> android:launchMode="singleTop">
<intent-filter> <intent-filter>

View file

@ -19,6 +19,7 @@ import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.database.ContentObserver; import android.database.ContentObserver;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.media.AudioManager; import android.media.AudioManager;
@ -487,6 +488,7 @@ public class XmppConnectionService extends Service {
private WakeLock wakeLock; private WakeLock wakeLock;
private LruCache<String, Bitmap> mBitmapCache; private LruCache<String, Bitmap> mBitmapCache;
private final BroadcastReceiver mInternalEventReceiver = new InternalEventReceiver(); private final BroadcastReceiver mInternalEventReceiver = new InternalEventReceiver();
private final BroadcastReceiver mInternalRestrictedEventReceiver = new RestrictedEventReceiver(Arrays.asList(TorServiceUtils.ACTION_STATUS));
private final BroadcastReceiver mInternalScreenEventReceiver = new InternalEventReceiver(); private final BroadcastReceiver mInternalScreenEventReceiver = new InternalEventReceiver();
private static String generateFetchKey(Account account, final Avatar avatar) { private static String generateFetchKey(Account account, final Avatar avatar) {
@ -1236,16 +1238,26 @@ public class XmppConnectionService extends Service {
toggleForegroundService(); toggleForegroundService();
updateUnreadCountBadge(); updateUnreadCountBadge();
toggleScreenEventReceiver(); toggleScreenEventReceiver();
final IntentFilter intentFilter = new IntentFilter(); final IntentFilter systemBroadcastFilter = new IntentFilter();
intentFilter.addAction(TorServiceUtils.ACTION_STATUS);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
scheduleNextIdlePing(); scheduleNextIdlePing();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); systemBroadcastFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
} }
intentFilter.addAction(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED); systemBroadcastFilter.addAction(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
} }
registerReceiver(this.mInternalEventReceiver, intentFilter); ContextCompat.registerReceiver(
this,
this.mInternalEventReceiver,
systemBroadcastFilter,
ContextCompat.RECEIVER_NOT_EXPORTED);
final IntentFilter exportedBroadcastFilter = new IntentFilter();
exportedBroadcastFilter.addAction(TorServiceUtils.ACTION_STATUS);
ContextCompat.registerReceiver(
this,
this.mInternalRestrictedEventReceiver,
exportedBroadcastFilter,
ContextCompat.RECEIVER_EXPORTED);
mForceDuringOnCreate.set(false); mForceDuringOnCreate.set(false);
toggleForegroundService(); toggleForegroundService();
setupPhoneStateListener(); setupPhoneStateListener();
@ -1315,6 +1327,7 @@ public class XmppConnectionService extends Service {
public void onDestroy() { public void onDestroy() {
try { try {
unregisterReceiver(this.mInternalEventReceiver); unregisterReceiver(this.mInternalEventReceiver);
unregisterReceiver(this.mInternalRestrictedEventReceiver);
unregisterReceiver(this.mInternalScreenEventReceiver); unregisterReceiver(this.mInternalScreenEventReceiver);
} catch (final IllegalArgumentException e) { } catch (final IllegalArgumentException e) {
//ignored //ignored
@ -1396,8 +1409,25 @@ public class XmppConnectionService extends Service {
private void startForegroundOrCatch(final int id, final Notification notification) { private void startForegroundOrCatch(final int id, final Notification notification) {
try { try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
final int foregroundServiceType;
if (getSystemService(PowerManager.class)
.isIgnoringBatteryOptimizations(getPackageName())) {
foregroundServiceType = ServiceInfo.FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED;
} else if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
== PackageManager.PERMISSION_GRANTED) {
foregroundServiceType = ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE;
} else if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
== PackageManager.PERMISSION_GRANTED) {
foregroundServiceType = ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA;
} else {
foregroundServiceType = ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE;
}
startForeground(id, notification, foregroundServiceType);
} else {
startForeground(id, notification); startForeground(id, notification);
} catch (final IllegalStateException e) { }
} catch (final IllegalStateException | SecurityException e) {
Log.e(Config.LOGTAG, "Could not start foreground service", e); Log.e(Config.LOGTAG, "Could not start foreground service", e);
} }
} }
@ -5027,11 +5057,30 @@ public class XmppConnectionService extends Service {
private class InternalEventReceiver extends BroadcastReceiver { private class InternalEventReceiver extends BroadcastReceiver {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(final Context context, final Intent intent) {
onStartCommand(intent, 0, 0); onStartCommand(intent, 0, 0);
} }
} }
private class RestrictedEventReceiver extends BroadcastReceiver {
private final Collection<String> allowedActions;
private RestrictedEventReceiver(final Collection<String> allowedActions) {
this.allowedActions = allowedActions;
}
@Override
public void onReceive(final Context context, final Intent intent) {
final String action = intent == null ? null : intent.getAction();
if (allowedActions.contains(action)) {
onStartCommand(intent,0,0);
} else {
Log.e(Config.LOGTAG,"restricting broadcast of event "+action);
}
}
}
public static class OngoingCall { public static class OngoingCall {
public final AbstractJingleConnection.Id id; public final AbstractJingleConnection.Id id;
public final Set<Media> media; public final Set<Media> media;