From e36ca3d07facc1f76708d372aadc155cd5a1a2b9 Mon Sep 17 00:00:00 2001 From: Nikos Gorogiannis Date: Wed, 23 May 2018 05:24:00 -0700 Subject: [PATCH] [starvation] explain why we think a method runs on the ui thread Summary: Track and surface the reasons why a method is assessed to run on the UI thread. Reviewed By: mbouaziz Differential Revision: D8096099 fbshipit-source-id: 2403c6c --- infer/src/absint/AbstractDomain.ml | 2 +- infer/src/absint/PatternMatch.ml | 55 ++++++++++--------- infer/src/absint/PatternMatch.mli | 5 ++ infer/src/concurrency/RacerD.ml | 2 +- infer/src/concurrency/RacerDConfig.ml | 54 +++++++++++++----- infer/src/concurrency/RacerDConfig.mli | 5 +- infer/src/concurrency/starvation.ml | 48 ++++++++-------- infer/src/concurrency/starvationDomain.ml | 49 +++++++++++++---- infer/src/concurrency/starvationDomain.mli | 9 ++- .../codetoanalyze/java/starvation/issues.exp | 54 +++++++++--------- 10 files changed, 178 insertions(+), 105 deletions(-) diff --git a/infer/src/absint/AbstractDomain.ml b/infer/src/absint/AbstractDomain.ml index ba724e0a6..010d391f4 100644 --- a/infer/src/absint/AbstractDomain.ml +++ b/infer/src/absint/AbstractDomain.ml @@ -157,7 +157,7 @@ module Pair (Domain1 : S) (Domain2 : S) = struct , Domain2.widen ~prev:(snd prev) ~next:(snd next) ~num_iters ) - let pp fmt (astate1, astate2) = F.fprintf fmt "(%a, %a)" Domain1.pp astate1 Domain2.pp astate2 + let pp fmt astate = Pp.pair ~fst:Domain1.pp ~snd:Domain2.pp fmt astate end module FiniteSetOfPPSet (S : PrettyPrintable.PPSet) = struct diff --git a/infer/src/absint/PatternMatch.ml b/infer/src/absint/PatternMatch.ml index 60d59e142..f9f06592f 100644 --- a/infer/src/absint/PatternMatch.ml +++ b/infer/src/absint/PatternMatch.ml @@ -276,35 +276,40 @@ let proc_calls resolve_attributes pdesc filter : (Typ.Procname.t * ProcAttribute List.rev !res -let override_exists ?(check_current_type= true) f tenv proc_name = +let override_find ?(check_current_type= true) f tenv proc_name = let method_name = Typ.Procname.get_method proc_name in - let rec super_type_exists_ tenv super_class_name = - match Tenv.lookup tenv super_class_name with - | Some {methods; supers} -> - let is_override pname = - (* Note: very coarse! TODO: match parameter names/types to get an exact match *) - String.equal (Typ.Procname.get_method pname) method_name - && not (Typ.Procname.is_constructor pname) - in - List.exists ~f:(fun pname -> is_override pname && f pname) methods - || List.exists ~f:(super_type_exists_ tenv) supers - | _ -> - false + let is_override pname = + (* Note: very coarse! TODO: match parameter names/types to get an exact match *) + String.equal (Typ.Procname.get_method pname) method_name + && not (Typ.Procname.is_constructor pname) in - let super_type_exists tenv type_name = - List.exists ~f:(super_type_exists_ tenv) + let rec find_super_type_ super_class_name = + Tenv.lookup tenv super_class_name + |> Option.bind ~f:(fun {Typ.Struct.methods; supers} -> + match List.find ~f:(fun pname -> is_override pname && f pname) methods with + | None -> + List.find_map ~f:find_super_type_ supers + | pname_opt -> + pname_opt ) + in + let find_super_type type_name = + List.find_map ~f:find_super_type_ (type_get_direct_supertypes tenv (Typ.mk (Tstruct type_name))) in - (check_current_type && f proc_name) - || - match proc_name with - | Typ.Procname.Java proc_name_java -> - super_type_exists tenv - (Typ.Name.Java.from_string (Typ.Procname.Java.get_class_name proc_name_java)) - | Typ.Procname.ObjC_Cpp proc_name_cpp -> - super_type_exists tenv (Typ.Procname.ObjC_Cpp.get_class_type_name proc_name_cpp) - | _ -> - false + if check_current_type && f proc_name then Some proc_name + else + match proc_name with + | Typ.Procname.Java proc_name_java -> + find_super_type + (Typ.Name.Java.from_string (Typ.Procname.Java.get_class_name proc_name_java)) + | Typ.Procname.ObjC_Cpp proc_name_cpp -> + find_super_type (Typ.Procname.ObjC_Cpp.get_class_type_name proc_name_cpp) + | _ -> + None + + +let override_exists ?(check_current_type= true) f tenv proc_name = + override_find ~check_current_type f tenv proc_name |> Option.is_some (* Only java supported at the moment *) diff --git a/infer/src/absint/PatternMatch.mli b/infer/src/absint/PatternMatch.mli index 7f36d7182..b670ea897 100644 --- a/infer/src/absint/PatternMatch.mli +++ b/infer/src/absint/PatternMatch.mli @@ -50,6 +50,11 @@ val proc_calls : -> (Typ.Procname.t -> ProcAttributes.t -> bool) -> (Typ.Procname.t * ProcAttributes.t) list (** Return the callees that satisfy [filter]. *) +val override_find : + ?check_current_type:bool -> (Typ.Procname.t -> bool) -> Tenv.t -> Typ.Procname.t + -> Typ.Procname.t option +(** Return a method which overrides [procname] and satisfies [f] (including [procname] itself when [check_current_type] is true, which it is by default). *) + val override_exists : ?check_current_type:bool -> (Typ.Procname.t -> bool) -> Tenv.t -> Typ.Procname.t -> bool (** Return true if applying the given predicate to an override of [procname] (including [procname] itself when [check_current_type] is true, which it is by default) returns true. *) diff --git a/infer/src/concurrency/RacerD.ml b/infer/src/concurrency/RacerD.ml index 8b54bd936..8f3a671fa 100644 --- a/infer/src/concurrency/RacerD.ml +++ b/infer/src/concurrency/RacerD.ml @@ -672,7 +672,7 @@ let analyze_procedure {Callbacks.proc_desc; get_proc_desc; tenv; summary} = let initial = let threads = if - Models.runs_on_ui_thread tenv proc_desc + Models.runs_on_ui_thread tenv proc_desc |> Option.is_some || Models.is_thread_confined_method tenv proc_desc then ThreadsDomain.AnyThreadButSelf else if diff --git a/infer/src/concurrency/RacerDConfig.ml b/infer/src/concurrency/RacerDConfig.ml index 37c98878d..f924f0de6 100644 --- a/infer/src/concurrency/RacerDConfig.ml +++ b/infer/src/concurrency/RacerDConfig.ml @@ -10,6 +10,7 @@ open! IStd module F = Format module L = Logging +module MF = MarkupFormatter module AnnotationAliases = struct let of_json = function @@ -494,8 +495,8 @@ module Models = struct None - let is_annotated_or_overriden_annotated_method is_annot pname tenv = - PatternMatch.override_exists + let find_annotated_or_overriden_annotated_method is_annot pname tenv = + PatternMatch.override_find (fun pn -> Annotations.pname_has_return_annot pn ~attrs_of_pname:Summary.proc_resolve_attributes is_annot ) @@ -513,17 +514,42 @@ module Models = struct || Annotations.ia_is_on_unbind annot || Annotations.ia_is_on_unmount annot in let pname = Procdesc.get_proc_name proc_desc in - Annotations.pdesc_has_return_annot proc_desc is_annot - || is_annotated_or_overriden_annotated_method is_annot pname tenv - || - match get_current_class_and_annotated_superclasses Annotations.ia_is_ui_thread tenv pname with - | Some (_, _ :: _) -> - true - | Some (current_class, _) -> - PatternMatch.is_subtype_of_str tenv current_class "android.app.Service" - && not (PatternMatch.is_subtype_of_str tenv current_class "android.app.IntentService") - | _ -> - false + if Annotations.pdesc_has_return_annot proc_desc is_annot then + Some + (F.asprintf "%a is annotated %s" + (MF.wrap_monospaced Typ.Procname.pp) + pname + (MF.monospaced_to_string Annotations.ui_thread)) + else + match find_annotated_or_overriden_annotated_method is_annot pname tenv with + | Some override_pname -> + Some + (F.asprintf "class %a overrides %a, which is annotated %s" + (MF.wrap_monospaced Typ.Procname.pp) + pname + (MF.wrap_monospaced Typ.Procname.pp) + override_pname + (MF.monospaced_to_string Annotations.ui_thread)) + | None -> + match + get_current_class_and_annotated_superclasses Annotations.ia_is_ui_thread tenv pname + with + | Some (current_class, _) + when let open PatternMatch in + is_subtype_of_str tenv current_class "android.app.Service" + && not (is_subtype_of_str tenv current_class "android.app.IntentService") -> + Some + (F.asprintf "class %s extends %s" + (MF.monospaced_to_string (Typ.Name.name current_class)) + (MF.monospaced_to_string "android.app.Service")) + | Some (current_class, super_class :: _) -> + Some + (F.asprintf "class %s extends %a, which is annotated %s" + (MF.monospaced_to_string (Typ.Name.name current_class)) + (MF.wrap_monospaced Typ.Name.pp) super_class + (MF.monospaced_to_string Annotations.ui_thread)) + | _ -> + None let get_current_class_and_threadsafe_superclasses tenv pname = @@ -544,7 +570,7 @@ module Models = struct let is_thread_safe_method pname tenv = - is_annotated_or_overriden_annotated_method is_thread_safe pname tenv + find_annotated_or_overriden_annotated_method is_thread_safe pname tenv |> Option.is_some let is_marked_thread_safe pdesc tenv = diff --git a/infer/src/concurrency/RacerDConfig.mli b/infer/src/concurrency/RacerDConfig.mli index f262d38d2..21a765b49 100644 --- a/infer/src/concurrency/RacerDConfig.mli +++ b/infer/src/concurrency/RacerDConfig.mli @@ -54,11 +54,12 @@ module Models : sig completely different classes that don't necessarily run on the same thread as the confined object. *) - val runs_on_ui_thread : Tenv.t -> Procdesc.t -> bool + val runs_on_ui_thread : Tenv.t -> Procdesc.t -> string option (** We don't want to warn on methods that run on the UI thread because they should always be single-threaded. Assume that methods annotated with @UiThread, @OnEvent, @OnBind, @OnMount, @OnUnbind, @OnUnmount always run on the UI thread. Also assume that any superclass - marked @UiThread implies all methods are on UI thread. *) + marked @UiThread implies all methods are on UI thread. Return Some string explaining why + this method is on the UI thread, else return None. *) val should_analyze_proc : Procdesc.t -> Tenv.t -> bool (** return true if we should compute a summary for the procedure. if this returns false, we won't diff --git a/infer/src/concurrency/starvation.ml b/infer/src/concurrency/starvation.ml index 8064ce3c9..37b683295 100644 --- a/infer/src/concurrency/starvation.ml +++ b/infer/src/concurrency/starvation.ml @@ -13,7 +13,7 @@ module MF = MarkupFormatter let debug fmt = L.(debug Analysis Verbose fmt) -let is_on_main_thread pn = +let is_on_ui_thread pn = RacerDConfig.(match Models.get_thread pn with Models.MainThread -> true | _ -> false) @@ -81,8 +81,9 @@ module TransferFunctions (CFG : ProcCfg.S) = struct | NoEffect when Models.may_block tenv callee actuals -> let caller = Procdesc.get_proc_name pdesc in Domain.blocking_call ~caller ~callee loc astate - | NoEffect when is_on_main_thread callee -> - Domain.set_on_main_thread astate + | NoEffect when is_on_ui_thread callee -> + let explanation = F.asprintf "calls %a" (MF.wrap_monospaced Typ.Procname.pp) callee in + Domain.set_on_ui_thread astate explanation | _ -> Payload.read pdesc callee |> Option.value_map ~default:astate ~f:(Domain.integrate_summary astate callee loc) ) @@ -124,9 +125,8 @@ let analyze_procedure {Callbacks.proc_desc; tenv; summary} = ~f:(StarvationDomain.acquire StarvationDomain.empty loc) in let initial = - if RacerDConfig.Models.runs_on_ui_thread tenv proc_desc then - StarvationDomain.set_on_main_thread initial - else initial + RacerDConfig.Models.runs_on_ui_thread tenv proc_desc + |> Option.value_map ~default:initial ~f:(StarvationDomain.set_on_ui_thread initial) in Analyzer.compute_post proc_data ~initial |> Option.value_map ~default:summary ~f:(fun lock_state -> @@ -244,13 +244,13 @@ let report_deadlocks tenv current_pdesc (summary, current_main) = let endpoint_summaries = get_summaries_of_methods_in_class tenv endpoint_class in (* for each summary related to the endpoint, analyse and report on its pairs *) List.iter endpoint_summaries ~f:(fun (endpoint_pname, (summary, endpoint_main)) -> - if not (current_main && endpoint_main) then + if UIThreadDomain.is_empty current_main || UIThreadDomain.is_empty endpoint_main then LockOrderDomain.iter (report_endpoint_elem elem endpoint_pname) summary ) in LockOrderDomain.iter report_on_current_elem summary -let report_blocks_on_main_thread tenv current_pdesc summary = +let report_blocks_on_main_thread tenv current_pdesc order ui_explain = let open StarvationDomain in let current_loc = Procdesc.get_loc current_pdesc in let current_pname = Procdesc.get_proc_name current_pdesc in @@ -260,9 +260,11 @@ let report_blocks_on_main_thread tenv current_pdesc summary = ; eventually= {LockEvent.event= LockEvent.MayBlock block_descr} } when LockIdentity.equal current_lock lock -> let error_message = - Format.asprintf "UI thread method %a %a, which may be held by another thread which %s" + Format.asprintf + "Method %a runs on UI thread (because %s) and %a, which may be held by another thread \ + which %s" (MF.wrap_monospaced Typ.Procname.pp) - current_pname LockIdentity.pp lock block_descr + current_pname ui_explain LockIdentity.pp lock block_descr in let exn = Exceptions.Checkers (IssueType.starvation, Localise.verbatim_desc error_message) @@ -278,9 +280,9 @@ let report_blocks_on_main_thread tenv current_pdesc summary = match eventually with | {LockEvent.event= LockEvent.MayBlock _} -> let error_message = - Format.asprintf "UI thread method %a may block; %a" + Format.asprintf "Method %a runs on UI thread (because %s), and may block; %a" (MF.wrap_monospaced Typ.Procname.pp) - current_pname LockEvent.pp_event eventually.LockEvent.event + current_pname ui_explain LockEvent.pp_event eventually.LockEvent.event in let exn = Exceptions.Checkers (IssueType.starvation, Localise.verbatim_desc error_message) @@ -293,27 +295,29 @@ let report_blocks_on_main_thread tenv current_pdesc summary = () | Some endpoint_class -> (* get the class of the root variable of the lock in the endpoint event - and retrieve all the summaries of the methods of that class *) + and retrieve all the summaries of the methods of that class *) let endpoint_summaries = get_summaries_of_methods_in_class tenv endpoint_class in (* for each summary related to the endpoint, analyse and report on its pairs *) - List.iter endpoint_summaries ~f:(fun (endpoint_pname, (summary, main)) -> + List.iter endpoint_summaries ~f:(fun (endpoint_pname, (order, ui)) -> (* skip methods known to run on ui thread, as they cannot run in parallel to us *) - if main then () - else - LockOrderDomain.iter - (report_remote_block elem endpoint_lock endpoint_pname) - summary ) + if UIThreadDomain.is_empty ui then + LockOrderDomain.iter (report_remote_block elem endpoint_lock endpoint_pname) order + ) in - LockOrderDomain.iter report_on_current_elem summary + LockOrderDomain.iter report_on_current_elem order let reporting {Callbacks.procedures; exe_env} = let report_procedure (tenv, proc_desc) = die_if_not_java proc_desc ; Payload.read proc_desc (Procdesc.get_proc_name proc_desc) - |> Option.iter ~f:(fun ((s, main) as summary) -> + |> Option.iter ~f:(fun ((order, ui) as summary) -> report_deadlocks tenv proc_desc summary ; - if main then report_blocks_on_main_thread tenv proc_desc s ) + match ui with + | AbstractDomain.Types.Bottom -> + () + | AbstractDomain.Types.NonBottom on_ui -> + report_blocks_on_main_thread tenv proc_desc order on_ui ) in List.iter procedures ~f:report_procedure ; let sourcefile = exe_env.Exe_env.source_file in diff --git a/infer/src/concurrency/starvationDomain.ml b/infer/src/concurrency/starvationDomain.ml index 4c0b65c9c..f0815449f 100644 --- a/infer/src/concurrency/starvationDomain.ml +++ b/infer/src/concurrency/starvationDomain.ml @@ -9,6 +9,7 @@ open! IStd module F = Format module L = Logging +module MF = MarkupFormatter module LockIdentity = struct type t = AccessPath.t @@ -41,7 +42,11 @@ module LockIdentity = struct let pp fmt (((_, typ), _) as lock) = - F.fprintf fmt "locks `%a` in class `%a`" AccessPath.pp lock (Typ.pp_full Pp.text) typ + F.fprintf fmt "locks %a in class %a" + (MF.wrap_monospaced AccessPath.pp) + lock + (MF.wrap_monospaced (Typ.pp_full Pp.text)) + typ let owner_class ((_, typ), _) = Typ.inner_name typ @@ -100,7 +105,13 @@ module LockEvent = struct let make_blocks msg loc = {event= MayBlock msg; loc; trace= []} let make_blocking_call ~caller ~callee loc = - let descr = F.asprintf "calls %a from %a" Typ.Procname.pp callee Typ.Procname.pp caller in + let descr = + F.asprintf "calls %a from %a" + (MF.wrap_monospaced Typ.Procname.pp) + callee + (MF.wrap_monospaced Typ.Procname.pp) + caller + in make_blocks descr loc @@ -108,7 +119,9 @@ module LockEvent = struct let call_trace, nesting = List.fold e.trace ~init:([], 0) ~f:(fun (tr, ns) callsite -> let elem_descr = - F.asprintf "Method call: %a" Typ.Procname.pp (CallSite.pname callsite) + F.asprintf "Method call: %a" + (MF.wrap_monospaced Typ.Procname.pp) + (CallSite.pname callsite) in let elem = Errlog.make_trace_element ns (CallSite.loc callsite) elem_descr [] in (elem :: tr, ns + 1) ) @@ -204,13 +217,25 @@ module LockState = struct fold ff map init end -module MainThreadDomain = AbstractDomain.BooleanOr -include AbstractDomain.Pair (AbstractDomain.Pair (LockState) (LockOrderDomain)) (MainThreadDomain) +module UIThreadExplanationDomain = struct + type astate = string + + let pp = String.pp + + let join lhs _ = lhs + + let widen ~prev ~next ~num_iters:_ = join prev next + + let ( <= ) ~lhs:_ ~rhs:_ = true +end + +module UIThreadDomain = AbstractDomain.BottomLifted (UIThreadExplanationDomain) +include AbstractDomain.Pair (AbstractDomain.Pair (LockState) (LockOrderDomain)) (UIThreadDomain) -let empty = ((LockState.empty, LockOrderDomain.empty), false) +let empty = ((LockState.empty, LockOrderDomain.empty), UIThreadDomain.empty) let is_empty ((ls, lo), main) = - LockState.is_empty ls && LockOrderDomain.is_empty lo && MainThreadDomain.is_empty main + LockState.is_empty ls && LockOrderDomain.is_empty lo && UIThreadDomain.is_empty main (* for every lock b held locally, add a pair (b, lock_event), plus (None, lock_event) *) @@ -260,15 +285,17 @@ let integrate_summary ((ls, lo), main) callee_pname loc callee_summary = (* add callsite to the "eventually" trace *) let elems = LockOrderDomain.with_callsite callsite callee_lo in let lo' = LockOrderDomain.fold do_elem elems lo in - let main' = MainThreadDomain.join main callee_main in + let main' = UIThreadDomain.join main callee_main in ((ls, lo'), main') -let set_on_main_thread (sum, _) = (sum, true) +let set_on_ui_thread (sum, explain_opt) explain = + (sum, UIThreadDomain.join explain_opt (AbstractDomain.Types.NonBottom explain)) + let to_summary ((_, lo), main) = (lo, main) -type summary = LockOrderDomain.astate * MainThreadDomain.astate +type summary = LockOrderDomain.astate * UIThreadDomain.astate let pp_summary fmt (lo, main) = - F.fprintf fmt "LockOrder: %a, MainThread: %a" LockOrderDomain.pp lo MainThreadDomain.pp main + F.fprintf fmt "LockOrder: %a, UIThread: %a" LockOrderDomain.pp lo UIThreadDomain.pp main diff --git a/infer/src/concurrency/starvationDomain.mli b/infer/src/concurrency/starvationDomain.mli index d8ed0104d..4baa91523 100644 --- a/infer/src/concurrency/starvationDomain.mli +++ b/infer/src/concurrency/starvationDomain.mli @@ -55,6 +55,9 @@ module LockOrderDomain : sig include AbstractDomain.WithBottom with type astate = t end +module UIThreadDomain : + AbstractDomain.WithBottom with type astate = string AbstractDomain.Types.bottom_lifted + include AbstractDomain.WithBottom val acquire : astate -> Location.t -> LockIdentity.t -> astate @@ -64,9 +67,11 @@ val release : astate -> LockIdentity.t -> astate val blocking_call : caller:Typ.Procname.t -> callee:Typ.Procname.t -> Location.t -> astate -> astate -val set_on_main_thread : astate -> astate +val set_on_ui_thread : astate -> string -> astate +(** set the property "runs on UI thread" to true by attaching the given explanation string as to + why this method is thought to do so *) -type summary = LockOrderDomain.astate * bool +type summary = LockOrderDomain.astate * UIThreadDomain.astate val pp_summary : F.formatter -> summary -> unit diff --git a/infer/tests/codetoanalyze/java/starvation/issues.exp b/infer/tests/codetoanalyze/java/starvation/issues.exp index f8a62d7b9..cd6db3418 100644 --- a/infer/tests/codetoanalyze/java/starvation/issues.exp +++ b/infer/tests/codetoanalyze/java/starvation/issues.exp @@ -1,29 +1,29 @@ -codetoanalyze/java/starvation/AccMgr.java, void AccMgr.lockOnUiThreadBad(), 26, STARVATION, ERROR, [[Trace 1] `void AccMgr.lockOnUiThreadBad()`,locks `this.AccMgr.lock` in class `AccMgr*`,[Trace 2] `void AccMgr.setUserDataUnderLock()`,locks `this.AccMgr.lock` in class `AccMgr*`,calls void AccountManager.setUserData(Account,String,String) from void AccMgr.setUserDataUnderLock()] -codetoanalyze/java/starvation/AccMgr.java, void AccMgr.onUiThreadBad(), 21, STARVATION, ERROR, [ `void AccMgr.onUiThreadBad()`,calls void AccountManager.setUserData(Account,String,String) from void AccMgr.onUiThreadBad()] -codetoanalyze/java/starvation/AsyncTaskGet.java, void AsyncTaskGet.lockOnUiThreadBad(), 32, STARVATION, ERROR, [[Trace 1] `void AsyncTaskGet.lockOnUiThreadBad()`,locks `this.AsyncTaskGet.lock` in class `AsyncTaskGet*`,[Trace 2] `void AsyncTaskGet.taskGetUnderLock()`,locks `this.AsyncTaskGet.lock` in class `AsyncTaskGet*`,calls Object AsyncTask.get() from void AsyncTaskGet.taskGetUnderLock()] -codetoanalyze/java/starvation/AsyncTaskGet.java, void AsyncTaskGet.taskGetOnUiThreadBad(), 21, STARVATION, ERROR, [ `void AsyncTaskGet.taskGetOnUiThreadBad()`,calls Object AsyncTask.get() from void AsyncTaskGet.taskGetOnUiThreadBad()] -codetoanalyze/java/starvation/Binders.java, void Binders.annotationBad(), 36, STARVATION, ERROR, [ `void Binders.annotationBad()`,Method call: void Binders.doTransact(),calls boolean Binder.transact(int,Parcel,Parcel,int) from void Binders.doTransact()] -codetoanalyze/java/starvation/Binders.java, void Binders.interBad(), 25, STARVATION, ERROR, [ `void Binders.interBad()`,calls boolean Binder.transact(int,Parcel,Parcel,int) from void Binders.interBad()] -codetoanalyze/java/starvation/Binders.java, void Binders.intraBad(), 30, STARVATION, ERROR, [ `void Binders.intraBad()`,Method call: void Binders.doTransact(),calls boolean Binder.transact(int,Parcel,Parcel,int) from void Binders.doTransact()] -codetoanalyze/java/starvation/Countdwn.java, void Countdwn.awaitOnMainByAnnotBad(), 22, STARVATION, ERROR, [ `void Countdwn.awaitOnMainByAnnotBad()`,calls void CountDownLatch.await() from void Countdwn.awaitOnMainByAnnotBad()] -codetoanalyze/java/starvation/Countdwn.java, void Countdwn.awaitOnMainByCallBad(), 16, STARVATION, ERROR, [ `void Countdwn.awaitOnMainByCallBad()`,calls void CountDownLatch.await() from void Countdwn.awaitOnMainByCallBad()] -codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getDirectBad(), 21, STARVATION, ERROR, [ `void FutureGet.getDirectBad()`,calls Object Future.get() from void FutureGet.getDirectBad()] -codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getIndirectBad(), 26, STARVATION, ERROR, [[Trace 1] `void FutureGet.getIndirectBad()`,locks `this.FutureGet.lock` in class `FutureGet*`,[Trace 2] `void FutureGet.getUnderLock()`,locks `this.FutureGet.lock` in class `FutureGet*`,calls Object Future.get() from void FutureGet.getUnderLock()] -codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getTimeout50000001MicroSecondsBad(), 76, STARVATION, ERROR, [ `void FutureGet.getTimeout50000001MicroSecondsBad()`,calls Object Future.get(long,TimeUnit) from void FutureGet.getTimeout50000001MicroSecondsBad()] -codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getTimeoutOneDayBad(), 41, STARVATION, ERROR, [ `void FutureGet.getTimeoutOneDayBad()`,calls Object Future.get(long,TimeUnit) from void FutureGet.getTimeoutOneDayBad()] -codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getTimeoutOneHourBad(), 55, STARVATION, ERROR, [ `void FutureGet.getTimeoutOneHourBad()`,calls Object Future.get(long,TimeUnit) from void FutureGet.getTimeoutOneHourBad()] -codetoanalyze/java/starvation/IndirectBlock.java, void IndirectBlock.takeExpensiveLockOnUiThreadBad(), 23, STARVATION, ERROR, [[Trace 1] `void IndirectBlock.takeExpensiveLockOnUiThreadBad()`,locks `this.IndirectBlock.expensiveLock` in class `IndirectBlock*`,[Trace 2] `void IndirectBlock.doTransactUnderLock()`,locks `this.IndirectBlock.expensiveLock` in class `IndirectBlock*`,calls boolean Binder.transact(int,Parcel,Parcel,int) from void IndirectBlock.doTransactUnderLock()] -codetoanalyze/java/starvation/IndirectBlock.java, void IndirectBlock.takeRemoteExpensiveLockOnUiThreadBad(IndirectInterproc), 34, STARVATION, ERROR, [[Trace 1] `void IndirectBlock.takeRemoteExpensiveLockOnUiThreadBad(IndirectInterproc)`,Method call: void IndirectInterproc.takeLock(),locks `this` in class `IndirectInterproc*`,[Trace 2] `void IndirectInterproc.doTransactUnderLock(Binder)`,locks `this` in class `IndirectInterproc*`,calls boolean Binder.transact(int,Parcel,Parcel,int) from void IndirectInterproc.doTransactUnderLock(Binder)] -codetoanalyze/java/starvation/InnerClass.java, InnerClass$InnerClassA.(InnerClass,Object), 49, DEADLOCK, ERROR, [[Trace 1] `InnerClass$InnerClassA.(InnerClass,Object)`,locks `this` in class `InnerClass$InnerClassA*`,Method call: void InnerClass.bar(),locks `this` in class `InnerClass*`,[Trace 2] `void InnerClass.outerInnerBad(InnerClass$InnerClassA)`,locks `this` in class `InnerClass*`,Method call: void InnerClass$InnerClassA.baz(),locks `this` in class `InnerClass$InnerClassA*`] -codetoanalyze/java/starvation/InnerClass.java, void InnerClass$InnerClassA.innerOuterBad(), 36, DEADLOCK, ERROR, [[Trace 1] `void InnerClass$InnerClassA.innerOuterBad()`,locks `this` in class `InnerClass$InnerClassA*`,Method call: void InnerClass.bar(),locks `this` in class `InnerClass*`,[Trace 2] `void InnerClass.outerInnerBad(InnerClass$InnerClassA)`,locks `this` in class `InnerClass*`,Method call: void InnerClass$InnerClassA.baz(),locks `this` in class `InnerClass$InnerClassA*`] -codetoanalyze/java/starvation/Interclass.java, void Interclass.interclass1Bad(InterclassA), 12, DEADLOCK, ERROR, [[Trace 1] `void Interclass.interclass1Bad(InterclassA)`,locks `this` in class `Interclass*`,Method call: void InterclassA.interclass1Bad(),locks `this` in class `InterclassA*`,[Trace 2] `void InterclassA.interclass2Bad(Interclass)`,locks `this` in class `InterclassA*`,Method call: void Interclass.interclass2Bad(),locks `this` in class `Interclass*`] -codetoanalyze/java/starvation/Interproc.java, void Interproc.interproc1Bad(InterprocA), 11, DEADLOCK, ERROR, [[Trace 1] `void Interproc.interproc1Bad(InterprocA)`,locks `this` in class `Interproc*`,Method call: void Interproc.interproc2Bad(InterprocA),locks `b` in class `InterprocA*`,[Trace 2] `void InterprocA.interproc1Bad(Interproc)`,locks `this` in class `InterprocA*`,Method call: void InterprocA.interproc2Bad(Interproc),locks `d` in class `Interproc*`] +codetoanalyze/java/starvation/AccMgr.java, void AccMgr.lockOnUiThreadBad(), 26, STARVATION, ERROR, [[Trace 1] `void AccMgr.lockOnUiThreadBad()`,locks `this.AccMgr.lock` in class `AccMgr*`,[Trace 2] `void AccMgr.setUserDataUnderLock()`,locks `this.AccMgr.lock` in class `AccMgr*`,calls `void AccountManager.setUserData(Account,String,String)` from `void AccMgr.setUserDataUnderLock()`] +codetoanalyze/java/starvation/AccMgr.java, void AccMgr.onUiThreadBad(), 21, STARVATION, ERROR, [ `void AccMgr.onUiThreadBad()`,calls `void AccountManager.setUserData(Account,String,String)` from `void AccMgr.onUiThreadBad()`] +codetoanalyze/java/starvation/AsyncTaskGet.java, void AsyncTaskGet.lockOnUiThreadBad(), 32, STARVATION, ERROR, [[Trace 1] `void AsyncTaskGet.lockOnUiThreadBad()`,locks `this.AsyncTaskGet.lock` in class `AsyncTaskGet*`,[Trace 2] `void AsyncTaskGet.taskGetUnderLock()`,locks `this.AsyncTaskGet.lock` in class `AsyncTaskGet*`,calls `Object AsyncTask.get()` from `void AsyncTaskGet.taskGetUnderLock()`] +codetoanalyze/java/starvation/AsyncTaskGet.java, void AsyncTaskGet.taskGetOnUiThreadBad(), 21, STARVATION, ERROR, [ `void AsyncTaskGet.taskGetOnUiThreadBad()`,calls `Object AsyncTask.get()` from `void AsyncTaskGet.taskGetOnUiThreadBad()`] +codetoanalyze/java/starvation/Binders.java, void Binders.annotationBad(), 36, STARVATION, ERROR, [ `void Binders.annotationBad()`,Method call: `void Binders.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void Binders.doTransact()`] +codetoanalyze/java/starvation/Binders.java, void Binders.interBad(), 25, STARVATION, ERROR, [ `void Binders.interBad()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void Binders.interBad()`] +codetoanalyze/java/starvation/Binders.java, void Binders.intraBad(), 30, STARVATION, ERROR, [ `void Binders.intraBad()`,Method call: `void Binders.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void Binders.doTransact()`] +codetoanalyze/java/starvation/Countdwn.java, void Countdwn.awaitOnMainByAnnotBad(), 22, STARVATION, ERROR, [ `void Countdwn.awaitOnMainByAnnotBad()`,calls `void CountDownLatch.await()` from `void Countdwn.awaitOnMainByAnnotBad()`] +codetoanalyze/java/starvation/Countdwn.java, void Countdwn.awaitOnMainByCallBad(), 16, STARVATION, ERROR, [ `void Countdwn.awaitOnMainByCallBad()`,calls `void CountDownLatch.await()` from `void Countdwn.awaitOnMainByCallBad()`] +codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getDirectBad(), 21, STARVATION, ERROR, [ `void FutureGet.getDirectBad()`,calls `Object Future.get()` from `void FutureGet.getDirectBad()`] +codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getIndirectBad(), 26, STARVATION, ERROR, [[Trace 1] `void FutureGet.getIndirectBad()`,locks `this.FutureGet.lock` in class `FutureGet*`,[Trace 2] `void FutureGet.getUnderLock()`,locks `this.FutureGet.lock` in class `FutureGet*`,calls `Object Future.get()` from `void FutureGet.getUnderLock()`] +codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getTimeout50000001MicroSecondsBad(), 76, STARVATION, ERROR, [ `void FutureGet.getTimeout50000001MicroSecondsBad()`,calls `Object Future.get(long,TimeUnit)` from `void FutureGet.getTimeout50000001MicroSecondsBad()`] +codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getTimeoutOneDayBad(), 41, STARVATION, ERROR, [ `void FutureGet.getTimeoutOneDayBad()`,calls `Object Future.get(long,TimeUnit)` from `void FutureGet.getTimeoutOneDayBad()`] +codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getTimeoutOneHourBad(), 55, STARVATION, ERROR, [ `void FutureGet.getTimeoutOneHourBad()`,calls `Object Future.get(long,TimeUnit)` from `void FutureGet.getTimeoutOneHourBad()`] +codetoanalyze/java/starvation/IndirectBlock.java, void IndirectBlock.takeExpensiveLockOnUiThreadBad(), 23, STARVATION, ERROR, [[Trace 1] `void IndirectBlock.takeExpensiveLockOnUiThreadBad()`,locks `this.IndirectBlock.expensiveLock` in class `IndirectBlock*`,[Trace 2] `void IndirectBlock.doTransactUnderLock()`,locks `this.IndirectBlock.expensiveLock` in class `IndirectBlock*`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void IndirectBlock.doTransactUnderLock()`] +codetoanalyze/java/starvation/IndirectBlock.java, void IndirectBlock.takeRemoteExpensiveLockOnUiThreadBad(IndirectInterproc), 34, STARVATION, ERROR, [[Trace 1] `void IndirectBlock.takeRemoteExpensiveLockOnUiThreadBad(IndirectInterproc)`,Method call: `void IndirectInterproc.takeLock()`,locks `this` in class `IndirectInterproc*`,[Trace 2] `void IndirectInterproc.doTransactUnderLock(Binder)`,locks `this` in class `IndirectInterproc*`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void IndirectInterproc.doTransactUnderLock(Binder)`] +codetoanalyze/java/starvation/InnerClass.java, InnerClass$InnerClassA.(InnerClass,Object), 49, DEADLOCK, ERROR, [[Trace 1] `InnerClass$InnerClassA.(InnerClass,Object)`,locks `this` in class `InnerClass$InnerClassA*`,Method call: `void InnerClass.bar()`,locks `this` in class `InnerClass*`,[Trace 2] `void InnerClass.outerInnerBad(InnerClass$InnerClassA)`,locks `this` in class `InnerClass*`,Method call: `void InnerClass$InnerClassA.baz()`,locks `this` in class `InnerClass$InnerClassA*`] +codetoanalyze/java/starvation/InnerClass.java, void InnerClass$InnerClassA.innerOuterBad(), 36, DEADLOCK, ERROR, [[Trace 1] `void InnerClass$InnerClassA.innerOuterBad()`,locks `this` in class `InnerClass$InnerClassA*`,Method call: `void InnerClass.bar()`,locks `this` in class `InnerClass*`,[Trace 2] `void InnerClass.outerInnerBad(InnerClass$InnerClassA)`,locks `this` in class `InnerClass*`,Method call: `void InnerClass$InnerClassA.baz()`,locks `this` in class `InnerClass$InnerClassA*`] +codetoanalyze/java/starvation/Interclass.java, void Interclass.interclass1Bad(InterclassA), 12, DEADLOCK, ERROR, [[Trace 1] `void Interclass.interclass1Bad(InterclassA)`,locks `this` in class `Interclass*`,Method call: `void InterclassA.interclass1Bad()`,locks `this` in class `InterclassA*`,[Trace 2] `void InterclassA.interclass2Bad(Interclass)`,locks `this` in class `InterclassA*`,Method call: `void Interclass.interclass2Bad()`,locks `this` in class `Interclass*`] +codetoanalyze/java/starvation/Interproc.java, void Interproc.interproc1Bad(InterprocA), 11, DEADLOCK, ERROR, [[Trace 1] `void Interproc.interproc1Bad(InterprocA)`,locks `this` in class `Interproc*`,Method call: `void Interproc.interproc2Bad(InterprocA)`,locks `b` in class `InterprocA*`,[Trace 2] `void InterprocA.interproc1Bad(Interproc)`,locks `this` in class `InterprocA*`,Method call: `void InterprocA.interproc2Bad(Interproc)`,locks `d` in class `Interproc*`] codetoanalyze/java/starvation/Intraproc.java, void Intraproc.intraBad(IntraprocA), 11, DEADLOCK, ERROR, [[Trace 1] `void Intraproc.intraBad(IntraprocA)`,locks `this` in class `Intraproc*`,locks `o` in class `IntraprocA*`,[Trace 2] `void IntraprocA.intraBad(Intraproc)`,locks `this` in class `IntraprocA*`,locks `o` in class `Intraproc*`] -codetoanalyze/java/starvation/JavaIO.java, void JavaIO.fileReadBad(), 32, STARVATION, ERROR, [ `void JavaIO.fileReadBad()`,Method call: int JavaIO.doFileRead(),calls int InputStreamReader.read() from int JavaIO.doFileRead()] -codetoanalyze/java/starvation/JavaIO.java, void JavaIO.streamReadBad(), 37, STARVATION, ERROR, [ `void JavaIO.streamReadBad()`,Method call: String JavaIO.doStreamRead(),calls String DataInputStream.readUTF() from String JavaIO.doStreamRead()] -codetoanalyze/java/starvation/LegacySync.java, Object LegacySync.onUiThreadOpBad(), 26, STARVATION, ERROR, [[Trace 1] `Object LegacySync.onUiThreadOpBad()`,locks `this.LegacySync.table` in class `LegacySync*`,[Trace 2] `void LegacySync.notOnUiThreadSyncedBad()`,locks `this.LegacySync.table` in class `LegacySync*`,calls Object Future.get() from void LegacySync.notOnUiThreadSyncedBad()] -codetoanalyze/java/starvation/ServiceOnUIThread.java, IBinder ServiceOnUIThread.onBind(Intent), 20, STARVATION, ERROR, [ `IBinder ServiceOnUIThread.onBind(Intent)`,Method call: void ServiceOnUIThread.transactBad(),calls boolean IBinder.transact(int,Parcel,Parcel,int) from void ServiceOnUIThread.transactBad()] -codetoanalyze/java/starvation/ServiceOnUIThread.java, void ServiceOnUIThread.transactBad(), 25, STARVATION, ERROR, [ `void ServiceOnUIThread.transactBad()`,calls boolean IBinder.transact(int,Parcel,Parcel,int) from void ServiceOnUIThread.transactBad()] -codetoanalyze/java/starvation/StaticLock.java, void StaticLock.lockOtherClassOneWayBad(), 24, DEADLOCK, ERROR, [[Trace 1] `void StaticLock.lockOtherClassOneWayBad()`,locks `StaticLock$0` in class `java.lang.Class*`,locks `this` in class `StaticLock*`,[Trace 2] `void StaticLock.lockOtherClassAnotherWayNad()`,locks `this` in class `StaticLock*`,Method call: void StaticLock.staticSynced(),locks `StaticLock$0` in class `java.lang.Class*`] +codetoanalyze/java/starvation/JavaIO.java, void JavaIO.fileReadBad(), 32, STARVATION, ERROR, [ `void JavaIO.fileReadBad()`,Method call: `int JavaIO.doFileRead()`,calls `int InputStreamReader.read()` from `int JavaIO.doFileRead()`] +codetoanalyze/java/starvation/JavaIO.java, void JavaIO.streamReadBad(), 37, STARVATION, ERROR, [ `void JavaIO.streamReadBad()`,Method call: `String JavaIO.doStreamRead()`,calls `String DataInputStream.readUTF()` from `String JavaIO.doStreamRead()`] +codetoanalyze/java/starvation/LegacySync.java, Object LegacySync.onUiThreadOpBad(), 26, STARVATION, ERROR, [[Trace 1] `Object LegacySync.onUiThreadOpBad()`,locks `this.LegacySync.table` in class `LegacySync*`,[Trace 2] `void LegacySync.notOnUiThreadSyncedBad()`,locks `this.LegacySync.table` in class `LegacySync*`,calls `Object Future.get()` from `void LegacySync.notOnUiThreadSyncedBad()`] +codetoanalyze/java/starvation/ServiceOnUIThread.java, IBinder ServiceOnUIThread.onBind(Intent), 20, STARVATION, ERROR, [ `IBinder ServiceOnUIThread.onBind(Intent)`,Method call: `void ServiceOnUIThread.transactBad()`,calls `boolean IBinder.transact(int,Parcel,Parcel,int)` from `void ServiceOnUIThread.transactBad()`] +codetoanalyze/java/starvation/ServiceOnUIThread.java, void ServiceOnUIThread.transactBad(), 25, STARVATION, ERROR, [ `void ServiceOnUIThread.transactBad()`,calls `boolean IBinder.transact(int,Parcel,Parcel,int)` from `void ServiceOnUIThread.transactBad()`] +codetoanalyze/java/starvation/StaticLock.java, void StaticLock.lockOtherClassOneWayBad(), 24, DEADLOCK, ERROR, [[Trace 1] `void StaticLock.lockOtherClassOneWayBad()`,locks `StaticLock$0` in class `java.lang.Class*`,locks `this` in class `StaticLock*`,[Trace 2] `void StaticLock.lockOtherClassAnotherWayNad()`,locks `this` in class `StaticLock*`,Method call: `void StaticLock.staticSynced()`,locks `StaticLock$0` in class `java.lang.Class*`] codetoanalyze/java/starvation/UIDeadlock.java, void UIDeadlock.onUIThreadBad(), 28, DEADLOCK, ERROR, [[Trace 1] `void UIDeadlock.onUIThreadBad()`,locks `this` in class `UIDeadlock*`,locks `this.UIDeadlock.lockB` in class `UIDeadlock*`,[Trace 2] `void UIDeadlock.notOnUIThreadBad()`,locks `this.UIDeadlock.lockB` in class `UIDeadlock*`,locks `this` in class `UIDeadlock*`] -codetoanalyze/java/starvation/VisDispFrame.java, void VisDispFrame.callsGetVisibleDisplayFrameOnUiThreadBad(), 19, STARVATION, ERROR, [ `void VisDispFrame.callsGetVisibleDisplayFrameOnUiThreadBad()`,calls void View.getWindowVisibleDisplayFrame(Rect) from void VisDispFrame.callsGetVisibleDisplayFrameOnUiThreadBad()] +codetoanalyze/java/starvation/VisDispFrame.java, void VisDispFrame.callsGetVisibleDisplayFrameOnUiThreadBad(), 19, STARVATION, ERROR, [ `void VisDispFrame.callsGetVisibleDisplayFrameOnUiThreadBad()`,calls `void View.getWindowVisibleDisplayFrame(Rect)` from `void VisDispFrame.callsGetVisibleDisplayFrameOnUiThreadBad()`]