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