From 21c854a6c0104759c03098b7bee5cec05f278060 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 8 Mar 2021 22:05:03 +0900 Subject: [PATCH] Create ServiceConnectivityResources Create the ServiceConnectivityResources package, which contains resources Connectivity unbundled from platform resources. Migrate the first few resources from ConnectivityService that have no RRO in AOSP. To avoid boot time impact, avoid loading the resources in the ConnectivityService constructor. Bug: 182125649 Test: atest FrameworksNetTests Merged-In: I77ac6f4303c54acc96f16e18ef02add30298ff3d Change-Id: I77ac6f4303c54acc96f16e18ef02add30298ff3d --- service/Android.bp | 1 + .../ServiceConnectivityResources/Android.bp | 35 ++++++++ .../AndroidManifest.xml | 37 +++++++++ .../res/values/config.xml | 45 ++++++++++ .../res/values/overlayable.xml | 27 ++++++ .../res/values/strings.xml | 22 +++++ .../android/server/ConnectivityService.java | 31 ++++--- .../connectivity/ConnectivityResources.java | 83 +++++++++++++++++++ tests/net/Android.bp | 1 + .../server/ConnectivityServiceTest.java | 29 ++++--- 10 files changed, 289 insertions(+), 22 deletions(-) create mode 100644 service/ServiceConnectivityResources/Android.bp create mode 100644 service/ServiceConnectivityResources/AndroidManifest.xml create mode 100644 service/ServiceConnectivityResources/res/values/config.xml create mode 100644 service/ServiceConnectivityResources/res/values/overlayable.xml create mode 100644 service/ServiceConnectivityResources/res/values/strings.xml create mode 100644 services/core/java/com/android/server/connectivity/ConnectivityResources.java diff --git a/service/Android.bp b/service/Android.bp index e65b7b423b..5392f8451a 100644 --- a/service/Android.bp +++ b/service/Android.bp @@ -61,6 +61,7 @@ java_library { "services.core", "services.net", "unsupportedappusage", + "ServiceConnectivityResources", ], static_libs: [ "modules-utils-os", diff --git a/service/ServiceConnectivityResources/Android.bp b/service/ServiceConnectivityResources/Android.bp new file mode 100644 index 0000000000..f2446b7f7e --- /dev/null +++ b/service/ServiceConnectivityResources/Android.bp @@ -0,0 +1,35 @@ +// +// 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. +// + +// APK to hold all the wifi overlayable resources. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_app { + name: "ServiceConnectivityResources", + sdk_version: "system_current", + resource_dirs: [ + "res", + ], + privileged: true, + export_package_resources: true, + apex_available: [ + "com.android.tethering", + ], + // TODO: use a dedicated cert once generated + certificate: "platform", +} diff --git a/service/ServiceConnectivityResources/AndroidManifest.xml b/service/ServiceConnectivityResources/AndroidManifest.xml new file mode 100644 index 0000000000..2c30302615 --- /dev/null +++ b/service/ServiceConnectivityResources/AndroidManifest.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + diff --git a/service/ServiceConnectivityResources/res/values/config.xml b/service/ServiceConnectivityResources/res/values/config.xml new file mode 100644 index 0000000000..7d98c76a40 --- /dev/null +++ b/service/ServiceConnectivityResources/res/values/config.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + 60000 + + + + + + + \ No newline at end of file diff --git a/service/ServiceConnectivityResources/res/values/overlayable.xml b/service/ServiceConnectivityResources/res/values/overlayable.xml new file mode 100644 index 0000000000..00ec2df0e6 --- /dev/null +++ b/service/ServiceConnectivityResources/res/values/overlayable.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + diff --git a/service/ServiceConnectivityResources/res/values/strings.xml b/service/ServiceConnectivityResources/res/values/strings.xml new file mode 100644 index 0000000000..2c7b992650 --- /dev/null +++ b/service/ServiceConnectivityResources/res/values/strings.xml @@ -0,0 +1,22 @@ + + + + + System Connectivity Resources + \ No newline at end of file diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 2c9837d38d..bc3411ce41 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -186,7 +186,6 @@ import android.util.SparseArray; import android.util.SparseIntArray; import com.android.connectivity.aidl.INetworkAgent; -import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; @@ -203,6 +202,7 @@ import com.android.net.module.util.NetworkCapabilitiesUtils; import com.android.net.module.util.PermissionUtils; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.AutodestructReference; +import com.android.server.connectivity.ConnectivityResources; import com.android.server.connectivity.DnsManager; import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate; import com.android.server.connectivity.KeepaliveTracker; @@ -319,6 +319,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private boolean mRestrictBackground; private final Context mContext; + private final ConnectivityResources mResources; // The Context is created for UserHandle.ALL. private final Context mUserAllContext; private final Dependencies mDeps; @@ -607,7 +608,6 @@ public class ConnectivityService extends IConnectivityManager.Stub private Intent mInitialBroadcast; private PowerManager.WakeLock mNetTransitionWakeLock; - private int mNetTransitionWakeLockTimeout; private final PowerManager.WakeLock mPendingIntentWakeLock; // A helper object to track the current default HTTP proxy. ConnectivityService needs to tell @@ -982,6 +982,13 @@ public class ConnectivityService extends IConnectivityManager.Stub return new MockableSystemProperties(); } + /** + * Get the {@link ConnectivityResources} to use in ConnectivityService. + */ + public ConnectivityResources getResources(@NonNull Context ctx) { + return new ConnectivityResources(ctx); + } + /** * Create a HandlerThread to use in ConnectivityService. */ @@ -1054,6 +1061,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mSystemProperties = mDeps.getSystemProperties(); mNetIdManager = mDeps.makeNetIdManager(); mContext = Objects.requireNonNull(context, "missing Context"); + mResources = deps.getResources(mContext); mNetworkRequestCounter = new PerUidCounter(MAX_NETWORK_REQUESTS_PER_UID); mMetricsLog = logger; @@ -1114,8 +1122,6 @@ public class ConnectivityService extends IConnectivityManager.Stub final PowerManager powerManager = (PowerManager) context.getSystemService( Context.POWER_SERVICE); mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); - mNetTransitionWakeLockTimeout = mContext.getResources().getInteger( - com.android.internal.R.integer.config_networkTransitionTimeout); mPendingIntentWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); mNetConfigs = new NetworkConfig[ConnectivityManager.MAX_NETWORK_TYPE+1]; @@ -1182,10 +1188,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - mWolSupportedInterfaces = new ArraySet( - mContext.getResources().getStringArray( - com.android.internal.R.array.config_wakeonlan_supported_interfaces)); - mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); mPermissionMonitor = new PermissionMonitor(mContext, mNetd); @@ -4581,7 +4583,9 @@ public class ConnectivityService extends IConnectivityManager.Stub } mWakelockLogs.log("ACQUIRE for " + forWhom); Message msg = mHandler.obtainMessage(EVENT_EXPIRE_NET_TRANSITION_WAKELOCK); - mHandler.sendMessageDelayed(msg, mNetTransitionWakeLockTimeout); + final int lockTimeout = mResources.get().getInteger( + com.android.connectivity.resources.R.integer.config_networkTransitionTimeout); + mHandler.sendMessageDelayed(msg, lockTimeout); } // Called when we gain a new default network to release the network transition wakelock in a @@ -6444,6 +6448,11 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void updateWakeOnLan(@NonNull LinkProperties lp) { + if (mWolSupportedInterfaces == null) { + mWolSupportedInterfaces = new ArraySet<>(mResources.get().getStringArray( + com.android.connectivity.resources.R.array + .config_wakeonlan_supported_interfaces)); + } lp.setWakeOnLanSupported(mWolSupportedInterfaces.contains(lp.getInterfaceName())); } @@ -8000,8 +8009,8 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public String getCaptivePortalServerUrl() { enforceNetworkStackOrSettingsPermission(); - String settingUrl = mContext.getResources().getString( - R.string.config_networkCaptivePortalServerUrl); + String settingUrl = mResources.get().getString( + com.android.connectivity.resources.R.string.config_networkCaptivePortalServerUrl); if (!TextUtils.isEmpty(settingUrl)) { return settingUrl; diff --git a/services/core/java/com/android/server/connectivity/ConnectivityResources.java b/services/core/java/com/android/server/connectivity/ConnectivityResources.java new file mode 100644 index 0000000000..45cf21e035 --- /dev/null +++ b/services/core/java/com/android/server/connectivity/ConnectivityResources.java @@ -0,0 +1,83 @@ +/* + * 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.connectivity; + +import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.res.Resources; +import android.util.Log; + +import com.android.server.ConnectivityService; + +import java.util.List; + +/** + * Utility to obtain the {@link ConnectivityService} {@link Resources}, in the + * ServiceConnectivityResources APK. + */ +public class ConnectivityResources { + private static final String RESOURCES_APK_INTENT = + "com.android.server.connectivity.intent.action.SERVICE_CONNECTIVITY_RESOURCES_APK"; + private static final String RES_PKG_DIR = "/apex/com.android.tethering/"; + + @NonNull + private final Context mContext; + + @Nullable + private Resources mResources = null; + + public ConnectivityResources(Context context) { + mContext = context; + } + + /** + * Get the {@link Resources} of the ServiceConnectivityResources APK. + */ + public synchronized Resources get() { + if (mResources != null) { + return mResources; + } + + final List pkgs = mContext.getPackageManager() + .queryIntentActivities(new Intent(RESOURCES_APK_INTENT), MATCH_SYSTEM_ONLY); + pkgs.removeIf(pkg -> !pkg.activityInfo.applicationInfo.sourceDir.startsWith(RES_PKG_DIR)); + if (pkgs.size() > 1) { + Log.wtf(ConnectivityResources.class.getSimpleName(), + "More than one package found: " + pkgs); + } + if (pkgs.isEmpty()) { + throw new IllegalStateException("No connectivity resource package found"); + } + + final Context pkgContext; + try { + pkgContext = mContext.createPackageContext( + pkgs.get(0).activityInfo.applicationInfo.packageName, 0 /* flags */); + } catch (PackageManager.NameNotFoundException e) { + throw new IllegalStateException("Resolved package not found", e); + } + + mResources = pkgContext.getResources(); + return mResources; + } +} diff --git a/tests/net/Android.bp b/tests/net/Android.bp index 81224957b2..d59b036da6 100644 --- a/tests/net/Android.bp +++ b/tests/net/Android.bp @@ -79,6 +79,7 @@ android_test { "android.test.runner", "android.test.base", "android.test.mock", + "ServiceConnectivityResources", ], jni_libs: [ "libservice-connectivity", diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 2546580e18..f2f9d2ae72 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -275,6 +275,7 @@ import com.android.internal.util.test.FakeSettingsProvider; import com.android.net.module.util.ArrayTrackRecord; import com.android.server.ConnectivityService.ConnectivityDiagnosticsCallbackInfo; import com.android.server.connectivity.ConnectivityConstants; +import com.android.server.connectivity.ConnectivityResources; import com.android.server.connectivity.MockableSystemProperties; import com.android.server.connectivity.Nat464Xlat; import com.android.server.connectivity.NetworkAgentInfo; @@ -445,6 +446,7 @@ public class ConnectivityServiceTest { @Mock NetworkPolicyManager mNetworkPolicyManager; @Mock VpnProfileStore mVpnProfileStore; @Mock SystemConfigManager mSystemConfigManager; + @Mock Resources mResources; private ArgumentCaptor mResolverParamsParcelCaptor = ArgumentCaptor.forClass(ResolverParamsParcel.class); @@ -472,7 +474,7 @@ public class ConnectivityServiceTest { private class MockContext extends BroadcastInterceptingContext { private final MockContentResolver mContentResolver; - @Spy private Resources mResources; + @Spy private Resources mInternalResources; private final LinkedBlockingQueue mStartedActivities = new LinkedBlockingQueue<>(); // Map of permission name -> PermissionManager.Permission_{GRANTED|DENIED} constant @@ -481,21 +483,15 @@ public class ConnectivityServiceTest { MockContext(Context base, ContentProvider settingsProvider) { super(base); - mResources = spy(base.getResources()); - when(mResources.getStringArray(com.android.internal.R.array.networkAttributes)). - thenReturn(new String[] { + mInternalResources = spy(base.getResources()); + when(mInternalResources.getStringArray(com.android.internal.R.array.networkAttributes)) + .thenReturn(new String[] { "wifi,1,1,1,-1,true", "mobile,0,0,0,-1,true", "mobile_mms,2,0,2,60000,true", "mobile_supl,3,0,2,60000,true", }); - when(mResources.getStringArray( - com.android.internal.R.array.config_wakeonlan_supported_interfaces)) - .thenReturn(new String[]{ - WIFI_WOL_IFNAME, - }); - mContentResolver = new MockContentResolver(); mContentResolver.addProvider(Settings.AUTHORITY, settingsProvider); } @@ -560,7 +556,7 @@ public class ConnectivityServiceTest { @Override public Resources getResources() { - return mResources; + return mInternalResources; } @Override @@ -1533,6 +1529,17 @@ public class ConnectivityServiceTest { return mPolicyTracker; }).when(deps).makeMultinetworkPolicyTracker(any(), any(), any()); + doReturn(60000).when(mResources).getInteger( + com.android.connectivity.resources.R.integer.config_networkTransitionTimeout); + doReturn("").when(mResources).getString( + com.android.connectivity.resources.R.string.config_networkCaptivePortalServerUrl); + doReturn(new String[]{ WIFI_WOL_IFNAME }).when(mResources).getStringArray( + com.android.connectivity.resources.R.array.config_wakeonlan_supported_interfaces); + final com.android.server.connectivity.ConnectivityResources connRes = mock( + ConnectivityResources.class); + doReturn(mResources).when(connRes).get(); + doReturn(connRes).when(deps).getResources(any()); + return deps; }