From 8308d9e9811e6ec4f08e8b4f7ef86e402993fe61 Mon Sep 17 00:00:00 2001 From: satayev Date: Wed, 12 Jan 2022 11:55:21 +0000 Subject: [PATCH] Introduce initOrder for apex-system-services. This allows to have a relative order between apex system services if needed due to dependencies. Bug: 192880996 Test: atest ApexSystemServicesTestCases PackageParserTest ApexManagerTest Change-Id: Ib9700be48390f8a78135c76e79ad2bc4cb6e8577 --- .../component/ParsedApexSystemService.java | 2 + .../ParsedApexSystemServiceImpl.java | 25 ++++++-- .../ParsedApexSystemServiceUtils.java | 5 +- core/res/res/values/attrs_manifest.xml | 8 +++ .../com/android/server/pm/ApexManager.java | 29 ++++++---- .../server/pm/ApexSystemServiceInfo.java | 58 +++++++++++++++++++ .../java/com/android/server/SystemServer.java | 21 ++++--- .../apexes/test_com.android.server/Android.bp | 2 +- .../AndroidManifest.xml | 20 +++++-- .../{service => services}/Android.bp | 2 +- .../server/testing/FakeApexSystemService.java | 0 .../testing/FakeApexSystemService2.java | 41 +++++++++++++ .../server/ApexSystemServicesTestCases.java | 39 ++++++++++++- .../android/server/pm/ApexManagerTest.java | 7 ++- 14 files changed, 222 insertions(+), 37 deletions(-) create mode 100644 services/core/java/com/android/server/pm/ApexSystemServiceInfo.java rename services/tests/apexsystemservices/{service => services}/Android.bp (94%) rename services/tests/apexsystemservices/{service => services}/src/com/android/server/testing/FakeApexSystemService.java (100%) create mode 100644 services/tests/apexsystemservices/services/src/com/android/server/testing/FakeApexSystemService2.java diff --git a/core/java/android/content/pm/parsing/component/ParsedApexSystemService.java b/core/java/android/content/pm/parsing/component/ParsedApexSystemService.java index fe821e04958f0..c89d3b21b1c15 100644 --- a/core/java/android/content/pm/parsing/component/ParsedApexSystemService.java +++ b/core/java/android/content/pm/parsing/component/ParsedApexSystemService.java @@ -35,4 +35,6 @@ public interface ParsedApexSystemService extends Parcelable { @Nullable String getMaxSdkVersion(); + int getInitOrder(); + } diff --git a/core/java/android/content/pm/parsing/component/ParsedApexSystemServiceImpl.java b/core/java/android/content/pm/parsing/component/ParsedApexSystemServiceImpl.java index 54196fddb1fb2..65d26b90a2281 100644 --- a/core/java/android/content/pm/parsing/component/ParsedApexSystemServiceImpl.java +++ b/core/java/android/content/pm/parsing/component/ParsedApexSystemServiceImpl.java @@ -45,10 +45,11 @@ public class ParsedApexSystemServiceImpl implements ParsedApexSystemService { @Nullable private String maxSdkVersion; + private int initOrder; + public ParsedApexSystemServiceImpl() { } - // Code below generated by codegen v1.0.23. // // DO NOT MODIFY! @@ -67,13 +68,15 @@ public class ParsedApexSystemServiceImpl implements ParsedApexSystemService { @NonNull String name, @Nullable String jarPath, @Nullable String minSdkVersion, - @Nullable String maxSdkVersion) { + @Nullable String maxSdkVersion, + int initOrder) { this.name = name; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, name); this.jarPath = jarPath; this.minSdkVersion = minSdkVersion; this.maxSdkVersion = maxSdkVersion; + this.initOrder = initOrder; // onConstructed(); // You can define this method to get a callback } @@ -98,6 +101,11 @@ public class ParsedApexSystemServiceImpl implements ParsedApexSystemService { return maxSdkVersion; } + @DataClass.Generated.Member + public int getInitOrder() { + return initOrder; + } + @DataClass.Generated.Member public @NonNull ParsedApexSystemServiceImpl setName(@NonNull String value) { name = value; @@ -124,6 +132,12 @@ public class ParsedApexSystemServiceImpl implements ParsedApexSystemService { return this; } + @DataClass.Generated.Member + public @NonNull ParsedApexSystemServiceImpl setInitOrder( int value) { + initOrder = value; + return this; + } + @DataClass.Generated.Member static Parcelling sParcellingForName = Parcelling.Cache.get( @@ -183,6 +197,7 @@ public class ParsedApexSystemServiceImpl implements ParsedApexSystemService { sParcellingForJarPath.parcel(jarPath, dest, flags); sParcellingForMinSdkVersion.parcel(minSdkVersion, dest, flags); sParcellingForMaxSdkVersion.parcel(maxSdkVersion, dest, flags); + dest.writeInt(initOrder); } @Override @@ -201,6 +216,7 @@ public class ParsedApexSystemServiceImpl implements ParsedApexSystemService { String _jarPath = sParcellingForJarPath.unparcel(in); String _minSdkVersion = sParcellingForMinSdkVersion.unparcel(in); String _maxSdkVersion = sParcellingForMaxSdkVersion.unparcel(in); + int _initOrder = in.readInt(); this.name = _name; com.android.internal.util.AnnotationValidations.validate( @@ -208,6 +224,7 @@ public class ParsedApexSystemServiceImpl implements ParsedApexSystemService { this.jarPath = _jarPath; this.minSdkVersion = _minSdkVersion; this.maxSdkVersion = _maxSdkVersion; + this.initOrder = _initOrder; // onConstructed(); // You can define this method to get a callback } @@ -227,10 +244,10 @@ public class ParsedApexSystemServiceImpl implements ParsedApexSystemService { }; @DataClass.Generated( - time = 1638903241144L, + time = 1641307133386L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedApexSystemServiceImpl.java", - inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.NonNull java.lang.String name\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String jarPath\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String minSdkVersion\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String maxSdkVersion\nclass ParsedApexSystemServiceImpl extends java.lang.Object implements [android.content.pm.parsing.component.ParsedApexSystemService]\n@com.android.internal.util.DataClass(genGetters=true, genAidl=false, genSetters=true, genParcelable=true)") + inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.NonNull java.lang.String name\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String jarPath\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String minSdkVersion\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String maxSdkVersion\nprivate int initOrder\nclass ParsedApexSystemServiceImpl extends java.lang.Object implements [android.content.pm.parsing.component.ParsedApexSystemService]\n@com.android.internal.util.DataClass(genGetters=true, genAidl=false, genSetters=true, genParcelable=true)") @Deprecated private void __metadata() {} diff --git a/core/java/android/content/pm/parsing/component/ParsedApexSystemServiceUtils.java b/core/java/android/content/pm/parsing/component/ParsedApexSystemServiceUtils.java index 26abf48ee3915..eca897602d40b 100644 --- a/core/java/android/content/pm/parsing/component/ParsedApexSystemServiceUtils.java +++ b/core/java/android/content/pm/parsing/component/ParsedApexSystemServiceUtils.java @@ -53,10 +53,13 @@ public class ParsedApexSystemServiceUtils { R.styleable.AndroidManifestApexSystemService_minSdkVersion); String maxSdkVersion = sa.getString( R.styleable.AndroidManifestApexSystemService_maxSdkVersion); + int initOrder = sa.getInt(R.styleable.AndroidManifestApexSystemService_initOrder, 0); systemService.setName(className) .setMinSdkVersion(minSdkVersion) - .setMaxSdkVersion(maxSdkVersion); + .setMaxSdkVersion(maxSdkVersion) + .setInitOrder(initOrder); + if (!TextUtils.isEmpty(jarPath)) { systemService.setJarPath(jarPath); } diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index db24475cf7806..f7e0fcf77c8fb 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -2825,6 +2825,14 @@ + + diff --git a/services/tests/apexsystemservices/service/Android.bp b/services/tests/apexsystemservices/services/Android.bp similarity index 94% rename from services/tests/apexsystemservices/service/Android.bp rename to services/tests/apexsystemservices/services/Android.bp index 9d04f39f2237a..477ea4cdad37a 100644 --- a/services/tests/apexsystemservices/service/Android.bp +++ b/services/tests/apexsystemservices/services/Android.bp @@ -8,7 +8,7 @@ package { } java_library { - name: "FakeApexSystemService", + name: "FakeApexSystemServices", srcs: ["**/*.java"], sdk_version: "system_server_current", libs: [ diff --git a/services/tests/apexsystemservices/service/src/com/android/server/testing/FakeApexSystemService.java b/services/tests/apexsystemservices/services/src/com/android/server/testing/FakeApexSystemService.java similarity index 100% rename from services/tests/apexsystemservices/service/src/com/android/server/testing/FakeApexSystemService.java rename to services/tests/apexsystemservices/services/src/com/android/server/testing/FakeApexSystemService.java diff --git a/services/tests/apexsystemservices/services/src/com/android/server/testing/FakeApexSystemService2.java b/services/tests/apexsystemservices/services/src/com/android/server/testing/FakeApexSystemService2.java new file mode 100644 index 0000000000000..e83343b9c996d --- /dev/null +++ b/services/tests/apexsystemservices/services/src/com/android/server/testing/FakeApexSystemService2.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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.server.testing; + +import android.content.Context; +import android.util.Log; + +import androidx.annotation.NonNull; + +import com.android.server.SystemService; + +/** + * A fake system service that just logs when it is started. + */ +public class FakeApexSystemService2 extends SystemService { + + private static final String TAG = "FakeApexSystemService"; + + public FakeApexSystemService2(@NonNull Context context) { + super(context); + } + + @Override + public void onStart() { + Log.d(TAG, "FakeApexSystemService2 onStart"); + } +} diff --git a/services/tests/apexsystemservices/src/com/android/server/ApexSystemServicesTestCases.java b/services/tests/apexsystemservices/src/com/android/server/ApexSystemServicesTestCases.java index 2b453a9265bb1..7ab7b6ed763c9 100644 --- a/services/tests/apexsystemservices/src/com/android/server/ApexSystemServicesTestCases.java +++ b/services/tests/apexsystemservices/src/com/android/server/ApexSystemServicesTestCases.java @@ -37,6 +37,10 @@ import org.junit.rules.RuleChain; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; +import java.util.Objects; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + @RunWith(DeviceJUnit4ClassRunner.class) public class ApexSystemServicesTestCases extends BaseHostJUnit4Test { @@ -67,7 +71,7 @@ public class ApexSystemServicesTestCases extends BaseHostJUnit4Test { } @Test - public void noApexSystemServerStartsWithoutApex() throws Exception { + public void testNoApexSystemServiceStartsWithoutApex() throws Exception { mPreparer.reboot(); assertThat(getFakeApexSystemServiceLogcat()) @@ -75,7 +79,7 @@ public class ApexSystemServicesTestCases extends BaseHostJUnit4Test { } @Test - public void apexSystemServerStarts() throws Exception { + public void testApexSystemServiceStarts() throws Exception { // Pre-install the apex String apex = "test_com.android.server.apex"; mPreparer.pushResourceFile(apex, "/system/apex/" + apex); @@ -86,9 +90,40 @@ public class ApexSystemServicesTestCases extends BaseHostJUnit4Test { .contains("FakeApexSystemService onStart"); } + @Test + public void testInitOrder() throws Exception { + // Pre-install the apex + String apex = "test_com.android.server.apex"; + mPreparer.pushResourceFile(apex, "/system/apex/" + apex); + // Reboot activates the apex + mPreparer.reboot(); + + assertThat(getFakeApexSystemServiceLogcat().lines() + .map(ApexSystemServicesTestCases::getDebugMessage) + .filter(Objects::nonNull) + .collect(Collectors.toList())) + .containsExactly( + // Second service has a higher initOrder and must be started first + "FakeApexSystemService2 onStart", + "FakeApexSystemService onStart" + ) + .inOrder(); + } + private String getFakeApexSystemServiceLogcat() throws DeviceNotAvailableException { return mDevice.executeAdbCommand("logcat", "-v", "brief", "-d", "FakeApexSystemService:D", "*:S"); } + private static final Pattern DEBUG_MESSAGE = + Pattern.compile("(FakeApexSystemService[0-9]* onStart)"); + + private static String getDebugMessage(String logcatLine) { + return DEBUG_MESSAGE.matcher(logcatLine) + .results() + .map(m -> m.group(1)) + .findFirst() + .orElse(null); + } + } diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java index 7f7c716bc1f05..2f5993d1d9895 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java @@ -61,7 +61,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.Map; +import java.util.List; @SmallTest @Presubmit @@ -136,9 +136,10 @@ public class ApexManagerTest { mApexManager.scanApexPackagesTraced(mPackageParser2, ParallelPackageParser.makeExecutorService()); - Map services = mApexManager.getApexSystemServices(); + List services = mApexManager.getApexSystemServices(); assertThat(services).hasSize(1); - assertThat(services).containsKey("com.android.apex.test.ApexSystemService"); + assertThat(services.stream().map(ApexSystemServiceInfo::getName).findFirst().orElse(null)) + .matches("com.android.apex.test.ApexSystemService"); } @Test