├── .gitignore ├── .gitmodules ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── scopes │ └── scope_settings.xml └── vcs.xml ├── AndroidSIMFileReader.iml ├── README.md ├── app ├── .gitignore ├── app.iml ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── net │ │ └── scintill │ │ └── simfilereader │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── aidl │ │ └── net │ │ │ └── scintill │ │ │ └── simio │ │ │ └── IRilExtender.aidl │ ├── java │ │ ├── android │ │ │ └── os │ │ │ │ ├── AsyncResult.java │ │ │ │ ├── Registrant.java │ │ │ │ └── RegistrantList.java │ │ ├── com │ │ │ └── SecUpwN │ │ │ │ └── AIMSICD │ │ │ │ └── utils │ │ │ │ ├── CMDProcessor.java │ │ │ │ ├── ChildProcess.java │ │ │ │ ├── CommandResult.java │ │ │ │ ├── Helpers.java │ │ │ │ └── atcmd │ │ │ │ ├── AtCommandTerminal.java │ │ │ │ ├── TtyPrivFile.java │ │ │ │ └── TtyStream.java │ │ └── net │ │ │ └── scintill │ │ │ ├── simfilereader │ │ │ └── MyActivity.java │ │ │ └── simio │ │ │ ├── AtCommandInterface.java │ │ │ ├── CardApplication.java │ │ │ ├── CommandsInterfaceFactory.java │ │ │ ├── RilExtender.java │ │ │ ├── RilExtenderCommandsInterface.java │ │ │ ├── TelephonySeekServiceCommandsInterface.java │ │ │ └── telephony │ │ │ ├── CommandsInterface.java │ │ │ ├── EncodeException.java │ │ │ ├── GsmAlphabet.java │ │ │ ├── MccTable.java │ │ │ ├── SmsConstants.java │ │ │ ├── TelephonyProperties.java │ │ │ ├── cdma │ │ │ └── sms │ │ │ │ └── UserData.java │ │ │ ├── gsm │ │ │ └── SimTlv.java │ │ │ └── uicc │ │ │ ├── AdnRecord.java │ │ │ ├── AdnRecordLoader.java │ │ │ ├── CsimFileHandler.java │ │ │ ├── IccCardApplicationStatus.java │ │ │ ├── IccCardStatus.java │ │ │ ├── IccConstants.java │ │ │ ├── IccException.java │ │ │ ├── IccFileHandler.java │ │ │ ├── IccFileNotFound.java │ │ │ ├── IccFileTypeMismatch.java │ │ │ ├── IccIoResult.java │ │ │ ├── IccRecords.java │ │ │ ├── IccRefreshResponse.java │ │ │ ├── IccUtils.java │ │ │ ├── IccVmFixedException.java │ │ │ ├── IccVmNotSupportedException.java │ │ │ ├── IsimFileHandler.java │ │ │ ├── IsimRecords.java │ │ │ ├── IsimUiccRecords.java │ │ │ ├── RuimFileHandler.java │ │ │ ├── RuimRecords.java │ │ │ ├── SIMFileHandler.java │ │ │ ├── SIMRecords.java │ │ │ ├── UiccCardApplication.java │ │ │ └── UsimFileHandler.java │ └── res │ │ ├── drawable-hdpi │ │ └── ic_launcher.png │ │ ├── drawable-mdpi │ │ └── ic_launcher.png │ │ ├── drawable-xhdpi │ │ └── ic_launcher.png │ │ ├── drawable-xxhdpi │ │ └── ic_launcher.png │ │ ├── icon.svg │ │ ├── layout │ │ └── activity_my.xml │ │ ├── menu │ │ └── my.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── native │ └── rilinject │ └── jni │ ├── Android.mk │ └── rilinject.c ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "app/src/native/adbi"] 2 | path = app/src/native/adbi 3 | url = https://github.com/crmulliner/adbi 4 | [submodule "app/src/native/ddi"] 5 | path = app/src/native/ddi 6 | url = https://github.com/scintill/ddi 7 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | SIMFileSEEKTest -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | Android API 20 Platform 14 | 15 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/scopes/scope_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AndroidSIMFileReader.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Android SIM File Reader 2 | 3 | This is an app to demonstrate reading SIM files in Android, with several methods. They are: using the SEEK API, injecting a new service implementation into the phone process, and AT/Hayes commands. 4 | 5 | The app uses a [factory method](https://github.com/scintill/AndroidSIMFileReader/blob/fd78417e10d5d0db74819b0057f740a444f701e9/app/src/main/java/net/scintill/simio/CommandsInterfaceFactory.java#L39) to transparently find a working interface to do SIM I/O. The code to locate and parse the SIM files is mostly lifted from CyanogenMod (though AOSP code should be pretty much the same), with my SIM I/O classes taking the place of the RIL class that these classes were written to use. 6 | 7 | ## SEEK API 8 | 9 | This refers to [Secure Element Evaluation Kit for the Android platform](https://code.google.com/p/seek-for-android/). You may not need the patches from this project, because it seems to have been merged into several Android distributions. This app does not use or need the official SEEK service APK, it directly invokes the backend methods in the telephony service. This is necessary to circumvent permissions checking, and is also useful for CyanogenMod 11, which does not seem to have a working OpenMobile service, but does have the SEEK patches. Implemented [here](https://github.com/scintill/AndroidSIMFileReader/blob/fd78417e10d5d0db74819b0057f740a444f701e9/app/src/main/java/net/scintill/simio/TelephonySeekServiceCommandsInterface.java). 10 | 11 | ## Injected service 12 | 13 | The code in the `com.android.phone` process is hot-patched using [ddi](https://github.com/crmulliner/ddi) to allow new service calls for invoking the SIM I/O methods the RIL class has (which is how Android reads your phone number, voicemail number, etc. from the SIM.) Should be fairly compatible, but it uses so much undocumented/private behavior that it can't really be guaranteed. I recommend killing your `com.android.phone` process (it will restart), to flush out my code, when you're done using it. Client side [here](https://github.com/scintill/AndroidSIMFileReader/blob/fd78417e10d5d0db74819b0057f740a444f701e9/app/src/main/java/net/scintill/simio/RilExtenderCommandsInterface.java), remote (in phone process) Java part [here](https://github.com/scintill/AndroidSIMFileReader/blob/fd78417e10d5d0db74819b0057f740a444f701e9/app/src/main/java/net/scintill/simio/RilExtender.java), native glue [here](https://github.com/scintill/AndroidSIMFileReader/blob/fd78417e10d5d0db74819b0057f740a444f701e9/app/src/native/rilinject/jni/rilinject.c). 14 | 15 | ## AT Commands 16 | 17 | Compatibility is probably quite limited right now, but this works on my own Qualcomm device. AT commands are sent to the `/dev/smd7` device, and responses are read and parsed. It is a bit fragile; sometimes the superuser'd processes that read/write to the device don't terminate correctly, meaning the next time the app runs it won't be able to connect to the device correctly, and may hang or crash. SIM I/O interface [here](https://github.com/scintill/AndroidSIMFileReader/blob/fd78417e10d5d0db74819b0057f740a444f701e9/app/src/main/java/net/scintill/simio/AtCommandInterface.java), general AT command interface [here](https://github.com/scintill/AndroidSIMFileReader/tree/fd78417e10d5d0db74819b0057f740a444f701e9/app/src/main/java/com/SecUpwN/AIMSICD/utils/atcmd). 18 | 19 | ## Other unimplemented methods 20 | 21 | ### TelephonyManager.iccExchangeSimIO() 22 | 23 | Android 5.0 appears to have introduced a public [iccExchangeSimIO\(\)](https://developer.android.com/reference/android/telephony/TelephonyManager.html#iccExchangeSimIO\(int, int, int, int, int, java.lang.String\)) API. I haven't tried it, but it looks like it can do what we need. It requires privileges, but that shouldn't be a problem. 24 | 25 | ## Privacy 26 | 27 | There are several places where potentially sensitive information (your phone number, your [TMSI](https://en.wikipedia.org/wiki/Mobility_management#TMSI), your [LAI](https://en.wikipedia.org/wiki/Location_area_identity)) is sent to `logcat`. Beware, other apps or users could view this log and learn these data about your phone/SIM card. 28 | 29 | ## Building 30 | 31 | Something is wrong with the build process. To reliably build the RilExtender (injected service), you have to build twice. The first build doesn't properly package the secondary dex file in to the app. 32 | 33 | ## Logs 34 | 35 | Example logcat command to filter to output from this app (also shown on the app's screen): 36 | 37 | adb logcat -s SIMFileReader,RilExtender,RilExtenderCommandsInterface,AtCommandInterface,CommandsInterfaceFactory,TelephonySeekServiceCommandsInterface,SIMRecords,Parcel,librilinject,CMDProcessor,lib__hijack.bin__.so,System.err,su 38 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | def BUILD_TOOLS_VERSION = '19.1.0' 4 | android { 5 | compileSdkVersion 19 6 | buildToolsVersion BUILD_TOOLS_VERSION 7 | 8 | defaultConfig { 9 | applicationId "net.scintill.simfilereader" 10 | minSdkVersion 15 11 | targetSdkVersion 20 12 | versionCode 1 13 | versionName "1.0" 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | compileOptions { 22 | sourceCompatibility JavaVersion.VERSION_1_7 23 | targetCompatibility JavaVersion.VERSION_1_7 24 | } 25 | sourceSets.main.jniLibs.srcDirs = ['build/native/bin'] 26 | } 27 | 28 | dependencies { 29 | compile fileTree(dir: 'libs', include: ['*.jar']) 30 | } 31 | 32 | // https://stackoverflow.com/questions/21999829/how-do-i-read-properties-defined-in-local-properties-in-build-gradle 33 | Properties properties = new Properties() 34 | properties.load(project.rootProject.file('local.properties').newDataInputStream()) 35 | def ndkDir = properties.getProperty('ndk.dir') 36 | def sdkDir = properties.getProperty('sdk.dir') 37 | 38 | task rilExtenderNdkBuild << { 39 | // https://stackoverflow.com/questions/16667903/android-studio-gradle-and-ndk 40 | 41 | task("nativeHijackBuild", type: Exec) { 42 | commandLine "$ndkDir/ndk-build", '--directory', "$projectDir/src/native/adbi/hijack/jni", 43 | "APP_PLATFORM=android-14", 44 | "NDK_OUT=$buildDir/native/obj", 45 | "NDK_APP_DST_DIR=$buildDir/native/bin/\$(TARGET_ARCH_ABI)" 46 | standardOutput = new OutputStream() { public void write(int b) throws IOException {} } 47 | }.execute() 48 | 49 | task("nativeInstrumentsBaseBuild", type: Exec) { 50 | commandLine "$ndkDir/ndk-build", '--directory', "$projectDir/src/native/adbi/instruments/base/jni", 51 | "APP_PLATFORM=android-14", 52 | "NDK_OUT=$buildDir/native/obj", 53 | "NDK_APP_DST_DIR=$buildDir/native/bin/\$(TARGET_ARCH_ABI)" 54 | standardOutput = new OutputStream() { public void write(int b) throws IOException {} } 55 | }.execute() 56 | 57 | task("nativeDalvikHookBuild", type: Exec) { 58 | commandLine "$ndkDir/ndk-build", '--directory', "$projectDir/src/native/ddi/dalvikhook/jni", 59 | "APP_PLATFORM=android-14", 60 | "NDK_OUT=$buildDir/native/obj", 61 | "NDK_APP_DST_DIR=$buildDir/native/bin/\$(TARGET_ARCH_ABI)" 62 | standardOutput = new OutputStream() { public void write(int b) throws IOException {} } 63 | }.execute() 64 | 65 | task("nativeRilInjectBuild", type: Exec) { 66 | commandLine "$ndkDir/ndk-build", '--directory', "$projectDir/src/native/rilinject/jni", 67 | "APP_PLATFORM=android-14", 68 | "NDK_OUT=$buildDir/native/obj", 69 | "NDK_APP_DST_DIR=$buildDir/native/bin/\$(TARGET_ARCH_ABI)" 70 | standardOutput = new OutputStream() { public void write(int b) throws IOException {} } 71 | }.execute() 72 | 73 | // name the hijack binary as a .so -- the packaging stuff will automatically take care of it. 74 | task("nativeHijackMangleName", type: Copy) { 75 | from file("$buildDir/native/bin/armeabi/hijack") 76 | into file("$buildDir/native/bin/armeabi") 77 | rename "hijack", "lib__hijack.bin__.so" 78 | }.execute() 79 | } 80 | 81 | // https://github.com/creativepsyco/secondary-dex-gradle/ 82 | /* 83 | * Copyright (c) 2014 Mohit Kanwal. 84 | * 85 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 86 | * software and associated documentation files (the "Software"), to deal in the Software 87 | * without restriction, including without limitation the rights to use, copy, modify, 88 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 89 | * permit persons to whom the Software is furnished to do so, subject to the following 90 | * conditions: 91 | * 92 | * The above copyright notice and this permission notice shall be included in all copies or 93 | * substantial portions of the Software. 94 | */ 95 | import org.gradle.internal.os.OperatingSystem 96 | android.applicationVariants.all { 97 | variant -> 98 | String DEX = "$sdkDir/build-tools/${BUILD_TOOLS_VERSION}/dx" 99 | String BUILD_TOOL_DX = OperatingSystem.current().windows ? "${DEX}.bat" : "${DEX}" 100 | String ASSET_DIR = "${variant.mergeAssets.outputDir}" 101 | String taskRilExtenderDex = "rilExtenderDex${variant.name.capitalize()}" 102 | String classDir = "$buildDir/intermediates/classes/${variant.name}" 103 | 104 | // NOTE: rilextender.dex lags behind the rest of the code, for "one build." 105 | // First build, it will not be present at all, each subsequent build will have 106 | // the compiled code from the last build. 107 | // 108 | // Probably I'm doing this at the wrong time, but I can't find the right 109 | // dependency tree to make this happen -- I get circular dependency errors. 110 | // Maybe they thought nobody could ever need compiled assets? 111 | task(taskRilExtenderDex, type: Exec, dependsOn: variant.dex) { 112 | commandLine "${BUILD_TOOL_DX}", "--dex", "--no-strict", 113 | "--output=${ASSET_DIR}/rilextender.dex", 114 | "$classDir/net/scintill/simio/RilExtender.class", 115 | "$classDir/net/scintill/simio/RilExtender\$1.class", 116 | "$classDir/net/scintill/simio/RilExtender\$2.class", 117 | "$classDir/net/scintill/simio/RilExtender\$3.class", 118 | "$classDir/net/scintill/simio/RilExtender\$4.class", 119 | "$classDir/net/scintill/simio/RilExtender\$5.class", 120 | "$classDir/net/scintill/simio/IRilExtender.class", 121 | "$classDir/net/scintill/simio/IRilExtender\$Stub\$Proxy.class", 122 | "$classDir/net/scintill/simio/IRilExtender\$Stub.class" 123 | } 124 | 125 | // Make packaging depend on the above 126 | variant.assemble.dependsOn tasks.findByName(taskRilExtenderDex); 127 | variant.assemble.dependsOn tasks.findByName("rilExtenderNdkBuild"); // XXX variantize? 128 | } 129 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /opt/android-studio/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/net/scintill/simfilereader/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package net.scintill.simfilereader; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/aidl/net/scintill/simio/IRilExtender.aidl: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 Joey Hewitt 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package net.scintill.simio; 23 | 24 | // "com.android.internal.telephony.ITelephony" is the descriptor of the phone service -- 25 | // hacking this interface's descriptor to that can come in handy for testing 26 | 27 | interface IRilExtender { 28 | 29 | byte[] iccIOForApp(int command, int fileId, String path, int p1, int p2, int p3, String data, String pin2, String aid); 30 | 31 | boolean pingRilExtender(); 32 | 33 | long getBirthDate(); 34 | 35 | int getVersion(); 36 | 37 | String[] oemRilRequestStrings(in String[] requestArgs); 38 | 39 | byte[] oemRilRequestRaw(String requestArgHex); 40 | 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/android/os/AsyncResult.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2006 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package android.os; 18 | 19 | import android.os.Message; 20 | 21 | /** @hide */ 22 | public class AsyncResult 23 | { 24 | 25 | /*************************** Instance Variables **************************/ 26 | 27 | // Expect either exception or result to be null 28 | public Object userObj; 29 | public Throwable exception; 30 | public Object result; 31 | 32 | /***************************** Class Methods *****************************/ 33 | 34 | /** Saves and sets m.obj */ 35 | public static AsyncResult 36 | forMessage(Message m, Object r, Throwable ex) 37 | { 38 | AsyncResult ret; 39 | 40 | ret = new AsyncResult (m.obj, r, ex); 41 | 42 | m.obj = ret; 43 | 44 | return ret; 45 | } 46 | 47 | /** Saves and sets m.obj */ 48 | public static AsyncResult 49 | forMessage(Message m) 50 | { 51 | AsyncResult ret; 52 | 53 | ret = new AsyncResult (m.obj, null, null); 54 | 55 | m.obj = ret; 56 | 57 | return ret; 58 | } 59 | 60 | /** please note, this sets m.obj to be this */ 61 | public 62 | AsyncResult (Object uo, Object r, Throwable ex) 63 | { 64 | userObj = uo; 65 | result = r; 66 | exception = ex; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/android/os/Registrant.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2006 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package android.os; 18 | 19 | import android.os.Handler; 20 | import android.os.Message; 21 | 22 | import java.lang.ref.WeakReference; 23 | import java.util.HashMap; 24 | 25 | /** @hide */ 26 | public class Registrant 27 | { 28 | public 29 | Registrant(Handler h, int what, Object obj) 30 | { 31 | refH = new WeakReference(h); 32 | this.what = what; 33 | userObj = obj; 34 | } 35 | 36 | public void 37 | clear() 38 | { 39 | refH = null; 40 | userObj = null; 41 | } 42 | 43 | public void 44 | notifyRegistrant() 45 | { 46 | internalNotifyRegistrant (null, null); 47 | } 48 | 49 | public void 50 | notifyResult(Object result) 51 | { 52 | internalNotifyRegistrant (result, null); 53 | } 54 | 55 | public void 56 | notifyException(Throwable exception) 57 | { 58 | internalNotifyRegistrant (null, exception); 59 | } 60 | 61 | /** 62 | * This makes a copy of @param ar 63 | */ 64 | public void 65 | notifyRegistrant(AsyncResult ar) 66 | { 67 | internalNotifyRegistrant (ar.result, ar.exception); 68 | } 69 | 70 | /*package*/ void 71 | internalNotifyRegistrant (Object result, Throwable exception) 72 | { 73 | Handler h = getHandler(); 74 | 75 | if (h == null) { 76 | clear(); 77 | } else { 78 | Message msg = Message.obtain(); 79 | 80 | msg.what = what; 81 | 82 | msg.obj = new AsyncResult(userObj, result, exception); 83 | 84 | h.sendMessage(msg); 85 | } 86 | } 87 | 88 | /** 89 | * NOTE: May return null if weak reference has been collected 90 | */ 91 | 92 | public Message 93 | messageForRegistrant() 94 | { 95 | Handler h = getHandler(); 96 | 97 | if (h == null) { 98 | clear(); 99 | 100 | return null; 101 | } else { 102 | Message msg = h.obtainMessage(); 103 | 104 | msg.what = what; 105 | msg.obj = userObj; 106 | 107 | return msg; 108 | } 109 | } 110 | 111 | public Handler 112 | getHandler() 113 | { 114 | if (refH == null) 115 | return null; 116 | 117 | return (Handler) refH.get(); 118 | } 119 | 120 | WeakReference refH; 121 | int what; 122 | Object userObj; 123 | } 124 | 125 | -------------------------------------------------------------------------------- /app/src/main/java/android/os/RegistrantList.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2006 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package android.os; 18 | 19 | import android.os.Handler; 20 | import android.os.Message; 21 | 22 | import java.util.ArrayList; 23 | import java.util.HashMap; 24 | 25 | /** @hide */ 26 | public class RegistrantList 27 | { 28 | ArrayList registrants = new ArrayList(); // of Registrant 29 | 30 | public synchronized void 31 | add(Handler h, int what, Object obj) 32 | { 33 | add(new Registrant(h, what, obj)); 34 | } 35 | 36 | public synchronized void 37 | addUnique(Handler h, int what, Object obj) 38 | { 39 | // if the handler is already in the registrant list, remove it 40 | remove(h); 41 | add(new Registrant(h, what, obj)); 42 | } 43 | 44 | public synchronized void 45 | add(Registrant r) 46 | { 47 | removeCleared(); 48 | registrants.add(r); 49 | } 50 | 51 | public synchronized void 52 | removeCleared() 53 | { 54 | for (int i = registrants.size() - 1; i >= 0 ; i--) { 55 | Registrant r = (Registrant) registrants.get(i); 56 | 57 | if (r.refH == null) { 58 | registrants.remove(i); 59 | } 60 | } 61 | } 62 | 63 | public synchronized int 64 | size() 65 | { 66 | return registrants.size(); 67 | } 68 | 69 | public synchronized Object 70 | get(int index) 71 | { 72 | return registrants.get(index); 73 | } 74 | 75 | private synchronized void 76 | internalNotifyRegistrants (Object result, Throwable exception) 77 | { 78 | for (int i = 0, s = registrants.size(); i < s ; i++) { 79 | Registrant r = (Registrant) registrants.get(i); 80 | r.internalNotifyRegistrant(result, exception); 81 | } 82 | } 83 | 84 | public /*synchronized*/ void 85 | notifyRegistrants() 86 | { 87 | internalNotifyRegistrants(null, null); 88 | } 89 | 90 | public /*synchronized*/ void 91 | notifyException(Throwable exception) 92 | { 93 | internalNotifyRegistrants (null, exception); 94 | } 95 | 96 | public /*synchronized*/ void 97 | notifyResult(Object result) 98 | { 99 | internalNotifyRegistrants (result, null); 100 | } 101 | 102 | 103 | public /*synchronized*/ void 104 | notifyRegistrants(AsyncResult ar) 105 | { 106 | internalNotifyRegistrants(ar.result, ar.exception); 107 | } 108 | 109 | public synchronized void 110 | remove(Handler h) 111 | { 112 | for (int i = 0, s = registrants.size() ; i < s ; i++) { 113 | Registrant r = (Registrant) registrants.get(i); 114 | Handler rh; 115 | 116 | rh = r.getHandler(); 117 | 118 | /* Clean up both the requested registrant and 119 | * any now-collected registrants 120 | */ 121 | if (rh == null || rh == h) { 122 | r.clear(); 123 | } 124 | } 125 | 126 | removeCleared(); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /app/src/main/java/com/SecUpwN/AIMSICD/utils/CMDProcessor.java: -------------------------------------------------------------------------------- 1 | /** Copyright (C) 2013 Louis Teboul (a.k.a Androguide) 2 | * 3 | * admin@pimpmyrom.org || louisteboul@gmail.com 4 | * http://pimpmyrom.org || http://androguide.fr 5 | * 71 quai Clémenceau, 69300 Caluire-et-Cuire, FRANCE. 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License along 18 | * with this program; if not, write to the Free Software Foundation, Inc., 19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | **/ 21 | 22 | package com.SecUpwN.AIMSICD.utils; 23 | 24 | import android.util.Log; 25 | 26 | public final class CMDProcessor { 27 | 28 | private static final String TAG = "CMDProcessor"; 29 | 30 | public CMDProcessor() { 31 | 32 | } 33 | 34 | /* Run a system command with full redirection */ 35 | public static ChildProcess startSysCmd(String[] cmdarray, String childStdin) { 36 | return new ChildProcess(cmdarray, childStdin); 37 | } 38 | 39 | public static CommandResult runSysCmd(String[] cmdarray, String childStdin) { 40 | ChildProcess proc = startSysCmd(cmdarray, childStdin); 41 | proc.waitFinished(); 42 | return proc.getResult(); 43 | } 44 | 45 | public static ChildProcess startShellCommand(String cmd) { 46 | String[] cmdarray = new String[3]; 47 | cmdarray[0] = "sh"; 48 | cmdarray[1] = "-c"; 49 | cmdarray[2] = cmd; 50 | return startSysCmd(cmdarray, null); 51 | } 52 | 53 | public static CommandResult runShellCommand(String cmd) { 54 | ChildProcess proc = startShellCommand(cmd); 55 | proc.waitFinished(); 56 | return proc.getResult(); 57 | } 58 | 59 | public static ChildProcess startSuCommand(String cmd) { 60 | String[] cmdarray = new String[3]; 61 | cmdarray[0] = "su"; 62 | cmdarray[1] = "-c"; 63 | cmdarray[2] = cmd; 64 | return startSysCmd(cmdarray, null); 65 | } 66 | 67 | private static boolean mSuImplChecked = false; 68 | private static boolean mSuImplIsSuperSU = false; 69 | 70 | public static ChildProcess startSuCommand(String uid, String cmd) { 71 | if (!mSuImplChecked) { 72 | // figure out which su binary we've got, as I haven't (yet?) figured out a syntax 73 | // that is compatible with both SuperSU and CWM Superuser 74 | 75 | // assume canSu() has already been used, and thus the command exists, but verify 76 | CommandResult versionResult = runShellCommand("su -v"); 77 | if (!versionResult.success()) { 78 | throw new RuntimeException("unable to check su version -- is it not installed?"); 79 | } 80 | mSuImplChecked = true; 81 | mSuImplIsSuperSU = versionResult.getStdout().contains("SUPERSU"); 82 | } 83 | 84 | String[] cmdarray; 85 | if (mSuImplIsSuperSU) { 86 | cmdarray = new String[4]; 87 | cmdarray[0] = "su"; 88 | cmdarray[1] = uid; 89 | cmdarray[2] = "-c"; 90 | cmdarray[3] = cmd; 91 | } else { 92 | cmdarray = new String[5]; 93 | cmdarray[0] = "su"; 94 | cmdarray[1] = "-c"; 95 | cmdarray[2] = cmd; 96 | cmdarray[3] = "--"; 97 | cmdarray[4] = uid; 98 | } 99 | return startSysCmd(cmdarray, null); 100 | } 101 | 102 | public static CommandResult runSuCommand(String cmd) { 103 | ChildProcess proc = startSuCommand(cmd); 104 | proc.waitFinished(); 105 | return proc.getResult(); 106 | } 107 | 108 | public static CommandResult runSuCommand(String uid, String cmd) { 109 | Log.d(TAG, "runSuCommand "+uid+" "+cmd); 110 | ChildProcess proc = startSuCommand(uid, cmd); 111 | proc.waitFinished(); 112 | return proc.getResult(); 113 | } 114 | 115 | public static boolean canSU() { 116 | CommandResult r = runShellCommand("id"); 117 | StringBuilder out = new StringBuilder(0); 118 | out.append(r.getStdout()); 119 | out.append(" ; "); 120 | out.append(r.getStderr()); 121 | Log.d(TAG, "canSU() su[" + r.getExitValue() + "]: " + out); 122 | return r.success(); 123 | } 124 | } -------------------------------------------------------------------------------- /app/src/main/java/com/SecUpwN/AIMSICD/utils/ChildProcess.java: -------------------------------------------------------------------------------- 1 | /** Copyright (C) 2013 Louis Teboul (a.k.a Androguide) 2 | * 3 | * admin@pimpmyrom.org || louisteboul@gmail.com 4 | * http://pimpmyrom.org || http://androguide.fr 5 | * 71 quai Clémenceau, 69300 Caluire-et-Cuire, FRANCE. 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License along 18 | * with this program; if not, write to the Free Software Foundation, Inc., 19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | **/ 21 | 22 | package com.SecUpwN.AIMSICD.utils; 23 | 24 | import java.io.IOException; 25 | import java.io.InputStream; 26 | import java.io.OutputStream; 27 | 28 | import static java.lang.System.nanoTime; 29 | 30 | public class ChildProcess { 31 | 32 | private String TAG = getClass().getSimpleName(); 33 | 34 | private static final int PIPE_SIZE = 1024; 35 | 36 | private class ChildReader extends Thread { 37 | 38 | final InputStream mStream; 39 | 40 | final StringBuffer mBuffer; 41 | 42 | ChildReader(InputStream is, StringBuffer buf) { 43 | mStream = is; 44 | mBuffer = buf; 45 | } 46 | 47 | public void run() { 48 | byte[] buf = new byte[PIPE_SIZE]; 49 | try { 50 | int len; 51 | while ((len = mStream.read(buf)) != -1) { 52 | String s = new String(buf, 0, len); 53 | mBuffer.append(s); 54 | } 55 | } catch (IOException e) { 56 | // Ignore 57 | } 58 | try { 59 | mStream.close(); 60 | } catch (IOException e) { 61 | // Ignore 62 | } 63 | } 64 | } 65 | 66 | private class ChildWriter extends Thread { 67 | 68 | final OutputStream mStream; 69 | 70 | final String mBuffer; 71 | 72 | ChildWriter(OutputStream os, String buf) { 73 | mStream = os; 74 | mBuffer = buf; 75 | } 76 | 77 | public void run() { 78 | int off = 0; 79 | byte[] buf = mBuffer.getBytes(); 80 | try { 81 | while (off < buf.length) { 82 | int len = Math.min(PIPE_SIZE, buf.length - off); 83 | mStream.write(buf, off, len); 84 | off += len; 85 | } 86 | } catch (IOException e) { 87 | // Ignore 88 | } 89 | try { 90 | mStream.close(); 91 | } catch (IOException e) { 92 | // Ignore 93 | } 94 | } 95 | } 96 | 97 | private final long mStartTime; 98 | private Process mChildProc; 99 | private ChildWriter mChildStdinWriter; 100 | private ChildReader mChildStdoutReader; 101 | private ChildReader mChildStderrReader; 102 | private StringBuffer mChildStdout; 103 | private StringBuffer mChildStderr; 104 | private int mExitValue; 105 | private long mEndTime; 106 | 107 | public ChildProcess(String[] cmdarray, String childStdin) { 108 | mStartTime = nanoTime(); 109 | try { 110 | mChildProc = Runtime.getRuntime().exec(cmdarray); 111 | if (childStdin != null) { 112 | mChildStdinWriter = new ChildWriter(mChildProc.getOutputStream(), childStdin); 113 | mChildStdinWriter.start(); 114 | } 115 | mChildStdout = new StringBuffer(); 116 | mChildStdoutReader = new ChildReader(mChildProc.getInputStream(), mChildStdout); 117 | mChildStdoutReader.start(); 118 | mChildStderr = new StringBuffer(); 119 | mChildStderrReader = new ChildReader(mChildProc.getErrorStream(), mChildStderr); 120 | mChildStderrReader.start(); 121 | } catch (IOException e) { 122 | // XXX: log 123 | } 124 | } 125 | 126 | public boolean isFinished() { 127 | boolean finished = true; 128 | if (mChildProc != null) { 129 | try { 130 | mChildProc.exitValue(); 131 | } catch (IllegalStateException e) { 132 | finished = false; 133 | } 134 | } 135 | return finished; 136 | } 137 | 138 | public int waitFinished() { 139 | while (mChildProc != null) { 140 | try { 141 | mExitValue = mChildProc.waitFor(); 142 | mEndTime = nanoTime(); 143 | mChildProc = null; 144 | mChildStderrReader.join(); 145 | mChildStderrReader = null; 146 | mChildStdoutReader.join(); 147 | mChildStdoutReader = null; 148 | if (mChildStdinWriter != null) { 149 | mChildStdinWriter.join(); 150 | mChildStdinWriter = null; 151 | } 152 | } catch (InterruptedException e) { 153 | // Ignore 154 | } 155 | } 156 | return mExitValue; 157 | } 158 | 159 | public CommandResult getResult() { 160 | if (!isFinished()) { 161 | throw new IllegalThreadStateException("Child process running"); 162 | } 163 | return new CommandResult( 164 | mStartTime, 165 | mExitValue, 166 | mChildStdout.toString(), 167 | mChildStderr.toString(), 168 | mEndTime); 169 | } 170 | } -------------------------------------------------------------------------------- /app/src/main/java/com/SecUpwN/AIMSICD/utils/CommandResult.java: -------------------------------------------------------------------------------- 1 | /** Copyright (C) 2013 Louis Teboul (a.k.a Androguide) 2 | * 3 | * admin@pimpmyrom.org || louisteboul@gmail.com 4 | * http://pimpmyrom.org || http://androguide.fr 5 | * 71 quai Clémenceau, 69300 Caluire-et-Cuire, FRANCE. 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License along 18 | * with this program; if not, write to the Free Software Foundation, Inc., 19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | **/ 21 | 22 | package com.SecUpwN.AIMSICD.utils; 23 | 24 | import android.os.Parcel; 25 | import android.os.Parcelable; 26 | import android.util.Log; 27 | 28 | @SuppressWarnings("AccessOfSystemProperties") 29 | public class CommandResult implements Parcelable { 30 | 31 | private final String TAG = "AIMSICD_CommandResult"; 32 | private final long mStartTime; 33 | private final int mExitValue; 34 | private final String mStdout; 35 | private final String mStderr; 36 | private final long mEndTime; 37 | 38 | public CommandResult(long startTime, 39 | int exitValue, 40 | String stdout, 41 | String stderr, 42 | long endTime) { 43 | mStartTime = startTime; 44 | mExitValue = exitValue; 45 | mStdout = stdout; 46 | mStderr = stderr; 47 | mEndTime = endTime; 48 | 49 | Log.d(TAG, "Time to execute: " + (mEndTime - mStartTime) + " ns (nanoseconds)"); 50 | // this is set last so log from here 51 | checkForErrors(); 52 | } 53 | 54 | // pretty much just forward the constructor from parcelable to our main 55 | // loading constructor 56 | @SuppressWarnings("CastToConcreteClass") 57 | public CommandResult(Parcel inParcel) { 58 | this(inParcel.readLong(), 59 | inParcel.readInt(), 60 | inParcel.readString(), 61 | inParcel.readString(), 62 | inParcel.readLong()); 63 | } 64 | 65 | public boolean success() { 66 | return (mExitValue == 0); 67 | } 68 | 69 | public long getEndTime() { 70 | return mEndTime; 71 | } 72 | 73 | public String getStderr() { 74 | return mStderr; 75 | } 76 | 77 | public String getStdout() { 78 | return mStdout; 79 | } 80 | 81 | public Integer getExitValue() { 82 | return mExitValue; 83 | } 84 | 85 | public long getStartTime() { 86 | return mStartTime; 87 | } 88 | 89 | @SuppressWarnings("UnnecessaryExplicitNumericCast") 90 | private void checkForErrors() { 91 | if (mExitValue != 0 || !"".equals(mStderr.trim())) { 92 | Log.e(TAG, "shell error detected! CommandResult {" + this.toString() + '}'); 93 | } 94 | } 95 | 96 | // implement parcelable 97 | @Override 98 | public int describeContents() { 99 | return 0; 100 | } 101 | 102 | @Override 103 | public void writeToParcel(Parcel parcel, int i) { 104 | parcel.writeLong(mStartTime); 105 | parcel.writeInt(mExitValue); 106 | parcel.writeString(mStdout); 107 | parcel.writeString(mStderr); 108 | parcel.writeLong(mEndTime); 109 | } 110 | 111 | @Override 112 | public String toString() { 113 | return "CommandResult{" + 114 | ", mStartTime=" + mStartTime + 115 | ", mExitValue=" + mExitValue + 116 | ", stdout='" + mStdout + "'" + 117 | ", stderr='" + mStderr + "'" + 118 | ", mEndTime=" + mEndTime + 119 | '}'; 120 | } 121 | 122 | public static final Parcelable.Creator CREATOR 123 | = new Parcelable.Creator() { 124 | public CommandResult createFromParcel(Parcel in) { 125 | return new CommandResult(in); 126 | } 127 | 128 | public CommandResult[] newArray(int size) { 129 | return new CommandResult[size]; 130 | } 131 | }; 132 | 133 | @Override 134 | public boolean equals(Object o) { 135 | if (this == o) { 136 | return true; 137 | } 138 | if (!(o instanceof CommandResult)) { 139 | return false; 140 | } 141 | 142 | CommandResult that = (CommandResult) o; 143 | 144 | return (mStartTime == that.mStartTime && 145 | mExitValue == that.mExitValue && 146 | mStdout.equals(that.mStdout) && 147 | mStderr.equals(that.mStderr) && 148 | mEndTime == that.mEndTime); 149 | } 150 | 151 | @Override 152 | public int hashCode() { 153 | int result = 0; 154 | result = 31 * result + (int) (mStartTime ^ (mStartTime >>> 32)); 155 | result = 31 * result + mExitValue; 156 | result = 31 * result + (mStdout != null ? mStdout.hashCode() : 0); 157 | result = 31 * result + (mStderr != null ? mStderr.hashCode() : 0); 158 | result = 31 * result + (int) (mEndTime ^ (mEndTime >>> 32)); 159 | return result; 160 | } 161 | } -------------------------------------------------------------------------------- /app/src/main/java/com/SecUpwN/AIMSICD/utils/Helpers.java: -------------------------------------------------------------------------------- 1 | /** Copyright (C) 2013 Louis Teboul (a.k.a Androguide) 2 | * 3 | * admin@pimpmyrom.org || louisteboul@gmail.com 4 | * http://pimpmyrom.org || http://androguide.fr 5 | * 71 quai Clémenceau, 69300 Caluire-et-Cuire, FRANCE. 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License along 18 | * with this program; if not, write to the Free Software Foundation, Inc., 19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | **/ 21 | 22 | package com.SecUpwN.AIMSICD.utils; 23 | 24 | import android.util.Log; 25 | 26 | import java.io.File; 27 | 28 | public class Helpers { 29 | 30 | private static final String TAG = "AIMSICD_Helpers"; 31 | 32 | /** 33 | * Checks device for SuperUser permission 34 | * 35 | * @return If SU was granted or denied 36 | */ 37 | @SuppressWarnings("MethodWithMultipleReturnPoints") 38 | public static boolean checkSu() { 39 | if (!new File("/system/bin/su").exists() 40 | && !new File("/system/xbin/su").exists()) { 41 | Log.e(TAG, "su binary does not exist!!!"); 42 | return false; // tell caller to bail... 43 | } 44 | try { 45 | if (CMDProcessor.runSuCommand("ls /data/app-private").success()) { 46 | Log.i(TAG, " SU exists and we have permission"); 47 | return true; 48 | } else { 49 | Log.i(TAG, " SU exists but we don't have permission"); 50 | return false; 51 | } 52 | } catch (NullPointerException e) { 53 | Log.e(TAG, "NullPointer throw while looking for su binary", e); 54 | return false; 55 | } 56 | } 57 | 58 | } 59 | 60 | -------------------------------------------------------------------------------- /app/src/main/java/com/SecUpwN/AIMSICD/utils/atcmd/AtCommandTerminal.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015 Joey Hewitt 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package com.SecUpwN.AIMSICD.utils.atcmd; 23 | 24 | import android.os.Message; 25 | import android.util.Log; 26 | 27 | import java.io.File; 28 | import java.io.IOException; 29 | 30 | /** 31 | * This probably won't work well with two clients! I don't know what happens 32 | * if your RIL currently uses the same AT interface. 33 | * 34 | * TODO track down SIGPIPE (apparently in "cat /dev/smd7") on uncaught exception? 35 | * The stack barf in logcat is bugging me, but I spent some time trying to figure it out and can't. 36 | */ 37 | public abstract class AtCommandTerminal { 38 | 39 | protected static final String TAG = "AtCommandTerminal"; 40 | 41 | // message may be null if the response is not needed 42 | public abstract void send(String s, Message message); 43 | 44 | public abstract void dispose(); 45 | 46 | /** 47 | * @return 48 | * @throws UnsupportedOperationException if no instance can be made 49 | */ 50 | public static AtCommandTerminal factory() throws UnsupportedOperationException { 51 | AtCommandTerminal term = null; 52 | 53 | // QCom: /dev/smd7, possibly other SMD devices. On 2 devices I've checked, 54 | // smd7 is owned by bluetooth:bluetooth, so that could be something to sniff for if 55 | // it's not always smd7. 56 | File smdFile = new File("/dev/smd7"); 57 | if (smdFile.exists()) { 58 | try { 59 | term = new TtyPrivFile(smdFile.getAbsolutePath()); 60 | } catch (IOException e) { 61 | Log.e(TAG, "IOException in constructor", e); 62 | // fall through 63 | } 64 | } 65 | 66 | if (term == null) { 67 | throw new UnsupportedOperationException("unable to find AT command terminal"); 68 | } 69 | 70 | return term; 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /app/src/main/java/com/SecUpwN/AIMSICD/utils/atcmd/TtyPrivFile.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015 Joey Hewitt 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package com.SecUpwN.AIMSICD.utils.atcmd; 23 | 24 | import android.util.Log; 25 | 26 | import java.io.IOException; 27 | 28 | /*package*/ class TtyPrivFile extends TtyStream { 29 | protected Process mReadProc, mWriteProc; 30 | 31 | public TtyPrivFile(String ttyPath) throws IOException { 32 | // TODO robustify su detection? 33 | this( 34 | new ProcessBuilder("su", "-c", "\\exec cat <" + ttyPath).start(), 35 | new ProcessBuilder("su", "-c", "\\exec cat >" + ttyPath).start() 36 | ); 37 | } 38 | 39 | private TtyPrivFile(Process read, Process write) { 40 | super(read.getInputStream(), write.getOutputStream()); 41 | mReadProc = read; 42 | mWriteProc = write; 43 | 44 | Log.d(TAG, "mReadProc=" + mReadProc + ", mWriteProc=" + mWriteProc); 45 | } 46 | 47 | @Override 48 | public void dispose() { 49 | super.dispose(); 50 | try { 51 | // Have to do this to get readproc to exit. 52 | // I guess it gets blocked waiting for input, so let's give it some. 53 | mOutputStream.write("ATE0\r".getBytes("ASCII")); 54 | mOutputStream.flush(); 55 | } catch (IOException e) { 56 | // ignore and hope it exits 57 | } 58 | mReadProc.destroy(); 59 | mWriteProc.destroy(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/com/SecUpwN/AIMSICD/utils/atcmd/TtyStream.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015 Joey Hewitt 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package com.SecUpwN.AIMSICD.utils.atcmd; 23 | 24 | import android.os.Message; 25 | import android.util.Log; 26 | import android.util.Pair; 27 | 28 | import java.io.BufferedReader; 29 | import java.io.IOException; 30 | import java.io.InputStream; 31 | import java.io.InputStreamReader; 32 | import java.io.OutputStream; 33 | import java.io.UnsupportedEncodingException; 34 | import java.util.ArrayList; 35 | import java.util.List; 36 | import java.util.concurrent.BlockingQueue; 37 | import java.util.concurrent.LinkedBlockingQueue; 38 | 39 | /*package*/ class TtyStream extends AtCommandTerminal { 40 | 41 | protected InputStream mInputStream; 42 | protected OutputStream mOutputStream; 43 | 44 | private boolean mThreadRun = true; 45 | private Thread mIoThread; 46 | 47 | protected BlockingQueue> mWriteQ; 48 | 49 | /*package*/ TtyStream(InputStream in, OutputStream out) { 50 | mInputStream = in; 51 | mOutputStream = out; 52 | 53 | mIoThread = new Thread(new IoRunnable(), "AtCommandTerminalIO"); 54 | mIoThread.start(); 55 | 56 | mWriteQ = new LinkedBlockingQueue<>(); 57 | 58 | // return result codes, return verbose codes, no local echo 59 | this.send("ATQ0V1E0", null); 60 | } 61 | 62 | private class IoRunnable implements Runnable { 63 | @Override 64 | public void run() { 65 | try { 66 | BufferedReader in = new BufferedReader(new InputStreamReader(mInputStream, "ASCII")); 67 | while (mThreadRun) { 68 | // wait for something to write 69 | byte[] bytesOut; 70 | Message resultMessage; 71 | try { 72 | Pair p = mWriteQ.take(); 73 | bytesOut = p.first; 74 | resultMessage = p.second; 75 | } catch (InterruptedException e) { 76 | continue; // restart loop 77 | } 78 | 79 | try { 80 | mOutputStream.write(bytesOut); 81 | mOutputStream.write('\r'); 82 | mOutputStream.flush(); 83 | } catch (IOException e) { 84 | Log.e(TAG, "Output IOException", e); 85 | if (resultMessage != null) { 86 | resultMessage.obj = e; 87 | resultMessage.sendToTarget(); 88 | } 89 | return; // kill thread 90 | } 91 | 92 | /** 93 | * ETSI TS 127 007 gives this example: 94 | * +CMD2: 3,0,15,"GSM" 95 | * +CMD2: (0-3),(0,1),(0-12,15),("GSM","IRA") 96 | * OK 97 | * 98 | * I see embedded sequences to line-break within responses. 99 | * We can fake it using the BufferedReader, ignoring blank lines. 100 | */ 101 | 102 | // dispatch response lines until done 103 | String line; 104 | List lines = new ArrayList<>(); 105 | do { 106 | try { 107 | line = in.readLine(); 108 | if (line == null) throw new IOException("reader closed"); 109 | } catch (IOException e) { 110 | Log.e(TAG, "Input IOException", e); 111 | if (resultMessage != null) { 112 | resultMessage.obj = e; 113 | resultMessage.sendToTarget(); 114 | } 115 | return; // kill thread 116 | } 117 | 118 | if (line.length() != 0) lines.add(line); 119 | // ignore empty lines 120 | } while (!(line.equals("OK") || line.equals("ERROR") || line.startsWith("+CME ERROR"))); 121 | 122 | // XXX remove this logging, could have sensitive info 123 | Log.d(TAG, "IO< " + lines); 124 | 125 | if (resultMessage != null) { 126 | resultMessage.obj = lines; 127 | resultMessage.sendToTarget(); 128 | } else { 129 | Log.d(TAG, "Data came in with no handler"); 130 | } 131 | } 132 | } catch (UnsupportedEncodingException e) { 133 | // ASCII should work 134 | throw new RuntimeException(e); 135 | } finally { 136 | dispose(); 137 | } 138 | } 139 | } 140 | 141 | @Override 142 | public void send(String s, Message resultMessage) { 143 | try { 144 | // XXX remove this logging, could have sensitive info 145 | Log.d(TAG, "IO> " + s); 146 | mWriteQ.add(Pair.create(s.getBytes("ASCII"), resultMessage)); 147 | } catch (UnsupportedEncodingException e) { 148 | // we assume that if a String is being used for convenience, it must be ASCII 149 | throw new RuntimeException(e); 150 | } 151 | } 152 | 153 | @Override 154 | public void dispose() { 155 | mThreadRun = false; 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /app/src/main/java/net/scintill/simfilereader/MyActivity.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 Joey Hewitt 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package net.scintill.simfilereader; 23 | 24 | import android.app.Activity; 25 | import android.os.Bundle; 26 | import android.os.Handler; 27 | import android.os.HandlerThread; 28 | import android.os.Looper; 29 | import android.os.Message; 30 | import android.util.Log; 31 | import android.view.Menu; 32 | import android.view.MenuItem; 33 | import android.widget.TextView; 34 | 35 | import com.SecUpwN.AIMSICD.utils.Helpers; 36 | 37 | import net.scintill.simio.CardApplication; 38 | import net.scintill.simio.telephony.CommandsInterface; 39 | import net.scintill.simio.CommandsInterfaceFactory; 40 | import net.scintill.simio.telephony.uicc.IccUtils; 41 | import net.scintill.simio.telephony.uicc.SIMRecords; 42 | import net.scintill.simio.telephony.uicc.UiccCardApplication; 43 | 44 | 45 | public class MyActivity extends Activity { 46 | 47 | private final static String TAG = "SIMFileReader"; 48 | 49 | @Override 50 | protected void onCreate(Bundle savedInstanceState) { 51 | super.onCreate(savedInstanceState); 52 | setContentView(R.layout.activity_my); 53 | 54 | // do files test in another thread, so the UI doesn't get blocked 55 | HandlerThread handlerThread = new HandlerThread("SIMFilesTest"); 56 | handlerThread.start(); 57 | // getLooper() can block, but it shouldn't be as bad as the blocking on SuperSU before. 58 | // Maybe I'm doing something wrong here, though. 59 | new Handler(handlerThread.getLooper()).post(new Runnable() { 60 | @Override 61 | public void run() { 62 | filesTests(); 63 | } 64 | }); 65 | } 66 | 67 | 68 | @Override 69 | public boolean onCreateOptionsMenu(Menu menu) { 70 | // Inflate the menu; this adds items to the action bar if it is present. 71 | getMenuInflater().inflate(R.menu.my, menu); 72 | return true; 73 | } 74 | 75 | @Override 76 | public boolean onOptionsItemSelected(MenuItem item) { 77 | // Handle action bar item clicks here. The action bar will 78 | // automatically handle clicks on the Home/Up button, so long 79 | // as you specify a parent activity in AndroidManifest.xml. 80 | int id = item.getItemId(); 81 | if (id == R.id.action_settings) { 82 | return true; 83 | } 84 | return super.onOptionsItemSelected(item); 85 | } 86 | 87 | private CommandsInterface mCommandsInterface; 88 | 89 | private void filesTests() { 90 | try { 91 | if (Helpers.checkSu()) { 92 | // XXX get SIM application ID? 93 | mCommandsInterface = CommandsInterfaceFactory.factory(getApplicationContext()); 94 | UiccCardApplication cardApplication = new CardApplication(mCommandsInterface); 95 | final SIMRecords records = new SIMRecords(cardApplication, this.getApplicationContext(), mCommandsInterface); 96 | 97 | records.registerForRecordsLoaded(new Handler() { 98 | @Override 99 | public void handleMessage(Message message) { 100 | new Handler(Looper.getMainLooper()).post(new Runnable() { 101 | @Override 102 | public void run() { 103 | String results = 104 | "MSISDN=" + records.getMsisdnNumber()+"\n"+ 105 | "TMSI=" + IccUtils.bytesToHexString(records.getTemporaryMobileSubscriberIdentity())+"\n"+ 106 | "LAI=" + IccUtils.bytesToHexString(records.getLocationAreaInformation())+"\n"+ 107 | "\n"+ 108 | "Commands interface: "+mCommandsInterface.getClass().getSimpleName()+"\n"+ 109 | mCommandsInterface.getInterfaceDebugInfo(); 110 | 111 | TextView textViewResults = (TextView)MyActivity.this.findViewById(R.id.results); 112 | textViewResults.setText(results); 113 | } 114 | }); 115 | } 116 | }, 0, null); 117 | } else { 118 | new Handler(Looper.getMainLooper()).post(new Runnable() { 119 | @Override 120 | public void run() { 121 | // technically we can work without su, if the phone process has already been injected 122 | TextView textViewResults = (TextView) MyActivity.this.findViewById(R.id.results); 123 | textViewResults.setText("Superuser/su not available!"); 124 | } 125 | }); 126 | } 127 | } catch (Throwable t) { 128 | Log.e(TAG, "Error loading SIM files", t); 129 | } 130 | } 131 | 132 | @Override 133 | protected void onPause() { 134 | super.onPause(); 135 | if (mCommandsInterface != null) { 136 | mCommandsInterface.dispose(); 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /app/src/main/java/net/scintill/simio/AtCommandInterface.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015 Joey Hewitt 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package net.scintill.simio; 23 | 24 | import android.os.AsyncResult; 25 | import android.os.Handler; 26 | import android.os.Message; 27 | import android.util.Log; 28 | 29 | import com.SecUpwN.AIMSICD.utils.atcmd.AtCommandTerminal; 30 | 31 | import net.scintill.simio.telephony.CommandsInterface; 32 | import net.scintill.simio.telephony.uicc.IccIoResult; 33 | import net.scintill.simio.telephony.uicc.IccRecords; 34 | import net.scintill.simio.telephony.uicc.IccUtils; 35 | 36 | import java.io.IOException; 37 | import java.util.List; 38 | import java.util.concurrent.ConcurrentLinkedQueue; 39 | 40 | public class AtCommandInterface implements CommandsInterface { 41 | 42 | private static final String TAG = "AtCommandInterface"; 43 | 44 | private AtCommandTerminal mTerminal; 45 | private Handler mHandler; 46 | 47 | private final Object mTerminalMutex = new Object(); 48 | private ConcurrentLinkedQueue mResponseQ; 49 | 50 | private String mAtiResponse; 51 | 52 | private static final int EVENT_CRSM = 1; 53 | private static final int EVENT_ATI = 2; 54 | 55 | public AtCommandInterface(AtCommandTerminal terminal) { 56 | mTerminal = terminal; 57 | mResponseQ = new ConcurrentLinkedQueue<>(); 58 | mHandler = new ResponseHandler(); 59 | 60 | mTerminal.send("ATI", mHandler.obtainMessage(EVENT_ATI)); 61 | } 62 | 63 | @Override 64 | public void iccIOForApp(int command, int fileid, String path, int p1, int p2, int p3, String data, String pin2, String aid, Message result) { 65 | //if (path == null) path = ""; 66 | //if (data == null) data = ""; 67 | 68 | synchronized (mTerminalMutex) { 69 | mTerminal.send("AT+CRSM="+command+","+fileid+","+p1+","+p2+","+p3/*+","+data+","+path*/, mHandler.obtainMessage(EVENT_CRSM)); 70 | mResponseQ.add(result); 71 | } 72 | } 73 | 74 | private class ResponseHandler extends Handler { 75 | @Override 76 | public void handleMessage(Message message) { 77 | if (message.what == EVENT_CRSM) { 78 | Message result = null; 79 | try { 80 | String line = null; 81 | if (message.obj instanceof List) { 82 | line = ((List) message.obj).get(0).toUpperCase(); 83 | } else if (message.obj instanceof IOException) { 84 | throw (IOException) message.obj; 85 | } 86 | 87 | result = mResponseQ.remove(); 88 | if (line.startsWith("+CRSM:")) { 89 | String[] pieces = line.substring(6).split(","); 90 | int sw1 = Integer.valueOf(pieces[0].trim(), 10) & 0xff; 91 | int sw2 = Integer.valueOf(pieces[1].trim(), 10) & 0xff; 92 | pieces[2] = pieces[2].trim(); 93 | 94 | String hexBody; 95 | if (pieces[2].charAt(0) == '"') { 96 | hexBody = pieces[2].substring(1, pieces[2].length() - 1); 97 | } else { 98 | hexBody = pieces[2]; 99 | } 100 | 101 | if ((hexBody.length() % 2) != 0) { 102 | throw new IOException("malformed body: " + pieces[2]); 103 | } 104 | 105 | // XXX remove, sensitive info 106 | Log.d(TAG, "iccIO result=" + sw1 + " " + sw2 + " " + hexBody); 107 | 108 | IccIoResult iccIoResult = new IccIoResult(sw1, sw2, IccUtils.hexStringToBytes(hexBody)); 109 | AsyncResult.forMessage(result, iccIoResult, null); 110 | result.sendToTarget(); 111 | } else if (line.equals("ERROR")) { 112 | throw new IOException("AT error response"); 113 | } else { 114 | throw new IOException("unexpected response " + line); 115 | } 116 | } catch (Throwable e) { 117 | if (result != null) { 118 | AsyncResult.forMessage(result, null, e); 119 | result.sendToTarget(); 120 | } else { 121 | throw new RuntimeException(e); 122 | } 123 | } 124 | } else if (message.what == EVENT_ATI) { 125 | if (message.obj instanceof IOException) { 126 | mAtiResponse = "IOException: "+((IOException)message.obj).getMessage(); 127 | } else { 128 | mAtiResponse = ""; 129 | for (String line : (List)message.obj) { 130 | mAtiResponse += line+"\n"; 131 | } 132 | } 133 | } 134 | } 135 | } 136 | 137 | @Override 138 | public void registerForIccRefresh(IccRecords iccRecords, int eventRefresh, Object o) { 139 | } 140 | 141 | @Override 142 | public void unregisterForIccRefresh(IccRecords iccRecords) { 143 | } 144 | 145 | @Override 146 | public void getCDMASubscription(Message message) { 147 | throw new RuntimeException("unimplemented"); 148 | } 149 | 150 | @Override 151 | public void getIMSIForApp(String aid, Message message) { 152 | throw new RuntimeException("unimplemented"); 153 | } 154 | 155 | @Override 156 | public void setRadioPower(boolean b, Object o) { 157 | throw new RuntimeException("unimplemented"); 158 | } 159 | 160 | @Override 161 | public void dispose() { 162 | if (mTerminal != null) { 163 | mTerminal.dispose(); 164 | mTerminal = null; 165 | } 166 | } 167 | 168 | @Override 169 | public String getInterfaceDebugInfo() { 170 | return "ATI: "+mAtiResponse; 171 | } 172 | 173 | } 174 | -------------------------------------------------------------------------------- /app/src/main/java/net/scintill/simio/CardApplication.java: -------------------------------------------------------------------------------- 1 | package net.scintill.simio; 2 | 3 | import android.os.AsyncResult; 4 | import android.os.Handler; 5 | import android.os.Registrant; 6 | 7 | import net.scintill.simio.telephony.CommandsInterface; 8 | import net.scintill.simio.telephony.uicc.IccCardApplicationStatus; 9 | import net.scintill.simio.telephony.uicc.IccFileHandler; 10 | import net.scintill.simio.telephony.uicc.SIMFileHandler; 11 | import net.scintill.simio.telephony.uicc.UiccCardApplication; 12 | 13 | public class CardApplication implements UiccCardApplication { 14 | 15 | private CommandsInterface mCi; 16 | 17 | public CardApplication(CommandsInterface ci) { 18 | this.mCi = ci; 19 | } 20 | 21 | @Override 22 | public IccCardApplicationStatus.AppType getType() { 23 | return IccCardApplicationStatus.AppType.APPTYPE_SIM; 24 | } 25 | 26 | private IccFileHandler mFh; 27 | 28 | @Override 29 | public IccFileHandler getIccFileHandler() { 30 | if (mFh == null) { 31 | mFh = new SIMFileHandler(this, getAid(), mCi); 32 | } 33 | return mFh; 34 | } 35 | 36 | @Override 37 | public IccCardApplicationStatus.AppState getState() { 38 | return IccCardApplicationStatus.AppState.APPSTATE_READY; 39 | } 40 | 41 | @Override 42 | public String getAid() { 43 | return null; 44 | } 45 | 46 | @Override 47 | public void registerForReady(Handler handler, int what, Object o) { 48 | new Registrant(handler, what, o).notifyRegistrant(new AsyncResult(null, null, null)); 49 | } 50 | 51 | @Override 52 | public void unregisterForReady(Handler handler) { 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/net/scintill/simio/CommandsInterfaceFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015 Joey Hewitt 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package net.scintill.simio; 23 | 24 | import android.util.Log; 25 | 26 | import com.SecUpwN.AIMSICD.utils.atcmd.AtCommandTerminal; 27 | 28 | import net.scintill.simio.telephony.CommandsInterface; 29 | 30 | public class CommandsInterfaceFactory { 31 | 32 | private static final String TAG = "CommandsInterfaceFactory"; 33 | 34 | /** 35 | * @param appContext 36 | * @return 37 | * @throws UnsupportedOperationException if no instance can be found 38 | */ 39 | public static CommandsInterface factory(android.content.Context appContext) throws UnsupportedOperationException { 40 | try { 41 | return new TelephonySeekServiceCommandsInterface(appContext); 42 | } catch (UnsupportedOperationException e) { 43 | Log.d(TAG, "SEEK not available", e); 44 | } catch (Exception e) { 45 | Log.e(TAG, "Uncaught exception from SEEK", e); 46 | } 47 | 48 | try { 49 | return new AtCommandInterface(AtCommandTerminal.factory()); 50 | } catch (UnsupportedOperationException e) { 51 | Log.d(TAG, "AT command terminal not available", e); 52 | } catch (Exception e) { 53 | Log.e(TAG, "Uncaught exception from AT command terminal", e); 54 | } 55 | 56 | try { 57 | return new RilExtenderCommandsInterface(appContext); 58 | } catch (UnsupportedOperationException e) { 59 | Log.d(TAG, "RilExtender not available", e); 60 | } catch (Exception e) { 61 | Log.e(TAG, "Uncaught exception from RilExtender", e); 62 | } 63 | 64 | throw new UnsupportedOperationException("no supported SIM I/O interfaces found"); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/java/net/scintill/simio/TelephonySeekServiceCommandsInterface.java: -------------------------------------------------------------------------------- 1 | package net.scintill.simio; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageManager; 5 | import android.os.AsyncResult; 6 | import android.os.Message; 7 | import android.os.Parcel; 8 | import android.telephony.TelephonyManager; 9 | import android.util.Log; 10 | 11 | import com.SecUpwN.AIMSICD.utils.CMDProcessor; 12 | import com.SecUpwN.AIMSICD.utils.CommandResult; 13 | 14 | import net.scintill.simio.telephony.CommandsInterface; 15 | import net.scintill.simio.telephony.uicc.IccIoResult; 16 | import net.scintill.simio.telephony.uicc.IccRecords; 17 | import net.scintill.simio.telephony.uicc.IccUtils; 18 | 19 | import java.lang.reflect.Field; 20 | import java.nio.ByteOrder; 21 | import java.util.Arrays; 22 | 23 | public class TelephonySeekServiceCommandsInterface implements CommandsInterface { 24 | protected static final String TAG = "TelephonySeekServiceCommandsInterface"; 25 | 26 | private TelephonyManager mTelephonyManager; 27 | private int mTRANSACTION_transmitIccSimIO; 28 | private int mSeekUid; 29 | 30 | /** 31 | * @param context 32 | * @throws UnsupportedOperationException if SEEK could not be found 33 | */ 34 | public TelephonySeekServiceCommandsInterface(Context context) throws UnsupportedOperationException { 35 | if (ByteOrder.nativeOrder() != ByteOrder.LITTLE_ENDIAN) { 36 | // The "service" cmd output is byte-order sensitive. We could probably deal with 37 | // big-endian, but there's no need for now. 38 | throw new UnsupportedOperationException("Only little-endian byte order is supported"); 39 | } 40 | 41 | // Get transmitIccSimIO service call ID 42 | try { 43 | Field f = Class.forName("com.android.internal.telephony.ITelephony$Stub").getDeclaredField("TRANSACTION_transmitIccSimIO"); 44 | f.setAccessible(true); 45 | mTRANSACTION_transmitIccSimIO = f.getInt(null); 46 | } catch (NoSuchFieldException | ClassNotFoundException | IllegalAccessException e) { 47 | throw new UnsupportedOperationException("could not get com.android.internal.telephony.ITelephony.Stub.TRANSACTION_transmitIccSimIO -- the telephony service probably doesn't support SEEK"); 48 | } 49 | 50 | // Get OpenMobile Service's user ID, or NFC id 51 | try { 52 | mSeekUid = context.getPackageManager().getApplicationInfo("org.simalliance.openmobileapi.service", PackageManager.GET_UNINSTALLED_PACKAGES).uid; 53 | } catch (PackageManager.NameNotFoundException e) { 54 | // CyanogenMod 11 currently doesn't have the service, but it does have the service call, granted to NFC user 55 | try { 56 | // this is not a public part of the API, but should be a public field 57 | Field f = Class.forName("android.os.Process").getField("NFC_UID"); 58 | mSeekUid = f.getInt(null); 59 | } catch (NoSuchFieldException | ClassNotFoundException | IllegalAccessException e2) { 60 | throw new UnsupportedOperationException("could not get android.os.Process.NFC_UID", e2); 61 | } 62 | } 63 | 64 | //SEService ses = new SEService(context, this); 65 | } 66 | 67 | @Override 68 | public void iccIOForApp(int command, int fileid, String path, int p1, int p2, int p3, String data, String pin2, String aid, Message 69 | result) { 70 | Log.d(TAG, "iccIO "+command + " " + fileid + " " + path + " " + p1 + " " + p2 + " " + p3 + " " + data + " " + pin2 + " " + aid + " " + result); 71 | 72 | /** 73 | * Use the "service" command-line utility, elevated to a privileged user, to invoke a Binder call to the SEEK endpoint 74 | * in the telephony service. The only access check it does is that the UID is allowed, so we bypass the access 75 | * checks implemented by the OpenMobile service. 76 | */ 77 | 78 | CommandResult cmdResult = CMDProcessor.runSuCommand(Integer.toString(mSeekUid), 79 | "service call phone " + mTRANSACTION_transmitIccSimIO + 80 | " i32 " + fileid + " i32 " + command + " i32 " + p1 + " i32 " + p2 + " i32 " + p3 + " s16 " + path); // XXX shell escaping? 81 | if (!cmdResult.success()) { 82 | throw new RuntimeException("privileged service call failed"); 83 | } 84 | 85 | // this is ugly. I'd like to forgo it altogether and find a way to call through binder as the privileged user in Java. 86 | // I'm considering copying the OpenMobile service to this project, patching out the access checks, and starting it up as the privileged user, 87 | // then driving it through the standard OpenMobile classes. Sounds like a lot of work that may end up being impossible, or not much nicer than this. 88 | String asciiHex = cmdResult.getStdout(); // something like Parcel(\n 0x0000: 00000000 00000000 00000000 00000000 'asdfasfdadsfasdf'\n... 89 | Log.d(TAG, "service result="+asciiHex); 90 | String[] lines = asciiHex.split("\\n"); 91 | StringBuffer fixedBytesAsciiHex = new StringBuffer(); 92 | for (int i = 1; i < lines.length; i++) { 93 | String[] lineReversedWords = lines[i].substring(lines[i].indexOf(':')+2, lines[i].indexOf('\'')-1).trim().split(" "); 94 | // https://github.com/CyanogenMod/android_frameworks_native/blob/bf9b6621f64bff02fc94bc1b82b045d2ad64659b/libs/binder/Debug.cpp#L223 95 | // not sure why, but OK... this is way too dependent on the system for my taste, even in a hack like this... 96 | for (String lineReversedWord : lineReversedWords) { 97 | fixedBytesAsciiHex.append(lineReversedWord.substring(6, 8)) 98 | .append(lineReversedWord.substring(4,6)) 99 | .append(lineReversedWord.substring(2,4)) 100 | .append(lineReversedWord.substring(0, 2)); 101 | } 102 | } 103 | 104 | byte[] bytes = IccUtils.hexStringToBytes(fixedBytesAsciiHex.toString()); 105 | 106 | // unwrap the Binder parcel 107 | Parcel p = Parcel.obtain(); 108 | p.unmarshall(bytes, 0, bytes.length); 109 | p.setDataPosition(0); // I owe you one, StackOverflow person! http://stackoverflow.com/a/18000094 110 | p.readException(); 111 | bytes = p.createByteArray(); 112 | p.recycle(); 113 | 114 | if (bytes == null) { 115 | throw new IllegalArgumentException("error parsing parcel"); 116 | } 117 | 118 | // strip off sw1 and sw2 119 | int sw1 = bytes[bytes.length-2] & 0xff; 120 | int sw2 = bytes[bytes.length-1] & 0xff; 121 | bytes = Arrays.copyOf(bytes, bytes.length-2); 122 | 123 | Log.d(TAG, "iccIO parsedResult="+sw1+" "+sw2+" "+IccUtils.bytesToHexString(bytes)); 124 | 125 | IccIoResult iccIoResult = new IccIoResult(sw1, sw2, bytes); 126 | 127 | AsyncResult.forMessage(result, iccIoResult, null); 128 | result.sendToTarget(); 129 | } 130 | 131 | @Override 132 | public void registerForIccRefresh(IccRecords iccRecords, int eventRefresh, Object o) { 133 | } 134 | 135 | @Override 136 | public void unregisterForIccRefresh(IccRecords iccRecords) { 137 | } 138 | 139 | @Override 140 | public void getCDMASubscription(Message message) { 141 | throw new RuntimeException("unimplemented"); 142 | } 143 | 144 | @Override 145 | public void getIMSIForApp(String aid, Message message) { 146 | throw new RuntimeException("unimplemented"); 147 | } 148 | 149 | @Override 150 | public void setRadioPower(boolean b, Object o) { 151 | throw new RuntimeException("unimplemented"); 152 | } 153 | 154 | @Override 155 | public void dispose() { 156 | // empty 157 | } 158 | 159 | @Override 160 | public String getInterfaceDebugInfo() { 161 | return ""; 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /app/src/main/java/net/scintill/simio/telephony/CommandsInterface.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015 Joey Hewitt 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | package net.scintill.simio.telephony; 24 | 25 | import android.os.Message; 26 | 27 | import net.scintill.simio.telephony.uicc.IccRecords; 28 | 29 | public interface CommandsInterface { 30 | 31 | void iccIOForApp(int command, int fileid, String path, int p1, int p2, int p3, String data, String pin2, String aid, Message result); 32 | 33 | void registerForIccRefresh(IccRecords iccRecords, int eventRefresh, Object o); 34 | 35 | void unregisterForIccRefresh(IccRecords iccRecords); 36 | 37 | void getCDMASubscription(Message message); 38 | 39 | void getIMSIForApp(String aid, Message message); 40 | 41 | void setRadioPower(boolean b, Object o); 42 | 43 | void dispose(); 44 | 45 | String getInterfaceDebugInfo(); 46 | 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/net/scintill/simio/telephony/EncodeException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2006 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.scintill.simio.telephony; 18 | 19 | /** 20 | * {@hide} 21 | */ 22 | public class EncodeException extends Exception { 23 | public EncodeException() { 24 | super(); 25 | } 26 | 27 | public EncodeException(String s) { 28 | super(s); 29 | } 30 | 31 | public EncodeException(char c) { 32 | super("Unencodable char: '" + c + "'"); 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/java/net/scintill/simio/telephony/SmsConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 The Android Open Source Project 3 | * Copyright (c) 2012, The Linux Foundation. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package net.scintill.simio.telephony; 18 | 19 | /** 20 | * SMS Constants and must be the same as the corresponding 21 | * deprecated version in SmsMessage. 22 | * 23 | * @hide 24 | */ 25 | public class SmsConstants { 26 | /** User data text encoding code unit size */ 27 | public static final int ENCODING_UNKNOWN = 0; 28 | public static final int ENCODING_7BIT = 1; 29 | public static final int ENCODING_8BIT = 2; 30 | public static final int ENCODING_16BIT = 3; 31 | 32 | /** The maximum number of payload septets per message */ 33 | public static final int MAX_USER_DATA_SEPTETS = 160; 34 | 35 | /** 36 | * The maximum number of payload septets per message if a user data header 37 | * is present. This assumes the header only contains the 38 | * CONCATENATED_8_BIT_REFERENCE element. 39 | */ 40 | public static final int MAX_USER_DATA_SEPTETS_WITH_HEADER = 153; 41 | 42 | /** 43 | * This value is not defined in global standard. Only in Korea, this is used. 44 | */ 45 | public static final int ENCODING_KSC5601 = 4; 46 | 47 | /** The maximum number of payload bytes per message */ 48 | public static final int MAX_USER_DATA_BYTES = 140; 49 | 50 | /** 51 | * The maximum number of payload bytes per message if a user data header 52 | * is present. This assumes the header only contains the 53 | * CONCATENATED_8_BIT_REFERENCE element. 54 | */ 55 | public static final int MAX_USER_DATA_BYTES_WITH_HEADER = 134; 56 | 57 | /** 58 | * SMS Class enumeration. 59 | * See TS 23.038. 60 | */ 61 | public enum MessageClass{ 62 | UNKNOWN, CLASS_0, CLASS_1, CLASS_2, CLASS_3; 63 | } 64 | 65 | /** 66 | * Indicates unknown format SMS message. 67 | * @hide pending API council approval 68 | */ 69 | public static final String FORMAT_UNKNOWN = "unknown"; 70 | 71 | /** 72 | * Indicates a 3GPP format SMS message. 73 | * @hide pending API council approval 74 | */ 75 | public static final String FORMAT_3GPP = "3gpp"; 76 | 77 | /** 78 | * Indicates a 3GPP2 format SMS message. 79 | * @hide pending API council approval 80 | */ 81 | public static final String FORMAT_3GPP2 = "3gpp2"; 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/java/net/scintill/simio/telephony/TelephonyProperties.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. 3 | * Not a Contribution. 4 | * Copyright (C) 2006 The Android Open Source Project 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package net.scintill.simio.telephony; 20 | 21 | /** 22 | * Contains a list of string constants used to get or set telephone properties 23 | * in the system. You can use {@link android.os.SystemProperties os.SystemProperties} 24 | * to get and set these values. 25 | * @hide 26 | */ 27 | public interface TelephonyProperties 28 | { 29 | //****** Baseband and Radio Interface version 30 | 31 | //TODO T: property strings do not have to be gsm specific 32 | // change gsm.*operator.*" properties to "operator.*" properties 33 | 34 | /** 35 | * Baseband version 36 | * Availability: property is available any time radio is on 37 | */ 38 | static final String PROPERTY_BASEBAND_VERSION = "gsm.version.baseband"; 39 | 40 | /** Radio Interface Layer (RIL) library implementation. */ 41 | static final String PROPERTY_RIL_IMPL = "gsm.version.ril-impl"; 42 | 43 | //****** Current Network 44 | 45 | /** Alpha name of current registered operator.

