Files
Daniel Elliott c080f0d97f Add Discord community version (64-bit only)
- Added realracing3-community.apk (71.57 MB)
- Removed 32-bit support (armeabi-v7a)
- Only includes arm64-v8a libraries
- Decompiled source code included
- Added README-community.md with analysis
2026-02-18 15:48:36 -08:00

270 lines
13 KiB
Java

package androidx.work.impl.utils;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.ApplicationExitInfo;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.database.sqlite.SQLiteAccessPermException;
import android.database.sqlite.SQLiteCantOpenDatabaseException;
import android.database.sqlite.SQLiteConstraintException;
import android.database.sqlite.SQLiteDatabaseCorruptException;
import android.database.sqlite.SQLiteDatabaseLockedException;
import android.database.sqlite.SQLiteDiskIOException;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteFullException;
import android.database.sqlite.SQLiteTableLockedException;
import android.os.Build;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.VisibleForTesting;
import androidx.core.app.NotificationCompat;
import androidx.core.os.UserManagerCompat;
import androidx.core.util.Consumer;
import androidx.work.Configuration;
import androidx.work.Logger;
import androidx.work.WorkInfo;
import androidx.work.impl.Schedulers;
import androidx.work.impl.WorkDatabase;
import androidx.work.impl.WorkDatabasePathHelper;
import androidx.work.impl.WorkManagerImpl;
import androidx.work.impl.background.systemjob.SystemJobScheduler;
import androidx.work.impl.model.WorkProgressDao;
import androidx.work.impl.model.WorkSpec;
import androidx.work.impl.model.WorkSpecDao;
import com.google.android.gms.drive.DriveFile;
import java.util.List;
import java.util.concurrent.TimeUnit;
@RestrictTo({RestrictTo.Scope.LIBRARY_GROUP})
/* loaded from: classes.dex */
public class ForceStopRunnable implements Runnable {
@VisibleForTesting
static final String ACTION_FORCE_STOP_RESCHEDULE = "ACTION_FORCE_STOP_RESCHEDULE";
private static final int ALARM_ID = -1;
private static final long BACKOFF_DURATION_MS = 300;
@VisibleForTesting
static final int MAX_ATTEMPTS = 3;
private static final String TAG = Logger.tagWithPrefix("ForceStopRunnable");
private static final long TEN_YEARS = TimeUnit.DAYS.toMillis(3650);
private final Context mContext;
private final PreferenceUtils mPreferenceUtils;
private int mRetryCount = 0;
private final WorkManagerImpl mWorkManager;
public ForceStopRunnable(@NonNull Context context, @NonNull WorkManagerImpl workManagerImpl) {
this.mContext = context.getApplicationContext();
this.mWorkManager = workManagerImpl;
this.mPreferenceUtils = workManagerImpl.getPreferenceUtils();
}
@Override // java.lang.Runnable
public void run() {
int i;
try {
if (multiProcessChecks()) {
while (true) {
try {
WorkDatabasePathHelper.migrateDatabase(this.mContext);
Logger.get().debug(TAG, "Performing cleanup operations.");
try {
forceStopRunnable();
break;
} catch (SQLiteAccessPermException | SQLiteCantOpenDatabaseException | SQLiteConstraintException | SQLiteDatabaseCorruptException | SQLiteDatabaseLockedException | SQLiteDiskIOException | SQLiteFullException | SQLiteTableLockedException e) {
i = this.mRetryCount + 1;
this.mRetryCount = i;
if (i >= 3) {
String str = UserManagerCompat.isUserUnlocked(this.mContext) ? "The file system on the device is in a bad state. WorkManager cannot access the app's internal data store." : "WorkManager can't be accessed from direct boot, because credential encrypted storage isn't accessible.\nDon't access or initialise WorkManager from directAware components. See https://developer.android.com/training/articles/direct-boot";
Logger logger = Logger.get();
String str2 = TAG;
logger.error(str2, str, e);
IllegalStateException illegalStateException = new IllegalStateException(str, e);
Consumer<Throwable> initializationExceptionHandler = this.mWorkManager.getConfiguration().getInitializationExceptionHandler();
if (initializationExceptionHandler != null) {
Logger.get().debug(str2, "Routing exception to the specified exception handler", illegalStateException);
initializationExceptionHandler.accept(illegalStateException);
} else {
throw illegalStateException;
}
} else {
long j = i * BACKOFF_DURATION_MS;
Logger.get().debug(TAG, "Retrying after " + j, e);
sleep(((long) this.mRetryCount) * BACKOFF_DURATION_MS);
}
}
long j2 = i * BACKOFF_DURATION_MS;
Logger.get().debug(TAG, "Retrying after " + j2, e);
sleep(((long) this.mRetryCount) * BACKOFF_DURATION_MS);
} catch (SQLiteException e2) {
Logger.get().error(TAG, "Unexpected SQLite exception during migrations");
IllegalStateException illegalStateException2 = new IllegalStateException("Unexpected SQLite exception during migrations", e2);
Consumer<Throwable> initializationExceptionHandler2 = this.mWorkManager.getConfiguration().getInitializationExceptionHandler();
if (initializationExceptionHandler2 != null) {
initializationExceptionHandler2.accept(illegalStateException2);
} else {
throw illegalStateException2;
}
}
}
}
} finally {
this.mWorkManager.onForceStopRunnableCompleted();
}
}
@SuppressLint({"ClassVerificationFailure"})
@VisibleForTesting
public boolean isForceStopped() {
List historicalProcessExitReasons;
int reason;
long timestamp;
try {
int i = Build.VERSION.SDK_INT;
PendingIntent pendingIntent = getPendingIntent(this.mContext, i >= 31 ? 570425344 : DriveFile.MODE_WRITE_ONLY);
if (i >= 30) {
if (pendingIntent != null) {
pendingIntent.cancel();
}
historicalProcessExitReasons = ((ActivityManager) this.mContext.getSystemService("activity")).getHistoricalProcessExitReasons(null, 0, 0);
if (historicalProcessExitReasons != null && !historicalProcessExitReasons.isEmpty()) {
long lastForceStopEventMillis = this.mPreferenceUtils.getLastForceStopEventMillis();
for (int i2 = 0; i2 < historicalProcessExitReasons.size(); i2++) {
ApplicationExitInfo m = ForceStopRunnable$$ExternalSyntheticApiModelOutline1.m(historicalProcessExitReasons.get(i2));
reason = m.getReason();
if (reason == 10) {
timestamp = m.getTimestamp();
if (timestamp >= lastForceStopEventMillis) {
return true;
}
}
}
}
} else if (pendingIntent == null) {
setAlarm(this.mContext);
return true;
}
return false;
} catch (IllegalArgumentException e) {
e = e;
Logger.get().warning(TAG, "Ignoring exception", e);
return true;
} catch (SecurityException e2) {
e = e2;
Logger.get().warning(TAG, "Ignoring exception", e);
return true;
}
}
@VisibleForTesting
public void forceStopRunnable() {
boolean cleanUp = cleanUp();
if (shouldRescheduleWorkers()) {
Logger.get().debug(TAG, "Rescheduling Workers.");
this.mWorkManager.rescheduleEligibleWork();
this.mWorkManager.getPreferenceUtils().setNeedsReschedule(false);
} else if (isForceStopped()) {
Logger.get().debug(TAG, "Application was force-stopped, rescheduling.");
this.mWorkManager.rescheduleEligibleWork();
this.mPreferenceUtils.setLastForceStopEventMillis(this.mWorkManager.getConfiguration().getClock().currentTimeMillis());
} else if (cleanUp) {
Logger.get().debug(TAG, "Found unfinished work, scheduling it.");
Schedulers.schedule(this.mWorkManager.getConfiguration(), this.mWorkManager.getWorkDatabase(), this.mWorkManager.getSchedulers());
}
}
@VisibleForTesting
public boolean cleanUp() {
boolean reconcileJobs = SystemJobScheduler.reconcileJobs(this.mContext, this.mWorkManager.getWorkDatabase());
WorkDatabase workDatabase = this.mWorkManager.getWorkDatabase();
WorkSpecDao workSpecDao = workDatabase.workSpecDao();
WorkProgressDao workProgressDao = workDatabase.workProgressDao();
workDatabase.beginTransaction();
try {
List<WorkSpec> runningWork = workSpecDao.getRunningWork();
boolean z = (runningWork == null || runningWork.isEmpty()) ? false : true;
if (z) {
for (WorkSpec workSpec : runningWork) {
workSpecDao.setState(WorkInfo.State.ENQUEUED, workSpec.id);
workSpecDao.setStopReason(workSpec.id, WorkInfo.STOP_REASON_UNKNOWN);
workSpecDao.markWorkSpecScheduled(workSpec.id, -1L);
}
}
workProgressDao.deleteAll();
workDatabase.setTransactionSuccessful();
workDatabase.endTransaction();
return z || reconcileJobs;
} catch (Throwable th) {
workDatabase.endTransaction();
throw th;
}
}
@VisibleForTesting
public boolean shouldRescheduleWorkers() {
return this.mWorkManager.getPreferenceUtils().getNeedsReschedule();
}
@VisibleForTesting
public boolean multiProcessChecks() {
Configuration configuration = this.mWorkManager.getConfiguration();
if (TextUtils.isEmpty(configuration.getDefaultProcessName())) {
Logger.get().debug(TAG, "The default process name was not specified.");
return true;
}
boolean isDefaultProcess = ProcessUtils.isDefaultProcess(this.mContext, configuration);
Logger.get().debug(TAG, "Is default app process = " + isDefaultProcess);
return isDefaultProcess;
}
@VisibleForTesting
public void sleep(long j) {
try {
Thread.sleep(j);
} catch (InterruptedException unused) {
}
}
private static PendingIntent getPendingIntent(Context context, int i) {
return PendingIntent.getBroadcast(context, -1, getIntent(context), i);
}
@VisibleForTesting
public static Intent getIntent(Context context) {
Intent intent = new Intent();
intent.setComponent(new ComponentName(context, (Class<?>) BroadcastReceiver.class));
intent.setAction(ACTION_FORCE_STOP_RESCHEDULE);
return intent;
}
@SuppressLint({"ClassVerificationFailure"})
public static void setAlarm(Context context) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(NotificationCompat.CATEGORY_ALARM);
PendingIntent pendingIntent = getPendingIntent(context, Build.VERSION.SDK_INT >= 31 ? 167772160 : 134217728);
long currentTimeMillis = System.currentTimeMillis() + TEN_YEARS;
if (alarmManager != null) {
alarmManager.setExact(0, currentTimeMillis, pendingIntent);
}
}
@RestrictTo({RestrictTo.Scope.LIBRARY_GROUP})
public static class BroadcastReceiver extends android.content.BroadcastReceiver {
private static final String TAG = Logger.tagWithPrefix("ForceStopRunnable$Rcvr");
@Override // android.content.BroadcastReceiver
public void onReceive(@NonNull Context context, @Nullable Intent intent) {
if (intent == null || !ForceStopRunnable.ACTION_FORCE_STOP_RESCHEDULE.equals(intent.getAction())) {
return;
}
Logger.get().verbose(TAG, "Rescheduling alarm that keeps track of force-stops.");
ForceStopRunnable.setAlarm(context);
}
}
}