From c094a5402c98851b380fa276e7557bf916c36c1b Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 7 Dec 2018 16:52:24 +0900 Subject: [PATCH] Add NetworkStack app The app is not started yet, and does not contain any service for now. Test: built, booted Bug: b/112869080 Change-Id: Id5a0fd02c891100e85d86b1040e53beec3581950 --- Android.bp | 11 ++ core/java/android/app/SystemServiceRegistry.java | 8 ++ core/java/android/content/Context.java | 10 ++ core/java/android/net/INetworkStackConnector.aidl | 21 +++ core/java/android/net/NetworkStack.java | 156 +++++++++++++++++++++ core/java/android/os/Process.java | 6 + core/jni/com_android_internal_os_Zygote.cpp | 7 + packages/NetworkStack/Android.bp | 37 +++++ packages/NetworkStack/AndroidManifest.xml | 38 +++++ .../com/android/server/NetworkStackService.java | 74 ++++++++++ .../android/server/pm/PackageManagerService.java | 3 + 11 files changed, 371 insertions(+) create mode 100644 core/java/android/net/INetworkStackConnector.aidl create mode 100644 core/java/android/net/NetworkStack.java create mode 100644 packages/NetworkStack/Android.bp create mode 100644 packages/NetworkStack/AndroidManifest.xml create mode 100644 packages/NetworkStack/src/com/android/server/NetworkStackService.java diff --git a/Android.bp b/Android.bp index 92c4abe9de32..124f4732f2c5 100644 --- a/Android.bp +++ b/Android.bp @@ -679,6 +679,7 @@ java_defaults { static_libs: [ "apex_aidl_interface-java", + "networkstack-aidl-interfaces-java", "framework-protos", "android.hidl.base-V1.0-java", "android.hardware.cas-V1.0-java", @@ -818,6 +819,16 @@ gensrcs { output_extension: "srcjar", } +// AIDL interfaces between the core system and the networking mainline module. +aidl_interface { + name: "networkstack-aidl-interfaces", + local_include_dir: "core/java", + srcs: [ + "core/java/android/net/INetworkStackConnector.aidl", + ], + api_dir: "aidl/networkstack", +} + // Build ext.jar // ============================================================ java_library { diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index b976d3f4de5e..15005d094af4 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -87,6 +87,7 @@ import android.net.INetworkPolicyManager; import android.net.IpSecManager; import android.net.NetworkPolicyManager; import android.net.NetworkScoreManager; +import android.net.NetworkStack; import android.net.NetworkWatchlistManager; import android.net.lowpan.ILowpanManager; import android.net.lowpan.LowpanManager; @@ -283,6 +284,13 @@ final class SystemServiceRegistry { return new ConnectivityManager(context, service); }}); + registerService(Context.NETWORK_STACK_SERVICE, NetworkStack.class, + new StaticServiceFetcher() { + @Override + public NetworkStack createService() { + return new NetworkStack(); + }}); + registerService(Context.IPSEC_SERVICE, IpSecManager.class, new CachedServiceFetcher() { @Override diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 72795cf5b6ee..81e72ccafe4d 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -49,6 +49,7 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; +import android.net.NetworkStack; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -3504,6 +3505,15 @@ public abstract class Context { /** * Use with {@link #getSystemService(String)} to retrieve a + * {@link NetworkStack} for communicating with the network stack + * @hide + * @see #getSystemService(String) + * @see NetworkStack + */ + public static final String NETWORK_STACK_SERVICE = "network_stack"; + + /** + * Use with {@link #getSystemService(String)} to retrieve a * {@link android.net.IpSecManager} for encrypting Sockets or Networks with * IPSec. * diff --git a/core/java/android/net/INetworkStackConnector.aidl b/core/java/android/net/INetworkStackConnector.aidl new file mode 100644 index 000000000000..29f882858c05 --- /dev/null +++ b/core/java/android/net/INetworkStackConnector.aidl @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2018, 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 perNmissions and + * limitations under the License. + */ +package android.net; + +/** @hide */ +oneway interface INetworkStackConnector { + // TODO: requestDhcpServer(), etc. will go here +} \ No newline at end of file diff --git a/core/java/android/net/NetworkStack.java b/core/java/android/net/NetworkStack.java new file mode 100644 index 000000000000..82a4e31a81dd --- /dev/null +++ b/core/java/android/net/NetworkStack.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2018 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 android.net; + +import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH; +import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemService; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Binder; +import android.os.IBinder; +import android.os.Process; +import android.os.ServiceManager; +import android.os.UserHandle; +import android.util.Slog; + +import com.android.internal.annotations.GuardedBy; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; + +/** + * Service used to communicate with the network stack, which is running in a separate module. + * @hide + */ +@SystemService(Context.NETWORK_STACK_SERVICE) +public class NetworkStack { + private static final String TAG = NetworkStack.class.getSimpleName(); + + @NonNull + @GuardedBy("mPendingNetStackRequests") + private final ArrayList mPendingNetStackRequests = new ArrayList<>(); + @Nullable + @GuardedBy("mPendingNetStackRequests") + private INetworkStackConnector mConnector; + + private interface NetworkStackRequest { + void onNetworkStackConnected(INetworkStackConnector connector); + } + + public NetworkStack() { } + + private class NetworkStackConnection implements ServiceConnection { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + registerNetworkStackService(service); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + // TODO: crash/reboot the system ? + Slog.wtf(TAG, "Lost network stack connector"); + } + }; + + private void registerNetworkStackService(@NonNull IBinder service) { + final INetworkStackConnector connector = INetworkStackConnector.Stub.asInterface(service); + + ServiceManager.addService(Context.NETWORK_STACK_SERVICE, service, false /* allowIsolated */, + DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL); + + final ArrayList requests; + synchronized (mPendingNetStackRequests) { + requests = new ArrayList<>(mPendingNetStackRequests); + mPendingNetStackRequests.clear(); + mConnector = connector; + } + + for (NetworkStackRequest r : requests) { + r.onNetworkStackConnected(connector); + } + } + + /** + * Start the network stack. Should be called only once on device startup. + * + *

This method will start the network stack either in the network stack process, or inside + * the system server on devices that do not support the network stack module. The network stack + * connector will then be delivered asynchronously to clients that requested it before it was + * started. + */ + public void start(Context context) { + // Try to bind in-process if the library is available + IBinder connector = null; + try { + final Class service = Class.forName( + "com.android.server.NetworkStackService", + true /* initialize */, + context.getClassLoader()); + connector = (IBinder) service.getMethod("makeConnector").invoke(null); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + Slog.wtf(TAG, "Could not create network stack connector from NetworkStackService"); + // TODO: crash/reboot system here ? + return; + } catch (ClassNotFoundException e) { + // Normal behavior if stack is provided by the app: fall through + } + + // In-process network stack. Add the service to the service manager here. + if (connector != null) { + registerNetworkStackService(connector); + return; + } + // Start the network stack process. The service will be added to the service manager in + // NetworkStackConnection.onServiceConnected(). + final Intent intent = new Intent(INetworkStackConnector.class.getName()); + final ComponentName comp = intent.resolveSystemService(context.getPackageManager(), 0); + intent.setComponent(comp); + + if (comp == null || !context.bindServiceAsUser(intent, new NetworkStackConnection(), + Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM)) { + Slog.wtf(TAG, + "Could not bind to network stack in-process, or in app with " + intent); + // TODO: crash/reboot system server if no network stack after a timeout ? + } + } + + // TODO: use this method to obtain the connector when implementing network stack operations + private void requestConnector(@NonNull NetworkStackRequest request) { + // TODO: PID check. + if (Binder.getCallingUid() != Process.SYSTEM_UID) { + // Don't even attempt to obtain the connector and give a nice error message + throw new SecurityException( + "Only the system server should try to bind to the network stack."); + } + + final INetworkStackConnector connector; + synchronized (mPendingNetStackRequests) { + connector = mConnector; + if (connector == null) { + mPendingNetStackRequests.add(request); + return; + } + } + + request.onNetworkStackConnected(connector); + } +} diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index d0cdf6e75224..f2837ecba215 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -174,6 +174,12 @@ public class Process { */ public static final int SE_UID = 1068; + /** + * Defines the UID/GID for the NetworkStack app. + * @hide + */ + public static final int NETWORK_STACK_UID = 1073; + /** {@hide} */ public static final int NOBODY_UID = 9999; diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 2e6b1b95fc3d..d4fe1edf0e7a 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -917,6 +917,13 @@ static jlong CalculateCapabilities(JNIEnv* env, jint uid, jint gid, jintArray gi capabilities |= (1LL << CAP_SYS_NICE); } + if (multiuser_get_app_id(uid) == AID_NETWORK_STACK) { + capabilities |= (1LL << CAP_NET_ADMIN); + capabilities |= (1LL << CAP_NET_BROADCAST); + capabilities |= (1LL << CAP_NET_BIND_SERVICE); + capabilities |= (1LL << CAP_NET_RAW); + } + /* * Grant CAP_BLOCK_SUSPEND to processes that belong to GID "wakelock" */ diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp new file mode 100644 index 000000000000..55bb5175c28d --- /dev/null +++ b/packages/NetworkStack/Android.bp @@ -0,0 +1,37 @@ +// +// Copyright (C) 2018 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. +// + +// Library including the network stack, used to compile the network stack app, or linked into the +// system server on devices that run the stack there +java_library { + name: "NetworkStackLib", + installable: true, + srcs: [ + "src/**/*.java", + ], +} + +// Updatable network stack packaged as an application +android_app { + name: "NetworkStack", + platform_apis: true, + certificate: "platform", + privileged: true, + static_libs: [ + "NetworkStackLib" + ], + manifest: "AndroidManifest.xml", +} \ No newline at end of file diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml new file mode 100644 index 000000000000..d1c5cb67197e --- /dev/null +++ b/packages/NetworkStack/AndroidManifest.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + diff --git a/packages/NetworkStack/src/com/android/server/NetworkStackService.java b/packages/NetworkStack/src/com/android/server/NetworkStackService.java new file mode 100644 index 000000000000..5afaf586f74d --- /dev/null +++ b/packages/NetworkStack/src/com/android/server/NetworkStackService.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2018 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; + +import static android.os.Binder.getCallingUid; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.Service; +import android.content.Intent; +import android.net.INetworkStackConnector; +import android.os.IBinder; +import android.os.Process; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +/** + * Android service used to start the network stack when bound to via an intent. + * + *

The service returns a binder for the system server to communicate with the network stack. + */ +public class NetworkStackService extends Service { + private static final String TAG = NetworkStackService.class.getSimpleName(); + + /** + * Create a binder connector for the system server to communicate with the network stack. + * + *

On platforms where the network stack runs in the system server process, this method may + * be called directly instead of obtaining the connector by binding to the service. + */ + public static IBinder makeConnector() { + return new NetworkStackConnector(); + } + + @NonNull + @Override + public IBinder onBind(Intent intent) { + return makeConnector(); + } + + private static class NetworkStackConnector extends INetworkStackConnector.Stub { + // TODO: makeDhcpServer(), etc. will go here. + + @Override + protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout, + @Nullable String[] args) { + checkCaller(); + fout.println("NetworkStack logs:"); + // TODO: dump logs here + } + } + + private static void checkCaller() { + // TODO: check that the calling PID is the system server. + if (getCallingUid() != Process.SYSTEM_UID && getCallingUid() != Process.ROOT_UID) { + throw new SecurityException("Invalid caller: " + getCallingUid()); + } + } +} diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 9345ad1339af..f4673a8fa7ba 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -456,6 +456,7 @@ public class PackageManagerService extends IPackageManager.Stub private static final int BLUETOOTH_UID = Process.BLUETOOTH_UID; private static final int SHELL_UID = Process.SHELL_UID; private static final int SE_UID = Process.SE_UID; + private static final int NETWORKSTACK_UID = Process.NETWORK_STACK_UID; // Suffix used during package installation when copying/moving // package apks to install directory. @@ -2469,6 +2470,8 @@ public class PackageManagerService extends IPackageManager.Stub ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.se", SE_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); + mSettings.addSharedUserLPw("android.uid.networkstack", NETWORKSTACK_UID, + ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); String separateProcesses = SystemProperties.get("debug.separate_processes"); if (separateProcesses != null && separateProcesses.length() > 0) { -- 2.11.0