Các thay đổi về hành vi của Android 7.0

Cùng với các tính năng và chức năng mới, Android 7.0 còn có nhiều thay đổi về hành vi của hệ thống và API. Tài liệu này nêu bật một số thay đổi quan trọng mà bạn nên nắm rõ và cân nhắc trong ứng dụng của mình.

Nếu trước đây bạn đã phát hành một ứng dụng cho Android, hãy lưu ý rằng ứng dụng của bạn có thể bị ảnh hưởng bởi những thay đổi này trong nền tảng.

Pin và bộ nhớ

Android 7.0 có các thay đổi về hành vi của hệ thống nhằm cải thiện thời lượng pin của thiết bị và giảm mức sử dụng RAM. Những thay đổi này có thể ảnh hưởng đến quyền truy cập của ứng dụng vào tài nguyên hệ thống, cũng như cách ứng dụng tương tác với các ứng dụng khác bằng một số ý định ngầm ẩn.

Nghỉ

Được giới thiệu trong Android 6.0 (cấp độ API 23), Chế độ ngủ gật giúp cải thiện thời lượng pin bằng cách trì hoãn các hoạt động của CPU và mạng khi người dùng không cắm sạc thiết bị, không di chuyển thiết bị và tắt màn hình. Android 7.0 mang đến những cải tiến hơn nữa cho Chế độ ngủ gật bằng cách áp dụng một số hạn chế về CPU và hoạt động mạng khi thiết bị không được cắm sạc và tắt màn hình, nhưng không nhất thiết phải đứng yên, chẳng hạn như khi điện thoại đang di chuyển trong túi của người dùng.

Hình minh hoạ cách Chế độ ngủ áp dụng cấp độ đầu tiên của các quy định hạn chế về hoạt động của hệ thống để cải thiện thời lượng pin

Hình 1. Hình minh hoạ cách Chế độ ngủ áp dụng cấp độ đầu tiên của các quy định hạn chế hoạt động hệ thống để cải thiện thời lượng pin.

Khi thiết bị đang dùng pin và màn hình đã tắt trong một khoảng thời gian nhất định, thiết bị sẽ chuyển sang chế độ Nghỉ và áp dụng nhóm hạn chế đầu tiên: Tắt quyền truy cập mạng của ứng dụng, đồng thời trì hoãn các công việc và hoạt động đồng bộ hoá. Nếu thiết bị đứng yên trong một khoảng thời gian nhất định sau khi chuyển sang Chế độ nghỉ, thì hệ thống sẽ áp dụng các hạn chế còn lại của Chế độ nghỉ cho PowerManager.WakeLock, chuông báo AlarmManager, GPS và quét Wi-Fi. Bất kể một số hay tất cả các quy định hạn chế của Chế độ ngủ li bì đang được áp dụng, hệ thống sẽ đánh thức thiết bị trong thời gian bảo trì ngắn, trong thời gian đó, các ứng dụng được phép truy cập mạng và có thể thực thi mọi công việc/hoạt động đồng bộ hoá bị trì hoãn.

Hình minh hoạ cách Chế độ nghỉ áp dụng cấp độ thứ hai của các quy định hạn chế hoạt động hệ thống sau khi thiết bị đứng yên trong một khoảng thời gian nhất định

Hình 2. Hình minh hoạ cách Chế độ nghỉ áp dụng cấp độ thứ hai của các quy định hạn chế hoạt động hệ thống sau khi thiết bị đứng yên trong một khoảng thời gian nhất định.

Lưu ý rằng việc bật màn hình hoặc cắm thiết bị sẽ thoát khỏi chế độ Nghỉ và xoá các quy định hạn chế xử lý này. Hành vi bổ sung không ảnh hưởng đến các đề xuất và phương pháp hay nhất trong việc điều chỉnh ứng dụng của bạn cho phù hợp với phiên bản trước của Chế độ nghỉ được giới thiệu trong Android 6.0 (API cấp 23), như đã thảo luận trong phần Tối ưu hoá cho Chế độ nghỉ và Chế độ chờ ứng dụng. Bạn vẫn nên làm theo các đề xuất đó, chẳng hạn như sử dụng Giải pháp gửi thông báo qua đám mây của Firebase (FCM) để gửi và nhận thông báo, đồng thời bắt đầu lên kế hoạch cập nhật để phù hợp với hành vi bổ sung của Chế độ nghỉ.

Dự án Svelte: Tối ưu hoá ở chế độ nền

Android 7.0 xoá 3 thông báo truyền phát ngầm để giúp tối ưu hoá cả mức sử dụng bộ nhớ và mức tiêu thụ điện năng. Thay đổi này là cần thiết vì thông báo truyền phát ngầm thường khởi động các ứng dụng đã đăng ký để nghe thông báo trong nền. Việc xoá các thông báo này có thể mang lại lợi ích đáng kể cho hiệu suất của thiết bị và trải nghiệm người dùng.

Thiết bị di động thường xuyên thay đổi kết nối, chẳng hạn như khi chuyển đổi giữa Wi-Fi và dữ liệu di động. Hiện tại, các ứng dụng có thể theo dõi thay đổi về khả năng kết nối bằng cách đăng ký một trình nhận cho thông báo truyền phát ngầm CONNECTIVITY_ACTION trong tệp kê khai. Vì nhiều ứng dụng đăng ký nhận thông báo này, nên một bộ chuyển mạng duy nhất có thể khiến tất cả các ứng dụng đó thức dậy và xử lý thông báo cùng một lúc.

