Hạn chế tương tác với ứng dụng khác

Quyền không chỉ có tác dụng yêu cầu chức năng của hệ thống. Bạn cũng có thể hạn chế cách ứng dụng khác có thể tương tác với các thành phần trong ứng dụng của mình.

Hướng dẫn này giải thích cách kiểm tra tập hợp các quyền mà một ứng dụng khác đã khai báo. Hướng dẫn này cũng giải thích cách bạn có thể định cấu hình các hoạt động, dịch vụ, nhà cung cấp nội dung và broadcast receiver để hạn chế cách các ứng dụng khác có thể tương tác với ứng dụng của bạn.

Kiểm tra quyền của ứng dụng khác

Để xem tập hợp các quyền mà một ứng dụng khác khai báo, hãy sử dụng một thiết bị hoặc trình mô phỏng để hoàn thành các bước sau:

  1. Mở màn hình App info (Thông tin ứng dụng) của một ứng dụng.
  2. Chọn Permissions (Quyền). Màn hình App permissions (Quyền cho ứng dụng) sẽ tải.

    Màn hình này hiển thị một tập hợp các nhóm quyền. Hệ thống sắp xếp tập hợp các quyền mà một ứng dụng đã khai báo vào các nhóm này.

Có một số cách hữu ích khác giúp bạn kiểm tra quyền như sau:

  • Trong lệnh gọi đến dịch vụ, truyền chuỗi quyền vào Context.checkCallingPermission(). Phương thức này trả về một số nguyên cho biết liệu quyền đó đã được cấp cho quá trình gọi hiện tại hay chưa. Xin lưu ý rằng bạn chỉ có thể sử dụng phương thức này khi thực thi một lệnh gọi đến từ một quy trình khác, thường là thông qua giao diện IDL được phát hành từ một dịch vụ hoặc theo một cách nào đó đối với một quy trình khác.
  • Để kiểm tra xem một quy trình khác đã được cấp quyền cụ thể hay chưa, hãy truyền quy trình đó (PID) vào Context.checkPermission().
  • Để kiểm tra xem một gói khác đã được cấp quyền cụ thể hay chưa, hãy truyền tên gói đó vào PackageManager.checkPermission().

Hạn chế tương tác với các hoạt động trong ứng dụng của bạn

Dùng thuộc tính android:permission cho thẻ <activity> trong tệp kê khai để đặt ra hạn chế cho biết những ứng dụng nào khác có thể khởi động Activity đó. Quyền sẽ được kiểm tra trong Context.startActivity()Activity.startActivityForResult(). Nếu phương thức gọi không có quyền cần thiết, thì SecurityException sẽ xảy ra.

Hạn chế tương tác với các dịch vụ trong ứng dụng của bạn

Dùng thuộc tính android:permission cho thẻ <service> trong tệp kê khai để đặt ra hạn chế cho biết những ứng dụng nào khác có thể khởi động hoặc ràng buộc với Service liên kết. Quyền sẽ được kiểm tra trong Context.startService(), Context.stopService()Context.bindService(). Nếu phương thức gọi không có quyền cần thiết, thì SecurityException sẽ xảy ra.

Hạn chế tương tác với nhà cung cấp nội dung trong ứng dụng của bạn

Dùng thuộc tính android:permission cho thẻ <provider> để đặt ra hạn chế cho biết những ứng dụng nào khác có thể truy cập vào dữ liệu trong ContentProvider. (Nhà cung cấp nội dung có thể sử dụng thêm một thành phần bảo mật quan trọng có tên quyền URI, được mô tả trong phần sau đây.) Không giống như các thành phần khác, có 2 thuộc tính quyền riêng biệt mà bạn có thể thiết lập cho nhà cung cấp nội dung: android:readPermission đặt ra hạn chế cho biết những ứng dụng nào khác có thể đọc dữ liệu của nhà cung cấp, còn android:writePermission đặt ra hạn chế cho biết các ứng dụng nào khác có thể ghi. Hãy lưu ý rằng nếu nhà cung cấp được bảo vệ bằng cả quyền đọc và ghi, thì chỉ có quyền ghi thôi là chưa đủ để ứng dụng được phép đọc dữ liệu của nhà cung cấp.

