blob: d79be8007311ee8b5afed836b9d20fed9b07ed81 [file] [log] [blame]
Daniel Sandlerb9eb2862013-06-14 20:17:30 -04001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Daniel Sandlera127b7a2013-06-17 14:25:46 -040017package com.android.launcher3;
18
19import android.app.Activity;
Daniel Sandler8540bb82013-06-26 01:39:02 -040020import android.content.ComponentName;
Daniel Sandlera127b7a2013-06-17 14:25:46 -040021import android.content.Context;
22import android.content.Intent;
Daniel Sandler8540bb82013-06-26 01:39:02 -040023import android.content.ServiceConnection;
Daniel Sandlera127b7a2013-06-17 14:25:46 -040024import android.content.pm.PackageManager;
25import android.net.Uri;
Daniel Sandler8540bb82013-06-26 01:39:02 -040026import android.os.*;
Daniel Sandlera127b7a2013-06-17 14:25:46 -040027import android.util.Log;
28
Daniel Sandler8540bb82013-06-26 01:39:02 -040029import java.io.*;
Daniel Sandlera127b7a2013-06-17 14:25:46 -040030import java.util.ArrayList;
Daniel Sandler0adfc5a2013-07-07 17:16:49 -050031import java.util.Arrays;
Daniel Sandler8540bb82013-06-26 01:39:02 -040032import java.util.zip.ZipEntry;
33import java.util.zip.ZipOutputStream;
Daniel Sandlera127b7a2013-06-17 14:25:46 -040034
35public class MemoryDumpActivity extends Activity {
Daniel Sandler8540bb82013-06-26 01:39:02 -040036 private static final String TAG = "MemoryDumpActivity";
37
38 @Override
Daniel Sandlera127b7a2013-06-17 14:25:46 -040039 public void onCreate(Bundle savedInstanceState) {
40 super.onCreate(savedInstanceState);
41 }
42
Daniel Sandler8540bb82013-06-26 01:39:02 -040043 public static String zipUp(ArrayList<String> paths) {
44 final int BUFSIZ = 256 * 1024; // 256K
45 final byte[] buf = new byte[BUFSIZ];
46 final String zipfilePath = String.format("%s/hprof-%d.zip",
47 Environment.getExternalStorageDirectory(),
48 System.currentTimeMillis());
49 ZipOutputStream zos = null;
Daniel Sandlera127b7a2013-06-17 14:25:46 -040050 try {
Daniel Sandler8540bb82013-06-26 01:39:02 -040051 OutputStream os = new FileOutputStream(zipfilePath);
52 zos = new ZipOutputStream(new BufferedOutputStream(os));
53 for (String filename : paths) {
54 InputStream is = null;
55 try {
56 is = new BufferedInputStream(new FileInputStream(filename));
57 ZipEntry entry = new ZipEntry(filename);
58 zos.putNextEntry(entry);
59 int len;
60 while ( 0 < (len = is.read(buf, 0, BUFSIZ)) ) {
61 zos.write(buf, 0, len);
62 }
63 zos.closeEntry();
64 } finally {
65 is.close();
66 }
67 }
68 } catch (IOException e) {
69 Log.e(TAG, "error zipping up profile data", e);
70 return null;
71 } finally {
72 if (zos != null) {
73 try {
74 zos.close();
75 } catch (IOException e) {
76 // ugh, whatever
77 }
78 }
79 }
80 return zipfilePath;
81 }
82
83 public static void dumpHprofAndShare(final Context context, MemoryTracker tracker) {
84 final StringBuilder body = new StringBuilder();
85
86 final ArrayList<String> paths = new ArrayList<String>();
Daniel Sandler4de7f732013-07-02 14:16:04 -050087 final int myPid = android.os.Process.myPid();
Daniel Sandlera127b7a2013-06-17 14:25:46 -040088
Daniel Sandler0adfc5a2013-07-07 17:16:49 -050089 final int[] pids_orig = tracker.getTrackedProcesses();
90 final int[] pids_copy = Arrays.copyOf(pids_orig, pids_orig.length);
91 for (int pid : pids_copy) {
Daniel Sandler4de7f732013-07-02 14:16:04 -050092 MemoryTracker.ProcessMemInfo info = tracker.getMemInfo(pid);
93 if (info != null) {
94 body.append("pid ").append(pid).append(":")
95 .append(" up=").append(info.getUptime())
96 .append(" pss=").append(info.currentPss)
97 .append(" uss=").append(info.currentUss)
98 .append("\n");
99 }
100 if (pid == myPid) {
101 final String path = String.format("%s/launcher-memory-%d.ahprof",
102 Environment.getExternalStorageDirectory(),
103 pid);
104 Log.v(TAG, "Dumping memory info for process " + pid + " to " + path);
105 try {
106 android.os.Debug.dumpHprofData(path); // will block
107 } catch (IOException e) {
108 Log.e(TAG, "error dumping memory:", e);
109 }
110 paths.add(path);
111 }
Daniel Sandlera127b7a2013-06-17 14:25:46 -0400112 }
Daniel Sandler8540bb82013-06-26 01:39:02 -0400113
114 String zipfile = zipUp(paths);
115
116 if (zipfile == null) return;
117
118 Intent shareIntent = new Intent(Intent.ACTION_SEND);
119 shareIntent.setType("application/zip");
120
121 final PackageManager pm = context.getPackageManager();
Daniel Sandler4de7f732013-07-02 14:16:04 -0500122 shareIntent.putExtra(Intent.EXTRA_SUBJECT, String.format("Launcher memory dump (%d)", myPid));
Daniel Sandler8540bb82013-06-26 01:39:02 -0400123 String appVersion;
124 try {
125 appVersion = pm.getPackageInfo(context.getPackageName(), 0).versionName;
126 } catch (PackageManager.NameNotFoundException e) {
127 appVersion = "?";
128 }
129
130 body.append("\nApp version: ").append(appVersion).append("\nBuild: ").append(Build.DISPLAY).append("\n");
131 shareIntent.putExtra(Intent.EXTRA_TEXT, body.toString());
132
133 final File pathFile = new File(zipfile);
134 final Uri pathUri = Uri.fromFile(pathFile);
135
136 shareIntent.putExtra(Intent.EXTRA_STREAM, pathUri);
137 context.startActivity(shareIntent);
Daniel Sandlera127b7a2013-06-17 14:25:46 -0400138 }
139
140 @Override
141 public void onStart() {
142 super.onStart();
Daniel Sandler8540bb82013-06-26 01:39:02 -0400143
Daniel Sandlerf8577a32013-06-26 14:04:59 -0400144 startDump(this, new Runnable() {
145 @Override
146 public void run() {
147 finish();
148 }
149 });
150 }
151
152 public static void startDump(final Context context) {
153 startDump(context, null);
154 }
155
156 public static void startDump(final Context context, final Runnable andThen) {
Daniel Sandler8540bb82013-06-26 01:39:02 -0400157 final ServiceConnection connection = new ServiceConnection() {
158 public void onServiceConnected(ComponentName className, IBinder service) {
159 Log.v(TAG, "service connected, dumping...");
Daniel Sandlerf8577a32013-06-26 14:04:59 -0400160 dumpHprofAndShare(context,
161 ((MemoryTracker.MemoryTrackerInterface) service).getService());
162 context.unbindService(this);
163 if (andThen != null) andThen.run();
Daniel Sandler8540bb82013-06-26 01:39:02 -0400164 }
165
166 public void onServiceDisconnected(ComponentName className) {
167 }
168 };
169 Log.v(TAG, "attempting to bind to memory tracker");
Daniel Sandlerf8577a32013-06-26 14:04:59 -0400170 context.bindService(new Intent(context, MemoryTracker.class),
Daniel Sandler8540bb82013-06-26 01:39:02 -0400171 connection, Context.BIND_AUTO_CREATE);
Daniel Sandlera127b7a2013-06-17 14:25:46 -0400172 }
Daniel Sandler8540bb82013-06-26 01:39:02 -0400173}