summaryrefslogtreecommitdiffstats
path: root/tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java')
-rwxr-xr-xtests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java654
1 files changed, 654 insertions, 0 deletions
diff --git a/tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java b/tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java
new file mode 100755
index 0000000..914d98b
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java
@@ -0,0 +1,654 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageDataObserver;
+import android.content.pm.IPackageStatsObserver;
+import android.content.pm.PackageStats;
+import android.content.pm.IPackageManager;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
+import android.util.Log;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.StatFs;
+
+public class AppCacheTest extends AndroidTestCase {
+ private static final boolean localLOGV = false;
+ public static final String TAG="AppCacheTest";
+ public final long MAX_WAIT_TIME=60*1000;
+ public final long WAIT_TIME_INCR=10*1000;
+ private static final int THRESHOLD=5;
+ private static final int ACTUAL_THRESHOLD=10;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ if(localLOGV) Log.i(TAG, "Cleaning up cache directory first");
+ cleanUpCacheDirectory();
+ }
+
+ void cleanUpDirectory(File pDir, String dirName) {
+ File testDir = new File(pDir, dirName);
+ if(!testDir.exists()) {
+ return;
+ }
+ String fList[] = testDir.list();
+ for(int i = 0; i < fList.length; i++) {
+ File file = new File(testDir, fList[i]);
+ if(file.isDirectory()) {
+ cleanUpDirectory(testDir, fList[i]);
+ } else {
+ file.delete();
+ }
+ }
+ testDir.delete();
+ }
+
+ void cleanUpCacheDirectory() {
+ File testDir = mContext.getCacheDir();
+ if(!testDir.exists()) {
+ return;
+ }
+
+ String fList[] = testDir.list();
+ if(fList == null) {
+ testDir.delete();
+ return;
+ }
+ for(int i = 0; i < fList.length; i++) {
+ File file = new File(testDir, fList[i]);
+ if(file.isDirectory()) {
+ cleanUpDirectory(testDir, fList[i]);
+ } else {
+ file.delete();
+ }
+ }
+ }
+
+ @SmallTest
+ public void testDeleteAllCacheFiles() {
+ String testName="testDeleteAllCacheFiles";
+ cleanUpCacheDirectory();
+ }
+
+ void failStr(String errMsg) {
+ Log.w(TAG, "errMsg="+errMsg);
+ fail(errMsg);
+ }
+ void failStr(Exception e) {
+ Log.w(TAG, "e.getMessage="+e.getMessage());
+ Log.w(TAG, "e="+e);
+ }
+ long getFreeStorageBlks(StatFs st) {
+ st.restat("/data");
+ return st.getFreeBlocks();
+ }
+
+ long getFreeStorageSize(StatFs st) {
+ st.restat("/data");
+ return (st.getFreeBlocks()*st.getBlockSize());
+ }
+ @LargeTest
+ public void testFreeApplicationCacheAllFiles() throws Exception {
+ StatFs st = new StatFs("/data");
+ long blks1 = getFreeStorageBlks(st);
+ long availableMem = getFreeStorageSize(st);
+ File cacheDir = mContext.getCacheDir();
+ assertNotNull(cacheDir);
+ createTestFiles1(cacheDir, "testtmpdir", 5);
+ long blks2 = getFreeStorageBlks(st);
+ if(localLOGV) Log.i(TAG, "blk1="+blks1+", blks2="+blks2);
+ //this should free up the test files that were created earlier
+ invokePMFreeApplicationCache(availableMem);
+ long blks3 = getFreeStorageBlks(st);
+ if(localLOGV) Log.i(TAG, "blks3="+blks3);
+ verifyTestFiles1(cacheDir, "testtmpdir", 5);
+ }
+
+ @LargeTest
+ public void testFreeApplicationCacheSomeFiles() throws Exception {
+ StatFs st = new StatFs("/data");
+ long blks1 = getFreeStorageBlks(st);
+ File cacheDir = mContext.getCacheDir();
+ assertNotNull(cacheDir);
+ createTestFiles1(cacheDir, "testtmpdir", 5);
+ long blks2 = getFreeStorageBlks(st);
+ Log.i(TAG, "blk1="+blks1+", blks2="+blks2);
+ long diff = (blks1-blks2-2);
+ assertTrue(invokePMFreeApplicationCache(diff*st.getBlockSize()));
+ long blks3 = getFreeStorageBlks(st);
+ //blks3 should be greater than blks2 and less than blks1
+ if(!((blks3 <= blks1) && (blks3 >= blks2))) {
+ failStr("Expected "+(blks1-blks2)+" number of blocks to be freed but freed only "
+ +(blks1-blks3));
+ }
+ }
+
+ /**
+ * This method opens an output file writes to it, opens the same file as an input
+ * stream, reads the contents and verifies the data that was written earlier can be read
+ */
+ public void openOutFileInAppFilesDir(File pFile, String pFileOut) {
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(pFile);
+ } catch (FileNotFoundException e1) {
+ failStr("Error when opening file "+e1);
+ return;
+ }
+ try {
+ fos.write(pFileOut.getBytes());
+ fos.close();
+ } catch (FileNotFoundException e) {
+ failStr(e.getMessage());
+ } catch (IOException e) {
+ failStr(e.getMessage());
+ }
+ int count = pFileOut.getBytes().length;
+ byte[] buffer = new byte[count];
+ try {
+ FileInputStream fis = new FileInputStream(pFile);
+ fis.read(buffer, 0, count);
+ fis.close();
+ } catch (FileNotFoundException e) {
+ failStr("Failed when verifing output opening file "+e.getMessage());
+ } catch (IOException e) {
+ failStr("Failed when verifying output, reading from written file "+e);
+ }
+ String str = new String(buffer);
+ assertEquals(str, pFileOut);
+ }
+
+ /*
+ * This test case verifies that output written to a file
+ * using Context.openFileOutput has executed successfully.
+ * The operation is verified by invoking Context.openFileInput
+ */
+ @MediumTest
+ public void testAppFilesCreateFile() {
+ String fileName = "testFile1.txt";
+ String fileOut = "abcdefghijklmnopqrstuvwxyz";
+ Context con = super.getContext();
+ try {
+ FileOutputStream fos = con.openFileOutput(fileName, Context.MODE_PRIVATE);
+ fos.close();
+ } catch (FileNotFoundException e) {
+ failStr(e);
+ } catch (IOException e) {
+ failStr(e);
+ }
+ }
+
+ @SmallTest
+ public void testAppCacheCreateFile() {
+ String fileName = "testFile1.txt";
+ String fileOut = "abcdefghijklmnopqrstuvwxyz";
+ Context con = super.getContext();
+ File file = new File(con.getCacheDir(), fileName);
+ openOutFileInAppFilesDir(file, fileOut);
+ cleanUpCacheDirectory();
+ }
+
+ @MediumTest
+ public void testAppCreateCacheFiles() {
+ File cacheDir = mContext.getCacheDir();
+ String testDirName = "testtmp";
+ File testTmpDir = new File(cacheDir, testDirName);
+ testTmpDir.mkdir();
+ int numDirs = 3;
+ File fileArr[] = new File[numDirs];
+ for(int i = 0; i < numDirs; i++) {
+ fileArr[i] = new File(testTmpDir, "dir"+(i+1));
+ fileArr[i].mkdir();
+ }
+ byte buffer[] = getBuffer();
+ Log.i(TAG, "Size of bufer="+buffer.length);
+ for(int i = 0; i < numDirs; i++) {
+ for(int j = 1; j <= (i); j++) {
+ File file1 = new File(fileArr[i], "testFile"+j+".txt");
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(file1);
+ for(int k = 1; k < 10; k++) {
+ fos.write(buffer);
+ }
+ Log.i(TAG, "wrote 10K bytes to "+file1);
+ fos.close();
+ } catch (FileNotFoundException e) {
+ Log.i(TAG, "Excetion ="+e);
+ fail("Error when creating outputstream "+e);
+ } catch(IOException e) {
+ Log.i(TAG, "Excetion ="+e);
+ fail("Error when writing output "+e);
+ }
+ }
+ }
+ }
+
+ byte[] getBuffer() {
+ String sbuffer = "a";
+ for(int i = 0; i < 10; i++) {
+ sbuffer += sbuffer;
+ }
+ return sbuffer.getBytes();
+ }
+
+ long getFileNumBlocks(long fileSize, int blkSize) {
+ long ret = fileSize/blkSize;
+ if(ret*blkSize < fileSize) {
+ ret++;
+ }
+ return ret;
+ }
+
+ //@LargeTest
+ public void testAppCacheClear() {
+ String dataDir="/data/data";
+ StatFs st = new StatFs(dataDir);
+ int blkSize = st.getBlockSize();
+ int totBlks = st.getBlockCount();
+ long availableBlks = st.getFreeBlocks();
+ long thresholdBlks = (totBlks*THRESHOLD)/100;
+ String testDirName = "testdir";
+ //create directory in cache
+ File testDir = new File(mContext.getCacheDir(), testDirName);
+ testDir.mkdirs();
+ byte[] buffer = getBuffer();
+ int i = 1;
+ if(localLOGV) Log.i(TAG, "availableBlks="+availableBlks+", thresholdBlks="+thresholdBlks);
+ long createdFileBlks = 0;
+ int imax = 300;
+ while((availableBlks > thresholdBlks) &&(i < imax)) {
+ File testFile = new File(testDir, "testFile"+i+".txt");
+ if(localLOGV) Log.i(TAG, "Creating "+i+"th test file "+testFile);
+ int jmax = i;
+ i++;
+ FileOutputStream fos;
+ try {
+ fos = new FileOutputStream(testFile);
+ } catch (FileNotFoundException e) {
+ Log.i(TAG, "Failed creating test file:"+testFile);
+ continue;
+ }
+ boolean err = false;
+ for(int j = 1; j <= jmax;j++) {
+ try {
+ fos.write(buffer);
+ } catch (IOException e) {
+ Log.i(TAG, "Failed to write to file:"+testFile);
+ err = true;
+ }
+ }
+ try {
+ fos.close();
+ } catch (IOException e) {
+ Log.i(TAG, "Failed closing file:"+testFile);
+ }
+ if(err) {
+ continue;
+ }
+ createdFileBlks += getFileNumBlocks(testFile.length(), blkSize);
+ st.restat(dataDir);
+ availableBlks = st.getFreeBlocks();
+ }
+ st.restat(dataDir);
+ long availableBytes = st.getFreeBlocks()*blkSize;
+ long shouldFree = (ACTUAL_THRESHOLD-THRESHOLD)*totBlks;
+ //would have run out of memory
+ //wait for some time and confirm cache is deleted
+ try {
+ Log.i(TAG, "Sleeping for 2 minutes...");
+ Thread.sleep(2*60*1000);
+ } catch (InterruptedException e) {
+ fail("Exception when sleeping "+e);
+ }
+ boolean removedFlag = false;
+ long existingFileBlks = 0;
+ for(int k = 1; k <i; k++) {
+ File testFile = new File(testDir, "testFile"+k+".txt");
+ if(!testFile.exists()) {
+ removedFlag = true;
+ if(localLOGV) Log.i(TAG, testFile+" removed");
+ } else {
+ existingFileBlks += getFileNumBlocks(testFile.length(), blkSize);
+ }
+ }
+ if(localLOGV) Log.i(TAG, "createdFileBlks="+createdFileBlks+
+ ", existingFileBlks="+existingFileBlks);
+ long fileSize = createdFileBlks-existingFileBlks;
+ //verify fileSize number of bytes have been cleared from cache
+ if(localLOGV) Log.i(TAG, "deletedFileBlks="+fileSize+" shouldFreeBlks="+shouldFree);
+ if((fileSize > (shouldFree-blkSize) && (fileSize < (shouldFree+blkSize)))) {
+ Log.i(TAG, "passed");
+ }
+ assertTrue(removedFlag);
+ }
+
+ //createTestFiles(new File(super.getContext().getCacheDir(), "testtmp", "dir", 3)
+ void createTestFiles1(File cacheDir, String testFilePrefix, int numTestFiles) {
+ byte buffer[] = getBuffer();
+ for(int i = 0; i < numTestFiles; i++) {
+ File file1 = new File(cacheDir, testFilePrefix+i+".txt");
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(file1);
+ for(int k = 1; k < 10; k++) {
+ fos.write(buffer);
+ }
+ fos.close();
+ } catch (FileNotFoundException e) {
+ Log.i(TAG, "Exception ="+e);
+ fail("Error when creating outputstream "+e);
+ } catch(IOException e) {
+ Log.i(TAG, "Exception ="+e);
+ fail("Error when writing output "+e);
+ }
+ try {
+ //introduce sleep for 1 s to avoid common time stamps for files being created
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ fail("Exception when sleeping "+e);
+ }
+ }
+ }
+
+ void verifyTestFiles1(File cacheDir, String testFilePrefix, int numTestFiles) {
+ for(int i = 0; i < numTestFiles; i++) {
+ File file1 = new File(cacheDir, testFilePrefix+i+".txt");
+ if(file1.exists()) {
+ fail("file:"+file1+" should not exist");
+ }
+ }
+ }
+
+ void createTestFiles2(File cacheDir, String rootTestDirName, String subDirPrefix, int numDirs, String testFilePrefix) {
+ Context con = super.getContext();
+ File testTmpDir = new File(cacheDir, rootTestDirName);
+ testTmpDir.mkdir();
+ File fileArr[] = new File[numDirs];
+ for(int i = 0; i < numDirs; i++) {
+ fileArr[i] = new File(testTmpDir, subDirPrefix+(i+1));
+ fileArr[i].mkdir();
+ }
+ byte buffer[] = getBuffer();
+ for(int i = 0; i < numDirs; i++) {
+ for(int j = 1; j <= (i); j++) {
+ File file1 = new File(fileArr[i], testFilePrefix+j+".txt");
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(file1);
+ for(int k = 1; k < 10; k++) {
+ fos.write(buffer);
+ }
+ fos.close();
+ } catch (FileNotFoundException e) {
+ Log.i(TAG, "Exception ="+e);
+ fail("Error when creating outputstream "+e);
+ } catch(IOException e) {
+ Log.i(TAG, "Exception ="+e);
+ fail("Error when writing output "+e);
+ }
+ try {
+ //introduce sleep for 10 ms to avoid common time stamps for files being created
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ fail("Exception when sleeping "+e);
+ }
+ }
+ }
+ }
+
+ class PackageDataObserver extends IPackageDataObserver.Stub {
+ public boolean retValue = false;
+ private boolean doneFlag = false;
+ public void onRemoveCompleted(String packageName, boolean succeeded)
+ throws RemoteException {
+ synchronized(this) {
+ retValue = succeeded;
+ doneFlag = true;
+ notifyAll();
+ }
+ }
+ public boolean isDone() {
+ return doneFlag;
+ }
+ }
+
+ IPackageManager getPm() {
+ return IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
+ }
+
+ boolean invokePMDeleteAppCacheFiles() throws Exception {
+ try {
+ String packageName = mContext.getPackageName();
+ PackageDataObserver observer = new PackageDataObserver();
+ //wait on observer
+ synchronized(observer) {
+ getPm().deleteApplicationCacheFiles(packageName, observer);
+ long waitTime = 0;
+ while(!observer.isDone() || (waitTime > MAX_WAIT_TIME)) {
+ observer.wait(WAIT_TIME_INCR);
+ waitTime += WAIT_TIME_INCR;
+ }
+ if(!observer.isDone()) {
+ throw new Exception("timed out waiting for PackageDataObserver.onRemoveCompleted");
+ }
+ }
+ return observer.retValue;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e);
+ return false;
+ } catch (InterruptedException e) {
+ Log.w(TAG, "InterruptedException :"+e);
+ return false;
+ }
+ }
+
+ boolean invokePMFreeApplicationCache(long idealStorageSize) throws Exception {
+ try {
+
+ String packageName = mContext.getPackageName();
+ PackageDataObserver observer = new PackageDataObserver();
+ //wait on observer
+ synchronized(observer) {
+ getPm().freeApplicationCache(idealStorageSize, observer);
+ long waitTime = 0;
+ while(!observer.isDone() || (waitTime > MAX_WAIT_TIME)) {
+ observer.wait(WAIT_TIME_INCR);
+ waitTime += WAIT_TIME_INCR;
+ }
+ if(!observer.isDone()) {
+ throw new Exception("timed out waiting for PackageDataObserver.onRemoveCompleted");
+ }
+ }
+ return observer.retValue;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e);
+ return false;
+ } catch (InterruptedException e) {
+ Log.w(TAG, "InterruptedException :"+e);
+ return false;
+ }
+ }
+
+ @LargeTest
+ public void testDeleteAppCacheFiles() throws Exception {
+ String testName="testDeleteAppCacheFiles";
+ File cacheDir = mContext.getCacheDir();
+ createTestFiles1(cacheDir, "testtmpdir", 5);
+ assertTrue(invokePMDeleteAppCacheFiles());
+ //confirm files dont exist
+ verifyTestFiles1(cacheDir, "testtmpdir", 5);
+ }
+
+ class PackageStatsObserver extends IPackageStatsObserver.Stub {
+ public boolean retValue = false;
+ public PackageStats stats;
+ private boolean doneFlag = false;
+
+ public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)
+ throws RemoteException {
+ synchronized(this) {
+ retValue = succeeded;
+ stats = pStats;
+ doneFlag = true;
+ notifyAll();
+ }
+ }
+ public boolean isDone() {
+ return doneFlag;
+ }
+ }
+
+ public PackageStats invokePMGetPackageSizeInfo() throws Exception {
+ try {
+ String packageName = mContext.getPackageName();
+ PackageStatsObserver observer = new PackageStatsObserver();
+ //wait on observer
+ synchronized(observer) {
+ getPm().getPackageSizeInfo(packageName, observer);
+ long waitTime = 0;
+ while((!observer.isDone()) || (waitTime > MAX_WAIT_TIME) ) {
+ observer.wait(WAIT_TIME_INCR);
+ waitTime += WAIT_TIME_INCR;
+ }
+ if(!observer.isDone()) {
+ throw new Exception("Timed out waiting for PackageStatsObserver.onGetStatsCompleted");
+ }
+ }
+ if(localLOGV) Log.i(TAG, "OBSERVER RET VALUES code="+observer.stats.codeSize+
+ ", data="+observer.stats.dataSize+", cache="+observer.stats.cacheSize);
+ return observer.stats;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e);
+ return null;
+ } catch (InterruptedException e) {
+ Log.w(TAG, "InterruptedException :"+e);
+ return null;
+ }
+ }
+
+ @SmallTest
+ public void testGetPackageSizeInfo() throws Exception {
+ String testName="testGetPackageSizeInfo";
+ PackageStats stats = invokePMGetPackageSizeInfo();
+ assertTrue(stats!=null);
+ //confirm result
+ if(localLOGV) Log.i(TAG, "code="+stats.codeSize+", data="+stats.dataSize+
+ ", cache="+stats.cacheSize);
+ }
+
+ /* utility method used to create observer and check async call back from PackageManager.
+ * ClearApplicationUserData
+ */
+ boolean invokePMClearApplicationUserData() throws Exception {
+ try {
+ String packageName = mContext.getPackageName();
+ PackageDataObserver observer = new PackageDataObserver();
+ //wait on observer
+ synchronized(observer) {
+ getPm().clearApplicationUserData(packageName, observer);
+ long waitTime = 0;
+ while(!observer.isDone() || (waitTime > MAX_WAIT_TIME)) {
+ observer.wait(WAIT_TIME_INCR);
+ waitTime += WAIT_TIME_INCR;
+ }
+ if(!observer.isDone()) {
+ throw new Exception("timed out waiting for PackageDataObserver.onRemoveCompleted");
+ }
+ }
+ return observer.retValue;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e);
+ return false;
+ } catch (InterruptedException e) {
+ Log.w(TAG, "InterruptedException :"+e);
+ return false;
+ }
+ }
+
+ void verifyUserDataCleared(File pDir) {
+ if(localLOGV) Log.i(TAG, "Verifying "+pDir);
+ if(pDir == null) {
+ return;
+ }
+ String fileList[] = pDir.list();
+ if(fileList == null) {
+ return;
+ }
+ int imax = fileList.length;
+ //look recursively in user data dir
+ for(int i = 0; i < imax; i++) {
+ if(localLOGV) Log.i(TAG, "Found entry "+fileList[i]+ "in "+pDir);
+ if("lib".equalsIgnoreCase(fileList[i])) {
+ if(localLOGV) Log.i(TAG, "Ignoring lib directory");
+ continue;
+ }
+ fail(pDir+" should be empty or contain only lib subdirectory. Found "+fileList[i]);
+ }
+ }
+
+ File getDataDir() {
+ try {
+ ApplicationInfo appInfo = getPm().getApplicationInfo(mContext.getPackageName(), 0);
+ return new File(appInfo.dataDir);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Pacakge manager dead", e);
+ }
+ }
+
+ @LargeTest
+ public void testClearApplicationUserDataWithTestData() throws Exception {
+ File cacheDir = mContext.getCacheDir();
+ createTestFiles1(cacheDir, "testtmpdir", 5);
+ if(localLOGV) {
+ Log.i(TAG, "Created test data Waiting for 60seconds before continuing");
+ Thread.sleep(60*1000);
+ }
+ assertTrue(invokePMClearApplicationUserData());
+ //confirm files dont exist
+ verifyUserDataCleared(getDataDir());
+ }
+
+ @SmallTest
+ public void testClearApplicationUserDataWithNoTestData() throws Exception {
+ assertTrue(invokePMClearApplicationUserData());
+ //confirm files dont exist
+ verifyUserDataCleared(getDataDir());
+ }
+
+ @LargeTest
+ public void testClearApplicationUserDataNoObserver() throws Exception {
+ getPm().clearApplicationUserData(mContext.getPackageName(), null);
+ //sleep for 1 minute
+ Thread.sleep(60*1000);
+ //confirm files dont exist
+ verifyUserDataCleared(getDataDir());
+ }
+
+}