1b9eb2865af05d9ade572e71934a9e6a50421aa7dDaniel Sandler/* 2b9eb2865af05d9ade572e71934a9e6a50421aa7dDaniel Sandler * Copyright (C) 2013 The Android Open Source Project 3b9eb2865af05d9ade572e71934a9e6a50421aa7dDaniel Sandler * 4b9eb2865af05d9ade572e71934a9e6a50421aa7dDaniel Sandler * Licensed under the Apache License, Version 2.0 (the "License"); 5b9eb2865af05d9ade572e71934a9e6a50421aa7dDaniel Sandler * you may not use this file except in compliance with the License. 6b9eb2865af05d9ade572e71934a9e6a50421aa7dDaniel Sandler * You may obtain a copy of the License at 7b9eb2865af05d9ade572e71934a9e6a50421aa7dDaniel Sandler * 8b9eb2865af05d9ade572e71934a9e6a50421aa7dDaniel Sandler * http://www.apache.org/licenses/LICENSE-2.0 9b9eb2865af05d9ade572e71934a9e6a50421aa7dDaniel Sandler * 10b9eb2865af05d9ade572e71934a9e6a50421aa7dDaniel Sandler * Unless required by applicable law or agreed to in writing, software 11b9eb2865af05d9ade572e71934a9e6a50421aa7dDaniel Sandler * distributed under the License is distributed on an "AS IS" BASIS, 12b9eb2865af05d9ade572e71934a9e6a50421aa7dDaniel Sandler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b9eb2865af05d9ade572e71934a9e6a50421aa7dDaniel Sandler * See the License for the specific language governing permissions and 14b9eb2865af05d9ade572e71934a9e6a50421aa7dDaniel Sandler * limitations under the License. 15b9eb2865af05d9ade572e71934a9e6a50421aa7dDaniel Sandler */ 16b9eb2865af05d9ade572e71934a9e6a50421aa7dDaniel Sandler 17322d55622031985c75f7e5db07964b7730a97dacSunny Goyalpackage com.android.launcher3.testing; 18a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandler 19a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandlerimport android.app.Activity; 208540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandlerimport android.content.ComponentName; 21a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandlerimport android.content.Context; 22a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandlerimport android.content.Intent; 238540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandlerimport android.content.ServiceConnection; 24a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandlerimport android.content.pm.PackageManager; 25a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandlerimport android.net.Uri; 26322d55622031985c75f7e5db07964b7730a97dacSunny Goyalimport android.os.Build; 27322d55622031985c75f7e5db07964b7730a97dacSunny Goyalimport android.os.Bundle; 28322d55622031985c75f7e5db07964b7730a97dacSunny Goyalimport android.os.Environment; 29322d55622031985c75f7e5db07964b7730a97dacSunny Goyalimport android.os.IBinder; 30a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandlerimport android.util.Log; 31a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandler 32322d55622031985c75f7e5db07964b7730a97dacSunny Goyalimport java.io.BufferedInputStream; 33322d55622031985c75f7e5db07964b7730a97dacSunny Goyalimport java.io.BufferedOutputStream; 34322d55622031985c75f7e5db07964b7730a97dacSunny Goyalimport java.io.File; 35322d55622031985c75f7e5db07964b7730a97dacSunny Goyalimport java.io.FileInputStream; 36322d55622031985c75f7e5db07964b7730a97dacSunny Goyalimport java.io.FileOutputStream; 37322d55622031985c75f7e5db07964b7730a97dacSunny Goyalimport java.io.IOException; 38322d55622031985c75f7e5db07964b7730a97dacSunny Goyalimport java.io.InputStream; 39322d55622031985c75f7e5db07964b7730a97dacSunny Goyalimport java.io.OutputStream; 40a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandlerimport java.util.ArrayList; 410adfc5a75580dcf3294da95b378a27c4bcd015fbDaniel Sandlerimport java.util.Arrays; 428540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandlerimport java.util.zip.ZipEntry; 438540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandlerimport java.util.zip.ZipOutputStream; 44a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandler 45a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandlerpublic class MemoryDumpActivity extends Activity { 468540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler private static final String TAG = "MemoryDumpActivity"; 478540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler 488540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler @Override 49a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandler public void onCreate(Bundle savedInstanceState) { 50a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandler super.onCreate(savedInstanceState); 51a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandler } 52a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandler 538540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler public static String zipUp(ArrayList<String> paths) { 548540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler final int BUFSIZ = 256 * 1024; // 256K 558540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler final byte[] buf = new byte[BUFSIZ]; 568540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler final String zipfilePath = String.format("%s/hprof-%d.zip", 578540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler Environment.getExternalStorageDirectory(), 588540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler System.currentTimeMillis()); 598540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler ZipOutputStream zos = null; 60a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandler try { 618540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler OutputStream os = new FileOutputStream(zipfilePath); 628540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler zos = new ZipOutputStream(new BufferedOutputStream(os)); 638540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler for (String filename : paths) { 648540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler InputStream is = null; 658540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler try { 668540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler is = new BufferedInputStream(new FileInputStream(filename)); 678540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler ZipEntry entry = new ZipEntry(filename); 688540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler zos.putNextEntry(entry); 698540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler int len; 708540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler while ( 0 < (len = is.read(buf, 0, BUFSIZ)) ) { 718540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler zos.write(buf, 0, len); 728540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler } 738540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler zos.closeEntry(); 748540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler } finally { 758540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler is.close(); 768540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler } 778540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler } 788540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler } catch (IOException e) { 798540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler Log.e(TAG, "error zipping up profile data", e); 808540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler return null; 818540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler } finally { 828540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler if (zos != null) { 838540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler try { 848540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler zos.close(); 858540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler } catch (IOException e) { 868540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler // ugh, whatever 878540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler } 888540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler } 898540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler } 908540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler return zipfilePath; 918540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler } 92a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandler 938540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler public static void dumpHprofAndShare(final Context context, MemoryTracker tracker) { 948540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler final StringBuilder body = new StringBuilder(); 95a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandler 968540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler final ArrayList<String> paths = new ArrayList<String>(); 974de7f739c15615d5564cefd22f60176cc45ae88eDaniel Sandler final int myPid = android.os.Process.myPid(); 984de7f739c15615d5564cefd22f60176cc45ae88eDaniel Sandler 990adfc5a75580dcf3294da95b378a27c4bcd015fbDaniel Sandler final int[] pids_orig = tracker.getTrackedProcesses(); 1000adfc5a75580dcf3294da95b378a27c4bcd015fbDaniel Sandler final int[] pids_copy = Arrays.copyOf(pids_orig, pids_orig.length); 1010adfc5a75580dcf3294da95b378a27c4bcd015fbDaniel Sandler for (int pid : pids_copy) { 1028540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler MemoryTracker.ProcessMemInfo info = tracker.getMemInfo(pid); 1034de7f739c15615d5564cefd22f60176cc45ae88eDaniel Sandler if (info != null) { 1044de7f739c15615d5564cefd22f60176cc45ae88eDaniel Sandler body.append("pid ").append(pid).append(":") 1054de7f739c15615d5564cefd22f60176cc45ae88eDaniel Sandler .append(" up=").append(info.getUptime()) 1064de7f739c15615d5564cefd22f60176cc45ae88eDaniel Sandler .append(" pss=").append(info.currentPss) 1074de7f739c15615d5564cefd22f60176cc45ae88eDaniel Sandler .append(" uss=").append(info.currentUss) 1084de7f739c15615d5564cefd22f60176cc45ae88eDaniel Sandler .append("\n"); 1094de7f739c15615d5564cefd22f60176cc45ae88eDaniel Sandler } 1104de7f739c15615d5564cefd22f60176cc45ae88eDaniel Sandler if (pid == myPid) { 1114de7f739c15615d5564cefd22f60176cc45ae88eDaniel Sandler final String path = String.format("%s/launcher-memory-%d.ahprof", 1124de7f739c15615d5564cefd22f60176cc45ae88eDaniel Sandler Environment.getExternalStorageDirectory(), 1134de7f739c15615d5564cefd22f60176cc45ae88eDaniel Sandler pid); 1144de7f739c15615d5564cefd22f60176cc45ae88eDaniel Sandler Log.v(TAG, "Dumping memory info for process " + pid + " to " + path); 1154de7f739c15615d5564cefd22f60176cc45ae88eDaniel Sandler try { 1164de7f739c15615d5564cefd22f60176cc45ae88eDaniel Sandler android.os.Debug.dumpHprofData(path); // will block 1174de7f739c15615d5564cefd22f60176cc45ae88eDaniel Sandler } catch (IOException e) { 1184de7f739c15615d5564cefd22f60176cc45ae88eDaniel Sandler Log.e(TAG, "error dumping memory:", e); 1194de7f739c15615d5564cefd22f60176cc45ae88eDaniel Sandler } 1204de7f739c15615d5564cefd22f60176cc45ae88eDaniel Sandler paths.add(path); 121a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandler } 1228540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler } 123a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandler 1248540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler String zipfile = zipUp(paths); 125a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandler 1268540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler if (zipfile == null) return; 1278540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler 1288540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler Intent shareIntent = new Intent(Intent.ACTION_SEND); 1298540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler shareIntent.setType("application/zip"); 1308540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler 1318540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler final PackageManager pm = context.getPackageManager(); 1324de7f739c15615d5564cefd22f60176cc45ae88eDaniel Sandler shareIntent.putExtra(Intent.EXTRA_SUBJECT, String.format("Launcher memory dump (%d)", myPid)); 1338540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler String appVersion; 1348540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler try { 1358540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler appVersion = pm.getPackageInfo(context.getPackageName(), 0).versionName; 1368540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler } catch (PackageManager.NameNotFoundException e) { 1378540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler appVersion = "?"; 138a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandler } 1398540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler 1408540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler body.append("\nApp version: ").append(appVersion).append("\nBuild: ").append(Build.DISPLAY).append("\n"); 1418540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler shareIntent.putExtra(Intent.EXTRA_TEXT, body.toString()); 1428540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler 1438540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler final File pathFile = new File(zipfile); 1448540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler final Uri pathUri = Uri.fromFile(pathFile); 1458540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler 1468540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler shareIntent.putExtra(Intent.EXTRA_STREAM, pathUri); 1478540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler context.startActivity(shareIntent); 148a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandler } 149a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandler 150a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandler @Override 151a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandler public void onStart() { 152a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandler super.onStart(); 1538540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler 154f8577a39058fcc07a390c650cf7b8c68949450d9Daniel Sandler startDump(this, new Runnable() { 155f8577a39058fcc07a390c650cf7b8c68949450d9Daniel Sandler @Override 156f8577a39058fcc07a390c650cf7b8c68949450d9Daniel Sandler public void run() { 157f8577a39058fcc07a390c650cf7b8c68949450d9Daniel Sandler finish(); 158f8577a39058fcc07a390c650cf7b8c68949450d9Daniel Sandler } 159f8577a39058fcc07a390c650cf7b8c68949450d9Daniel Sandler }); 160f8577a39058fcc07a390c650cf7b8c68949450d9Daniel Sandler } 161f8577a39058fcc07a390c650cf7b8c68949450d9Daniel Sandler 162f8577a39058fcc07a390c650cf7b8c68949450d9Daniel Sandler public static void startDump(final Context context) { 163f8577a39058fcc07a390c650cf7b8c68949450d9Daniel Sandler startDump(context, null); 164f8577a39058fcc07a390c650cf7b8c68949450d9Daniel Sandler } 165f8577a39058fcc07a390c650cf7b8c68949450d9Daniel Sandler 166f8577a39058fcc07a390c650cf7b8c68949450d9Daniel Sandler public static void startDump(final Context context, final Runnable andThen) { 1678540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler final ServiceConnection connection = new ServiceConnection() { 1688540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler public void onServiceConnected(ComponentName className, IBinder service) { 1698540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler Log.v(TAG, "service connected, dumping..."); 170f8577a39058fcc07a390c650cf7b8c68949450d9Daniel Sandler dumpHprofAndShare(context, 171f8577a39058fcc07a390c650cf7b8c68949450d9Daniel Sandler ((MemoryTracker.MemoryTrackerInterface) service).getService()); 172f8577a39058fcc07a390c650cf7b8c68949450d9Daniel Sandler context.unbindService(this); 173f8577a39058fcc07a390c650cf7b8c68949450d9Daniel Sandler if (andThen != null) andThen.run(); 1748540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler } 1758540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler 1768540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler public void onServiceDisconnected(ComponentName className) { 1778540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler } 1788540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler }; 1798540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler Log.v(TAG, "attempting to bind to memory tracker"); 180f8577a39058fcc07a390c650cf7b8c68949450d9Daniel Sandler context.bindService(new Intent(context, MemoryTracker.class), 1818540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler connection, Context.BIND_AUTO_CREATE); 182a127b7ad151dd1ae66d665a073e98984930c3d9dDaniel Sandler } 1838540bb8d72496dca3182ac091c2cafaaad597457Daniel Sandler} 184