@ -591,23 +591,28 @@ module Models = struct
&& not ( Annotations . pdesc_return_annot_ends_with proc_desc Annotations . visibleForTesting )
&& not ( Annotations . pdesc_return_annot_ends_with proc_desc Annotations . visibleForTesting )
let is_call_of_class_or_superclass ? ( method_prefix = false ) ? ( actuals_pred = fun _ -> true )
let is_call_of_class ? ( search_superclasses = true ) ? ( method_prefix = false )
class_names method_name tenv pn actuals =
? ( actuals_pred = fun _ -> true ) class_names method_name =
actuals_pred actuals
let is_target_class =
&&
let target_set = List . map class_names ~ f : Typ . Name . Java . from_string | > Typ . Name . Set . of_list in
match pn with
fun tname -> Typ . Name . Set . mem tname target_set
| Typ . Procname . Java java_pname ->
in
let classname = Typ . Procname . Java . get_class_type_name java_pname in
let is_target_struct tname _ = is_target_class tname in
let mthd = Typ . Procname . Java . get_method java_pname in
Staged . stage ( fun tenv pn actuals ->
let is_target_class =
actuals_pred actuals
let targets = List . map class_names ~ f : Typ . Name . Java . from_string in
&&
fun tname _ -> List . mem targets tname ~ equal : Typ . Name . equal
match pn with
in
| Typ . Procname . Java java_pname ->
( if method_prefix then String . is_prefix mthd ~ prefix : method_name
let classname = Typ . Procname . Java . get_class_type_name java_pname in
else String . equal mthd method_name )
let mthd = Typ . Procname . Java . get_method java_pname in
&& PatternMatch . supertype_exists tenv is_target_class classname
( if method_prefix then String . is_prefix mthd ~ prefix : method_name
| _ ->
else String . equal mthd method_name )
false
&&
if search_superclasses then
PatternMatch . supertype_exists tenv is_target_struct classname
else is_target_class classname
| _ ->
false )
(* * magical value from https://developer.android.com/topic/performance/vitals/anr *)
(* * magical value from https://developer.android.com/topic/performance/vitals/anr *)
@ -649,7 +654,7 @@ module Models = struct
many reports * )
many reports * )
(* let is_blocking_java_io =
(* let is_blocking_java_io =
is_call_of_class _or_superclass [ " java.io.Reader " ; " java.io.InputStream " ] ~ method_prefix : true
is_call_of_class [ " java.io.Reader " ; " java.io.InputStream " ] ~ method_prefix : true
" read " * )
" read " * )
let actuals_are_empty_or_timeout = function
let actuals_are_empty_or_timeout = function
@ -663,8 +668,9 @@ module Models = struct
(* * is the method called CountDownLath.await or on subclass? *)
(* * is the method called CountDownLath.await or on subclass? *)
let is_countdownlatch_await =
let is_countdownlatch_await =
is_call_of_class _or_superclass ~ actuals_pred : actuals_are_empty_or_timeout
is_call_of_class ~ actuals_pred : actuals_are_empty_or_timeout
[ " java.util.concurrent.CountDownLatch " ] " await "
[ " java.util.concurrent.CountDownLatch " ] " await "
| > Staged . unstage
(* * an IBinder.transact call is an RPC. If the 4th argument ( 5th counting `this` as the first )
(* * an IBinder.transact call is an RPC. If the 4th argument ( 5th counting `this` as the first )
@ -675,39 +681,43 @@ module Models = struct
let actuals_pred actuals =
let actuals_pred actuals =
List . nth actuals 4 | > Option . value_map ~ default : false ~ f : HilExp . is_int_zero
List . nth actuals 4 | > Option . value_map ~ default : false ~ f : HilExp . is_int_zero
in
in
is_call_of_class _or_superclass ~ actuals_pred [ " android.os.IBinder " ] " transact "
is_call_of_class ~ actuals_pred [ " android.os.IBinder " ] " transact " | > Staged . unstage
(* * is it a call to android.view.View.getWindowVisibleDisplayFrame or on sublass ? *)
(* * is it a call to android.view.View.getWindowVisibleDisplayFrame ? *)
let is_getWindowVisibleDisplayFrame =
let is_getWindowVisibleDisplayFrame =
is_call_of_class_or_superclass [ " android.view.View " ] " getWindowVisibleDisplayFrame "
is_call_of_class ~ search_superclasses : false [ " android.view.View " ]
" getWindowVisibleDisplayFrame "
| > Staged . unstage
(* * is it a call to Future.get ( ) or on sublass ? *)
(* * is it a call to Future.get ( ) ? *)
let is_future_get =
let is_future_get =
is_call_of_class _or_superclass ~ actuals_pred : actuals_are_empty_or_timeout
is_call_of_class ~ search_superclasses : false ~ actuals_pred : actuals_are_empty_or_timeout
[ " java.util.concurrent.Future " ] " get "
[ " java.util.concurrent.Future " ] " get "
| > Staged . unstage
let is_accountManager_setUserData =
let is_accountManager_setUserData =
is_call_of_class_or_superclass [ " android.accounts.AccountManager " ] " setUserData "
is_call_of_class ~ search_superclasses : false [ " android.accounts.AccountManager " ] " setUserData "
| > Staged . unstage
let is_asyncTask_get =
let is_asyncTask_get =
is_call_of_class _or_superclass ~ actuals_pred : actuals_are_empty_or_timeout
is_call_of_class ~ actuals_pred : actuals_are_empty_or_timeout [ " android.os.AsyncTask " ] " get "
[ " android.os.AsyncTask " ] " get "
| > Staged . unstage
(* at most one function is allowed to be true *)
(* at most one function is allowed to be true , sort from High to Low *)
let may_block =
let may_block =
let open StarvationDomain . Event in
let open StarvationDomain . Event in
let matchers =
let matchers =
[ ( is_ countdownlatch_await, Medium )
[ ( is_ accountManager_setUserData, High )
; ( is_two_way_binder_transact , High )
; ( is_two_way_binder_transact , High )
; ( is_ getWindowVisibleDisplayFrame, Low )
; ( is_ countdownlatch_await, High )
; ( is_ future_get, High )
; ( is_ getWindowVisibleDisplayFrame, Medium )
; ( is_a ccountManager_setUserData, High )
; ( is_a syncTask_get, Low )
; ( is_ asyncTask_get, High ) ]
; ( is_ future_get, Low ) ]
in
in
fun tenv pn actuals ->
fun tenv pn actuals ->
List . find_map matchers ~ f : ( fun ( matcher , sev ) -> Option . some_if ( matcher tenv pn actuals ) sev )
List . find_map matchers ~ f : ( fun ( matcher , sev ) -> Option . some_if ( matcher tenv pn actuals ) sev )