From de9cf3392d7872c2bee69b65a614e77bb166b26e Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Wed, 19 Jan 2022 08:33:21 +0000 Subject: [MS66] Initialize TrafficStats with context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TrafficStats has static methods created in API level 8 that need access to NetworkStatsManager but doesn't take a context. Previously this was achieved by using ServiceManager, but with TrafficStats moving to the connectivity module, this is no longer possible. Instead, make sure TrafficStats has an appropriate context by the time any client code can call the relevant methods. • In app code, this achieved by passing the application context from ActivityThread#handleBindApplication, before any app code can run. • In the system server, this is achieved by passing the context right after creating service. Test: atest TrafficStatsTest CtsWebkitTestCases Bug: 204830222 Change-Id: I251bb8a4431ad12ff61929879ef1363cf06b9244 --- core/api/module-lib-current.txt | 4 +++ core/java/android/app/ActivityThread.java | 8 +++++ .../src/android/app/usage/NetworkStatsManager.java | 5 +++ .../framework-t/src/android/net/TrafficStats.java | 42 ++++++++++++---------- services/java/com/android/server/SystemServer.java | 2 ++ 5 files changed, 42 insertions(+), 19 deletions(-) diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index 445512e00f96..ed206b027ee0 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -317,6 +317,10 @@ package android.net { method public static void setHttpProxyConfiguration(@Nullable android.net.ProxyInfo); } + public class TrafficStats { + method public static void init(@NonNull android.content.Context); + } + public final class UnderlyingNetworkInfo implements android.os.Parcelable { ctor public UnderlyingNetworkInfo(int, @NonNull String, @NonNull java.util.List); method public int describeContents(); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 3b0a5f3e9bdd..6d7835f84dc7 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -97,6 +97,7 @@ import android.media.MediaFrameworkPlatformInitializer; import android.media.MediaServiceManager; import android.net.ConnectivityManager; import android.net.Proxy; +import android.net.TrafficStats; import android.net.Uri; import android.os.AsyncTask; import android.os.Binder; @@ -6663,6 +6664,13 @@ public final class ActivityThread extends ClientTransactionHandler NetworkSecurityConfigProvider.install(appContext); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); + // For backward compatibility, TrafficStats needs static access to the application context. + // But for isolated apps which cannot access network related services, service discovery + // is restricted. Hence, calling this would result in NPE. + if (!Process.isIsolated()) { + TrafficStats.init(appContext); + } + // Continue loading instrumentation. if (ii != null) { initInstrumentation(ii, data, appContext); diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java index 683678ad4671..8813f984519b 100644 --- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -157,6 +157,11 @@ public class NetworkStatsManager { setAugmentWithSubscriptionPlan(true); } + /** @hide */ + public INetworkStatsService getBinder() { + return mService; + } + /** * Set poll on open flag to indicate the poll is needed before service gets statistics * result. This is default enabled. However, for any non-privileged caller, the poll might diff --git a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java b/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java index 1af32bf5524c..c803a723ba83 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java +++ b/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java @@ -17,7 +17,6 @@ package android.net; import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; @@ -27,8 +26,8 @@ import android.app.usage.NetworkStatsManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.media.MediaPlayer; +import android.os.Binder; import android.os.Build; -import android.os.IBinder; import android.os.RemoteException; import com.android.server.NetworkManagementSocketTagger; @@ -37,8 +36,6 @@ import dalvik.system.SocketTagger; import java.io.FileDescriptor; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.net.DatagramSocket; import java.net.Socket; import java.net.SocketException; @@ -177,25 +174,12 @@ public class TrafficStats { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) private synchronized static INetworkStatsService getStatsService() { if (sStatsService == null) { - sStatsService = getStatsBinder(); + throw new IllegalStateException("TrafficStats not initialized, uid=" + + Binder.getCallingUid()); } return sStatsService; } - @Nullable - private static INetworkStatsService getStatsBinder() { - try { - final Method getServiceMethod = Class.forName("android.os.ServiceManager") - .getDeclaredMethod("getService", new Class[]{String.class}); - final IBinder binder = (IBinder) getServiceMethod.invoke( - null, Context.NETWORK_STATS_SERVICE); - return INetworkStatsService.Stub.asInterface(binder); - } catch (NoSuchMethodException | ClassNotFoundException | IllegalAccessException - | InvocationTargetException e) { - throw new NullPointerException("Cannot get INetworkStatsService: " + e); - } - } - /** * Snapshot of {@link NetworkStats} when the currently active profiling * session started, or {@code null} if no session active. @@ -209,6 +193,26 @@ public class TrafficStats { private static final String LOOPBACK_IFACE = "lo"; + /** + * Initialization {@link TrafficStats} with the context, to + * allow {@link TrafficStats} to fetch the needed binder. + * + * @param context a long-lived context, such as the application context or system + * server context. + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @SuppressLint("VisiblySynchronized") + public static synchronized void init(@NonNull final Context context) { + if (sStatsService != null) { + throw new IllegalStateException("TrafficStats is already initialized, uid=" + + Binder.getCallingUid()); + } + final NetworkStatsManager statsManager = + context.getSystemService(NetworkStatsManager.class); + sStatsService = statsManager.getBinder(); + } + /** * Set active tag to use when accounting {@link Socket} traffic originating * from the current thread. Only one active tag per thread is supported. diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 554a7b1bd574..710a9cf74112 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -54,6 +54,7 @@ import android.hardware.display.DisplayManagerInternal; import android.net.ConnectivityManager; import android.net.ConnectivityModuleConnector; import android.net.NetworkStackClient; +import android.net.TrafficStats; import android.os.BaseBundle; import android.os.Binder; import android.os.Build; @@ -1838,6 +1839,7 @@ public final class SystemServer implements Dumpable { try { networkStats = NetworkStatsService.create(context); ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats); + TrafficStats.init(context); } catch (Throwable e) { reportWtf("starting NetworkStats Service", e); } -- cgit v1.2.3-59-g8ed1b