summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
authorVasu Nori <vnori@google.com>2011-01-04 12:15:53 -0800
committerAndroid (Google) Code Review <android-gerrit@google.com>2011-01-04 12:15:53 -0800
commitdc3c9c4b85988f187d84386bac82448d534de6cf (patch)
tree1828ecfa0874fa6146a662668eaea88b8a41691f /core/java
parent068a73555a3ed79710fb511c7684f4d0048fc7d6 (diff)
parent6141e13f6e84846ae531358a8bcbf6d2102b1bd4 (diff)
downloadframeworks_base-dc3c9c4b85988f187d84386bac82448d534de6cf.zip
frameworks_base-dc3c9c4b85988f187d84386bac82448d534de6cf.tar.gz
frameworks_base-dc3c9c4b85988f187d84386bac82448d534de6cf.tar.bz2
Merge "when cursorwindow allocation fails, print the number of cursors left open"
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/database/CursorWindow.java91
-rw-r--r--core/java/android/database/CursorWindowAllocationException.java34
2 files changed, 117 insertions, 8 deletions
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index 9a8f2d2..d15fb88 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -18,14 +18,20 @@ package android.database;
import android.content.res.Resources;
import android.database.sqlite.SQLiteClosable;
+import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.Process;
+import android.util.Log;
+import android.util.SparseIntArray;
/**
* A buffer containing multiple cursor rows.
*/
public class CursorWindow extends SQLiteClosable implements Parcelable {
+ private static final String STATS_TAG = "CursorWindowStats";
+
/** The cursor window size. resource xml file specifies the value in kB.
* convert it to bytes here by multiplying with 1024.
*/
@@ -33,8 +39,9 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
Resources.getSystem().getInteger(
com.android.internal.R.integer.config_cursorWindowSize) * 1024;
- /** The pointer to the native window class */
- @SuppressWarnings("unused")
+ /** The pointer to the native window class. set by the native methods in
+ * android_database_CursorWindow.cpp
+ */
private int nWindow;
private int mStartPos;
@@ -46,7 +53,18 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
*/
public CursorWindow(boolean localWindow) {
mStartPos = 0;
- native_init(sCursorWindowSize, localWindow);
+ int rslt = native_init(sCursorWindowSize, localWindow);
+ printDebugMsgIfError(rslt);
+ recordNewWindow(Binder.getCallingPid(), nWindow);
+ }
+
+ private void printDebugMsgIfError(int rslt) {
+ if (rslt > 0) {
+ // cursor window allocation failed. either low memory or too many cursors being open.
+ // print info to help in debugging this.
+ throw new CursorWindowAllocationException("Cursor Window allocation of " +
+ sCursorWindowSize/1024 + " kb failed. " + printStats());
+ }
}
/**
@@ -574,21 +592,78 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
private CursorWindow(Parcel source) {
IBinder nativeBinder = source.readStrongBinder();
mStartPos = source.readInt();
-
- native_init(nativeBinder);
+ int rslt = native_init(nativeBinder);
+ printDebugMsgIfError(rslt);
}
/** Get the binder for the native side of the window */
private native IBinder native_getBinder();
/** Does the native side initialization for an empty window */
- private native void native_init(int cursorWindowSize, boolean localOnly);
+ private native int native_init(int cursorWindowSize, boolean localOnly);
/** Does the native side initialization with an existing binder from another process */
- private native void native_init(IBinder nativeBinder);
+ private native int native_init(IBinder nativeBinder);
@Override
protected void onAllReferencesReleased() {
- close_native();
+ int windowId = nWindow;
+ recordClosingOfWindow(Binder.getCallingPid(), nWindow);
+ close_native();
+ }
+
+ private static final SparseIntArray sWindowToPidMap = new SparseIntArray();
+
+ private void recordNewWindow(int pid, int window) {
+ synchronized (sWindowToPidMap) {
+ sWindowToPidMap.put(window, pid);
+ if (Log.isLoggable(STATS_TAG, Log.VERBOSE)) {
+ Log.i(STATS_TAG, "Created a new Cursor. " + printStats());
+ }
+ }
+ }
+
+ private void recordClosingOfWindow(int pid, int window) {
+ synchronized (sWindowToPidMap) {
+ if (sWindowToPidMap.size() == 0) {
+ // this means we are not in the ContentProvider.
+ return;
+ }
+ sWindowToPidMap.delete(window);
+ }
+ }
+ private String printStats() {
+ StringBuilder buff = new StringBuilder();
+ int myPid = Process.myPid();
+ int total = 0;
+ SparseIntArray pidCounts = new SparseIntArray();
+ synchronized (sWindowToPidMap) {
+ int size = sWindowToPidMap.size();
+ if (size == 0) {
+ // this means we are not in the ContentProvider.
+ return "";
+ }
+ for (int indx = 0; indx < size; indx++) {
+ int pid = sWindowToPidMap.valueAt(indx);
+ int value = pidCounts.get(pid);
+ pidCounts.put(pid, ++value);
+ }
+ }
+ int numPids = pidCounts.size();
+ for (int i = 0; i < numPids;i++) {
+ buff.append(" (# cursors opened by ");
+ int pid = pidCounts.keyAt(i);
+ if (pid == myPid) {
+ buff.append("this proc=");
+ } else {
+ buff.append("pid " + pid + "=");
+ }
+ int num = pidCounts.get(pid);
+ buff.append(num + ")");
+ total += num;
+ }
+ // limit the returned string size to 1000
+ String s = (buff.length() > 980) ? buff.substring(0, 980) : buff.toString();
+ return "# Open Cursors=" + total + s;
}
}
diff --git a/core/java/android/database/CursorWindowAllocationException.java b/core/java/android/database/CursorWindowAllocationException.java
new file mode 100644
index 0000000..ba7df68
--- /dev/null
+++ b/core/java/android/database/CursorWindowAllocationException.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.database;
+
+/**
+ * This exception is thrown when a CursorWindow couldn't be allocated,
+ * most probably due to memory not being available
+ */
+class CursorWindowAllocationException extends java.lang.RuntimeException
+{
+ public CursorWindowAllocationException()
+ {
+ super();
+ }
+
+ public CursorWindowAllocationException(String description)
+ {
+ super(description);
+ }
+}