Tương tự, trong các phiên bản Android trước, ứng dụng có thể đăng ký nhận thông báo truyền tin ngầm ẩn ACTION_NEW_PICTURE và ACTION_NEW_VIDEO từ các ứng dụng khác, chẳng hạn như Máy ảnh. Khi người dùng chụp ảnh bằng ứng dụng Máy ảnh, các ứng dụng này sẽ thức dậy để xử lý thông báo truyền tin.

Để giảm bớt các vấn đề này, Android 7.0 áp dụng các biện pháp tối ưu hoá sau:

  • Các ứng dụng nhắm đến Android 7.0 (cấp độ API 24) trở lên sẽ không nhận được thông báo CONNECTIVITY_ACTION nếu những ứng dụng đó khai báo bộ nhận tín hiệu truyền tin trong tệp kê khai. Các ứng dụng vẫn sẽ nhận được thông báo CONNECTIVITY_ACTION nếu đăng ký BroadcastReceiver thông qua Context.registerReceiver() và ngữ cảnh đó vẫn hợp lệ.
  • Hệ thống không còn gửi thông báo ACTION_NEW_PICTURE hoặc ACTION_NEW_VIDEO nữa. Tính năng tối ưu hoá này ảnh hưởng đến tất cả ứng dụng chứ không chỉ những ứng dụng nhắm mục tiêu Android 7.0.

Nếu ứng dụng của bạn sử dụng các ý định này, thì bạn nên xoá các phần phụ thuộc này càng sớm càng tốt để có thể nhắm mục tiêu đúng cách trên những thiết bị chạy Android 7.0. Khung Android cung cấp một số giải pháp để giảm thiểu nhu cầu đối với các thông báo truyền phát ngầm này. Ví dụ: API JobScheduler cung cấp một cơ chế mạnh mẽ để lên lịch hoạt động mạng khi các điều kiện được chỉ định, chẳng hạn như việc kết nối với mạng không đo lượng dữ liệu được đáp ứng. Bạn thậm chí có thể dùng JobScheduler để phản hồi với các thay đổi đối với nhà cung cấp nội dung.

Để biết thêm thông tin về tính năng tối ưu hoá ở chế độ nền trong Android 7.0 (cấp độ API 24) và cách điều chỉnh ứng dụng, hãy xem bài viết Tối ưu hoá ở chế độ nền.

Thay đổi về quyền

Android 7.0 có những thay đổi về quyền có thể ảnh hưởng đến ứng dụng của bạn.

Thay đổi về quyền đối với hệ thống tệp

Để cải thiện tính bảo mật của các tệp riêng tư, thư mục riêng tư của các ứng dụng nhắm đến Android 7.0 trở lên đã bị hạn chế quyền truy cập (0700). Chế độ cài đặt này ngăn chặn việc rò rỉ siêu dữ liệu của các tệp riêng tư, chẳng hạn như kích thước hoặc sự tồn tại của các tệp đó. Thay đổi về quyền này có nhiều tác dụng phụ:

  • Chủ sở hữu không được nới lỏng quyền truy cập tệp của các tệp riêng tư nữa. Nếu chủ sở hữu cố gắng làm như vậy bằng cách sử dụng MODE_WORLD_READABLE và/hoặc MODE_WORLD_WRITEABLE, thì hệ thống sẽ kích hoạt SecurityException.

    Lưu ý: Cho đến nay, quy định hạn chế này chưa được thực thi đầy đủ. Ứng dụng vẫn có thể sửa đổi quyền đối với thư mục riêng tư của mình bằng cách sử dụng API gốc hoặc API File. Tuy nhiên, bạn không nên nới lỏng quyền đối với thư mục riêng tư.

  • Việc truyền URI file:// ra bên ngoài miền gói có thể khiến trình nhận có đường dẫn không thể truy cập được. Do đó, việc cố gắng truyền một URI file:// sẽ kích hoạt FileUriExposedException. Bạn nên chia sẻ nội dung của tệp riêng tư bằng FileProvider.
  • DownloadManager không thể chia sẻ tệp được lưu trữ riêng tư theo tên tệp nữa. Các ứng dụng cũ có thể có đường dẫn không truy cập được khi truy cập vào COLUMN_LOCAL_FILENAME. Các ứng dụng nhắm đến Android 7.0 trở lên sẽ kích hoạt SecurityException khi cố gắng truy cập vào COLUMN_LOCAL_FILENAME. Các ứng dụng cũ đặt vị trí tải xuống thành vị trí công khai bằng cách sử dụng DownloadManager.Request.setDestinationInExternalFilesDir() hoặc DownloadManager.Request.setDestinationInExternalPublicDir() vẫn có thể truy cập vào đường dẫn trong COLUMN_LOCAL_FILENAME, tuy nhiên, bạn không nên sử dụng phương thức này. Cách ưu tiên để truy cập vào tệp do DownloadManager hiển thị là sử dụng ContentResolver.openFileDescriptor().

Chia sẻ tệp giữa các ứng dụng

