1 /*
2  * Copyright (C) 2016 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 
17 package android.net.util;
18 
19 import android.net.INetd;
20 import android.os.RemoteException;
21 import android.os.ServiceManager;
22 import android.os.ServiceSpecificException;
23 import android.os.SystemClock;
24 import android.util.Log;
25 
26 
27 /**
28  * @hide
29  */
30 public class NetdService {
31     private static final String TAG = NetdService.class.getSimpleName();
32     private static final String NETD_SERVICE_NAME = "netd";
33     private static final long BASE_TIMEOUT_MS = 100;
34     private static final long MAX_TIMEOUT_MS = 1000;
35 
36 
37     /**
38      * Return an INetd instance, or null if not available.
39      *
40      * It is the caller's responsibility to check for a null return value
41      * and to handle RemoteException errors from invocations on the returned
42      * interface if, for example, netd dies and is restarted.
43      *
44      * Returned instances of INetd should not be cached.
45      *
46      * @return an INetd instance or null.
47      */
getInstance()48     public static INetd getInstance() {
49         // NOTE: ServiceManager does no caching for the netd service,
50         // because netd is not one of the defined common services.
51         final INetd netdInstance = INetd.Stub.asInterface(
52                 ServiceManager.getService(NETD_SERVICE_NAME));
53         if (netdInstance == null) {
54             Log.w(TAG, "WARNING: returning null INetd instance.");
55         }
56         return netdInstance;
57     }
58 
59     /**
60      * Blocks for a specified time until an INetd instance is available.
61      *
62      * It is the caller's responsibility to handle RemoteException errors
63      * from invocations on the returned interface if, for example, netd
64      * dies after this interface was returned.
65      *
66      * Returned instances of INetd should not be cached.
67      *
68      * Special values of maxTimeoutMs include: 0, meaning try to obtain an
69      * INetd instance only once, and -1 (or any value less than 0), meaning
70      * try to obtain an INetd instance indefinitely.
71      *
72      * @param maxTimeoutMs the maximum time to spend getting an INetd instance
73      * @return an INetd instance or null if no instance is available
74      * within |maxTimeoutMs| milliseconds.
75      */
get(long maxTimeoutMs)76     public static INetd get(long maxTimeoutMs) {
77         if (maxTimeoutMs == 0) return getInstance();
78 
79         final long stop = (maxTimeoutMs > 0)
80                 ? SystemClock.elapsedRealtime() + maxTimeoutMs
81                 : Long.MAX_VALUE;
82 
83         long timeoutMs = 0;
84         while (true) {
85             final INetd netdInstance = getInstance();
86             if (netdInstance != null) {
87                 return netdInstance;
88             }
89 
90             final long remaining = stop - SystemClock.elapsedRealtime();
91             if (remaining <= 0) break;
92 
93             // No netdInstance was received; sleep and retry.
94             timeoutMs = Math.min(timeoutMs + BASE_TIMEOUT_MS, MAX_TIMEOUT_MS);
95             timeoutMs = Math.min(timeoutMs, remaining);
96             try {
97                 Thread.sleep(timeoutMs);
98             } catch (InterruptedException e) {}
99         }
100         return null;
101     }
102 
103     /**
104      * Blocks until an INetd instance is available.
105      *
106      * It is the caller's responsibility to handle RemoteException errors
107      * from invocations on the returned interface if, for example, netd
108      * dies after this interface was returned.
109      *
110      * Returned instances of INetd should not be cached.
111      *
112      * @return an INetd instance.
113      */
get()114     public static INetd get() {
115         return get(-1);
116     }
117 
118     public static interface NetdCommand {
run(INetd netd)119         void run(INetd netd) throws RemoteException;
120     }
121 
122     /**
123      * Blocks until an INetd instance is availabe, and retries until either
124      * the command succeeds or a runtime exception is thrown.
125      */
run(NetdCommand cmd)126     public static void run(NetdCommand cmd) {
127         while (true) {
128             try {
129                 cmd.run(get());
130                 return;
131             } catch (RemoteException re) {
132                 Log.e(TAG, "error communicating with netd: " + re);
133             }
134         }
135     }
136 }
137