1 /*
2  * Copyright (C) 2009 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 
17 package com.android.server;
18 
19 import android.content.ContentResolver;
20 import android.content.Context;
21 import android.content.ContextWrapper;
22 import android.content.Intent;
23 import android.os.Bundle;
24 import android.os.DropBoxManager;
25 import android.os.Looper;
26 import android.os.Parcel;
27 import android.os.ParcelFileDescriptor;
28 import android.os.Parcelable;
29 import android.os.Process;
30 import android.os.StatFs;
31 import android.os.UserHandle;
32 import android.provider.Settings;
33 import android.test.AndroidTestCase;
34 
35 import com.android.server.DropBoxManagerInternal.EntrySource;
36 import com.android.server.DropBoxManagerService.EntryFile;
37 
38 import libcore.io.Streams;
39 
40 import java.io.BufferedReader;
41 import java.io.File;
42 import java.io.FileDescriptor;
43 import java.io.FileOutputStream;
44 import java.io.FileWriter;
45 import java.io.IOException;
46 import java.io.InputStream;
47 import java.io.InputStreamReader;
48 import java.nio.charset.StandardCharsets;
49 import java.util.Random;
50 import java.util.zip.GZIPOutputStream;
51 
52 /**
53  * Test {@link DropBoxManager} functionality.
54  *
55  * Run with:
56  * bit FrameworksServicesTests:com.android.server.DropBoxTest
57  */
58 public class DropBoxTest extends AndroidTestCase {
59     private Context mContext;
60 
61     @Override
setUp()62     protected void setUp() throws Exception {
63         super.setUp();
64 
65         LocalServices.removeServiceForTest(DropBoxManagerInternal.class);
66 
67         mContext = new ContextWrapper(super.getContext()) {
68             @Override
69             public void sendBroadcastAsUser(Intent intent,
70                     UserHandle user, String receiverPermission, Bundle options) {
71                 // Don't actually send broadcasts.
72             }
73         };
74     }
75 
tearDown()76     public void tearDown() throws Exception {
77         ContentResolver cr = getContext().getContentResolver();
78         Settings.Global.putString(cr, Settings.Global.DROPBOX_AGE_SECONDS, "");
79         Settings.Global.putString(cr, Settings.Global.DROPBOX_MAX_FILES, "");
80         Settings.Global.putString(cr, Settings.Global.DROPBOX_QUOTA_KB, "");
81         Settings.Global.putString(cr, Settings.Global.DROPBOX_TAG_PREFIX + "DropBoxTest", "");
82     }
83 
84     @Override
getContext()85     public Context getContext() {
86         return mContext;
87     }
88 
testAddText()89     public void testAddText() throws Exception {
90         File dir = getEmptyDir("testAddText");
91         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
92                 Looper.getMainLooper());
93         DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
94 
95         long before = System.currentTimeMillis();
96         Thread.sleep(5);
97         dropbox.addText("DropBoxTest", "TEST0");
98         Thread.sleep(5);
99         long between = System.currentTimeMillis();
100         Thread.sleep(5);
101         dropbox.addText("DropBoxTest", "TEST1");
102         dropbox.addText("DropBoxTest", "TEST2");
103         Thread.sleep(5);
104         long after = System.currentTimeMillis();
105 
106         DropBoxManager.Entry e0 = dropbox.getNextEntry("DropBoxTest", before);
107         DropBoxManager.Entry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis());
108         DropBoxManager.Entry e2 = dropbox.getNextEntry("DropBoxTest", e1.getTimeMillis());
109         assertTrue(null == dropbox.getNextEntry("DropBoxTest", e2.getTimeMillis()));
110 
111         assertTrue(e0.getTimeMillis() > before);
112         assertTrue(e0.getTimeMillis() < between);
113         assertTrue(e1.getTimeMillis() > between);
114         assertTrue(e1.getTimeMillis() < e2.getTimeMillis());
115         assertTrue(e2.getTimeMillis() < after);
116 
117         assertEquals("TEST0", e0.getText(80));
118         assertEquals("TEST1", e1.getText(80));
119         assertEquals("TES", e2.getText(3));
120 
121         e0.close();
122         e1.close();
123         e2.close();
124     }
125 
126     public void testAddData() throws Exception {
127         File dir = getEmptyDir("testAddData");
128         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
129                 Looper.getMainLooper());
130         DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
131 
132         long before = System.currentTimeMillis();
133         Thread.sleep(1);
134         dropbox.addData("DropBoxTest", "TEST".getBytes(), 0);
135         Thread.sleep(1);
136         long after = System.currentTimeMillis();
137 
138         DropBoxManager.Entry e = dropbox.getNextEntry("DropBoxTest", before);
139         assertNotNull(e);
140         assertNull(dropbox.getNextEntry("DropBoxTest", e.getTimeMillis()));
141 
142         assertEquals("DropBoxTest", e.getTag());
143         assertTrue(e.getTimeMillis() >= before);
144         assertEquals(0, e.getFlags());
145         assertTrue(null == e.getText(80));
146 
147         byte[] buf = new byte[80];
148         assertEquals("TEST", new String(buf, 0, e.getInputStream().read(buf)));
149 
150         e.close();
151     }
152 
153     public void testAddFile() throws Exception {
154         File dir = getEmptyDir("testAddFile");
155         long before = System.currentTimeMillis();
156 
157         File clientDir = getEmptyDir("testAddFile_client");
158 
159         File f0 = new File(clientDir, "f0.txt");
160         File f1 = new File(clientDir, "f1.txt.gz");
161         File f2 = new File(clientDir, "f2.dat");
162         File f3 = new File(clientDir, "f2.dat.gz");
163 
164         FileWriter w0 = new FileWriter(f0);
165         GZIPOutputStream gz1 = new GZIPOutputStream(new FileOutputStream(f1));
166         FileOutputStream os2 = new FileOutputStream(f2);
167         GZIPOutputStream gz3 = new GZIPOutputStream(new FileOutputStream(f3));
168 
169         w0.write("FILE0");
170         gz1.write("FILE1".getBytes());
171         os2.write("DATA2".getBytes());
172         gz3.write("DATA3".getBytes());
173 
174         w0.close();
175         gz1.close();
176         os2.close();
177         gz3.close();
178 
179         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
180                 Looper.getMainLooper());
181         DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
182 
183         dropbox.addFile("DropBoxTest", f0, DropBoxManager.IS_TEXT);
184         dropbox.addFile("DropBoxTest", f1, DropBoxManager.IS_TEXT | DropBoxManager.IS_GZIPPED);
185         dropbox.addFile("DropBoxTest", f2, 0);
186         dropbox.addFile("DropBoxTest", f3, DropBoxManager.IS_GZIPPED);
187 
188         DropBoxManager.Entry e0 = dropbox.getNextEntry("DropBoxTest", before);
189         DropBoxManager.Entry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis());
190         DropBoxManager.Entry e2 = dropbox.getNextEntry("DropBoxTest", e1.getTimeMillis());
191         DropBoxManager.Entry e3 = dropbox.getNextEntry("DropBoxTest", e2.getTimeMillis());
192         assertTrue(null == dropbox.getNextEntry("DropBoxTest", e3.getTimeMillis()));
193 
194         assertTrue(e0.getTimeMillis() > before);
195         assertTrue(e1.getTimeMillis() > e0.getTimeMillis());
196         assertTrue(e2.getTimeMillis() > e1.getTimeMillis());
197         assertTrue(e3.getTimeMillis() > e2.getTimeMillis());
198 
199         assertEquals(DropBoxManager.IS_TEXT, e0.getFlags());
200         assertEquals(DropBoxManager.IS_TEXT, e1.getFlags());
201         assertEquals(0, e2.getFlags());
202         assertEquals(0, e3.getFlags());
203 
204         assertEquals("FILE0", e0.getText(80));
205 
206         byte[] buf1 = new byte[80];
207         assertEquals("FILE1", new String(buf1, 0, e1.getInputStream().read(buf1)));
208 
209         assertTrue(null == e2.getText(80));
210         byte[] buf2 = new byte[80];
211         assertEquals("DATA2", new String(buf2, 0, e2.getInputStream().read(buf2)));
212 
213         assertTrue(null == e3.getText(80));
214         byte[] buf3 = new byte[80];
215         assertEquals("DATA3", new String(buf3, 0, e3.getInputStream().read(buf3)));
216 
217         e0.close();
218         e1.close();
219         e2.close();
220         e3.close();
221     }
222 
testAddEntry_Success()223     public void testAddEntry_Success() throws Exception {
224         File dir = getEmptyDir("testAddEntry");
225         long before = System.currentTimeMillis();
226 
227         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
228                 Looper.getMainLooper());
229         DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
230 
231         LocalServices.getService(DropBoxManagerInternal.class).addEntry("DropBoxTest",
232                 new EntrySource() {
233                     @Override
234                     public void writeTo(FileDescriptor fd) throws IOException {
235                         try (FileOutputStream out = new FileOutputStream(fd)) {
236                             out.write("test".getBytes(StandardCharsets.UTF_8));
237                         }
238                     }
239 
240                     @Override
241                     public void close() throws IOException {
242                     }
243 
244                     @Override
245                     public long length() {
246                         return 0;
247                     }
248                 }, DropBoxManager.IS_TEXT);
249 
250         DropBoxManager.Entry entry = dropbox.getNextEntry("DropBoxTest", before);
251         assertEquals(DropBoxManager.IS_TEXT, entry.getFlags());
252         assertEquals("test", new String(Streams.readFully(entry.getInputStream())));
253     }
254 
testAddEntry_Failure()255     public void testAddEntry_Failure() throws Exception {
256         File dir = getEmptyDir("testAddEntry");
257         long before = System.currentTimeMillis();
258 
259         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
260                 Looper.getMainLooper());
261         DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
262 
263         LocalServices.getService(DropBoxManagerInternal.class).addEntry("DropBoxTest",
264                 new EntrySource() {
265                     @Override
266                     public void writeTo(FileDescriptor fd) throws IOException {
267                         throw new IOException();
268                     }
269 
270                     @Override
271                     public void close() throws IOException {
272                     }
273 
274                     @Override
275                     public long length() {
276                         return 0;
277                     }
278                 }, DropBoxManager.IS_TEXT);
279 
280         DropBoxManager.Entry entry = dropbox.getNextEntry("DropBoxTest", before);
281         assertNull(entry);
282     }
283 
testAddEntriesInTheFuture()284     public void testAddEntriesInTheFuture() throws Exception {
285         File dir = getEmptyDir("testAddEntriesInTheFuture");
286         long before = System.currentTimeMillis();
287 
288         // Near future: should be allowed to persist
289         FileWriter w0 = new FileWriter(new File(dir, "DropBoxTest@" + (before + 5000) + ".txt"));
290         w0.write("FUTURE0");
291         w0.close();
292 
293         // Far future: should be collapsed
294         FileWriter w1 = new FileWriter(new File(dir, "DropBoxTest@" + (before + 100000) + ".txt"));
295         w1.write("FUTURE1");
296         w1.close();
297 
298         // Another far future item, this one gzipped
299         File f2 = new File(dir, "DropBoxTest@" + (before + 100001) + ".txt.gz");
300         GZIPOutputStream gz2 = new GZIPOutputStream(new FileOutputStream(f2));
301         gz2.write("FUTURE2".getBytes());
302         gz2.close();
303 
304         // Tombstone in the far future
305         new FileOutputStream(new File(dir, "DropBoxTest@" + (before + 100002) + ".lost")).close();
306 
307         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
308                 Looper.getMainLooper());
309         DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
310 
311         // Until a write, the timestamps are taken at face value
312         DropBoxManager.Entry e0 = dropbox.getNextEntry(null, before);
313         DropBoxManager.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
314         DropBoxManager.Entry e2 = dropbox.getNextEntry(null, e1.getTimeMillis());
315         DropBoxManager.Entry e3 = dropbox.getNextEntry(null, e2.getTimeMillis());
316         assertTrue(null == dropbox.getNextEntry(null, e3.getTimeMillis()));
317 
318         assertEquals("FUTURE0", e0.getText(80));
319         assertEquals("FUTURE1", e1.getText(80));
320         assertEquals("FUTURE2", e2.getText(80));
321         assertEquals(null, e3.getText(80));
322 
323         assertEquals(before + 5000, e0.getTimeMillis());
324         assertEquals(before + 100000, e1.getTimeMillis());
325         assertEquals(before + 100001, e2.getTimeMillis());
326         assertEquals(before + 100002, e3.getTimeMillis());
327 
328         e0.close();
329         e1.close();
330         e2.close();
331         e3.close();
332 
333         // Write something to force a collapse
334         dropbox.addText("NotDropBoxTest", "FUTURE");
335         e0 = dropbox.getNextEntry(null, before);
336         e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
337         e2 = dropbox.getNextEntry(null, e1.getTimeMillis());
338         e3 = dropbox.getNextEntry(null, e2.getTimeMillis());
339         assertTrue(null == dropbox.getNextEntry("DropBoxTest", e3.getTimeMillis()));
340 
341         assertEquals("FUTURE0", e0.getText(80));
342         assertEquals("FUTURE1", e1.getText(80));
343         assertEquals("FUTURE2", e2.getText(80));
344         assertEquals(null, e3.getText(80));
345 
346         assertEquals(before + 5000, e0.getTimeMillis());
347         assertEquals(before + 5001, e1.getTimeMillis());
348         assertEquals(before + 5002, e2.getTimeMillis());
349         assertEquals(before + 5003, e3.getTimeMillis());
350 
351         e0.close();
352         e1.close();
353         e2.close();
354         e3.close();
355     }
356 
testIsTagEnabled()357     public void testIsTagEnabled() throws Exception {
358         File dir = getEmptyDir("testIsTagEnabled");
359         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
360                 Looper.getMainLooper());
361         DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
362 
363         long before = System.currentTimeMillis();
364         dropbox.addText("DropBoxTest", "TEST-ENABLED");
365         assertTrue(dropbox.isTagEnabled("DropBoxTest"));
366 
367         ContentResolver cr = getContext().getContentResolver();
368         Settings.Global.putString(cr, Settings.Global.DROPBOX_TAG_PREFIX + "DropBoxTest",
369                                   "disabled");
370 
371         dropbox.addText("DropBoxTest", "TEST-DISABLED");
372         assertFalse(dropbox.isTagEnabled("DropBoxTest"));
373 
374         Settings.Global.putString(cr, Settings.Global.DROPBOX_TAG_PREFIX + "DropBoxTest",
375                                   "");
376 
377         dropbox.addText("DropBoxTest", "TEST-ENABLED-AGAIN");
378         assertTrue(dropbox.isTagEnabled("DropBoxTest"));
379 
380         DropBoxManager.Entry e0 = dropbox.getNextEntry("DropBoxTest", before);
381         DropBoxManager.Entry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis());
382         assertTrue(null == dropbox.getNextEntry("DropBoxTest", e1.getTimeMillis()));
383 
384         assertEquals("TEST-ENABLED", e0.getText(80));
385         assertEquals("TEST-ENABLED-AGAIN", e1.getText(80));
386 
387         e0.close();
388         e1.close();
389     }
390 
testGetNextEntry()391     public void testGetNextEntry() throws Exception {
392         File dir = getEmptyDir("testGetNextEntry");
393         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
394                 Looper.getMainLooper());
395         DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
396 
397         long before = System.currentTimeMillis();
398         dropbox.addText("DropBoxTest.A", "A0");
399         dropbox.addText("DropBoxTest.B", "B0");
400         dropbox.addText("DropBoxTest.A", "A1");
401 
402         DropBoxManager.Entry a0 = dropbox.getNextEntry("DropBoxTest.A", before);
403         DropBoxManager.Entry a1 = dropbox.getNextEntry("DropBoxTest.A", a0.getTimeMillis());
404         assertTrue(null == dropbox.getNextEntry("DropBoxTest.A", a1.getTimeMillis()));
405 
406         DropBoxManager.Entry b0 = dropbox.getNextEntry("DropBoxTest.B", before);
407         assertTrue(null == dropbox.getNextEntry("DropBoxTest.B", b0.getTimeMillis()));
408 
409         DropBoxManager.Entry x0 = dropbox.getNextEntry(null, before);
410         DropBoxManager.Entry x1 = dropbox.getNextEntry(null, x0.getTimeMillis());
411         DropBoxManager.Entry x2 = dropbox.getNextEntry(null, x1.getTimeMillis());
412         assertTrue(null == dropbox.getNextEntry(null, x2.getTimeMillis()));
413 
414         assertEquals("DropBoxTest.A", a0.getTag());
415         assertEquals("DropBoxTest.A", a1.getTag());
416         assertEquals("A0", a0.getText(80));
417         assertEquals("A1", a1.getText(80));
418 
419         assertEquals("DropBoxTest.B", b0.getTag());
420         assertEquals("B0", b0.getText(80));
421 
422         assertEquals("DropBoxTest.A", x0.getTag());
423         assertEquals("DropBoxTest.B", x1.getTag());
424         assertEquals("DropBoxTest.A", x2.getTag());
425         assertEquals("A0", x0.getText(80));
426         assertEquals("B0", x1.getText(80));
427         assertEquals("A1", x2.getText(80));
428 
429         a0.close();
430         a1.close();
431         b0.close();
432         x0.close();
433         x1.close();
434         x2.close();
435     }
436 
testSizeLimits()437     public void testSizeLimits() throws Exception {
438         File dir = getEmptyDir("testSizeLimits");
439         int blockSize =  new StatFs(dir.getPath()).getBlockSize();
440 
441         // Limit storage to 10 blocks
442         int kb = blockSize * 10 / 1024;
443         ContentResolver cr = getContext().getContentResolver();
444         Settings.Global.putString(cr, Settings.Global.DROPBOX_QUOTA_KB, Integer.toString(kb));
445 
446         // Three tags using a total of 12 blocks:
447         // DropBoxTest0 [ ][ ]
448         // DropBoxTest1 [x][ ][    ][ ][xxx(20 blocks)xxx]
449         // DropBoxTest2 [xxxxxxxxxx][ ][ ]
450         //
451         // The blocks marked "x" will be removed due to storage restrictions.
452         // Use random fill (so it doesn't compress), subtract a little for gzip overhead
453 
454         final int overhead = 64;
455         long before = System.currentTimeMillis();
456         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
457                 Looper.getMainLooper());
458         DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
459 
460         addRandomEntry(dropbox, "DropBoxTest0", blockSize - overhead);
461         addRandomEntry(dropbox, "DropBoxTest0", blockSize - overhead);
462 
463         addRandomEntry(dropbox, "DropBoxTest1", blockSize - overhead);
464         addRandomEntry(dropbox, "DropBoxTest1", blockSize - overhead);
465         addRandomEntry(dropbox, "DropBoxTest1", blockSize * 2 - overhead);
466         addRandomEntry(dropbox, "DropBoxTest1", blockSize - overhead);
467         addRandomEntry(dropbox, "DropBoxTest1", blockSize * 20 - overhead);
468 
469         addRandomEntry(dropbox, "DropBoxTest2", blockSize * 4 - overhead);
470         addRandomEntry(dropbox, "DropBoxTest2", blockSize - overhead);
471         addRandomEntry(dropbox, "DropBoxTest2", blockSize - overhead);
472 
473         DropBoxManager.Entry e0 = dropbox.getNextEntry(null, before);
474         DropBoxManager.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
475         DropBoxManager.Entry e2 = dropbox.getNextEntry(null, e1.getTimeMillis());
476         DropBoxManager.Entry e3 = dropbox.getNextEntry(null, e2.getTimeMillis());
477         DropBoxManager.Entry e4 = dropbox.getNextEntry(null, e3.getTimeMillis());
478         DropBoxManager.Entry e5 = dropbox.getNextEntry(null, e4.getTimeMillis());
479         DropBoxManager.Entry e6 = dropbox.getNextEntry(null, e5.getTimeMillis());
480         DropBoxManager.Entry e7 = dropbox.getNextEntry(null, e6.getTimeMillis());
481         DropBoxManager.Entry e8 = dropbox.getNextEntry(null, e7.getTimeMillis());
482         DropBoxManager.Entry e9 = dropbox.getNextEntry(null, e8.getTimeMillis());
483         assertTrue(null == dropbox.getNextEntry(null, e9.getTimeMillis()));
484 
485         assertEquals("DropBoxTest0", e0.getTag());
486         assertEquals("DropBoxTest0", e1.getTag());
487         assertEquals(blockSize - overhead, getEntrySize(e0));
488         assertEquals(blockSize - overhead, getEntrySize(e1));
489 
490         assertEquals("DropBoxTest1", e2.getTag());
491         assertEquals("DropBoxTest1", e3.getTag());
492         assertEquals("DropBoxTest1", e4.getTag());
493         assertEquals("DropBoxTest1", e5.getTag());
494         assertEquals("DropBoxTest1", e6.getTag());
495         assertEquals(-1, getEntrySize(e2));  // Tombstone
496         assertEquals(blockSize - overhead, getEntrySize(e3));
497         assertEquals(blockSize * 2 - overhead, getEntrySize(e4));
498         assertEquals(blockSize - overhead, getEntrySize(e5));
499         assertEquals(-1, getEntrySize(e6));
500 
501         assertEquals("DropBoxTest2", e7.getTag());
502         assertEquals("DropBoxTest2", e8.getTag());
503         assertEquals("DropBoxTest2", e9.getTag());
504         assertEquals(-1, getEntrySize(e7));  // Tombstone
505         assertEquals(blockSize - overhead, getEntrySize(e8));
506         assertEquals(blockSize - overhead, getEntrySize(e9));
507 
508         e0.close();
509         e1.close();
510         e2.close();
511         e3.close();
512         e4.close();
513         e5.close();
514         e6.close();
515         e7.close();
516         e8.close();
517         e9.close();
518 
519         // Specifying a tag name skips tombstone records.
520 
521         DropBoxManager.Entry t0 = dropbox.getNextEntry("DropBoxTest1", before);
522         DropBoxManager.Entry t1 = dropbox.getNextEntry("DropBoxTest1", t0.getTimeMillis());
523         DropBoxManager.Entry t2 = dropbox.getNextEntry("DropBoxTest1", t1.getTimeMillis());
524         assertTrue(null == dropbox.getNextEntry("DropBoxTest1", t2.getTimeMillis()));
525 
526         assertEquals("DropBoxTest1", t0.getTag());
527         assertEquals("DropBoxTest1", t1.getTag());
528         assertEquals("DropBoxTest1", t2.getTag());
529 
530         assertEquals(blockSize - overhead, getEntrySize(t0));
531         assertEquals(blockSize * 2 - overhead, getEntrySize(t1));
532         assertEquals(blockSize - overhead, getEntrySize(t2));
533 
534         t0.close();
535         t1.close();
536         t2.close();
537     }
538 
testAgeLimits()539     public void testAgeLimits() throws Exception {
540         File dir = getEmptyDir("testAgeLimits");
541         int blockSize = new StatFs(dir.getPath()).getBlockSize();
542 
543         // Limit storage to 10 blocks with an expiration of 1 second
544         int kb = blockSize * 10 / 1024;
545         ContentResolver cr = getContext().getContentResolver();
546         Settings.Global.putString(cr, Settings.Global.DROPBOX_AGE_SECONDS, "1");
547         Settings.Global.putString(cr, Settings.Global.DROPBOX_QUOTA_KB, Integer.toString(kb));
548 
549         // Write one normal entry and another so big that it is instantly tombstoned
550         long before = System.currentTimeMillis();
551         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
552                 Looper.getMainLooper());
553         DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
554 
555         dropbox.addText("DropBoxTest", "TEST");
556         addRandomEntry(dropbox, "DropBoxTest", blockSize * 20);
557 
558         // Verify that things are as expected
559         DropBoxManager.Entry e0 = dropbox.getNextEntry(null, before);
560         DropBoxManager.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
561         assertTrue(null == dropbox.getNextEntry(null, e1.getTimeMillis()));
562 
563         assertEquals("TEST", e0.getText(80));
564         assertEquals(null, e1.getText(80));
565         assertEquals(-1, getEntrySize(e1));
566 
567         e0.close();
568         e1.close();
569 
570         // Wait a second and write another entry -- old ones should be expunged
571         Thread.sleep(2000);
572         dropbox.addText("DropBoxTest", "TEST1");
573 
574         e0 = dropbox.getNextEntry(null, before);
575         assertTrue(null == dropbox.getNextEntry(null, e0.getTimeMillis()));
576         assertEquals("TEST1", e0.getText(80));
577         e0.close();
578     }
579 
testFileCountLimits()580     public void testFileCountLimits() throws Exception {
581         File dir = getEmptyDir("testFileCountLimits");
582 
583         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
584                 Looper.getMainLooper());
585         DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
586         dropbox.addText("DropBoxTest", "TEST0");
587         dropbox.addText("DropBoxTest", "TEST1");
588         dropbox.addText("DropBoxTest", "TEST2");
589         dropbox.addText("DropBoxTest", "TEST3");
590         dropbox.addText("DropBoxTest", "TEST4");
591         dropbox.addText("DropBoxTest", "TEST5");
592 
593         // Verify 6 files added
594         DropBoxManager.Entry e0 = dropbox.getNextEntry(null, 0);
595         DropBoxManager.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
596         DropBoxManager.Entry e2 = dropbox.getNextEntry(null, e1.getTimeMillis());
597         DropBoxManager.Entry e3 = dropbox.getNextEntry(null, e2.getTimeMillis());
598         DropBoxManager.Entry e4 = dropbox.getNextEntry(null, e3.getTimeMillis());
599         DropBoxManager.Entry e5 = dropbox.getNextEntry(null, e4.getTimeMillis());
600         assertTrue(null == dropbox.getNextEntry(null, e5.getTimeMillis()));
601         assertEquals("TEST0", e0.getText(80));
602         assertEquals("TEST5", e5.getText(80));
603 
604         e0.close();
605         e1.close();
606         e2.close();
607         e3.close();
608         e4.close();
609         e5.close();
610 
611         // Limit to 3 files and add one more entry
612         ContentResolver cr = getContext().getContentResolver();
613         Settings.Global.putString(cr, Settings.Global.DROPBOX_MAX_FILES, "3");
614         dropbox.addText("DropBoxTest", "TEST6");
615 
616         // Verify only 3 files left
617         DropBoxManager.Entry f0 = dropbox.getNextEntry(null, 0);
618         DropBoxManager.Entry f1 = dropbox.getNextEntry(null, f0.getTimeMillis());
619         DropBoxManager.Entry f2 = dropbox.getNextEntry(null, f1.getTimeMillis());
620         assertTrue(null == dropbox.getNextEntry(null, f2.getTimeMillis()));
621         assertEquals("TEST4", f0.getText(80));
622         assertEquals("TEST5", f1.getText(80));
623         assertEquals("TEST6", f2.getText(80));
624 
625         f0.close();
626         f1.close();
627         f2.close();
628     }
629 
testCreateDropBoxManagerWithInvalidDirectory()630     public void testCreateDropBoxManagerWithInvalidDirectory() throws Exception {
631         // If created with an invalid directory, the DropBoxManager should suffer quietly
632         // and fail all operations (this is how it survives a full disk).
633         // Once the directory becomes possible to create, it will start working.
634 
635         File dir = new File(getEmptyDir("testCreateDropBoxManagerWith"), "InvalidDirectory");
636         new FileOutputStream(dir).close();  // Create an empty file
637         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
638                 Looper.getMainLooper());
639         DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
640 
641         dropbox.addText("DropBoxTest", "should be ignored");
642         dropbox.addData("DropBoxTest", "should be ignored".getBytes(), 0);
643         assertTrue(null == dropbox.getNextEntry("DropBoxTest", 0));
644 
645         dir.delete();  // Remove the file so a directory can be created
646         dropbox.addText("DropBoxTest", "TEST");
647         DropBoxManager.Entry e = dropbox.getNextEntry("DropBoxTest", 0);
648         assertTrue(null == dropbox.getNextEntry("DropBoxTest", e.getTimeMillis()));
649         assertEquals("DropBoxTest", e.getTag());
650         assertEquals("TEST", e.getText(80));
651         e.close();
652     }
653 
testDropBoxEntrySerialization()654     public void testDropBoxEntrySerialization() throws Exception {
655         // Make sure DropBoxManager.Entry can be serialized to a Parcel and back
656         // under a variety of conditions.
657 
658         Parcel parcel = Parcel.obtain();
659         File dir = getEmptyDir("testDropBoxEntrySerialization");
660 
661         new DropBoxManager.Entry("empty", 1000000).writeToParcel(parcel, 0);
662         new DropBoxManager.Entry("string", 2000000, "String Value").writeToParcel(parcel, 0);
663         new DropBoxManager.Entry("bytes", 3000000, "Bytes Value".getBytes(),
664                 DropBoxManager.IS_TEXT).writeToParcel(parcel, 0);
665         new DropBoxManager.Entry("zerobytes", 4000000, new byte[0], 0).writeToParcel(parcel, 0);
666         new DropBoxManager.Entry("emptybytes", 5000000, (byte[]) null,
667                 DropBoxManager.IS_EMPTY).writeToParcel(parcel, 0);
668 
669         try {
670             new DropBoxManager.Entry("badbytes", 99999,
671                     "Bad Bytes Value".getBytes(),
672                     DropBoxManager.IS_EMPTY).writeToParcel(parcel, 0);
673             fail("IllegalArgumentException expected for non-null byte[] and IS_EMPTY flags");
674         } catch (IllegalArgumentException e) {
675             // expected
676         }
677 
678         try {
679             new DropBoxManager.Entry("badbytes", 99999, (byte[]) null, 0).writeToParcel(parcel, 0);
680             fail("IllegalArgumentException expected for null byte[] and non-IS_EMPTY flags");
681         } catch (IllegalArgumentException e) {
682             // expected
683         }
684 
685         File f = new File(dir, "file.dat");
686         FileOutputStream os = new FileOutputStream(f);
687         os.write("File Value".getBytes());
688         os.close();
689 
690         new DropBoxManager.Entry("file", 6000000, f, DropBoxManager.IS_TEXT).writeToParcel(
691                 parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
692         new DropBoxManager.Entry("binfile", 7000000, f, 0).writeToParcel(
693                 parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
694         new DropBoxManager.Entry("emptyfile", 8000000, (ParcelFileDescriptor) null,
695                 DropBoxManager.IS_EMPTY).writeToParcel(parcel, 0);
696 
697         try {
698             new DropBoxManager.Entry("badfile", 99999, new File(dir, "nonexist.dat"), 0);
699             fail("IOException expected for nonexistent file");
700         } catch (IOException e) {
701             // expected
702         }
703 
704         try {
705             new DropBoxManager.Entry("badfile", 99999, f, DropBoxManager.IS_EMPTY).writeToParcel(
706                     parcel, 0);
707             fail("IllegalArgumentException expected for non-null file and IS_EMPTY flags");
708         } catch (IllegalArgumentException e) {
709             // expected
710         }
711 
712         try {
713             new DropBoxManager.Entry("badfile", 99999, (ParcelFileDescriptor) null, 0);
714             fail("IllegalArgumentException expected for null PFD and non-IS_EMPTY flags");
715         } catch (IllegalArgumentException e) {
716             // expected
717         }
718 
719         File gz = new File(dir, "file.gz");
720         GZIPOutputStream gzout = new GZIPOutputStream(new FileOutputStream(gz));
721         gzout.write("Gzip File Value".getBytes());
722         gzout.close();
723 
724         new DropBoxManager.Entry("gzipfile", 9000000, gz,
725                 DropBoxManager.IS_TEXT | DropBoxManager.IS_GZIPPED).writeToParcel(
726                     parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
727         new DropBoxManager.Entry("gzipbinfile", 10000000, gz,
728                 DropBoxManager.IS_GZIPPED).writeToParcel(
729                     parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
730 
731         //
732         // Switch from writing to reading
733         //
734 
735         parcel.setDataPosition(0);
736         DropBoxManager.Entry e;
737 
738         e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
739         assertEquals("empty", e.getTag());
740         assertEquals(1000000, e.getTimeMillis());
741         assertEquals(DropBoxManager.IS_EMPTY, e.getFlags());
742         assertEquals(null, e.getText(100));
743         assertEquals(null, e.getInputStream());
744         e.close();
745 
746         e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
747         assertEquals("string", e.getTag());
748         assertEquals(2000000, e.getTimeMillis());
749         assertEquals(DropBoxManager.IS_TEXT, e.getFlags());
750         assertEquals("String Value", e.getText(100));
751         assertEquals("String Value",
752                 new BufferedReader(new InputStreamReader(e.getInputStream())).readLine());
753         e.close();
754 
755         e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
756         assertEquals("bytes", e.getTag());
757         assertEquals(3000000, e.getTimeMillis());
758         assertEquals(DropBoxManager.IS_TEXT, e.getFlags());
759         assertEquals("Bytes Value", e.getText(100));
760         e.close();
761 
762         e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
763         assertEquals("zerobytes", e.getTag());
764         assertEquals(4000000, e.getTimeMillis());
765         assertEquals(0, e.getFlags());
766         assertEquals(null, e.getText(100));
767         assertEquals(null,
768                 new BufferedReader(new InputStreamReader(e.getInputStream())).readLine());
769         e.close();
770 
771         e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
772         assertEquals("emptybytes", e.getTag());
773         assertEquals(5000000, e.getTimeMillis());
774         assertEquals(DropBoxManager.IS_EMPTY, e.getFlags());
775         assertEquals(null, e.getText(100));
776         assertEquals(null, e.getInputStream());
777         e.close();
778 
779         e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
780         assertEquals("file", e.getTag());
781         assertEquals(6000000, e.getTimeMillis());
782         assertEquals(DropBoxManager.IS_TEXT, e.getFlags());
783         assertEquals("File Value", e.getText(100));
784         e.close();
785 
786         e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
787         assertEquals("binfile", e.getTag());
788         assertEquals(7000000, e.getTimeMillis());
789         assertEquals(0, e.getFlags());
790         assertEquals(null, e.getText(100));
791         assertEquals("File Value",
792                 new BufferedReader(new InputStreamReader(e.getInputStream())).readLine());
793         e.close();
794         e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
795         assertEquals("emptyfile", e.getTag());
796         assertEquals(8000000, e.getTimeMillis());
797         assertEquals(DropBoxManager.IS_EMPTY, e.getFlags());
798         assertEquals(null, e.getText(100));
799         assertEquals(null, e.getInputStream());
800         e.close();
801 
802         e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
803         assertEquals("gzipfile", e.getTag());
804         assertEquals(9000000, e.getTimeMillis());
805         assertEquals(DropBoxManager.IS_TEXT, e.getFlags());
806         assertEquals("Gzip File Value", e.getText(100));
807         e.close();
808 
809         e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
810         assertEquals("gzipbinfile", e.getTag());
811         assertEquals(10000000, e.getTimeMillis());
812         assertEquals(0, e.getFlags());
813         assertEquals(null, e.getText(100));
814         assertEquals("Gzip File Value",
815                 new BufferedReader(new InputStreamReader(e.getInputStream())).readLine());
816         e.close();
817         assertEquals(0, parcel.dataAvail());
818         parcel.recycle();
819     }
820 
testDropBoxEntrySerializationDoesntLeakFileDescriptors()821     public void testDropBoxEntrySerializationDoesntLeakFileDescriptors() throws Exception {
822         File dir = getEmptyDir("testDropBoxEntrySerialization");
823         File f = new File(dir, "file.dat");
824         FileOutputStream os = new FileOutputStream(f);
825         os.write("File Value".getBytes());
826         os.close();
827 
828         int before = countOpenFiles();
829         assertTrue(before > 0);
830 
831         for (int i = 0; i < 1000; i++) {
832             Parcel parcel = Parcel.obtain();
833             new DropBoxManager.Entry("file", 1000000, f, 0).writeToParcel(
834                     parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
835 
836             parcel.setDataPosition(0);
837             DropBoxManager.Entry e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
838             assertEquals("file", e.getTag());
839             e.close();
840 
841             parcel.recycle();
842         }
843 
844         int after = countOpenFiles();
845         assertTrue(after > 0);
846         assertTrue(after < before + 20);
847     }
848 
849     public void testEntryFile() throws Exception {
850         File fromDir = getEmptyDir("testEntryFile_from");
851         File toDir = getEmptyDir("testEntryFile_to");
852 
853         {
854             File f = new File(fromDir, "f0.txt");
855             try (FileWriter w = new FileWriter(f)) {
856                 w.write("abc");
857             }
858 
859             EntryFile e = new EntryFile(f, toDir, "tag:!", 12345, DropBoxManager.IS_TEXT, 1024);
860 
861             assertEquals("tag:!", e.tag);
862             assertEquals(12345, e.timestampMillis);
863             assertEquals(DropBoxManager.IS_TEXT, e.flags);
864             assertEquals(1, e.blocks);
865 
866             assertFalse(f.exists()); // Because it should be renamed.
867 
868             assertTrue(e.hasFile());
869             assertEquals(new File(toDir, "tag%3A!@12345.txt"), e.getFile(toDir));
870             assertTrue(e.getFile(toDir).exists());
871         }
872         // Same test with gzip.
873         {
874             File f = new File(fromDir, "f0.txt.gz"); // It's a lie; it's not actually gz.
875             try (FileWriter w = new FileWriter(f)) {
876                 w.write("abc");
877             }
878 
879             EntryFile e = new EntryFile(f, toDir, "tag:!", 12345,
880                     DropBoxManager.IS_TEXT | DropBoxManager.IS_GZIPPED, 1024);
881 
882             assertEquals("tag:!", e.tag);
883 
884             assertFalse(f.exists()); // Because it should be renamed.
885 
886             assertTrue(e.hasFile());
887             assertEquals(new File(toDir, "tag%3A!@12345.txt.gz"), e.getFile(toDir));
888             assertTrue(e.getFile(toDir).exists());
889 
890         }
891         // binary, gzip.
892         {
893             File f = new File(fromDir, "f0.dat.gz"); // It's a lie; it's not actually gz.
894             try (FileWriter w = new FileWriter(f)) {
895                 w.write("abc");
896             }
897 
898             EntryFile e = new EntryFile(f, toDir, "tag:!", 12345,
899                     DropBoxManager.IS_GZIPPED, 1024);
900 
901             assertEquals("tag:!", e.tag);
902 
903             assertFalse(f.exists()); // Because it should be renamed.
904 
905             assertTrue(e.hasFile());
906             assertEquals(new File(toDir, "tag%3A!@12345.dat.gz"), e.getFile(toDir));
907             assertTrue(e.getFile(toDir).exists());
908 
909         }
910 
911         // Tombstone.
912         {
913             EntryFile e = new EntryFile(toDir, "tag:!", 12345);
914 
915             assertEquals("tag:!", e.tag);
916             assertEquals(12345, e.timestampMillis);
917             assertEquals(DropBoxManager.IS_EMPTY, e.flags);
918             assertEquals(0, e.blocks);
919 
920             assertTrue(e.hasFile());
921             assertEquals(new File(toDir, "tag%3A!@12345.lost"), e.getFile(toDir));
922             assertTrue(e.getFile(toDir).exists());
923         }
924 
925         // From existing files.
926         {
927             File f = new File(fromDir, "tag%3A!@12345.dat");
928             f.createNewFile();
929 
930             EntryFile e = new EntryFile(f, 1024);
931 
932             assertEquals("tag:!", e.tag);
933             assertEquals(12345, e.timestampMillis);
934             assertEquals(0, e.flags);
935             assertEquals(0, e.blocks);
936 
937             assertTrue(f.exists());
938         }
939         {
940             File f = new File(fromDir, "tag%3A!@12345.dat.gz");
941             f.createNewFile();
942 
943             EntryFile e = new EntryFile(f, 1024);
944 
945             assertEquals("tag:!", e.tag);
946             assertEquals(12345, e.timestampMillis);
947             assertEquals(DropBoxManager.IS_GZIPPED, e.flags);
948             assertEquals(0, e.blocks);
949 
950             assertTrue(f.exists());
951         }
952         {
953             File f = new File(fromDir, "tag%3A!@12345.txt");
954             try (FileWriter w = new FileWriter(f)) {
955                 w.write(new char[1024]);
956             }
957 
958             EntryFile e = new EntryFile(f, 1024);
959 
960             assertEquals("tag:!", e.tag);
961             assertEquals(12345, e.timestampMillis);
962             assertEquals(DropBoxManager.IS_TEXT, e.flags);
963             assertEquals(1, e.blocks);
964 
965             assertTrue(f.exists());
966         }
967         {
968             File f = new File(fromDir, "tag%3A!@12345.txt.gz");
969             try (FileWriter w = new FileWriter(f)) {
970                 w.write(new char[1025]);
971             }
972 
973             EntryFile e = new EntryFile(f, 1024);
974 
975             assertEquals("tag:!", e.tag);
976             assertEquals(12345, e.timestampMillis);
977             assertEquals(DropBoxManager.IS_TEXT | DropBoxManager.IS_GZIPPED, e.flags);
978             assertEquals(2, e.blocks);
979 
980             assertTrue(f.exists());
981         }
982         {
983             File f = new File(fromDir, "tag%3A!@12345.lost");
984             f.createNewFile();
985 
986             EntryFile e = new EntryFile(f, 1024);
987 
988             assertEquals("tag:!", e.tag);
989             assertEquals(12345, e.timestampMillis);
990             assertEquals(DropBoxManager.IS_EMPTY, e.flags);
991             assertEquals(0, e.blocks);
992 
993             assertTrue(f.exists());
994         }
995         {
996             File f = new File(fromDir, "@12345.dat"); // Empty tag -- this actually works.
997             f.createNewFile();
998 
999             EntryFile e = new EntryFile(f, 1024);
1000 
1001             assertEquals("", e.tag);
1002             assertEquals(12345, e.timestampMillis);
1003             assertEquals(0, e.flags);
1004             assertEquals(0, e.blocks);
1005 
1006             assertTrue(f.exists());
1007         }
1008         // From invalid filenames.
1009         {
1010             File f = new File(fromDir, "tag.dat"); // No @.
1011             f.createNewFile();
1012 
1013             EntryFile e = new EntryFile(f, 1024);
1014 
1015             assertEquals(null, e.tag);
1016             assertEquals(0, e.timestampMillis);
1017             assertEquals(DropBoxManager.IS_EMPTY, e.flags);
1018             assertEquals(0, e.blocks);
1019 
1020             assertFalse(f.exists());
1021         }
1022         {
1023             File f = new File(fromDir, "tag@.dat"); // Invalid timestamp.
1024             f.createNewFile();
1025 
1026             EntryFile e = new EntryFile(f, 1024);
1027 
1028             assertEquals(null, e.tag);
1029             assertEquals(0, e.timestampMillis);
1030             assertEquals(DropBoxManager.IS_EMPTY, e.flags);
1031             assertEquals(0, e.blocks);
1032 
1033             assertFalse(f.exists());
1034         }
1035         {
1036             File f = new File(fromDir, "tag@12345.daxt"); // Invalid extension.
1037             f.createNewFile();
1038 
1039             EntryFile e = new EntryFile(f, 1024);
1040 
1041             assertEquals(null, e.tag);
1042             assertEquals(0, e.timestampMillis);
1043             assertEquals(DropBoxManager.IS_EMPTY, e.flags);
1044             assertEquals(0, e.blocks);
1045 
1046             assertFalse(f.exists());
1047         }
1048     }
1049 
1050     public void testCompareEntries() {
1051         File dir = getEmptyDir("testCompareEntries");
1052         assertEquals(-1,
1053                 new EntryFile(new File(dir, "aaa@100.dat"), 1).compareTo(
1054                 new EntryFile(new File(dir, "bbb@200.dat"), 1)));
1055         assertEquals(1,
1056                 new EntryFile(new File(dir, "aaa@200.dat"), 1).compareTo(
1057                 new EntryFile(new File(dir, "bbb@100.dat"), 1)));
1058         assertEquals(-1,
1059                 new EntryFile(new File(dir, "aaa@100.dat"), 1).compareTo(
1060                 new EntryFile(new File(dir, "bbb@100.dat"), 1)));
1061         assertEquals(1,
1062                 new EntryFile(new File(dir, "bbb@100.dat"), 1).compareTo(
1063                 new EntryFile(new File(dir, "aaa@100.dat"), 1)));
1064     }
1065 
1066     private void addRandomEntry(DropBoxManager dropbox, String tag, int size) throws Exception {
1067         byte[] bytes = new byte[size];
1068         new Random(System.currentTimeMillis()).nextBytes(bytes);
1069 
1070         File f = new File(getEmptyDir("addRandomEntry"), "random.dat");
1071         FileOutputStream os = new FileOutputStream(f);
1072         os.write(bytes);
1073         os.close();
1074 
1075         dropbox.addFile(tag, f, 0);
1076     }
1077 
1078     private int getEntrySize(DropBoxManager.Entry e) throws Exception {
1079         InputStream is = e.getInputStream();
1080         if (is == null) return -1;
1081         int length = 0;
1082         while (is.read() != -1) length++;
1083         return length;
1084     }
1085 
1086     private void recursiveDelete(File file) {
1087         if (!file.delete() && file.isDirectory()) {
1088             for (File f : file.listFiles()) recursiveDelete(f);
1089             file.delete();
1090         }
1091     }
1092 
1093     private File getEmptyDir(String name) {
1094         File dir = getContext().getDir("DropBoxTest." + name, 0);
1095         for (File f : dir.listFiles()) recursiveDelete(f);
1096         assertTrue(dir.listFiles().length == 0);
1097         return dir;
1098     }
1099 
1100     private int countOpenFiles() {
1101         return new File("/proc/" + Process.myPid() + "/fd").listFiles().length;
1102     }
1103 }
1104