Merge "DropBoxManagerService: Don't store redundant information" into oc-mr1-dev
am: 75590ffa84
Change-Id: Id0037c455e0e37f7896d06aeedda9b7cdca35f63
diff --git a/core/java/com/android/internal/util/ObjectUtils.java b/core/java/com/android/internal/util/ObjectUtils.java
index d109a5a..59e5a64 100644
--- a/core/java/com/android/internal/util/ObjectUtils.java
+++ b/core/java/com/android/internal/util/ObjectUtils.java
@@ -28,4 +28,12 @@
public static <T> T firstNotNull(@Nullable T a, @NonNull T b) {
return a != null ? a : Preconditions.checkNotNull(b);
}
+
+ public static <T extends Comparable> int compare(@Nullable T a, @Nullable T b) {
+ if (a != null) {
+ return (b != null) ? a.compareTo(b) : 1;
+ } else {
+ return (b != null) ? -1 : 0;
+ }
+ }
}
diff --git a/core/tests/utiltests/src/com/android/internal/util/ObjectUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/ObjectUtilsTest.java
new file mode 100644
index 0000000..443183e
--- /dev/null
+++ b/core/tests/utiltests/src/com/android/internal/util/ObjectUtilsTest.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2017 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 com.android.internal.util;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+@SmallTest
+public class ObjectUtilsTest extends AndroidTestCase {
+ public void testCompare() {
+ assertEquals(0, ObjectUtils.compare(null, null));
+ assertEquals(1, ObjectUtils.compare("a", null));
+ assertEquals(-1, ObjectUtils.compare(null, "a"));
+
+ assertEquals(0, ObjectUtils.compare("a", "a"));
+
+ assertEquals(-1, ObjectUtils.compare("a", "b"));
+ assertEquals(1, ObjectUtils.compare("b", "a"));
+ }
+}
diff --git a/services/core/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java
index e1756d1..1bf12c4 100644
--- a/services/core/java/com/android/server/DropBoxManagerService.java
+++ b/services/core/java/com/android/server/DropBoxManagerService.java
@@ -29,18 +29,23 @@
import android.os.DropBoxManager;
import android.os.FileUtils;
import android.os.Handler;
+import android.os.Looper;
import android.os.Message;
import android.os.StatFs;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
+import android.text.TextUtils;
import android.text.format.Time;
+import android.util.ArrayMap;
import android.util.Slog;
import libcore.io.IoUtils;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.IDropBoxManagerService;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.ObjectUtils;
import java.io.BufferedOutputStream;
import java.io.File;
@@ -52,7 +57,7 @@
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Objects;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.zip.GZIPOutputStream;
@@ -87,7 +92,7 @@
// Accounting of all currently written log files (set in init()).
private FileList mAllFiles = null;
- private HashMap<String, FileList> mFilesByTag = null;
+ private ArrayMap<String, FileList> mFilesByTag = null;
// Various bits of disk information
@@ -153,7 +158,7 @@
* @param context to use for receiving free space & gservices intents
*/
public DropBoxManagerService(final Context context) {
- this(context, new File("/data/system/dropbox"));
+ this(context, new File("/data/system/dropbox"), FgThread.get().getLooper());
}
/**
@@ -163,11 +168,12 @@
* @param context to use for receiving free space & gservices intents
* @param path to store drop box entries in
*/
- public DropBoxManagerService(final Context context, File path) {
+ @VisibleForTesting
+ public DropBoxManagerService(final Context context, File path, Looper looper) {
super(context);
mDropBoxDir = path;
mContentResolver = getContext().getContentResolver();
- mHandler = new Handler() {
+ mHandler = new Handler(looper) {
@Override
public void handleMessage(Message msg) {
if (msg.what == MSG_SEND_BROADCAST) {
@@ -338,11 +344,12 @@
if ((entry.flags & DropBoxManager.IS_EMPTY) != 0) {
return new DropBoxManager.Entry(entry.tag, entry.timestampMillis);
}
+ final File file = entry.getFile(mDropBoxDir);
try {
return new DropBoxManager.Entry(
- entry.tag, entry.timestampMillis, entry.file, entry.flags);
+ entry.tag, entry.timestampMillis, file, entry.flags);
} catch (IOException e) {
- Slog.e(TAG, "Can't read: " + entry.file, e);
+ Slog.wtf(TAG, "Can't read: " + file, e);
// Continue to next file
}
}
@@ -410,7 +417,9 @@
numFound++;
if (doPrint) out.append("========================================\n");
out.append(date).append(" ").append(entry.tag == null ? "(no tag)" : entry.tag);
- if (entry.file == null) {
+
+ final File file = entry.getFile(mDropBoxDir);
+ if (file == null) {
out.append(" (no file)\n");
continue;
} else if ((entry.flags & DropBoxManager.IS_EMPTY) != 0) {
@@ -420,12 +429,12 @@
out.append(" (");
if ((entry.flags & DropBoxManager.IS_GZIPPED) != 0) out.append("compressed ");
out.append((entry.flags & DropBoxManager.IS_TEXT) != 0 ? "text" : "data");
- out.append(", ").append(entry.file.length()).append(" bytes)\n");
+ out.append(", ").append(file.length()).append(" bytes)\n");
}
if (doFile || (doPrint && (entry.flags & DropBoxManager.IS_TEXT) == 0)) {
if (!doPrint) out.append(" ");
- out.append(entry.file.getPath()).append("\n");
+ out.append(file.getPath()).append("\n");
}
if ((entry.flags & DropBoxManager.IS_TEXT) != 0 && (doPrint || !doFile)) {
@@ -433,7 +442,7 @@
InputStreamReader isr = null;
try {
dbe = new DropBoxManager.Entry(
- entry.tag, entry.timestampMillis, entry.file, entry.flags);
+ entry.tag, entry.timestampMillis, file, entry.flags);
if (doPrint) {
isr = new InputStreamReader(dbe.getInputStream());
@@ -466,7 +475,7 @@
}
} catch (IOException e) {
out.append("*** ").append(e.toString()).append("\n");
- Slog.e(TAG, "Can't read: " + entry.file, e);
+ Slog.e(TAG, "Can't read: " + file, e);
} finally {
if (dbe != null) dbe.close();
if (isr != null) {
@@ -509,29 +518,37 @@
}
}
- /** Metadata describing an on-disk log file. */
- private static final class EntryFile implements Comparable<EntryFile> {
+ /**
+ * Metadata describing an on-disk log file.
+ *
+ * Note its instances do no have knowledge on what directory they're stored, just to save
+ * 4/8 bytes per instance. Instead, {@link #getFile} takes a directory so it can build a
+ * fullpath.
+ */
+ @VisibleForTesting
+ static final class EntryFile implements Comparable<EntryFile> {
public final String tag;
public final long timestampMillis;
public final int flags;
- public final File file;
public final int blocks;
/** Sorts earlier EntryFile instances before later ones. */
public final int compareTo(EntryFile o) {
- if (timestampMillis < o.timestampMillis) return -1;
- if (timestampMillis > o.timestampMillis) return 1;
- if (file != null && o.file != null) return file.compareTo(o.file);
- if (o.file != null) return -1;
- if (file != null) return 1;
- if (this == o) return 0;
- if (hashCode() < o.hashCode()) return -1;
- if (hashCode() > o.hashCode()) return 1;
- return 0;
+ int comp = Long.compare(timestampMillis, o.timestampMillis);
+ if (comp != 0) return comp;
+
+ comp = ObjectUtils.compare(tag, o.tag);
+ if (comp != 0) return comp;
+
+ comp = Integer.compare(flags, o.flags);
+ if (comp != 0) return comp;
+
+ return Integer.compare(hashCode(), o.hashCode());
}
/**
* Moves an existing temporary file to a new log filename.
+ *
* @param temp file to rename
* @param dir to store file in
* @param tag to use for new log file name
@@ -544,76 +561,94 @@
int flags, int blockSize) throws IOException {
if ((flags & DropBoxManager.IS_EMPTY) != 0) throw new IllegalArgumentException();
- this.tag = tag;
+ this.tag = TextUtils.safeIntern(tag);
this.timestampMillis = timestampMillis;
this.flags = flags;
- this.file = new File(dir, Uri.encode(tag) + "@" + timestampMillis +
- ((flags & DropBoxManager.IS_TEXT) != 0 ? ".txt" : ".dat") +
- ((flags & DropBoxManager.IS_GZIPPED) != 0 ? ".gz" : ""));
- if (!temp.renameTo(this.file)) {
- throw new IOException("Can't rename " + temp + " to " + this.file);
+ final File file = this.getFile(dir);
+ if (!temp.renameTo(file)) {
+ throw new IOException("Can't rename " + temp + " to " + file);
}
- this.blocks = (int) ((this.file.length() + blockSize - 1) / blockSize);
+ this.blocks = (int) ((file.length() + blockSize - 1) / blockSize);
}
/**
* Creates a zero-length tombstone for a file whose contents were lost.
+ *
* @param dir to store file in
* @param tag to use for new log file name
* @param timestampMillis of log entry
* @throws IOException if the file can't be created.
*/
public EntryFile(File dir, String tag, long timestampMillis) throws IOException {
- this.tag = tag;
+ this.tag = TextUtils.safeIntern(tag);
this.timestampMillis = timestampMillis;
this.flags = DropBoxManager.IS_EMPTY;
- this.file = new File(dir, Uri.encode(tag) + "@" + timestampMillis + ".lost");
this.blocks = 0;
- new FileOutputStream(this.file).close();
+ new FileOutputStream(getFile(dir)).close();
}
/**
* Extracts metadata from an existing on-disk log filename.
+ *
+ * Note when a filename is not recognizable, it will create an instance that
+ * {@link #hasFile()} would return false on, and also remove the file.
+ *
* @param file name of existing log file
* @param blockSize to use for space accounting
*/
public EntryFile(File file, int blockSize) {
- this.file = file;
- this.blocks = (int) ((this.file.length() + blockSize - 1) / blockSize);
+
+ boolean parseFailure = false;
String name = file.getName();
- int at = name.lastIndexOf('@');
- if (at < 0) {
- this.tag = null;
- this.timestampMillis = 0;
- this.flags = DropBoxManager.IS_EMPTY;
- return;
- }
-
int flags = 0;
- this.tag = Uri.decode(name.substring(0, at));
- if (name.endsWith(".gz")) {
- flags |= DropBoxManager.IS_GZIPPED;
- name = name.substring(0, name.length() - 3);
- }
- if (name.endsWith(".lost")) {
- flags |= DropBoxManager.IS_EMPTY;
- name = name.substring(at + 1, name.length() - 5);
- } else if (name.endsWith(".txt")) {
- flags |= DropBoxManager.IS_TEXT;
- name = name.substring(at + 1, name.length() - 4);
- } else if (name.endsWith(".dat")) {
- name = name.substring(at + 1, name.length() - 4);
+ String tag = null;
+ long millis = 0;
+
+ final int at = name.lastIndexOf('@');
+ if (at < 0) {
+ parseFailure = true;
} else {
+ tag = Uri.decode(name.substring(0, at));
+ if (name.endsWith(".gz")) {
+ flags |= DropBoxManager.IS_GZIPPED;
+ name = name.substring(0, name.length() - 3);
+ }
+ if (name.endsWith(".lost")) {
+ flags |= DropBoxManager.IS_EMPTY;
+ name = name.substring(at + 1, name.length() - 5);
+ } else if (name.endsWith(".txt")) {
+ flags |= DropBoxManager.IS_TEXT;
+ name = name.substring(at + 1, name.length() - 4);
+ } else if (name.endsWith(".dat")) {
+ name = name.substring(at + 1, name.length() - 4);
+ } else {
+ parseFailure = true;
+ }
+ if (!parseFailure) {
+ try {
+ millis = Long.parseLong(name);
+ } catch (NumberFormatException e) {
+ parseFailure = true;
+ }
+ }
+ }
+ if (parseFailure) {
+ Slog.wtf(TAG, "Invalid filename: " + file);
+
+ // Remove the file and return an empty instance.
+ file.delete();
+ this.tag = null;
this.flags = DropBoxManager.IS_EMPTY;
this.timestampMillis = 0;
+ this.blocks = 0;
return;
}
- this.flags = flags;
- long millis;
- try { millis = Long.parseLong(name); } catch (NumberFormatException e) { millis = 0; }
+ this.blocks = (int) ((file.length() + blockSize - 1) / blockSize);
+ this.tag = TextUtils.safeIntern(tag);
+ this.flags = flags;
this.timestampMillis = millis;
}
@@ -625,9 +660,50 @@
this.tag = null;
this.timestampMillis = millis;
this.flags = DropBoxManager.IS_EMPTY;
- this.file = null;
this.blocks = 0;
}
+
+ /**
+ * @return whether an entry actually has a backing file, or it's an empty "tombstone"
+ * entry.
+ */
+ public boolean hasFile() {
+ return tag != null;
+ }
+
+ /** @return File extension for the flags. */
+ private String getExtension() {
+ if ((flags & DropBoxManager.IS_EMPTY) != 0) {
+ return ".lost";
+ }
+ return ((flags & DropBoxManager.IS_TEXT) != 0 ? ".txt" : ".dat") +
+ ((flags & DropBoxManager.IS_GZIPPED) != 0 ? ".gz" : "");
+ }
+
+ /**
+ * @return filename for this entry without the pathname.
+ */
+ public String getFilename() {
+ return hasFile() ? Uri.encode(tag) + "@" + timestampMillis + getExtension() : null;
+ }
+
+ /**
+ * Get a full-path {@link File} representing this entry.
+ * @param dir Parent directly. The caller needs to pass it because {@link EntryFile}s don't
+ * know in which directory they're stored.
+ */
+ public File getFile(File dir) {
+ return hasFile() ? new File(dir, getFilename()) : null;
+ }
+
+ /**
+ * If an entry has a backing file, remove it.
+ */
+ public void deleteFile(File dir) {
+ if (hasFile()) {
+ getFile(dir).delete();
+ }
+ }
}
///////////////////////////////////////////////////////////////////////////
@@ -651,7 +727,7 @@
if (files == null) throw new IOException("Can't list files: " + mDropBoxDir);
mAllFiles = new FileList();
- mFilesByTag = new HashMap<String, FileList>();
+ mFilesByTag = new ArrayMap<>();
// Scan pre-existing files.
for (File file : files) {
@@ -662,16 +738,12 @@
}
EntryFile entry = new EntryFile(file, mBlockSize);
- if (entry.tag == null) {
- Slog.w(TAG, "Unrecognized file: " + file);
- continue;
- } else if (entry.timestampMillis == 0) {
- Slog.w(TAG, "Invalid filename: " + file);
- file.delete();
- continue;
- }
- enrollEntry(entry);
+ if (entry.hasFile()) {
+ // Enroll only when the filename is valid. Otherwise the above constructor
+ // has removed the file already.
+ enrollEntry(entry);
+ }
}
}
}
@@ -684,11 +756,11 @@
// mFilesByTag is used for trimming, so don't list empty files.
// (Zero-length/lost files are trimmed by date from mAllFiles.)
- if (entry.tag != null && entry.file != null && entry.blocks > 0) {
+ if (entry.hasFile() && entry.blocks > 0) {
FileList tagFiles = mFilesByTag.get(entry.tag);
if (tagFiles == null) {
tagFiles = new FileList();
- mFilesByTag.put(entry.tag, tagFiles);
+ mFilesByTag.put(TextUtils.safeIntern(entry.tag), tagFiles);
}
tagFiles.contents.add(entry);
tagFiles.blocks += entry.blocks;
@@ -722,8 +794,8 @@
tagFiles.blocks -= late.blocks;
}
if ((late.flags & DropBoxManager.IS_EMPTY) == 0) {
- enrollEntry(new EntryFile(
- late.file, mDropBoxDir, late.tag, t++, late.flags, mBlockSize));
+ enrollEntry(new EntryFile(late.getFile(mDropBoxDir), mDropBoxDir,
+ late.tag, t++, late.flags, mBlockSize));
} else {
enrollEntry(new EntryFile(mDropBoxDir, late.tag, t++));
}
@@ -757,7 +829,7 @@
FileList tag = mFilesByTag.get(entry.tag);
if (tag != null && tag.contents.remove(entry)) tag.blocks -= entry.blocks;
if (mAllFiles.contents.remove(entry)) mAllFiles.blocks -= entry.blocks;
- if (entry.file != null) entry.file.delete();
+ entry.deleteFile(mDropBoxDir);
}
// Compute overall quota (a fraction of available free space) in blocks.
@@ -823,7 +895,7 @@
if (mAllFiles.contents.remove(entry)) mAllFiles.blocks -= entry.blocks;
try {
- if (entry.file != null) entry.file.delete();
+ entry.deleteFile(mDropBoxDir);
enrollEntry(new EntryFile(mDropBoxDir, entry.tag, entry.timestampMillis));
} catch (IOException e) {
Slog.e(TAG, "Can't write tombstone file", e);
diff --git a/services/tests/servicestests/src/com/android/server/DropBoxTest.java b/services/tests/servicestests/src/com/android/server/DropBoxTest.java
index 7f28d44..56773e8 100644
--- a/services/tests/servicestests/src/com/android/server/DropBoxTest.java
+++ b/services/tests/servicestests/src/com/android/server/DropBoxTest.java
@@ -18,18 +18,20 @@
import android.content.ContentResolver;
import android.content.Context;
+import android.content.ContextWrapper;
import android.content.Intent;
import android.os.DropBoxManager;
+import android.os.Looper;
import android.os.Parcel;
-import android.os.Parcelable;
import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
import android.os.Process;
-import android.os.ServiceManager;
import android.os.StatFs;
+import android.os.UserHandle;
import android.provider.Settings;
import android.test.AndroidTestCase;
-import com.android.server.DropBoxManagerService;
+import com.android.server.DropBoxManagerService.EntryFile;
import java.io.BufferedReader;
import java.io.File;
@@ -41,8 +43,28 @@
import java.util.Random;
import java.util.zip.GZIPOutputStream;
-/** Test {@link DropBoxManager} functionality. */
+/**
+ * Test {@link DropBoxManager} functionality.
+ *
+ * Run with:
+ * bit FrameworksServicesTests:com.android.server.DropBoxTest
+ */
public class DropBoxTest extends AndroidTestCase {
+ private Context mContext;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mContext = new ContextWrapper(super.getContext()) {
+ @Override
+ public void sendBroadcastAsUser(Intent intent,
+ UserHandle user, String receiverPermission) {
+ // Don't actually send broadcasts.
+ }
+ };
+ }
+
public void tearDown() throws Exception {
ContentResolver cr = getContext().getContentResolver();
Settings.Global.putString(cr, Settings.Global.DROPBOX_AGE_SECONDS, "");
@@ -51,9 +73,15 @@
Settings.Global.putString(cr, Settings.Global.DROPBOX_TAG_PREFIX + "DropBoxTest", "");
}
+ @Override
+ public Context getContext() {
+ return mContext;
+ }
+
public void testAddText() throws Exception {
File dir = getEmptyDir("testAddText");
- DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+ DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
+ Looper.getMainLooper());
DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
long before = System.currentTimeMillis();
@@ -89,15 +117,19 @@
public void testAddData() throws Exception {
File dir = getEmptyDir("testAddData");
- DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+ DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
+ Looper.getMainLooper());
DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
long before = System.currentTimeMillis();
+ Thread.sleep(1);
dropbox.addData("DropBoxTest", "TEST".getBytes(), 0);
+ Thread.sleep(1);
long after = System.currentTimeMillis();
DropBoxManager.Entry e = dropbox.getNextEntry("DropBoxTest", before);
- assertTrue(null == dropbox.getNextEntry("DropBoxTest", e.getTimeMillis()));
+ assertNotNull(e);
+ assertNull(dropbox.getNextEntry("DropBoxTest", e.getTimeMillis()));
assertEquals("DropBoxTest", e.getTag());
assertTrue(e.getTimeMillis() >= before);
@@ -114,10 +146,12 @@
File dir = getEmptyDir("testAddFile");
long before = System.currentTimeMillis();
- File f0 = new File(dir, "f0.txt");
- File f1 = new File(dir, "f1.txt.gz");
- File f2 = new File(dir, "f2.dat");
- File f3 = new File(dir, "f2.dat.gz");
+ File clientDir = getEmptyDir("testAddFile_client");
+
+ File f0 = new File(clientDir, "f0.txt");
+ File f1 = new File(clientDir, "f1.txt.gz");
+ File f2 = new File(clientDir, "f2.dat");
+ File f3 = new File(clientDir, "f2.dat.gz");
FileWriter w0 = new FileWriter(f0);
GZIPOutputStream gz1 = new GZIPOutputStream(new FileOutputStream(f1));
@@ -134,7 +168,8 @@
os2.close();
gz3.close();
- DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+ DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
+ Looper.getMainLooper());
DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
dropbox.addFile("DropBoxTest", f0, DropBoxManager.IS_TEXT);
@@ -200,7 +235,8 @@
// Tombstone in the far future
new FileOutputStream(new File(dir, "DropBoxTest@" + (before + 100002) + ".lost")).close();
- DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+ DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
+ Looper.getMainLooper());
DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
// Until a write, the timestamps are taken at face value
@@ -251,7 +287,8 @@
public void testIsTagEnabled() throws Exception {
File dir = getEmptyDir("testIsTagEnabled");
- DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+ DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
+ Looper.getMainLooper());
DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
long before = System.currentTimeMillis();
@@ -284,7 +321,8 @@
public void testGetNextEntry() throws Exception {
File dir = getEmptyDir("testGetNextEntry");
- DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+ DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
+ Looper.getMainLooper());
DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
long before = System.currentTimeMillis();
@@ -346,7 +384,8 @@
final int overhead = 64;
long before = System.currentTimeMillis();
- DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+ DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
+ Looper.getMainLooper());
DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
addRandomEntry(dropbox, "DropBoxTest0", blockSize - overhead);
@@ -440,7 +479,8 @@
// Write one normal entry and another so big that it is instantly tombstoned
long before = System.currentTimeMillis();
- DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+ DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
+ Looper.getMainLooper());
DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
dropbox.addText("DropBoxTest", "TEST");
@@ -471,7 +511,8 @@
public void testFileCountLimits() throws Exception {
File dir = getEmptyDir("testFileCountLimits");
- DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+ DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
+ Looper.getMainLooper());
DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
dropbox.addText("DropBoxTest", "TEST0");
dropbox.addText("DropBoxTest", "TEST1");
@@ -524,7 +565,8 @@
File dir = new File(getEmptyDir("testCreateDropBoxManagerWith"), "InvalidDirectory");
new FileOutputStream(dir).close(); // Create an empty file
- DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+ DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
+ Looper.getMainLooper());
DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
dropbox.addText("DropBoxTest", "should be ignored");
@@ -735,6 +777,223 @@
assertTrue(after < before + 20);
}
+ public void testEntryFile() throws Exception {
+ File fromDir = getEmptyDir("testEntryFile_from");
+ File toDir = getEmptyDir("testEntryFile_to");
+
+ {
+ File f = new File(fromDir, "f0.txt");
+ try (FileWriter w = new FileWriter(f)) {
+ w.write("abc");
+ }
+
+ EntryFile e = new EntryFile(f, toDir, "tag:!", 12345, DropBoxManager.IS_TEXT, 1024);
+
+ assertEquals("tag:!", e.tag);
+ assertEquals(12345, e.timestampMillis);
+ assertEquals(DropBoxManager.IS_TEXT, e.flags);
+ assertEquals(1, e.blocks);
+
+ assertFalse(f.exists()); // Because it should be renamed.
+
+ assertTrue(e.hasFile());
+ assertEquals(new File(toDir, "tag%3A!@12345.txt"), e.getFile(toDir));
+ assertTrue(e.getFile(toDir).exists());
+ }
+ // Same test with gzip.
+ {
+ File f = new File(fromDir, "f0.txt.gz"); // It's a lie; it's not actually gz.
+ try (FileWriter w = new FileWriter(f)) {
+ w.write("abc");
+ }
+
+ EntryFile e = new EntryFile(f, toDir, "tag:!", 12345,
+ DropBoxManager.IS_TEXT | DropBoxManager.IS_GZIPPED, 1024);
+
+ assertEquals("tag:!", e.tag);
+
+ assertFalse(f.exists()); // Because it should be renamed.
+
+ assertTrue(e.hasFile());
+ assertEquals(new File(toDir, "tag%3A!@12345.txt.gz"), e.getFile(toDir));
+ assertTrue(e.getFile(toDir).exists());
+
+ }
+ // binary, gzip.
+ {
+ File f = new File(fromDir, "f0.dat.gz"); // It's a lie; it's not actually gz.
+ try (FileWriter w = new FileWriter(f)) {
+ w.write("abc");
+ }
+
+ EntryFile e = new EntryFile(f, toDir, "tag:!", 12345,
+ DropBoxManager.IS_GZIPPED, 1024);
+
+ assertEquals("tag:!", e.tag);
+
+ assertFalse(f.exists()); // Because it should be renamed.
+
+ assertTrue(e.hasFile());
+ assertEquals(new File(toDir, "tag%3A!@12345.dat.gz"), e.getFile(toDir));
+ assertTrue(e.getFile(toDir).exists());
+
+ }
+
+ // Tombstone.
+ {
+ EntryFile e = new EntryFile(toDir, "tag:!", 12345);
+
+ assertEquals("tag:!", e.tag);
+ assertEquals(12345, e.timestampMillis);
+ assertEquals(DropBoxManager.IS_EMPTY, e.flags);
+ assertEquals(0, e.blocks);
+
+ assertTrue(e.hasFile());
+ assertEquals(new File(toDir, "tag%3A!@12345.lost"), e.getFile(toDir));
+ assertTrue(e.getFile(toDir).exists());
+ }
+
+ // From existing files.
+ {
+ File f = new File(fromDir, "tag%3A!@12345.dat");
+ f.createNewFile();
+
+ EntryFile e = new EntryFile(f, 1024);
+
+ assertEquals("tag:!", e.tag);
+ assertEquals(12345, e.timestampMillis);
+ assertEquals(0, e.flags);
+ assertEquals(0, e.blocks);
+
+ assertTrue(f.exists());
+ }
+ {
+ File f = new File(fromDir, "tag%3A!@12345.dat.gz");
+ f.createNewFile();
+
+ EntryFile e = new EntryFile(f, 1024);
+
+ assertEquals("tag:!", e.tag);
+ assertEquals(12345, e.timestampMillis);
+ assertEquals(DropBoxManager.IS_GZIPPED, e.flags);
+ assertEquals(0, e.blocks);
+
+ assertTrue(f.exists());
+ }
+ {
+ File f = new File(fromDir, "tag%3A!@12345.txt");
+ try (FileWriter w = new FileWriter(f)) {
+ w.write(new char[1024]);
+ }
+
+ EntryFile e = new EntryFile(f, 1024);
+
+ assertEquals("tag:!", e.tag);
+ assertEquals(12345, e.timestampMillis);
+ assertEquals(DropBoxManager.IS_TEXT, e.flags);
+ assertEquals(1, e.blocks);
+
+ assertTrue(f.exists());
+ }
+ {
+ File f = new File(fromDir, "tag%3A!@12345.txt.gz");
+ try (FileWriter w = new FileWriter(f)) {
+ w.write(new char[1025]);
+ }
+
+ EntryFile e = new EntryFile(f, 1024);
+
+ assertEquals("tag:!", e.tag);
+ assertEquals(12345, e.timestampMillis);
+ assertEquals(DropBoxManager.IS_TEXT | DropBoxManager.IS_GZIPPED, e.flags);
+ assertEquals(2, e.blocks);
+
+ assertTrue(f.exists());
+ }
+ {
+ File f = new File(fromDir, "tag%3A!@12345.lost");
+ f.createNewFile();
+
+ EntryFile e = new EntryFile(f, 1024);
+
+ assertEquals("tag:!", e.tag);
+ assertEquals(12345, e.timestampMillis);
+ assertEquals(DropBoxManager.IS_EMPTY, e.flags);
+ assertEquals(0, e.blocks);
+
+ assertTrue(f.exists());
+ }
+ {
+ File f = new File(fromDir, "@12345.dat"); // Empty tag -- this actually works.
+ f.createNewFile();
+
+ EntryFile e = new EntryFile(f, 1024);
+
+ assertEquals("", e.tag);
+ assertEquals(12345, e.timestampMillis);
+ assertEquals(0, e.flags);
+ assertEquals(0, e.blocks);
+
+ assertTrue(f.exists());
+ }
+ // From invalid filenames.
+ {
+ File f = new File(fromDir, "tag.dat"); // No @.
+ f.createNewFile();
+
+ EntryFile e = new EntryFile(f, 1024);
+
+ assertEquals(null, e.tag);
+ assertEquals(0, e.timestampMillis);
+ assertEquals(DropBoxManager.IS_EMPTY, e.flags);
+ assertEquals(0, e.blocks);
+
+ assertFalse(f.exists());
+ }
+ {
+ File f = new File(fromDir, "tag@.dat"); // Invalid timestamp.
+ f.createNewFile();
+
+ EntryFile e = new EntryFile(f, 1024);
+
+ assertEquals(null, e.tag);
+ assertEquals(0, e.timestampMillis);
+ assertEquals(DropBoxManager.IS_EMPTY, e.flags);
+ assertEquals(0, e.blocks);
+
+ assertFalse(f.exists());
+ }
+ {
+ File f = new File(fromDir, "tag@12345.daxt"); // Invalid extension.
+ f.createNewFile();
+
+ EntryFile e = new EntryFile(f, 1024);
+
+ assertEquals(null, e.tag);
+ assertEquals(0, e.timestampMillis);
+ assertEquals(DropBoxManager.IS_EMPTY, e.flags);
+ assertEquals(0, e.blocks);
+
+ assertFalse(f.exists());
+ }
+ }
+
+ public void testCompareEntries() {
+ File dir = getEmptyDir("testCompareEntries");
+ assertEquals(-1,
+ new EntryFile(new File(dir, "aaa@100.dat"), 1).compareTo(
+ new EntryFile(new File(dir, "bbb@200.dat"), 1)));
+ assertEquals(1,
+ new EntryFile(new File(dir, "aaa@200.dat"), 1).compareTo(
+ new EntryFile(new File(dir, "bbb@100.dat"), 1)));
+ assertEquals(-1,
+ new EntryFile(new File(dir, "aaa@100.dat"), 1).compareTo(
+ new EntryFile(new File(dir, "bbb@100.dat"), 1)));
+ assertEquals(1,
+ new EntryFile(new File(dir, "bbb@100.dat"), 1).compareTo(
+ new EntryFile(new File(dir, "aaa@100.dat"), 1)));
+ }
+
private void addRandomEntry(DropBoxManager dropbox, String tag, int size) throws Exception {
byte[] bytes = new byte[size];
new Random(System.currentTimeMillis()).nextBytes(bytes);