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