Merge "DropBoxManagerService: Don't store redundant information" into oc-mr1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
75590ffa84
@@ -28,4 +28,12 @@ public class ObjectUtils {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
@@ -29,18 +29,23 @@ import android.os.Debug;
|
||||
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.InputStreamReader;
|
||||
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 @@ public final class DropBoxManagerService extends SystemService {
|
||||
// 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 @@ public final class DropBoxManagerService extends SystemService {
|
||||
* @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 @@ public final class DropBoxManagerService extends SystemService {
|
||||
* @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 @@ public final class DropBoxManagerService extends SystemService {
|
||||
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 @@ public final class DropBoxManagerService extends SystemService {
|
||||
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 @@ public final class DropBoxManagerService extends SystemService {
|
||||
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 @@ public final class DropBoxManagerService extends SystemService {
|
||||
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 @@ public final class DropBoxManagerService extends SystemService {
|
||||
}
|
||||
} 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 @@ public final class DropBoxManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
/** 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 @@ public final class DropBoxManagerService extends SystemService {
|
||||
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 @@ public final class DropBoxManagerService extends SystemService {
|
||||
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 @@ public final class DropBoxManagerService extends SystemService {
|
||||
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 @@ public final class DropBoxManagerService extends SystemService {
|
||||
}
|
||||
|
||||
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 @@ public final class DropBoxManagerService extends SystemService {
|
||||
// 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 @@ public final class DropBoxManagerService extends SystemService {
|
||||
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 @@ public final class DropBoxManagerService extends SystemService {
|
||||
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 @@ public final class DropBoxManagerService extends SystemService {
|
||||
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);
|
||||
|
||||
@@ -18,18 +18,20 @@ package com.android.server;
|
||||
|
||||
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.io.InputStreamReader;
|
||||
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 @@ public class DropBoxTest extends AndroidTestCase {
|
||||
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 class DropBoxTest extends AndroidTestCase {
|
||||
|
||||
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 @@ public class DropBoxTest extends AndroidTestCase {
|
||||
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 @@ public class DropBoxTest extends AndroidTestCase {
|
||||
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 @@ public class DropBoxTest extends AndroidTestCase {
|
||||
// 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 class DropBoxTest extends AndroidTestCase {
|
||||
|
||||
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 class DropBoxTest extends AndroidTestCase {
|
||||
|
||||
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 @@ public class DropBoxTest extends AndroidTestCase {
|
||||
|
||||
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 @@ public class DropBoxTest extends AndroidTestCase {
|
||||
|
||||
// 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 class DropBoxTest extends AndroidTestCase {
|
||||
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 @@ public class DropBoxTest extends AndroidTestCase {
|
||||
|
||||
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 @@ public class DropBoxTest extends AndroidTestCase {
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user