Đối với các ứng dụng nhắm đến Android 7.0, khung Android thực thi chính sách API StrictMode nghiêm cấm việc hiển thị URI file:// bên ngoài ứng dụng của bạn. Nếu một ý định chứa URI tệp rời khỏi ứng dụng của bạn, thì ứng dụng sẽ không thành công với ngoại lệ FileUriExposedException.

Để chia sẻ tệp giữa các ứng dụng, bạn nên gửi một URI content:// và cấp quyền truy cập tạm thời trên URI đó. Cách dễ nhất để cấp quyền này là sử dụng lớp FileProvider. Để biết thêm thông tin về quyền và cách chia sẻ tệp, hãy xem bài viết Chia sẻ tệp.

Cải tiến khả năng hỗ trợ tiếp cận

Android 7.0 bao gồm các thay đổi nhằm cải thiện khả năng hữu dụng của nền tảng cho người dùng có thị lực kém hoặc bị suy giảm thị lực. Nhìn chung, những thay đổi này không yêu cầu bạn phải thay đổi mã trong ứng dụng. Tuy nhiên, bạn nên xem xét các tính năng này và thử nghiệm chúng với ứng dụng của mình để đánh giá tác động tiềm ẩn đối với trải nghiệm người dùng.

Thu phóng màn hình

Android 7.0 cho phép người dùng đặt Kích thước hiển thị để phóng to hoặc thu nhỏ tất cả các thành phần trên màn hình, nhờ đó cải thiện khả năng hỗ trợ tiếp cận thiết bị cho người dùng có thị lực kém. Người dùng không thể thu phóng màn hình vượt quá chiều rộng màn hình tối thiểu là sw320dp, tức là chiều rộng của Nexus 4, một chiếc điện thoại có kích thước trung bình phổ biến.

Màn hình cho thấy kích thước hiển thị chưa thu phóng của thiết bị chạy hình ảnh hệ thống Android 7.0
Màn hình cho thấy hiệu ứng của việc tăng kích thước hiển thị của thiết bị chạy hình ảnh hệ thống Android 7.0

Hình 3. Màn hình bên phải cho thấy hiệu ứng của việc tăng Kích thước hiển thị của một thiết bị chạy hình ảnh hệ thống Android 7.0.

Khi mật độ thiết bị thay đổi, hệ thống sẽ thông báo cho các ứng dụng đang chạy theo những cách sau:

  • Nếu một ứng dụng nhắm đến cấp độ API mục tiêu 23 trở xuống, thì hệ thống sẽ tự động loại bỏ tất cả các tiến trình nền của ứng dụng đó. Điều này có nghĩa là nếu người dùng chuyển từ một ứng dụng như vậy sang màn hình Cài đặt và thay đổi chế độ cài đặt Kích thước hiển thị, thì hệ thống sẽ tắt ứng dụng đó theo cách tương tự như trong trường hợp bộ nhớ thấp. Nếu ứng dụng có bất kỳ quy trình trên nền trước nào, thì hệ thống sẽ thông báo cho các quy trình đó về thay đổi cấu hình như mô tả trong phần Xử lý các thay đổi trong thời gian chạy, giống như khi hướng của thiết bị thay đổi.
  • Nếu một ứng dụng nhắm đến Android 7.0, thì tất cả quy trình của ứng dụng đó (nền trước và nền sau) đều được thông báo về thay đổi cấu hình như mô tả trong phần Xử lý các thay đổi trong thời gian chạy.

Hầu hết các ứng dụng không cần thực hiện bất kỳ thay đổi nào để hỗ trợ tính năng này, miễn là các ứng dụng đó tuân theo các phương pháp hay nhất của Android. Những điều cụ thể cần kiểm tra:

  • Kiểm thử ứng dụng của bạn trên một thiết bị có chiều rộng màn hình sw320dp và đảm bảo ứng dụng hoạt động đúng cách.
  • Khi cấu hình thiết bị thay đổi, hãy cập nhật mọi thông tin được lưu vào bộ nhớ đệm phụ thuộc vào mật độ, chẳng hạn như bitmap được lưu vào bộ nhớ đệm hoặc tài nguyên được tải từ mạng. Kiểm tra các thay đổi về cấu hình khi ứng dụng tiếp tục từ trạng thái tạm dừng.

    Lưu ý: Nếu bạn lưu dữ liệu phụ thuộc vào cấu hình vào bộ nhớ đệm, thì bạn nên đưa vào siêu dữ liệu có liên quan, chẳng hạn như kích thước màn hình hoặc mật độ pixel phù hợp cho dữ liệu đó. Việc lưu siêu dữ liệu này cho phép bạn quyết định xem có cần làm mới dữ liệu đã lưu vào bộ nhớ đệm sau khi thay đổi cấu hình hay không.

  • Tránh chỉ định kích thước bằng đơn vị px, vì các đơn vị này không điều chỉnh theo mật độ màn hình. Thay vào đó, hãy chỉ định kích thước bằng đơn vị pixel không phụ thuộc vào mật độ (dp).

Cài đặt hỗ trợ thị giác trong Trình hướng dẫn thiết lập

