Vì sao ứng dụng Android của bạn không thể thêm hồ sơ VPN hệ thống
VpnService tạo một đường hầm thuộc về ứng dụng của bạn; nó không thể thêm hay sửa các mục PPTP, L2TP hoặc IPsec của điện thoại. Đi theo ranh giới và chọn đúng con đường.
Bạn chạm vào hàng VPN trong Cài đặt, thấy một hồ sơ do người khác cài, và bắt đầu tìm lệnh gọi thêm một hồ sơ. Không có lệnh gọi đó. Ứng dụng có thể mở đường hầm của riêng nó qua VpnService, nhưng các mục trong danh sách đó thuộc về nền tảng và thuộc về ứng dụng khách đã tạo ra chúng. Biết chính xác ranh giới nằm ở đâu giúp bạn tiết kiệm một tuần rượt đuổi các lớp ẩn.
Bắt đầu từ những gì màn hình Cài đặt hiển thị
Danh sách VPN là sổ đăng ký các hồ sơ do hệ thống hoặc ứng dụng khách của nhà sản xuất cài: PPTP, L2TP/IPsec, IKEv2 và những hàng do ứng dụng OEM hoặc MDM đẩy vào. Mỗi hàng mang một địa chỉ máy chủ, thông tin đăng nhập và một bản triển khai giao thức sống ngoài tiến trình của bạn. Khi người dùng chạm Kết nối ở đó, ứng dụng khách của nền tảng mới dựng đường hầm, không phải mã của bạn. Đó là lý do hàng đó tồn tại sau khi khởi động lại và lý do gỡ cài đặt ứng dụng của bạn không bao giờ xóa nó.
Từ phía người dùng, danh sách trông như một bề mặt API, một nơi mà việc thêm VPN chỉ cách một intent. Không phải vậy. Các điểm vào công khai duy nhất chạm tới nó là các intent điều hướng, và mọi thứ ghi vào đó đều thuộc về nền tảng hoặc một thành phần đặc quyền.
Hệ quả thực tế: nếu một văn bản hỗ trợ bảo người dùng thêm hồ sơ trong Cài đặt, thì ứng dụng của bạn hoàn toàn không phải một phần của luồng đó.
VpnService thực sự cho bạn những gì
VpnService và VpnService.Builder mô tả một đường hầm thuộc về ứng dụng của bạn. Bạn thêm địa chỉ, tuyến, máy chủ DNS và MTU, giới hạn lưu lượng bằng addAllowedApplication() hoặc addDisallowedApplication(), rồi establish() trả về một ParcelFileDescriptor cho giao diện TUN. Từ điểm đó ứng dụng đọc gói IP và ghi phản hồi, nghĩa là giao thức là của bạn để triển khai hoặc nhúng: OpenVPN, WireGuard, một phương thức truyền tùy chỉnh.
Không có gì trong trình tự đó nói PPTP, L2TP/IPsec hay IKEv2. Builder không có công tắc nào nói hãy dùng ứng dụng khách L2TP của hệ thống, và không có callback nào cho phép bạn điều khiển một hồ sơ mà nền tảng đã sở hữu. Đó là ranh giới thật, và đó là ranh giới thiết kế chứ không phải lỗ hổng quyền.
Vậy nên một ứng dụng hoàn toàn có thể là ứng dụng khách VPN trên Android. Chỉ là nó không thể là người quản lý cho các ứng dụng khách đi kèm điện thoại.
Hộp thoại đồng ý không phải đồ trang trí
Vì đường hầm của bạn có thể bắt lưu lượng của ứng dụng khác, hệ thống buộc người dùng phải chấp thuận rõ ràng. prepare() trả về một Intent mà bạn phải khởi chạy, sự chấp thuận gắn với gói của bạn, và khi đường hầm đang chạy thanh trạng thái hiển thị một chỉ báo thường trực. Một VPN thứ hai dựng lên sẽ hủy kích hoạt cái thứ nhất, vì Android chạy một VPN hoạt động tại một thời điểm.
Quy tắc chỉ một cái hoạt động đó làm người ta vấp khi kiểm thử. Bạn dựng đường hầm trong khi một ứng dụng khách doanh nghiệp đang kết nối và kết luận mã của bạn hỏng, trong khi nền tảng chỉ đơn giản chuyển khỏi ứng dụng khách kia. Các chấp thuận có thể bị thu hồi sau này, và prepare() có thể trả về null trên thiết bị thiếu hoạt động đồng ý, nên establish() vẫn phải xử lý thất bại.
API ẩn và intent cài đặt
Các câu trả lời cũ trỏ tới lớp com.android.internal và giao diện AIDL mà ứng dụng khách tích hợp dùng. Chúng không có trong SDK, thay đổi giữa các bản phát hành mà không báo trước, và cửa hàng ứng dụng coi việc truy cập đó là rủi ro. Root thiết bị cũng không làm chúng ổn định, vì root và truy cập API ẩn là hai vấn đề không liên quan.
Trợ giúp điều hướng được hỗ trợ là Settings.ACTION_VPN_SETTINGS, có giá trị là android.net.vpn.SETTINGS. Hãy phân giải nó trước khi khởi chạy, vì một số bản dựng OEM không cung cấp hoạt động đó, và chuyển sang các bước bằng văn bản khi phân giải thất bại. Nó đưa người dùng tới màn hình và không cấu hình gì cả.
Các đường chủ sở hữu thiết bị và MDM là ngoại lệ mà người ta thường muốn nói. DevicePolicyManager có thể chỉ định một gói VPN luôn bật, và cấu hình được quản lý có thể tải trước cài đặt cho một ứng dụng khách hỗ trợ chúng, nhưng đó vẫn chưa phải SDK công khai soạn hồ sơ PPTP.
Đi qua quyết định từ phía người dùng
Nếu sản phẩm của bạn phải mang lưu lượng, hãy lên kế hoạch cho VpnService cùng một ngăn xếp giao thức thật, và dành thời gian cho luồng chấp thuận và quy tắc một VPN. Nếu mục tiêu là kết nối tới một hồ sơ doanh nghiệp sẵn có, công việc của bạn là hướng dẫn: liên kết sâu tới màn hình cài đặt, ghi tài liệu các trường, và để ứng dụng khách của nền tảng làm việc tạo đường hầm. Nếu ứng dụng chỉ cần tới một điểm cuối riêng, nó không cần đường hầm riêng chút nào.
Hãy viết quyết định đó ra trước khi viết mã, vì ba con đường gần như không có gì chung sau sprint đầu tiên.
Một lần kiểm tra cuối trước khi bắt đầu: yêu cầu nói ứng dụng của chúng ta kết nối hay thiết bị kết nối? Cái đầu là VpnService, cái sau là hồ sơ bạn không thể tạo. Viết đúng câu đó rẻ hơn mọi lần tái cấu trúc.