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