From 888a169dcecfd0e1aa4037b6e3addb15f7a1c4c9 Mon Sep 17 00:00:00 2001 From: Nikos Gorogiannis Date: Tue, 11 Sep 2018 20:20:10 -0700 Subject: [PATCH] [starvation] make a trace out of our explanation as to why a method runs on the UI thread Summary: Sometimes it's very confusing to see why infer believes a method is running on the UI thread. Make a trace out of all the relevant info. Reviewed By: mbouaziz Differential Revision: D9781212 fbshipit-source-id: 6d018e400 --- infer/src/concurrency/starvation.ml | 27 +++++--- infer/src/concurrency/starvationDomain.ml | 38 +++++++++-- infer/src/concurrency/starvationDomain.mli | 11 ++- .../codetoanalyze/java/starvation/issues.exp | 68 +++++++++---------- 4 files changed, 93 insertions(+), 51 deletions(-) diff --git a/infer/src/concurrency/starvation.ml b/infer/src/concurrency/starvation.ml index 5f7b6bcd8..6348ff8f5 100644 --- a/infer/src/concurrency/starvation.ml +++ b/infer/src/concurrency/starvation.ml @@ -104,7 +104,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct do_lock actuals loc astate |> do_unlock actuals | NoEffect when is_on_ui_thread callee -> let explanation = F.asprintf "it calls %a" (MF.wrap_monospaced Typ.Procname.pp) callee in - Domain.set_on_ui_thread astate explanation + Domain.set_on_ui_thread astate loc explanation | NoEffect -> ( let caller = Procdesc.get_proc_name pdesc in match may_block tenv callee actuals with @@ -143,10 +143,10 @@ let analyze_procedure {Callbacks.proc_desc; tenv; summary} = let pname = Procdesc.get_proc_name proc_desc in let formals = FormalMap.make proc_desc in let proc_data = ProcData.make proc_desc tenv formals in + let loc = Procdesc.get_loc proc_desc in let initial = if not (Procdesc.is_java_synchronized proc_desc) then StarvationDomain.empty else - let loc = Procdesc.get_loc proc_desc in let lock = match pname with | Typ.Procname.Java java_pname when Typ.Procname.Java.is_static java_pname -> @@ -161,7 +161,7 @@ let analyze_procedure {Callbacks.proc_desc; tenv; summary} = in let initial = ConcurrencyModels.runs_on_ui_thread tenv proc_desc - |> Option.value_map ~default:initial ~f:(StarvationDomain.set_on_ui_thread initial) + |> Option.value_map ~default:initial ~f:(StarvationDomain.set_on_ui_thread initial loc) in let filter_blocks = if is_nonblocking tenv proc_desc then fun ({events; order} as astate) -> @@ -412,14 +412,18 @@ let report_starvation env {StarvationDomain.events; ui} report_map' = | MayBlock (block_descr, sev) when Lock.equal current_lock lock -> let error_message = Format.asprintf - "Method %a runs on UI thread (because %s) and %a, which may be held by another thread \ + "Method %a runs on UI thread (because %a) and %a, which may be held by another thread \ which %s." (MF.wrap_monospaced Typ.Procname.pp) - current_pname ui_explain Lock.pp lock block_descr + current_pname UIThreadExplanationDomain.pp ui_explain Lock.pp lock block_descr in let first_trace = Event.make_trace ~header:"[Trace 1] " current_pname event in let second_trace = Order.make_trace ~header:"[Trace 2] " endpoint_pname endpoint_elem in - let ltr = first_trace @ second_trace in + let ui_trace = + UIThreadExplanationDomain.make_trace ~header:"[Trace 1 on UI thread] " current_pname + ui_explain + in + let ltr = first_trace @ second_trace @ ui_trace in let loc = Event.get_loc event in ReportMap.add_starvation tenv sev current_pdesc loc ltr error_message report_map | _ -> @@ -429,12 +433,17 @@ let report_starvation env {StarvationDomain.events; ui} report_map' = match event.Event.elem with | MayBlock (_, sev) -> let error_message = - Format.asprintf "Method %a runs on UI thread (because %s), and may block; %a." + Format.asprintf "Method %a runs on UI thread (because %a), and may block; %a." (MF.wrap_monospaced Typ.Procname.pp) - current_pname ui_explain Event.pp event + current_pname UIThreadExplanationDomain.pp ui_explain Event.pp event in let loc = Event.get_loc event in - let ltr = Event.make_trace current_pname event in + let trace = Event.make_trace current_pname event in + let ui_trace = + UIThreadExplanationDomain.make_trace ~header:"[Trace on UI thread] " current_pname + ui_explain + in + let ltr = trace @ ui_trace in ReportMap.add_starvation tenv sev current_pdesc loc ltr error_message report_map | LockAcquire endpoint_lock -> Lock.owner_class endpoint_lock diff --git a/infer/src/concurrency/starvationDomain.ml b/infer/src/concurrency/starvationDomain.ml index 65543ab79..9cb34bc38 100644 --- a/infer/src/concurrency/starvationDomain.ml +++ b/infer/src/concurrency/starvationDomain.ml @@ -216,18 +216,39 @@ module LockState = struct end module UIThreadExplanationDomain = struct - type astate = string + include MakeTraceElem (struct + type t = string [@@deriving compare] + + let pp = String.pp + end) - let pp = String.pp + type astate = t let join lhs _ = lhs let widen ~prev ~next ~num_iters:_ = join prev next let ( <= ) ~lhs:_ ~rhs:_ = true + + let make_trace ?(header = "") pname elem = + let trace = make_loc_trace elem in + let trace_descr = Format.asprintf "%s%a" header (MF.wrap_monospaced Typ.Procname.pp) pname in + let start_loc = get_loc elem in + let header_step = Errlog.make_trace_element 0 start_loc trace_descr [] in + header_step :: trace end -module UIThreadDomain = AbstractDomain.BottomLifted (UIThreadExplanationDomain) +module UIThreadDomain = struct + include AbstractDomain.BottomLifted (UIThreadExplanationDomain) + + let with_callsite astate callsite = + match astate with + | AbstractDomain.Types.Bottom -> + astate + | AbstractDomain.Types.NonBottom ui_explain -> + AbstractDomain.Types.NonBottom + (UIThreadExplanationDomain.with_callsite ui_explain callsite) +end type astate = { lock_state: LockState.astate @@ -305,6 +326,7 @@ let release ({lock_state} as astate) lock = let integrate_summary ({lock_state; events; order; ui} as astate) callee_pname loc callee_summary = let callsite = CallSite.make callee_pname loc in let callee_order = OrderDomain.with_callsite callee_summary.order callsite in + let callee_ui = UIThreadDomain.with_callsite callee_summary.ui callsite in let filtered_order = OrderDomain.filter (fun {elem= {eventually}} -> LockState.is_taken eventually lock_state |> not) @@ -318,11 +340,15 @@ let integrate_summary ({lock_state; events; order; ui} as astate) callee_pname l { astate with events= EventDomain.join events filtered_events ; order= OrderDomain.join order order' - ; ui= UIThreadDomain.join ui callee_summary.ui } + ; ui= UIThreadDomain.join ui callee_ui } -let set_on_ui_thread ({ui} as astate) explain = - {astate with ui= UIThreadDomain.join ui (AbstractDomain.Types.NonBottom explain)} +let set_on_ui_thread ({ui} as astate) loc explain = + let ui = + UIThreadDomain.join ui + (AbstractDomain.Types.NonBottom (UIThreadExplanationDomain.make explain loc)) + in + {astate with ui} type summary = astate diff --git a/infer/src/concurrency/starvationDomain.mli b/infer/src/concurrency/starvationDomain.mli index 01ec2d95d..396be1a85 100644 --- a/infer/src/concurrency/starvationDomain.mli +++ b/infer/src/concurrency/starvationDomain.mli @@ -78,8 +78,15 @@ end module LockState : AbstractDomain.WithBottom +module UIThreadExplanationDomain : sig + include TraceElem with type elem_t = string + + val make_trace : ?header:string -> Typ.Procname.t -> t -> Errlog.loc_trace +end + module UIThreadDomain : - AbstractDomain.WithBottom with type astate = string AbstractDomain.Types.bottom_lifted + AbstractDomain.WithBottom + with type astate = UIThreadExplanationDomain.t AbstractDomain.Types.bottom_lifted type astate = { lock_state: LockState.astate @@ -101,7 +108,7 @@ val blocking_call : -> astate -> astate -val set_on_ui_thread : astate -> string -> astate +val set_on_ui_thread : astate -> Location.t -> 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 *) diff --git a/infer/tests/codetoanalyze/java/starvation/issues.exp b/infer/tests/codetoanalyze/java/starvation/issues.exp index 84a442336..60de11819 100644 --- a/infer/tests/codetoanalyze/java/starvation/issues.exp +++ b/infer/tests/codetoanalyze/java/starvation/issues.exp @@ -1,44 +1,44 @@ -codetoanalyze/java/starvation/AccMgr.java, AccMgr.lockOnUiThreadBad():void, 25, STARVATION, no_bucket, 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, AccMgr.onUiThreadBad():void, 20, STARVATION, no_bucket, ERROR, [`void AccMgr.onUiThreadBad()`,calls `void AccountManager.setUserData(Account,String,String)` from `void AccMgr.onUiThreadBad()`] -codetoanalyze/java/starvation/AsyncTaskGet.java, AsyncTaskGet.lockOnUiThreadBad():void, 31, STARVATION, no_bucket, 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, AsyncTaskGet.taskGetOnUiThreadBad():void, 20, STARVATION, no_bucket, ERROR, [`void AsyncTaskGet.taskGetOnUiThreadBad()`,calls `Object AsyncTask.get()` from `void AsyncTaskGet.taskGetOnUiThreadBad()`] -codetoanalyze/java/starvation/Binders.java, Binders.annotationBad():void, 35, STARVATION, no_bucket, 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, Binders.interBad():void, 24, STARVATION, no_bucket, ERROR, [`void Binders.interBad()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void Binders.interBad()`] -codetoanalyze/java/starvation/Binders.java, Binders.intraBad():void, 30, STARVATION, no_bucket, 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, Countdwn.awaitOnMainByAnnotBad():void, 21, STARVATION, no_bucket, ERROR, [`void Countdwn.awaitOnMainByAnnotBad()`,calls `void CountDownLatch.await()` from `void Countdwn.awaitOnMainByAnnotBad()`] -codetoanalyze/java/starvation/Countdwn.java, Countdwn.awaitOnMainByCallBad():void, 16, STARVATION, no_bucket, ERROR, [`void Countdwn.awaitOnMainByCallBad()`,calls `void CountDownLatch.await()` from `void Countdwn.awaitOnMainByCallBad()`] -codetoanalyze/java/starvation/Dedup.java, Dedup.callMethodWithMultipleBlocksBad():void, 27, STARVATION, no_bucket, ERROR, [`void Dedup.callMethodWithMultipleBlocksBad()`,calls `Object Future.get()` from `void Dedup.callMethodWithMultipleBlocksBad()`] -codetoanalyze/java/starvation/Dedup.java, Dedup.callMethodWithMultipleBlocksBad():void, 28, STARVATION, no_bucket, ERROR, [`void Dedup.callMethodWithMultipleBlocksBad()`,calls `void CountDownLatch.await()` from `void Dedup.callMethodWithMultipleBlocksBad()`] -codetoanalyze/java/starvation/Dedup.java, Dedup.callMethodWithMultipleBlocksBad():void, 29, STARVATION, no_bucket, ERROR, [`void Dedup.callMethodWithMultipleBlocksBad()`,calls `Object Future.get()` from `void Dedup.callMethodWithMultipleBlocksBad()`] -codetoanalyze/java/starvation/Dedup.java, Dedup.onUiThreadBad():void, 21, STARVATION, no_bucket, ERROR, [`void Dedup.onUiThreadBad()`,Method call: `void Dedup.callMethodWithMultipleBlocksBad()`,calls `void CountDownLatch.await()` from `void Dedup.callMethodWithMultipleBlocksBad()`] +codetoanalyze/java/starvation/AccMgr.java, AccMgr.lockOnUiThreadBad():void, 25, STARVATION, no_bucket, 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()`,[Trace 1 on UI thread] `void AccMgr.lockOnUiThreadBad()`,`void AccMgr.lockOnUiThreadBad()` is annotated `UiThread`] +codetoanalyze/java/starvation/AccMgr.java, AccMgr.onUiThreadBad():void, 20, STARVATION, no_bucket, ERROR, [`void AccMgr.onUiThreadBad()`,calls `void AccountManager.setUserData(Account,String,String)` from `void AccMgr.onUiThreadBad()`,[Trace on UI thread] `void AccMgr.onUiThreadBad()`,`void AccMgr.onUiThreadBad()` is annotated `UiThread`] +codetoanalyze/java/starvation/AsyncTaskGet.java, AsyncTaskGet.lockOnUiThreadBad():void, 31, STARVATION, no_bucket, 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()`,[Trace 1 on UI thread] `void AsyncTaskGet.lockOnUiThreadBad()`,`void AsyncTaskGet.lockOnUiThreadBad()` is annotated `UiThread`] +codetoanalyze/java/starvation/AsyncTaskGet.java, AsyncTaskGet.taskGetOnUiThreadBad():void, 20, STARVATION, no_bucket, ERROR, [`void AsyncTaskGet.taskGetOnUiThreadBad()`,calls `Object AsyncTask.get()` from `void AsyncTaskGet.taskGetOnUiThreadBad()`,[Trace on UI thread] `void AsyncTaskGet.taskGetOnUiThreadBad()`,`void AsyncTaskGet.taskGetOnUiThreadBad()` is annotated `UiThread`] +codetoanalyze/java/starvation/Binders.java, Binders.annotationBad():void, 35, STARVATION, no_bucket, ERROR, [`void Binders.annotationBad()`,Method call: `void Binders.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void Binders.doTransact()`,[Trace on UI thread] `void Binders.annotationBad()`,`void Binders.annotationBad()` is annotated `UiThread`] +codetoanalyze/java/starvation/Binders.java, Binders.interBad():void, 24, STARVATION, no_bucket, ERROR, [`void Binders.interBad()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void Binders.interBad()`,[Trace on UI thread] `void Binders.interBad()`,Method call: `void Binders.forceMainThread()`,it calls `void OurThreadUtils.assertMainThread()`] +codetoanalyze/java/starvation/Binders.java, Binders.intraBad():void, 30, STARVATION, no_bucket, ERROR, [`void Binders.intraBad()`,Method call: `void Binders.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void Binders.doTransact()`,[Trace on UI thread] `void Binders.intraBad()`,it calls `void OurThreadUtils.assertMainThread()`] +codetoanalyze/java/starvation/Countdwn.java, Countdwn.awaitOnMainByAnnotBad():void, 21, STARVATION, no_bucket, ERROR, [`void Countdwn.awaitOnMainByAnnotBad()`,calls `void CountDownLatch.await()` from `void Countdwn.awaitOnMainByAnnotBad()`,[Trace on UI thread] `void Countdwn.awaitOnMainByAnnotBad()`,`void Countdwn.awaitOnMainByAnnotBad()` is annotated `UiThread`] +codetoanalyze/java/starvation/Countdwn.java, Countdwn.awaitOnMainByCallBad():void, 16, STARVATION, no_bucket, ERROR, [`void Countdwn.awaitOnMainByCallBad()`,calls `void CountDownLatch.await()` from `void Countdwn.awaitOnMainByCallBad()`,[Trace on UI thread] `void Countdwn.awaitOnMainByCallBad()`,it calls `void OurThreadUtils.assertMainThread()`] +codetoanalyze/java/starvation/Dedup.java, Dedup.callMethodWithMultipleBlocksBad():void, 27, STARVATION, no_bucket, ERROR, [`void Dedup.callMethodWithMultipleBlocksBad()`,calls `Object Future.get()` from `void Dedup.callMethodWithMultipleBlocksBad()`,[Trace on UI thread] `void Dedup.callMethodWithMultipleBlocksBad()`,`void Dedup.callMethodWithMultipleBlocksBad()` is annotated `UiThread`] +codetoanalyze/java/starvation/Dedup.java, Dedup.callMethodWithMultipleBlocksBad():void, 28, STARVATION, no_bucket, ERROR, [`void Dedup.callMethodWithMultipleBlocksBad()`,calls `void CountDownLatch.await()` from `void Dedup.callMethodWithMultipleBlocksBad()`,[Trace on UI thread] `void Dedup.callMethodWithMultipleBlocksBad()`,`void Dedup.callMethodWithMultipleBlocksBad()` is annotated `UiThread`] +codetoanalyze/java/starvation/Dedup.java, Dedup.callMethodWithMultipleBlocksBad():void, 29, STARVATION, no_bucket, ERROR, [`void Dedup.callMethodWithMultipleBlocksBad()`,calls `Object Future.get()` from `void Dedup.callMethodWithMultipleBlocksBad()`,[Trace on UI thread] `void Dedup.callMethodWithMultipleBlocksBad()`,`void Dedup.callMethodWithMultipleBlocksBad()` is annotated `UiThread`] +codetoanalyze/java/starvation/Dedup.java, Dedup.onUiThreadBad():void, 21, STARVATION, no_bucket, ERROR, [`void Dedup.onUiThreadBad()`,Method call: `void Dedup.callMethodWithMultipleBlocksBad()`,calls `void CountDownLatch.await()` from `void Dedup.callMethodWithMultipleBlocksBad()`,[Trace on UI thread] `void Dedup.onUiThreadBad()`,`void Dedup.onUiThreadBad()` is annotated `UiThread`] codetoanalyze/java/starvation/Dedup.java, Dedup.oneWayBad():void, 36, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void Dedup.oneWayBad()`,locks `this.Dedup.lockA` in class `Dedup*`,locks `this.Dedup.lockB` in class `Dedup*`,[Trace 2] `void Dedup.anotherWayBad()`,locks `this.Dedup.lockB` in class `Dedup*`,locks `this.Dedup.lockA` in class `Dedup*`] -codetoanalyze/java/starvation/FutureGet.java, FutureGet.getDirectBad():void, 21, STARVATION, no_bucket, ERROR, [`void FutureGet.getDirectBad()`,calls `Object Future.get()` from `void FutureGet.getDirectBad()`] -codetoanalyze/java/starvation/FutureGet.java, FutureGet.getIndirectBad():void, 26, STARVATION, no_bucket, 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, FutureGet.getTimeout50000001MicroSecondsBad():void, 77, STARVATION, no_bucket, ERROR, [`void FutureGet.getTimeout50000001MicroSecondsBad()`,calls `Object Future.get(long,TimeUnit)` from `void FutureGet.getTimeout50000001MicroSecondsBad()`] -codetoanalyze/java/starvation/FutureGet.java, FutureGet.getTimeout64BitsBad():void, 84, STARVATION, no_bucket, ERROR, [`void FutureGet.getTimeout64BitsBad()`,calls `Object Future.get(long,TimeUnit)` from `void FutureGet.getTimeout64BitsBad()`] -codetoanalyze/java/starvation/FutureGet.java, FutureGet.getTimeoutOneDayBad():void, 42, STARVATION, no_bucket, ERROR, [`void FutureGet.getTimeoutOneDayBad()`,calls `Object Future.get(long,TimeUnit)` from `void FutureGet.getTimeoutOneDayBad()`] -codetoanalyze/java/starvation/FutureGet.java, FutureGet.getTimeoutOneHourBad():void, 56, STARVATION, no_bucket, ERROR, [`void FutureGet.getTimeoutOneHourBad()`,calls `Object Future.get(long,TimeUnit)` from `void FutureGet.getTimeoutOneHourBad()`] -codetoanalyze/java/starvation/IndirectBlock.java, IndirectBlock.takeExpensiveLockOnUiThreadBad():void, 22, STARVATION, no_bucket, 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, IndirectBlock.takeRemoteExpensiveLockOnUiThreadBad(IndirectInterproc):void, 33, STARVATION, no_bucket, 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/FutureGet.java, FutureGet.getDirectBad():void, 21, STARVATION, no_bucket, ERROR, [`void FutureGet.getDirectBad()`,calls `Object Future.get()` from `void FutureGet.getDirectBad()`,[Trace on UI thread] `void FutureGet.getDirectBad()`,`void FutureGet.getDirectBad()` is annotated `UiThread`] +codetoanalyze/java/starvation/FutureGet.java, FutureGet.getIndirectBad():void, 26, STARVATION, no_bucket, 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()`,[Trace 1 on UI thread] `void FutureGet.getIndirectBad()`,`void FutureGet.getIndirectBad()` is annotated `UiThread`] +codetoanalyze/java/starvation/FutureGet.java, FutureGet.getTimeout50000001MicroSecondsBad():void, 77, STARVATION, no_bucket, ERROR, [`void FutureGet.getTimeout50000001MicroSecondsBad()`,calls `Object Future.get(long,TimeUnit)` from `void FutureGet.getTimeout50000001MicroSecondsBad()`,[Trace on UI thread] `void FutureGet.getTimeout50000001MicroSecondsBad()`,`void FutureGet.getTimeout50000001MicroSecondsBad()` is annotated `UiThread`] +codetoanalyze/java/starvation/FutureGet.java, FutureGet.getTimeout64BitsBad():void, 84, STARVATION, no_bucket, ERROR, [`void FutureGet.getTimeout64BitsBad()`,calls `Object Future.get(long,TimeUnit)` from `void FutureGet.getTimeout64BitsBad()`,[Trace on UI thread] `void FutureGet.getTimeout64BitsBad()`,`void FutureGet.getTimeout64BitsBad()` is annotated `UiThread`] +codetoanalyze/java/starvation/FutureGet.java, FutureGet.getTimeoutOneDayBad():void, 42, STARVATION, no_bucket, ERROR, [`void FutureGet.getTimeoutOneDayBad()`,calls `Object Future.get(long,TimeUnit)` from `void FutureGet.getTimeoutOneDayBad()`,[Trace on UI thread] `void FutureGet.getTimeoutOneDayBad()`,`void FutureGet.getTimeoutOneDayBad()` is annotated `UiThread`] +codetoanalyze/java/starvation/FutureGet.java, FutureGet.getTimeoutOneHourBad():void, 56, STARVATION, no_bucket, ERROR, [`void FutureGet.getTimeoutOneHourBad()`,calls `Object Future.get(long,TimeUnit)` from `void FutureGet.getTimeoutOneHourBad()`,[Trace on UI thread] `void FutureGet.getTimeoutOneHourBad()`,`void FutureGet.getTimeoutOneHourBad()` is annotated `UiThread`] +codetoanalyze/java/starvation/IndirectBlock.java, IndirectBlock.takeExpensiveLockOnUiThreadBad():void, 22, STARVATION, no_bucket, 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()`,[Trace 1 on UI thread] `void IndirectBlock.takeExpensiveLockOnUiThreadBad()`,`void IndirectBlock.takeExpensiveLockOnUiThreadBad()` is annotated `UiThread`] +codetoanalyze/java/starvation/IndirectBlock.java, IndirectBlock.takeRemoteExpensiveLockOnUiThreadBad(IndirectInterproc):void, 33, STARVATION, no_bucket, 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)`,[Trace 1 on UI thread] `void IndirectBlock.takeRemoteExpensiveLockOnUiThreadBad(IndirectInterproc)`,`void IndirectBlock.takeRemoteExpensiveLockOnUiThreadBad(IndirectInterproc)` is annotated `UiThread`] codetoanalyze/java/starvation/InnerClass.java, InnerClass$InnerClassA.(InnerClass,java.lang.Object), 48, DEADLOCK, no_bucket, 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, InnerClass$InnerClassA.innerOuterBad():void, 34, DEADLOCK, no_bucket, 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, Interclass.interclass1Bad(InterclassA):void, 10, DEADLOCK, no_bucket, 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, Interproc.interproc1Bad(InterprocA):void, 9, DEADLOCK, no_bucket, 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, Intraproc.intraBad(IntraprocA):void, 10, DEADLOCK, no_bucket, 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/LegacySync.java, LegacySync.onUiThreadOpBad():java.lang.Object, 25, STARVATION, no_bucket, 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/LegacySync.java, LegacySync.onUiThreadOpBad():java.lang.Object, 25, STARVATION, no_bucket, 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()`,[Trace 1 on UI thread] `Object LegacySync.onUiThreadOpBad()`,`Object LegacySync.onUiThreadOpBad()` is annotated `UiThread`] codetoanalyze/java/starvation/NonBlk.java, NonBlk.deadlockABBad():void, 34, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void NonBlk.deadlockABBad()`,locks `this` in class `NonBlk*`,locks `this.NonBlk.future` in class `NonBlk*`,[Trace 2] `void NonBlk.deadlockBABad()`,locks `this.NonBlk.future` in class `NonBlk*`,locks `this` in class `NonBlk*`] -codetoanalyze/java/starvation/ObjWait.java, ObjWait.indirectWaitOnMainWithoutTimeoutBad():void, 46, STARVATION, no_bucket, ERROR, [[Trace 1] `void ObjWait.indirectWaitOnMainWithoutTimeoutBad()`,locks `this.ObjWait.lock` in class `ObjWait*`,[Trace 2] `void ObjWait.lockAndWaitOnAnyWithoutTimeoutBad()`,locks `this.ObjWait.lock` in class `ObjWait*`,calls `void Object.wait()` from `void ObjWait.lockAndWaitOnAnyWithoutTimeoutBad()`] -codetoanalyze/java/starvation/ObjWait.java, ObjWait.waitOnMainWithExcessiveTimeout1Bad():void, 31, STARVATION, no_bucket, ERROR, [`void ObjWait.waitOnMainWithExcessiveTimeout1Bad()`,calls `void Object.wait(long)` from `void ObjWait.waitOnMainWithExcessiveTimeout1Bad()`] -codetoanalyze/java/starvation/ObjWait.java, ObjWait.waitOnMainWithExcessiveTimeout2Bad():void, 38, STARVATION, no_bucket, ERROR, [`void ObjWait.waitOnMainWithExcessiveTimeout2Bad()`,calls `void Object.wait(long,int)` from `void ObjWait.waitOnMainWithExcessiveTimeout2Bad()`] -codetoanalyze/java/starvation/ObjWait.java, ObjWait.waitOnMainWithoutTimeoutBad():void, 24, STARVATION, no_bucket, ERROR, [`void ObjWait.waitOnMainWithoutTimeoutBad()`,calls `void Object.wait()` from `void ObjWait.waitOnMainWithoutTimeoutBad()`] -codetoanalyze/java/starvation/PubPriv.java, PubPriv.alsoBad():void, 25, STARVATION, no_bucket, ERROR, [`void PubPriv.alsoBad()`,Method call: `void PubPriv.transactBad()`,Method call: `void PubPriv.doTransactOk()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void PubPriv.doTransactOk()`] +codetoanalyze/java/starvation/ObjWait.java, ObjWait.indirectWaitOnMainWithoutTimeoutBad():void, 46, STARVATION, no_bucket, ERROR, [[Trace 1] `void ObjWait.indirectWaitOnMainWithoutTimeoutBad()`,locks `this.ObjWait.lock` in class `ObjWait*`,[Trace 2] `void ObjWait.lockAndWaitOnAnyWithoutTimeoutBad()`,locks `this.ObjWait.lock` in class `ObjWait*`,calls `void Object.wait()` from `void ObjWait.lockAndWaitOnAnyWithoutTimeoutBad()`,[Trace 1 on UI thread] `void ObjWait.indirectWaitOnMainWithoutTimeoutBad()`,`void ObjWait.indirectWaitOnMainWithoutTimeoutBad()` is annotated `UiThread`] +codetoanalyze/java/starvation/ObjWait.java, ObjWait.waitOnMainWithExcessiveTimeout1Bad():void, 31, STARVATION, no_bucket, ERROR, [`void ObjWait.waitOnMainWithExcessiveTimeout1Bad()`,calls `void Object.wait(long)` from `void ObjWait.waitOnMainWithExcessiveTimeout1Bad()`,[Trace on UI thread] `void ObjWait.waitOnMainWithExcessiveTimeout1Bad()`,`void ObjWait.waitOnMainWithExcessiveTimeout1Bad()` is annotated `UiThread`] +codetoanalyze/java/starvation/ObjWait.java, ObjWait.waitOnMainWithExcessiveTimeout2Bad():void, 38, STARVATION, no_bucket, ERROR, [`void ObjWait.waitOnMainWithExcessiveTimeout2Bad()`,calls `void Object.wait(long,int)` from `void ObjWait.waitOnMainWithExcessiveTimeout2Bad()`,[Trace on UI thread] `void ObjWait.waitOnMainWithExcessiveTimeout2Bad()`,`void ObjWait.waitOnMainWithExcessiveTimeout2Bad()` is annotated `UiThread`] +codetoanalyze/java/starvation/ObjWait.java, ObjWait.waitOnMainWithoutTimeoutBad():void, 24, STARVATION, no_bucket, ERROR, [`void ObjWait.waitOnMainWithoutTimeoutBad()`,calls `void Object.wait()` from `void ObjWait.waitOnMainWithoutTimeoutBad()`,[Trace on UI thread] `void ObjWait.waitOnMainWithoutTimeoutBad()`,`void ObjWait.waitOnMainWithoutTimeoutBad()` is annotated `UiThread`] +codetoanalyze/java/starvation/PubPriv.java, PubPriv.alsoBad():void, 25, STARVATION, no_bucket, ERROR, [`void PubPriv.alsoBad()`,Method call: `void PubPriv.transactBad()`,Method call: `void PubPriv.doTransactOk()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void PubPriv.doTransactOk()`,[Trace on UI thread] `void PubPriv.alsoBad()`,Method call: `void PubPriv.transactBad()`,Method call: `void PubPriv.doTransactOk()`,`void PubPriv.doTransactOk()` is annotated `UiThread`] codetoanalyze/java/starvation/PubPriv.java, PubPriv.callOneWayBad():void, 47, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void PubPriv.callOneWayBad()`,Method call: `void PubPriv.oneWayOk()`,locks `this.PubPriv.lockA` in class `PubPriv*`,locks `this.PubPriv.lockB` in class `PubPriv*`,[Trace 2] `void PubPriv.callAnotherWayBad()`,Method call: `void PubPriv.anotherWayOk()`,locks `this.PubPriv.lockB` in class `PubPriv*`,locks `this.PubPriv.lockA` in class `PubPriv*`] -codetoanalyze/java/starvation/PubPriv.java, PubPriv.transactBad():void, 21, STARVATION, no_bucket, ERROR, [`void PubPriv.transactBad()`,Method call: `void PubPriv.doTransactOk()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void PubPriv.doTransactOk()`] -codetoanalyze/java/starvation/ServiceOnUIThread.java, ServiceOnUIThread.onBind(android.content.Intent):android.os.IBinder, 19, STARVATION, no_bucket, 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, ServiceOnUIThread.transactBad():void, 25, STARVATION, no_bucket, ERROR, [`void ServiceOnUIThread.transactBad()`,calls `boolean IBinder.transact(int,Parcel,Parcel,int)` from `void ServiceOnUIThread.transactBad()`] +codetoanalyze/java/starvation/PubPriv.java, PubPriv.transactBad():void, 21, STARVATION, no_bucket, ERROR, [`void PubPriv.transactBad()`,Method call: `void PubPriv.doTransactOk()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void PubPriv.doTransactOk()`,[Trace on UI thread] `void PubPriv.transactBad()`,Method call: `void PubPriv.doTransactOk()`,`void PubPriv.doTransactOk()` is annotated `UiThread`] +codetoanalyze/java/starvation/ServiceOnUIThread.java, ServiceOnUIThread.onBind(android.content.Intent):android.os.IBinder, 19, STARVATION, no_bucket, ERROR, [`IBinder ServiceOnUIThread.onBind(Intent)`,Method call: `void ServiceOnUIThread.transactBad()`,calls `boolean IBinder.transact(int,Parcel,Parcel,int)` from `void ServiceOnUIThread.transactBad()`,[Trace on UI thread] `IBinder ServiceOnUIThread.onBind(Intent)`,class `ServiceOnUIThread` extends `android.app.Service`] +codetoanalyze/java/starvation/ServiceOnUIThread.java, ServiceOnUIThread.transactBad():void, 25, STARVATION, no_bucket, ERROR, [`void ServiceOnUIThread.transactBad()`,calls `boolean IBinder.transact(int,Parcel,Parcel,int)` from `void ServiceOnUIThread.transactBad()`,[Trace on UI thread] `void ServiceOnUIThread.transactBad()`,class `ServiceOnUIThread` extends `android.app.Service`] codetoanalyze/java/starvation/StaticLock.java, StaticLock.lockOtherClassOneWayBad():void, 23, DEADLOCK, no_bucket, 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/SuppLint.java, SuppLint.onUiThreadBad():void, 26, STARVATION, no_bucket, ERROR, [`void SuppLint.onUiThreadBad()`,calls `Object Future.get()` from `void SuppLint.onUiThreadBad()`] -codetoanalyze/java/starvation/ThreadSleep.java, ThreadSleep.indirectSleepOnUIThreadBad():void, 25, STARVATION, no_bucket, ERROR, [[Trace 1] `void ThreadSleep.indirectSleepOnUIThreadBad()`,locks `this.ThreadSleep.lock` in class `ThreadSleep*`,[Trace 2] `void ThreadSleep.lockAndSleepOnNonUIThread()`,locks `this.ThreadSleep.lock` in class `ThreadSleep*`,Method call: `void ThreadSleep.sleepOnAnyThreadOk()`,calls `void Thread.sleep(long)` from `void ThreadSleep.sleepOnAnyThreadOk()`] -codetoanalyze/java/starvation/ThreadSleep.java, ThreadSleep.sleepOnUIThreadBad():void, 18, STARVATION, no_bucket, ERROR, [`void ThreadSleep.sleepOnUIThreadBad()`,calls `void Thread.sleep(long)` from `void ThreadSleep.sleepOnUIThreadBad()`] +codetoanalyze/java/starvation/SuppLint.java, SuppLint.onUiThreadBad():void, 26, STARVATION, no_bucket, ERROR, [`void SuppLint.onUiThreadBad()`,calls `Object Future.get()` from `void SuppLint.onUiThreadBad()`,[Trace on UI thread] `void SuppLint.onUiThreadBad()`,`void SuppLint.onUiThreadBad()` is annotated `UiThread`] +codetoanalyze/java/starvation/ThreadSleep.java, ThreadSleep.indirectSleepOnUIThreadBad():void, 25, STARVATION, no_bucket, ERROR, [[Trace 1] `void ThreadSleep.indirectSleepOnUIThreadBad()`,locks `this.ThreadSleep.lock` in class `ThreadSleep*`,[Trace 2] `void ThreadSleep.lockAndSleepOnNonUIThread()`,locks `this.ThreadSleep.lock` in class `ThreadSleep*`,Method call: `void ThreadSleep.sleepOnAnyThreadOk()`,calls `void Thread.sleep(long)` from `void ThreadSleep.sleepOnAnyThreadOk()`,[Trace 1 on UI thread] `void ThreadSleep.indirectSleepOnUIThreadBad()`,`void ThreadSleep.indirectSleepOnUIThreadBad()` is annotated `UiThread`] +codetoanalyze/java/starvation/ThreadSleep.java, ThreadSleep.sleepOnUIThreadBad():void, 18, STARVATION, no_bucket, ERROR, [`void ThreadSleep.sleepOnUIThreadBad()`,calls `void Thread.sleep(long)` from `void ThreadSleep.sleepOnUIThreadBad()`,[Trace on UI thread] `void ThreadSleep.sleepOnUIThreadBad()`,`void ThreadSleep.sleepOnUIThreadBad()` is annotated `UiThread`] codetoanalyze/java/starvation/UIDeadlock.java, UIDeadlock.onUIThreadBad():void, 26, DEADLOCK, no_bucket, 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/Workers.java, Workers.uiThreadBad():void, 28, STARVATION, no_bucket, ERROR, [`void Workers.uiThreadBad()`,Method call: `void Workers.workerOk()`,Method call: `void Workers.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void Workers.doTransact()`] +codetoanalyze/java/starvation/Workers.java, Workers.uiThreadBad():void, 28, STARVATION, no_bucket, ERROR, [`void Workers.uiThreadBad()`,Method call: `void Workers.workerOk()`,Method call: `void Workers.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void Workers.doTransact()`,[Trace on UI thread] `void Workers.uiThreadBad()`,`void Workers.uiThreadBad()` is annotated `UiThread`]