Android 7.0 có phần Cài đặt thị lực trên màn hình Chào mừng, nơi người dùng có thể thiết lập các chế độ cài đặt hỗ trợ tiếp cận sau đây trên thiết bị mới: Cử chỉ phóng to, Cỡ chữ, Kích thước hiển thị và TalkBack. Thay đổi này giúp tăng khả năng phát hiện lỗi liên quan đến các chế độ cài đặt màn hình khác nhau. Để đánh giá tác động của tính năng này, bạn nên kiểm thử ứng dụng khi bật các chế độ cài đặt này. Bạn có thể tìm thấy các chế độ cài đặt trong phần Cài đặt > Hỗ trợ tiếp cận.

Các ứng dụng NDK liên kết với thư viện nền tảng

Kể từ Android 7.0, hệ thống sẽ ngăn các ứng dụng liên kết động với các thư viện không phải NDK. Điều này có thể khiến ứng dụng của bạn gặp sự cố. Sự thay đổi này về hành vi nhằm tạo ra trải nghiệm trong ứng dụng nhất quán trên các bản cập nhật nền tảng và các thiết bị khác nhau. Mặc dù mã của bạn có thể không liên kết với các thư viện riêng tư, nhưng có thể một thư viện tĩnh của bên thứ ba trong ứng dụng của bạn đang làm như vậy. Do đó, tất cả nhà phát triển nên kiểm tra để đảm bảo rằng ứng dụng của họ không gặp sự cố trên các thiết bị chạy Android 7.0. Nếu ứng dụng của bạn sử dụng mã gốc, thì bạn chỉ nên dùng API NDK công khai.

Có 3 cách mà ứng dụng của bạn có thể đang cố gắng truy cập vào các API nền tảng riêng tư:

  • Ứng dụng của bạn truy cập trực tiếp vào các thư viện nền tảng riêng tư. Bạn nên cập nhật ứng dụng để đưa bản sao của riêng ứng dụng vào các thư viện đó hoặc sử dụng API NDK công khai.
  • Ứng dụng của bạn sử dụng một thư viện bên thứ ba truy cập vào các thư viện nền tảng riêng tư. Ngay cả khi chắc chắn rằng ứng dụng của bạn không truy cập trực tiếp vào các thư viện riêng tư, bạn vẫn nên kiểm thử ứng dụng cho trường hợp này.
  • Ứng dụng của bạn tham chiếu đến một thư viện không có trong tệp APK của ứng dụng. Ví dụ: điều này có thể xảy ra nếu bạn cố gắng sử dụng bản sao OpenSSL của riêng mình nhưng quên gói bản sao đó với APK của ứng dụng. Ứng dụng có thể chạy bình thường trên các phiên bản của nền tảng Android có chứa libcrypto.so. Tuy nhiên, ứng dụng có thể gặp sự cố trên các phiên bản Android mới hơn không có thư viện này (chẳng hạn như Android 6.0 trở lên). Để khắc phục vấn đề này, hãy đảm bảo rằng bạn đã đóng gói tất cả thư viện không phải NDK bằng APK.

Ứng dụng không nên sử dụng các thư viện gốc không có trong NDK vì các thư viện này có thể thay đổi hoặc bị xoá giữa các phiên bản Android. Việc chuyển từ OpenSSL sang BoringSSL là một ví dụ về thay đổi như vậy. Ngoài ra, vì không có yêu cầu về khả năng tương thích đối với các thư viện nền tảng không có trong NDK, nên các thiết bị khác nhau có thể cung cấp các mức độ tương thích khác nhau.

Để giảm tác động của quy định hạn chế này đối với các ứng dụng hiện được phát hành, một nhóm thư viện được sử dụng nhiều (chẳng hạn như libandroid_runtime.so, libcutils.so, libcrypto.so và libssl.so) có thể tạm thời truy cập được trên Android 7.0 (API cấp 24) cho các ứng dụng nhắm đến API cấp 23 trở xuống. Nếu ứng dụng của bạn tải một trong các thư viện này, thì logcat sẽ tạo cảnh báo và một thông báo ngắn sẽ xuất hiện trên thiết bị mục tiêu để thông báo cho bạn. Nếu thấy những cảnh báo này, bạn nên cập nhật ứng dụng để thêm bản sao của riêng ứng dụng cho các thư viện đó hoặc chỉ sử dụng API NDK công khai. Các bản phát hành trong tương lai của nền tảng Android có thể hạn chế hoàn toàn việc sử dụng thư viện riêng tư và khiến ứng dụng của bạn gặp sự cố.

Tất cả ứng dụng đều tạo ra lỗi thời gian chạy khi gọi một API không công khai cũng như không thể truy cập tạm thời. Kết quả là cả System.loadLibrary và dlopen(3) đều trả về NULL và có thể khiến ứng dụng của bạn gặp sự cố. Bạn nên xem lại mã ứng dụng để xoá việc sử dụng các API nền tảng riêng tư và kiểm thử kỹ lưỡng ứng dụng bằng thiết bị hoặc trình mô phỏng chạy Android 7.0 (cấp độ API 24). Nếu không chắc ứng dụng của mình có sử dụng thư viện riêng tư hay không, bạn có thể kiểm tra logcat để xác định lỗi thời gian chạy.

Bảng sau đây mô tả hành vi mà bạn có thể thấy từ một ứng dụng, tuỳ thuộc vào việc ứng dụng đó sử dụng thư viện gốc riêng tư và cấp độ API mục tiêu (android:targetSdkVersion).

