[MS66] Initialize TrafficStats with context

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
This commit is contained in:
Junyu Lai
2022-01-19 08:33:21 +00:00
committed by junyulai
parent 139e007dc5
commit de9cf3392d
5 changed files with 42 additions and 19 deletions

View File

@@ -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<java.lang.String>);
method public int describeContents();

View File

@@ -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);

View File

@@ -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

View File

@@ -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.

View File

@@ -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);
}