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

Ngoà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 API và hệ thống. 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à lưu ý trong ứng dụng của mình.

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

Pin và bộ nhớ

Android 7.0 có các thay đổi về hành vi 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 thông qua một số ý định ngầm ẩn.

Nghỉ

Ra mắt trong Android 6.0 (API cấp 23), Doze 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 rời khỏi thiết bị rút phích cắm, đứng yên và tắt màn hình. Android 7.0 mang đến nhiều cải tiến hơn cho chế độ Nghỉ bằng cách áp dụng một phần các hạn chế về CPU và mạng trong khi thiết bị đang rút phích cắm 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 người dùng đang di chuyển trong túi điện thoại.

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

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

Khi thiết bị đang chạy bằ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 tập hợp con đầu tiên của các hạn chế: Chế độ này tắt quyền truy cập mạng của ứng dụng, trì hoãn các công việc và đồ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ỉ, hệ thống sẽ áp dụng các hạn chế còn lại của chế độ Nghỉ cho chuông báo PowerManager.WakeLock, AlarmManager, quét GPS và Wi-Fi. Bất kể một số hay tất cả quy tắc hạn chế Chế độ nghỉ đang được áp dụng, hệ thống sẽ đánh thức thiết bị để bảo trì trong thời gian ngắn. Trong thời gian đó, các ứng dụng sẽ được phép truy cập vào 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 độ hạn chế thứ hai đối với 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 độ hạn chế thứ hai đối với hoạt động của hệ thống sau khi thiết bị đứng yên trong một khoảng thời gian nhất định.

Xin lưu ý rằng việc kích hoạt màn hình trên hoặc cắm thiết bị sẽ thoát khỏi Chế độ nghỉ và loại bỏ các hạn chế xử lý này. Hành vi bổ sung này không ảnh hưởng đến các đề xuất và phương pháp hay nhất để đ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ỉ ra mắt 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 những đề 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 tin nhắn, đồng thời bắt đầu lập kế hoạch cập nhật để phù hợp với hành vi Nghỉ ngơi bổ sung.

Project Svelte: Tối ưu hoá nền

Android 7.0 loại bỏ 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ớ lẫn mức tiêu thụ điện năng. Thay đổi này là cần thiết vì các thông báo truyền phát ngầm thường khởi động các ứng dụng đã đăng ký để theo dõi thông báo đó ở chế độ nền. Việc loại bỏ những thông báo này có thể mang lại lợi ích đáng kể về 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 khả năng kết nối, chẳng hạn như khi di chuyển giữa Wi-Fi và dữ liệu di động. Hiện tại, các ứng dụng có thể theo dõi các thay đổi về khả năng kết nối bằng cách đăng ký trình thu nhận cho thông báo CONNECTIVITY_ACTION ngầm ẩn trong tệp kê khai. Vì nhiều ứng dụng đăng ký nhận thông báo truyền tin này, nên một công tắc mạng duy nhất có thể khiến tất cả ứng dụng đó đánh thức và xử lý thông báo truyền tin 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 ACTION_NEW_PICTUREACTION_NEW_VIDEO ngầm ẩn 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ẽ đánh thức để xử lý thông báo truyền tin.

