|
|
|
@ -21,14 +21,7 @@ let is_synchronized_library_call =
|
|
|
|
|
false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let is_futures_getdone =
|
|
|
|
|
is_call_of_class "com.google.common.util.concurrent.Futures" ["getDone"] |> Staged.unstage
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let should_skip_analysis =
|
|
|
|
|
let matchers = [is_futures_getdone] in
|
|
|
|
|
fun tenv pn actuals -> List.exists matchers ~f:(fun matcher -> matcher tenv pn actuals)
|
|
|
|
|
|
|
|
|
|
let should_skip_analysis = ConcurrencyModels.matcher_of_json Config.starvation_skip_analysis
|
|
|
|
|
|
|
|
|
|
(** magical value from https://developer.android.com/topic/performance/vitals/anr *)
|
|
|
|
|
let android_anr_time_limit = 5.0
|
|
|
|
@ -97,61 +90,15 @@ let empty_or_excessive_timeout actuals =
|
|
|
|
|
false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(** is the method called Object.wait or on subclass, without timeout or with excessive timeout ? *)
|
|
|
|
|
let is_object_wait =
|
|
|
|
|
is_call_of_class ~actuals_pred:empty_or_excessive_timeout "java.lang.Object" ["wait"]
|
|
|
|
|
|> Staged.unstage
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(** is the method called CountDownLath.await or on subclass? *)
|
|
|
|
|
let is_countdownlatch_await =
|
|
|
|
|
is_call_of_class ~actuals_pred:empty_or_excessive_timeout "java.util.concurrent.CountDownLatch"
|
|
|
|
|
["await"]
|
|
|
|
|
|> Staged.unstage
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(** an IBinder.transact call is an RPC. If the 4th argument (5th counting `this` as the first)
|
|
|
|
|
is int-zero then a reply is expected and returned from the remote process, thus potentially
|
|
|
|
|
blocking. If the 4th argument is anything else, we assume a one-way call which doesn't block.
|
|
|
|
|
*)
|
|
|
|
|
let is_two_way_binder_transact =
|
|
|
|
|
let actuals_pred actuals =
|
|
|
|
|
List.nth actuals 4 |> Option.value_map ~default:false ~f:HilExp.is_int_zero
|
|
|
|
|
(* matchers used for normal analysis as well as in --dev-android-strict-mode *)
|
|
|
|
|
(* selection is a bit arbitrary as some would be generated anyway if not here; no harm though *)
|
|
|
|
|
(* some, like [file], need manual addition due to our lack of handling dynamic dispatch *)
|
|
|
|
|
let strict_mode_common_matchers =
|
|
|
|
|
let is_system_gc =
|
|
|
|
|
is_call_of_class "java.lang.System" ["gc"; "runFinalization"] |> Staged.unstage
|
|
|
|
|
in
|
|
|
|
|
is_call_of_class ~actuals_pred "android.os.IBinder" ["transact"] |> Staged.unstage
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(** is it a call to Future.get()? *)
|
|
|
|
|
let is_future_get =
|
|
|
|
|
is_call_of_class ~search_superclasses:false ~actuals_pred:empty_or_excessive_timeout
|
|
|
|
|
"java.util.concurrent.Future" ["get"]
|
|
|
|
|
|> Staged.unstage
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let is_accountManager_setUserData =
|
|
|
|
|
is_call_of_class ~search_superclasses:false "android.accounts.AccountManager" ["setUserData"]
|
|
|
|
|
|> Staged.unstage
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let is_asyncTask_get =
|
|
|
|
|
is_call_of_class ~actuals_pred:empty_or_excessive_timeout "android.os.AsyncTask" ["get"]
|
|
|
|
|
|> Staged.unstage
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(* consider any call to sleep as bad, even with timeouts lower than the anr limit *)
|
|
|
|
|
let is_thread_sleep = is_call_of_class "java.lang.Thread" ["sleep"] |> Staged.unstage
|
|
|
|
|
|
|
|
|
|
(* matcher for strict mode throws in Android libcore implementation,
|
|
|
|
|
used with --dev-android strict mode *)
|
|
|
|
|
let is_blockguard_on =
|
|
|
|
|
is_call_of_class ~method_prefix:true "dalvik.system.BlockGuard$Policy" ["on"] |> Staged.unstage
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let is_system_gc = is_call_of_class "java.lang.System" ["gc"; "runFinalization"] |> Staged.unstage
|
|
|
|
|
|
|
|
|
|
let is_runtime_gc = is_call_of_class "java.lang.Runtime" ["gc"] |> Staged.unstage
|
|
|
|
|
|
|
|
|
|
let is_file_io =
|
|
|
|
|
let is_runtime_gc = is_call_of_class "java.lang.Runtime" ["gc"] |> Staged.unstage in
|
|
|
|
|
let is_file_io =
|
|
|
|
|
is_call_of_class "java.io.File"
|
|
|
|
|
[ "canRead"
|
|
|
|
|
; "canWrite"
|
|
|
|
@ -177,25 +124,17 @@ let is_file_io =
|
|
|
|
|
; "setReadOnly"
|
|
|
|
|
; "setWritable" ]
|
|
|
|
|
|> Staged.unstage
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let is_socket_connect = is_call_of_class "java.net.Socket" ["connect"] |> Staged.unstage
|
|
|
|
|
|
|
|
|
|
let is_connected_socket_constructor =
|
|
|
|
|
in
|
|
|
|
|
let is_socket_connect = is_call_of_class "java.net.Socket" ["connect"] |> Staged.unstage in
|
|
|
|
|
let is_connected_socket_constructor =
|
|
|
|
|
(* all public constructors of Socket with two or more arguments call connect *)
|
|
|
|
|
let actuals_pred = function [] | [_] -> false | _ -> true in
|
|
|
|
|
is_call_of_class ~actuals_pred "java.net.Socket" [Typ.Procname.Java.constructor_method_name]
|
|
|
|
|
|> Staged.unstage
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let is_datagram_socket_connect =
|
|
|
|
|
in
|
|
|
|
|
let is_datagram_socket_connect =
|
|
|
|
|
is_call_of_class "java.net.DatagramSocket" ["connect"] |> Staged.unstage
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(* matchers used for normal analysis as well as in --dev-android-strict-mode *)
|
|
|
|
|
(* selection is a bit arbitrary as some would be generated anyway if not here; no harm though *)
|
|
|
|
|
(* some, like [file], need manual addition due to our lack of handling dynamic dispatch *)
|
|
|
|
|
let strict_mode_common_matchers =
|
|
|
|
|
in
|
|
|
|
|
let open StarvationDomain.Event in
|
|
|
|
|
[ (is_connected_socket_constructor, High)
|
|
|
|
|
; (is_datagram_socket_connect, High)
|
|
|
|
@ -206,6 +145,11 @@ let strict_mode_common_matchers =
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let strict_mode_seed_matchers =
|
|
|
|
|
(* matcher for strict mode throws in Android libcore implementation,
|
|
|
|
|
used with --dev-android strict mode *)
|
|
|
|
|
let is_blockguard_on =
|
|
|
|
|
is_call_of_class ~method_prefix:true "dalvik.system.BlockGuard$Policy" ["on"] |> Staged.unstage
|
|
|
|
|
in
|
|
|
|
|
(is_blockguard_on, StarvationDomain.Event.High) :: strict_mode_common_matchers
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -215,6 +159,41 @@ let strict_mode_matchers =
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let standard_matchers =
|
|
|
|
|
(* is the method called Object.wait or on subclass, without timeout or with excessive timeout ? *)
|
|
|
|
|
let is_object_wait =
|
|
|
|
|
is_call_of_class ~actuals_pred:empty_or_excessive_timeout "java.lang.Object" ["wait"]
|
|
|
|
|
|> Staged.unstage
|
|
|
|
|
in
|
|
|
|
|
(* is the method called CountDownLath.await or on subclass? *)
|
|
|
|
|
let is_countdownlatch_await =
|
|
|
|
|
is_call_of_class ~actuals_pred:empty_or_excessive_timeout "java.util.concurrent.CountDownLatch"
|
|
|
|
|
["await"]
|
|
|
|
|
|> Staged.unstage
|
|
|
|
|
in
|
|
|
|
|
(* an IBinder.transact call is an RPC. If the 4th argument (5th counting `this` as the first)
|
|
|
|
|
is int-zero then a reply is expected and returned from the remote process, thus potentially
|
|
|
|
|
blocking. If the 4th argument is anything else, we assume a one-way call which doesn't block. *)
|
|
|
|
|
let is_two_way_binder_transact =
|
|
|
|
|
let actuals_pred actuals =
|
|
|
|
|
List.nth actuals 4 |> Option.value_map ~default:false ~f:HilExp.is_int_zero
|
|
|
|
|
in
|
|
|
|
|
is_call_of_class ~actuals_pred "android.os.IBinder" ["transact"] |> Staged.unstage
|
|
|
|
|
in
|
|
|
|
|
let is_future_get =
|
|
|
|
|
is_call_of_class ~search_superclasses:false ~actuals_pred:empty_or_excessive_timeout
|
|
|
|
|
"java.util.concurrent.Future" ["get"]
|
|
|
|
|
|> Staged.unstage
|
|
|
|
|
in
|
|
|
|
|
let is_accountManager_setUserData =
|
|
|
|
|
is_call_of_class ~search_superclasses:false "android.accounts.AccountManager" ["setUserData"]
|
|
|
|
|
|> Staged.unstage
|
|
|
|
|
in
|
|
|
|
|
let is_asyncTask_get =
|
|
|
|
|
is_call_of_class ~actuals_pred:empty_or_excessive_timeout "android.os.AsyncTask" ["get"]
|
|
|
|
|
|> Staged.unstage
|
|
|
|
|
in
|
|
|
|
|
(* consider any call to sleep as bad, even with timeouts lower than the anr limit *)
|
|
|
|
|
let is_thread_sleep = is_call_of_class "java.lang.Thread" ["sleep"] |> Staged.unstage in
|
|
|
|
|
let open StarvationDomain.Event in
|
|
|
|
|
[ (is_accountManager_setUserData, High)
|
|
|
|
|
; (is_two_way_binder_transact, High)
|
|
|
|
|