Thư viện Cấp API mục tiêu Quyền truy cập trong thời gian chạy bằng trình liên kết động Hành vi của Android 7.0 (cấp độ API 24) Hành vi của nền tảng Android trong tương lai
NDK công khai Khán giả có Phù hợp cho người khuyết tật Hoạt động như mong đợi Hoạt động như mong đợi
Riêng tư (thư viện riêng tư có thể truy cập tạm thời) 23 trở xuống Tạm thời có thể truy cập Hoạt động như mong đợi, nhưng bạn nhận được cảnh báo logcat. Lỗi thời gian chạy
Riêng tư (thư viện riêng tư có thể truy cập tạm thời) 24 trở lên Bị hạn chế Lỗi thời gian chạy Lỗi thời gian chạy
Tư nhân (khác) Khán giả có Bị hạn chế Lỗi thời gian chạy Lỗi thời gian chạy

Kiểm tra xem ứng dụng của bạn có sử dụng thư viện riêng tư hay không

Để giúp bạn xác định các vấn đề khi tải thư viện riêng tư, logcat có thể tạo cảnh báo hoặc lỗi thời gian chạy. Ví dụ: nếu ứng dụng của bạn nhắm đến cấp độ API mục tiêu 23 trở xuống và cố gắng truy cập vào một thư viện riêng tư trên thiết bị chạy Android 7.0, thì bạn có thể thấy cảnh báo tương tự như sau:

03-21 17:07:51.502 31234 31234 W linker  : library "libandroid_runtime.so"
("/system/lib/libandroid_runtime.so") needed or dlopened by
"/data/app/com.popular-app.android-2/lib/arm/libapplib.so" is not accessible
for the namespace "classloader-namespace" - the access is temporarily granted
as a workaround for http://b/26394120

Những cảnh báo logcat này cho bạn biết thư viện nào đang cố gắng truy cập vào một API nền tảng riêng tư, nhưng sẽ không khiến ứng dụng của bạn gặp sự cố. Tuy nhiên, nếu ứng dụng nhắm đến cấp độ API mục tiêu 24 trở lên, thì Logcat sẽ tạo ra lỗi thời gian chạy sau đây và ứng dụng của bạn có thể gặp sự cố:

java.lang.UnsatisfiedLinkError: dlopen failed: library "libcutils.so"
("/system/lib/libcutils.so") needed or dlopened by
"/system/lib/libnativeloader.so" is not accessible for the namespace
"classloader-namespace"
  at java.lang.Runtime.loadLibrary0(Runtime.java:977)
  at java.lang.System.loadLibrary(System.java:1602)

Bạn cũng có thể thấy các kết quả logcat này nếu ứng dụng của bạn sử dụng thư viện bên thứ ba liên kết linh động với API nền tảng riêng tư. Công cụ readelf trong NDK của Android 7.0 cho phép bạn tạo danh sách tất cả thư viện dùng chung được liên kết động của một tệp .so nhất định bằng cách chạy lệnh sau:

aarch64-linux-android-readelf -dW libMyLibrary.so

Cập nhật ứng dụng

Sau đây là một số bước bạn có thể thực hiện để khắc phục các loại lỗi này và đảm bảo ứng dụng của bạn không gặp sự cố trong các bản cập nhật nền tảng trong tương lai:

  • Nếu ứng dụng của bạn sử dụng thư viện nền tảng riêng tư, bạn nên cập nhật ứng dụng để thêm bản sao riêng của các thư viện đó hoặc sử dụng API NDK công khai.
  • Nếu ứng dụng của bạn sử dụng thư viện bên thứ ba truy cập vào các biểu tượng riêng tư, hãy liên hệ với tác giả thư viện để cập nhật thư viện.
  • Đảm bảo bạn đóng gói tất cả thư viện không phải NDK bằng APK.
  • Sử dụng các hàm JNI chuẩn thay vì getJavaVM và getJNIEnv từ libandroid_runtime.so:
    AndroidRuntime::getJavaVM -> GetJavaVM from <jni.h>
    AndroidRuntime::getJNIEnv -> JavaVM::GetEnv or
    JavaVM::AttachCurrentThread from <jni.h>.
    
  • Sử dụng __system_property_get thay vì ký hiệu property_get riêng tư từ libcutils.so. Để thực hiện việc này, hãy sử dụng __system_property_get với nội dung sau:
    #include <sys/system_properties.h>

    Lưu ý: CTS không kiểm tra phạm vi cung cấp và nội dung của các thuộc tính hệ thống. Cách khắc phục tốt hơn là tránh sử dụng hoàn toàn các thuộc tính này.

  • Sử dụng phiên bản cục bộ của biểu tượng SSL_ctrl từ libcrypto.so. Ví dụ: bạn nên liên kết tĩnh libcyrpto.a trong tệp .so hoặc thêm phiên bản liên kết động của libcrypto.so từ BoringSSL/OpenSSL và đóng gói phiên bản đó trong tệp APK.

Android for Work

