[concurrency] treat @MainThread annotation

Summary: Treat MainThread annotation as equivalent to UiThread

Reviewed By: jeremydubreil

Differential Revision: D9995018

fbshipit-source-id: 3e4ff0993
master
Nikos Gorogiannis 7 years ago committed by Facebook Github Bot
parent a2adde8948
commit 0c7a8556dc

@ -67,6 +67,8 @@ let on_unbind = "OnUnbind"
let on_unmount = "OnUnmount"
let mainthread = "MainThread"
let nonblocking = "NonBlocking"
let notnull = "NotNull"
@ -243,6 +245,8 @@ let ia_is_on_unmount ia = ia_ends_with ia on_unmount
let ia_is_ui_thread ia = ia_ends_with ia ui_thread
let ia_is_mainthread ia = ia_ends_with ia mainthread
let ia_is_thread_confined ia = ia_ends_with ia thread_confined
let ia_is_worker_thread ia = ia_ends_with ia worker_thread

@ -102,6 +102,8 @@ val ia_is_on_unbind : Annot.Item.t -> bool
val ia_is_on_unmount : Annot.Item.t -> bool
val ia_is_mainthread : Annot.Item.t -> bool
val ia_is_not_thread_safe : Annot.Item.t -> bool
val ia_is_nonblocking : Annot.Item.t -> bool

@ -285,17 +285,22 @@ let is_ui_method =
fun tenv pname -> List.exists matchers ~f:(fun m -> m tenv pname [])
let runs_on_ui_thread tenv proc_desc =
let runs_on_ui_thread =
(* assume that methods annotated with @UiThread, @OnEvent, @OnBind, @OnMount, @OnUnbind,
@OnUnmount always run on the UI thread *)
let is_annot annot =
Annotations.ia_is_ui_thread annot || Annotations.ia_is_on_bind annot
|| Annotations.ia_is_on_event annot || Annotations.ia_is_on_mount annot
|| Annotations.ia_is_on_unbind annot
|| Annotations.ia_is_on_unmount annot
let annotation_matchers =
[ Annotations.ia_is_mainthread
; Annotations.ia_is_ui_thread
; Annotations.ia_is_on_bind
; Annotations.ia_is_on_event
; Annotations.ia_is_on_mount
; Annotations.ia_is_on_unbind
; Annotations.ia_is_on_unmount ]
in
let pname = Procdesc.get_proc_name proc_desc in
let is_annot annot = List.exists annotation_matchers ~f:(fun m -> m annot) in
let mono_pname = MF.wrap_monospaced Typ.Procname.pp in
fun tenv proc_desc ->
let pname = Procdesc.get_proc_name proc_desc in
if
Annotations.pdesc_has_return_annot proc_desc Annotations.ia_is_worker_thread
|| find_annotated_or_overriden_annotated_method Annotations.ia_is_worker_thread pname tenv
@ -317,9 +322,7 @@ let runs_on_ui_thread tenv proc_desc =
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
match get_current_class_and_annotated_superclasses is_annot tenv pname with
| Some (current_class, (super_class :: _ as super_classes)) ->
let middle =
if List.exists super_classes ~f:(Typ.Name.equal current_class) then ""

@ -0,0 +1,32 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import android.os.Binder;
import android.os.RemoteException;
import android.support.annotation.MainThread;
class MainThreadTest {
Binder b;
void doTransact() {
try {
b.transact(0, null, null, 0);
} catch (Exception e) {}
}
@MainThread
void callTransactBad() {
doTransact();
}
}
@MainThread
class AnnotatedClass {
void callTransactBad(MainThreadTest m) {
m.doTransact();
}
}

@ -26,6 +26,8 @@ codetoanalyze/java/starvation/Interclass.java, Interclass.interclass1Bad(Intercl
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()`,[Trace 1 on UI thread] `Object LegacySync.onUiThreadOpBad()`,`Object LegacySync.onUiThreadOpBad()` is annotated `UiThread`]
codetoanalyze/java/starvation/MainThreadTest.java, AnnotatedClass.callTransactBad(MainThreadTest):void, 30, STARVATION, no_bucket, ERROR, [`void AnnotatedClass.callTransactBad(MainThreadTest)`,Method call: `void MainThreadTest.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void MainThreadTest.doTransact()`,[Trace on UI thread] `void AnnotatedClass.callTransactBad(MainThreadTest)`,class `AnnotatedClass` is annotated `UiThread`]
codetoanalyze/java/starvation/MainThreadTest.java, MainThreadTest.callTransactBad():void, 23, STARVATION, no_bucket, ERROR, [`void MainThreadTest.callTransactBad()`,Method call: `void MainThreadTest.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void MainThreadTest.doTransact()`,[Trace on UI thread] `void MainThreadTest.callTransactBad()`,`void MainThreadTest.callTransactBad()` is annotated `UiThread`]
codetoanalyze/java/starvation/MyActivity.java, MyActivity.onCreate(android.os.Bundle):void, 23, STARVATION, no_bucket, ERROR, [`void MyActivity.onCreate(Bundle)`,Method call: `void MyActivity.bad()`,calls `void AccountManager.setUserData(Account,String,String)` from `void MyActivity.bad()`,[Trace on UI thread] `void MyActivity.onCreate(Bundle)`,`void MyActivity.onCreate(Bundle)` is a standard UI-thread method]
codetoanalyze/java/starvation/MyActivity.java, MyActivity.onDestroy():void, 53, STARVATION, no_bucket, ERROR, [`void MyActivity.onDestroy()`,Method call: `void MyActivity.bad()`,calls `void AccountManager.setUserData(Account,String,String)` from `void MyActivity.bad()`,[Trace on UI thread] `void MyActivity.onDestroy()`,`void MyActivity.onDestroy()` is a standard UI-thread method]
codetoanalyze/java/starvation/MyActivity.java, MyActivity.onPause():void, 43, STARVATION, no_bucket, ERROR, [`void MyActivity.onPause()`,Method call: `void MyActivity.bad()`,calls `void AccountManager.setUserData(Account,String,String)` from `void MyActivity.bad()`,[Trace on UI thread] `void MyActivity.onPause()`,`void MyActivity.onPause()` is a standard UI-thread method]

Loading…
Cancel
Save