46 | * Availability: when registered to a network. Result may be unreliable on 47 | * CDMA networks. 48 | */ 49 | static final String PROPERTY_OPERATOR_ALPHA = "gsm.operator.alpha"; 50 | //TODO: most of these properties are generic, substitute gsm. with phone. bug 1856959 51 | 52 | /** Numeric name (MCC+MNC) of current registered operator.

53 | * Availability: when registered to a network. Result may be unreliable on 54 | * CDMA networks. 55 | */ 56 | static final String PROPERTY_OPERATOR_NUMERIC = "gsm.operator.numeric"; 57 | 58 | /** 'true' if the device is on a manually selected network 59 | * 60 | * Availability: when registered to a network 61 | */ 62 | static final String PROPERTY_OPERATOR_ISMANUAL = "operator.ismanual"; 63 | 64 | /** 'true' if the device is considered roaming on this network for GSM 65 | * purposes. 66 | * Availability: when registered to a network 67 | */ 68 | static final String PROPERTY_OPERATOR_ISROAMING = "gsm.operator.isroaming"; 69 | 70 | /** The ISO country code equivalent of the current registered operator's 71 | * MCC (Mobile Country Code)

72 | * Availability: when registered to a network. Result may be unreliable on 73 | * CDMA networks. 74 | */ 75 | static final String PROPERTY_OPERATOR_ISO_COUNTRY = "gsm.operator.iso-country"; 76 | 77 | /** 78 | * The contents of this property is the value of the kernel command line 79 | * product_type variable that corresponds to a product that supports LTE on CDMA. 80 | * {@see BaseCommands#getLteOnCdmaMode()} 81 | */ 82 | static final String PROPERTY_LTE_ON_CDMA_PRODUCT_TYPE = "telephony.lteOnCdmaProductType"; 83 | 84 | /** 85 | * The contents of this property is the one of {@link Phone#LTE_ON_CDMA_TRUE} or 86 | * {@link Phone#LTE_ON_CDMA_FALSE}. If absent the value will assumed to be false 87 | * and the {@see #PROPERTY_LTE_ON_CDMA_PRODUCT_TYPE} will be used to determine its 88 | * final value which could also be {@link Phone#LTE_ON_CDMA_FALSE}. 89 | * {@see BaseCommands#getLteOnCdmaMode()} 90 | */ 91 | static final String PROPERTY_LTE_ON_CDMA_DEVICE = "telephony.lteOnCdmaDevice"; 92 | 93 | /** 94 | * {@see BaseCommands#getLteOnGsmMode()} 95 | */ 96 | static final String PROPERTY_LTE_ON_GSM_DEVICE = "telephony.lteOnGsmDevice"; 97 | 98 | static final String CURRENT_ACTIVE_PHONE = "gsm.current.phone-type"; 99 | 100 | //****** SIM Card 101 | /** 102 | * One of "UNKNOWN" "ABSENT" "PIN_REQUIRED" 103 | * "PUK_REQUIRED" "PERSO_LOCKED" or "READY" 104 | */ 105 | static String PROPERTY_SIM_STATE = "gsm.sim.state"; 106 | 107 | /** The MCC+MNC (mobile country code+mobile network code) of the 108 | * provider of the SIM. 5 or 6 decimal digits. 109 | * Availability: SIM state must be "READY" 110 | */ 111 | static String PROPERTY_ICC_OPERATOR_NUMERIC = "gsm.sim.operator.numeric"; 112 | 113 | /** The MCC+MNC (mobile country code+mobile network code) of the 114 | * provider of the SIM to be used for APNs lookup. 5 or 6 decimal digits. 115 | * Availability: SIM state must be "READY" 116 | */ 117 | static String PROPERTY_APN_SIM_OPERATOR_NUMERIC = "gsm.apn.sim.operator.numeric"; 118 | 119 | /** PROPERTY_ICC_OPERATOR_ALPHA is also known as the SPN, or Service Provider Name. 120 | * Availability: SIM state must be "READY" 121 | */ 122 | static String PROPERTY_ICC_OPERATOR_ALPHA = "gsm.sim.operator.alpha"; 123 | 124 | /** ISO country code equivalent for the SIM provider's country code*/ 125 | static String PROPERTY_ICC_OPERATOR_ISO_COUNTRY = "gsm.sim.operator.iso-country"; 126 | 127 | /** 128 | * Indicates the available radio technology. Values include: "unknown", 129 | * "GPRS", "EDGE" and "UMTS". 130 | */ 131 | static String PROPERTY_DATA_NETWORK_TYPE = "gsm.network.type"; 132 | 133 | /** Indicate if phone is in emergency callback mode */ 134 | static final String PROPERTY_INECM_MODE = "ril.cdma.inecmmode"; 135 | 136 | /** Indicate the timer value for exiting emergency callback mode */ 137 | static final String PROPERTY_ECM_EXIT_TIMER = "ro.cdma.ecmexittimer"; 138 | 139 | /** The international dialing prefix conversion string */ 140 | static final String PROPERTY_IDP_STRING = "ro.cdma.idpstring"; 141 | 142 | /** 143 | * Defines the schema for the carrier specified OTASP number 144 | */ 145 | static final String PROPERTY_OTASP_NUM_SCHEMA = "ro.cdma.otaspnumschema"; 146 | 147 | /** 148 | * Disable all calls including Emergency call when it set to true. 149 | */ 150 | static final String PROPERTY_DISABLE_CALL = "ro.telephony.disable-call"; 151 | 152 | /** 153 | * Set to true for vendor RIL's that send multiple UNSOL_CALL_RING notifications. 154 | */ 155 | static final String PROPERTY_RIL_SENDS_MULTIPLE_CALL_RING = 156 | "ro.telephony.call_ring.multiple"; 157 | 158 | /** 159 | * The number of milliseconds between CALL_RING notifications. 160 | */ 161 | static final String PROPERTY_CALL_RING_DELAY = "ro.telephony.call_ring.delay"; 162 | 163 | /** 164 | * Track CDMA SMS message id numbers to ensure they increment 165 | * monotonically, regardless of reboots. 166 | */ 167 | static final String PROPERTY_CDMA_MSG_ID = "persist.radio.cdma.msgid"; 168 | 169 | /** 170 | * Property to override DEFAULT_WAKE_LOCK_TIMEOUT 171 | */ 172 | static final String PROPERTY_WAKE_LOCK_TIMEOUT = "ro.ril.wake_lock_timeout"; 173 | 174 | /** 175 | * Set to true to indicate that the modem needs to be reset 176 | * when there is a radio technology change. 177 | */ 178 | static final String PROPERTY_RESET_ON_RADIO_TECH_CHANGE = "persist.radio.reset_on_switch"; 179 | 180 | /** 181 | * Set to false to disable SMS receiving, default is 182 | * the value of config_sms_capable 183 | */ 184 | static final String PROPERTY_SMS_RECEIVE = "telephony.sms.receive"; 185 | 186 | /** 187 | * Set to false to disable SMS sending, default is 188 | * the value of config_sms_capable 189 | */ 190 | static final String PROPERTY_SMS_SEND = "telephony.sms.send"; 191 | 192 | /** 193 | * Set to true to indicate a test CSIM card is used in the device. 194 | * This property is for testing purpose only. This should not be defined 195 | * in commercial configuration. 196 | */ 197 | static final String PROPERTY_TEST_CSIM = "persist.radio.test-csim"; 198 | 199 | /** 200 | * Specify if Android supports VoLTE/VT calls on IMS 201 | */ 202 | static final String CALLS_ON_IMS_ENABLED_PROPERTY = "persist.radio.calls.on.ims"; 203 | 204 | /** 205 | * Specify if Android supports CSVT calls. 206 | */ 207 | static final String PROPERTY_CSVT_ENABLED = "persist.radio.csvt.enabled"; 208 | 209 | /** 210 | * Ignore RIL_UNSOL_NITZ_TIME_RECEIVED completely, used for debugging/testing. 211 | */ 212 | static final String PROPERTY_IGNORE_NITZ = "telephony.test.ignore.nitz"; 213 | 214 | /** 215 | * Set to true to indicates support for simultaneous voice and EvDo. 216 | */ 217 | static final String PROPERTY_SVDO = "ro.ril.svdo"; 218 | 219 | /** 220 | * Property to control alpha ID display for proactive commands 221 | * Type: boolean ( true = alpha display enabled, false = alpha display disabled) 222 | */ 223 | static final String PROPERTY_ALPHA_USRCNF = "persist.atel.noalpha.usrcnf"; 224 | 225 | /** 226 | * Property to set multi sim feature. 227 | * Type: String(dsds, dsda) 228 | */ 229 | static final String PROPERTY_MULTI_SIM_CONFIG = "persist.radio.multisim.config"; 230 | 231 | /** 232 | * Property to store default subscription. 233 | */ 234 | static final String PROPERTY_DEFAULT_SUBSCRIPTION = "persist.radio.default.sub"; 235 | 236 | /** 237 | * Property to enable MMS Mode. 238 | * Type: string ( default = silent, enable to = prompt ) 239 | */ 240 | static final String PROPERTY_MMS_TRANSACTION = "mms.transaction"; 241 | } 242 | -------------------------------------------------------------------------------- /app/src/main/java/net/scintill/simio/telephony/cdma/sms/UserData.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.scintill.simio.telephony.cdma.sms; 18 | 19 | import android.util.SparseIntArray; 20 | 21 | public class UserData { 22 | 23 | /** 24 | * User data encoding types. 25 | * (See 3GPP2 C.R1001-F, v1.0, table 9.1-1) 26 | */ 27 | public static final int ENCODING_OCTET = 0x00; 28 | public static final int ENCODING_IS91_EXTENDED_PROTOCOL = 0x01; 29 | public static final int ENCODING_7BIT_ASCII = 0x02; 30 | public static final int ENCODING_IA5 = 0x03; 31 | public static final int ENCODING_UNICODE_16 = 0x04; 32 | public static final int ENCODING_SHIFT_JIS = 0x05; 33 | public static final int ENCODING_KOREAN = 0x06; 34 | public static final int ENCODING_LATIN_HEBREW = 0x07; 35 | public static final int ENCODING_LATIN = 0x08; 36 | public static final int ENCODING_GSM_7BIT_ALPHABET = 0x09; 37 | public static final int ENCODING_GSM_DCS = 0x0A; 38 | 39 | /** 40 | * User data message type encoding types. 41 | * (See 3GPP2 C.S0015-B, 4.5.2 and 3GPP 23.038, Section 4) 42 | */ 43 | public static final int ENCODING_GSM_DCS_7BIT = 0x00; 44 | public static final int ENCODING_GSM_DCS_8BIT = 0x01; 45 | public static final int ENCODING_GSM_DCS_16BIT = 0x02; 46 | 47 | /** 48 | * IS-91 message types. 49 | * (See TIA/EIS/IS-91-A-ENGL 1999, table 3.7.1.1-3) 50 | */ 51 | public static final int IS91_MSG_TYPE_VOICEMAIL_STATUS = 0x82; 52 | public static final int IS91_MSG_TYPE_SHORT_MESSAGE_FULL = 0x83; 53 | public static final int IS91_MSG_TYPE_CLI = 0x84; 54 | public static final int IS91_MSG_TYPE_SHORT_MESSAGE = 0x85; 55 | 56 | /** 57 | * US ASCII character mapping table. 58 | * 59 | * This table contains only the printable ASCII characters, with a 60 | * 0x20 offset, meaning that the ASCII SPACE character is at index 61 | * 0, with the resulting code of 0x20. 62 | * 63 | * Note this mapping is also equivalent to that used by both the 64 | * IA5 and the IS-91 encodings. For the former this is defined 65 | * using CCITT Rec. T.50 Tables 1 and 3. For the latter IS 637 B, 66 | * Table 4.3.1.4.1-1 -- and note the encoding uses only 6 bits, 67 | * and hence only maps entries up to the '_' character. 68 | * 69 | */ 70 | public static final char[] ASCII_MAP = { 71 | ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', 72 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', 73 | '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 74 | 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', 75 | '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 76 | 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~'}; 77 | 78 | /** 79 | * Character to use when forced to encode otherwise unencodable 80 | * characters, meaning those not in the respective ASCII or GSM 81 | * 7-bit encoding tables. Current choice is SPACE, which is 0x20 82 | * in both the GSM-7bit and ASCII-7bit encodings. 83 | */ 84 | static final byte UNENCODABLE_7_BIT_CHAR = 0x20; 85 | 86 | /** 87 | * Only elements between these indices in the ASCII table are printable. 88 | */ 89 | public static final int PRINTABLE_ASCII_MIN_INDEX = 0x20; 90 | public static final int ASCII_NL_INDEX = 0x0A; 91 | public static final int ASCII_CR_INDEX = 0x0D; 92 | public static final SparseIntArray charToAscii = new SparseIntArray(); 93 | static { 94 | for (int i = 0; i < ASCII_MAP.length; i++) { 95 | charToAscii.put(ASCII_MAP[i], PRINTABLE_ASCII_MIN_INDEX + i); 96 | } 97 | charToAscii.put('\n', ASCII_NL_INDEX); 98 | charToAscii.put('\r', ASCII_CR_INDEX); 99 | } 100 | 101 | /* 102 | * TODO(cleanup): Move this very generic functionality somewhere 103 | * more general. 104 | */ 105 | /** 106 | * Given a string generate a corresponding ASCII-encoded byte 107 | * array, but limited to printable characters. If the input 108 | * contains unprintable characters, return null. 109 | */ 110 | public static byte[] stringToAscii(String str) { 111 | int len = str.length(); 112 | byte[] result = new byte[len]; 113 | for (int i = 0; i < len; i++) { 114 | int charCode = charToAscii.get(str.charAt(i), -1); 115 | if (charCode == -1) return null; 116 | result[i] = (byte)charCode; 117 | } 118 | return result; 119 | } 120 | 121 | /** 122 | * Mapping for ASCII values less than 32 are flow control signals 123 | * and not used here. 124 | */ 125 | public static final int ASCII_MAP_BASE_INDEX = 0x20; 126 | public static final int ASCII_MAP_MAX_INDEX = ASCII_MAP_BASE_INDEX + ASCII_MAP.length - 1; 127 | 128 | /** 129 | * Contains the data encoding type for the SMS message 130 | */ 131 | public int msgEncoding; 132 | public boolean msgEncodingSet = false; 133 | 134 | public int msgType; 135 | 136 | /** 137 | * Number of invalid bits in the last byte of data. 138 | */ 139 | public int paddingBits; 140 | 141 | public int numFields; 142 | 143 | /** 144 | * Contains the user data of a SMS message 145 | * (See 3GPP2 C.S0015-B, v2, 4.5.2) 146 | */ 147 | public byte[] payload; 148 | public String payloadStr; 149 | 150 | @Override 151 | public String toString() { 152 | StringBuilder builder = new StringBuilder(); 153 | builder.append("UserData "); 154 | builder.append("{ msgEncoding=" + (msgEncodingSet ? msgEncoding : "unset")); 155 | builder.append(", msgType=" + msgType); 156 | builder.append(", paddingBits=" + paddingBits); 157 | builder.append(", numFields=" + numFields); 158 | builder.append(", payloadStr='" + payloadStr + "'"); 159 | builder.append(" }"); 160 | return builder.toString(); 161 | } 162 | 163 | } 164 | -------------------------------------------------------------------------------- /app/src/main/java/net/scintill/simio/telephony/gsm/SimTlv.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2006 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.scintill.simio.telephony.gsm; 18 | 19 | /** 20 | * SIM Tag-Length-Value record 21 | * TS 102 223 Annex C 22 | * 23 | * {@hide} 24 | * 25 | */ 26 | public class SimTlv 27 | { 28 | //***** Private Instance Variables 29 | 30 | byte mRecord[]; 31 | int mTlvOffset; 32 | int mTlvLength; 33 | int mCurOffset; 34 | int mCurDataOffset; 35 | int mCurDataLength; 36 | boolean mHasValidTlvObject; 37 | 38 | public SimTlv(byte[] record, int offset, int length) { 39 | mRecord = record; 40 | 41 | mTlvOffset = offset; 42 | mTlvLength = length; 43 | mCurOffset = offset; 44 | 45 | mHasValidTlvObject = parseCurrentTlvObject(); 46 | } 47 | 48 | public boolean nextObject() { 49 | if (!mHasValidTlvObject) return false; 50 | mCurOffset = mCurDataOffset + mCurDataLength; 51 | mHasValidTlvObject = parseCurrentTlvObject(); 52 | return mHasValidTlvObject; 53 | } 54 | 55 | public boolean isValidObject() { 56 | return mHasValidTlvObject; 57 | } 58 | 59 | /** 60 | * Returns the tag for the current TLV object 61 | * Return 0 if !isValidObject() 62 | * 0 and 0xff are invalid tag values 63 | * valid tags range from 1 - 0xfe 64 | */ 65 | public int getTag() { 66 | if (!mHasValidTlvObject) return 0; 67 | return mRecord[mCurOffset] & 0xff; 68 | } 69 | 70 | /** 71 | * Returns data associated with current TLV object 72 | * returns null if !isValidObject() 73 | */ 74 | 75 | public byte[] getData() { 76 | if (!mHasValidTlvObject) return null; 77 | 78 | byte[] ret = new byte[mCurDataLength]; 79 | System.arraycopy(mRecord, mCurDataOffset, ret, 0, mCurDataLength); 80 | return ret; 81 | } 82 | 83 | /** 84 | * Updates curDataLength and curDataOffset 85 | * @return false on invalid record, true on valid record 86 | */ 87 | 88 | private boolean parseCurrentTlvObject() { 89 | // 0x00 and 0xff are invalid tag values 90 | 91 | try { 92 | if (mRecord[mCurOffset] == 0 || (mRecord[mCurOffset] & 0xff) == 0xff) { 93 | return false; 94 | } 95 | 96 | if ((mRecord[mCurOffset + 1] & 0xff) < 0x80) { 97 | // one byte length 0 - 0x7f 98 | mCurDataLength = mRecord[mCurOffset + 1] & 0xff; 99 | mCurDataOffset = mCurOffset + 2; 100 | } else if ((mRecord[mCurOffset + 1] & 0xff) == 0x81) { 101 | // two byte length 0x80 - 0xff 102 | mCurDataLength = mRecord[mCurOffset + 2] & 0xff; 103 | mCurDataOffset = mCurOffset + 3; 104 | } else { 105 | return false; 106 | } 107 | } catch (ArrayIndexOutOfBoundsException ex) { 108 | return false; 109 | } 110 | 111 | if (mCurDataLength + mCurDataOffset > mTlvOffset + mTlvLength) { 112 | return false; 113 | } 114 | 115 | return true; 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /app/src/main/java/net/scintill/simio/telephony/uicc/AdnRecordLoader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2006 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.scintill.simio.telephony.uicc; 18 | 19 | import java.util.ArrayList; 20 | 21 | import android.os.AsyncResult; 22 | import android.os.Handler; 23 | import android.os.Looper; 24 | import android.os.Message; 25 | import android.util.Log; 26 | 27 | public class AdnRecordLoader extends Handler { 28 | final static String LOG_TAG = "AdnRecordLoader"; 29 | final static boolean VDBG = false; 30 | 31 | //***** Instance Variables 32 | 33 | private IccFileHandler mFh; 34 | int mEf; 35 | int mExtensionEF; 36 | int mPendingExtLoads; 37 | Message mUserResponse; 38 | String mPin2; 39 | 40 | // For "load one" 41 | int mRecordNumber; 42 | 43 | // for "load all" 44 | ArrayList mAdns; // only valid after EVENT_ADN_LOAD_ALL_DONE 45 | 46 | // Either an AdnRecord or a reference to adns depending 47 | // if this is a load one or load all operation 48 | Object mResult; 49 | 50 | //***** Event Constants 51 | 52 | static final int EVENT_ADN_LOAD_DONE = 1; 53 | static final int EVENT_EXT_RECORD_LOAD_DONE = 2; 54 | static final int EVENT_ADN_LOAD_ALL_DONE = 3; 55 | static final int EVENT_EF_LINEAR_RECORD_SIZE_DONE = 4; 56 | static final int EVENT_UPDATE_RECORD_DONE = 5; 57 | 58 | //***** Constructor 59 | 60 | AdnRecordLoader(IccFileHandler fh) { 61 | // The telephony unit-test cases may create AdnRecords 62 | // in secondary threads 63 | super(Looper.getMainLooper()); 64 | mFh = fh; 65 | } 66 | 67 | private String getEFPath(int efid) { 68 | if (efid == IccConstants.EF_ADN) { 69 | return IccConstants.MF_SIM + IccConstants.DF_TELECOM; 70 | } 71 | 72 | return null; 73 | } 74 | 75 | /** 76 | * Resulting AdnRecord is placed in response.obj.result 77 | * or response.obj.exception is set 78 | */ 79 | public void 80 | loadFromEF(int ef, int extensionEF, int recordNumber, 81 | Message response) { 82 | mEf = ef; 83 | mExtensionEF = extensionEF; 84 | mRecordNumber = recordNumber; 85 | mUserResponse = response; 86 | 87 | if (ef == IccConstants.EF_ADN) { 88 | mFh.loadEFLinearFixed( 89 | ef, getEFPath(ef), recordNumber, 90 | obtainMessage(EVENT_ADN_LOAD_DONE)); 91 | } else { 92 | mFh.loadEFLinearFixed( 93 | ef, recordNumber, 94 | obtainMessage(EVENT_ADN_LOAD_DONE)); 95 | } 96 | 97 | } 98 | 99 | 100 | /** 101 | * Resulting ArrayList<adnRecord> is placed in response.obj.result 102 | * or response.obj.exception is set 103 | */ 104 | public void 105 | loadAllFromEF(int ef, int extensionEF, 106 | Message response) { 107 | mEf = ef; 108 | mExtensionEF = extensionEF; 109 | mUserResponse = response; 110 | 111 | /* If we are loading from EF_ADN, specifically 112 | * specify the path as well, since, on some cards, 113 | * the fileid is not unique. 114 | */ 115 | if (ef == IccConstants.EF_ADN) { 116 | 117 | mFh.loadEFLinearFixedAll( 118 | ef, getEFPath(ef), 119 | obtainMessage(EVENT_ADN_LOAD_ALL_DONE)); 120 | } else { 121 | mFh.loadEFLinearFixedAll( 122 | ef, 123 | obtainMessage(EVENT_ADN_LOAD_ALL_DONE)); 124 | } 125 | } 126 | 127 | /** 128 | * Write adn to a EF SIM record 129 | * It will get the record size of EF record and compose hex adn array 130 | * then write the hex array to EF record 131 | * 132 | * @param adn is set with alphaTag and phone number 133 | * @param ef EF fileid 134 | * @param extensionEF extension EF fileid 135 | * @param recordNumber 1-based record index 136 | * @param pin2 for CHV2 operations, must be null if pin2 is not needed 137 | * @param response will be sent to its handler when completed 138 | */ 139 | public void 140 | updateEF(AdnRecord adn, int ef, int extensionEF, int recordNumber, 141 | String pin2, Message response) { 142 | mEf = ef; 143 | mExtensionEF = extensionEF; 144 | mRecordNumber = recordNumber; 145 | mUserResponse = response; 146 | mPin2 = pin2; 147 | 148 | if (ef == IccConstants.EF_ADN) { 149 | mFh.getEFLinearRecordSize( ef, getEFPath(ef), 150 | obtainMessage(EVENT_EF_LINEAR_RECORD_SIZE_DONE, adn)); 151 | } else { 152 | mFh.getEFLinearRecordSize( ef, 153 | obtainMessage(EVENT_EF_LINEAR_RECORD_SIZE_DONE, adn)); 154 | } 155 | } 156 | 157 | //***** Overridden from Handler 158 | 159 | @Override 160 | public void 161 | handleMessage(Message msg) { 162 | AsyncResult ar; 163 | byte data[]; 164 | AdnRecord adn; 165 | 166 | try { 167 | switch (msg.what) { 168 | case EVENT_EF_LINEAR_RECORD_SIZE_DONE: 169 | ar = (AsyncResult)(msg.obj); 170 | adn = (AdnRecord)(ar.userObj); 171 | 172 | if (ar.exception != null) { 173 | throw new RuntimeException("get EF record size failed", 174 | ar.exception); 175 | } 176 | 177 | int[] recordSize = (int[])ar.result; 178 | // recordSize is int[3] array 179 | // int[0] is the record length 180 | // int[1] is the total length of the EF file 181 | // int[2] is the number of records in the EF file 182 | // So int[0] * int[2] = int[1] 183 | if (recordSize.length != 3 || mRecordNumber > recordSize[2]) { 184 | throw new RuntimeException("get wrong EF record size format", 185 | ar.exception); 186 | } 187 | 188 | data = adn.buildAdnString(recordSize[0]); 189 | 190 | if(data == null) { 191 | throw new RuntimeException("wrong ADN format", 192 | ar.exception); 193 | } 194 | 195 | if (mEf == IccConstants.EF_ADN) { 196 | mFh.updateEFLinearFixed(mEf, getEFPath(mEf), mRecordNumber, 197 | data, mPin2, obtainMessage(EVENT_UPDATE_RECORD_DONE)); 198 | } else { 199 | mFh.updateEFLinearFixed(mEf, mRecordNumber, 200 | data, mPin2, obtainMessage(EVENT_UPDATE_RECORD_DONE)); 201 | } 202 | 203 | mPendingExtLoads = 1; 204 | 205 | break; 206 | case EVENT_UPDATE_RECORD_DONE: 207 | ar = (AsyncResult)(msg.obj); 208 | if (ar.exception != null) { 209 | throw new RuntimeException("update EF adn record failed", 210 | ar.exception); 211 | } 212 | mPendingExtLoads = 0; 213 | mResult = null; 214 | break; 215 | case EVENT_ADN_LOAD_DONE: 216 | ar = (AsyncResult)(msg.obj); 217 | data = (byte[])(ar.result); 218 | 219 | if (ar.exception != null) { 220 | throw new RuntimeException("load failed", ar.exception); 221 | } 222 | 223 | if (VDBG) { 224 | Log.d(LOG_TAG,"ADN EF: 0x" 225 | + Integer.toHexString(mEf) 226 | + ":" + mRecordNumber 227 | + "\n" + IccUtils.bytesToHexString(data)); 228 | } 229 | 230 | adn = new AdnRecord(mEf, mRecordNumber, data); 231 | mResult = adn; 232 | 233 | if (adn.hasExtendedRecord()) { 234 | // If we have a valid value in the ext record field, 235 | // we're not done yet: we need to read the corresponding 236 | // ext record and append it 237 | 238 | mPendingExtLoads = 1; 239 | 240 | mFh.loadEFLinearFixed( 241 | mExtensionEF, adn.mExtRecord, 242 | obtainMessage(EVENT_EXT_RECORD_LOAD_DONE, adn)); 243 | } 244 | break; 245 | 246 | case EVENT_EXT_RECORD_LOAD_DONE: 247 | ar = (AsyncResult)(msg.obj); 248 | data = (byte[])(ar.result); 249 | adn = (AdnRecord)(ar.userObj); 250 | 251 | if (ar.exception != null) { 252 | throw new RuntimeException("load failed", ar.exception); 253 | } 254 | 255 | Log.d(LOG_TAG,"ADN extension EF: 0x" 256 | + Integer.toHexString(mExtensionEF) 257 | + ":" + adn.mExtRecord 258 | + "\n" + IccUtils.bytesToHexString(data)); 259 | 260 | adn.appendExtRecord(data); 261 | 262 | mPendingExtLoads--; 263 | // result should have been set in 264 | // EVENT_ADN_LOAD_DONE or EVENT_ADN_LOAD_ALL_DONE 265 | break; 266 | 267 | case EVENT_ADN_LOAD_ALL_DONE: 268 | ar = (AsyncResult)(msg.obj); 269 | ArrayList datas = (ArrayList)(ar.result); 270 | 271 | if (ar.exception != null) { 272 | throw new RuntimeException("load failed", ar.exception); 273 | } 274 | 275 | mAdns = new ArrayList(datas.size()); 276 | mResult = mAdns; 277 | mPendingExtLoads = 0; 278 | 279 | for(int i = 0, s = datas.size() ; i < s ; i++) { 280 | adn = new AdnRecord(mEf, 1 + i, datas.get(i)); 281 | mAdns.add(adn); 282 | 283 | if (adn.hasExtendedRecord()) { 284 | // If we have a valid value in the ext record field, 285 | // we're not done yet: we need to read the corresponding 286 | // ext record and append it 287 | 288 | mPendingExtLoads++; 289 | 290 | mFh.loadEFLinearFixed( 291 | mExtensionEF, adn.mExtRecord, 292 | obtainMessage(EVENT_EXT_RECORD_LOAD_DONE, adn)); 293 | } 294 | } 295 | break; 296 | } 297 | } catch (RuntimeException exc) { 298 | if (mUserResponse != null) { 299 | AsyncResult.forMessage(mUserResponse) 300 | .exception = exc; 301 | mUserResponse.sendToTarget(); 302 | // Loading is all or nothing--either every load succeeds 303 | // or we fail the whole thing. 304 | mUserResponse = null; 305 | } 306 | return; 307 | } 308 | 309 | if (mUserResponse != null && mPendingExtLoads == 0) { 310 | AsyncResult.forMessage(mUserResponse).result 311 | = mResult; 312 | 313 | mUserResponse.sendToTarget(); 314 | mUserResponse = null; 315 | } 316 | } 317 | 318 | 319 | } 320 | -------------------------------------------------------------------------------- /app/src/main/java/net/scintill/simio/telephony/uicc/CsimFileHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2006, 2012 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.scintill.simio.telephony.uicc; 18 | 19 | import android.util.Log; 20 | 21 | import net.scintill.simio.telephony.CommandsInterface; 22 | 23 | /** 24 | * {@hide} 25 | * This class should be used to access files in CSIM ADF 26 | */ 27 | public final class CsimFileHandler extends IccFileHandler implements IccConstants { 28 | static final String LOG_TAG = "CsimFH"; 29 | 30 | public CsimFileHandler(UiccCardApplication app, String aid, CommandsInterface ci) { 31 | super(app, aid, ci); 32 | } 33 | 34 | @Override 35 | protected String getEFPath(int efid) { 36 | switch(efid) { 37 | case EF_SMS: 38 | case EF_CST: 39 | case EF_FDN: 40 | case EF_MSISDN: 41 | case EF_RUIM_SPN: 42 | case EF_CSIM_LI: 43 | case EF_CSIM_MDN: 44 | case EF_CSIM_IMSIM: 45 | case EF_CSIM_CDMAHOME: 46 | case EF_CSIM_EPRL: 47 | return MF_SIM + DF_ADF; 48 | } 49 | String path = getCommonIccEFPath(efid); 50 | if (path == null) { 51 | // The EFids in UICC phone book entries are decided by the card manufacturer. 52 | // So if we don't match any of the cases above and if its a UICC return 53 | // the global 3g phone book path. 54 | return MF_SIM + DF_TELECOM + DF_PHONEBOOK; 55 | } 56 | return path; 57 | } 58 | 59 | @Override 60 | protected void logd(String msg) { 61 | Log.d(LOG_TAG, msg); 62 | } 63 | 64 | @Override 65 | protected void loge(String msg) { 66 | Log.e(LOG_TAG, msg); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/net/scintill/simio/telephony/uicc/IccCardApplicationStatus.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2006 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.scintill.simio.telephony.uicc; 18 | 19 | import android.util.Log; 20 | 21 | import net.scintill.simio.telephony.uicc.IccCardStatus.PinState; 22 | 23 | 24 | /** 25 | * See also RIL_AppStatus in include/telephony/ril.h 26 | * 27 | * {@hide} 28 | */ 29 | public class IccCardApplicationStatus { 30 | public enum AppType{ 31 | APPTYPE_UNKNOWN, 32 | APPTYPE_SIM, 33 | APPTYPE_USIM, 34 | APPTYPE_RUIM, 35 | APPTYPE_CSIM, 36 | APPTYPE_ISIM 37 | } 38 | 39 | public enum AppState{ 40 | APPSTATE_UNKNOWN, 41 | APPSTATE_DETECTED, 42 | APPSTATE_PIN, 43 | APPSTATE_PUK, 44 | APPSTATE_SUBSCRIPTION_PERSO, 45 | APPSTATE_READY; 46 | 47 | boolean isPinRequired() { 48 | return this == APPSTATE_PIN; 49 | } 50 | 51 | boolean isPukRequired() { 52 | return this == APPSTATE_PUK; 53 | } 54 | 55 | boolean isSubscriptionPersoEnabled() { 56 | return this == APPSTATE_SUBSCRIPTION_PERSO; 57 | } 58 | 59 | boolean isAppReady() { 60 | return this == APPSTATE_READY; 61 | } 62 | 63 | boolean isAppNotReady() { 64 | return this == APPSTATE_UNKNOWN || 65 | this == APPSTATE_DETECTED; 66 | } 67 | } 68 | 69 | public enum PersoSubState{ 70 | PERSOSUBSTATE_UNKNOWN, 71 | PERSOSUBSTATE_IN_PROGRESS, 72 | PERSOSUBSTATE_READY, 73 | PERSOSUBSTATE_SIM_NETWORK, 74 | PERSOSUBSTATE_SIM_NETWORK_SUBSET, 75 | PERSOSUBSTATE_SIM_CORPORATE, 76 | PERSOSUBSTATE_SIM_SERVICE_PROVIDER, 77 | PERSOSUBSTATE_SIM_SIM, 78 | PERSOSUBSTATE_SIM_NETWORK_PUK, 79 | PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK, 80 | PERSOSUBSTATE_SIM_CORPORATE_PUK, 81 | PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK, 82 | PERSOSUBSTATE_SIM_SIM_PUK, 83 | PERSOSUBSTATE_RUIM_NETWORK1, 84 | PERSOSUBSTATE_RUIM_NETWORK2, 85 | PERSOSUBSTATE_RUIM_HRPD, 86 | PERSOSUBSTATE_RUIM_CORPORATE, 87 | PERSOSUBSTATE_RUIM_SERVICE_PROVIDER, 88 | PERSOSUBSTATE_RUIM_RUIM, 89 | PERSOSUBSTATE_RUIM_NETWORK1_PUK, 90 | PERSOSUBSTATE_RUIM_NETWORK2_PUK, 91 | PERSOSUBSTATE_RUIM_HRPD_PUK, 92 | PERSOSUBSTATE_RUIM_CORPORATE_PUK, 93 | PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK, 94 | PERSOSUBSTATE_RUIM_RUIM_PUK; 95 | 96 | boolean isPersoSubStateUnknown() { 97 | return this == PERSOSUBSTATE_UNKNOWN; 98 | } 99 | } 100 | 101 | public AppType app_type; 102 | public AppState app_state; 103 | // applicable only if app_state == RIL_APPSTATE_SUBSCRIPTION_PERSO 104 | public PersoSubState perso_substate; 105 | // null terminated string, e.g., from 0xA0, 0x00 -> 0x41, 0x30, 0x30, 0x30 */ 106 | public String aid; 107 | // null terminated string 108 | public String app_label; 109 | // applicable to USIM and CSIM 110 | public int pin1_replaced; 111 | public PinState pin1; 112 | public PinState pin2; 113 | 114 | public AppType AppTypeFromRILInt(int type) { 115 | AppType newType; 116 | /* RIL_AppType ril.h */ 117 | switch(type) { 118 | case 0: newType = AppType.APPTYPE_UNKNOWN; break; 119 | case 1: newType = AppType.APPTYPE_SIM; break; 120 | case 2: newType = AppType.APPTYPE_USIM; break; 121 | case 3: newType = AppType.APPTYPE_RUIM; break; 122 | case 4: newType = AppType.APPTYPE_CSIM; break; 123 | case 5: newType = AppType.APPTYPE_ISIM; break; 124 | default: 125 | newType = AppType.APPTYPE_UNKNOWN; 126 | loge("AppTypeFromRILInt: bad RIL_AppType: " + type + " use APPTYPE_UNKNOWN"); 127 | } 128 | return newType; 129 | } 130 | 131 | public AppState AppStateFromRILInt(int state) { 132 | AppState newState; 133 | /* RIL_AppState ril.h */ 134 | switch(state) { 135 | case 0: newState = AppState.APPSTATE_UNKNOWN; break; 136 | case 1: newState = AppState.APPSTATE_DETECTED; break; 137 | case 2: newState = AppState.APPSTATE_PIN; break; 138 | case 3: newState = AppState.APPSTATE_PUK; break; 139 | case 4: newState = AppState.APPSTATE_SUBSCRIPTION_PERSO; break; 140 | case 5: newState = AppState.APPSTATE_READY; break; 141 | default: 142 | newState = AppState.APPSTATE_UNKNOWN; 143 | loge("AppStateFromRILInt: bad state: " + state + " use APPSTATE_UNKNOWN"); 144 | } 145 | return newState; 146 | } 147 | 148 | public PersoSubState PersoSubstateFromRILInt(int substate) { 149 | PersoSubState newSubState; 150 | /* RIL_PeroSubstate ril.h */ 151 | switch(substate) { 152 | case 0: newSubState = PersoSubState.PERSOSUBSTATE_UNKNOWN; break; 153 | case 1: newSubState = PersoSubState.PERSOSUBSTATE_IN_PROGRESS; break; 154 | case 2: newSubState = PersoSubState.PERSOSUBSTATE_READY; break; 155 | case 3: newSubState = PersoSubState.PERSOSUBSTATE_SIM_NETWORK; break; 156 | case 4: newSubState = PersoSubState.PERSOSUBSTATE_SIM_NETWORK_SUBSET; break; 157 | case 5: newSubState = PersoSubState.PERSOSUBSTATE_SIM_CORPORATE; break; 158 | case 6: newSubState = PersoSubState.PERSOSUBSTATE_SIM_SERVICE_PROVIDER; break; 159 | case 7: newSubState = PersoSubState.PERSOSUBSTATE_SIM_SIM; break; 160 | case 8: newSubState = PersoSubState.PERSOSUBSTATE_SIM_NETWORK_PUK; break; 161 | case 9: newSubState = PersoSubState.PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK; break; 162 | case 10: newSubState = PersoSubState.PERSOSUBSTATE_SIM_CORPORATE_PUK; break; 163 | case 11: newSubState = PersoSubState.PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK; break; 164 | case 12: newSubState = PersoSubState.PERSOSUBSTATE_SIM_SIM_PUK; break; 165 | case 13: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_NETWORK1; break; 166 | case 14: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_NETWORK2; break; 167 | case 15: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_HRPD; break; 168 | case 16: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_CORPORATE; break; 169 | case 17: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_SERVICE_PROVIDER; break; 170 | case 18: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_RUIM; break; 171 | case 19: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_NETWORK1_PUK; break; 172 | case 20: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_NETWORK2_PUK; break; 173 | case 21: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_HRPD_PUK ; break; 174 | case 22: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_CORPORATE_PUK; break; 175 | case 23: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK; break; 176 | case 24: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_RUIM_PUK; break; 177 | default: 178 | newSubState = PersoSubState.PERSOSUBSTATE_UNKNOWN; 179 | loge("PersoSubstateFromRILInt: bad substate: " + substate 180 | + " use PERSOSUBSTATE_UNKNOWN"); 181 | } 182 | return newSubState; 183 | } 184 | 185 | public PinState PinStateFromRILInt(int state) { 186 | PinState newPinState; 187 | switch(state) { 188 | case 0: 189 | newPinState = PinState.PINSTATE_UNKNOWN; 190 | break; 191 | case 1: 192 | newPinState = PinState.PINSTATE_ENABLED_NOT_VERIFIED; 193 | break; 194 | case 2: 195 | newPinState = PinState.PINSTATE_ENABLED_VERIFIED; 196 | break; 197 | case 3: 198 | newPinState = PinState.PINSTATE_DISABLED; 199 | break; 200 | case 4: 201 | newPinState = PinState.PINSTATE_ENABLED_BLOCKED; 202 | break; 203 | case 5: 204 | newPinState = PinState.PINSTATE_ENABLED_PERM_BLOCKED; 205 | break; 206 | default: 207 | newPinState = PinState.PINSTATE_UNKNOWN; 208 | loge("PinStateFromRILInt: bad pin state: " + state + " use PINSTATE_UNKNOWN"); 209 | } 210 | return newPinState; 211 | } 212 | 213 | @Override 214 | public String toString() { 215 | StringBuilder sb = new StringBuilder(); 216 | 217 | sb.append("{").append(app_type).append(",").append(app_state); 218 | if (app_state == AppState.APPSTATE_SUBSCRIPTION_PERSO) { 219 | sb.append(",").append(perso_substate); 220 | } 221 | if (app_type == AppType.APPTYPE_CSIM || 222 | app_type == AppType.APPTYPE_USIM || 223 | app_type == AppType.APPTYPE_ISIM) { 224 | sb.append(",pin1=").append(pin1); 225 | sb.append(",pin2=").append(pin2); 226 | } 227 | sb.append("}"); 228 | return sb.toString(); 229 | } 230 | 231 | private void loge(String s) { 232 | Log.e("IccCardApplicationStatus", s); 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /app/src/main/java/net/scintill/simio/telephony/uicc/IccCardStatus.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2006 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.scintill.simio.telephony.uicc; 18 | 19 | /** 20 | * See also RIL_CardStatus in include/telephony/ril.h 21 | * 22 | * {@hide} 23 | */ 24 | public class IccCardStatus { 25 | public static final int CARD_MAX_APPS = 8; 26 | 27 | public enum CardState { 28 | CARDSTATE_ABSENT, 29 | CARDSTATE_PRESENT, 30 | CARDSTATE_ERROR; 31 | 32 | boolean isCardPresent() { 33 | return this == CARDSTATE_PRESENT; 34 | } 35 | 36 | boolean isCardFaulty() { 37 | return this == CARDSTATE_ERROR; 38 | } 39 | }; 40 | 41 | public enum PinState { 42 | PINSTATE_UNKNOWN, 43 | PINSTATE_ENABLED_NOT_VERIFIED, 44 | PINSTATE_ENABLED_VERIFIED, 45 | PINSTATE_DISABLED, 46 | PINSTATE_ENABLED_BLOCKED, 47 | PINSTATE_ENABLED_PERM_BLOCKED; 48 | 49 | boolean isPermBlocked() { 50 | return this == PINSTATE_ENABLED_PERM_BLOCKED; 51 | } 52 | 53 | boolean isPinRequired() { 54 | return this == PINSTATE_ENABLED_NOT_VERIFIED; 55 | } 56 | 57 | boolean isPukRequired() { 58 | return this == PINSTATE_ENABLED_BLOCKED; 59 | } 60 | } 61 | 62 | public CardState mCardState; 63 | public PinState mUniversalPinState; 64 | public int mGsmUmtsSubscriptionAppIndex; 65 | public int mCdmaSubscriptionAppIndex; 66 | public int mImsSubscriptionAppIndex; 67 | 68 | public IccCardApplicationStatus[] mApplications; 69 | 70 | public void setCardState(int state) { 71 | switch(state) { 72 | case 0: 73 | mCardState = CardState.CARDSTATE_ABSENT; 74 | break; 75 | case 1: 76 | mCardState = CardState.CARDSTATE_PRESENT; 77 | break; 78 | case 2: 79 | mCardState = CardState.CARDSTATE_ERROR; 80 | break; 81 | default: 82 | throw new RuntimeException("Unrecognized RIL_CardState: " + state); 83 | } 84 | } 85 | 86 | public void setUniversalPinState(int state) { 87 | switch(state) { 88 | case 0: 89 | mUniversalPinState = PinState.PINSTATE_UNKNOWN; 90 | break; 91 | case 1: 92 | mUniversalPinState = PinState.PINSTATE_ENABLED_NOT_VERIFIED; 93 | break; 94 | case 2: 95 | mUniversalPinState = PinState.PINSTATE_ENABLED_VERIFIED; 96 | break; 97 | case 3: 98 | mUniversalPinState = PinState.PINSTATE_DISABLED; 99 | break; 100 | case 4: 101 | mUniversalPinState = PinState.PINSTATE_ENABLED_BLOCKED; 102 | break; 103 | case 5: 104 | mUniversalPinState = PinState.PINSTATE_ENABLED_PERM_BLOCKED; 105 | break; 106 | default: 107 | throw new RuntimeException("Unrecognized RIL_PinState: " + state); 108 | } 109 | } 110 | 111 | @Override 112 | public String toString() { 113 | IccCardApplicationStatus app; 114 | 115 | StringBuilder sb = new StringBuilder(); 116 | sb.append("IccCardState {").append(mCardState).append(",") 117 | .append(mUniversalPinState) 118 | .append(",num_apps=").append(mApplications.length) 119 | .append(",gsm_id=").append(mGsmUmtsSubscriptionAppIndex); 120 | if (mGsmUmtsSubscriptionAppIndex >=0 121 | && mGsmUmtsSubscriptionAppIndex 0x41, 35 | 0x30, 0x30, 0x30 */ 36 | /* Example: a0000000871002f310ffff89080000ff */ 37 | 38 | @Override 39 | public String toString() { 40 | return "{" + refreshResult + ", " + aid +", " + efId + "}"; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/net/scintill/simio/telephony/uicc/IccVmFixedException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.scintill.simio.telephony.uicc; 18 | 19 | 20 | /** 21 | * {@hide} 22 | */ 23 | public final class IccVmFixedException extends IccException { 24 | IccVmFixedException() 25 | { 26 | 27 | } 28 | 29 | public IccVmFixedException(String s) 30 | { 31 | super(s); 32 | } 33 | } -------------------------------------------------------------------------------- /app/src/main/java/net/scintill/simio/telephony/uicc/IccVmNotSupportedException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.scintill.simio.telephony.uicc; 18 | 19 | 20 | /** 21 | * {@hide} 22 | */ 23 | public final class IccVmNotSupportedException extends IccException { 24 | IccVmNotSupportedException() 25 | { 26 | 27 | } 28 | 29 | public IccVmNotSupportedException(String s) 30 | { 31 | super(s); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/net/scintill/simio/telephony/uicc/IsimFileHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2006, 2012 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.scintill.simio.telephony.uicc; 18 | 19 | import android.util.Log; 20 | 21 | import net.scintill.simio.telephony.CommandsInterface; 22 | 23 | /** 24 | * {@hide} 25 | * This class should be used to access files in ISIM ADF 26 | */ 27 | public final class IsimFileHandler extends IccFileHandler implements IccConstants { 28 | static final String LOG_TAG = "IsimFH"; 29 | 30 | public IsimFileHandler(UiccCardApplication app, String aid, CommandsInterface ci) { 31 | super(app, aid, ci); 32 | } 33 | 34 | @Override 35 | protected String getEFPath(int efid) { 36 | switch(efid) { 37 | case EF_IMPI: 38 | case EF_IMPU: 39 | case EF_DOMAIN: 40 | return MF_SIM + DF_ADF; 41 | } 42 | String path = getCommonIccEFPath(efid); 43 | return path; 44 | } 45 | 46 | @Override 47 | protected void logd(String msg) { 48 | Log.d(LOG_TAG, msg); 49 | } 50 | 51 | @Override 52 | protected void loge(String msg) { 53 | Log.e(LOG_TAG, msg); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/net/scintill/simio/telephony/uicc/IsimRecords.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.scintill.simio.telephony.uicc; 18 | 19 | /** 20 | * {@hide} 21 | */ 22 | public interface IsimRecords { 23 | 24 | /** 25 | * Return the IMS private user identity (IMPI). 26 | * Returns null if the IMPI hasn't been loaded or isn't present on the ISIM. 27 | * @return the IMS private user identity string, or null if not available 28 | */ 29 | String getIsimImpi(); 30 | 31 | /** 32 | * Return the IMS home network domain name. 33 | * Returns null if the IMS domain hasn't been loaded or isn't present on the ISIM. 34 | * @return the IMS home network domain name, or null if not available 35 | */ 36 | String getIsimDomain(); 37 | 38 | /** 39 | * Return an array of IMS public user identities (IMPU). 40 | * Returns null if the IMPU hasn't been loaded or isn't present on the ISIM. 41 | * @return an array of IMS public user identity strings, or null if not available 42 | */ 43 | String[] getIsimImpu(); 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/net/scintill/simio/telephony/uicc/IsimUiccRecords.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.scintill.simio.telephony.uicc; 18 | 19 | import android.content.Context; 20 | import android.os.AsyncResult; 21 | import android.os.Message; 22 | import android.util.Log; 23 | 24 | import net.scintill.simio.telephony.CommandsInterface; 25 | import net.scintill.simio.telephony.gsm.SimTlv; 26 | //import com.android.internal.telephony.gsm.VoiceMailConstants; 27 | 28 | import java.io.FileDescriptor; 29 | import java.io.PrintWriter; 30 | import java.nio.charset.Charset; 31 | import java.util.ArrayList; 32 | import java.util.Arrays; 33 | 34 | /** 35 | * {@hide} 36 | */ 37 | public final class IsimUiccRecords extends IccRecords implements IsimRecords { 38 | protected static final String LOG_TAG = "IsimUiccRecords"; 39 | 40 | private static final boolean DBG = true; 41 | private static final boolean DUMP_RECORDS = false; // Note: PII is logged when this is true 42 | 43 | private static final int EVENT_APP_READY = 1; 44 | 45 | // ISIM EF records (see 3GPP TS 31.103) 46 | private String mIsimImpi; // IMS private user identity 47 | private String mIsimDomain; // IMS home network domain name 48 | private String[] mIsimImpu; // IMS public user identity(s) 49 | 50 | private static final int TAG_ISIM_VALUE = 0x80; // From 3GPP TS 31.103 51 | 52 | @Override 53 | public String toString() { 54 | return "IsimUiccRecords: " + super.toString() 55 | + " mIsimImpi=" + mIsimImpi 56 | + " mIsimDomain=" + mIsimDomain 57 | + " mIsimImpu=" + mIsimImpu; 58 | } 59 | 60 | public IsimUiccRecords(UiccCardApplication app, Context c, CommandsInterface ci) { 61 | super(app, c, ci); 62 | 63 | mRecordsRequested = false; // No load request is made till SIM ready 64 | 65 | // recordsToLoad is set to 0 because no requests are made yet 66 | mRecordsToLoad = 0; 67 | 68 | mParentApp.registerForReady(this, EVENT_APP_READY, null); 69 | if (DBG) log("IsimUiccRecords X ctor this=" + this); 70 | } 71 | 72 | @Override 73 | public void dispose() { 74 | log("Disposing " + this); 75 | //Unregister for all events 76 | mParentApp.unregisterForReady(this); 77 | resetRecords(); 78 | super.dispose(); 79 | } 80 | 81 | // ***** Overridden from Handler 82 | public void handleMessage(Message msg) { 83 | if (mDestroyed.get()) { 84 | Log.e(LOG_TAG, "Received message " + msg + 85 | "[" + msg.what + "] while being destroyed. Ignoring."); 86 | return; 87 | } 88 | 89 | try { 90 | switch (msg.what) { 91 | case EVENT_APP_READY: 92 | onReady(); 93 | break; 94 | 95 | default: 96 | super.handleMessage(msg); // IccRecords handles generic record load responses 97 | 98 | } 99 | } catch (RuntimeException exc) { 100 | // I don't want these exceptions to be fatal 101 | Log.w(LOG_TAG, "Exception parsing SIM record", exc); 102 | } 103 | } 104 | 105 | protected void fetchIsimRecords() { 106 | mRecordsRequested = true; 107 | 108 | mFh.loadEFTransparent(EF_IMPI, obtainMessage( 109 | IccRecords.EVENT_GET_ICC_RECORD_DONE, new EfIsimImpiLoaded())); 110 | mRecordsToLoad++; 111 | 112 | mFh.loadEFLinearFixedAll(EF_IMPU, obtainMessage( 113 | IccRecords.EVENT_GET_ICC_RECORD_DONE, new EfIsimImpuLoaded())); 114 | mRecordsToLoad++; 115 | 116 | mFh.loadEFTransparent(EF_DOMAIN, obtainMessage( 117 | IccRecords.EVENT_GET_ICC_RECORD_DONE, new EfIsimDomainLoaded())); 118 | mRecordsToLoad++; 119 | 120 | log("fetchIsimRecords " + mRecordsToLoad); 121 | } 122 | 123 | protected void resetRecords() { 124 | // recordsRequested is set to false indicating that the SIM 125 | // read requests made so far are not valid. This is set to 126 | // true only when fresh set of read requests are made. 127 | mRecordsRequested = false; 128 | } 129 | 130 | private class EfIsimImpiLoaded implements IccRecords.IccRecordLoaded { 131 | public String getEfName() { 132 | return "EF_ISIM_IMPI"; 133 | } 134 | public void onRecordLoaded(AsyncResult ar) { 135 | byte[] data = (byte[]) ar.result; 136 | mIsimImpi = isimTlvToString(data); 137 | if (DUMP_RECORDS) log("EF_IMPI=" + mIsimImpi); 138 | } 139 | } 140 | 141 | private class EfIsimImpuLoaded implements IccRecords.IccRecordLoaded { 142 | public String getEfName() { 143 | return "EF_ISIM_IMPU"; 144 | } 145 | public void onRecordLoaded(AsyncResult ar) { 146 | ArrayList impuList = (ArrayList) ar.result; 147 | if (DBG) log("EF_IMPU record count: " + impuList.size()); 148 | mIsimImpu = new String[impuList.size()]; 149 | int i = 0; 150 | for (byte[] identity : impuList) { 151 | String impu = isimTlvToString(identity); 152 | if (DUMP_RECORDS) log("EF_IMPU[" + i + "]=" + impu); 153 | mIsimImpu[i++] = impu; 154 | } 155 | } 156 | } 157 | 158 | private class EfIsimDomainLoaded implements IccRecords.IccRecordLoaded { 159 | public String getEfName() { 160 | return "EF_ISIM_DOMAIN"; 161 | } 162 | public void onRecordLoaded(AsyncResult ar) { 163 | byte[] data = (byte[]) ar.result; 164 | mIsimDomain = isimTlvToString(data); 165 | if (DUMP_RECORDS) log("EF_DOMAIN=" + mIsimDomain); 166 | } 167 | } 168 | 169 | /** 170 | * ISIM records for IMS are stored inside a Tag-Length-Value record as a UTF-8 string 171 | * with tag value 0x80. 172 | * @param record the byte array containing the IMS data string 173 | * @return the decoded String value, or null if the record can't be decoded 174 | */ 175 | private static String isimTlvToString(byte[] record) { 176 | SimTlv tlv = new SimTlv(record, 0, record.length); 177 | do { 178 | if (tlv.getTag() == TAG_ISIM_VALUE) { 179 | return new String(tlv.getData(), Charset.forName("UTF-8")); 180 | } 181 | } while (tlv.nextObject()); 182 | 183 | Log.e(LOG_TAG, "[ISIM] can't find TLV tag in ISIM record, returning null"); 184 | return null; 185 | } 186 | 187 | @Override 188 | protected void onRecordLoaded() { 189 | // One record loaded successfully or failed, In either case 190 | // we need to update the recordsToLoad count 191 | mRecordsToLoad -= 1; 192 | 193 | if (mRecordsToLoad == 0 && mRecordsRequested == true) { 194 | onAllRecordsLoaded(); 195 | } else if (mRecordsToLoad < 0) { 196 | loge("recordsToLoad <0, programmer error suspected"); 197 | mRecordsToLoad = 0; 198 | } 199 | } 200 | 201 | @Override 202 | protected void onAllRecordsLoaded() { 203 | mRecordsLoadedRegistrants.notifyRegistrants( 204 | new AsyncResult(null, null, null)); 205 | } 206 | 207 | /** 208 | * Return the IMS private user identity (IMPI). 209 | * Returns null if the IMPI hasn't been loaded or isn't present on the ISIM. 210 | * @return the IMS private user identity string, or null if not available 211 | */ 212 | @Override 213 | public String getIsimImpi() { 214 | return mIsimImpi; 215 | } 216 | 217 | /** 218 | * Return the IMS home network domain name. 219 | * Returns null if the IMS domain hasn't been loaded or isn't present on the ISIM. 220 | * @return the IMS home network domain name, or null if not available 221 | */ 222 | @Override 223 | public String getIsimDomain() { 224 | return mIsimDomain; 225 | } 226 | 227 | /** 228 | * Return an array of IMS public user identities (IMPU). 229 | * Returns null if the IMPU hasn't been loaded or isn't present on the ISIM. 230 | * @return an array of IMS public user identity strings, or null if not available 231 | */ 232 | @Override 233 | public String[] getIsimImpu() { 234 | return (mIsimImpu != null) ? mIsimImpu.clone() : null; 235 | } 236 | 237 | @Override 238 | public int getDisplayRule(String plmn) { 239 | // Not applicable to Isim 240 | return 0; 241 | } 242 | 243 | @Override 244 | public void onReady() { 245 | fetchIsimRecords(); 246 | } 247 | 248 | @Override 249 | protected void handleFileUpdate(int efid) { 250 | // We do not handle it in Isim 251 | } 252 | 253 | @Override 254 | public void onRefresh(boolean fileChanged, int[] fileList) { 255 | // We do not handle it in Isim 256 | } 257 | 258 | @Override 259 | public void setVoiceMailNumber(String alphaTag, String voiceNumber, 260 | Message onComplete) { 261 | // Not applicable to Isim 262 | } 263 | 264 | @Override 265 | public void setVoiceMessageWaiting(int line, int countWaiting) { 266 | // Not applicable to Isim 267 | } 268 | 269 | @Override 270 | protected void log(String s) { 271 | if (DBG) Log.d(LOG_TAG, "[ISIM] " + s); 272 | } 273 | 274 | @Override 275 | protected void loge(String s) { 276 | if (DBG) Log.e(LOG_TAG, "[ISIM] " + s); 277 | } 278 | 279 | @Override 280 | public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 281 | pw.println("IsimRecords: " + this); 282 | pw.println(" extends:"); 283 | super.dump(fd, pw, args); 284 | pw.println(" mIsimImpi=" + mIsimImpi); 285 | pw.println(" mIsimDomain=" + mIsimDomain); 286 | pw.println(" mIsimImpu[]=" + Arrays.toString(mIsimImpu)); 287 | pw.flush(); 288 | } 289 | 290 | public int getVoiceMessageCount() { 291 | return 0; // Not applicable to Isim 292 | } 293 | 294 | } 295 | -------------------------------------------------------------------------------- /app/src/main/java/net/scintill/simio/telephony/uicc/RuimFileHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.scintill.simio.telephony.uicc; 18 | 19 | import android.os.*; 20 | import android.util.Log; 21 | 22 | import net.scintill.simio.telephony.CommandsInterface; 23 | 24 | /** 25 | * {@hide} 26 | */ 27 | public final class RuimFileHandler extends IccFileHandler { 28 | static final String LOG_TAG = "RuimFH"; 29 | 30 | //***** Instance Variables 31 | 32 | //***** Constructor 33 | public RuimFileHandler(UiccCardApplication app, String aid, CommandsInterface ci) { 34 | super(app, aid, ci); 35 | } 36 | 37 | //***** Overridden from IccFileHandler 38 | 39 | @Override 40 | public void loadEFImgTransparent(int fileid, int highOffset, int lowOffset, 41 | int length, Message onLoaded) { 42 | Message response = obtainMessage(EVENT_READ_ICON_DONE, fileid, 0, 43 | onLoaded); 44 | 45 | /* Per TS 31.102, for displaying of Icon, under 46 | * DF Telecom and DF Graphics , EF instance(s) (4FXX,transparent files) 47 | * are present. The possible image file identifiers (EF instance) for 48 | * EF img ( 4F20, linear fixed file) are : 4F01 ... 4F05. 49 | * It should be MF_SIM + DF_TELECOM + DF_GRAPHICS, same path as EF IMG 50 | */ 51 | mCi.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(EF_IMG), 0, 0, 52 | GET_RESPONSE_EF_IMG_SIZE_BYTES, null, null, 53 | mAid, response); 54 | } 55 | 56 | @Override 57 | protected String getEFPath(int efid) { 58 | switch(efid) { 59 | case EF_SMS: 60 | case EF_CST: 61 | case EF_RUIM_SPN: 62 | case EF_RUIM_ID: 63 | case EF_CSIM_LI: 64 | case EF_CSIM_MDN: 65 | case EF_CSIM_IMSIM: 66 | case EF_CSIM_CDMAHOME: 67 | case EF_CSIM_EPRL: 68 | return MF_SIM + DF_CDMA; 69 | } 70 | return getCommonIccEFPath(efid); 71 | } 72 | 73 | @Override 74 | protected void logd(String msg) { 75 | Log.d(LOG_TAG, "[RuimFileHandler] " + msg); 76 | } 77 | 78 | @Override 79 | protected void loge(String msg) { 80 | Log.e(LOG_TAG, "[RuimFileHandler] " + msg); 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/net/scintill/simio/telephony/uicc/SIMFileHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2006 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.scintill.simio.telephony.uicc; 18 | 19 | import android.util.Log; 20 | 21 | import net.scintill.simio.telephony.CommandsInterface; 22 | 23 | /** 24 | * {@hide} 25 | */ 26 | public final class SIMFileHandler extends IccFileHandler implements IccConstants { 27 | static final String LOG_TAG = "SIMFileHandler"; 28 | 29 | //***** Instance Variables 30 | 31 | //***** Constructor 32 | 33 | public SIMFileHandler(UiccCardApplication app, String aid, CommandsInterface ci) { 34 | super(app, aid, ci); 35 | } 36 | 37 | //***** Overridden from IccFileHandler 38 | 39 | @Override 40 | protected String getEFPath(int efid) { 41 | // TODO(): DF_GSM can be 7F20 or 7F21 to handle backward compatibility. 42 | // Implement this after discussion with OEMs. 43 | switch(efid) { 44 | case EF_SMS: 45 | return MF_SIM + DF_TELECOM; 46 | 47 | case EF_EXT6: 48 | case EF_MWIS: 49 | case EF_MBI: 50 | case EF_SPN: 51 | case EF_AD: 52 | case EF_MBDN: 53 | case EF_PNN: 54 | case EF_SPDI: 55 | case EF_SST: 56 | case EF_CFIS: 57 | case EF_GID1: 58 | return MF_SIM + DF_GSM; 59 | 60 | case EF_MAILBOX_CPHS: 61 | case EF_VOICE_MAIL_INDICATOR_CPHS: 62 | case EF_CFF_CPHS: 63 | case EF_SPN_CPHS: 64 | case EF_SPN_SHORT_CPHS: 65 | case EF_INFO_CPHS: 66 | case EF_CSP_CPHS: 67 | case EF_PLMNWACT: 68 | case EF_LOCI: 69 | return MF_SIM + DF_GSM; 70 | } 71 | String path = getCommonIccEFPath(efid); 72 | if (path == null) { 73 | Log.e(LOG_TAG, "Error: EF Path being returned in null"); 74 | } 75 | return path; 76 | } 77 | 78 | @Override 79 | protected void logd(String msg) { 80 | Log.d(LOG_TAG, msg); 81 | } 82 | 83 | @Override 84 | protected void loge(String msg) { 85 | Log.e(LOG_TAG, msg); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /app/src/main/java/net/scintill/simio/telephony/uicc/UiccCardApplication.java: -------------------------------------------------------------------------------- 1 | package net.scintill.simio.telephony.uicc; 2 | 3 | import android.os.Handler; 4 | 5 | public interface UiccCardApplication { 6 | 7 | public IccCardApplicationStatus.AppType getType(); 8 | 9 | IccFileHandler getIccFileHandler(); 10 | 11 | IccCardApplicationStatus.AppState getState(); 12 | 13 | String getAid(); 14 | 15 | void registerForReady(Handler handler, int what, Object o); 16 | 17 | void unregisterForReady(Handler handler); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/net/scintill/simio/telephony/uicc/UsimFileHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2006, 2012 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.scintill.simio.telephony.uicc; 18 | 19 | import android.util.Log; 20 | 21 | import net.scintill.simio.telephony.CommandsInterface; 22 | 23 | /** 24 | * {@hide} 25 | * This class should be used to access files in USIM ADF 26 | */ 27 | public final class UsimFileHandler extends IccFileHandler implements IccConstants { 28 | static final String LOG_TAG = "UsimFH"; 29 | 30 | public UsimFileHandler(UiccCardApplication app, String aid, CommandsInterface ci) { 31 | super(app, aid, ci); 32 | } 33 | 34 | @Override 35 | protected String getEFPath(int efid) { 36 | switch(efid) { 37 | case EF_SMS: 38 | case EF_EXT6: 39 | case EF_EXT5: 40 | case EF_MWIS: 41 | case EF_MBI: 42 | case EF_SPN: 43 | case EF_AD: 44 | case EF_MBDN: 45 | case EF_PNN: 46 | case EF_OPL: 47 | case EF_SPDI: 48 | case EF_SST: 49 | case EF_CFIS: 50 | case EF_MAILBOX_CPHS: 51 | case EF_VOICE_MAIL_INDICATOR_CPHS: 52 | case EF_CFF_CPHS: 53 | case EF_SPN_CPHS: 54 | case EF_SPN_SHORT_CPHS: 55 | case EF_FDN: 56 | case EF_MSISDN: 57 | case EF_EXT2: 58 | case EF_INFO_CPHS: 59 | case EF_CSP_CPHS: 60 | case EF_GID1: 61 | case EF_PLMNWACT: 62 | return MF_SIM + DF_ADF; 63 | 64 | case EF_PBR: 65 | // we only support global phonebook. 66 | return MF_SIM + DF_TELECOM + DF_PHONEBOOK; 67 | } 68 | String path = getCommonIccEFPath(efid); 69 | if (path == null) { 70 | // The EFids in USIM phone book entries are decided by the card manufacturer. 71 | // So if we don't match any of the cases above and if its a USIM return 72 | // the phone book path. 73 | return MF_SIM + DF_TELECOM + DF_PHONEBOOK; 74 | } 75 | return path; 76 | } 77 | 78 | @Override 79 | protected void logd(String msg) { 80 | Log.d(LOG_TAG, msg); 81 | } 82 | 83 | @Override 84 | protected void loge(String msg) { 85 | Log.e(LOG_TAG, msg); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scintill/AndroidSIMFileReader/cf7859fd6f19fabcc315f8451420a70aa98b0ade/app/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scintill/AndroidSIMFileReader/cf7859fd6f19fabcc315f8451420a70aa98b0ade/app/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scintill/AndroidSIMFileReader/cf7859fd6f19fabcc315f8451420a70aa98b0ade/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scintill/AndroidSIMFileReader/cf7859fd6f19fabcc315f8451420a70aa98b0ade/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 23 | 42 | 44 | 48 | 52 | 53 | 54 | 56 | 57 | 59 | image/svg+xml 60 | 62 | 63 | 64 | 65 | 66 | 71 | 77 | 82 | 85 | 94 | 99 | 104 | 109 | 114 | 115 | 1 1 1 1 1 0 0 1 1 1 0 00 1 0 147 | 148 | 149 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_my.xml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 19 | 20 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/menu/my.xml: -------------------------------------------------------------------------------- 1 |

