1/*
2 * Copyright (C) 2006 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
17package android.content.pm;
18
19import android.app.PendingIntent;
20import android.content.BroadcastReceiver;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.os.RemoteException;
25import android.os.ServiceManager;
26import android.os.StatFs;
27import android.test.AndroidTestCase;
28import android.test.suitebuilder.annotation.LargeTest;
29import android.test.suitebuilder.annotation.MediumTest;
30import android.test.suitebuilder.annotation.SmallTest;
31import android.util.Log;
32
33import java.io.File;
34import java.io.FileInputStream;
35import java.io.FileNotFoundException;
36import java.io.FileOutputStream;
37import java.io.IOException;
38import java.util.ArrayList;
39import java.util.Arrays;
40import java.util.List;
41
42public class AppCacheTest extends AndroidTestCase {
43    private static final boolean localLOGV = false;
44    public static final String TAG="AppCacheTest";
45    public final long MAX_WAIT_TIME=60*1000;
46    public final long WAIT_TIME_INCR=10*1000;
47    private static final long THRESHOLD=5;
48    private static final long ACTUAL_THRESHOLD=10;
49
50    @Override
51    protected void setUp() throws Exception {
52        super.setUp();
53        if(localLOGV) Log.i(TAG, "Cleaning up cache directory first");
54        cleanUpCacheDirectory();
55    }
56
57    void cleanUpDirectory(File pDir, String dirName) {
58       File testDir = new File(pDir,  dirName);
59       if(!testDir.exists()) {
60           return;
61       }
62        String fList[] = testDir.list();
63        for(int i = 0; i < fList.length; i++) {
64            File file = new File(testDir, fList[i]);
65            if(file.isDirectory()) {
66                cleanUpDirectory(testDir, fList[i]);
67            } else {
68                file.delete();
69            }
70        }
71        testDir.delete();
72    }
73
74    void cleanUpCacheDirectory() {
75        File testDir = mContext.getCacheDir();
76        if(!testDir.exists()) {
77            return;
78        }
79
80         String fList[] = testDir.list();
81         if(fList == null) {
82             testDir.delete();
83             return;
84         }
85         for(int i = 0; i < fList.length; i++) {
86             File file = new File(testDir, fList[i]);
87             if(file.isDirectory()) {
88                 cleanUpDirectory(testDir, fList[i]);
89             } else {
90                 file.delete();
91             }
92         }
93     }
94
95    @SmallTest
96    public void testDeleteAllCacheFiles() {
97        String testName="testDeleteAllCacheFiles";
98        cleanUpCacheDirectory();
99    }
100
101    void failStr(String errMsg) {
102        Log.w(TAG, "errMsg="+errMsg);
103        fail(errMsg);
104    }
105
106    void failStr(Exception e) {
107        Log.w(TAG, "e.getMessage="+e.getMessage());
108        Log.w(TAG, "e="+e);
109    }
110
111    long getFreeStorageBlks(StatFs st) {
112        st.restat("/data");
113        return st.getFreeBlocks();
114    }
115
116    long getFreeStorageSize(StatFs st) {
117        st.restat("/data");
118        return (long) st.getFreeBlocks() * (long) st.getBlockSize();
119    }
120
121    @LargeTest
122    public void testFreeApplicationCacheAllFiles() throws Exception {
123        boolean TRACKING = true;
124        StatFs st = new StatFs("/data");
125        long blks1 = getFreeStorageBlks(st);
126        long availableMem = getFreeStorageSize(st);
127        File cacheDir = mContext.getCacheDir();
128        assertNotNull(cacheDir);
129        createTestFiles1(cacheDir, "testtmpdir", 5);
130        long blks2 = getFreeStorageBlks(st);
131        if(localLOGV || TRACKING) Log.i(TAG, "blk1="+blks1+", blks2="+blks2);
132        //this should free up the test files that were created earlier
133        if (!invokePMFreeApplicationCache(availableMem)) {
134            fail("Could not successfully invoke PackageManager free app cache API");
135        }
136        long blks3 = getFreeStorageBlks(st);
137        if(localLOGV || TRACKING) Log.i(TAG, "blks3="+blks3);
138        verifyTestFiles1(cacheDir, "testtmpdir", 5);
139    }
140
141    public void testFreeApplicationCacheSomeFiles() throws Exception {
142        StatFs st = new StatFs("/data");
143        long blks1 = getFreeStorageBlks(st);
144        File cacheDir = mContext.getCacheDir();
145        assertNotNull(cacheDir);
146        createTestFiles1(cacheDir, "testtmpdir", 5);
147        long blks2 = getFreeStorageBlks(st);
148        Log.i(TAG, "blk1="+blks1+", blks2="+blks2);
149        long diff = (blks1-blks2-2);
150        if (!invokePMFreeApplicationCache(diff * st.getBlockSize())) {
151            fail("Could not successfully invoke PackageManager free app cache API");
152        }
153        long blks3 = getFreeStorageBlks(st);
154        //blks3 should be greater than blks2 and less than blks1
155        if(!((blks3 <= blks1) && (blks3 >= blks2))) {
156            failStr("Expected "+(blks1-blks2)+" number of blocks to be freed but freed only "
157                    +(blks1-blks3));
158        }
159    }
160
161    /**
162     * This method opens an output file writes to it, opens the same file as an input
163     * stream, reads the contents and verifies the data that was written earlier can be read
164     */
165    public void openOutFileInAppFilesDir(File pFile, String pFileOut) {
166        FileOutputStream fos = null;
167        try {
168            fos = new FileOutputStream(pFile);
169        } catch (FileNotFoundException e1) {
170            failStr("Error when opening file "+e1);
171            return;
172        }
173        try {
174            fos.write(pFileOut.getBytes());
175            fos.close();
176        } catch (FileNotFoundException e) {
177            failStr(e.getMessage());
178        } catch (IOException e) {
179            failStr(e.getMessage());
180        }
181        int count = pFileOut.getBytes().length;
182        byte[] buffer = new byte[count];
183        try {
184            FileInputStream fis = new FileInputStream(pFile);
185            fis.read(buffer, 0, count);
186            fis.close();
187        } catch (FileNotFoundException e) {
188            failStr("Failed when verifing output opening file "+e.getMessage());
189        } catch (IOException e) {
190            failStr("Failed when verifying output, reading from written file "+e);
191        }
192        String str = new String(buffer);
193        assertEquals(str, pFileOut);
194    }
195
196    /*
197     * This test case verifies that output written to a file
198     * using Context.openFileOutput has executed successfully.
199     * The operation is verified by invoking Context.openFileInput
200     */
201    @MediumTest
202    public void testAppFilesCreateFile() {
203        String fileName = "testFile1.txt";
204        String fileOut = "abcdefghijklmnopqrstuvwxyz";
205        Context con = super.getContext();
206        try {
207            FileOutputStream fos = con.openFileOutput(fileName, Context.MODE_PRIVATE);
208            fos.close();
209        } catch (FileNotFoundException e) {
210            failStr(e);
211        } catch (IOException e) {
212            failStr(e);
213        }
214    }
215
216    @SmallTest
217    public void testAppCacheCreateFile() {
218        String fileName = "testFile1.txt";
219        String fileOut = "abcdefghijklmnopqrstuvwxyz";
220        Context con = super.getContext();
221        File file = new File(con.getCacheDir(), fileName);
222        openOutFileInAppFilesDir(file, fileOut);
223        cleanUpCacheDirectory();
224    }
225
226    @MediumTest
227    public void testAppCreateCacheFiles() {
228        File cacheDir = mContext.getCacheDir();
229        String testDirName = "testtmp";
230        File testTmpDir = new File(cacheDir, testDirName);
231        testTmpDir.mkdir();
232        int numDirs = 3;
233        File fileArr[] = new File[numDirs];
234        for(int i = 0; i < numDirs; i++) {
235            fileArr[i] = new File(testTmpDir, "dir"+(i+1));
236            fileArr[i].mkdir();
237        }
238        byte buffer[] = getBuffer();
239        Log.i(TAG, "Size of bufer="+buffer.length);
240        for(int i = 0; i < numDirs; i++) {
241            for(int j = 1; j <= (i); j++) {
242                File file1 = new File(fileArr[i], "testFile"+j+".txt");
243                FileOutputStream fos = null;
244                try {
245                    fos = new FileOutputStream(file1);
246                    for(int k = 1; k < 10; k++) {
247                        fos.write(buffer);
248                    }
249                    Log.i(TAG, "wrote 10K bytes to "+file1);
250                    fos.close();
251                } catch (FileNotFoundException e) {
252                    Log.i(TAG, "Excetion ="+e);
253                    fail("Error when creating outputstream "+e);
254                } catch(IOException e) {
255                    Log.i(TAG, "Excetion ="+e);
256                    fail("Error when writing output "+e);
257                }
258            }
259        }
260    }
261
262    byte[] getBuffer() {
263        String sbuffer = "a";
264        for(int i = 0; i < 10; i++) {
265            sbuffer += sbuffer;
266        }
267        return sbuffer.getBytes();
268    }
269
270    long getFileNumBlocks(long fileSize, long blkSize) {
271        long ret = fileSize/blkSize;
272        if(ret*blkSize < fileSize) {
273            ret++;
274        }
275        return ret;
276    }
277
278    //@LargeTest
279    public void testAppCacheClear() {
280        String dataDir="/data/data";
281        StatFs st = new StatFs(dataDir);
282        long blkSize = st.getBlockSize();
283        long totBlks = st.getBlockCount();
284        long availableBlks = st.getFreeBlocks();
285        long thresholdBlks = (totBlks * THRESHOLD) / 100L;
286        String testDirName = "testdir";
287        //create directory in cache
288        File testDir = new File(mContext.getCacheDir(),  testDirName);
289        testDir.mkdirs();
290        byte[] buffer = getBuffer();
291        int i = 1;
292        if(localLOGV) Log.i(TAG, "availableBlks="+availableBlks+", thresholdBlks="+thresholdBlks);
293        long createdFileBlks = 0;
294        int imax = 300;
295        while((availableBlks > thresholdBlks) &&(i < imax)) {
296            File testFile = new File(testDir, "testFile"+i+".txt");
297            if(localLOGV) Log.i(TAG, "Creating "+i+"th test file "+testFile);
298            int jmax = i;
299            i++;
300            FileOutputStream fos;
301            try {
302                fos = new FileOutputStream(testFile);
303            } catch (FileNotFoundException e) {
304                Log.i(TAG, "Failed creating test file:"+testFile);
305                continue;
306            }
307            boolean err = false;
308            for(int j = 1; j <= jmax;j++) {
309                try {
310                    fos.write(buffer);
311                } catch (IOException e) {
312                    Log.i(TAG, "Failed to write to file:"+testFile);
313                    err = true;
314                }
315            }
316            try {
317                fos.close();
318            } catch (IOException e) {
319                Log.i(TAG, "Failed closing file:"+testFile);
320            }
321            if(err) {
322                continue;
323            }
324            createdFileBlks += getFileNumBlocks(testFile.length(), blkSize);
325            st.restat(dataDir);
326            availableBlks = st.getFreeBlocks();
327        }
328        st.restat(dataDir);
329        long availableBytes = st.getFreeBlocks()*blkSize;
330        long shouldFree = (ACTUAL_THRESHOLD-THRESHOLD)*totBlks;
331        //would have run out of memory
332        //wait for some time and confirm cache is deleted
333        try {
334            Log.i(TAG, "Sleeping for 2 minutes...");
335            Thread.sleep(2*60*1000);
336        } catch (InterruptedException e) {
337            fail("Exception when sleeping "+e);
338        }
339        boolean removedFlag = false;
340        long existingFileBlks = 0;
341        for(int k = 1; k <i; k++) {
342            File testFile = new File(testDir, "testFile"+k+".txt");
343            if(!testFile.exists()) {
344                removedFlag = true;
345                if(localLOGV) Log.i(TAG, testFile+" removed");
346            }  else {
347                existingFileBlks += getFileNumBlocks(testFile.length(), blkSize);
348            }
349        }
350        if(localLOGV) Log.i(TAG, "createdFileBlks="+createdFileBlks+
351                ", existingFileBlks="+existingFileBlks);
352        long fileSize = createdFileBlks-existingFileBlks;
353        //verify fileSize number of bytes have been cleared from cache
354        if(localLOGV) Log.i(TAG, "deletedFileBlks="+fileSize+" shouldFreeBlks="+shouldFree);
355        if((fileSize > (shouldFree-blkSize) && (fileSize < (shouldFree+blkSize)))) {
356            Log.i(TAG, "passed");
357        }
358        assertTrue("Files should have been removed", removedFlag);
359    }
360
361    //createTestFiles(new File(super.getContext().getCacheDir(), "testtmp", "dir", 3)
362    void createTestFiles1(File cacheDir, String testFilePrefix, int numTestFiles) {
363        byte buffer[] = getBuffer();
364        for(int i = 0; i < numTestFiles; i++) {
365            File file1 = new File(cacheDir, testFilePrefix+i+".txt");
366            FileOutputStream fos = null;
367            try {
368                fos = new FileOutputStream(file1);
369                for(int k = 1; k < 10; k++) {
370                    fos.write(buffer);
371               }
372                fos.close();
373            } catch (FileNotFoundException e) {
374                Log.i(TAG, "Exception ="+e);
375                fail("Error when creating outputstream "+e);
376            } catch(IOException e) {
377                Log.i(TAG, "Exception ="+e);
378                fail("Error when writing output "+e);
379            }
380            try {
381                //introduce sleep for 1 s to avoid common time stamps for files being created
382                Thread.sleep(1000);
383            } catch (InterruptedException e) {
384                fail("Exception when sleeping "+e);
385            }
386        }
387    }
388
389    void verifyTestFiles1(File cacheDir, String testFilePrefix, int numTestFiles) {
390        List<String> files = new ArrayList<String>();
391        for(int i = 0; i < numTestFiles; i++) {
392            File file1 = new File(cacheDir, testFilePrefix+i+".txt");
393            if(file1.exists()) {
394                files.add(file1.getName());
395            }
396        }
397        if (files.size() > 0) {
398            fail("Files should have been deleted: "
399                    + Arrays.toString(files.toArray(new String[files.size()])));
400        }
401    }
402
403    void createTestFiles2(File cacheDir, String rootTestDirName, String subDirPrefix, int numDirs, String testFilePrefix) {
404        Context con = super.getContext();
405        File testTmpDir = new File(cacheDir, rootTestDirName);
406        testTmpDir.mkdir();
407        File fileArr[] = new File[numDirs];
408        for(int i = 0; i < numDirs; i++) {
409            fileArr[i] = new File(testTmpDir, subDirPrefix+(i+1));
410            fileArr[i].mkdir();
411        }
412        byte buffer[] = getBuffer();
413        for(int i = 0; i < numDirs; i++) {
414            for(int j = 1; j <= (i); j++) {
415                File file1 = new File(fileArr[i], testFilePrefix+j+".txt");
416                FileOutputStream fos = null;
417                try {
418                    fos = new FileOutputStream(file1);
419                    for(int k = 1; k < 10; k++) {
420                        fos.write(buffer);
421                    }
422                    fos.close();
423                } catch (FileNotFoundException e) {
424                    Log.i(TAG, "Exception ="+e);
425                    fail("Error when creating outputstream "+e);
426                } catch(IOException e) {
427                    Log.i(TAG, "Exception ="+e);
428                    fail("Error when writing output "+e);
429                }
430                try {
431                    //introduce sleep for 10 ms to avoid common time stamps for files being created
432                    Thread.sleep(10);
433                } catch (InterruptedException e) {
434                    fail("Exception when sleeping "+e);
435                }
436            }
437        }
438    }
439
440    class PackageDataObserver extends IPackageDataObserver.Stub {
441        public boolean retValue = false;
442        private boolean doneFlag = false;
443        public void onRemoveCompleted(String packageName, boolean succeeded)
444                throws RemoteException {
445            synchronized(this) {
446                retValue = succeeded;
447                doneFlag = true;
448                notifyAll();
449            }
450        }
451        public boolean isDone() {
452            return doneFlag;
453        }
454    }
455
456    IPackageManager getPm() {
457        return  IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
458    }
459
460    boolean invokePMDeleteAppCacheFiles() throws Exception {
461        try {
462            String packageName = mContext.getPackageName();
463            PackageDataObserver observer = new PackageDataObserver();
464            //wait on observer
465            synchronized(observer) {
466                getPm().deleteApplicationCacheFiles(packageName, observer);
467                long waitTime = 0;
468                while(!observer.isDone() || (waitTime > MAX_WAIT_TIME)) {
469                    observer.wait(WAIT_TIME_INCR);
470                    waitTime += WAIT_TIME_INCR;
471                }
472                if(!observer.isDone()) {
473                    throw new Exception("timed out waiting for PackageDataObserver.onRemoveCompleted");
474                }
475            }
476            return observer.retValue;
477        } catch (RemoteException e) {
478            Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e);
479            return false;
480        } catch (InterruptedException e) {
481            Log.w(TAG, "InterruptedException :"+e);
482            return false;
483        }
484    }
485
486    boolean invokePMFreeApplicationCache(long idealStorageSize) throws Exception {
487        try {
488            String packageName = mContext.getPackageName();
489            PackageDataObserver observer = new PackageDataObserver();
490            //wait on observer
491            synchronized(observer) {
492                getPm().freeStorageAndNotify(idealStorageSize, observer);
493                long waitTime = 0;
494                while(!observer.isDone() || (waitTime > MAX_WAIT_TIME)) {
495                    observer.wait(WAIT_TIME_INCR);
496                    waitTime += WAIT_TIME_INCR;
497                }
498                if(!observer.isDone()) {
499                    throw new Exception("timed out waiting for PackageDataObserver.onRemoveCompleted");
500                }
501            }
502            return observer.retValue;
503        } catch (RemoteException e) {
504            Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e);
505            return false;
506        } catch (InterruptedException e) {
507            Log.w(TAG, "InterruptedException :"+e);
508            return false;
509        }
510    }
511
512    boolean invokePMFreeStorage(long idealStorageSize, FreeStorageReceiver r,
513            PendingIntent pi) throws Exception {
514        try {
515            // Spin lock waiting for call back
516            synchronized(r) {
517                getPm().freeStorage(idealStorageSize, pi.getIntentSender());
518                long waitTime = 0;
519                while(!r.isDone() && (waitTime < MAX_WAIT_TIME)) {
520                    r.wait(WAIT_TIME_INCR);
521                    waitTime += WAIT_TIME_INCR;
522                }
523                if(!r.isDone()) {
524                    throw new Exception("timed out waiting for call back from PendingIntent");
525                }
526            }
527            return r.getResultCode() == 1;
528        } catch (RemoteException e) {
529            Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e);
530            return false;
531        } catch (InterruptedException e) {
532            Log.w(TAG, "InterruptedException :"+e);
533            return false;
534        }
535    }
536
537    @LargeTest
538    public void testDeleteAppCacheFiles() throws Exception {
539        String testName="testDeleteAppCacheFiles";
540        File cacheDir = mContext.getCacheDir();
541        createTestFiles1(cacheDir, "testtmpdir", 5);
542        assertTrue(invokePMDeleteAppCacheFiles());
543        //confirm files dont exist
544        verifyTestFiles1(cacheDir, "testtmpdir", 5);
545    }
546
547    class PackageStatsObserver extends IPackageStatsObserver.Stub {
548        public boolean retValue = false;
549        public PackageStats stats;
550        private boolean doneFlag = false;
551
552        public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)
553                throws RemoteException {
554            synchronized(this) {
555                retValue = succeeded;
556                stats = pStats;
557                doneFlag = true;
558                notifyAll();
559            }
560        }
561        public boolean isDone() {
562            return doneFlag;
563        }
564    }
565
566    public PackageStats invokePMGetPackageSizeInfo() throws Exception {
567        try {
568            String packageName = mContext.getPackageName();
569            PackageStatsObserver observer = new PackageStatsObserver();
570            //wait on observer
571            synchronized(observer) {
572                getPm().getPackageSizeInfo(packageName, observer);
573                long waitTime = 0;
574                while((!observer.isDone()) || (waitTime > MAX_WAIT_TIME) ) {
575                    observer.wait(WAIT_TIME_INCR);
576                    waitTime += WAIT_TIME_INCR;
577                }
578                if(!observer.isDone()) {
579                    throw new Exception("Timed out waiting for PackageStatsObserver.onGetStatsCompleted");
580                }
581            }
582            if(localLOGV) Log.i(TAG, "OBSERVER RET VALUES code="+observer.stats.codeSize+
583                    ", data="+observer.stats.dataSize+", cache="+observer.stats.cacheSize);
584            return observer.stats;
585        } catch (RemoteException e) {
586            Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e);
587            return null;
588        } catch (InterruptedException e) {
589            Log.w(TAG, "InterruptedException :"+e);
590            return null;
591        }
592    }
593
594    @SmallTest
595    public void testGetPackageSizeInfo() throws Exception {
596        String testName="testGetPackageSizeInfo";
597        PackageStats stats = invokePMGetPackageSizeInfo();
598        assertTrue(stats!=null);
599        //confirm result
600        if(localLOGV) Log.i(TAG, "code="+stats.codeSize+", data="+stats.dataSize+
601                ", cache="+stats.cacheSize);
602    }
603
604    @SmallTest
605    public void testGetSystemSharedLibraryNames() throws Exception {
606        try {
607            String[] sharedLibs = getPm().getSystemSharedLibraryNames();
608            if (localLOGV) {
609                for (String str : sharedLibs) {
610                    Log.i(TAG, str);
611                }
612            }
613        } catch (RemoteException e) {
614            fail("Failed invoking getSystemSharedLibraryNames with exception:" + e);
615        }
616    }
617
618    class FreeStorageReceiver extends BroadcastReceiver {
619        public static final String ACTION_FREE = "com.android.unit_tests.testcallback";
620        private boolean doneFlag = false;
621
622        public boolean isDone() {
623            return doneFlag;
624        }
625
626        @Override
627        public void onReceive(Context context, Intent intent) {
628            if(intent.getAction().equalsIgnoreCase(ACTION_FREE)) {
629                if (localLOGV) Log.i(TAG, "Got notification: clear cache succeeded "+getResultCode());
630                synchronized (this) {
631                    doneFlag = true;
632                    notifyAll();
633                }
634            }
635        }
636    }
637
638    // TODO: flaky test, omit from LargeTest for now
639    //@LargeTest
640    public void testFreeStorage() throws Exception {
641        boolean TRACKING = true;
642        StatFs st = new StatFs("/data");
643        long blks1 = getFreeStorageBlks(st);
644        if(localLOGV || TRACKING) Log.i(TAG, "Available free blocks="+blks1);
645        long availableMem = getFreeStorageSize(st);
646        File cacheDir = mContext.getCacheDir();
647        assertNotNull(cacheDir);
648        createTestFiles1(cacheDir, "testtmpdir", 5);
649        long blks2 = getFreeStorageBlks(st);
650        if(localLOGV || TRACKING) Log.i(TAG, "Available blocks after writing test files in application cache="+blks2);
651        // Create receiver and register it
652        FreeStorageReceiver receiver = new FreeStorageReceiver();
653        mContext.registerReceiver(receiver, new IntentFilter(FreeStorageReceiver.ACTION_FREE));
654        PendingIntent pi = PendingIntent.getBroadcast(mContext,
655                0,  new Intent(FreeStorageReceiver.ACTION_FREE), 0);
656        // Invoke PackageManager api
657        if (!invokePMFreeStorage(availableMem, receiver, pi)) {
658            fail("Could not invoke PackageManager free storage API");
659        }
660        long blks3 = getFreeStorageBlks(st);
661        if(localLOGV || TRACKING) Log.i(TAG, "Available blocks after freeing cache"+blks3);
662        assertEquals(receiver.getResultCode(), 1);
663        mContext.unregisterReceiver(receiver);
664        // Verify result
665        verifyTestFiles1(cacheDir, "testtmpdir", 5);
666    }
667
668    /* utility method used to create observer and check async call back from PackageManager.
669     * ClearApplicationUserData
670     */
671    boolean invokePMClearApplicationUserData() throws Exception {
672        try {
673            String packageName = mContext.getPackageName();
674            PackageDataObserver observer = new PackageDataObserver();
675            //wait on observer
676            synchronized(observer) {
677                getPm().clearApplicationUserData(packageName, observer);
678                long waitTime = 0;
679                while(!observer.isDone() || (waitTime > MAX_WAIT_TIME)) {
680                    observer.wait(WAIT_TIME_INCR);
681                    waitTime += WAIT_TIME_INCR;
682                }
683                if(!observer.isDone()) {
684                    throw new Exception("timed out waiting for PackageDataObserver.onRemoveCompleted");
685                }
686            }
687            return observer.retValue;
688        } catch (RemoteException e) {
689            Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e);
690            return false;
691        } catch (InterruptedException e) {
692            Log.w(TAG, "InterruptedException :"+e);
693            return false;
694        }
695    }
696
697    void verifyUserDataCleared(File pDir) {
698        if(localLOGV) Log.i(TAG, "Verifying "+pDir);
699        if(pDir == null) {
700            return;
701        }
702        String fileList[] = pDir.list();
703        if(fileList == null) {
704            return;
705        }
706        int imax = fileList.length;
707       //look recursively in user data dir
708        for(int i = 0; i < imax; i++) {
709            if(localLOGV) Log.i(TAG, "Found entry "+fileList[i]+ "in "+pDir);
710            if("lib".equalsIgnoreCase(fileList[i])) {
711                if(localLOGV) Log.i(TAG, "Ignoring lib directory");
712                continue;
713            }
714            fail(pDir+" should be empty or contain only lib subdirectory. Found "+fileList[i]);
715        }
716    }
717
718    File getDataDir() {
719        try {
720            ApplicationInfo appInfo = getPm().getApplicationInfo(mContext.getPackageName(), 0);
721            return new File(appInfo.dataDir);
722        } catch (RemoteException e) {
723            throw new RuntimeException("Pacakge manager dead", e);
724        }
725    }
726
727    @LargeTest
728    public void testClearApplicationUserDataWithTestData() throws Exception {
729        File cacheDir = mContext.getCacheDir();
730        createTestFiles1(cacheDir, "testtmpdir", 5);
731        if(localLOGV) {
732            Log.i(TAG, "Created test data Waiting for 60seconds before continuing");
733            Thread.sleep(60*1000);
734        }
735        assertTrue(invokePMClearApplicationUserData());
736        //confirm files dont exist
737        verifyUserDataCleared(getDataDir());
738    }
739
740    @SmallTest
741    public void testClearApplicationUserDataWithNoTestData() throws Exception {
742        assertTrue(invokePMClearApplicationUserData());
743        //confirm files dont exist
744        verifyUserDataCleared(getDataDir());
745    }
746
747    @LargeTest
748    public void testClearApplicationUserDataNoObserver() throws Exception {
749        getPm().clearApplicationUserData(mContext.getPackageName(), null);
750        //sleep for 1 minute
751        Thread.sleep(60*1000);
752        //confirm files dont exist
753        verifyUserDataCleared(getDataDir());
754    }
755
756}
757