การเข้าถึงข้อมูลในการตรวจสอบ

คุณจะได้รับข้อมูลเชิงลึกเกี่ยวกับวิธีที่แอปและทรัพยากร Dependencies เข้าถึงข้อมูลส่วนตัวจากผู้ใช้โดยทำการตรวจสอบการเข้าถึงข้อมูล กระบวนการนี้พร้อมใช้งานในอุปกรณ์ที่ใช้ Android 11 (API ระดับ 30) ขึ้นไป ซึ่งจะช่วยให้คุณระบุการเข้าถึงข้อมูลที่ไม่คาดคิดได้ดีขึ้น แอปสามารถลงทะเบียนอินสแตนซ์ของ AppOpsManager.OnOpNotedCallback ซึ่งจะดําเนินการทุกครั้งที่มีเหตุการณ์อย่างใดอย่างหนึ่งต่อไปนี้เกิดขึ้น

ระบบจะเรียกใช้การตรวจสอบการเข้าถึงข้อมูลในเธรดที่มีคำขอข้อมูล ซึ่งหมายความว่าหาก SDK หรือไลบรารีของบุคคลที่สามในแอปเรียก API ที่เข้าถึงข้อมูลส่วนตัว การตรวจสอบการเข้าถึงข้อมูลจะช่วยให้ OnOpNotedCallback ตรวจสอบข้อมูลเกี่ยวกับการเรียกใช้ได้ โดยปกติแล้ว ออบเจ็กต์การเรียกคืนนี้จะบอกได้ว่าการเรียกมาจากแอปหรือ SDK โดยการดูสถานะปัจจุบันของแอป เช่น สแต็กเทรซของเธรดปัจจุบัน

บันทึกการเข้าถึงข้อมูล

หากต้องการตรวจสอบการเข้าถึงข้อมูลโดยใช้อินสแตนซ์ของ AppOpsManager.OnOpNotedCallback ให้ใช้ตรรกะการเรียกกลับในคอมโพเนนต์ที่คุณต้องการตรวจสอบการเข้าถึงข้อมูล เช่น ภายในเมธอด onCreate() ของกิจกรรมหรือเมธอด onCreate() ของแอปพลิเคชัน

ข้อมูลโค้ดต่อไปนี้จะกําหนด AppOpsManager.OnOpNotedCallback สําหรับการตรวจสอบการเข้าถึงข้อมูลภายในกิจกรรมเดียว

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    val appOpsCallback = object : AppOpsManager.OnOpNotedCallback() {
        private fun logPrivateDataAccess(opCode: String, trace: String) {
            Log.i(MY_APP_TAG, "Private data accessed. " +
                    "Operation: $opCode\nStack Trace:\n$trace")
        }

        override fun onNoted(syncNotedAppOp: SyncNotedAppOp) {
            logPrivateDataAccess(
                    syncNotedAppOp.op, Throwable().stackTrace.toString())
        }

        override fun onSelfNoted(syncNotedAppOp: SyncNotedAppOp) {
            logPrivateDataAccess(
                    syncNotedAppOp.op, Throwable().stackTrace.toString())
        }

        override fun onAsyncNoted(asyncNotedAppOp: AsyncNotedAppOp) {
            logPrivateDataAccess(asyncNotedAppOp.op, asyncNotedAppOp.message)
        }
    }

    val appOpsManager =
            getSystemService(AppOpsManager::class.java) as AppOpsManager
    appOpsManager.setOnOpNotedCallback(mainExecutor, appOpsCallback)
}

Java

@Override
public void onCreate(@Nullable Bundle savedInstanceState,
        @Nullable PersistableBundle persistentState) {
    AppOpsManager.OnOpNotedCallback appOpsCallback =
            new AppOpsManager.OnOpNotedCallback() {
        private void logPrivateDataAccess(String opCode, String trace) {
            Log.i(MY_APP_TAG, "Private data accessed. " +
                    "Operation: $opCode\nStack Trace:\n$trace");
        }

        @Override
        public void onNoted(@NonNull SyncNotedAppOp syncNotedAppOp) {
            logPrivateDataAccess(syncNotedAppOp.getOp(),
                    Arrays.toString(new Throwable().getStackTrace()));
        }

        @Override
        public void onSelfNoted(@NonNull SyncNotedAppOp syncNotedAppOp) {
            logPrivateDataAccess(syncNotedAppOp.getOp(),
                    Arrays.toString(new Throwable().getStackTrace()));
        }

        @Override
        public void onAsyncNoted(@NonNull AsyncNotedAppOp asyncNotedAppOp) {
            logPrivateDataAccess(asyncNotedAppOp.getOp(),
                    asyncNotedAppOp.getMessage());
        }
    };

    AppOpsManager appOpsManager = getSystemService(AppOpsManager.class);
    if (appOpsManager != null) {
        appOpsManager.setOnOpNotedCallback(getMainExecutor(), appOpsCallback);
    }
}

