Add <extension-sdk> manifest tag inside <uses-sdk>
This allows apps to specify the minimum versions they need of extension sdks, and fails install if they aren't met. There is additional work required to prevent local rollbacks from triggering a downgrade of SDK versions after an install. Bug: 137191822 Test: atest PackageParserTest Exempt-From-Owner-Approval: PS4 was approved Change-Id: If61ae6c67ceb752bec6876006a29e52b996901e7
This commit is contained in:
@@ -439,8 +439,8 @@ java_library {
|
||||
srcs: [":framework-non-updatable-sources"],
|
||||
libs: [
|
||||
"framework-appsearch-stubs",
|
||||
// TODO(b/146167933): Use framework-statsd-stubs
|
||||
"framework-statsd",
|
||||
"framework-sdkextensions-stubs-systemapi",
|
||||
"framework-statsd", // TODO(b/146167933): Use framework-statsd-stubs
|
||||
"framework-permission-stubs",
|
||||
"framework-wifi-stubs",
|
||||
"ike-stubs",
|
||||
|
||||
@@ -242,8 +242,10 @@ package android {
|
||||
public static final class R.attr {
|
||||
field public static final int allowClearUserDataOnFailedRestore = 16844288; // 0x1010600
|
||||
field public static final int isVrOnly = 16844152; // 0x1010578
|
||||
field public static final int minExtensionVersion = 16844306; // 0x1010612
|
||||
field public static final int requiredSystemPropertyName = 16844133; // 0x1010565
|
||||
field public static final int requiredSystemPropertyValue = 16844134; // 0x1010566
|
||||
field public static final int sdkVersion = 16844305; // 0x1010611
|
||||
field public static final int supportsAmbientMode = 16844173; // 0x101058d
|
||||
field public static final int userRestriction = 16844164; // 0x1010584
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ import android.os.FileUtils;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.Trace;
|
||||
import android.os.ext.SdkExtensions;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
@@ -1615,11 +1616,72 @@ public class ApkParseUtils {
|
||||
);
|
||||
}
|
||||
|
||||
int type;
|
||||
final int innerDepth = parser.getDepth();
|
||||
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
|
||||
&& (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
|
||||
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
|
||||
continue;
|
||||
}
|
||||
if (parser.getName().equals("extension-sdk")) {
|
||||
final ParseResult result =
|
||||
parseExtensionSdk(parseInput, parsingPackage, res, parser);
|
||||
if (!result.isSuccess()) {
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
Slog.w(TAG, "Unknown element under <uses-sdk>: " + parser.getName()
|
||||
+ " at " + parsingPackage.getBaseCodePath() + " "
|
||||
+ parser.getPositionDescription());
|
||||
}
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
}
|
||||
|
||||
parsingPackage.setMinSdkVersion(minSdkVersion)
|
||||
.setTargetSdkVersion(targetSdkVersion);
|
||||
}
|
||||
return parseInput.success(parsingPackage);
|
||||
}
|
||||
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
private static ParseResult parseExtensionSdk(
|
||||
ParseInput parseInput,
|
||||
ParsingPackage parsingPackage,
|
||||
Resources res,
|
||||
XmlResourceParser parser
|
||||
) throws IOException, XmlPullParserException {
|
||||
TypedArray sa = res.obtainAttributes(parser,
|
||||
com.android.internal.R.styleable.AndroidManifestExtensionSdk);
|
||||
int sdkVersion = sa.getInt(
|
||||
com.android.internal.R.styleable.AndroidManifestExtensionSdk_sdkVersion, -1);
|
||||
int minVersion = sa.getInt(
|
||||
com.android.internal.R.styleable.AndroidManifestExtensionSdk_minExtensionVersion,
|
||||
-1);
|
||||
sa.recycle();
|
||||
|
||||
if (sdkVersion < 0) {
|
||||
return parseInput.error(
|
||||
PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
|
||||
"<extension-sdk> must specify an sdkVersion >= 0");
|
||||
}
|
||||
if (minVersion < 0) {
|
||||
return parseInput.error(
|
||||
PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
|
||||
"<extension-sdk> must specify minExtensionVersion >= 0");
|
||||
}
|
||||
|
||||
try {
|
||||
int version = SdkExtensions.getExtensionVersion(sdkVersion);
|
||||
if (version < minVersion) {
|
||||
return parseInput.error(
|
||||
PackageManager.INSTALL_FAILED_OLDER_SDK,
|
||||
"Package requires " + sdkVersion + " extension version " + minVersion
|
||||
+ " which exceeds device version " + version);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
return parseInput.error(
|
||||
PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
|
||||
"Specified sdkVersion " + sdkVersion + " is not valid");
|
||||
}
|
||||
return parseInput.success(parsingPackage);
|
||||
}
|
||||
|
||||
|
||||
@@ -2005,6 +2005,15 @@
|
||||
<attr name="maxSdkVersion" />
|
||||
</declare-styleable>
|
||||
|
||||
<!-- The <code>extension-sdk</code> tag is a child of the <uses-sdk> tag,
|
||||
and specifies required extension sdk features. -->
|
||||
<declare-styleable name="AndroidManifestExtensionSdk">
|
||||
<!-- The extension SDK version that this tag refers to. -->
|
||||
<attr name="sdkVersion" format="integer" />
|
||||
<!-- The minimum version of the extension SDK this application requires.-->
|
||||
<attr name="minExtensionVersion" format="integer" />
|
||||
</declare-styleable>
|
||||
|
||||
<!-- The <code>library</code> tag declares that this apk is providing itself
|
||||
as a shared library for other applications to use. It can only be used
|
||||
with apks that are built in to the system image. Other apks can link to
|
||||
|
||||
@@ -3008,6 +3008,10 @@
|
||||
<public name="supportsInlineSuggestions" />
|
||||
<public name="crossProfile" />
|
||||
<public name="canTakeScreenshot"/>
|
||||
<!-- @hide @SystemApi -->
|
||||
<public name="sdkVersion" />
|
||||
<!-- @hide @SystemApi -->
|
||||
<public name="minExtensionVersion" />
|
||||
</public-group>
|
||||
|
||||
<public-group type="drawable" first-id="0x010800b5">
|
||||
|
||||
@@ -84,6 +84,11 @@ java_genrule {
|
||||
":FrameworksCoreTests_install_split_feature_a",
|
||||
":FrameworksCoreTests_install_use_perm_good",
|
||||
":FrameworksCoreTests_install_uses_feature",
|
||||
":FrameworksCoreTests_install_uses_sdk_0",
|
||||
":FrameworksCoreTests_install_uses_sdk_q0",
|
||||
":FrameworksCoreTests_install_uses_sdk_r",
|
||||
":FrameworksCoreTests_install_uses_sdk_r0",
|
||||
":FrameworksCoreTests_install_uses_sdk_r5",
|
||||
":FrameworksCoreTests_install_verifier_bad",
|
||||
":FrameworksCoreTests_install_verifier_good",
|
||||
":FrameworksCoreTests_keyset_permdef_sa_unone",
|
||||
|
||||
39
core/tests/coretests/apks/install_uses_sdk/Android.bp
Normal file
39
core/tests/coretests/apks/install_uses_sdk/Android.bp
Normal file
@@ -0,0 +1,39 @@
|
||||
android_test_helper_app {
|
||||
name: "FrameworksCoreTests_install_uses_sdk_r0",
|
||||
defaults: ["FrameworksCoreTests_apks_defaults"],
|
||||
manifest: "AndroidManifest-r0.xml",
|
||||
|
||||
srcs: ["**/*.java"],
|
||||
}
|
||||
|
||||
android_test_helper_app {
|
||||
name: "FrameworksCoreTests_install_uses_sdk_r5",
|
||||
defaults: ["FrameworksCoreTests_apks_defaults"],
|
||||
manifest: "AndroidManifest-r5.xml",
|
||||
|
||||
srcs: ["**/*.java"],
|
||||
}
|
||||
|
||||
android_test_helper_app {
|
||||
name: "FrameworksCoreTests_install_uses_sdk_q0",
|
||||
defaults: ["FrameworksCoreTests_apks_defaults"],
|
||||
manifest: "AndroidManifest-q0.xml",
|
||||
|
||||
srcs: ["**/*.java"],
|
||||
}
|
||||
|
||||
android_test_helper_app {
|
||||
name: "FrameworksCoreTests_install_uses_sdk_r",
|
||||
defaults: ["FrameworksCoreTests_apks_defaults"],
|
||||
manifest: "AndroidManifest-r.xml",
|
||||
|
||||
srcs: ["**/*.java"],
|
||||
}
|
||||
|
||||
android_test_helper_app {
|
||||
name: "FrameworksCoreTests_install_uses_sdk_0",
|
||||
defaults: ["FrameworksCoreTests_apks_defaults"],
|
||||
manifest: "AndroidManifest-0.xml",
|
||||
|
||||
srcs: ["**/*.java"],
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2010 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.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.frameworks.coretests.install_uses_sdk">
|
||||
|
||||
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
|
||||
<!-- This is invalid, because there is no sdk version specified -->
|
||||
<extension-sdk android:minExtensionVersion="5" />
|
||||
</uses-sdk>
|
||||
|
||||
<application>
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2010 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.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.frameworks.coretests.install_uses_sdk">
|
||||
|
||||
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
|
||||
<!-- This fails because 29 doesn't have an extension sdk -->
|
||||
<extension-sdk android:sdkVersion="29" android:minExtensionVersion="0" />
|
||||
</uses-sdk>
|
||||
|
||||
<application>
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2010 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.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.frameworks.coretests.install_uses_sdk">
|
||||
|
||||
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
|
||||
<!-- This is invalid, because there is no minimum extension version specified -->
|
||||
<extension-sdk android:sdkVersion="10000" />
|
||||
</uses-sdk>
|
||||
|
||||
<application>
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2010 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.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.frameworks.coretests.install_uses_sdk">
|
||||
|
||||
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
|
||||
<extension-sdk android:sdkVersion="10000" android:minExtensionVersion="0" />
|
||||
</uses-sdk>
|
||||
|
||||
<application>
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2010 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.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.frameworks.coretests.install_uses_sdk">
|
||||
|
||||
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
|
||||
<!-- This will fail to install, because minExtensionVersion is not met -->
|
||||
<extension-sdk android:sdkVersion="10000" android:minExtensionVersion="5" />
|
||||
</uses-sdk>
|
||||
|
||||
<application>
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!-- Just need this dummy file to have something to build. -->
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dummy">dummy</string>
|
||||
</resources>
|
||||
@@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import android.apex.ApexInfo;
|
||||
import android.content.Context;
|
||||
@@ -486,4 +487,34 @@ public class PackageParserTest {
|
||||
assertTrue((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0);
|
||||
assertTrue((pi.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUsesSdk() throws Exception {
|
||||
parsePackage("install_uses_sdk.apk_r0", R.raw.install_uses_sdk_r0, x -> x);
|
||||
try {
|
||||
parsePackage("install_uses_sdk.apk_r5", R.raw.install_uses_sdk_r5, x -> x);
|
||||
fail("Expected parsing exception due to incompatible extension SDK version");
|
||||
} catch (PackageParser.PackageParserException expected) {
|
||||
assertEquals(PackageManager.INSTALL_FAILED_OLDER_SDK, expected.error);
|
||||
}
|
||||
try {
|
||||
parsePackage("install_uses_sdk.apk_q0", R.raw.install_uses_sdk_q0, x -> x);
|
||||
fail("Expected parsing exception due to non-existent extension SDK");
|
||||
} catch (PackageParser.PackageParserException expected) {
|
||||
assertEquals(PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, expected.error);
|
||||
}
|
||||
try {
|
||||
parsePackage("install_uses_sdk.apk_r", R.raw.install_uses_sdk_r, x -> x);
|
||||
fail("Expected parsing exception due to unspecified extension SDK version");
|
||||
} catch (PackageParser.PackageParserException expected) {
|
||||
assertEquals(PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, expected.error);
|
||||
}
|
||||
try {
|
||||
parsePackage("install_uses_sdk.apk_0", R.raw.install_uses_sdk_0, x -> x);
|
||||
fail("Expected parsing exception due to unspecified extension SDK");
|
||||
} catch (PackageParser.PackageParserException expected) {
|
||||
assertEquals(PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, expected.error);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,6 +349,7 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
|
||||
}
|
||||
return true;
|
||||
});
|
||||
manifest_action["uses-sdk"]["extension-sdk"];
|
||||
|
||||
// Instrumentation actions.
|
||||
manifest_action["instrumentation"].Action(RequiredNameIsJavaClassName);
|
||||
|
||||
Reference in New Issue
Block a user