M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions
+16
View File
@@ -0,0 +1,16 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_JAVA_LIBRARIES :=
LOCAL_PACKAGE_NAME := VpnServices
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
########################
include $(call all-makefiles-under,$(LOCAL_PATH))
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.server.vpn"
android:sharedUserId="android.uid.system"
>
<application android:label="@string/app_label">
<service android:name=".VpnServiceBinder" android:process=":remote">
<intent-filter>
<!-- These are the interfaces supported by the service, which
you can bind to. -->
<action android:name="android.net.vpn.IVpnService" />
<!-- This is an action code you can use to select the service
without explicitly supplying the implementation class. -->
<action android:name="android.net.vpn.SERVICE" />
</intent-filter>
</service>
</application>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
</manifest>
+190
View File
@@ -0,0 +1,190 @@
Copyright (c) 2005-2008, The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"خدمات الشبكة الظاهرية الخاصة (VPN)"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"تم توصيل الشبكة الظاهرية الخاصة (VPN) لـ <xliff:g id="PROFILENAME">%s</xliff:g>"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"تم فصل الشبكة الظاهرية الخاصة (VPN) لـ <xliff:g id="PROFILENAME">%s</xliff:g>"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"يمكنك اللمس لإعادة الاتصال بالشبكة الظاهرية الخاصة (VPN)."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"VPN услуги"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"Връзката с VPN <xliff:g id="PROFILENAME">%s</xliff:g> бе установена"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"Връзката с VPN <xliff:g id="PROFILENAME">%s</xliff:g> бе прекъсната"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Докоснете за повторно свързване с VPN."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"Serveis VPN"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"VPN <xliff:g id="PROFILENAME">%s</xliff:g> connectada"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"VPN <xliff:g id="PROFILENAME">%s</xliff:g> desconnectada"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Toqueu-ho per tornar-vos a connectar a una VPN."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"Služby VPN"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"Síť VPN <xliff:g id="PROFILENAME">%s</xliff:g> je připojena"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"Síť VPN <xliff:g id="PROFILENAME">%s</xliff:g> odpojena"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Dotykem se znovu připojíte k síti VPN."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"VPN-tjenester"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"<xliff:g id="PROFILENAME">%s</xliff:g> VPN forbundet"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"<xliff:g id="PROFILENAME">%s</xliff:g> VPN afbrudt"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Tryk for at oprette forbindelse til et VPN igen."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"VPN-Dienste"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"<xliff:g id="PROFILENAME">%s</xliff:g> mit VPN verbunden"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"<xliff:g id="PROFILENAME">%s</xliff:g> von VPN getrennt"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Zur Wiederherstellung der Verbindung mit einem VPN berühren"</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"Υπηρεσίες VPN"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"Το VPN <xliff:g id="PROFILENAME">%s</xliff:g> συνδέθηκε"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"Το VPN <xliff:g id="PROFILENAME">%s</xliff:g> αποσυνδέθηκε"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Πατήστε για να επανασυνδεθείτε σε ένα VPN."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"VPN Services"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"<xliff:g id="PROFILENAME">%s</xliff:g> VPN connected"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"<xliff:g id="PROFILENAME">%s</xliff:g> VPN disconnected"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Touch to reconnect to a VPN."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"Servicios VPN"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"<xliff:g id="PROFILENAME">%s</xliff:g> VPN conectados"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"<xliff:g id="PROFILENAME">%s</xliff:g> VPN desconectada"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Tocar para volver a conectarse a una VPN."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"Servicios VPN"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"VPN <xliff:g id="PROFILENAME">%s</xliff:g> conectada"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"VPN <xliff:g id="PROFILENAME">%s</xliff:g> desconectada"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Toca para volver a conectarte a una red VPN."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"سرویس های VPN"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"<xliff:g id="PROFILENAME">%s</xliff:g> VPN وصل شد"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"<xliff:g id="PROFILENAME">%s</xliff:g> VPN قطع شد"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"برای اتصال مجدد به VPN لمس کنید."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"VPN-palvelut"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"<xliff:g id="PROFILENAME">%s</xliff:g>: VPN-yhteys muodostettu"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"<xliff:g id="PROFILENAME">%s</xliff:g>: VPN-yhteys katkaistu"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Yhdistä VPN-verkkoon uudelleen koskettamalla."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"Services VPN"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"VPN <xliff:g id="PROFILENAME">%s</xliff:g> connecté"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"VPN <xliff:g id="PROFILENAME">%s</xliff:g> déconnecté"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Touchez l\'écran pour vous reconnecter à un VPN."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"VPN usluge"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"<xliff:g id="PROFILENAME">%s</xliff:g> VPN priključen"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"<xliff:g id="PROFILENAME">%s</xliff:g> VPN je isključen"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Dotaknite za ponovno povezivanje s VPN-om."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"VPN-szolgáltatások"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"Kapcsolódva a(z) <xliff:g id="PROFILENAME">%s</xliff:g> virtuális magánhálózathoz"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"Kapcsolat bontva a(z) <xliff:g id="PROFILENAME">%s</xliff:g> virtuális magánhálózattal"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Érintse meg az újracsatlakozáshoz."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"Layanan VPN"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"VPN <xliff:g id="PROFILENAME">%s</xliff:g> terhubung"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"VPN <xliff:g id="PROFILENAME">%s</xliff:g> terputus"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Sentuh untuk terhubung kembali ke suatu VPN."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"Servizi VPN"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"VPN <xliff:g id="PROFILENAME">%s</xliff:g> collegata"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"VPN <xliff:g id="PROFILENAME">%s</xliff:g> scollegata"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Tocca per riconnetterti a una rete VPN."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"שירותי VPN"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"VPN של <xliff:g id="PROFILENAME">%s</xliff:g> מחובר"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"VPN של <xliff:g id="PROFILENAME">%s</xliff:g> נותק"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"גע כדי להתחבר שוב ל-VPN."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"VPNサービス"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"<xliff:g id="PROFILENAME">%s</xliff:g> VPNが接続されました"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"<xliff:g id="PROFILENAME">%s</xliff:g> VPNが切断されました"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"タップしてVPNに再接続してください。"</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"VPN 서비스"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"<xliff:g id="PROFILENAME">%s</xliff:g> VPN 연결됨"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"<xliff:g id="PROFILENAME">%s</xliff:g> VPN 연결 끊김"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"VPN에 다시 연결하려면 터치하세요."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"VPT paslaugos"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"<xliff:g id="PROFILENAME">%s</xliff:g> VPT prijungtas"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"<xliff:g id="PROFILENAME">%s</xliff:g> VPT atjungtas"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Palieskite, kad būtų iš naujo sujungta su VPT."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"VPN pakalpojumi"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"<xliff:g id="PROFILENAME">%s</xliff:g> VPN ir savienots"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"<xliff:g id="PROFILENAME">%s</xliff:g> VPN ir atvienots"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Pieskarieties, lai atkārtoti izveidotu savienojumu ar VPN."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"VPN-tjenester"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"Koblet til VPNet <xliff:g id="PROFILENAME">%s</xliff:g>"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"Koblet fra VPNet <xliff:g id="PROFILENAME">%s</xliff:g>"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Trykk for å koble til et VPN på nytt"</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"VPN-services"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"<xliff:g id="PROFILENAME">%s</xliff:g> verbonden via VPN"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"VPN-verbinding met <xliff:g id="PROFILENAME">%s</xliff:g> verbroken"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Raak aan om opnieuw verbinding te maken met een VPN."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"Usługi VPN"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"Połączono z siecią VPN <xliff:g id="PROFILENAME">%s</xliff:g>"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"Rozłączono z siecią VPN <xliff:g id="PROFILENAME">%s</xliff:g>"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Dotknij, aby ponownie połączyć się z siecią VPN."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"Serviços VPN"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"VPN <xliff:g id="PROFILENAME">%s</xliff:g> ligado"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"VPN <xliff:g id="PROFILENAME">%s</xliff:g> desligado"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Toque para voltar a ligar a uma VPN."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"Serviços de VPN"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"VPN de <xliff:g id="PROFILENAME">%s</xliff:g> conectada"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"VPN de <xliff:g id="PROFILENAME">%s</xliff:g> desconectada"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Toque para reconectar-se a uma VPN."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"Servetschs VPN"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"VPN <xliff:g id="PROFILENAME">%s</xliff:g> connectà"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"VPN <xliff:g id="PROFILENAME">%s</xliff:g> deconnectà"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Tutgar per reconnectar ad in VPN."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"Servicii VPN"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"VPN <xliff:g id="PROFILENAME">%s</xliff:g> conectat"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"VPN <xliff:g id="PROFILENAME">%s</xliff:g> deconectat"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Atingeţi pentru a vă reconecta la o reţea VPN."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"Службы VPN"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"Сеть VPN (<xliff:g id="PROFILENAME">%s</xliff:g>) подключена"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"Сеть VPN (<xliff:g id="PROFILENAME">%s</xliff:g>) отключена"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Нажмите, чтобы повторно подключиться к VPN."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"Služby VPN"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"Sieť VPN <xliff:g id="PROFILENAME">%s</xliff:g> je pripojená"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"Sieť VPN <xliff:g id="PROFILENAME">%s</xliff:g> odpojená"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Dotykom sa znova pripojíte k sieti VPN."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"Storitve VPN"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"VPN profila <xliff:g id="PROFILENAME">%s</xliff:g> je povezan"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"VPN profila <xliff:g id="PROFILENAME">%s</xliff:g> je izklopljen"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Dotaknite se, če želite preklopiti v navidezno zasebno omrežje."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"VPN услуге"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"<xliff:g id="PROFILENAME">%s</xliff:g> VPN веза је успостављена"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"<xliff:g id="PROFILENAME">%s</xliff:g> VPN веза је прекинута"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Додирните да бисте се поново повезали са VPN-ом."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"VPN-tjänster"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"<xliff:g id="PROFILENAME">%s</xliff:g> VPN anslutet"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"<xliff:g id="PROFILENAME">%s</xliff:g> VPN frånkopplat"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Tryck här om du vill återansluta till ett VPN."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"บริการ VPN"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"<xliff:g id="PROFILENAME">%s</xliff:g> เชื่อมต่อ VPN แล้ว"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"<xliff:g id="PROFILENAME">%s</xliff:g> ตัดการเชื่อมต่อ VPN แล้ว"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"แตะเพื่อเชื่อมต่อกับ VPN อีกครั้ง"</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"Mga serbisyo ng VPN"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"Hindi konektado ang <xliff:g id="PROFILENAME">%s</xliff:g> VPN"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"Hindi konektado ang <xliff:g id="PROFILENAME">%s</xliff:g> VPN"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Galawin upang muling kumonekta sa VPN."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"VPN Hizmetleri"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"<xliff:g id="PROFILENAME">%s</xliff:g> VPN bağlandı"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"<xliff:g id="PROFILENAME">%s</xliff:g> VPN bağlantısı kesildi"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Bir VPN\'ye tekrar bağlanmak için dokunun."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"Служби VPN"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"<xliff:g id="PROFILENAME">%s</xliff:g> підключ. ч-з VPN"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"VPN <xliff:g id="PROFILENAME">%s</xliff:g> роз\'єднано"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Натисн. для повт. з\'єдн. з VPN."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"Dịch vụ VPN"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"Đã kết nối VPN <xliff:g id="PROFILENAME">%s</xliff:g>"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"Đã ngắt kết nối VPN <xliff:g id="PROFILENAME">%s</xliff:g>"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Chạm để kết nối lại với VPN."</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"虚拟专用网服务"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"VPN“<xliff:g id="PROFILENAME">%s</xliff:g>”已连接"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"VPN“<xliff:g id="PROFILENAME">%s</xliff:g>”连接已断开"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"轻触可重新连接到虚拟专用网。"</string>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4589592829302498102">"VPN 服務"</string>
<string name="vpn_notification_title_connected" msgid="8598654486956133580">"<xliff:g id="PROFILENAME">%s</xliff:g> VPN 已連線"</string>
<string name="vpn_notification_title_disconnected" msgid="6216572264382192027">"<xliff:g id="PROFILENAME">%s</xliff:g> VPN 已中斷連線"</string>
<string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"輕觸即可重新連線至 VPN。"</string>
</resources>
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Title for the VPN Services activity. -->
<string name="app_label">VPN Services</string>
<string name="vpn_notification_title_connected"><xliff:g id="profilename">%s</xliff:g> VPN connected</string>
<string name="vpn_notification_title_disconnected"><xliff:g id="profilename">%s</xliff:g> VPN disconnected</string>
<string name="vpn_notification_hint_disconnected">Touch to reconnect to a VPN.</string>
</resources>
@@ -0,0 +1,199 @@
/*
* Copyright (C) 2009, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.vpn;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.net.vpn.VpnManager;
import android.os.SystemProperties;
import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
/**
* Proxy to start, stop and interact with a VPN daemon.
* The daemon is expected to accept connection through Unix domain socket.
* When the proxy successfully starts the daemon, it will establish a socket
* connection with the daemon, to both send commands to the daemon and receive
* response and connecting error code from the daemon.
*/
class DaemonProxy implements Serializable {
private static final long serialVersionUID = 1L;
private static final boolean DBG = true;
private static final int WAITING_TIME = 15; // sec
private static final String SVC_STATE_CMD_PREFIX = "init.svc.";
private static final String SVC_START_CMD = "ctl.start";
private static final String SVC_STOP_CMD = "ctl.stop";
private static final String SVC_STATE_RUNNING = "running";
private static final String SVC_STATE_STOPPED = "stopped";
private static final int END_OF_ARGUMENTS = 255;
private String mName;
private String mTag;
private transient LocalSocket mControlSocket;
/**
* Creates a proxy of the specified daemon.
* @param daemonName name of the daemon
*/
DaemonProxy(String daemonName) {
mName = daemonName;
mTag = "SProxy_" + daemonName;
}
String getName() {
return mName;
}
void start() throws IOException {
String svc = mName;
Log.i(mTag, "Start VPN daemon: " + svc);
SystemProperties.set(SVC_START_CMD, svc);
if (!blockUntil(SVC_STATE_RUNNING, WAITING_TIME)) {
throw new IOException("cannot start service: " + svc);
} else {
mControlSocket = createServiceSocket();
}
}
void sendCommand(String ...args) throws IOException {
OutputStream out = getControlSocketOutput();
for (String arg : args) outputString(out, arg);
out.write(END_OF_ARGUMENTS);
out.flush();
int result = getResultFromSocket(true);
if (result != args.length) {
throw new IOException("socket error, result from service: "
+ result);
}
}
// returns 0 if nothing is in the receive buffer
int getResultFromSocket() throws IOException {
return getResultFromSocket(false);
}
void closeControlSocket() {
if (mControlSocket == null) return;
try {
mControlSocket.close();
} catch (IOException e) {
Log.w(mTag, "close control socket", e);
} finally {
mControlSocket = null;
}
}
void stop() {
String svc = mName;
Log.i(mTag, "Stop VPN daemon: " + svc);
SystemProperties.set(SVC_STOP_CMD, svc);
boolean success = blockUntil(SVC_STATE_STOPPED, 5);
if (DBG) Log.d(mTag, "stopping " + svc + ", success? " + success);
}
boolean isStopped() {
String cmd = SVC_STATE_CMD_PREFIX + mName;
return SVC_STATE_STOPPED.equals(SystemProperties.get(cmd));
}
private int getResultFromSocket(boolean blocking) throws IOException {
LocalSocket s = mControlSocket;
if (s == null) return 0;
InputStream in = s.getInputStream();
if (!blocking && in.available() == 0) return 0;
int data = in.read();
Log.i(mTag, "got data from control socket: " + data);
return data;
}
private LocalSocket createServiceSocket() throws IOException {
LocalSocket s = new LocalSocket();
LocalSocketAddress a = new LocalSocketAddress(mName,
LocalSocketAddress.Namespace.RESERVED);
// try a few times in case the service has not listen()ed
IOException excp = null;
for (int i = 0; i < 10; i++) {
try {
s.connect(a);
return s;
} catch (IOException e) {
if (DBG) Log.d(mTag, "service not yet listen()ing; try again");
excp = e;
sleep(500);
}
}
throw excp;
}
private OutputStream getControlSocketOutput() throws IOException {
if (mControlSocket != null) {
return mControlSocket.getOutputStream();
} else {
throw new IOException("no control socket available");
}
}
/**
* Waits for the process to be in the expected state. The method returns
* false if after the specified duration (in seconds), the process is still
* not in the expected state.
*/
private boolean blockUntil(String expectedState, int waitTime) {
String cmd = SVC_STATE_CMD_PREFIX + mName;
int sleepTime = 200; // ms
int n = waitTime * 1000 / sleepTime;
for (int i = 0; i < n; i++) {
if (expectedState.equals(SystemProperties.get(cmd))) {
if (DBG) {
Log.d(mTag, mName + " is " + expectedState + " after "
+ (i * sleepTime) + " msec");
}
break;
}
sleep(sleepTime);
}
return expectedState.equals(SystemProperties.get(cmd));
}
private void outputString(OutputStream out, String s) throws IOException {
byte[] bytes = s.getBytes();
out.write(bytes.length);
out.write(bytes);
out.flush();
}
private void sleep(int msec) {
try {
Thread.currentThread().sleep(msec);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2009, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.vpn;
import android.net.vpn.L2tpIpsecPskProfile;
import java.io.IOException;
/**
* The service that manages the preshared key based L2TP-over-IPSec VPN
* connection.
*/
class L2tpIpsecPskService extends VpnService<L2tpIpsecPskProfile> {
private static final String IPSEC = "racoon";
@Override
protected void connect(String serverIp, String username, String password)
throws IOException {
L2tpIpsecPskProfile p = getProfile();
VpnDaemons daemons = getDaemons();
// IPSEC
daemons.startIpsecForL2tp(serverIp, p.getPresharedKey())
.closeControlSocket();
sleep(2000); // 2 seconds
// L2TP
daemons.startL2tp(serverIp,
(p.isSecretEnabled() ? p.getSecretString() : null),
username, password);
}
}
@@ -0,0 +1,50 @@
/*
* Copyright (C) 2009, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.vpn;
import android.net.vpn.L2tpIpsecProfile;
import android.security.Credentials;
import java.io.IOException;
/**
* The service that manages the certificate based L2TP-over-IPSec VPN connection.
*/
class L2tpIpsecService extends VpnService<L2tpIpsecProfile> {
private static final String IPSEC = "racoon";
@Override
protected void connect(String serverIp, String username, String password)
throws IOException {
L2tpIpsecProfile p = getProfile();
VpnDaemons daemons = getDaemons();
// IPSEC
DaemonProxy ipsec = daemons.startIpsecForL2tp(serverIp,
Credentials.USER_PRIVATE_KEY + p.getUserCertificate(),
Credentials.USER_CERTIFICATE + p.getUserCertificate(),
Credentials.CA_CERTIFICATE + p.getCaCertificate());
ipsec.closeControlSocket();
sleep(2000); // 2 seconds
// L2TP
daemons.startL2tp(serverIp,
(p.isSecretEnabled() ? p.getSecretString() : null),
username, password);
}
}
@@ -0,0 +1,35 @@
/*
* Copyright (C) 2009, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.vpn;
import android.net.vpn.L2tpProfile;
import java.io.IOException;
/**
* The service that manages the L2TP VPN connection.
*/
class L2tpService extends VpnService<L2tpProfile> {
@Override
protected void connect(String serverIp, String username, String password)
throws IOException {
L2tpProfile p = getProfile();
getDaemons().startL2tp(serverIp,
(p.isSecretEnabled() ? p.getSecretString() : null),
username, password);
}
}
@@ -0,0 +1,34 @@
/*
* Copyright (C) 2009, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.vpn;
import android.net.vpn.PptpProfile;
import java.io.IOException;
/**
* The service that manages the PPTP VPN connection.
*/
class PptpService extends VpnService<PptpProfile> {
@Override
protected void connect(String serverIp, String username, String password)
throws IOException {
PptpProfile p = getProfile();
getDaemons().startPptp(serverIp, username, password,
p.isEncryptionEnabled());
}
}
@@ -0,0 +1,35 @@
/*
* Copyright (C) 2009, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.vpn;
import java.io.IOException;
/**
* Exception thrown when a connecting attempt fails.
*/
class VpnConnectingError extends IOException {
private int mErrorCode;
VpnConnectingError(int errorCode) {
super("Connecting error: " + errorCode);
mErrorCode = errorCode;
}
int getErrorCode() {
return mErrorCode;
}
}
@@ -0,0 +1,147 @@
/*
* Copyright (C) 2009, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.vpn;
import android.util.Log;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* A helper class for managing native VPN daemons.
*/
class VpnDaemons implements Serializable {
static final long serialVersionUID = 1L;
private final String TAG = VpnDaemons.class.getSimpleName();
private static final String MTPD = "mtpd";
private static final String IPSEC = "racoon";
private static final String L2TP = "l2tp";
private static final String L2TP_PORT = "1701";
private static final String PPTP = "pptp";
private static final String PPTP_PORT = "1723";
private static final String VPN_LINKNAME = "vpn";
private static final String PPP_ARGS_SEPARATOR = "";
private List<DaemonProxy> mDaemonList = new ArrayList<DaemonProxy>();
public DaemonProxy startL2tp(String serverIp, String secret,
String username, String password) throws IOException {
return startMtpd(L2TP, serverIp, L2TP_PORT, secret, username, password,
false);
}
public DaemonProxy startPptp(String serverIp, String username,
String password, boolean encryption) throws IOException {
return startMtpd(PPTP, serverIp, PPTP_PORT, null, username, password,
encryption);
}
public DaemonProxy startIpsecForL2tp(String serverIp, String pskKey)
throws IOException {
DaemonProxy ipsec = startDaemon(IPSEC);
ipsec.sendCommand(serverIp, L2TP_PORT, pskKey);
return ipsec;
}
public DaemonProxy startIpsecForL2tp(String serverIp, String userKeyKey,
String userCertKey, String caCertKey) throws IOException {
DaemonProxy ipsec = startDaemon(IPSEC);
ipsec.sendCommand(serverIp, L2TP_PORT, userKeyKey, userCertKey,
caCertKey);
return ipsec;
}
public synchronized void stopAll() {
new DaemonProxy(MTPD).stop();
new DaemonProxy(IPSEC).stop();
}
public synchronized void closeSockets() {
for (DaemonProxy s : mDaemonList) s.closeControlSocket();
}
public synchronized boolean anyDaemonStopped() {
for (DaemonProxy s : mDaemonList) {
if (s.isStopped()) {
Log.w(TAG, " VPN daemon gone: " + s.getName());
return true;
}
}
return false;
}
public synchronized int getSocketError() {
for (DaemonProxy s : mDaemonList) {
int errCode = getResultFromSocket(s);
if (errCode != 0) return errCode;
}
return 0;
}
private synchronized DaemonProxy startDaemon(String daemonName)
throws IOException {
DaemonProxy daemon = new DaemonProxy(daemonName);
mDaemonList.add(daemon);
daemon.start();
return daemon;
}
private int getResultFromSocket(DaemonProxy s) {
try {
return s.getResultFromSocket();
} catch (IOException e) {
return -1;
}
}
private DaemonProxy startMtpd(String protocol,
String serverIp, String port, String secret, String username,
String password, boolean encryption) throws IOException {
ArrayList<String> args = new ArrayList<String>();
args.addAll(Arrays.asList(protocol, serverIp, port));
if (secret != null) args.add(secret);
args.add(PPP_ARGS_SEPARATOR);
addPppArguments(args, serverIp, username, password, encryption);
DaemonProxy mtpd = startDaemon(MTPD);
mtpd.sendCommand(args.toArray(new String[args.size()]));
return mtpd;
}
private static void addPppArguments(ArrayList<String> args, String serverIp,
String username, String password, boolean encryption)
throws IOException {
args.addAll(Arrays.asList(
"linkname", VPN_LINKNAME,
"name", username,
"password", password,
"refuse-eap", "nodefaultroute", "usepeerdns",
"idle", "1800",
"mtu", "1400",
"mru", "1400"));
if (encryption) {
args.add("+mppe");
}
}
}
@@ -0,0 +1,486 @@
/*
* Copyright (C) 2009, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.vpn;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.net.vpn.VpnManager;
import android.net.vpn.VpnProfile;
import android.net.vpn.VpnState;
import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.Log;
import java.io.IOException;
import java.io.Serializable;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
/**
* The service base class for managing a type of VPN connection.
*/
abstract class VpnService<E extends VpnProfile> implements Serializable {
static final long serialVersionUID = 1L;
private static final boolean DBG = true;
private static final int NOTIFICATION_ID = 1;
private static final String DNS1 = "net.dns1";
private static final String DNS2 = "net.dns2";
private static final String VPN_DNS1 = "vpn.dns1";
private static final String VPN_DNS2 = "vpn.dns2";
private static final String VPN_STATUS = "vpn.status";
private static final String VPN_IS_UP = "ok";
private static final String VPN_IS_DOWN = "down";
private static final String REMOTE_IP = "net.ipremote";
private static final String DNS_DOMAIN_SUFFICES = "net.dns.search";
private final String TAG = VpnService.class.getSimpleName();
// FIXME: profile is only needed in connecting phase, so we can just save
// the profile name and service class name for recovery
E mProfile;
transient VpnServiceBinder mContext;
private VpnState mState = VpnState.IDLE;
private Throwable mError;
// connection settings
private String mOriginalDns1;
private String mOriginalDns2;
private String mOriginalDomainSuffices;
private String mLocalIp;
private String mLocalIf;
private long mStartTime; // VPN connection start time
// for helping managing daemons
private VpnDaemons mDaemons = new VpnDaemons();
// for helping showing, updating notification
private transient NotificationHelper mNotification;
/**
* Establishes a VPN connection with the specified username and password.
*/
protected abstract void connect(String serverIp, String username,
String password) throws IOException;
/**
* Returns the daemons management class for this service object.
*/
protected VpnDaemons getDaemons() {
return mDaemons;
}
/**
* Returns the VPN profile associated with the connection.
*/
protected E getProfile() {
return mProfile;
}
/**
* Returns the IP address of the specified host name.
*/
protected String getIp(String hostName) throws IOException {
return InetAddress.getByName(hostName).getHostAddress();
}
void setContext(VpnServiceBinder context, E profile) {
mProfile = profile;
recover(context);
}
void recover(VpnServiceBinder context) {
mContext = context;
mNotification = new NotificationHelper();
if (VpnState.CONNECTED.equals(mState)) {
Log.i("VpnService", " recovered: " + mProfile.getName());
startConnectivityMonitor();
}
}
VpnState getState() {
return mState;
}
synchronized boolean onConnect(String username, String password) {
try {
setState(VpnState.CONNECTING);
mDaemons.stopAll();
String serverIp = getIp(getProfile().getServerName());
saveLocalIpAndInterface(serverIp);
onBeforeConnect();
connect(serverIp, username, password);
waitUntilConnectedOrTimedout();
return true;
} catch (Throwable e) {
onError(e);
return false;
}
}
synchronized void onDisconnect() {
try {
Log.i(TAG, "disconnecting VPN...");
setState(VpnState.DISCONNECTING);
mNotification.showDisconnect();
mDaemons.stopAll();
} catch (Throwable e) {
Log.e(TAG, "onDisconnect()", e);
} finally {
onFinalCleanUp();
}
}
private void onError(Throwable error) {
// error may occur during or after connection setup
// and it may be due to one or all services gone
if (mError != null) {
Log.w(TAG, " multiple errors occur, record the last one: "
+ error);
}
Log.e(TAG, "onError()", error);
mError = error;
onDisconnect();
}
private void onError(int errorCode) {
onError(new VpnConnectingError(errorCode));
}
private void onBeforeConnect() throws IOException {
mNotification.disableNotification();
SystemProperties.set(VPN_DNS1, "");
SystemProperties.set(VPN_DNS2, "");
SystemProperties.set(VPN_STATUS, VPN_IS_DOWN);
if (DBG) {
Log.d(TAG, " VPN UP: " + SystemProperties.get(VPN_STATUS));
}
}
private void waitUntilConnectedOrTimedout() throws IOException {
sleep(2000); // 2 seconds
for (int i = 0; i < 80; i++) {
if (mState != VpnState.CONNECTING) {
break;
} else if (VPN_IS_UP.equals(
SystemProperties.get(VPN_STATUS))) {
onConnected();
return;
} else {
int err = mDaemons.getSocketError();
if (err != 0) {
onError(err);
return;
}
}
sleep(500); // 0.5 second
}
if (mState == VpnState.CONNECTING) {
onError(new IOException("Connecting timed out"));
}
}
private synchronized void onConnected() throws IOException {
if (DBG) Log.d(TAG, "onConnected()");
mDaemons.closeSockets();
saveOriginalDns();
saveAndSetDomainSuffices();
mStartTime = System.currentTimeMillis();
// Correct order to make sure VpnService doesn't break when killed:
// (1) set state to CONNECTED
// (2) save states
// (3) set DNS
setState(VpnState.CONNECTED);
saveSelf();
setVpnDns();
startConnectivityMonitor();
}
private void saveSelf() throws IOException {
mContext.saveStates();
}
private synchronized void onFinalCleanUp() {
if (DBG) Log.d(TAG, "onFinalCleanUp()");
if (mState == VpnState.IDLE) return;
// keep the notification when error occurs
if (!anyError()) mNotification.disableNotification();
restoreOriginalDns();
restoreOriginalDomainSuffices();
setState(VpnState.IDLE);
// stop the service itself
SystemProperties.set(VPN_STATUS, VPN_IS_DOWN);
mContext.removeStates();
mContext.stopSelf();
}
private boolean anyError() {
return (mError != null);
}
private void restoreOriginalDns() {
// restore only if they are not overridden
String vpnDns1 = SystemProperties.get(VPN_DNS1);
if (vpnDns1.equals(SystemProperties.get(DNS1))) {
Log.i(TAG, String.format("restore original dns prop: %s --> %s",
SystemProperties.get(DNS1), mOriginalDns1));
Log.i(TAG, String.format("restore original dns prop: %s --> %s",
SystemProperties.get(DNS2), mOriginalDns2));
SystemProperties.set(DNS1, mOriginalDns1);
SystemProperties.set(DNS2, mOriginalDns2);
}
}
private void saveOriginalDns() {
mOriginalDns1 = SystemProperties.get(DNS1);
mOriginalDns2 = SystemProperties.get(DNS2);
Log.i(TAG, String.format("save original dns prop: %s, %s",
mOriginalDns1, mOriginalDns2));
}
private void setVpnDns() {
String vpnDns1 = SystemProperties.get(VPN_DNS1);
String vpnDns2 = SystemProperties.get(VPN_DNS2);
SystemProperties.set(DNS1, vpnDns1);
SystemProperties.set(DNS2, vpnDns2);
Log.i(TAG, String.format("set vpn dns prop: %s, %s",
vpnDns1, vpnDns2));
}
private void saveAndSetDomainSuffices() {
mOriginalDomainSuffices = SystemProperties.get(DNS_DOMAIN_SUFFICES);
Log.i(TAG, "save original suffices: " + mOriginalDomainSuffices);
String list = mProfile.getDomainSuffices();
if (!TextUtils.isEmpty(list)) {
SystemProperties.set(DNS_DOMAIN_SUFFICES, list);
}
}
private void restoreOriginalDomainSuffices() {
Log.i(TAG, "restore original suffices --> " + mOriginalDomainSuffices);
SystemProperties.set(DNS_DOMAIN_SUFFICES, mOriginalDomainSuffices);
}
private void setState(VpnState newState) {
mState = newState;
broadcastConnectivity(newState);
}
private void broadcastConnectivity(VpnState s) {
VpnManager m = new VpnManager(mContext);
Throwable err = mError;
if ((s == VpnState.IDLE) && (err != null)) {
if (err instanceof UnknownHostException) {
m.broadcastConnectivity(mProfile.getName(), s,
VpnManager.VPN_ERROR_UNKNOWN_SERVER);
} else if (err instanceof VpnConnectingError) {
m.broadcastConnectivity(mProfile.getName(), s,
((VpnConnectingError) err).getErrorCode());
} else if (VPN_IS_UP.equals(SystemProperties.get(VPN_STATUS))) {
m.broadcastConnectivity(mProfile.getName(), s,
VpnManager.VPN_ERROR_CONNECTION_LOST);
} else {
m.broadcastConnectivity(mProfile.getName(), s,
VpnManager.VPN_ERROR_CONNECTION_FAILED);
}
} else {
m.broadcastConnectivity(mProfile.getName(), s);
}
}
private void startConnectivityMonitor() {
new Thread(new Runnable() {
public void run() {
Log.i(TAG, "VPN connectivity monitor running");
try {
for (int i = 10; ; i--) {
long now = System.currentTimeMillis();
boolean heavyCheck = i == 0;
synchronized (VpnService.this) {
if (mState != VpnState.CONNECTED) break;
mNotification.update(now);
if (heavyCheck) {
i = 10;
if (checkConnectivity()) checkDns();
}
long t = 1000L - System.currentTimeMillis() + now;
if (t > 100L) VpnService.this.wait(t);
}
}
} catch (InterruptedException e) {
onError(e);
}
Log.i(TAG, "VPN connectivity monitor stopped");
}
}).start();
}
private void saveLocalIpAndInterface(String serverIp) throws IOException {
DatagramSocket s = new DatagramSocket();
int port = 80; // arbitrary
s.connect(InetAddress.getByName(serverIp), port);
InetAddress localIp = s.getLocalAddress();
mLocalIp = localIp.getHostAddress();
NetworkInterface localIf = NetworkInterface.getByInetAddress(localIp);
mLocalIf = (localIf == null) ? null : localIf.getName();
if (TextUtils.isEmpty(mLocalIf)) {
throw new IOException("Local interface is empty!");
}
if (DBG) {
Log.d(TAG, " Local IP: " + mLocalIp + ", if: " + mLocalIf);
}
}
// returns false if vpn connectivity is broken
private boolean checkConnectivity() {
if (mDaemons.anyDaemonStopped() || isLocalIpChanged()) {
onError(new IOException("Connectivity lost"));
return false;
} else {
return true;
}
}
private void checkDns() {
String dns1 = SystemProperties.get(DNS1);
String vpnDns1 = SystemProperties.get(VPN_DNS1);
if (!dns1.equals(vpnDns1) && dns1.equals(mOriginalDns1)) {
// dhcp expires?
setVpnDns();
}
}
private boolean isLocalIpChanged() {
try {
InetAddress localIp = InetAddress.getByName(mLocalIp);
NetworkInterface localIf =
NetworkInterface.getByInetAddress(localIp);
if (localIf == null || !mLocalIf.equals(localIf.getName())) {
Log.w(TAG, " local If changed from " + mLocalIf
+ " to " + localIf);
return true;
} else {
return false;
}
} catch (IOException e) {
Log.w(TAG, "isLocalIpChanged()", e);
return true;
}
}
protected void sleep(int ms) {
try {
Thread.currentThread().sleep(ms);
} catch (InterruptedException e) {
}
}
private class DaemonHelper implements Serializable {
}
// Helper class for showing, updating notification.
private class NotificationHelper {
void update(long now) {
String title = getNotificationTitle(true);
Notification n = new Notification(R.drawable.vpn_connected, title,
mStartTime);
n.setLatestEventInfo(mContext, title,
getConnectedNotificationMessage(now),
prepareNotificationIntent());
n.flags |= Notification.FLAG_NO_CLEAR;
n.flags |= Notification.FLAG_ONGOING_EVENT;
enableNotification(n);
}
void showDisconnect() {
String title = getNotificationTitle(false);
Notification n = new Notification(R.drawable.vpn_disconnected,
title, System.currentTimeMillis());
n.setLatestEventInfo(mContext, title,
getDisconnectedNotificationMessage(),
prepareNotificationIntent());
n.flags |= Notification.FLAG_AUTO_CANCEL;
disableNotification();
enableNotification(n);
}
void disableNotification() {
((NotificationManager) mContext.getSystemService(
Context.NOTIFICATION_SERVICE)).cancel(NOTIFICATION_ID);
}
private void enableNotification(Notification n) {
((NotificationManager) mContext.getSystemService(
Context.NOTIFICATION_SERVICE)).notify(NOTIFICATION_ID, n);
}
private PendingIntent prepareNotificationIntent() {
return PendingIntent.getActivity(mContext, 0,
new VpnManager(mContext).createSettingsActivityIntent(), 0);
}
private String getNotificationTitle(boolean connected) {
String formatString = connected
? mContext.getString(
R.string.vpn_notification_title_connected)
: mContext.getString(
R.string.vpn_notification_title_disconnected);
return String.format(formatString, mProfile.getName());
}
private String getFormattedTime(int duration) {
int hours = duration / 3600;
StringBuilder sb = new StringBuilder();
if (hours > 0) sb.append(hours).append(':');
sb.append(String.format("%02d:%02d", (duration % 3600 / 60),
(duration % 60)));
return sb.toString();
}
private String getConnectedNotificationMessage(long now) {
return getFormattedTime((int) (now - mStartTime) / 1000);
}
private String getDisconnectedNotificationMessage() {
return mContext.getString(
R.string.vpn_notification_hint_disconnected);
}
}
}
@@ -0,0 +1,188 @@
/*
* Copyright (C) 2009, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.vpn;
import android.app.Service;
import android.content.Intent;
import android.net.vpn.IVpnService;
import android.net.vpn.L2tpIpsecProfile;
import android.net.vpn.L2tpIpsecPskProfile;
import android.net.vpn.L2tpProfile;
import android.net.vpn.PptpProfile;
import android.net.vpn.VpnManager;
import android.net.vpn.VpnProfile;
import android.net.vpn.VpnState;
import android.os.Environment;
import android.os.IBinder;
import android.os.SystemProperties;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* The service class for managing a VPN connection. It implements the
* {@link IVpnService} binder interface.
*/
public class VpnServiceBinder extends Service {
private static final String TAG = VpnServiceBinder.class.getSimpleName();
private static final boolean DBG = true;
private static final String STATES_FILE_RELATIVE_PATH = "/misc/vpn/.states";
// The actual implementation is delegated to the VpnService class.
private VpnService<? extends VpnProfile> mService;
// TODO(oam): Test VPN when EFS is enabled (will do later)...
private static String getStateFilePath() {
// This call will return the correcu directory whether Encrypted FS is enabled or not
// Disabled: /data/misc/vpn/.states Enabled: /data/secure/misc/vpn/.states
return Environment.getSecureDataDirectory().getPath() + STATES_FILE_RELATIVE_PATH;
}
private final IBinder mBinder = new IVpnService.Stub() {
public boolean connect(VpnProfile p, String username, String password) {
return VpnServiceBinder.this.connect(p, username, password);
}
public void disconnect() {
VpnServiceBinder.this.disconnect();
}
public void checkStatus(VpnProfile p) {
VpnServiceBinder.this.checkStatus(p);
}
};
@Override
public void onCreate() {
super.onCreate();
checkSavedStates();
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
void saveStates() throws IOException {
if (DBG) Log.d("VpnServiceBinder", " saving states");
ObjectOutputStream oos =
new ObjectOutputStream(new FileOutputStream(getStateFilePath()));
oos.writeObject(mService);
oos.close();
}
void removeStates() {
try {
File f = new File(getStateFilePath());
if (f.exists()) f.delete();
} catch (Throwable e) {
if (DBG) Log.d("VpnServiceBinder", " remove states: " + e);
}
}
private synchronized boolean connect(final VpnProfile p,
final String username, final String password) {
if (mService != null) return false;
final VpnService s = mService = createService(p);
new Thread(new Runnable() {
public void run() {
s.onConnect(username, password);
}
}).start();
return true;
}
private synchronized void disconnect() {
if (mService == null) return;
final VpnService s = mService;
new Thread(new Runnable() {
public void run() {
s.onDisconnect();
}
}).start();
}
private synchronized void checkStatus(VpnProfile p) {
if ((mService == null)
|| (!p.getName().equals(mService.mProfile.getName()))) {
broadcastConnectivity(p.getName(), VpnState.IDLE);
} else {
broadcastConnectivity(p.getName(), mService.getState());
}
}
private void checkSavedStates() {
try {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
getStateFilePath()));
mService = (VpnService<? extends VpnProfile>) ois.readObject();
mService.recover(this);
ois.close();
} catch (FileNotFoundException e) {
// do nothing
} catch (Throwable e) {
Log.i("VpnServiceBinder", "recovery error, remove states: " + e);
removeStates();
}
}
private VpnService<? extends VpnProfile> createService(VpnProfile p) {
switch (p.getType()) {
case L2TP:
L2tpService l2tp = new L2tpService();
l2tp.setContext(this, (L2tpProfile) p);
return l2tp;
case PPTP:
PptpService pptp = new PptpService();
pptp.setContext(this, (PptpProfile) p);
return pptp;
case L2TP_IPSEC_PSK:
L2tpIpsecPskService psk = new L2tpIpsecPskService();
psk.setContext(this, (L2tpIpsecPskProfile) p);
return psk;
case L2TP_IPSEC:
L2tpIpsecService l2tpIpsec = new L2tpIpsecService();
l2tpIpsec.setContext(this, (L2tpIpsecProfile) p);
return l2tpIpsec;
default:
return null;
}
}
private void broadcastConnectivity(String name, VpnState s) {
new VpnManager(this).broadcastConnectivity(name, s);
}
}