summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdnan Begovic <adnan@cyngn.com>2015-02-10 14:00:16 -0800
committerniks255 <niks255@mail.ru>2017-01-07 04:39:45 +0600
commitd2cc2b20bc60b39bf251ed853009b552868dfc79 (patch)
tree259520bd983058984e66666b948ad284aa67b3e6
parentb90b682c5c26bcc5f9e806e490342e076b25df74 (diff)
downloadandroid_packages_apps_Trebuchet-d2cc2b20bc60b39bf251ed853009b552868dfc79.tar.gz
android_packages_apps_Trebuchet-d2cc2b20bc60b39bf251ed853009b552868dfc79.tar.bz2
android_packages_apps_Trebuchet-d2cc2b20bc60b39bf251ed853009b552868dfc79.zip
Trebuchet: Catch SQLiteReadOnlyException.
Change-Id: I5e3cbd85a2fba84263b1e6df25f00f98b1ef55c0
-rw-r--r--src/com/android/launcher3/WidgetPreviewLoader.java87
1 files changed, 87 insertions, 0 deletions
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index 3db0b51ad..a030ab8b6 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -9,9 +9,11 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.database.Cursor;
+import android.database.sqlite.SQLiteCantOpenDatabaseException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDiskIOException;
import android.database.sqlite.SQLiteOpenHelper;
+import android.database.sqlite.SQLiteReadOnlyDatabaseException;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
@@ -29,11 +31,14 @@ import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.File;
+import java.io.IOException;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
abstract class SoftReferenceThreadLocal<T> {
private ThreadLocal<SoftReference<T>> mThreadLocal;
@@ -367,6 +372,10 @@ public class WidgetPreviewLoader {
try {
db.delete(CacheDb.TABLE_NAME, null, null);
} catch (SQLiteDiskIOException e) {
+ } catch (SQLiteCantOpenDatabaseException e) {
+ } catch (SQLiteReadOnlyDatabaseException e) {
+ dumpOpenFiles();
+ throw e;
}
}
@@ -672,4 +681,82 @@ public class WidgetPreviewLoader {
}
}
+ private static final int MAX_OPEN_FILES = 1024;
+ private static final int SAMPLE_RATE = 23;
+ /**
+ * Dumps all files that are open in this process without allocating a file descriptor.
+ */
+ private static void dumpOpenFiles() {
+ try {
+ Log.i(TAG, "DUMP OF OPEN FILES (sample rate: 1 every " + SAMPLE_RATE + "):");
+ final String TYPE_APK = "apk";
+ final String TYPE_JAR = "jar";
+ final String TYPE_PIPE = "pipe";
+ final String TYPE_SOCKET = "socket";
+ final String TYPE_DB = "db";
+ final String TYPE_ANON_INODE = "anon_inode";
+ final String TYPE_DEV = "dev";
+ final String TYPE_NON_FS = "non-fs";
+ final String TYPE_OTHER = "other";
+ List<String> types = Arrays.asList(TYPE_APK, TYPE_JAR, TYPE_PIPE, TYPE_SOCKET, TYPE_DB,
+ TYPE_ANON_INODE, TYPE_DEV, TYPE_NON_FS, TYPE_OTHER);
+ int[] count = new int[types.size()];
+ int[] duplicates = new int[types.size()];
+ HashSet<String> files = new HashSet<String>();
+ int total = 0;
+ for (int i = 0; i < MAX_OPEN_FILES; i++) {
+ // This is a gigantic hack but unfortunately the only way to resolve an fd
+ // to a file name. Note that we have to loop over all possible fds because
+ // reading the directory would require allocating a new fd. The kernel is
+ // currently implemented such that no fd is larger then the current rlimit,
+ // which is why it's safe to loop over them in such a way.
+ String fd = "/proc/self/fd/" + i;
+ try {
+ // getCanonicalPath() uses readlink behind the scene which doesn't require
+ // a file descriptor.
+ String resolved = new File(fd).getCanonicalPath();
+ int type = types.indexOf(TYPE_OTHER);
+ if (resolved.startsWith("/dev/")) {
+ type = types.indexOf(TYPE_DEV);
+ } else if (resolved.endsWith(".apk")) {
+ type = types.indexOf(TYPE_APK);
+ } else if (resolved.endsWith(".jar")) {
+ type = types.indexOf(TYPE_JAR);
+ } else if (resolved.contains("/fd/pipe:")) {
+ type = types.indexOf(TYPE_PIPE);
+ } else if (resolved.contains("/fd/socket:")) {
+ type = types.indexOf(TYPE_SOCKET);
+ } else if (resolved.contains("/fd/anon_inode:")) {
+ type = types.indexOf(TYPE_ANON_INODE);
+ } else if (resolved.endsWith(".db") || resolved.contains("/databases/")) {
+ type = types.indexOf(TYPE_DB);
+ } else if (resolved.startsWith("/proc/") && resolved.contains("/fd/")) {
+ // Those are the files that don't point anywhere on the file system.
+ // getCanonicalPath() wrongly interprets these as relative symlinks and
+ // resolves them within /proc/<pid>/fd/.
+ type = types.indexOf(TYPE_NON_FS);
+ }
+ count[type]++;
+ total++;
+ if (files.contains(resolved)) {
+ duplicates[type]++;
+ }
+ files.add(resolved);
+ if (total % SAMPLE_RATE == 0) {
+ Log.i(TAG, " fd " + i + ": " + resolved
+ + " (" + types.get(type) + ")");
+ }
+ } catch (IOException e) {
+ // Ignoring exceptions for non-existing file descriptors.
+ }
+ }
+ for (int i = 0; i < types.size(); i++) {
+ Log.i(TAG, String.format("Open %10s files: %4d total, %4d duplicates",
+ types.get(i), count[i], duplicates[i]));
+ }
+ } catch (Throwable t) {
+ // Catch everything. This is called from an exception handler that we shouldn't upset.
+ Log.e(TAG, "Unable to log open files.", t);
+ }
+ }
}