• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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 com.android.internal.os;
18 
19 import android.annotation.NonNull;
20 import android.compat.annotation.UnsupportedAppUsage;
21 import android.os.Binder;
22 import android.os.Handler;
23 import android.os.IBinder;
24 import android.os.SystemClock;
25 import android.util.EventLog;
26 import android.util.SparseIntArray;
27 
28 import com.android.internal.util.Preconditions;
29 
30 import dalvik.system.VMRuntime;
31 
32 import java.lang.ref.WeakReference;
33 import java.util.ArrayList;
34 import java.util.Collection;
35 
36 /**
37  * Private and debugging Binder APIs.
38  *
39  * @see IBinder
40  */
41 public class BinderInternal {
42     private static final String TAG = "BinderInternal";
43     static WeakReference<GcWatcher> sGcWatcher
44             = new WeakReference<GcWatcher>(new GcWatcher());
45     static ArrayList<Runnable> sGcWatchers = new ArrayList<>();
46     static Runnable[] sTmpWatchers = new Runnable[1];
47     static long sLastGcTime;
48     static final BinderProxyLimitListenerDelegate sBinderProxyLimitListenerDelegate =
49             new BinderProxyLimitListenerDelegate();
50 
51     static final class GcWatcher {
52         @Override
finalize()53         protected void finalize() throws Throwable {
54             handleGc();
55             sLastGcTime = SystemClock.uptimeMillis();
56             synchronized (sGcWatchers) {
57                 sTmpWatchers = sGcWatchers.toArray(sTmpWatchers);
58             }
59             for (int i=0; i<sTmpWatchers.length; i++) {
60                 if (sTmpWatchers[i] != null) {
61                     sTmpWatchers[i].run();
62                 }
63             }
64             sGcWatcher = new WeakReference<GcWatcher>(new GcWatcher());
65         }
66     }
67 
addGcWatcher(Runnable watcher)68     public static void addGcWatcher(Runnable watcher) {
69         synchronized (sGcWatchers) {
70             sGcWatchers.add(watcher);
71         }
72     }
73 
74     /**
75      * A session used by {@link Observer} in order to keep track of some data.
76      */
77     public static class CallSession {
78         // Binder interface descriptor.
79         public Class<? extends Binder> binderClass;
80         // Binder transaction code.
81         public int transactionCode;
82         // CPU time at the beginning of the call.
83         long cpuTimeStarted;
84         // System time at the beginning of the call.
85         long timeStarted;
86         // Should be set to one when an exception is thrown.
87         boolean exceptionThrown;
88         // Detailed information should be recorded for this call when it ends.
89         public boolean recordedCall;
90     }
91 
92     /**
93      * Responsible for resolving a work source.
94      */
95     @FunctionalInterface
96     public interface WorkSourceProvider {
97         /**
98          * <p>This method is called in a critical path of the binder transaction.
99          * <p>The implementation should never execute a binder call since it is called during a
100          * binder transaction.
101          *
102          * @param untrustedWorkSourceUid The work source set by the caller.
103          * @return the uid of the process to attribute the binder transaction to.
104          */
resolveWorkSourceUid(int untrustedWorkSourceUid)105         int resolveWorkSourceUid(int untrustedWorkSourceUid);
106     }
107 
108     /**
109      * Allows to track various steps of an API call.
110      */
111     public interface Observer {
112         /**
113          * Called when a binder call starts.
114          *
115          * @return a CallSession to pass to the callEnded method.
116          */
callStarted(Binder binder, int code, int workSourceUid)117         CallSession callStarted(Binder binder, int code, int workSourceUid);
118 
119         /**
120          * Called when a binder call stops.
121          *
122          * <li>This method will be called even when an exception is thrown by the binder stub
123          * implementation.
124          */
callEnded(CallSession s, int parcelRequestSize, int parcelReplySize, int workSourceUid)125         void callEnded(CallSession s, int parcelRequestSize, int parcelReplySize,
126                 int workSourceUid);
127 
128         /**
129          * Called if an exception is thrown while executing the binder transaction.
130          *
131          * <li>BinderCallsStats#callEnded will be called afterwards.
132          * <li>Do not throw an exception in this method, it will swallow the original exception
133          * thrown by the binder transaction.
134          */
callThrewException(CallSession s, Exception exception)135         public void callThrewException(CallSession s, Exception exception);
136     }
137 
138     /**
139      * Allows to track observe incoming binder call stats.
140      */
141     public interface CallStatsObserver {
142         /**
143          * Notes incoming binder call stats associated with this work source UID.
144          */
noteCallStats(int workSourceUid, long incrementalCallCount, Collection<BinderCallsStats.CallStat> callStats)145         void noteCallStats(int workSourceUid, long incrementalCallCount,
146                 Collection<BinderCallsStats.CallStat> callStats);
147 
148         /**
149          * Notes the native IDs of threads taking incoming binder calls.
150          */
noteBinderThreadNativeIds(int[] binderThreadNativeTids)151         void noteBinderThreadNativeIds(int[] binderThreadNativeTids);
152     }
153 
154     /**
155      * Add the calling thread to the IPC thread pool.  This function does
156      * not return until the current process is exiting.
157      */
joinThreadPool()158     public static final native void joinThreadPool();
159 
160     /**
161      * Return the system time (as reported by {@link SystemClock#uptimeMillis
162      * SystemClock.uptimeMillis()}) that the last garbage collection occurred
163      * in this process.  This is not for general application use, and the
164      * meaning of "when a garbage collection occurred" will change as the
165      * garbage collector evolves.
166      *
167      * @return Returns the time as per {@link SystemClock#uptimeMillis
168      * SystemClock.uptimeMillis()} of the last garbage collection.
169      */
getLastGcTime()170     public static long getLastGcTime() {
171         return sLastGcTime;
172     }
173 
174     /**
175      * Return the global "context object" of the system.  This is usually
176      * an implementation of IServiceManager, which you can use to find
177      * other services.
178      */
179     @UnsupportedAppUsage
getContextObject()180     public static final native IBinder getContextObject();
181 
182     /**
183      * Special for system process to not allow incoming calls to run at
184      * background scheduling priority.
185      * @hide
186      */
disableBackgroundScheduling(boolean disable)187     public static final native void disableBackgroundScheduling(boolean disable);
188 
setMaxThreads(int numThreads)189     public static final native void setMaxThreads(int numThreads);
190 
191     @UnsupportedAppUsage
handleGc()192     static native final void handleGc();
193 
forceGc(String reason)194     public static void forceGc(String reason) {
195         EventLog.writeEvent(2741, reason);
196         VMRuntime.getRuntime().requestConcurrentGC();
197     }
198 
forceBinderGc()199     static void forceBinderGc() {
200         forceGc("Binder");
201     }
202 
203     /**
204      * Enable/disable Binder Proxy Instance Counting by Uid. While enabled, the set callback will
205      * be called if this process holds too many Binder Proxies on behalf of a Uid.
206      * @param enabled true to enable counting, false to disable
207      */
nSetBinderProxyCountEnabled(boolean enabled)208     public static final native void nSetBinderProxyCountEnabled(boolean enabled);
209 
210     /**
211      * Get the current number of Binder Proxies held for each uid.
212      * @return SparseIntArray mapping uids to the number of Binder Proxies currently held
213      */
nGetBinderProxyPerUidCounts()214     public static final native SparseIntArray nGetBinderProxyPerUidCounts();
215 
216     /**
217      * Get the current number of Binder Proxies held for an individual uid.
218      * @param uid Requested uid for Binder Proxy count
219      * @return int with the number of Binder proxies held for a uid
220      */
nGetBinderProxyCount(int uid)221     public static final native int nGetBinderProxyCount(int uid);
222 
223     /**
224      * Set the Binder Proxy watermarks. Default high watermark = 2500. Default low watermark = 2000
225      * @param high  The limit at which the BinderProxyListener callback will be called.
226      * @param low   The threshold a binder count must drop below before the callback
227      *              can be called again. (This is to avoid many repeated calls to the
228      *              callback in a brief period of time)
229      */
nSetBinderProxyCountWatermarks(int high, int low)230     public static final native void nSetBinderProxyCountWatermarks(int high, int low);
231 
232     /**
233      * Interface for callback invocation when the Binder Proxy limit is reached. onLimitReached will
234      * be called with the uid of the app causing too many Binder Proxies
235      */
236     public interface BinderProxyLimitListener {
onLimitReached(int uid)237         public void onLimitReached(int uid);
238     }
239 
240     /**
241      * Callback used by native code to trigger a callback in java code. The callback will be
242      * triggered when too many binder proxies from a uid hits the allowed limit.
243      * @param uid The uid of the bad behaving app sending too many binders
244      */
binderProxyLimitCallbackFromNative(int uid)245     public static void binderProxyLimitCallbackFromNative(int uid) {
246        sBinderProxyLimitListenerDelegate.notifyClient(uid);
247     }
248 
249     /**
250      * Set a callback to be triggered when a uid's Binder Proxy limit is reached for this process.
251      * @param listener OnLimitReached of listener will be called in the thread provided by handler
252      * @param handler must not be null, callback will be posted through the handler;
253      *
254      */
setBinderProxyCountCallback(BinderProxyLimitListener listener, @NonNull Handler handler)255     public static void setBinderProxyCountCallback(BinderProxyLimitListener listener,
256             @NonNull Handler handler) {
257         Preconditions.checkNotNull(handler,
258                 "Must provide NonNull Handler to setBinderProxyCountCallback when setting "
259                         + "BinderProxyLimitListener");
260         sBinderProxyLimitListenerDelegate.setListener(listener, handler);
261     }
262 
263     /**
264      * Clear the Binder Proxy callback
265      */
clearBinderProxyCountCallback()266     public static void clearBinderProxyCountCallback() {
267         sBinderProxyLimitListenerDelegate.setListener(null, null);
268     }
269 
270     static private class BinderProxyLimitListenerDelegate {
271         private BinderProxyLimitListener mBinderProxyLimitListener;
272         private Handler mHandler;
273 
setListener(BinderProxyLimitListener listener, Handler handler)274         void setListener(BinderProxyLimitListener listener, Handler handler) {
275             synchronized (this) {
276                 mBinderProxyLimitListener = listener;
277                 mHandler = handler;
278             }
279         }
280 
notifyClient(final int uid)281         void notifyClient(final int uid) {
282             synchronized (this) {
283                 if (mBinderProxyLimitListener != null) {
284                     mHandler.post(new Runnable() {
285                         @Override
286                         public void run() {
287                             mBinderProxyLimitListener.onLimitReached(uid);
288                         }
289                     });
290                 }
291             }
292         }
293     }
294 }
295