Android 7.0 có những thay đổi đối với các ứng dụng nhắm đến Android for Work, bao gồm cả những thay đổi đối với việc cài đặt chứng chỉ, đặt lại mật khẩu, quản lý người dùng phụ và quyền truy cập vào giá trị nhận dạng thiết bị. Nếu đang xây dựng ứng dụng cho môi trường Android for Work, bạn nên xem xét những thay đổi này và sửa đổi ứng dụng cho phù hợp.

  • Bạn phải cài đặt trình cài đặt chứng chỉ được uỷ quyền trước khi DPC có thể đặt chứng chỉ đó. Đối với cả ứng dụng của chủ sở hữu hồ sơ và chủ sở hữu thiết bị nhắm đến Android 7.0 (cấp độ API 24), bạn nên cài đặt trình cài đặt chứng chỉ được uỷ quyền trước khi trình kiểm soát chính sách thiết bị (DPC) gọi DevicePolicyManager.setCertInstallerPackage(). Nếu trình cài đặt chưa được cài đặt, hệ thống sẽ gửi một IllegalArgumentException.
  • Các quy định hạn chế về việc đặt lại mật khẩu cho quản trị viên thiết bị hiện áp dụng cho chủ sở hữu hồ sơ. Quản trị viên thiết bị không thể dùng DevicePolicyManager.resetPassword() để xoá mật khẩu hoặc thay đổi mật khẩu đã đặt nữa. Quản trị viên thiết bị vẫn có thể đặt mật khẩu, nhưng chỉ khi thiết bị không có mật khẩu, mã PIN hoặc hình mở khoá.
  • Chủ sở hữu thiết bị và hồ sơ có thể quản lý tài khoản ngay cả khi đã đặt các quy định hạn chế. Chủ sở hữu thiết bị và chủ sở hữu hồ sơ có thể gọi API Quản lý tài khoản ngay cả khi có các quy định hạn chế đối với người dùng DISALLOW_MODIFY_ACCOUNTS.
  • Chủ sở hữu thiết bị có thể quản lý người dùng phụ. Khi thiết bị đang chạy ở chế độ chủ sở hữu thiết bị, quy định hạn chế DISALLOW_ADD_USER sẽ tự động được đặt. Điều này ngăn người dùng tạo người dùng phụ không được quản lý. Ngoài ra, các phương thức CreateUser() và createAndInitializeUser() không còn được dùng nữa; phương thức DevicePolicyManager.createAndManageUser() mới sẽ thay thế các phương thức này.
  • Chủ sở hữu thiết bị có thể truy cập vào giá trị nhận dạng thiết bị. Chủ sở hữu thiết bị có thể truy cập vào địa chỉ MAC của Wi-Fi mà thiết bị sử dụng bằng cách dùng DevicePolicyManager.getWifiMacAddress(). Nếu Wi-Fi chưa từng được bật trên thiết bị, thì phương thức này sẽ trả về giá trị null.
  • Chế độ công việc kiểm soát quyền truy cập vào các ứng dụng công việc. Khi chế độ công việc tắt, trình chạy hệ thống sẽ cho biết các ứng dụng công việc không hoạt động bằng cách chuyển chúng sang màu xám. Việc bật lại chế độ công việc sẽ khôi phục hành vi bình thường.
  • Khi cài đặt tệp PKCS #12 chứa chuỗi chứng chỉ máy khách và khoá riêng tư tương ứng từ giao diện người dùng Cài đặt, chứng chỉ CA trong chuỗi sẽ không còn được cài đặt vào vùng lưu trữ thông tin xác thực đáng tin cậy nữa. Điều này không ảnh hưởng đến kết quả của KeyChain.getCertificateChain() khi các ứng dụng cố gắng truy xuất chuỗi chứng chỉ ứng dụng sau này. Nếu cần, bạn nên cài đặt chứng chỉ CA vào vùng lưu trữ thông tin xác thực đáng tin cậy bằng cách sử dụng riêng Giao diện người dùng Cài đặt, với định dạng được mã hoá DER trong đuôi tệp .crt hoặc .cer.
  • Kể từ Android 7.0, việc đăng ký và lưu trữ vân tay được quản lý theo từng người dùng. Nếu Trình khách chính sách thiết bị (DPC) của chủ sở hữu hồ sơ nhắm đến API cấp 23 (hoặc thấp hơn) trên thiết bị chạy Android 7.0 (API cấp 24), thì người dùng vẫn có thể đặt vân tay trên thiết bị, nhưng các ứng dụng công việc không thể truy cập vào vân tay của thiết bị. Khi DPC nhắm đến cấp độ API mục tiêu 24 trở lên, người dùng có thể đặt vân tay dành riêng cho hồ sơ công việc bằng cách chuyển đến phần Cài đặt > Bảo mật > Bảo mật hồ sơ công việc.
  • DevicePolicyManager.getStorageEncryptionStatus() trả về trạng thái mã hoá mới ENCRYPTION_STATUS_ACTIVE_PER_USER để cho biết rằng tính năng mã hoá đang hoạt động và khoá mã hoá được liên kết với người dùng. Trạng thái mới chỉ được trả về nếu trình kiểm soát chính sách thiết bị (DPC) nhắm đến cấp độ API mục tiêu 24 trở lên. Đối với các ứng dụng nhắm đến cấp độ API cũ hơn, ENCRYPTION_STATUS_ACTIVE sẽ được trả về, ngay cả khi khoá mã hoá dành riêng cho người dùng hoặc hồ sơ.
  • Trong Android 7.0, một số phương thức thường ảnh hưởng đến toàn bộ thiết bị sẽ hoạt động theo cách khác nếu thiết bị đã cài đặt hồ sơ công việc có phương thức xác thực công việc riêng. Thay vì ảnh hưởng đến toàn bộ thiết bị, các phương thức này chỉ áp dụng cho hồ sơ công việc. (Danh sách đầy đủ các phương thức như vậy có trong tài liệu về DevicePolicyManager.getParentProfileInstance().) Ví dụ: DevicePolicyManager.lockNow() chỉ khoá hồ sơ công việc thay vì khoá toàn bộ thiết bị. Đối với mỗi phương thức này, bạn có thể nhận được hành vi cũ bằng cách gọi phương thức trên thực thể mẹ của DevicePolicyManager; bạn có thể lấy thực thể mẹ này bằng cách gọi DevicePolicyManager.getParentProfileInstance(). Ví dụ: nếu bạn gọi phương thức lockNow() của thực thể mẹ, thì toàn bộ thiết bị sẽ bị khoá.

