Merge commit '1aa64b53eb9b3cc7904705076a015a5cd0e3b536' into kraken * commit '1aa64b53eb9b3cc7904705076a015a5cd0e3b536': Change certificate policy.
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:installLocation="internalOnly"
|
||||
package="com.android.frameworks.coretests">
|
||||
|
||||
<permission android:name="com.android.frameworks.coretests.permission.TEST_GRANTED"
|
||||
|
||||
BIN
core/tests/coretests/res/raw/install_app1_cert1
Normal file
BIN
core/tests/coretests/res/raw/install_app1_cert1
Normal file
Binary file not shown.
BIN
core/tests/coretests/res/raw/install_app1_cert1_cert2
Normal file
BIN
core/tests/coretests/res/raw/install_app1_cert1_cert2
Normal file
Binary file not shown.
BIN
core/tests/coretests/res/raw/install_app1_cert2
Normal file
BIN
core/tests/coretests/res/raw/install_app1_cert2
Normal file
Binary file not shown.
BIN
core/tests/coretests/res/raw/install_app1_cert3
Normal file
BIN
core/tests/coretests/res/raw/install_app1_cert3
Normal file
Binary file not shown.
BIN
core/tests/coretests/res/raw/install_app1_cert3_cert4
Normal file
BIN
core/tests/coretests/res/raw/install_app1_cert3_cert4
Normal file
Binary file not shown.
BIN
core/tests/coretests/res/raw/install_app1_unsigned
Normal file
BIN
core/tests/coretests/res/raw/install_app1_unsigned
Normal file
Binary file not shown.
BIN
core/tests/coretests/res/raw/install_app2_cert1
Normal file
BIN
core/tests/coretests/res/raw/install_app2_cert1
Normal file
Binary file not shown.
BIN
core/tests/coretests/res/raw/install_app2_cert1_cert2
Normal file
BIN
core/tests/coretests/res/raw/install_app2_cert1_cert2
Normal file
Binary file not shown.
BIN
core/tests/coretests/res/raw/install_app2_cert2
Normal file
BIN
core/tests/coretests/res/raw/install_app2_cert2
Normal file
Binary file not shown.
BIN
core/tests/coretests/res/raw/install_app2_cert3
Normal file
BIN
core/tests/coretests/res/raw/install_app2_cert3
Normal file
Binary file not shown.
BIN
core/tests/coretests/res/raw/install_app2_unsigned
Normal file
BIN
core/tests/coretests/res/raw/install_app2_unsigned
Normal file
Binary file not shown.
BIN
core/tests/coretests/res/raw/install_shared1_cert1
Normal file
BIN
core/tests/coretests/res/raw/install_shared1_cert1
Normal file
Binary file not shown.
BIN
core/tests/coretests/res/raw/install_shared1_cert12
Normal file
BIN
core/tests/coretests/res/raw/install_shared1_cert12
Normal file
Binary file not shown.
BIN
core/tests/coretests/res/raw/install_shared1_cert1_cert2
Normal file
BIN
core/tests/coretests/res/raw/install_shared1_cert1_cert2
Normal file
Binary file not shown.
BIN
core/tests/coretests/res/raw/install_shared1_cert2
Normal file
BIN
core/tests/coretests/res/raw/install_shared1_cert2
Normal file
Binary file not shown.
BIN
core/tests/coretests/res/raw/install_shared1_unsigned
Normal file
BIN
core/tests/coretests/res/raw/install_shared1_unsigned
Normal file
Binary file not shown.
BIN
core/tests/coretests/res/raw/install_shared2_cert1
Normal file
BIN
core/tests/coretests/res/raw/install_shared2_cert1
Normal file
Binary file not shown.
BIN
core/tests/coretests/res/raw/install_shared2_cert12
Normal file
BIN
core/tests/coretests/res/raw/install_shared2_cert12
Normal file
Binary file not shown.
BIN
core/tests/coretests/res/raw/install_shared2_cert1_cert2
Normal file
BIN
core/tests/coretests/res/raw/install_shared2_cert1_cert2
Normal file
Binary file not shown.
BIN
core/tests/coretests/res/raw/install_shared2_cert2
Normal file
BIN
core/tests/coretests/res/raw/install_shared2_cert2
Normal file
Binary file not shown.
BIN
core/tests/coretests/res/raw/install_shared2_unsigned
Normal file
BIN
core/tests/coretests/res/raw/install_shared2_unsigned
Normal file
Binary file not shown.
@@ -23,10 +23,18 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageParser;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.Resources.NotFoundException;
|
||||
import android.net.Uri;
|
||||
import android.test.AndroidTestCase;
|
||||
import android.test.suitebuilder.annotation.Suppress;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.os.Environment;
|
||||
import android.os.FileUtils;
|
||||
import android.os.IBinder;
|
||||
@@ -497,6 +505,15 @@ public class PackageManagerTests extends AndroidTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
private PackageParser.Package getParsedPackage(String outFileName, int rawResId) {
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
File filesDir = mContext.getFilesDir();
|
||||
File outFile = new File(filesDir, outFileName);
|
||||
Uri packageURI = getInstallablePackage(rawResId, outFile);
|
||||
PackageParser.Package pkg = parsePackage(packageURI);
|
||||
return pkg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility function that reads a apk bundled as a raw resource
|
||||
* copies it into own data directory and invokes
|
||||
@@ -529,7 +546,9 @@ public class PackageManagerTests extends AndroidTestCase {
|
||||
if (fail) {
|
||||
assertTrue(invokeInstallPackageFail(packageURI, flags,
|
||||
pkg.packageName, result));
|
||||
assertNotInstalled(pkg.packageName);
|
||||
if ((flags & PackageManager.INSTALL_REPLACE_EXISTING) == 0) {
|
||||
assertNotInstalled(pkg.packageName);
|
||||
}
|
||||
} else {
|
||||
InstallReceiver receiver = new InstallReceiver(pkg.packageName);
|
||||
assertTrue(invokeInstallPackage(packageURI, flags,
|
||||
@@ -621,7 +640,7 @@ public class PackageManagerTests extends AndroidTestCase {
|
||||
* PackageManager api to install first and then replace it
|
||||
* again.
|
||||
*/
|
||||
public void replaceFromRawResource(int flags) {
|
||||
private void sampleReplaceFromRawResource(int flags) {
|
||||
InstallParams ip = sampleInstallFromRawResource(flags, false);
|
||||
boolean replace = ((flags & PackageManager.INSTALL_REPLACE_EXISTING) != 0);
|
||||
Log.i(TAG, "replace=" + replace);
|
||||
@@ -648,28 +667,28 @@ public class PackageManagerTests extends AndroidTestCase {
|
||||
}
|
||||
|
||||
public void testReplaceFailNormalInternal() {
|
||||
replaceFromRawResource(0);
|
||||
sampleReplaceFromRawResource(0);
|
||||
}
|
||||
|
||||
public void testReplaceFailFwdLockedInternal() {
|
||||
replaceFromRawResource(PackageManager.INSTALL_FORWARD_LOCK);
|
||||
sampleReplaceFromRawResource(PackageManager.INSTALL_FORWARD_LOCK);
|
||||
}
|
||||
|
||||
public void testReplaceFailSdcard() {
|
||||
replaceFromRawResource(PackageManager.INSTALL_EXTERNAL);
|
||||
sampleReplaceFromRawResource(PackageManager.INSTALL_EXTERNAL);
|
||||
}
|
||||
|
||||
public void testReplaceNormalInternal() {
|
||||
replaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING);
|
||||
sampleReplaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING);
|
||||
}
|
||||
|
||||
public void testReplaceFwdLockedInternal() {
|
||||
replaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING |
|
||||
sampleReplaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING |
|
||||
PackageManager.INSTALL_FORWARD_LOCK);
|
||||
}
|
||||
|
||||
public void testReplaceSdcard() {
|
||||
replaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING |
|
||||
sampleReplaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING |
|
||||
PackageManager.INSTALL_EXTERNAL);
|
||||
}
|
||||
|
||||
@@ -1014,6 +1033,19 @@ public class PackageManagerTests extends AndroidTestCase {
|
||||
outFile.delete();
|
||||
}
|
||||
}
|
||||
void cleanUpInstall(String pkgName) {
|
||||
if (pkgName == null) {
|
||||
return;
|
||||
}
|
||||
Log.i(TAG, "Deleting package : " + pkgName);
|
||||
try {
|
||||
ApplicationInfo info = getPm().getApplicationInfo(pkgName,
|
||||
PackageManager.GET_UNINSTALLED_PACKAGES);
|
||||
if (info != null) {
|
||||
getPm().deletePackage(pkgName, null, 0);
|
||||
}
|
||||
} catch (NameNotFoundException e) {}
|
||||
}
|
||||
|
||||
public void testManifestInstallLocationInternal() {
|
||||
installFromRawResource("install.apk", R.raw.install_loc_internal,
|
||||
@@ -2152,6 +2184,360 @@ public class PackageManagerTests extends AndroidTestCase {
|
||||
|
||||
}
|
||||
}
|
||||
/*
|
||||
* The following series of tests are related to upgrading apps with
|
||||
* different certificates.
|
||||
*/
|
||||
private int APP1_UNSIGNED = R.raw.install_app1_unsigned;
|
||||
private int APP1_CERT1 = R.raw.install_app1_cert1;
|
||||
private int APP1_CERT2 = R.raw.install_app1_cert2;
|
||||
private int APP1_CERT1_CERT2 = R.raw.install_app1_cert1_cert2;
|
||||
private int APP1_CERT3_CERT4 = R.raw.install_app1_cert3_cert4;
|
||||
private int APP1_CERT3 = R.raw.install_app1_cert3;
|
||||
private int APP2_UNSIGNED = R.raw.install_app2_unsigned;
|
||||
private int APP2_CERT1 = R.raw.install_app2_cert1;
|
||||
private int APP2_CERT2 = R.raw.install_app2_cert2;
|
||||
private int APP2_CERT1_CERT2 = R.raw.install_app2_cert1_cert2;
|
||||
private int APP2_CERT3 = R.raw.install_app2_cert3;
|
||||
|
||||
private InstallParams replaceCerts(int apk1, int apk2, boolean cleanUp, boolean fail, int retCode) {
|
||||
int rFlags = PackageManager.INSTALL_REPLACE_EXISTING;
|
||||
String apk1Name = "install1.apk";
|
||||
String apk2Name = "install2.apk";
|
||||
PackageParser.Package pkg1 = getParsedPackage(apk1Name, apk1);
|
||||
try {
|
||||
InstallParams ip = installFromRawResource(apk1Name, apk1, 0, false,
|
||||
false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
|
||||
installFromRawResource(apk2Name, apk2, rFlags, false,
|
||||
fail, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
|
||||
return ip;
|
||||
} catch (Exception e) {
|
||||
failStr(e.getMessage());
|
||||
} finally {
|
||||
if (cleanUp) {
|
||||
cleanUpInstall(pkg1.packageName);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/*
|
||||
* Test that an app signed with two certificates can be upgraded by the
|
||||
* same app signed with two certificates.
|
||||
*/
|
||||
public void testReplaceMatchAllCerts() {
|
||||
replaceCerts(APP1_CERT1_CERT2, APP1_CERT1_CERT2, true, false, -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that an app signed with two certificates cannot be upgraded
|
||||
* by an app signed with a different certificate.
|
||||
*/
|
||||
public void testReplaceMatchNoCerts1() {
|
||||
replaceCerts(APP1_CERT1_CERT2, APP1_CERT3, true, true,
|
||||
PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
|
||||
}
|
||||
/*
|
||||
* Test that an app signed with two certificates cannot be upgraded
|
||||
* by an app signed with a different certificate.
|
||||
*/
|
||||
public void testReplaceMatchNoCerts2() {
|
||||
replaceCerts(APP1_CERT1_CERT2, APP1_CERT3_CERT4, true, true,
|
||||
PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
|
||||
}
|
||||
/*
|
||||
* Test that an app signed with two certificates cannot be upgraded by
|
||||
* an app signed with a subset of initial certificates.
|
||||
*/
|
||||
public void testReplaceMatchSomeCerts1() {
|
||||
replaceCerts(APP1_CERT1_CERT2, APP1_CERT1, true, true,
|
||||
PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
|
||||
}
|
||||
/*
|
||||
* Test that an app signed with two certificates cannot be upgraded by
|
||||
* an app signed with the last certificate.
|
||||
*/
|
||||
public void testReplaceMatchSomeCerts2() {
|
||||
replaceCerts(APP1_CERT1_CERT2, APP1_CERT2, true, true,
|
||||
PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
|
||||
}
|
||||
/*
|
||||
* Test that an app signed with a certificate can be upgraded by app
|
||||
* signed with a superset of certificates.
|
||||
*/
|
||||
public void testReplaceMatchMoreCerts() {
|
||||
replaceCerts(APP1_CERT1, APP1_CERT1_CERT2, true, true,
|
||||
PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
|
||||
}
|
||||
/*
|
||||
* Test that an app signed with a certificate can be upgraded by app
|
||||
* signed with a superset of certificates. Then verify that the an app
|
||||
* signed with the original set of certs cannot upgrade the new one.
|
||||
*/
|
||||
public void testReplaceMatchMoreCertsReplaceSomeCerts() {
|
||||
InstallParams ip = replaceCerts(APP1_CERT1, APP1_CERT1_CERT2, false, true,
|
||||
PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
|
||||
try {
|
||||
int rFlags = PackageManager.INSTALL_REPLACE_EXISTING;
|
||||
installFromRawResource("install.apk", APP1_CERT1, rFlags, false,
|
||||
false, -1,
|
||||
PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
|
||||
} catch (Exception e) {
|
||||
failStr(e.getMessage());
|
||||
} finally {
|
||||
if (ip != null) {
|
||||
cleanUpInstall(ip);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* The following tests are related to testing the checkSignatures
|
||||
* api.
|
||||
*/
|
||||
private void checkSignatures(int apk1, int apk2, int expMatchResult) {
|
||||
checkSharedSignatures(apk1, apk2, true, false, -1, expMatchResult);
|
||||
}
|
||||
public void testCheckSignaturesAllMatch() {
|
||||
int apk1 = APP1_CERT1_CERT2;
|
||||
int apk2 = APP2_CERT1_CERT2;
|
||||
checkSignatures(apk1, apk2, PackageManager.SIGNATURE_MATCH);
|
||||
}
|
||||
public void testCheckSignaturesNoMatch() {
|
||||
int apk1 = APP1_CERT1;
|
||||
int apk2 = APP2_CERT2;
|
||||
checkSignatures(apk1, apk2, PackageManager.SIGNATURE_NO_MATCH);
|
||||
}
|
||||
public void testCheckSignaturesSomeMatch1() {
|
||||
int apk1 = APP1_CERT1_CERT2;
|
||||
int apk2 = APP2_CERT1;
|
||||
checkSignatures(apk1, apk2, PackageManager.SIGNATURE_NO_MATCH);
|
||||
}
|
||||
public void testCheckSignaturesSomeMatch2() {
|
||||
int apk1 = APP1_CERT1_CERT2;
|
||||
int apk2 = APP2_CERT2;
|
||||
checkSignatures(apk1, apk2, PackageManager.SIGNATURE_NO_MATCH);
|
||||
}
|
||||
public void testCheckSignaturesMoreMatch() {
|
||||
int apk1 = APP1_CERT1;
|
||||
int apk2 = APP2_CERT1_CERT2;
|
||||
checkSignatures(apk1, apk2, PackageManager.SIGNATURE_NO_MATCH);
|
||||
}
|
||||
public void testCheckSignaturesUnknown() {
|
||||
int apk1 = APP1_CERT1_CERT2;
|
||||
int apk2 = APP2_CERT1_CERT2;
|
||||
String apk1Name = "install1.apk";
|
||||
String apk2Name = "install2.apk";
|
||||
InstallParams ip1 = null;
|
||||
|
||||
try {
|
||||
ip1 = installFromRawResource(apk1Name, apk1, 0, false,
|
||||
false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
// Delete app2
|
||||
File filesDir = mContext.getFilesDir();
|
||||
File outFile = new File(filesDir, apk2Name);
|
||||
int rawResId = apk2;
|
||||
Uri packageURI = getInstallablePackage(rawResId, outFile);
|
||||
PackageParser.Package pkg = parsePackage(packageURI);
|
||||
getPm().deletePackage(pkg.packageName, null, 0);
|
||||
// Check signatures now
|
||||
int match = mContext.getPackageManager().checkSignatures(
|
||||
ip1.pkg.packageName, pkg.packageName);
|
||||
assertEquals(PackageManager.SIGNATURE_UNKNOWN_PACKAGE, match);
|
||||
} finally {
|
||||
if (ip1 != null) {
|
||||
cleanUpInstall(ip1);
|
||||
}
|
||||
}
|
||||
}
|
||||
public void testInstallNoCertificates() {
|
||||
int apk1 = APP1_UNSIGNED;
|
||||
String apk1Name = "install1.apk";
|
||||
InstallParams ip1 = null;
|
||||
|
||||
try {
|
||||
installFromRawResource(apk1Name, apk1, 0, false,
|
||||
true, PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES,
|
||||
PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
|
||||
} finally {
|
||||
}
|
||||
}
|
||||
/* The following tests are related to apps using shared uids signed
|
||||
* with different certs.
|
||||
*/
|
||||
private int SHARED1_UNSIGNED = R.raw.install_shared1_unsigned;
|
||||
private int SHARED1_CERT1 = R.raw.install_shared1_cert1;
|
||||
private int SHARED1_CERT2 = R.raw.install_shared1_cert2;
|
||||
private int SHARED1_CERT1_CERT2 = R.raw.install_shared1_cert1_cert2;
|
||||
private int SHARED2_UNSIGNED = R.raw.install_shared2_unsigned;
|
||||
private int SHARED2_CERT1 = R.raw.install_shared2_cert1;
|
||||
private int SHARED2_CERT2 = R.raw.install_shared2_cert2;
|
||||
private int SHARED2_CERT1_CERT2 = R.raw.install_shared2_cert1_cert2;
|
||||
private void checkSharedSignatures(int apk1, int apk2, boolean cleanUp, boolean fail, int retCode, int expMatchResult) {
|
||||
String apk1Name = "install1.apk";
|
||||
String apk2Name = "install2.apk";
|
||||
PackageParser.Package pkg1 = getParsedPackage(apk1Name, apk1);
|
||||
PackageParser.Package pkg2 = getParsedPackage(apk2Name, apk2);
|
||||
|
||||
try {
|
||||
// Clean up before testing first.
|
||||
cleanUpInstall(pkg1.packageName);
|
||||
cleanUpInstall(pkg2.packageName);
|
||||
installFromRawResource(apk1Name, apk1, 0, false,
|
||||
false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
|
||||
if (fail) {
|
||||
installFromRawResource(apk2Name, apk2, 0, false,
|
||||
true, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
|
||||
} else {
|
||||
installFromRawResource(apk2Name, apk2, 0, false,
|
||||
false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
|
||||
int match = mContext.getPackageManager().checkSignatures(
|
||||
pkg1.packageName, pkg2.packageName);
|
||||
assertEquals(expMatchResult, match);
|
||||
}
|
||||
} finally {
|
||||
if (cleanUp) {
|
||||
cleanUpInstall(pkg1.packageName);
|
||||
cleanUpInstall(pkg2.packageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
public void testCheckSignaturesSharedAllMatch() {
|
||||
int apk1 = SHARED1_CERT1_CERT2;
|
||||
int apk2 = SHARED2_CERT1_CERT2;
|
||||
boolean fail = false;
|
||||
int retCode = -1;
|
||||
int expMatchResult = PackageManager.SIGNATURE_MATCH;
|
||||
checkSharedSignatures(apk1, apk2, true, fail, retCode, expMatchResult);
|
||||
}
|
||||
public void testCheckSignaturesSharedNoMatch() {
|
||||
int apk1 = SHARED1_CERT1;
|
||||
int apk2 = SHARED2_CERT2;
|
||||
boolean fail = true;
|
||||
int retCode = PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
|
||||
int expMatchResult = -1;
|
||||
checkSharedSignatures(apk1, apk2, true, fail, retCode, expMatchResult);
|
||||
}
|
||||
/*
|
||||
* Test that an app signed with cert1 and cert2 cannot be replaced when signed with cert1 alone.
|
||||
*/
|
||||
public void testCheckSignaturesSharedSomeMatch1() {
|
||||
int apk1 = SHARED1_CERT1_CERT2;
|
||||
int apk2 = SHARED2_CERT1;
|
||||
boolean fail = true;
|
||||
int retCode = PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
|
||||
int expMatchResult = -1;
|
||||
checkSharedSignatures(apk1, apk2, true, fail, retCode, expMatchResult);
|
||||
}
|
||||
/*
|
||||
* Test that an app signed with cert1 and cert2 cannot be replaced when signed with cert2 alone.
|
||||
*/
|
||||
public void testCheckSignaturesSharedSomeMatch2() {
|
||||
int apk1 = SHARED1_CERT1_CERT2;
|
||||
int apk2 = SHARED2_CERT2;
|
||||
boolean fail = true;
|
||||
int retCode = PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
|
||||
int expMatchResult = -1;
|
||||
checkSharedSignatures(apk1, apk2, true, fail, retCode, expMatchResult);
|
||||
}
|
||||
public void testCheckSignaturesSharedUnknown() {
|
||||
int apk1 = SHARED1_CERT1_CERT2;
|
||||
int apk2 = SHARED2_CERT1_CERT2;
|
||||
String apk1Name = "install1.apk";
|
||||
String apk2Name = "install2.apk";
|
||||
InstallParams ip1 = null;
|
||||
|
||||
try {
|
||||
ip1 = installFromRawResource(apk1Name, apk1, 0, false,
|
||||
false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
// Delete app2
|
||||
PackageParser.Package pkg = getParsedPackage(apk2Name, apk2);
|
||||
getPm().deletePackage(pkg.packageName, null, 0);
|
||||
// Check signatures now
|
||||
int match = mContext.getPackageManager().checkSignatures(
|
||||
ip1.pkg.packageName, pkg.packageName);
|
||||
assertEquals(PackageManager.SIGNATURE_UNKNOWN_PACKAGE, match);
|
||||
} finally {
|
||||
if (ip1 != null) {
|
||||
cleanUpInstall(ip1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void testReplaceFirstSharedMatchAllCerts() {
|
||||
int apk1 = SHARED1_CERT1;
|
||||
int apk2 = SHARED2_CERT1;
|
||||
int rapk1 = SHARED1_CERT1;
|
||||
checkSignatures(apk1, apk2, PackageManager.SIGNATURE_MATCH);
|
||||
replaceCerts(apk1, rapk1, true, false, -1);
|
||||
}
|
||||
public void testReplaceSecondSharedMatchAllCerts() {
|
||||
int apk1 = SHARED1_CERT1;
|
||||
int apk2 = SHARED2_CERT1;
|
||||
int rapk2 = SHARED2_CERT1;
|
||||
checkSignatures(apk1, apk2, PackageManager.SIGNATURE_MATCH);
|
||||
replaceCerts(apk2, rapk2, true, false, -1);
|
||||
}
|
||||
public void testReplaceFirstSharedMatchSomeCerts() {
|
||||
int apk1 = SHARED1_CERT1_CERT2;
|
||||
int apk2 = SHARED2_CERT1_CERT2;
|
||||
int rapk1 = SHARED1_CERT1;
|
||||
boolean fail = true;
|
||||
int retCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
|
||||
checkSharedSignatures(apk1, apk2, false, false, -1, PackageManager.SIGNATURE_MATCH);
|
||||
installFromRawResource("install.apk", rapk1, PackageManager.INSTALL_REPLACE_EXISTING, true,
|
||||
fail, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
|
||||
}
|
||||
public void testReplaceSecondSharedMatchSomeCerts() {
|
||||
int apk1 = SHARED1_CERT1_CERT2;
|
||||
int apk2 = SHARED2_CERT1_CERT2;
|
||||
int rapk2 = SHARED2_CERT1;
|
||||
boolean fail = true;
|
||||
int retCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
|
||||
checkSharedSignatures(apk1, apk2, false, false, -1, PackageManager.SIGNATURE_MATCH);
|
||||
installFromRawResource("install.apk", rapk2, PackageManager.INSTALL_REPLACE_EXISTING, true,
|
||||
fail, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
|
||||
}
|
||||
public void testReplaceFirstSharedMatchNoCerts() {
|
||||
int apk1 = SHARED1_CERT1;
|
||||
int apk2 = SHARED2_CERT1;
|
||||
int rapk1 = SHARED1_CERT2;
|
||||
boolean fail = true;
|
||||
int retCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
|
||||
checkSharedSignatures(apk1, apk2, false, false, -1, PackageManager.SIGNATURE_MATCH);
|
||||
installFromRawResource("install.apk", rapk1, PackageManager.INSTALL_REPLACE_EXISTING, true,
|
||||
fail, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
|
||||
}
|
||||
public void testReplaceSecondSharedMatchNoCerts() {
|
||||
int apk1 = SHARED1_CERT1;
|
||||
int apk2 = SHARED2_CERT1;
|
||||
int rapk2 = SHARED2_CERT2;
|
||||
boolean fail = true;
|
||||
int retCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
|
||||
checkSharedSignatures(apk1, apk2, false, false, -1, PackageManager.SIGNATURE_MATCH);
|
||||
installFromRawResource("install.apk", rapk2, PackageManager.INSTALL_REPLACE_EXISTING, true,
|
||||
fail, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
|
||||
}
|
||||
public void testReplaceFirstSharedMatchMoreCerts() {
|
||||
int apk1 = SHARED1_CERT1;
|
||||
int apk2 = SHARED2_CERT1;
|
||||
int rapk1 = SHARED1_CERT1_CERT2;
|
||||
boolean fail = true;
|
||||
int retCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
|
||||
checkSharedSignatures(apk1, apk2, false, false, -1, PackageManager.SIGNATURE_MATCH);
|
||||
installFromRawResource("install.apk", rapk1, PackageManager.INSTALL_REPLACE_EXISTING, true,
|
||||
fail, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
|
||||
}
|
||||
public void testReplaceSecondSharedMatchMoreCerts() {
|
||||
int apk1 = SHARED1_CERT1;
|
||||
int apk2 = SHARED2_CERT1;
|
||||
int rapk2 = SHARED2_CERT1_CERT2;
|
||||
boolean fail = true;
|
||||
int retCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
|
||||
checkSharedSignatures(apk1, apk2, false, false, -1, PackageManager.SIGNATURE_MATCH);
|
||||
installFromRawResource("install.apk", rapk2, PackageManager.INSTALL_REPLACE_EXISTING, true,
|
||||
fail, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
|
||||
}
|
||||
/*---------- Recommended install location tests ----*/
|
||||
/*
|
||||
* TODO's
|
||||
|
||||
@@ -1835,21 +1835,19 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
if (s2 == null) {
|
||||
return PackageManager.SIGNATURE_SECOND_NOT_SIGNED;
|
||||
}
|
||||
final int N1 = s1.length;
|
||||
final int N2 = s2.length;
|
||||
for (int i=0; i<N1; i++) {
|
||||
boolean match = false;
|
||||
for (int j=0; j<N2; j++) {
|
||||
if (s1[i].equals(s2[j])) {
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!match) {
|
||||
return PackageManager.SIGNATURE_NO_MATCH;
|
||||
}
|
||||
HashSet<Signature> set1 = new HashSet<Signature>();
|
||||
for (Signature sig : s1) {
|
||||
set1.add(sig);
|
||||
}
|
||||
return PackageManager.SIGNATURE_MATCH;
|
||||
HashSet<Signature> set2 = new HashSet<Signature>();
|
||||
for (Signature sig : s2) {
|
||||
set2.add(sig);
|
||||
}
|
||||
// Make sure s2 contains all signatures in s1.
|
||||
if (set1.equals(set2)) {
|
||||
return PackageManager.SIGNATURE_MATCH;
|
||||
}
|
||||
return PackageManager.SIGNATURE_NO_MATCH;
|
||||
}
|
||||
|
||||
public String[] getPackagesForUid(int uid) {
|
||||
@@ -2501,6 +2499,9 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
mLastScanError = pp.getParseError();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Lets implicitly assign existing certificates.
|
||||
pkg.mSignatures = ps.signatures.mSignatures;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -2629,28 +2630,27 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
|
||||
private boolean verifySignaturesLP(PackageSetting pkgSetting,
|
||||
PackageParser.Package pkg, int parseFlags, boolean updateSignature) {
|
||||
if (pkg.mSignatures != null) {
|
||||
if (!pkgSetting.signatures.updateSignatures(pkg.mSignatures,
|
||||
updateSignature)) {
|
||||
Slog.e(TAG, "Package " + pkg.packageName
|
||||
+ " signatures do not match the previously installed version; ignoring!");
|
||||
mLastScanError = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pkgSetting.sharedUser != null) {
|
||||
if (!pkgSetting.sharedUser.signatures.mergeSignatures(
|
||||
pkg.mSignatures, updateSignature)) {
|
||||
PackageParser.Package pkg) {
|
||||
if (pkgSetting.signatures.mSignatures != null) {
|
||||
// Already existing package. Make sure signatures match
|
||||
if (checkSignaturesLP(pkgSetting.signatures.mSignatures, pkg.mSignatures) !=
|
||||
PackageManager.SIGNATURE_MATCH) {
|
||||
Slog.e(TAG, "Package " + pkg.packageName
|
||||
+ " has no signatures that match those in shared user "
|
||||
+ pkgSetting.sharedUser.name + "; ignoring!");
|
||||
mLastScanError = PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
|
||||
+ " signatures do not match the previously installed version; ignoring!");
|
||||
mLastScanError = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Check for shared user signatures
|
||||
if (pkgSetting.sharedUser != null && pkgSetting.sharedUser.signatures.mSignatures != null) {
|
||||
if (checkSignaturesLP(pkgSetting.sharedUser.signatures.mSignatures,
|
||||
pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
|
||||
Slog.e(TAG, "Package " + pkg.packageName
|
||||
+ " has no signatures that match those in shared user "
|
||||
+ pkgSetting.sharedUser.name + "; ignoring!");
|
||||
mLastScanError = PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
pkg.mSignatures = pkgSetting.signatures.mSignatures;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -2996,10 +2996,8 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
pkg.applicationInfo.uid = pkgSetting.userId;
|
||||
pkg.mExtras = pkgSetting;
|
||||
|
||||
if (!verifySignaturesLP(pkgSetting, pkg, parseFlags,
|
||||
(scanMode&SCAN_UPDATE_SIGNATURE) != 0)) {
|
||||
if (!verifySignaturesLP(pkgSetting, pkg)) {
|
||||
if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
|
||||
mLastScanError = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
|
||||
return null;
|
||||
}
|
||||
// The signature has changed, but this package is in the system
|
||||
@@ -3011,8 +3009,9 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
// associated with an overall shared user, which doesn't seem all
|
||||
// that unreasonable.
|
||||
if (pkgSetting.sharedUser != null) {
|
||||
if (!pkgSetting.sharedUser.signatures.mergeSignatures(
|
||||
pkg.mSignatures, false)) {
|
||||
if (checkSignaturesLP(pkgSetting.sharedUser.signatures.mSignatures,
|
||||
pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
|
||||
Log.w(TAG, "Signature mismatch for shared user : " + pkgSetting.sharedUser);
|
||||
mLastScanError = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
|
||||
return null;
|
||||
}
|
||||
@@ -5543,7 +5542,7 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
// First find the old package info and check signatures
|
||||
synchronized(mPackages) {
|
||||
oldPackage = mPackages.get(pkgName);
|
||||
if (checkSignaturesLP(pkg.mSignatures, oldPackage.mSignatures)
|
||||
if (checkSignaturesLP(oldPackage.mSignatures, pkg.mSignatures)
|
||||
!= PackageManager.SIGNATURE_MATCH) {
|
||||
res.returnCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
|
||||
return;
|
||||
@@ -5571,7 +5570,6 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
oldInstallerPackageName = mSettings.getInstallerPackageName(pkgName);
|
||||
}
|
||||
|
||||
parseFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
|
||||
// First delete the existing package while retaining the data directory
|
||||
if (!deletePackageLI(pkgName, true, PackageManager.DONT_DELETE_DATA,
|
||||
res.removedInfo)) {
|
||||
@@ -5595,20 +5593,7 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
|
||||
// If we deleted an exisiting package, the old source and resource files that we
|
||||
// were keeping around in case we needed them (see below) can now be deleted.
|
||||
// This info will be set on the res.removedInfo to clean up later on as post
|
||||
// install action.
|
||||
|
||||
//update signature on the new package setting
|
||||
//this should always succeed, since we checked the
|
||||
//signature earlier.
|
||||
synchronized(mPackages) {
|
||||
verifySignaturesLP(mSettings.mPackages.get(pkgName), pkg,
|
||||
parseFlags, true);
|
||||
}
|
||||
} else {
|
||||
if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
|
||||
// remove package from internal structures. Note that we want deletePackageX to
|
||||
// delete the package data and cache directories that it created in
|
||||
// scanPackageLocked, unless those directories existed before we even tried to
|
||||
@@ -5627,19 +5612,23 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
Slog.e(TAG, "Failed allocating storage when restoring pkg : " + pkgName);
|
||||
return;
|
||||
}
|
||||
PackageInstalledInfo restoreRes = new PackageInstalledInfo();
|
||||
restoreRes.removedInfo = new PackageRemovedInfo();
|
||||
// Parse old package
|
||||
parseFlags &= ~PackageManager.INSTALL_REPLACE_EXISTING;
|
||||
scanPackageLI(restoreFile, parseFlags, scanMode);
|
||||
boolean oldOnSd = isExternal(deletedPackage);
|
||||
int oldParseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY |
|
||||
(isForwardLocked(deletedPackage) ? PackageParser.PARSE_FORWARD_LOCK : 0) |
|
||||
(oldOnSd ? PackageParser.PARSE_ON_SDCARD : 0);
|
||||
int oldScanMode = (oldOnSd ? 0 : SCAN_MONITOR) | SCAN_UPDATE_SIGNATURE;
|
||||
if (scanPackageLI(restoreFile, oldParseFlags, oldScanMode) == null) {
|
||||
Slog.e(TAG, "Failed to restore package : " + pkgName + " after failed upgrade");
|
||||
return;
|
||||
}
|
||||
// Restore of old package succeeded. Update permissions.
|
||||
synchronized (mPackages) {
|
||||
updatePermissionsLP(deletedPackage.packageName, deletedPackage,
|
||||
true, false);
|
||||
mSettings.writeLP();
|
||||
}
|
||||
if (restoreRes.returnCode != PackageManager.INSTALL_SUCCEEDED) {
|
||||
Slog.e(TAG, "Failed restoring pkg : " + pkgName + " after failed upgrade");
|
||||
}
|
||||
Slog.i(TAG, "Successfully restored package : " + pkgName + " after failed upgrade");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5691,15 +5680,7 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
updatedSettings = true;
|
||||
}
|
||||
|
||||
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
|
||||
//update signature on the new package setting
|
||||
//this should always succeed, since we checked the
|
||||
//signature earlier.
|
||||
synchronized(mPackages) {
|
||||
verifySignaturesLP(mSettings.mPackages.get(packageName), pkg,
|
||||
parseFlags, true);
|
||||
}
|
||||
} else {
|
||||
if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
|
||||
// Re installation failed. Restore old information
|
||||
// Remove new pkg information
|
||||
if (newPackage != null) {
|
||||
@@ -5781,7 +5762,7 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
boolean forwardLocked = ((pFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
|
||||
boolean onSd = ((pFlags & PackageManager.INSTALL_EXTERNAL) != 0);
|
||||
boolean replace = false;
|
||||
int scanMode = SCAN_MONITOR | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE
|
||||
int scanMode = (onSd ? 0 : SCAN_MONITOR) | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE
|
||||
| (newInstall ? SCAN_NEW_INSTALL : 0);
|
||||
// Result object to be returned
|
||||
res.returnCode = PackageManager.INSTALL_SUCCEEDED;
|
||||
@@ -5911,6 +5892,10 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
return ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
|
||||
}
|
||||
|
||||
private boolean isExternal(PackageParser.Package pkg) {
|
||||
return ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
|
||||
}
|
||||
|
||||
private void extractPublicFiles(PackageParser.Package newPackage,
|
||||
File publicZipFile) throws IOException {
|
||||
final ZipOutputStream publicZipOutStream =
|
||||
@@ -7345,101 +7330,6 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If any of the given 'sigs' is contained in the existing signatures,
|
||||
* then completely replace the current signatures with the ones in
|
||||
* 'sigs'. This is used for updating an existing package to a newly
|
||||
* installed version.
|
||||
*/
|
||||
boolean updateSignatures(Signature[] sigs, boolean update) {
|
||||
if (mSignatures == null) {
|
||||
if (update) {
|
||||
assignSignatures(sigs);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (sigs == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i=0; i<sigs.length; i++) {
|
||||
Signature sig = sigs[i];
|
||||
for (int j=0; j<mSignatures.length; j++) {
|
||||
if (mSignatures[j].equals(sig)) {
|
||||
if (update) {
|
||||
assignSignatures(sigs);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If any of the given 'sigs' is contained in the existing signatures,
|
||||
* then add in any new signatures found in 'sigs'. This is used for
|
||||
* including a new package into an existing shared user id.
|
||||
*/
|
||||
boolean mergeSignatures(Signature[] sigs, boolean update) {
|
||||
if (mSignatures == null) {
|
||||
if (update) {
|
||||
assignSignatures(sigs);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (sigs == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Signature[] added = null;
|
||||
int addedCount = 0;
|
||||
boolean haveMatch = false;
|
||||
for (int i=0; i<sigs.length; i++) {
|
||||
Signature sig = sigs[i];
|
||||
boolean found = false;
|
||||
for (int j=0; j<mSignatures.length; j++) {
|
||||
if (mSignatures[j].equals(sig)) {
|
||||
found = true;
|
||||
haveMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
if (added == null) {
|
||||
added = new Signature[sigs.length];
|
||||
}
|
||||
added[i] = sig;
|
||||
addedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!haveMatch) {
|
||||
// Nothing matched -- reject the new signatures.
|
||||
return false;
|
||||
}
|
||||
if (added == null) {
|
||||
// Completely matched -- nothing else to do.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Add additional signatures in.
|
||||
if (update) {
|
||||
Signature[] total = new Signature[addedCount+mSignatures.length];
|
||||
System.arraycopy(mSignatures, 0, total, 0, mSignatures.length);
|
||||
int j = mSignatures.length;
|
||||
for (int i=0; i<added.length; i++) {
|
||||
if (added[i] != null) {
|
||||
total[j] = added[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
mSignatures = total;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void assignSignatures(Signature[] sigs) {
|
||||
if (sigs == null) {
|
||||
mSignatures = null;
|
||||
@@ -8227,6 +8117,15 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
if (pkg.mVersionCode != p.versionCode) {
|
||||
p.versionCode = pkg.mVersionCode;
|
||||
}
|
||||
// Update signatures if needed.
|
||||
if (p.signatures.mSignatures == null) {
|
||||
p.signatures.assignSignatures(pkg.mSignatures);
|
||||
}
|
||||
// If this app defines a shared user id initialize
|
||||
// the shared user signatures as well.
|
||||
if (p.sharedUser != null && p.sharedUser.signatures.mSignatures == null) {
|
||||
p.sharedUser.signatures.assignSignatures(pkg.mSignatures);
|
||||
}
|
||||
addPackageSettingLP(p, pkg.packageName, p.sharedUser);
|
||||
}
|
||||
|
||||
@@ -9655,22 +9554,12 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
// Parse package
|
||||
int parseFlags = PackageParser.PARSE_CHATTY |
|
||||
PackageParser.PARSE_ON_SDCARD | mDefParseFlags;
|
||||
PackageParser pp = new PackageParser(codePath);
|
||||
pp.setSeparateProcesses(mSeparateProcesses);
|
||||
final PackageParser.Package pkg = pp.parsePackage(new File(codePath),
|
||||
codePath, mMetrics, parseFlags);
|
||||
pp = null;
|
||||
doGc = true;
|
||||
// Check for parse errors
|
||||
if (pkg == null) {
|
||||
Slog.e(TAG, "Parse error when installing install pkg : "
|
||||
+ args.cid + " from " + args.cachePath);
|
||||
continue;
|
||||
}
|
||||
setApplicationInfoPaths(pkg, codePath, codePath);
|
||||
synchronized (mInstallLock) {
|
||||
final PackageParser.Package pkg = scanPackageLI(new File(codePath),
|
||||
parseFlags, 0);
|
||||
// Scan the package
|
||||
if (scanPackageLI(pkg, parseFlags, SCAN_MONITOR) != null) {
|
||||
if (pkg != null) {
|
||||
synchronized (mPackages) {
|
||||
retCode = PackageManager.INSTALL_SUCCEEDED;
|
||||
pkgList.add(pkg.packageName);
|
||||
@@ -9678,8 +9567,8 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
args.doPostInstall(PackageManager.INSTALL_SUCCEEDED);
|
||||
}
|
||||
} else {
|
||||
Slog.i(TAG, "Failed to install pkg: " +
|
||||
pkg.packageName + " from sdcard");
|
||||
Slog.i(TAG, "Failed to install pkg from " +
|
||||
codePath + " from sdcard");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user