diff options
5 files changed, 101 insertions, 0 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 9e88bc6e8442..bac3c6c4b835 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -65,6 +65,7 @@ import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Log; import android.util.LogPrinter; +import android.util.PrintWriterPrinter; import android.util.Slog; import android.view.Display; import android.view.HardwareRenderer; @@ -1039,6 +1040,14 @@ public final class ActivityThread { WindowManagerImpl.getDefault().dumpGfxInfo(fd); } + @Override + public void dumpDbInfo(FileDescriptor fd, String[] args) { + PrintWriter pw = new PrintWriter(new FileOutputStream(fd)); + PrintWriterPrinter printer = new PrintWriterPrinter(pw); + SQLiteDebug.dump(printer, args); + pw.flush(); + } + private void printRow(PrintWriter pw, String format, Object...objs) { pw.println(String.format(format, objs)); } diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index e6d28ef48c21..e75d7b4ce46d 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -554,6 +554,26 @@ public abstract class ApplicationThreadNative extends Binder reply.writeNoException(); return true; } + + case DUMP_DB_INFO_TRANSACTION: + { + data.enforceInterface(IApplicationThread.descriptor); + ParcelFileDescriptor fd = data.readFileDescriptor(); + String[] args = data.readStringArray(); + if (fd != null) { + try { + dumpDbInfo(fd.getFileDescriptor(), args); + } finally { + try { + fd.close(); + } catch (IOException e) { + // swallowed, not propagated back to the caller + } + } + } + reply.writeNoException(); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -1131,4 +1151,13 @@ class ApplicationThreadProxy implements IApplicationThread { mRemote.transact(DUMP_GFX_INFO_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); } + + public void dumpDbInfo(FileDescriptor fd, String[] args) throws RemoteException { + Parcel data = Parcel.obtain(); + data.writeInterfaceToken(IApplicationThread.descriptor); + data.writeFileDescriptor(fd); + data.writeStringArray(args); + mRemote.transact(DUMP_DB_INFO_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); + data.recycle(); + } } diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index a3627781bdaf..6ad1736a0659 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -127,6 +127,7 @@ public interface IApplicationThread extends IInterface { Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, boolean checkin, boolean all, String[] args) throws RemoteException; void dumpGfxInfo(FileDescriptor fd, String[] args) throws RemoteException; + void dumpDbInfo(FileDescriptor fd, String[] args) throws RemoteException; String descriptor = "android.app.IApplicationThread"; @@ -174,4 +175,5 @@ public interface IApplicationThread extends IInterface { int DUMP_MEM_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+42; int DUMP_GFX_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+43; int DUMP_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+44; + int DUMP_DB_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+45; } diff --git a/core/java/android/database/sqlite/SQLiteDebug.java b/core/java/android/database/sqlite/SQLiteDebug.java index cc057e016fe3..029bb4a87249 100644 --- a/core/java/android/database/sqlite/SQLiteDebug.java +++ b/core/java/android/database/sqlite/SQLiteDebug.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import android.os.Build; import android.os.SystemProperties; import android.util.Log; +import android.util.Printer; /** * Provides debugging info about all SQLite databases running in the current process. @@ -181,6 +182,13 @@ public final class SQLiteDebug { } /** + * Dumps detailed information about all databases used by the process. + * @param printer The printer for dumping database state. + */ + public static void dump(Printer printer, String[] args) { + } + + /** * Gathers statistics about all pagers in the current process. */ public static native void getPagerStats(PagerStats stats); diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 4067f6e40a5d..bbb4917fbab2 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -1299,6 +1299,7 @@ public final class ActivityManagerService extends ActivityManagerNative ServiceManager.addService("activity", m); ServiceManager.addService("meminfo", new MemBinder(m)); ServiceManager.addService("gfxinfo", new GraphicsBinder(m)); + ServiceManager.addService("dbinfo", new DbBinder(m)); if (MONITOR_CPU_USAGE) { ServiceManager.addService("cpuinfo", new CpuBinder(m)); } @@ -1453,6 +1454,26 @@ public final class ActivityManagerService extends ActivityManagerNative } } + static class DbBinder extends Binder { + ActivityManagerService mActivityManagerService; + DbBinder(ActivityManagerService activityManagerService) { + mActivityManagerService = activityManagerService; + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (mActivityManagerService.checkCallingPermission(android.Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + pw.println("Permission Denial: can't dump dbinfo from from pid=" + + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() + + " without permission " + android.Manifest.permission.DUMP); + return; + } + + mActivityManagerService.dumpDbInfo(fd, pw, args); + } + } + static class CpuBinder extends Binder { ActivityManagerService mActivityManagerService; CpuBinder(ActivityManagerService activityManagerService) { @@ -9741,6 +9762,38 @@ public final class ActivityManagerService extends ActivityManagerNative } } + final void dumpDbInfo(FileDescriptor fd, PrintWriter pw, String[] args) { + ArrayList<ProcessRecord> procs = collectProcesses(pw, 0, args); + if (procs == null) { + return; + } + + pw.println("Applications Database Info:"); + + for (int i = procs.size() - 1 ; i >= 0 ; i--) { + ProcessRecord r = procs.get(i); + if (r.thread != null) { + pw.println("\n** Database info for pid " + r.pid + " [" + r.processName + "] **"); + pw.flush(); + try { + TransferPipe tp = new TransferPipe(); + try { + r.thread.dumpDbInfo(tp.getWriteFd().getFileDescriptor(), args); + tp.go(fd); + } finally { + tp.kill(); + } + } catch (IOException e) { + pw.println("Failure while dumping the app: " + r); + pw.flush(); + } catch (RemoteException e) { + pw.println("Got a RemoteException while dumping the app " + r); + pw.flush(); + } + } + } + } + final static class MemItem { final String label; final String shortLabel; |