ระบบจะเรียกใช้เมธอด onAsyncNoted() และ onSelfNoted() ในสถานการณ์ต่อไปนี้

  • onAsyncNoted() จะเรียกใช้หากการเข้าถึงข้อมูลไม่เกิดขึ้นระหว่างการเรียก API ของแอป ตัวอย่างที่พบบ่อยที่สุดคือเมื่อแอปลงทะเบียน Listener และมีการเข้าถึงข้อมูลทุกครั้งที่มีการเรียกใช้การเรียกกลับของ Listener

    อาร์กิวเมนต์ AsyncNotedOp ที่ส่งไปยัง onAsyncNoted() มีเมธอดชื่อ getMessage() วิธีนี้จะให้ข้อมูลเพิ่มเติมเกี่ยวกับการเข้าถึงข้อมูล ในกรณีของคอลแบ็กตำแหน่ง ข้อความจะมีแฮชข้อมูลประจำตัวของระบบของผู้ฟัง

  • onSelfNoted() จะเรียกใช้ในบางกรณีที่พบได้น้อยมากเมื่อแอปส่ง UID ของตัวเองไปยังnoteOp()

ตรวจสอบการเข้าถึงข้อมูลตามแท็กการระบุแหล่งที่มา

แอปของคุณอาจมีกรณีการใช้งานหลักหลายกรณี เช่น อนุญาตให้ผู้ใช้ถ่ายภาพและแชร์รูปภาพเหล่านี้กับรายชื่อติดต่อ หากพัฒนาแอปอเนกประสงค์ คุณสามารถใช้แท็กการระบุแหล่งที่มากับแต่ละส่วนของแอปเมื่อตรวจสอบการเข้าถึงข้อมูลของแอป ระบบจะแสดงผลบริบท attributionTag กลับในออบเจ็กต์ที่ส่งไปยังการเรียก onNoted() ซึ่งจะช่วยให้คุณติดตามการเข้าถึงข้อมูลกลับไปยังส่วนตรรกะของโค้ดได้ง่ายขึ้น

หากต้องการกําหนดแท็กการระบุแหล่งที่มาในแอป ให้ทําตามขั้นตอนในส่วนต่อไปนี้

ประกาศแท็กการระบุแหล่งที่มาในไฟล์ Manifest

หากแอปกำหนดเป้าหมายเป็น Android 12 (API ระดับ 31) ขึ้นไป คุณต้องประกาศแท็กการระบุแหล่งที่มาในไฟล์ Manifest ของแอปโดยใช้รูปแบบที่แสดงในตัวอย่างโค้ดต่อไปนี้ หากคุณพยายามใช้แท็กการระบุแหล่งที่มาที่ไม่ได้ประกาศไว้ในไฟล์ Manifest ของแอป ระบบจะสร้างแท็ก null ให้คุณและบันทึกข้อความใน Logcat

<manifest ...>
    <!-- The value of "android:tag" must be a literal string, and the
         value of "android:label" must be a resource. The value of
         "android:label" is user-readable. -->
    <attribution android:tag="sharePhotos"
                 android:label="@string/share_photos_attribution_label" />
    ...
</manifest>

สร้างแท็กการระบุแหล่งที่มา

ในวิธี onCreate() ของกิจกรรมที่คุณเข้าถึงข้อมูล เช่น กิจกรรมที่คุณขอตำแหน่งหรือเข้าถึงรายชื่อติดต่อของผู้ใช้ ให้เรียกใช้ createAttributionContext() โดยส่งแท็กการระบุแหล่งที่มาที่ต้องการเชื่อมโยงกับส่วนหนึ่งของแอป