Giữ lại chú thích

Android 7.0 khắc phục lỗi bỏ qua chế độ hiển thị của chú thích. Vấn đề này cho phép thời gian chạy truy cập vào các chú thích mà lẽ ra không thể truy cập được. Những chú thích này bao gồm:

  • VISIBILITY_BUILD: Chỉ hiển thị tại thời điểm xây dựng.
  • VISIBILITY_SYSTEM: Dự kiến sẽ hiển thị trong thời gian chạy, nhưng chỉ hiển thị với hệ thống cơ bản.

Nếu ứng dụng của bạn dựa vào hành vi này, hãy thêm chính sách giữ lại vào các chú thích phải có sẵn trong thời gian chạy. Bạn có thể thực hiện việc này bằng cách sử dụng @Retention(RetentionPolicy.RUNTIME).

Thay đổi về cấu hình mặc định của TLS/SSL

Android 7.0 thực hiện những thay đổi sau đối với cấu hình TLS/SSL mặc định mà các ứng dụng dùng cho HTTPS và lưu lượng truy cập TLS/SSL khác:

  • Bộ thuật toán mật mã RC4 hiện đã bị tắt.
  • Bộ thuật toán mật mã CHACHA20-POLY1305 hiện đã được bật.

Việc tắt RC4 theo mặc định có thể dẫn đến sự cố trong kết nối HTTPS hoặc TLS/SSL khi máy chủ không thương lượng các bộ thuật toán mật mã hiện đại. Cách khắc phục ưu tiên là cải thiện cấu hình của máy chủ để bật các bộ thuật toán mật mã và giao thức mạnh hơn và hiện đại hơn. Tốt nhất là bạn nên bật TLSv1.2 và AES-GCM, đồng thời bật và ưu tiên bộ thuật toán mật mã Bảo mật chuyển tiếp (ECDHE).

Một giải pháp thay thế là sửa đổi ứng dụng để sử dụng SSLSocketFactory tuỳ chỉnh nhằm giao tiếp với máy chủ. Nhà máy phải được thiết kế để tạo các thực thể SSLSocket có một số bộ thuật toán mật mã mà máy chủ yêu cầu, ngoài các bộ thuật toán mật mã mặc định.

Lưu ý: Những thay đổi này không liên quan đến WebView.

Ứng dụng nhắm đến Android 7.0

Những thay đổi về hành vi này chỉ áp dụng cho các ứng dụng nhắm đến Android 7.0 (cấp độ API 24) trở lên. Các ứng dụng biên dịch dựa trên Android 7.0 hoặc đặt targetSdkVersion thành Android 7.0 trở lên phải sửa đổi ứng dụng để hỗ trợ những hành vi này cho phù hợp (nếu có thể áp dụng cho ứng dụng).

Thay đổi về chuyển đổi tuần tự

Android 7.0 (cấp độ API 24) đã khắc phục lỗi trong quá trình tính toán serialVersionUID mặc định, trong đó serialVersionUID không khớp với thông số kỹ thuật.

Các lớp triển khai Serializable và không chỉ định trường serialVersionUID rõ ràng có thể thấy sự thay đổi trong serialVersionUID mặc định của chúng. Điều này sẽ khiến một ngoại lệ được gửi khi cố gắng giải tuần tự hoá các thực thể của lớp đã được tuần tự hoá trên phiên bản cũ hoặc được tuần tự hoá bởi một ứng dụng nhắm đến phiên bản cũ. Thông báo lỗi sẽ có dạng như sau:

local class incompatible: stream classdesc serialVersionUID = 1234, local class serialVersionUID = 4567

Để khắc phục những vấn đề này, bạn cần thêm trường serialVersionUID vào bất kỳ lớp nào bị ảnh hưởng bằng giá trị stream classdesc serialVersionUID từ thông báo lỗi, ví dụ: 1234 trong trường hợp này. Thay đổi đó tuân thủ tất cả các đề xuất về phương pháp hay nhất để viết mã chuyển đổi tuần tự và sẽ hoạt động trên tất cả các phiên bản Android.