Các quyền sẽ được kiểm tra khi truy xuất lần đầu nhà cung cấp và khi ứng dụng thực hiện các hoạt động trên nhà cung cấp đó. Nếu ứng dụng đang yêu cầu không có quyền nào trong 2 quyền nói trên, SecurityException sẽ xảy ra. Cần có quyền đọc để sử dụng ContentResolver.query(), cần có quyền ghi để sử dụng ContentResolver.insert(), ContentResolver.update() hoặc ContentResolver.delete(). Trong tất cả những trường hợp này, việc không có quyền cần thiết sẽ dẫn đến SecurityException.

Cấp quyền truy cập theo từng URI

Hệ thống này cung cấp cho bạn thêm khả năng kiểm soát ở mức độ chi tiết về cách các ứng dụng khác có thể truy cập vào nhà cung cấp nội dung trong ứng dụng của mình. Đặc biệt, nhà cung cấp nội dung của bạn có thể tự bảo vệ mình bằng quyền đọc và ghi, trong khi vẫn cho phép ứng dụng khách trực tiếp chia sẻ URI cụ thể với các ứng dụng khác. Để khai báo khả năng hỗ trợ của ứng dụng cho mô hình này, hãy sử dụng thuộc tính android:grantUriPermissions hoặc phần tử <grant-uri-permission>.

Bạn cũng có thể cấp quyền theo từng URI. Khi bắt đầu hoạt động hoặc trả về kết quả cho một hoạt động, hãy đặt cờ ý định Intent.FLAG_GRANT_READ_URI_PERMISSION, cờ ý định Intent.FLAG_GRANT_WRITE_URI_PERMISSION hoặc cả hai cờ. Thao tác này sẽ cung cấp cho những ứng dụng khác lần lượt các quyền đọc, ghi hoặc đọc/ghi cho URI dữ liệu có trong ý định. Các ứng dụng khác sẽ nhận được những quyền này cho URI cụ thể, bất kể có quyền truy cập vào dữ liệu trong nhà cung cấp nội dung nói chung hay không.

Ví dụ: giả sử một người dùng đang sử dụng ứng dụng của bạn để xem email có hình ảnh đính kèm. Các ứng dụng khác không thể truy cập vào nội dung email nói chung đó, nhưng có thể sẽ muốn xem hình ảnh. Ứng dụng của bạn có thể dùng ý định và cờ ý định Intent.FLAG_GRANT_READ_URI_PERMISSION để cho phép ứng dụng xem hình ảnh xem được hình ảnh đó.

Một yếu tố khác cần cân nhắc là khả năng hiển thị của ứng dụng. Nếu ứng dụng của bạn nhắm mục tiêu đến Android 11 (API cấp 30) trở lên, thì hệ thống sẽ tự động hiển thị một số ứng dụng để ứng dụng của bạn nhìn thấy và sẽ ẩn các ứng dụng khác theo mặc định. Nếu có nhà cung cấp nội dung và đã cấp quyền URI cho một ứng dụng khác, thì ứng dụng của bạn sẽ tự động hiển thị cho ứng dụng khác đó.

Để biết thêm thông tin, hãy xem tài liệu tham khảo cho phương thức grantUriPermission(), revokeUriPermission()checkUriPermission().

Hạn chế tương tác với broadcast receiver trong ứng dụng của bạn

Dùng thuộc tính android:permission cho thẻ <receiver> để đặt ra hạn chế cho biết những ứng dụng nào khác có thể truyền tin đến BroadcastReceiver liên kết. Quyền này được kiểm tra sau khi Context.sendBroadcast() trả về vì hệ thống cố gắng phân phối tin đã truyền đến đối tượng nhận cụ thể. Điều này có nghĩa là lỗi về quyền sẽ không dẫn đến việc ngoại lệ được trả về cho phương thức gọi mà chỉ không phân phối Intent.

Tương tự, bạn có thể cấp quyền cho Context.registerReceiver() để kiểm soát xem những ứng dụng nào khác có thể truyền đến đối tượng nhận đã đăng ký theo lập trình. Một cách khác, bạn có thể cung cấp quyền khi gọi Context.sendBroadcast() để đặt ra hạn chế cho biết những broadcast receiver nào có thể nhận tin truyền đi.

Lưu ý: Cả đối tượng nhận và truyền tin đều có thể yêu cầu quyền. Khi điều này xảy ra, cả hai bước kiểm tra quyền đều phải đạt thì ý định mới được gửi đến mục tiêu liên quan. Để biết thêm thông tin, hãy xem phần Hạn chế truyền tin bằng các quyền.