4 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | SIMFileReader 5 | Check logcat for error messages. Sometimes it can take a long time for SuperSU to prompt, and the test doesn\'t start until permission is granted.\n\nExample logcat command:\nadb logcat -s SIMFileReader,RilExtender,RilExtenderCommandsInterface,AtCommandInterface,CommandsInterfaceFactory,TelephonySeekServiceCommandsInterface,SIMRecords,Parcel,librilinject,CMDProcessor,lib__hijack.bin__.so,System.err,su\n\nIf the commands are being received by the RilExtender, you might also check the radio log to see what the RIL is doing with them. 6 | Settings 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/native/rilinject/jni/Android.mk: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014 Joey Hewitt 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | LOCAL_PATH := $(call my-dir) 21 | 22 | include $(CLEAR_VARS) 23 | 24 | LOCAL_MODULE := librilinject 25 | LOCAL_SRC_FILES := rilinject.c.arm 26 | LOCAL_C_INCLUDES := ../../adbi/instruments/base/ ../../ddi/dalvikhook/jni/ 27 | LOCAL_LDLIBS := -L ../../../../build/native/obj/local/armeabi -ldalvikhook -lbase -llog 28 | LOCAL_CFLAGS := -g 29 | 30 | include $(BUILD_SHARED_LIBRARY) 31 | -------------------------------------------------------------------------------- /app/src/native/rilinject/jni/rilinject.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Joey Hewitt 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | * 22 | * 23 | * 24 | * Based on smsdispatch.c from: 25 | * Collin's Dynamic Dalvik Instrumentation Toolkit for Android 26 | * Collin Mulliner 27 | * 28 | * (c) 2012,2013 29 | * 30 | * License: LGPL v2.1 31 | * 32 | */ 33 | 34 | // TODO review https://developer.android.com/training/articles/perf-jni.html , if this is going to be "production quality" 35 | // TODO look into this logcat message: "W/linker (27134): librilinject.so has text relocations. This is wasting memory and is a security risk. Please fix." 36 | // TODO gracefully handle failures like permissions errors, instead of crashing the phone process? or maybe crashing is the easy way to clean up? 37 | 38 | #define _GNU_SOURCE 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | 52 | #include 53 | #include 54 | #include 55 | 56 | #include "hook.h" 57 | #include "dexstuff.h" 58 | #include "dalvik_hook.h" 59 | #include "base.h" 60 | 61 | static struct hook_t eph; 62 | static struct dexstuff_t d; 63 | static struct dalvik_hook_t dalvikhook; 64 | 65 | // switch for debug output of dalvikhook and dexstuff code 66 | static int debug = 1; 67 | 68 | #define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "librilinject", __VA_ARGS__) 69 | 70 | static jclass loadClassFromDex(JNIEnv *env, const char *classNameSlash, const char *classNameDot, const char *dexPath, const char *cachePath) { 71 | jclass clLoadedClass = (*env)->FindClass(env, classNameSlash); 72 | 73 | if (!clLoadedClass) { 74 | (*env)->ExceptionClear(env); // FindClass() complains if there's an exception already 75 | 76 | // Load my class with BaseDexClassLoader 77 | // See RilExtenderCommandsInterface.java: 78 | // new BaseDexClassLoader(rilExtenderDex.getAbsolutePath(), rilExtenderDexCacheDir, null, ClassLoader.getSystemClassLoader()) 79 | 80 | jclass clFile = (*env)->FindClass(env, "java/io/File"); 81 | jmethodID mFileConstructor = (*env)->GetMethodID(env, clFile, "", "(Ljava/lang/String;)V"); 82 | jobject obCacheDirFile = NULL; 83 | if (clFile && mFileConstructor) { 84 | obCacheDirFile = (*env)->NewObject(env, clFile, mFileConstructor, (*env)->NewStringUTF(env, cachePath)); 85 | if ((*env)->ExceptionOccurred(env)) { 86 | ALOGD("new File() threw an exception"); 87 | (*env)->ExceptionDescribe(env); 88 | } 89 | } else { 90 | ALOGD("Couldn't open cache File!"); 91 | } 92 | 93 | jclass clDexClassLoader = (*env)->FindClass(env, "dalvik/system/BaseDexClassLoader"); 94 | jmethodID mClassLoaderConstructor = (*env)->GetMethodID(env, clDexClassLoader, "", "(Ljava/lang/String;Ljava/io/File;Ljava/lang/String;Ljava/lang/ClassLoader;)V"); 95 | jmethodID mGetSystemClassLoader = (*env)->GetStaticMethodID(env, clDexClassLoader, "getSystemClassLoader", "()Ljava/lang/ClassLoader;"); 96 | jmethodID mLoadClass = (*env)->GetMethodID(env, clDexClassLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); 97 | ALOGD("clDexClassLoader = %x, obCacheDirFile = %x", clDexClassLoader, obCacheDirFile); 98 | 99 | if (clDexClassLoader && mClassLoaderConstructor && mLoadClass && obCacheDirFile) { 100 | jobject classloaderobj = (*env)->NewObject(env, clDexClassLoader, mClassLoaderConstructor, 101 | (*env)->NewStringUTF(env, dexPath), obCacheDirFile, NULL, 102 | (*env)->CallStaticObjectMethod(env, clDexClassLoader, mGetSystemClassLoader)); 103 | 104 | // XXX stingutf necesary? 105 | if (classloaderobj) { 106 | clLoadedClass = (*env)->CallObjectMethod(env, classloaderobj, mLoadClass, (*env)->NewStringUTF(env, classNameDot)); 107 | if ((*env)->ExceptionOccurred(env)) { 108 | ALOGD("loadClass() threw an exception"); 109 | (*env)->ExceptionDescribe(env); 110 | } 111 | } else { 112 | ALOGD("classloader object not found!"); 113 | } 114 | } else { 115 | ALOGD("classloader/constructor not found!"); 116 | } 117 | 118 | ALOGD("clLoadedClass = %x", clLoadedClass); 119 | } 120 | 121 | return clLoadedClass; 122 | } 123 | 124 | jclass clRilExtender = 0; 125 | jmethodID mOnTransact = 0; 126 | 127 | static jboolean onTransact_hook(JNIEnv *env, jobject obj, jint jiCode, jobject joData, jobject joReply, jint jiFlags) { 128 | jboolean returnValue = JNI_FALSE; 129 | 130 | if (!clRilExtender) { 131 | clRilExtender = loadClassFromDex(env, "net/scintill/simio/RilExtender", "net.scintill.simio.RilExtender", 132 | "/data/data/net.scintill.simfilereader/app_rilextender/rilextender.dex", "/data/data/net.scintill.simfilereader/app_rilextender-cache"); 133 | if (clRilExtender) { 134 | clRilExtender = (*env)->NewGlobalRef(env, clRilExtender); 135 | // XXX delete ever? we're probably going to live forever, until the process dies 136 | mOnTransact = (*env)->GetStaticMethodID(env, clRilExtender, "onPhoneServiceTransact", "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z"); 137 | } 138 | } 139 | 140 | if (clRilExtender && mOnTransact) { 141 | (*env)->ExceptionClear(env); 142 | returnValue = (*env)->CallStaticBooleanMethod(env, clRilExtender, mOnTransact, jiCode, joData, joReply, jiFlags); 143 | 144 | if (!(*env)->ExceptionOccurred(env) && returnValue != JNI_TRUE) { 145 | // call original method 146 | dalvik_prepare(&d, &dalvikhook, env); 147 | returnValue = (*env)->CallBooleanMethod(env, obj, dalvikhook.mid, jiCode, joData, joReply, jiFlags); 148 | /*ALOGD("success calling : %s", dalvikhook.method_name);*/ 149 | dalvik_postcall(&d, &dalvikhook); 150 | } 151 | } else { 152 | ALOGD("class/method not found!"); 153 | } 154 | 155 | return returnValue; 156 | } 157 | 158 | static int my_epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout) { 159 | int (*orig_epoll_wait)(int epfd, struct epoll_event *events, int maxevents, int timeout); 160 | orig_epoll_wait = (void*)eph.orig; 161 | // remove hook for epoll_wait 162 | hook_precall(&eph); 163 | 164 | // resolve symbols from DVM 165 | debug = 0; // dlopen logging is noisy 166 | dexstuff_resolv_dvm(&d); 167 | debug = 1; 168 | 169 | // hook 170 | dalvik_hook_setup(&dalvikhook, "Lcom/android/phone/PhoneInterfaceManager;", "onTransact", "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z", 5, onTransact_hook); 171 | //dalvikhook.debug_me = debug; 172 | dalvik_hook(&d, &dalvikhook); 173 | 174 | // call original function 175 | int res = orig_epoll_wait(epfd, events, maxevents, timeout); 176 | return res; 177 | } 178 | 179 | 180 | static void my_log(char *msg) { 181 | if (debug) 182 | ALOGD("%s", msg); 183 | } 184 | 185 | // set my_init as the entry point 186 | void __attribute__ ((constructor)) my_init(void); 187 | 188 | void my_init(void) { 189 | ALOGD("initializing"); 190 | 191 | // set log function for libbase (very important!) 192 | set_logfunction(my_log); 193 | // set log function for libdalvikhook (very important!) 194 | dalvikhook_set_logfunction(my_log); 195 | 196 | hook(&eph, getpid(), "libc.", "epoll_wait", my_epoll_wait, 0); 197 | } 198 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.0.0' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | 20 | gradle.projectsEvaluated { 21 | tasks.withType(JavaCompile) { 22 | options.compilerArgs << "-Xlint:deprecation" //<< "-Xlint:unchecked" 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Settings specified in this file will override any Gradle settings 5 | # configured through the IDE. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scintill/AndroidSIMFileReader/cf7859fd6f19fabcc315f8451420a70aa98b0ade/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Dec 21 18:10:33 MST 2014 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------