Để khắc phục những vấn đề này, Android 7.0 áp dụng các tính năng tối ưu hoá sau:

  • Các ứng dụng nhắm mục tiêu Android 7.0 (API cấp 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 trình nhận truyền phát 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 các 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ả các ứng dụng, không chỉ những ứng dụng nhắm đến Android 7.0.

Nếu ứng dụng của bạn sử dụng ý định bất kỳ trong số này, thì bạn nên xoá các phần phụ thuộc đó càng sớm càng tốt để có thể nhắm đến các thiết bị Android 7.0 đúng cách. 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ư kết nối với một mạng không đo lượng dữ liệu, được đáp ứng. Thậm chí bạn có thể sử dụng JobScheduler để phản ứng với các thay đổi đối với trì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 (API cấp 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.

Các thay đổi về quyền

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

Thay đổi quyền của 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 giúp ngăn chặn tình trạng 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 đó. Việc thay đổi quyền này có nhiều tác dụng phụ:

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

    Lưu ý: Đến nay, hạn chế này chưa được thực thi đầy đủ. Các ứ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 đặc biệt không nên nới lỏng các quyền đối với thư mục riêng tư.

  • Việc chuyển các URI file:// ra bên ngoài miền gói có thể để lại một đường dẫn không thể truy cập cho receiver. Do đó, việc cố gắng truyền một URI file:// sẽ kích hoạt FileUriExposedException. Bạn nên dùng FileProvider để chia sẻ nội dung của tệp riêng tư.
  • DownloadManager không thể chia sẻ các tệp được lưu trữ riêng tư theo tên tệp nữa. Các ứng dụng cũ có thể dẫn đến một đường dẫn không thể truy cập khi truy cập vào COLUMN_LOCAL_FILENAME. Các ứng dụng nhắm mục tiêu đế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 một 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 pháp này. Cách ưu tiên để truy cập vào một 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 sẽ thực thi chính sách API StrictMode nghiêm cấm việc tiết lộ các URI file:// bên ngoài ứng dụng. 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 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ề các 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 những thay đổi nhằm cải thiện khả năng hữu dụng của nền tảng này cho những người dùng có thị lực kém hoặc khiếm thị. Những thay đổi này thường không yêu cầu thay đổi mã trong ứng dụng của bạn. Tuy nhiên, bạn nên xem xét và kiểm thử tính năng này trong ứng dụng để đánh giá các 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 trê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 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 màn hình chưa thu phóng của thiết bị chạy ảnh hệ thống Android 7.0
Màn hình cho thấy tác động của việc tăng kích thước màn hình của một thiết bị chạy ảnh hệ thống Android 7.0

Hình 3. Màn hình bên phải cho thấy tác động của việc tăng Kích thước màn hình của một thiết bị chạy ả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 API cấp 23 trở xuống, thì hệ thống sẽ tự động loại bỏ mọi quy 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 khỏi một ứng dụng như vậy để mở 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ư khi ứng dụng còn ít bộ nhớ. Nếu ứng dụng có bất kỳ quy trình nào trên nền trước, hệ thống sẽ thông báo cho các quy trình đó về sự thay đổi cấu hình như mô tả trong phần Xử lý thay đổi về 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ì mọi quy trình của ứng dụng đó (nền trước và nền) đều được thông báo về việc thay đổi cấu hình như mô tả trong phần Xử lý các thay đổi về 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 về 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 đầy đủ.
  • 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ư các bitmap hoặc tài nguyên được lưu vào bộ nhớ đệm đượ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 hoạt động từ trạng thái tạm dừng.

    Lưu ý: Nếu lưu dữ liệu phụ thuộc vào cấu hình vào bộ nhớ đệm, bạn nên thêm siêu dữ liệu có liên quan như kích thước màn hình hoặc mật độ pixel thích hợp cho dữ liệu đó. Khi lưu siêu dữ liệu này, bạn có thể 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ì chúng không điều chỉnh tỷ lệ theo mật độ màn hình. Thay vào đó, hãy chỉ định các kích thước bằng đơn vị pixel không phụ thuộc vào mật độ (dp).

Cài đặt Vision trong Trình hướng dẫn thiết lập

Android 7.0 cung cấp các chế độ Cài đặt hình ảnh trên màn hình Chào mừng, trong đó 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 một thiết bị mới: Cử chỉ phóng to, Kích thước phông chữ, Kích thước hiển thịTalkBack. Thay đổi này giúp tăng khả năng xuất hiện lỗi liên quan đến nhiều chế độ cài đặt màn hình. Để đánh giá tác động của tính năng này, bạn nên kiểm thử ứng dụng sau khi bật các chế độ cài đặt này. Bạn có thể tìm thấy chế độ cài đặt này trong phần Cài đặt > Hỗ trợ tiếp cận.

Ứ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ố. Thay đổi này về hành vi nhằm tạo ra trải nghiệm ứng dụng nhất quán trên các bản cập nhật nền tảng và nhiều thiết bị. Mặc dù mã của bạn có thể không liên kết với thư viện riêng tư, nhưng có thể thư viện tĩnh của bên thứ ba trong ứng dụng của bạn có thể làm như vậy. Do đó, mọi nhà phát triển đều nên kiểm tra để đảm bảo ứng dụng không gặp sự cố trên thiết bị chạy Android 7.0. Nếu ứng dụng của bạn dùng mã gốc, thì bạn chỉ nên dùng các 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 trên 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 riêng tư trên nền tảng. Bạn nên cập nhật ứng dụng của mình để có thêm bản sao thư viện riêng hoặc sử dụng các API NDK công khai.
  • Ứng dụng của bạn dùng một thư viện bên thứ ba để truy cập vào các thư viện riêng tư trên nền tảng. Ngay cả khi chắc chắn ứng dụng của mình 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 trong trường hợp này.
  • Ứng dụng của bạn tham chiếu 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 nền tảng Android 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 sau này không chứa 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 bạn gói tất cả thư viện không phải NDK với tệp APK.

Ứng dụng không nên sử dụng 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 khác nhau. Việc chuyển từ OpenSSL sang BoringSSL là một ví dụ về sự thay đổi này. Ngoài ra, do không có yêu cầu nào 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ể có 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 đang được phát hành, bạn có thể tạm thời truy cập vào một nhóm thư viện được sử dụng nhiều (chẳng hạn như libandroid_runtime.so, libcutils.so, libcrypto.solibssl.so) trên Android 7.0 (API cấp độ 24) đối với ứ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 những thư viện này, thì logcat sẽ tạo một 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 như vậy, 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 chỉ sử dụng các 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 các thư viện riêng tư và khiến ứng dụng của bạn gặp sự cố.

Tất cả cá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à System.loadLibrarydlopen(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 của mình để loại bỏ việc sử dụng API nền tảng riêng tư và kiểm thử kỹ lưỡng ứng dụng bằng một thiết bị hoặc trình mô phỏng chạy Android 7.0 (API cấp 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 sẽ thấy trong 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) của ứng dụng đó.

Thư viện Cấp API mục tiêu Quyền truy cập trong thời gian chạy thông qua trình liên kết động Hành vi trên Android 7.0 (API cấp 24) Hành vi trong tương lai của nền tảng Android
NDK công khai Khán giả có Dễ tiếp cận 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 sử dụng được 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
Riêng tư (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 ra 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 API cấp 23 trở xuống và cố gắng truy cập vào một thư viện riêng tư trên một 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 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 API cấp 24 trở lên, thì logcat sẽ tạo 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 có khả năng liên kết động với các API nền tảng riêng tư. Công cụ readelf trong Android 7.0DK 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

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

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

    Lưu ý: Tính sẵn có và nội dung của các thuộc tính hệ thống không được kiểm tra thông qua CTS. 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 libcyrpto.a theo cách tĩnh trong tệp .so hoặc bao gồm một phiên bản được liên kết động của libcrypto.so từ BoringSSL/OpenSSL và đóng gói phiên bản này trong tệp APK.

Android for Work

Android 7.0 có các thay đổi đối với ứng dụng nhắm đến Android for Work, bao gồm các thay đổi về 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, thì bạn nên xem xét những thay đổi này và sửa đổi ứng dụng của mình cho phù hợp.

  • Bạn phải cài đặt một trình cài đặt chứng chỉ được uỷ quyền trước khi DPC có thể thiết lập chứng chỉ đó. Đối với cả ứng dụng của hồ sơ và chủ sở hữu thiết bị nhắm đến Android 7.0 (API cấp 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.
  • Hiện tại, việc đặt lại các hạn chế về mật khẩu cho quản trị viên thiết bị sẽ á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 bạn đặ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 Account Management API (API Quản lý tài khoản) ngay cả khi có các 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ụ dễ dàng hơn. Khi một thiết bị đang chạy ở chế độ chủ sở hữu thiết bị, chế độ 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()createAndInitializeUser() không còn được dùng nữa; mà phương thức DevicePolicyManager.createAndManageUser() mới sẽ thay thế các phương thức đó.
  • Chủ sở hữu thiết bị có thể truy cập vào mã nhận dạng thiết bị. Chủ sở hữu thiết bị có thể truy cập vào địa chỉ Wi-Fi MAC của một thiết bị, bằng cách sử dụng DevicePolicyManager.getWifiMacAddress(). Nếu Wi-Fi chưa từng được bật trên thiết bị, phương thức này sẽ trả về một giá trị null.
  • Cài đặt 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ế độ làm việc đang 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ế độ làm 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ỉ ứng dụng 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 bộ nhớ thông tin xác thực đáng tin cậy. Đ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 phải cài đặt chứng chỉ CA vào bộ nhớ thông tin xác thực đáng tin cậy thông qua giao diện người dùng Cài đặt một cách riêng biệt, với định dạng được mã hoá DER theo đ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 Ứng dụng chính sách thiết bị (DPC) của chủ sở hữu hồ sơ nhắm đến API cấp 23 trở xuống trên một 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 số 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 số của thiết bị. Khi DPC nhắm đến API cấp 24 trở lên, người dùng có thể thiết lập vân tay số dành riêng cho hồ sơ công việc bằng cách chuyển đến phần Settings > Security > Work profile Security (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 quá trình 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 DPC nhắm mục tiêu đến API cấp 24 trở lên. Đối với các ứng dụng nhắm đến các 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 cài đặt hồ sơ công việc kèm theo một thử thách công việc riêng biệt. 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 trong số này, bạn có thể lấy 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 phần tử 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á.

Tỷ lệ giữ chân chú thích

Android 7.0 khắc phục lỗi hiển thị chú thích bị bỏ qua. Vấn đề này cho phép thời gian chạy truy cập vào các chú giải mà lẽ ra không nên 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ành 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, vui lòng thêm chính sách giữ lại dữ liệu vào các chú thích phải có trong thời gian chạy. Bạn thực hiện việc này bằng cách sử dụng @Retention(RetentionPolicy.RUNTIME).

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

Android 7.0 thực hiện các thay đổi sau đây đối với cấu hình TLS/SSL mặc định mà các ứng dụng sử 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 đã tắt.
  • Bộ thuật toán mật mã CHACHA20-POLY1305 hiện đang bật.

RC4 bị tắt theo mặc định có thể gây ra sự cố kết nối HTTPS hoặc TLS/SSL khi máy chủ không thương lượng đượ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ủ để kích hoạt các bộ thuật toán và giao thức mật mã mạnh và hiện đại hơn. Tốt nhất là bạn nên bật TLSv1.2 và AES-GCM và nên 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 cách khác là sửa đổi ứng dụng để dùng một SSLSocketFactory tuỳ chỉnh nhằm giao tiếp với máy chủ. Nhà máy nên đượ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 này về hành vi chỉ áp dụng cho các ứng dụng nhắm đến Android 7.0 (API cấp 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 để hỗ trợ những hành vi này cho phù hợp (nếu phù hợp).

Thay đổi về tuần tự hoá

Android 7.0 (API cấp 24) khắc phục một lỗi khi tính toán serialVersionUID mặc định, trong đó lỗi này 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. Điều này dẫn đến trường hợp ngoại lệ được gửi khi cố gắng giải tuần tự các thực thể của lớp đã được chuyển đổi tuần tự trong phiên bản cũ hoặc được chuyển đổi tuần tự bằng một ứng dụng nhắm đến phiên bản cũ hơn. 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 mọi lớp bị ảnh hưởng có giá trị stream classdesc serialVersionUID trong thông báo lỗi, chẳng hạn như 1234 trong trường hợp này. Thay đổi đó sẽ tuân thủ mọi đề xuất về phương pháp hay để viết mã chuyển đổi tuần tự và sẽ áp dụng được trên mọi 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 động tĩnh, ví dụ: <clinit>. Theo thông số kỹ thuật, việc có hay không có phương thức khởi động tĩnh trong lớp sẽ ảnh hưởng đến serialVersionUID mặc định được tính cho lớp đó. Trước khi sửa lỗi, việc tính toán cũng sẽ kiểm tra lớp cấp cao để 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.

Để làm rõ, thay đổi này không ảnh hưởng đến các ứng dụng nhắm đến API cấp 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 chạy 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 một cấp độ API thấp hơn và người dùng thay đổi kích thước màn hình, thì quy trình của ứng dụng sẽ bị 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ục Gần đây.

    Bạn nên kiểm thử ứng dụng của mình để đảm bảo 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 thông qua DDMS.

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

  • Các ứng dụng trên Android 7.0 có thể xử lý linh hoạt các thay đổi về cấu hình và không 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 kích thước phông chữ (Cài đặt > Hiển thị > Kích thước phông chữ), sau đó khôi phục ứng dụng từ mục Gần đây.
  • Do một lỗi trong các phiên bản Android trước, hệ thống đã không gắn cờ ghi vào cổng 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 thể hiện hành vi này hiện sẽ gửi một android.os.NetworkOnMainThreadException. Nhìn chung, việc thực hiện các hoạt động mạng trên luồng chính là việc không nên làm vì các thao tác này thường có độ trễ cao, gây ra lỗi ANR và giật.
  • Theo mặc định, nhóm phương thức Debug.startMethodTracing() hiện lưu trữ đầu ra trong thư mục dành riêng cho gói của bạn 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 những 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 đang được gửi qua các giao dịch Binder. Hệ thống hiện gửi lại TransactionTooLargeExceptions dưới dạng RuntimeExceptions, thay vì tự động ghi nhật ký hoặc chặn các tải trọng đó. Một ví dụ phổ biến là việc 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 tác vụ Runnable lên ViewView 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; tác vụ Runnable sẽ không thực thi cho đến khi View được đính kèm vào cửa sổ.View Hành vi này khắc phục các lỗi sau:
    • Nếu một ứng dụng được đăng lên View từ một luồng không phải là luồng giao diện người dùng của cửa sổ dự định, 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 lại, 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 tìm cách xoá 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, ứng dụng sẽ nhận STATUS_PENDING_USER_ACTION làm trạng thái trả về khi gọi PackageInstaller.uninstall().
  • Trì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 trình cung cấp này là SHA1PRNG yếu về mặt mã hoá. Các ứng dụng không thể sử dụng SHA1PRNG để lấy khoá (một cách không an toàn) vì trình cung cấp này không còn hoạt động nữa. Để biết thêm thông tin, hãy xem bài đăng trên blog Trình cung cấp dịch vụ bảo mật "Crypto" hiện không còn được dùng trong Android N.