1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package android.net;
17 
18 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
19 import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
20 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
21 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
22 
23 import android.annotation.NonNull;
24 import android.annotation.Nullable;
25 import android.content.ComponentName;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.ServiceConnection;
29 import android.content.SharedPreferences;
30 import android.content.pm.PackageManager;
31 import android.net.dhcp.DhcpServingParamsParcel;
32 import android.net.dhcp.IDhcpServerCallbacks;
33 import android.net.ip.IIpClientCallbacks;
34 import android.net.util.SharedLog;
35 import android.os.Binder;
36 import android.os.Build;
37 import android.os.Environment;
38 import android.os.IBinder;
39 import android.os.Process;
40 import android.os.RemoteException;
41 import android.os.ServiceManager;
42 import android.os.SystemClock;
43 import android.os.UserHandle;
44 import android.provider.DeviceConfig;
45 import android.text.format.DateUtils;
46 import android.util.ArraySet;
47 import android.util.Slog;
48 
49 import com.android.internal.annotations.GuardedBy;
50 
51 import java.io.File;
52 import java.io.PrintWriter;
53 import java.util.ArrayList;
54 
55 /**
56  * Service used to communicate with the network stack, which is running in a separate module.
57  * @hide
58  */
59 public class NetworkStackClient {
60     private static final String TAG = NetworkStackClient.class.getSimpleName();
61 
62     private static final int NETWORKSTACK_TIMEOUT_MS = 10_000;
63     private static final String IN_PROCESS_SUFFIX = ".InProcess";
64     private static final String PREFS_FILE = "NetworkStackClientPrefs.xml";
65     private static final String PREF_KEY_LAST_CRASH_TIME = "lastcrash_time";
66     private static final String CONFIG_MIN_CRASH_INTERVAL_MS = "min_crash_interval";
67     private static final String CONFIG_MIN_UPTIME_BEFORE_CRASH_MS = "min_uptime_before_crash";
68     private static final String CONFIG_ALWAYS_RATELIMIT_NETWORKSTACK_CRASH =
69             "always_ratelimit_networkstack_crash";
70 
71     // Even if the network stack is lost, do not crash the system more often than this.
72     // Connectivity would be broken, but if the user needs the device for something urgent
73     // (like calling emergency services) we should not bootloop the device.
74     // This is the default value: the actual value can be adjusted via device config.
75     private static final long DEFAULT_MIN_CRASH_INTERVAL_MS = 6 * DateUtils.HOUR_IN_MILLIS;
76 
77     // Even if the network stack is lost, do not crash the system server if it was less than
78     // this much after boot. This avoids bootlooping the device, and crashes should address very
79     // infrequent failures, not failures on boot.
80     private static final long DEFAULT_MIN_UPTIME_BEFORE_CRASH_MS = 30 * DateUtils.MINUTE_IN_MILLIS;
81 
82     private static NetworkStackClient sInstance;
83 
84     @NonNull
85     @GuardedBy("mPendingNetStackRequests")
86     private final ArrayList<NetworkStackCallback> mPendingNetStackRequests = new ArrayList<>();
87     @Nullable
88     @GuardedBy("mPendingNetStackRequests")
89     private INetworkStackConnector mConnector;
90 
91     @GuardedBy("mLog")
92     private final SharedLog mLog = new SharedLog(TAG);
93 
94     private volatile boolean mWasSystemServerInitialized = false;
95 
96     @GuardedBy("mHealthListeners")
97     private final ArraySet<NetworkStackHealthListener> mHealthListeners = new ArraySet<>();
98 
99     private interface NetworkStackCallback {
onNetworkStackConnected(INetworkStackConnector connector)100         void onNetworkStackConnected(INetworkStackConnector connector);
101     }
102 
103     /**
104      * Callback interface for severe failures of the NetworkStack.
105      *
106      * <p>Useful for health monitors such as PackageWatchdog.
107      */
108     public interface NetworkStackHealthListener {
109         /**
110          * Called when there is a severe failure of the network stack.
111          * @param packageName Package name of the network stack.
112          */
onNetworkStackFailure(@onNull String packageName)113         void onNetworkStackFailure(@NonNull String packageName);
114     }
115 
NetworkStackClient()116     private NetworkStackClient() { }
117 
118     /**
119      * Get the NetworkStackClient singleton instance.
120      */
getInstance()121     public static synchronized NetworkStackClient getInstance() {
122         if (sInstance == null) {
123             sInstance = new NetworkStackClient();
124         }
125         return sInstance;
126     }
127 
128     /**
129      * Add a {@link NetworkStackHealthListener} to listen to network stack health events.
130      */
registerHealthListener(@onNull NetworkStackHealthListener listener)131     public void registerHealthListener(@NonNull NetworkStackHealthListener listener) {
132         synchronized (mHealthListeners) {
133             mHealthListeners.add(listener);
134         }
135     }
136 
137     /**
138      * Create a DHCP server according to the specified parameters.
139      *
140      * <p>The server will be returned asynchronously through the provided callbacks.
141      */
makeDhcpServer(final String ifName, final DhcpServingParamsParcel params, final IDhcpServerCallbacks cb)142     public void makeDhcpServer(final String ifName, final DhcpServingParamsParcel params,
143             final IDhcpServerCallbacks cb) {
144         requestConnector(connector -> {
145             try {
146                 connector.makeDhcpServer(ifName, params, cb);
147             } catch (RemoteException e) {
148                 e.rethrowFromSystemServer();
149             }
150         });
151     }
152 
153     /**
154      * Create an IpClient on the specified interface.
155      *
156      * <p>The IpClient will be returned asynchronously through the provided callbacks.
157      */
makeIpClient(String ifName, IIpClientCallbacks cb)158     public void makeIpClient(String ifName, IIpClientCallbacks cb) {
159         requestConnector(connector -> {
160             try {
161                 connector.makeIpClient(ifName, cb);
162             } catch (RemoteException e) {
163                 e.rethrowFromSystemServer();
164             }
165         });
166     }
167 
168     /**
169      * Create a NetworkMonitor.
170      *
171      * <p>The INetworkMonitor will be returned asynchronously through the provided callbacks.
172      */
makeNetworkMonitor(Network network, String name, INetworkMonitorCallbacks cb)173     public void makeNetworkMonitor(Network network, String name, INetworkMonitorCallbacks cb) {
174         requestConnector(connector -> {
175             try {
176                 connector.makeNetworkMonitor(network, name, cb);
177             } catch (RemoteException e) {
178                 e.rethrowFromSystemServer();
179             }
180         });
181     }
182 
183     /**
184      * Get an instance of the IpMemoryStore.
185      *
186      * <p>The IpMemoryStore will be returned asynchronously through the provided callbacks.
187      */
fetchIpMemoryStore(IIpMemoryStoreCallbacks cb)188     public void fetchIpMemoryStore(IIpMemoryStoreCallbacks cb) {
189         requestConnector(connector -> {
190             try {
191                 connector.fetchIpMemoryStore(cb);
192             } catch (RemoteException e) {
193                 e.rethrowFromSystemServer();
194             }
195         });
196     }
197 
198     private class NetworkStackConnection implements ServiceConnection {
199         @NonNull
200         private final Context mContext;
201         @NonNull
202         private final String mPackageName;
203 
NetworkStackConnection(@onNull Context context, @NonNull String packageName)204         private NetworkStackConnection(@NonNull Context context, @NonNull String packageName) {
205             mContext = context;
206             mPackageName = packageName;
207         }
208 
209         @Override
onServiceConnected(ComponentName name, IBinder service)210         public void onServiceConnected(ComponentName name, IBinder service) {
211             logi("Network stack service connected");
212             registerNetworkStackService(service);
213         }
214 
215         @Override
onServiceDisconnected(ComponentName name)216         public void onServiceDisconnected(ComponentName name) {
217             // onServiceDisconnected is not being called on device shutdown, so this method being
218             // called always indicates a bad state for the system server.
219             // This code path is only run by the system server: only the system server binds
220             // to the NetworkStack as a service. Other processes get the NetworkStack from
221             // the ServiceManager.
222             maybeCrashWithTerribleFailure("Lost network stack", mContext, mPackageName);
223         }
224     }
225 
registerNetworkStackService(@onNull IBinder service)226     private void registerNetworkStackService(@NonNull IBinder service) {
227         final INetworkStackConnector connector = INetworkStackConnector.Stub.asInterface(service);
228 
229         ServiceManager.addService(Context.NETWORK_STACK_SERVICE, service, false /* allowIsolated */,
230                 DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL);
231         log("Network stack service registered");
232 
233         final ArrayList<NetworkStackCallback> requests;
234         synchronized (mPendingNetStackRequests) {
235             requests = new ArrayList<>(mPendingNetStackRequests);
236             mPendingNetStackRequests.clear();
237             mConnector = connector;
238         }
239 
240         for (NetworkStackCallback r : requests) {
241             r.onNetworkStackConnected(connector);
242         }
243     }
244 
245     /**
246      * Initialize the network stack. Should be called only once on device startup, before any
247      * client attempts to use the network stack.
248      */
init()249     public void init() {
250         log("Network stack init");
251         mWasSystemServerInitialized = true;
252     }
253 
254     /**
255      * Start the network stack. Should be called only once on device startup.
256      *
257      * <p>This method will start the network stack either in the network stack process, or inside
258      * the system server on devices that do not support the network stack module. The network stack
259      * connector will then be delivered asynchronously to clients that requested it before it was
260      * started.
261      */
start(Context context)262     public void start(Context context) {
263         log("Starting network stack");
264 
265         final PackageManager pm = context.getPackageManager();
266 
267         // Try to bind in-process if the device was shipped with an in-process version
268         Intent intent = getNetworkStackIntent(pm, true /* inSystemProcess */);
269 
270         // Otherwise use the updatable module version
271         if (intent == null) {
272             intent = getNetworkStackIntent(pm, false /* inSystemProcess */);
273             log("Starting network stack process");
274         } else {
275             log("Starting network stack in-process");
276         }
277 
278         if (intent == null) {
279             maybeCrashWithTerribleFailure("Could not resolve the network stack", context, null);
280             return;
281         }
282 
283         final String packageName = intent.getComponent().getPackageName();
284 
285         // Start the network stack. The service will be added to the service manager in
286         // NetworkStackConnection.onServiceConnected().
287         if (!context.bindServiceAsUser(intent, new NetworkStackConnection(context, packageName),
288                 Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM)) {
289             maybeCrashWithTerribleFailure(
290                     "Could not bind to network stack in-process, or in app with " + intent,
291                     context, packageName);
292             return;
293         }
294 
295         log("Network stack service start requested");
296     }
297 
298     @Nullable
getNetworkStackIntent(@onNull PackageManager pm, boolean inSystemProcess)299     private Intent getNetworkStackIntent(@NonNull PackageManager pm, boolean inSystemProcess) {
300         final String baseAction = INetworkStackConnector.class.getName();
301         final Intent intent =
302                 new Intent(inSystemProcess ? baseAction + IN_PROCESS_SUFFIX : baseAction);
303         final ComponentName comp = intent.resolveSystemService(pm, 0);
304 
305         if (comp == null) {
306             return null;
307         }
308         intent.setComponent(comp);
309 
310         int uid = -1;
311         try {
312             uid = pm.getPackageUidAsUser(comp.getPackageName(), UserHandle.USER_SYSTEM);
313         } catch (PackageManager.NameNotFoundException e) {
314             logWtf("Network stack package not found", e);
315             // Fall through
316         }
317 
318         final int expectedUid = inSystemProcess ? Process.SYSTEM_UID : Process.NETWORK_STACK_UID;
319         if (uid != expectedUid) {
320             throw new SecurityException("Invalid network stack UID: " + uid);
321         }
322 
323         if (!inSystemProcess) {
324             checkNetworkStackPermission(pm, comp);
325         }
326 
327         return intent;
328     }
329 
checkNetworkStackPermission( @onNull PackageManager pm, @NonNull ComponentName comp)330     private void checkNetworkStackPermission(
331             @NonNull PackageManager pm, @NonNull ComponentName comp) {
332         final int hasPermission =
333                 pm.checkPermission(PERMISSION_MAINLINE_NETWORK_STACK, comp.getPackageName());
334         if (hasPermission != PERMISSION_GRANTED) {
335             throw new SecurityException(
336                     "Network stack does not have permission " + PERMISSION_MAINLINE_NETWORK_STACK);
337         }
338     }
339 
maybeCrashWithTerribleFailure(@onNull String message, @NonNull Context context, @Nullable String packageName)340     private void maybeCrashWithTerribleFailure(@NonNull String message,
341             @NonNull Context context, @Nullable String packageName) {
342         logWtf(message, null);
343         // uptime is monotonic even after a framework restart
344         final long uptime = SystemClock.elapsedRealtime();
345         final long now = System.currentTimeMillis();
346         final long minCrashIntervalMs = DeviceConfig.getLong(DeviceConfig.NAMESPACE_CONNECTIVITY,
347                 CONFIG_MIN_CRASH_INTERVAL_MS, DEFAULT_MIN_CRASH_INTERVAL_MS);
348         final long minUptimeBeforeCrash = DeviceConfig.getLong(DeviceConfig.NAMESPACE_CONNECTIVITY,
349                 CONFIG_MIN_UPTIME_BEFORE_CRASH_MS, DEFAULT_MIN_UPTIME_BEFORE_CRASH_MS);
350         final boolean alwaysRatelimit = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_CONNECTIVITY,
351                 CONFIG_ALWAYS_RATELIMIT_NETWORKSTACK_CRASH, false);
352 
353         final SharedPreferences prefs = getSharedPreferences(context);
354         final long lastCrashTime = tryGetLastCrashTime(prefs);
355 
356         // Only crash if there was enough time since boot, and (if known) enough time passed since
357         // the last crash.
358         // time and lastCrashTime may be unreliable if devices have incorrect clock time, but they
359         // are only used to limit the number of crashes compared to only using the time since boot,
360         // which would also be OK behavior by itself.
361         // - If lastCrashTime is incorrectly more than the current time, only look at uptime
362         // - If it is much less than current time, only look at uptime
363         // - If current time is during the next few hours after last crash time, don't crash.
364         //   Considering that this only matters if last boot was some time ago, it's likely that
365         //   time will be set correctly. Otherwise, not crashing is not a big problem anyway. Being
366         //   in this last state would also not last for long since the window is only a few hours.
367         final boolean alwaysCrash = Build.IS_DEBUGGABLE && !alwaysRatelimit;
368         final boolean justBooted = uptime < minUptimeBeforeCrash;
369         final boolean haveLastCrashTime = (lastCrashTime != 0) && (lastCrashTime < now);
370         final boolean haveKnownRecentCrash =
371                 haveLastCrashTime && (now < lastCrashTime + minCrashIntervalMs);
372         if (alwaysCrash || (!justBooted && !haveKnownRecentCrash)) {
373             // The system is not bound to its network stack (for example due to a crash in the
374             // network stack process): better crash rather than stay in a bad state where all
375             // networking is broken.
376             // Using device-encrypted SharedPreferences as DeviceConfig does not have a synchronous
377             // API to persist settings before a crash.
378             tryWriteLastCrashTime(prefs, now);
379             throw new IllegalStateException(message);
380         }
381 
382         // Here the system crashed recently already. Inform listeners that something is
383         // definitely wrong.
384         if (packageName != null) {
385             final ArraySet<NetworkStackHealthListener> listeners;
386             synchronized (mHealthListeners) {
387                 listeners = new ArraySet<>(mHealthListeners);
388             }
389             for (NetworkStackHealthListener listener : listeners) {
390                 listener.onNetworkStackFailure(packageName);
391             }
392         }
393     }
394 
395     @Nullable
396     private SharedPreferences getSharedPreferences(@NonNull Context context) {
397         try {
398             final File prefsFile = new File(
399                     Environment.getDataSystemDeDirectory(UserHandle.USER_SYSTEM), PREFS_FILE);
400             return context.createDeviceProtectedStorageContext()
401                     .getSharedPreferences(prefsFile, Context.MODE_PRIVATE);
402         } catch (Throwable e) {
403             logWtf("Error loading shared preferences", e);
404             return null;
405         }
406     }
407 
408     private long tryGetLastCrashTime(@Nullable SharedPreferences prefs) {
409         if (prefs == null) return 0L;
410         try {
411             return prefs.getLong(PREF_KEY_LAST_CRASH_TIME, 0L);
412         } catch (Throwable e) {
413             logWtf("Error getting last crash time", e);
414             return 0L;
415         }
416     }
417 
418     private void tryWriteLastCrashTime(@Nullable SharedPreferences prefs, long value) {
419         if (prefs == null) return;
420         try {
421             prefs.edit().putLong(PREF_KEY_LAST_CRASH_TIME, value).commit();
422         } catch (Throwable e) {
423             logWtf("Error writing last crash time", e);
424         }
425     }
426 
427     /**
428      * Log a message in the local log.
429      */
430     private void log(@NonNull String message) {
431         synchronized (mLog) {
432             mLog.log(message);
433         }
434     }
435 
436     private void logWtf(@NonNull String message, @Nullable Throwable e) {
437         Slog.wtf(TAG, message);
438         synchronized (mLog) {
439             mLog.e(message, e);
440         }
441     }
442 
443     private void loge(@NonNull String message, @Nullable Throwable e) {
444         synchronized (mLog) {
445             mLog.e(message, e);
446         }
447     }
448 
449     /**
450      * Log a message in the local and system logs.
451      */
452     private void logi(@NonNull String message) {
453         synchronized (mLog) {
454             mLog.i(message);
455         }
456     }
457 
458     /**
459      * For non-system server clients, get the connector registered by the system server.
460      */
461     private INetworkStackConnector getRemoteConnector() {
462         // Block until the NetworkStack connector is registered in ServiceManager.
463         // <p>This is only useful for non-system processes that do not have a way to be notified of
464         // registration completion. Adding a callback system would be too heavy weight considering
465         // that the connector is registered on boot, so it is unlikely that a client would request
466         // it before it is registered.
467         // TODO: consider blocking boot on registration and simplify much of the logic in this class
468         IBinder connector;
469         try {
470             final long before = System.currentTimeMillis();
471             while ((connector = ServiceManager.getService(Context.NETWORK_STACK_SERVICE)) == null) {
472                 Thread.sleep(20);
473                 if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) {
474                     loge("Timeout waiting for NetworkStack connector", null);
475                     return null;
476                 }
477             }
478         } catch (InterruptedException e) {
479             loge("Error waiting for NetworkStack connector", e);
480             return null;
481         }
482 
483         return INetworkStackConnector.Stub.asInterface(connector);
484     }
485 
486     private void requestConnector(@NonNull NetworkStackCallback request) {
487         // TODO: PID check.
488         final int caller = Binder.getCallingUid();
489         if (caller != Process.SYSTEM_UID && !UserHandle.isSameApp(caller, Process.BLUETOOTH_UID)
490                 && !UserHandle.isSameApp(caller, Process.PHONE_UID)) {
491             // Don't even attempt to obtain the connector and give a nice error message
492             throw new SecurityException(
493                     "Only the system server should try to bind to the network stack.");
494         }
495 
496         if (!mWasSystemServerInitialized) {
497             // The network stack is not being started in this process, e.g. this process is not
498             // the system server. Get a remote connector registered by the system server.
499             final INetworkStackConnector connector = getRemoteConnector();
500             synchronized (mPendingNetStackRequests) {
501                 mConnector = connector;
502             }
503             request.onNetworkStackConnected(connector);
504             return;
505         }
506 
507         final INetworkStackConnector connector;
508         synchronized (mPendingNetStackRequests) {
509             connector = mConnector;
510             if (connector == null) {
511                 mPendingNetStackRequests.add(request);
512                 return;
513             }
514         }
515 
516         request.onNetworkStackConnected(connector);
517     }
518 
519     /**
520      * Dump NetworkStackClient logs to the specified {@link PrintWriter}.
521      */
522     public void dump(PrintWriter pw) {
523         // dump is thread-safe on SharedLog
524         mLog.dump(null, pw, null);
525 
526         final int requestsQueueLength;
527         synchronized (mPendingNetStackRequests) {
528             requestsQueueLength = mPendingNetStackRequests.size();
529         }
530 
531         pw.println();
532         pw.println("pendingNetStackRequests length: " + requestsQueueLength);
533     }
534 }
535