Lỗi cụ thể đã được khắc phục có liên quan đến sự hiện diện của các phương thức khởi tạo tĩnh, tức là <clinit>. Theo thông số kỹ thuật, sự hiện diện hoặc vắng mặt của phương thức khởi tạo tĩnh trong lớp sẽ ảnh hưởng đến serialVersionUID mặc định được tính cho lớp đó. Trước khi bản sửa lỗi, phép tính cũng sẽ kiểm tra lớp mẹ để tìm trình khởi chạy tĩnh nếu một lớp không có trình khởi chạy tĩnh.

Xin lưu ý rằng thay đổi này không ảnh hưởng đến các ứng dụng nhắm đến cấp độ API mục tiêu 23 trở xuống, các lớp có trường serialVersionUID hoặc các lớp có phương thức khởi tạo tĩnh.

Các điểm quan trọng khác

  • Khi một ứng dụng đang chạy trên Android 7.0 nhưng nhắm đến cấp độ API thấp hơn và người dùng thay đổi kích thước hiển thị, thì quy trình của ứng dụng sẽ bị buộc dừng. Ứng dụng phải có khả năng xử lý linh hoạt trường hợp này. Nếu không, ứng dụng sẽ gặp sự cố khi người dùng khôi phục ứng dụng từ màn hình Gần đây.

    Bạn nên kiểm thử ứng dụng để đảm bảo rằng hành vi này không xảy ra. Bạn có thể thực hiện việc này bằng cách gây ra một sự cố tương tự khi tắt ứng dụng theo cách thủ công bằng DDMS.

    Các ứng dụng nhắm đến Android 7.0 (cấp độ API 24) trở lên sẽ không tự động bị tắt khi mật độ thay đổi; tuy nhiên, các ứng dụng này vẫn có thể phản hồi kém với các thay đổi về cấu hình.

  • Ứng dụng trên Android 7.0 phải có khả năng xử lý linh hoạt các thay đổi về cấu hình và không được gặp sự cố trong những lần khởi động tiếp theo. Bạn có thể xác minh hành vi của ứng dụng bằng cách thay đổi cỡ chữ (Cài đặt > Màn hình > Cỡ chữ), sau đó khôi phục ứng dụng từ phần Gần đây.
  • Do lỗi trong các phiên bản Android trước, hệ thống không gắn cờ việc ghi vào ổ cắm TCP trên luồng chính là lỗi vi phạm chế độ nghiêm ngặt. Android 7.0 khắc phục lỗi này. Các ứng dụng có hành vi này hiện sẽ gửi android.os.NetworkOnMainThreadException. Nhìn chung, việc thực hiện các thao tác mạng trên luồng chính không phải là một ý tưởng hay vì các thao tác này thường có độ trễ cao, gây ra lỗi ANR và hiện tượng giật.
  • Nhóm phương thức Debug.startMethodTracing() hiện mặc định lưu trữ kết quả trong thư mục dành riêng cho gói trên bộ nhớ dùng chung, thay vì ở cấp cao nhất của thẻ SD. Điều này có nghĩa là các ứng dụng không cần yêu cầu quyền WRITE_EXTERNAL_STORAGE để sử dụng các API này nữa.
  • Nhiều API nền tảng hiện đã bắt đầu kiểm tra các tải trọng lớn được gửi qua các giao dịch Binder và hệ thống hiện gửi lại TransactionTooLargeExceptions dưới dạng RuntimeExceptions, thay vì ghi nhật ký hoặc chặn chúng một cách thầm lặng. Một ví dụ phổ biến là lưu trữ quá nhiều dữ liệu trong Activity.onSaveInstanceState(), khiến ActivityThread.StopInfo gửi RuntimeException khi ứng dụng của bạn nhắm đến Android 7.0.
  • Nếu một ứng dụng đăng các tác vụ Runnable lên một View và View không được đính kèm vào một cửa sổ, thì hệ thống sẽ đưa tác vụ Runnable vào hàng đợi bằng View; tác vụ Runnable sẽ không thực thi cho đến khi View được đính kèm vào một cửa sổ. Hành vi này khắc phục các lỗi sau:
    • Nếu một ứng dụng đăng lên View từ một luồng khác với luồng giao diện người dùng của cửa sổ dự kiến, thì Runnable có thể chạy trên luồng không chính xác.
    • Nếu tác vụ Runnable được đăng từ một luồng không phải là luồng lặp, thì ứng dụng có thể hiển thị tác vụ Runnable.
  • Nếu một ứng dụng trên Android 7.0 có quyền DELETE_PACKAGES cố gắng xoá một gói, nhưng một ứng dụng khác đã cài đặt gói đó, thì hệ thống sẽ yêu cầu người dùng xác nhận. Trong trường hợp này, các ứng dụng sẽ nhận được trạng thái trả về là STATUS_PENDING_USER_ACTION khi gọi PackageInstaller.uninstall().
  • Nhà cung cấp JCA có tên là Crypto không còn được dùng nữa vì thuật toán duy nhất của nhà cung cấp này là SHA1PRNG có khả năng mã hoá yếu. Ứng dụng không thể dùng SHA1PRNG để lấy khoá (không an toàn) nữa vì nhà cung cấp này không còn hoạt động. Để biết thêm thông tin, hãy xem bài đăng trên blog Nhà cung cấp "Crypto" bảo mật không còn được dùng trong Android N.