diff options
Diffstat (limited to 'src/com/android/providers/contacts/debug/DataExporter.java')
-rw-r--r-- | src/com/android/providers/contacts/debug/DataExporter.java | 104 |
1 files changed, 88 insertions, 16 deletions
diff --git a/src/com/android/providers/contacts/debug/DataExporter.java b/src/com/android/providers/contacts/debug/DataExporter.java index 886314b..6771c1a 100644 --- a/src/com/android/providers/contacts/debug/DataExporter.java +++ b/src/com/android/providers/contacts/debug/DataExporter.java @@ -16,58 +16,129 @@ package com.android.providers.contacts.debug; +import com.android.providers.contacts.util.Hex; +import com.google.common.io.Closeables; + import android.content.Context; -import android.media.MediaScannerConnection; +import android.net.Uri; import android.util.Log; -import com.google.common.io.Closeables; - import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.security.SecureRandom; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; /** * Compress all files under the app data dir into a single zip file. + * + * Make sure not to output dump filenames anywhere, including logcat. */ public class DataExporter { private static String TAG = "DataExporter"; public static final String ZIP_MIME_TYPE = "application/zip"; + public static final String DUMP_FILE_DIRECTORY_NAME = "dumpedfiles"; + + public static final String OUT_FILE_SUFFIX = "-contacts-db.zip"; + /** - * Compress all files under the app data dir into a single zip file. + * Compress all files under the app data dir into a single zip file, and return the content:// + * URI to the file, which can be read via {@link DumpFileProvider}. */ - public static void exportData(Context context, File outFile) throws IOException { - outFile.delete(); - Log.i(TAG, "Outfile=" + outFile.getAbsolutePath()); + public static Uri exportData(Context context) throws IOException { + final String fileName = generateRandomName() + OUT_FILE_SUFFIX; + final File outFile = getOutputFile(context, fileName); + + // Remove all existing ones. + removeDumpFiles(context); + Log.i(TAG, "Dump started..."); + + ensureOutputDirectory(context); final ZipOutputStream os = new ZipOutputStream(new FileOutputStream(outFile)); try { - addDirectory(os, context.getFilesDir().getParentFile(), "contacts-files"); + addDirectory(context, os, context.getFilesDir().getParentFile(), "contacts-files"); } finally { Closeables.closeQuietly(os); } - // Tell the media scanner about the new file so that it is - // immediately available to the user. - MediaScannerConnection.scanFile(context, - new String[] {outFile.toString()}, - new String[] {ZIP_MIME_TYPE}, null); + Log.i(TAG, "Dump finished."); + return DumpFileProvider.AUTHORITY_URI.buildUpon().appendPath(fileName).build(); + } + + /** @return long random string for a file name */ + private static String generateRandomName() { + final SecureRandom rng = new SecureRandom(); + final byte[] random = new byte[256 / 8]; + rng.nextBytes(random); + + return Hex.encodeHex(random, true); + } + + private static File getOutputDirectory(Context context) { + return new File(context.getCacheDir(), DUMP_FILE_DIRECTORY_NAME); + } + + private static void ensureOutputDirectory(Context context) { + final File directory = getOutputDirectory(context); + if (!directory.exists()) { + directory.mkdir(); + } + } + + public static File getOutputFile(Context context, String fileName) { + return new File(getOutputDirectory(context), fileName); + } + + public static boolean dumpFileExists(Context context) { + return getOutputDirectory(context).exists(); + } + + public static void removeDumpFiles(Context context) { + removeFileOrDirectory(getOutputDirectory(context)); + } + + private static void removeFileOrDirectory(File file) { + if (!file.exists()) return; + + if (file.isFile()) { + Log.i(TAG, "Removing " + file); + file.delete(); + return; + } + + if (file.isDirectory()) { + for (File child : file.listFiles()) { + removeFileOrDirectory(child); + } + Log.i(TAG, "Removing " + file); + file.delete(); + } } /** * Add all files under {@code current} to {@code os} zip stream */ - private static void addDirectory(ZipOutputStream os, File current, String storedPath) - throws IOException { + private static void addDirectory(Context context, ZipOutputStream os, File current, + String storedPath) throws IOException { for (File child : current.listFiles()) { final String childStoredPath = storedPath + "/" + child.getName(); if (child.isDirectory()) { - addDirectory(os, child, childStoredPath); + // Don't need the cache directory, which also contains the dump files. + if (child.equals(context.getCacheDir())) { + continue; + } + // This check is redundant as the output directory should be in the cache dir, + // but just in case... + if (child.getName().equals(DUMP_FILE_DIRECTORY_NAME)) { + continue; + } + addDirectory(context, os, child, childStoredPath); } else if (child.isFile()) { addFile(os, child, childStoredPath); } else { @@ -82,6 +153,7 @@ public class DataExporter { */ private static void addFile(ZipOutputStream os, File current, String storedPath) throws IOException { + Log.i(TAG, "Adding " + current.getAbsolutePath() + " ..."); final InputStream is = new FileInputStream(current); os.putNextEntry(new ZipEntry(storedPath)); |