1616
1717package android .content .pm ;
1818
19+ import static libcore .io .OsConstants .*;
20+
1921import com .android .frameworks .coretests .R ;
2022import com .android .internal .content .PackageHelper ;
2123
3234import android .os .Environment ;
3335import android .os .FileUtils ;
3436import android .os .IBinder ;
37+ import android .os .Process ;
3538import android .os .RemoteException ;
3639import android .os .ServiceManager ;
3740import android .os .StatFs ;
41+ import android .os .SystemClock ;
3842import android .os .storage .IMountService ;
3943import android .os .storage .StorageListener ;
4044import android .os .storage .StorageManager ;
5256import java .io .InputStream ;
5357
5458import java .util .List ;
59+ import java .util .concurrent .CountDownLatch ;
60+ import java .util .concurrent .TimeUnit ;
61+
62+ import libcore .io .ErrnoException ;
63+ import libcore .io .Libcore ;
64+ import libcore .io .StructStat ;
5565
5666public class PackageManagerTests extends AndroidTestCase {
5767 private static final boolean localLOGV = true ;
@@ -404,15 +414,12 @@ private void assertInstall(PackageParser.Package pkg, int flags, int expInstallL
404414 if ((flags & PackageManager .INSTALL_FORWARD_LOCK ) != 0 ) {
405415 assertTrue ("The application should be installed forward locked" ,
406416 (info .flags & ApplicationInfo .FLAG_FORWARD_LOCK ) != 0 );
407- assertTrue ("The APK path (" + srcPath + ") should start with "
408- + SECURE_CONTAINERS_PREFIX ,
409- srcPath .startsWith (SECURE_CONTAINERS_PREFIX ));
410- assertTrue ("The public APK path (" + publicSrcPath + ") should start with "
411- + SECURE_CONTAINERS_PREFIX ,
412- publicSrcPath .startsWith (SECURE_CONTAINERS_PREFIX ));
413- assertTrue ("The native library path (" + info .nativeLibraryDir
414- + ") should start with " + SECURE_CONTAINERS_PREFIX ,
415- info .nativeLibraryDir .startsWith (SECURE_CONTAINERS_PREFIX ));
417+ assertStartsWith ("The APK path should point to the ASEC" ,
418+ SECURE_CONTAINERS_PREFIX , srcPath );
419+ assertStartsWith ("The public APK path should point to the ASEC" ,
420+ SECURE_CONTAINERS_PREFIX , publicSrcPath );
421+ assertStartsWith ("The native library path should point to the ASEC" ,
422+ SECURE_CONTAINERS_PREFIX , info .nativeLibraryDir );
416423 try {
417424 String compatLib = new File (info .dataDir + "/lib" ).getCanonicalPath ();
418425 assertEquals ("The compatibility lib directory should be a symbolic link to "
@@ -425,7 +432,14 @@ private void assertInstall(PackageParser.Package pkg, int flags, int expInstallL
425432 assertFalse ((info .flags & ApplicationInfo .FLAG_FORWARD_LOCK ) != 0 );
426433 assertEquals (srcPath , appInstallPath );
427434 assertEquals (publicSrcPath , appInstallPath );
428- assertTrue (info .nativeLibraryDir .startsWith (dataDir .getPath ()));
435+ assertStartsWith ("Native library should point to shared lib directory" ,
436+ dataDir .getPath (),
437+ info .nativeLibraryDir );
438+ assertDirOwnerGroupPerms (
439+ "Native library directory should be owned by system:system and 0755" ,
440+ Process .SYSTEM_UID , Process .SYSTEM_UID ,
441+ S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH ,
442+ info .nativeLibraryDir );
429443 }
430444 assertFalse ((info .flags & ApplicationInfo .FLAG_EXTERNAL_STORAGE ) != 0 );
431445
@@ -435,8 +449,7 @@ private void assertInstall(PackageParser.Package pkg, int flags, int expInstallL
435449 nativeLibDir .exists ());
436450 try {
437451 assertEquals ("Native library dir should not be a symlink" ,
438- info .nativeLibraryDir ,
439- nativeLibDir .getCanonicalPath ());
452+ info .nativeLibraryDir , nativeLibDir .getCanonicalPath ());
440453 } catch (IOException e ) {
441454 fail ("Can't read " + nativeLibDir .getPath ());
442455 }
@@ -453,14 +466,12 @@ private void assertInstall(PackageParser.Package pkg, int flags, int expInstallL
453466 (info .flags & ApplicationInfo .FLAG_EXTERNAL_STORAGE ) != 0 );
454467 // Might need to check:
455468 // ((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0)
456- assertTrue ("The APK path (" + srcPath + ") should start with "
457- + SECURE_CONTAINERS_PREFIX , srcPath .startsWith (SECURE_CONTAINERS_PREFIX ));
458- assertTrue ("The public APK path (" + publicSrcPath + ") should start with "
459- + SECURE_CONTAINERS_PREFIX ,
460- publicSrcPath .startsWith (SECURE_CONTAINERS_PREFIX ));
461- assertTrue ("The native library path (" + info .nativeLibraryDir
462- + ") should start with " + SECURE_CONTAINERS_PREFIX ,
463- info .nativeLibraryDir .startsWith (SECURE_CONTAINERS_PREFIX ));
469+ assertStartsWith ("The APK path should point to the ASEC" ,
470+ SECURE_CONTAINERS_PREFIX , srcPath );
471+ assertStartsWith ("The public APK path should point to the ASEC" ,
472+ SECURE_CONTAINERS_PREFIX , publicSrcPath );
473+ assertStartsWith ("The native library path should point to the ASEC" ,
474+ SECURE_CONTAINERS_PREFIX , info .nativeLibraryDir );
464475
465476 // Make sure the native library in /data/data/<app>/lib is a
466477 // symlink to the ASEC
@@ -483,6 +494,66 @@ private void assertInstall(PackageParser.Package pkg, int flags, int expInstallL
483494 }
484495 }
485496
497+ private void assertDirOwnerGroupPerms (String reason , int uid , int gid , int perms , String path ) {
498+ final StructStat stat ;
499+
500+ try {
501+ stat = Libcore .os .lstat (path );
502+ } catch (ErrnoException e ) {
503+ throw new AssertionError (reason + "\n " + "Got: " + path + " does not exist" );
504+ }
505+
506+ StringBuilder sb = new StringBuilder ();
507+
508+ if (!S_ISDIR (stat .st_mode )) {
509+ sb .append ("\n Expected type: " );
510+ sb .append (S_IFDIR );
511+ sb .append ("\n got type: " );
512+ sb .append ((stat .st_mode & S_IFMT ));
513+ }
514+
515+ if (stat .st_uid != uid ) {
516+ sb .append ("\n Expected owner: " );
517+ sb .append (uid );
518+ sb .append ("\n Got owner: " );
519+ sb .append (stat .st_uid );
520+ }
521+
522+ if (stat .st_gid != gid ) {
523+ sb .append ("\n Expected group: " );
524+ sb .append (gid );
525+ sb .append ("\n Got group: " );
526+ sb .append (stat .st_gid );
527+ }
528+
529+ if ((stat .st_mode & ~S_IFMT ) != perms ) {
530+ sb .append ("\n Expected permissions: " );
531+ sb .append (Integer .toOctalString (perms ));
532+ sb .append ("\n Got permissions: " );
533+ sb .append (Integer .toOctalString (stat .st_mode & ~S_IFMT ));
534+ }
535+
536+ if (sb .length () > 0 ) {
537+ throw new AssertionError (reason + sb .toString ());
538+ }
539+ }
540+
541+ private static void assertStartsWith (String prefix , String actual ) {
542+ assertStartsWith ("" , prefix , actual );
543+ }
544+
545+ private static void assertStartsWith (String description , String prefix , String actual ) {
546+ if (!actual .startsWith (prefix )) {
547+ StringBuilder sb = new StringBuilder (description );
548+ sb .append ("\n Expected prefix: " );
549+ sb .append (prefix );
550+ sb .append ("\n got: " );
551+ sb .append (actual );
552+ sb .append ('\n' );
553+ throw new AssertionError (sb .toString ());
554+ }
555+ }
556+
486557 private void assertNotInstalled (String pkgName ) {
487558 try {
488559 ApplicationInfo info = getPm ().getApplicationInfo (pkgName , 0 );
@@ -820,22 +891,51 @@ public void testReplaceSdcard() throws Exception {
820891 | PackageManager .INSTALL_EXTERNAL );
821892 }
822893
823- /* -------------- Delete tests ---*/
894+ /* -------------- Delete tests --- */
824895 private static class DeleteObserver extends IPackageDeleteObserver .Stub {
896+ private CountDownLatch mLatch = new CountDownLatch (1 );
825897
826- public boolean succeeded ;
827- private boolean doneFlag = false ;
898+ private int mReturnCode ;
828899
829- public boolean isDone () {
830- return doneFlag ;
900+ private final String mPackageName ;
901+
902+ private String mObservedPackage ;
903+
904+ public DeleteObserver (String packageName ) {
905+ mPackageName = packageName ;
906+ }
907+
908+ public boolean isSuccessful () {
909+ return mReturnCode == PackageManager .DELETE_SUCCEEDED ;
831910 }
832911
833912 public void packageDeleted (String packageName , int returnCode ) throws RemoteException {
834- synchronized (this ) {
835- this .succeeded = returnCode == PackageManager .DELETE_SUCCEEDED ;
836- doneFlag = true ;
837- notifyAll ();
913+ mObservedPackage = packageName ;
914+
915+ mReturnCode = returnCode ;
916+
917+ mLatch .countDown ();
918+ }
919+
920+ public void waitForCompletion (long timeoutMillis ) {
921+ final long deadline = SystemClock .uptimeMillis () + timeoutMillis ;
922+
923+ long waitTime = timeoutMillis ;
924+ while (waitTime > 0 ) {
925+ try {
926+ boolean done = mLatch .await (waitTime , TimeUnit .MILLISECONDS );
927+ if (done ) {
928+ assertEquals (mPackageName , mObservedPackage );
929+ return ;
930+ }
931+ } catch (InterruptedException e ) {
932+ // TODO Auto-generated catch block
933+ e .printStackTrace ();
934+ }
935+ waitTime = deadline - SystemClock .uptimeMillis ();
838936 }
937+
938+ throw new AssertionError ("Timeout waiting for package deletion" );
839939 }
840940 }
841941
@@ -863,41 +963,40 @@ public boolean notifyNow(Intent intent) {
863963 }
864964 }
865965
866- public boolean invokeDeletePackage (final String pkgName , int flags ,
867- GenericReceiver receiver ) throws Exception {
868- DeleteObserver observer = new DeleteObserver ();
869- final boolean received = false ;
966+ public boolean invokeDeletePackage (final String pkgName , int flags , GenericReceiver receiver )
967+ throws Exception {
968+ ApplicationInfo info = getPm ().getApplicationInfo (pkgName ,
969+ PackageManager .GET_UNINSTALLED_PACKAGES );
970+
870971 mContext .registerReceiver (receiver , receiver .filter );
871972 try {
872- // Wait on observer
873- synchronized (observer ) {
874- synchronized (receiver ) {
875- getPm ().deletePackage (pkgName , observer , flags );
876- long waitTime = 0 ;
877- while ((!observer .isDone ()) && (waitTime < MAX_WAIT_TIME ) ) {
878- observer .wait (WAIT_TIME_INCR );
879- waitTime += WAIT_TIME_INCR ;
880- }
881- if (!observer .isDone ()) {
882- throw new Exception ("Timed out waiting for packageInstalled callback" );
883- }
884- // Verify we received the broadcast
885- waitTime = 0 ;
886- while ((!receiver .isDone ()) && (waitTime < MAX_WAIT_TIME ) ) {
887- receiver .wait (WAIT_TIME_INCR );
888- waitTime += WAIT_TIME_INCR ;
889- }
890- if (!receiver .isDone ()) {
891- throw new Exception ("Timed out waiting for PACKAGE_REMOVED notification" );
892- }
893- return receiver .received ;
894- }
973+ DeleteObserver observer = new DeleteObserver (pkgName );
974+
975+ getPm ().deletePackage (pkgName , observer , flags );
976+ observer .waitForCompletion (MAX_WAIT_TIME );
977+
978+ assertUninstalled (info );
979+
980+ // Verify we received the broadcast
981+ long waitTime = 0 ;
982+ while ((!receiver .isDone ()) && (waitTime < MAX_WAIT_TIME )) {
983+ receiver .wait (WAIT_TIME_INCR );
984+ waitTime += WAIT_TIME_INCR ;
895985 }
986+ if (!receiver .isDone ()) {
987+ throw new Exception ("Timed out waiting for PACKAGE_REMOVED notification" );
988+ }
989+ return receiver .received ;
896990 } finally {
897991 mContext .unregisterReceiver (receiver );
898992 }
899993 }
900994
995+ private static void assertUninstalled (ApplicationInfo info ) throws Exception {
996+ File nativeLibraryFile = new File (info .nativeLibraryDir );
997+ assertFalse ("Native library directory should be erased" , nativeLibraryFile .exists ());
998+ }
999+
9011000 public void deleteFromRawResource (int iFlags , int dFlags ) throws Exception {
9021001 InstallParams ip = sampleInstallFromRawResource (iFlags , false );
9031002 boolean retainData = ((dFlags & PackageManager .DELETE_KEEP_DATA ) != 0 );
@@ -1212,11 +1311,29 @@ void cleanUpInstall(InstallParams ip) throws Exception {
12121311 return ;
12131312 }
12141313 Runtime .getRuntime ().gc ();
1215- Log .i (TAG , "Deleting package : " + ip .pkg .packageName );
1216- getPm ().deletePackage (ip .pkg .packageName , null , 0 );
1217- File outFile = new File (ip .pkg .mScanPath );
1218- if (outFile != null && outFile .exists ()) {
1219- outFile .delete ();
1314+
1315+ final String packageName = ip .pkg .packageName ;
1316+ Log .i (TAG , "Deleting package : " + packageName );
1317+
1318+ ApplicationInfo info = null ;
1319+ try {
1320+ info = getPm ().getApplicationInfo (packageName , PackageManager .GET_UNINSTALLED_PACKAGES );
1321+ } catch (NameNotFoundException ignored ) {
1322+ }
1323+
1324+ DeleteObserver observer = new DeleteObserver (packageName );
1325+ getPm ().deletePackage (packageName , observer , 0 );
1326+ observer .waitForCompletion (MAX_WAIT_TIME );
1327+
1328+ try {
1329+ if (info != null ) {
1330+ assertUninstalled (info );
1331+ }
1332+ } finally {
1333+ File outFile = new File (ip .pkg .mScanPath );
1334+ if (outFile != null && outFile .exists ()) {
1335+ outFile .delete ();
1336+ }
12201337 }
12211338 }
12221339
@@ -1230,7 +1347,10 @@ private void cleanUpInstall(String pkgName) throws Exception {
12301347 PackageManager .GET_UNINSTALLED_PACKAGES );
12311348
12321349 if (info != null ) {
1233- getPm ().deletePackage (pkgName , null , 0 );
1350+ DeleteObserver observer = new DeleteObserver (pkgName );
1351+ getPm ().deletePackage (pkgName , observer , 0 );
1352+ observer .waitForCompletion (MAX_WAIT_TIME );
1353+ assertUninstalled (info );
12341354 }
12351355 } catch (NameNotFoundException e ) {
12361356 }
@@ -1587,16 +1707,16 @@ private void moveFromRawResource(String outFileName, int rawResId, int installFl
15871707 if ((moveFlags & PackageManager .MOVE_INTERNAL ) != 0 ) {
15881708 assertTrue ("ApplicationInfo.FLAG_EXTERNAL_STORAGE flag should NOT be set" ,
15891709 (info .flags & ApplicationInfo .FLAG_EXTERNAL_STORAGE ) == 0 );
1590- assertTrue ( "ApplicationInfo.nativeLibraryDir should start with " + info . dataDir ,
1591- info .nativeLibraryDir . startsWith ( info .dataDir ) );
1592- } else if ((moveFlags & PackageManager .MOVE_EXTERNAL_MEDIA ) != 0 ){
1710+ assertStartsWith ( "Native library dir should be in dataDir" ,
1711+ info .dataDir , info .nativeLibraryDir );
1712+ } else if ((moveFlags & PackageManager .MOVE_EXTERNAL_MEDIA ) != 0 ) {
15931713 assertTrue ("ApplicationInfo.FLAG_EXTERNAL_STORAGE flag should be set" ,
15941714 (info .flags & ApplicationInfo .FLAG_EXTERNAL_STORAGE ) != 0 );
1595- assertTrue ( "ApplicationInfo.nativeLibraryDir should start with " + SECURE_CONTAINERS_PREFIX ,
1596- info .nativeLibraryDir . startsWith ( SECURE_CONTAINERS_PREFIX ) );
1715+ assertStartsWith ( "Native library dir should point to ASEC" ,
1716+ SECURE_CONTAINERS_PREFIX , info .nativeLibraryDir );
15971717 final File nativeLibSymLink = new File (info .dataDir , "lib" );
1598- assertTrue ("The data directory should have a 'lib' symlink that points to the ASEC container" ,
1599- nativeLibSymLink .getCanonicalPath (). startsWith ( SECURE_CONTAINERS_PREFIX ));
1718+ assertStartsWith ("The data directory should have a 'lib' symlink that points to the ASEC container" ,
1719+ SECURE_CONTAINERS_PREFIX , nativeLibSymLink .getCanonicalPath ());
16001720 }
16011721 }
16021722 } catch (NameNotFoundException e ) {
0 commit comments