165 lines
7.2 KiB
Java
165 lines
7.2 KiB
Java
package com.squareup.leakcanary;
|
|
|
|
import android.annotation.TargetApi;
|
|
import android.app.PendingIntent;
|
|
import android.content.Context;
|
|
import android.os.Build;
|
|
import android.os.Environment;
|
|
import com.squareup.leakcanary.internal.LeakCanaryInternals;
|
|
import com.squareup.leakcanary.internal.RequestStoragePermissionActivity;
|
|
import java.io.File;
|
|
import java.io.FilenameFilter;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Collections;
|
|
import java.util.Comparator;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.UUID;
|
|
|
|
/* loaded from: classes.dex */
|
|
public final class DefaultLeakDirectoryProvider implements LeakDirectoryProvider {
|
|
private static final int ANALYSIS_MAX_DURATION_MS = 600000;
|
|
private static final int DEFAULT_MAX_STORED_HEAP_DUMPS = 7;
|
|
private static final String HPROF_SUFFIX = ".hprof";
|
|
private static final String PENDING_HEAPDUMP_SUFFIX = "_pending.hprof";
|
|
private final Context context;
|
|
private final int maxStoredHeapDumps;
|
|
private volatile boolean permissionNotificationDisplayed;
|
|
private volatile boolean writeExternalStorageGranted;
|
|
|
|
public DefaultLeakDirectoryProvider(Context context) {
|
|
this(context, 7);
|
|
}
|
|
|
|
private File appStorageDirectory() {
|
|
return new File(this.context.getFilesDir(), "leakcanary");
|
|
}
|
|
|
|
private void cleanupOldHeapDumps() {
|
|
List<File> listFiles = listFiles(new FilenameFilter() { // from class: com.squareup.leakcanary.DefaultLeakDirectoryProvider.3
|
|
@Override // java.io.FilenameFilter
|
|
public boolean accept(File file, String str) {
|
|
return str.endsWith(DefaultLeakDirectoryProvider.HPROF_SUFFIX);
|
|
}
|
|
});
|
|
int size = listFiles.size() - this.maxStoredHeapDumps;
|
|
if (size > 0) {
|
|
CanaryLog.d("Removing %d heap dumps", Integer.valueOf(size));
|
|
Collections.sort(listFiles, new Comparator<File>() { // from class: com.squareup.leakcanary.DefaultLeakDirectoryProvider.4
|
|
@Override // java.util.Comparator
|
|
public int compare(File file, File file2) {
|
|
return Long.valueOf(file.lastModified()).compareTo(Long.valueOf(file2.lastModified()));
|
|
}
|
|
});
|
|
for (int i = 0; i < size; i++) {
|
|
if (!listFiles.get(i).delete()) {
|
|
CanaryLog.d("Could not delete old hprof file %s", listFiles.get(i).getPath());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean directoryWritableAfterMkdirs(File file) {
|
|
return (file.mkdirs() || file.exists()) && file.canWrite();
|
|
}
|
|
|
|
private File externalStorageDirectory() {
|
|
return new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "leakcanary-" + this.context.getPackageName());
|
|
}
|
|
|
|
@TargetApi(23)
|
|
private boolean hasStoragePermission() {
|
|
if (Build.VERSION.SDK_INT < 23 || this.writeExternalStorageGranted) {
|
|
return true;
|
|
}
|
|
this.writeExternalStorageGranted = this.context.checkSelfPermission("android.permission.WRITE_EXTERNAL_STORAGE") == 0;
|
|
return this.writeExternalStorageGranted;
|
|
}
|
|
|
|
private void requestWritePermissionNotification() {
|
|
if (this.permissionNotificationDisplayed) {
|
|
return;
|
|
}
|
|
this.permissionNotificationDisplayed = true;
|
|
PendingIntent createPendingIntent = RequestStoragePermissionActivity.createPendingIntent(this.context);
|
|
LeakCanaryInternals.showNotification(this.context, this.context.getString(R.string.leak_canary_permission_notification_title), this.context.getString(R.string.leak_canary_permission_notification_text, this.context.getPackageName()), createPendingIntent, -558907665);
|
|
}
|
|
|
|
@Override // com.squareup.leakcanary.LeakDirectoryProvider
|
|
public void clearLeakDirectory() {
|
|
for (File file : listFiles(new FilenameFilter() { // from class: com.squareup.leakcanary.DefaultLeakDirectoryProvider.2
|
|
@Override // java.io.FilenameFilter
|
|
public boolean accept(File file2, String str) {
|
|
return !str.endsWith(DefaultLeakDirectoryProvider.PENDING_HEAPDUMP_SUFFIX);
|
|
}
|
|
})) {
|
|
if (!file.delete()) {
|
|
CanaryLog.d("Could not delete file %s", file.getPath());
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override // com.squareup.leakcanary.LeakDirectoryProvider
|
|
public List<File> listFiles(FilenameFilter filenameFilter) {
|
|
if (!hasStoragePermission()) {
|
|
requestWritePermissionNotification();
|
|
}
|
|
ArrayList arrayList = new ArrayList();
|
|
File[] listFiles = externalStorageDirectory().listFiles(filenameFilter);
|
|
if (listFiles != null) {
|
|
arrayList.addAll(Arrays.asList(listFiles));
|
|
}
|
|
File[] listFiles2 = appStorageDirectory().listFiles(filenameFilter);
|
|
if (listFiles2 != null) {
|
|
arrayList.addAll(Arrays.asList(listFiles2));
|
|
}
|
|
return arrayList;
|
|
}
|
|
|
|
@Override // com.squareup.leakcanary.LeakDirectoryProvider
|
|
public File newHeapDumpFile() {
|
|
Iterator<File> it = listFiles(new FilenameFilter() { // from class: com.squareup.leakcanary.DefaultLeakDirectoryProvider.1
|
|
@Override // java.io.FilenameFilter
|
|
public boolean accept(File file, String str) {
|
|
return str.endsWith(DefaultLeakDirectoryProvider.PENDING_HEAPDUMP_SUFFIX);
|
|
}
|
|
}).iterator();
|
|
while (it.hasNext()) {
|
|
if (System.currentTimeMillis() - it.next().lastModified() < 600000) {
|
|
CanaryLog.d("Could not dump heap, previous analysis still is in progress.", new Object[0]);
|
|
return HeapDumper.RETRY_LATER;
|
|
}
|
|
}
|
|
cleanupOldHeapDumps();
|
|
File externalStorageDirectory = externalStorageDirectory();
|
|
if (!directoryWritableAfterMkdirs(externalStorageDirectory)) {
|
|
if (hasStoragePermission()) {
|
|
String externalStorageState = Environment.getExternalStorageState();
|
|
if ("mounted".equals(externalStorageState)) {
|
|
CanaryLog.d("Could not create heap dump directory in external storage: [%s]", externalStorageDirectory.getAbsolutePath());
|
|
} else {
|
|
CanaryLog.d("External storage not mounted, state: %s", externalStorageState);
|
|
}
|
|
} else {
|
|
CanaryLog.d("WRITE_EXTERNAL_STORAGE permission not granted", new Object[0]);
|
|
requestWritePermissionNotification();
|
|
}
|
|
externalStorageDirectory = appStorageDirectory();
|
|
if (!directoryWritableAfterMkdirs(externalStorageDirectory)) {
|
|
CanaryLog.d("Could not create heap dump directory in app storage: [%s]", externalStorageDirectory.getAbsolutePath());
|
|
return HeapDumper.RETRY_LATER;
|
|
}
|
|
}
|
|
return new File(externalStorageDirectory, UUID.randomUUID().toString() + PENDING_HEAPDUMP_SUFFIX);
|
|
}
|
|
|
|
public DefaultLeakDirectoryProvider(Context context, int i) {
|
|
if (i < 1) {
|
|
throw new IllegalArgumentException("maxStoredHeapDumps must be at least 1");
|
|
}
|
|
this.context = context.getApplicationContext();
|
|
this.maxStoredHeapDumps = i;
|
|
}
|
|
}
|