An Android ContentProvider that exposes OpenEUICC/EasyEUICC LPA functionality via ADB, enabling programmatic eSIM profile management.
./build+install.shThe script:
- Compiles
LpaProvider.javato.classfiles - Converts to
.dexusing d8, then disassembles to smali - Injects smali into the decompiled EasyEUICC APK
- Rebuilds and signs the APK with 9eSIM Community Key
- Installs via
adb install
Requirements: apktool, adb, java, javac
Included: Build tools in tools/, Java dependencies in deps/
content://lpa/<endpoint>
| Endpoint | Description | Input | Output |
|---|---|---|---|
cards |
List eSIM cards | — | slot, port, eid |
profiles |
Get profiles on a card | slot, port |
iccid, enabled, provider, nickname |
downloadProfile |
Download a profile | slot, port, activationCode¹, address¹, matchingId?, confirmationCode?, imei?, callbackUrl? |
iccid, enabled, provider, nickname |
deleteProfile |
Delete a profile | slot, port, iccid |
success |
enableProfile |
Enable a profile | slot, port, iccid, refresh?=true |
success |
setProfileNickname |
Set/clear profile nickname | slot, port, iccid, nickname?="" |
success |
preferences |
Get all preferences | — | name, enabled |
setPreference |
Set a preference | name, enabled |
success |
¹ Provide either activationCode OR address
? = optional
adb shell content query --uri 'content://lpa/cards'Row: 0 slot=0, port=0, eid=89049032123456789012345678901234
Row: 1 slot=1, port=0, eid=89044012345678901234567890123456
adb shell content query --uri 'content://lpa/profiles?slot=0&port=0'Row: 0 iccid=8901234567890123456, enabled=true, provider=Example Carrier, nickname=Work
Row: 1 iccid=8909876543210987654, enabled=false, provider=Another Carrier, nickname=NULL
With activation code:
adb shell content query --uri 'content://lpa/downloadProfile?slot=0&port=0&activationCode=LPA:1$smdp.example.com$ABC123'With address and matching ID:
adb shell content query --uri 'content://lpa/downloadProfile?slot=0&port=0&address=smdp.example.com&matchingId=ABC123'With confirmation code:
adb shell content query --uri 'content://lpa/downloadProfile?slot=0&port=0&activationCode=LPA:1$smdp.example.com$ABC123&confirmationCode=1234'With callback URL:
adb shell content query --uri 'content://lpa/downloadProfile?slot=0&port=0&activationCode=LPA:1$smdp.example.com$ABC123&callbackUrl=https://example.com/callback'Row: 0 iccid=8901234567890123456, enabled=true, provider=Example Carrier, nickname=NULL
adb shell content query --uri 'content://lpa/deleteProfile?slot=0&port=0&iccid=8901234567890123456'Row: 0 success=true
adb shell content query --uri 'content://lpa/enableProfile?slot=0&port=0&iccid=8901234567890123456'Row: 0 success=true
adb shell content query --uri 'content://lpa/setProfileNickname?slot=0&port=0&iccid=8901234567890123456&nickname=Work'Clear profile nickname:
adb shell content query --uri 'content://lpa/setProfileNickname?slot=0&port=0&iccid=8901234567890123456'Row: 0 success=true
adb shell content query --uri 'content://lpa/preferences'Row: 0 name=verboseLogging, enabled=false
Row: 1 name=safeguardActiveProfile, enabled=true
Row: 2 name=filterProfileList, enabled=true
Row: 3 name=ignoreTlsCertificate, enabled=true
Row: 4 name=notificationsDownload, enabled=false
Row: 5 name=notificationsDelete, enabled=false
Row: 6 name=notificationsEnableDisable, enabled=false
adb shell content query --uri 'content://lpa/setPreference?name=ignoreTlsCertificate&enabled=true'Row: 0 success=true
adb shell content query --uri 'content://lpa/profiles'Row: 0 error=missing_arg_slot
Add the json parameter to any endpoint to receive results as JSON in a single rows column.
adb shell content query --uri 'content://lpa/profiles?slot=0&port=0&json'Example outputs:
// cards
[
{"slot":0,"port":0,"eid":"89049032123456789012345678901234"}
]
// profiles
[
{"iccid":"8901234567890123456","enabled":true,"provider":"Example Carrier","nickname":"Work"},
{"iccid":"8909876543210987654","enabled":false,"provider":"Another Carrier","nickname":null}
]
// preferences
[
{"name":"verboseLogging","enabled":false},
{"name":"safeguardActiveProfile","enabled":true}
]
// success response (enableProfile, deleteProfile, setProfileNickname, setPreference)
[
{"success":true}
]
// error response
[
{"error":"missing_arg_slot"}
]Errors are returned in an error column:
no_endpoint- No endpoint specifiedunknown_endpoint- Endpoint not foundmissing_arg_<name>- Required argument missingunknown_preference_name- Invalid preference namesafeguard_active_profile- Operation blocked by safeguard
| Name | Description |
|---|---|
verboseLogging |
Enable verbose logging |
forceUseTelephonyManager |
Force use TelephonyManager API (privileged only) |
safeguardActiveProfile |
Prevent operations on active profile |
filterProfileList |
Filter to show only operational profiles |
ignoreTlsCertificate |
Ignore TLS certificate errors |
notificationsDownload |
Process download notifications |
notificationsDelete |
Process delete notifications |
notificationsEnableDisable |
Process enable/disable notifications |
When callbackUrl is provided for downloadProfile, progress updates are POSTed as JSON:
{
"timestamp": 1770108790,
"state": "Authenticating",
"progress": 40,
"address": "smdp.example.com",
"matchingId": "ABC123",
"confirmationCode": null,
"imei": null
}