ข้อมูลโค้ดต่อไปนี้แสดงวิธีสร้างแท็กการระบุแหล่งที่มาสําหรับส่วนการแชร์รูปภาพและตําแหน่งของแอป

Kotlin

class SharePhotoLocationActivity : AppCompatActivity() {
    lateinit var attributionContext: Context

    override fun onCreate(savedInstanceState: Bundle?) {
        attributionContext = createAttributionContext("sharePhotos")
    }

    fun getLocation() {
        val locationManager = attributionContext.getSystemService(
                LocationManager::class.java) as LocationManager
        // Use "locationManager" to access device location information.
    }
}

Java

public class SharePhotoLocationActivity extends AppCompatActivity {
    private Context attributionContext;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState,
            @Nullable PersistableBundle persistentState) {
        attributionContext = createAttributionContext("sharePhotos");
    }

    public void getLocation() {
        LocationManager locationManager =
                attributionContext.getSystemService(LocationManager.class);
        if (locationManager != null) {
            // Use "locationManager" to access device location information.
        }
    }
}

รวมแท็กการระบุแหล่งที่มาในบันทึกการเข้าถึง

อัปเดตการเรียกกลับ AppOpsManager.OnOpNotedCallback เพื่อให้บันทึกของแอปมีชื่อแท็กการระบุแหล่งที่มาที่คุณกำหนดไว้

ข้อมูลโค้ดต่อไปนี้แสดงตรรกะที่อัปเดตแล้วซึ่งบันทึกแท็กการระบุแหล่งที่มา

Kotlin

val appOpsCallback = object : AppOpsManager.OnOpNotedCallback() {
    private fun logPrivateDataAccess(
            opCode: String, attributionTag: String, trace: String) {
        Log.i(MY_APP_TAG, "Private data accessed. " +
                    "Operation: $opCode\n " +
                    "Attribution Tag:$attributionTag\nStack Trace:\n$trace")
    }

    override fun onNoted(syncNotedAppOp: SyncNotedAppOp) {
        logPrivateDataAccess(syncNotedAppOp.op,
                syncNotedAppOp.attributionTag,
                Throwable().stackTrace.toString())
    }

    override fun onSelfNoted(syncNotedAppOp: SyncNotedAppOp) {
        logPrivateDataAccess(syncNotedAppOp.op,
                syncNotedAppOp.attributionTag,
                Throwable().stackTrace.toString())
    }

    override fun onAsyncNoted(asyncNotedAppOp: AsyncNotedAppOp) {
        logPrivateDataAccess(asyncNotedAppOp.op,
                asyncNotedAppOp.attributionTag,
                asyncNotedAppOp.message)
    }
}

Java

@Override
public void onCreate(@Nullable Bundle savedInstanceState,
        @Nullable PersistableBundle persistentState) {
    AppOpsManager.OnOpNotedCallback appOpsCallback =
            new AppOpsManager.OnOpNotedCallback() {
        private void logPrivateDataAccess(String opCode,
                String attributionTag, String trace) {
            Log.i("MY_APP_TAG", "Private data accessed. " +
                    "Operation: $opCode\n " +
                    "Attribution Tag:$attributionTag\nStack Trace:\n$trace");
        }

        @Override
        public void onNoted(@NonNull SyncNotedAppOp syncNotedAppOp) {
            logPrivateDataAccess(syncNotedAppOp.getOp(),
                    syncNotedAppOp.getAttributionTag(),
                    Arrays.toString(new Throwable().getStackTrace()));
        }

        @Override
        public void onSelfNoted(@NonNull SyncNotedAppOp syncNotedAppOp) {
            logPrivateDataAccess(syncNotedAppOp.getOp(),
                    syncNotedAppOp.getAttributionTag(),
                    Arrays.toString(new Throwable().getStackTrace()));
        }

        @Override
        public void onAsyncNoted(@NonNull AsyncNotedAppOp asyncNotedAppOp) {
            logPrivateDataAccess(asyncNotedAppOp.getOp(),
                    asyncNotedAppOp.getAttributionTag(),
                    asyncNotedAppOp.getMessage());
        }
    };

    AppOpsManager appOpsManager = getSystemService(AppOpsManager.class);
    if (appOpsManager != null) {
        appOpsManager.setNotedAppOpsCollector(appOpsCollector);
    }
}