Android O device serial number from native - java

What is the proper way to get the serial number from native on Android O without calling the Java Build.getSerial().
On Android < 26 versions from native we could get the device serial number using the following code:
string serial = read_property("ro.boot.serialno");
...
string read_property(const string& property_name) {
char propertyValue[PROP_VALUE_MAX];
int propertyLen = __system_property_get(property_name.c_str(), propertyValue);
...
}
On Android O this throws an error:
Access denied finding property "ro.boot.serialno"
Although the READ_PHONE_STATE permission is granted. Seems to be related to the deprecated Build.SERIAL in Android 26.
I managed to get this property using adb, so the value is not removed and is there:
adb shell getprop ro.boot.serialno

You can use Build.getSerial() to get the serial number.
If the user has granted the READ_PHONE_STATE permission then there is no problem but if the user revoked the permission or has never granted it - you should take into consideration that you will get a SecurityException at runtime when trying to retrieve it.
In general - it looks like Google is slowly pushing to prevent apps from using personal identifiable information (like serial numbers of device) over the last few years so and you should look into alternatives like installationId.

Related

How can I use hardwarepropertiesmanager(android) in android api 30, android 11

Now I'm trying to run
HardwarePropertiesManager hardwarePropertiesManager = getApplicationContext().getSystemService(HardwarePropertiesManager.class);
hardwarePropertiesManager.getDeviceTemperatures(HardwarePropertiesManager.DEVICE_TEMPERATURE_CPU, HardwarePropertiesManager.TEMPERATURE_CURRENT);
to check cpu usage and temperature..
but, the exception occurred, which is
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.example.___/com.example.___.MainActivity}:
java.lang.SecurityException: The caller is neither a device
owner, nor holding the DEVICE_POWER permission, nor the current
VrListener.
is there any method to check cpu temperature and cpu usage(memory, core)??
As the documentation mentions HardwarePropertiesManager is available for applications which are device owners - https://developer.android.com/reference/android/os/HardwarePropertiesManager
You can try reading the data from file
sys/class/hwmon/hwmonX/temp1_input
There are some changes based on vendors. You can refer to https://stackoverflow.com/a/59306562 for comprehensive list.

Permission is not a changeable permission type

Background: I was trying out the new Tiles and TileService and decided to recreate the USB Tethering tile from CyanogenMod. I used reflection to access Connectivity manager's methods.
Problem: One Such method is the isTetheringSupported() which causes java.lang.SecurityException: You either need MANAGE_USERS or CREATE_USERS permission to: query user
So I added the permissions to the manifest but every time I use pm grant it returns "Permission is not a changeable permission type"
According to this I should not get this error when signed with the debug key.
Question: How do I get those permissions?
UPDATE:
Via Xposed it is possible to hook into the PackageManger and remove the below check and then do pm grant... to successfully grant whatever permission. If someone sees this and needs help to do so comment below I'll help you out.
OLD ANSWER
This code in the source
boolean isDevelopment =
((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0);
doesn't check if your app is in development mode. It checks if the permission you are requesting has the protectionLevel attribute (set in manifest) set to development.
And the permission you are trying to get seems not to have any elements declared in the manifest that could pass this check:
if (!isNormal && !isDangerous && !isDevelopment) {
throw new SecurityException("Permission " + bp.name
+ " is not a changeable permission type");
}
Just stumbled upon this with another permission. Seems there's sadly no way to get it.

Send APDU commands to USIM/SIM card in android

I was already worked with smart cards and I am familiar with APDU commands (that are defined in ISO/IEC 7816 and Global Platform specifications).
Now I want to know if there is any way to send an APDU command to my USIM/SIM card that is inserted to my mobile phone? (Samsung A3 with Android v4.4.4 kitkat installed.)
I already searched in the Google and I found some related topics and tools named SIM Toolkit Application and Seek for Android. But I don't really understand what are these? Are these items two applications that I must install on my mobile phone? or are those two tools that was installed on the USIM/SIM card already and receive commands from the mobile phone?
What is the difference between Proactive commands , APDU commands and AT commands?
Should I learn android to develop SIM card applications or I just need Java Card specifications and ETSI standards?
Thanks in advance.
There can be two different types of applets present on your SIM card.
Common applets
Common applets written in plain JavaCard. This is the type of applet you are used to from the world of common smart cards. It has the process method and smart card is the passive subject in the communication: your app sends APDU commands and the card responses.
You can communicate with these applets using a special set of Android libraries called SEEK for Android. Have a look at this tutorial to learn how to create such a phone application.
Starting on API level 21 there is also a way to communicate to SIM using Telephony Manager. However, there is one huge obstacle: your app needs MODIFY_PHONE_STATE permission, which can be granted only to system apps. A reqular, non-system app isn't allowed to use it.
SIM Toolkit Applets
A SIM card is much more than just a common smart card and writing an applet for a SIM card can be much more complicated than for a common smart card if you want to use all the possibilities the SIM card offers. I recommend you to read this paper - it is someone's bachelor thesis, but it is the best overview for a beginner I have found all over the Internet. I also recommend this video from the DefConn conference.
The role of the applet loaded on the SIM card is different: the applet is no longer a passive entity. The phone asks your applet regularly: "Is there anything new I can do for you?" and your applet can reply: "Yes, send this SMS, please" or "Tell me what time it is" etc. Moreover, your applet can become a listener of some events: incoming call, received SMS, time interval elapsed etc. Yes, the SIM card seems to be passive from the technical point of view, but its role is in fact an active one: it is the SIM card who sends commands to the phone.
These commands are called "proactive commands" or SIM Application Toolkit commands. Structure is the same - CLA INS P1 P2 LC data LE; the meaning is different.
You can send them from your applet using classes in a special JavaCard package called sim.toolkit.
(SIM Application Toolkit is a standard that specifies the proactive commands in the same way Global Platform specifies the applet's lifecycle.)
Example of SIM Toolkit applet:
import sim.toolkit.ToolkitInterface;
import sim.toolkit.ToolkitRegistry;
...
import javacard.framework.ISOException;
public class STKTest extends Applet implements ToolkitInterface {
public static void install(byte[] bArray, short bOffset, byte bLength) {
// GP-compliant JavaCard applet registration
new STKTest().register(bArray, (short) (bOffset + 1), bArray[bOffset]);
}
//this method handles standard APDU commands
public void process(APDU apdu) {
// Good practice: Return 9000 on SELECT
if (selectingApplet()) {
return;
}
apdu.setIncomingAndReceive();
final byte[] buf = apdu.getBuffer();
switch (buf[ISO7816.OFFSET_INS]) {
case (byte) 0x00:
//do something
break;
}
}
//this method handles the SIM Toolkit commands
public void processToolkit(byte event) throws ToolkitException {
switch (event) {
case ToolkitConstants.EVENT_TIMER_EXPIRATION:
//do something
break;
}
}
}
Yes, you should learn Android - you will need it to use the SEEK library. Your question is very broad, please ask me for any details, if you want.
Starting on API level 22 (Android 5.1) there is another Option called "Carrier Privileges". It allows non-system apps to send APDUs to the SIM card using Android TelephonyManager. See:
https://developer.android.com/reference/android/telephony/TelephonyManager.html#hasCarrierPrivileges()
For example mobile network operator (MNO) Apps that are distributed on Google Play can use this.
But again it's not open for everybody. In this case you need to be granted access by the SIM. The Access Rules on the SIM are managed by the MNO who issued it. See also:
http://source.android.com/devices/tech/config/uicc.html

android device id confusion

If I dial
*
#
*
#
8
2
5
5
#
*
#
*
, I get my android device id which starts with android-35c2acdd...
source
If I use Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID) the result starts with a96b4b27...
If I use ((TelephonyManager) Context.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId() the result starts with 3538330...
What is the difference between these ID-s? How can I get the result of the
*
#
*
#
8
2
5
5
#
*
#
*
dial?
IMEI
The IMEI is the 'MAC' for the telephony module - the unique ID that the telephone uses when it connects via GSM/GPRS/HSPDA/etc. The GSM network uses it to route calls and data from the phone over the GSM network right up to the gateway into the Internet (which is an IP network).
A telephony module is a chip or circuit board that handles the telephone network, either GSM or CMDA, and often has a slot for a removable SIM card. Some phones have more than one telephony module (active dual- or multi-SIM phones). Each telephony module has its own IMEI.
Manufacturers give each phone (strictly the telephony module) a unique IMEI during manufacturing. However the number can normally be rewritten if you have the right software. This is often done after a phone has been stolen to give the phone a new identity and bipass stolen phone blocking system.
The IMEI can be programmatically obtained using the TelephonyManager.getDeviceId() API.
CDMA phones have a ESN or MEID which are different lengths and formats, even though it is retrieved using the same API.
Android devices without telephony modules - for example many tablets and TV devices - do not have an IMEI. As Schlangi commented, some devices that do not have a telephony module fake the IMEI, so the presence of an IMEI does not (always) guarantee the device has a telephony module.
ANDROID_ID
The ANDROID_ID is another unique number on the phone - this is automatically generated by the OS as it boots for the first time (doing it this way makes it much easier for the manufacturers by removing a step from the production line).
The ANDROID_ID can (and does) change, for example:
Factory reset (including when reflashing the OS)
In software: eg https://play.google.com/store/apps/details?id=com.vcastroi.changeid
It is mainly used by developers (eg identifying and connecting to devices using adb)
ANDROID_ID can be used to identify an Android device given the caveats above, realistically meaning that it uniquely identifies the device over significant portions of the device lifetime, but cannot be relied on.
Also note that there was a bug in Froyo where many devices gave themselves the same ANDROID_ID. This is the bug
Other identifiers
There are a number of other things that can be used identify the device:
MAC address of the WiFi module: WifiManager.getConnectionInfo() -> WifiInfo.getMacAddress(). This can often be changed in software, but generally is constant over the device lifetime. Also it can only be read if the WiFi module is switched on.
MAC address of the BlueTooth module: BluetoothAdaptor.getAddress(). Like WiFi MAC, this can often be changed in software and may be off when you need it
The subscriber's telephone number. This may change if the user requests a new number from the telco, or if the user switches SIMs. It is obtained from TelephonyManager.getLine1Number(). This is only present for Android phone devices with a current SIM installed and a paid service with a telco.
The SIM contains its own identifying number (IMSI). This is obtained from the TelephonyManager.getSubscriberId() API. Obviously the SIM may not be present at any specific time, and it changes when the SIM is changed - and users can upgrade/replace their SIM while keeping the same number, so you can't say that this is one-to-one to a specific phone or user.
Related to the IMSI is the MSISDN. This functions as the identification of a subscription (your contract for a specific telephone number with your mobile provider) and therefore gives the device its telephone number. The MSISDN may be associated with several SIM cards, and therefore several phones. It comes with all the caveats for reading the SIM above. This may be retrieved with TelephonyManager.getSimSerialNumber(). Thanks Schlangi for the corrections and additions
Gingerbread and later has android.os.Build.SERIAL which many manufacturers set (but not all. Bugger).
Other notes
You need specific permissions to access each and every API, so if you try for all of them, your app's permissions in the Google Play store look fairly permissive.
I think this link explains all the other available options also https://android-developers.googleblog.com/2011/03/identifying-app-installations.html
Found on the web:
private static final Uri URI = Uri.parse("content://com.google.android.gsf.gservices");
private static final String ID_KEY = "android_id";
String getAndroidId(Context ctx) {
String[] params = { ID_KEY };
Cursor c = ctx.getContentResolver()
.query(URI, null, null, params, null);
if (!c.moveToFirst() || c.getColumnCount() < 2)
return null;
try {
return Long.toHexString(Long.parseLong(c.getString(1)));
} catch (NumberFormatException e) {
return null;
}
}
Add permission:
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
However, I doubt that is a documented ID and I would be carefull because that might not work if GTalk gets updated.
Source: http://blog.codepainters.com/2012/01/17/how-to-obtain-gtalk-android-id/
Also worth having a look at: http://www.toxicbakery.com/android-development/getting-google-auth-sub-tokens-in-your-android-applications/
There are some approach to get unique identifier on android phone.
Android ID
It is a 64-bit hex string which is generated on the device's first boot.
Generally it won't changed unless is factory reset.
Secure.getString(getContentResolver(), Secure.ANDROID_ID);
The Android ID , considered unreliable because it can sometimes be null.
The documentation states that it "can change upon factory reset".
This string can also be altered on a rooted phone.
String m_szAndroidID = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
Returns: 9774d56d682e549c . No special permissions required.
2. The WLAN MAC Address string, is another unique identifier that you can use as a device id.
Before you read it, you will need to make sure that your project has the android.permission.ACCESS_WIFI_STATE
permission or the WLAN MAC Address will come up as null.
WifiManager wm = (WifiManager)getSystemService(Context.WIFI_SERVICE);
String m_szWLANMAC = wm.getConnectionInfo().getMacAddress();
Returns: 00:11:22:33:44:55 (not a real address since this is a custom ROM , as you can see the MAC address can easily be faked).
WLAN doesn't have to be on, to read this value.
3. The BT MAC Address string, available on Android devices with Bluetooth, can be read if your project has the android.permission.BLUETOOTH permission.
BluetoothAdapter m_BluetoothAdapter = null; // Local Bluetooth adapter
m_BluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
String m_szBTMAC = m_BluetoothAdapter.getAddress();
Returns: 43:25:78:50:93:38 . BT doesn't have to be on, to read it.
4. IMEI only for Android devices with Phone use:
TelephonyManager TelephonyMgr = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
String szImei = TelephonyMgr.getDeviceId(); // Requires READ_PHONE_STATE
This requires adding a permission in AndroidManifest.xml, and users will be notified upon installing
your software: android.permission.READ_PHONE_STATE. The IMEI is unique for your phone
and it looks like this: 359881030314356 (unless you have a pre-production device with an invalid IMEI like 0000000000000).
For more info refer this link.
IMEI
There is a mandatory requirement by the standardization bodies, that mobile devices for public networks may be uniquely identified by the IMEI number
It is the manufacturer's responsibility to set IMEI. In practice, developers sometimes see IMEIs like 000000... or 123456... Sometimes phones with identical IMEI go to production, which of course is a bug that should be fixed...
ANDROID_ID
A 64-bit number (as a hex string) that is randomly generated on the device's first boot and should remain constant for the lifetime of the device. (The value may change if a factory reset is performed on the device.)
It looks like Android does not trust the manufacturers and provides an alternative unique ID.
EDIT:
This is what I get (instead of IMEI) on and Android device that is not a phone:
$ adb shell dumpsys iphonesubinfo
Phone Subscriber Info:
Phone Type = GSM
Device ID = null
I think all the information provided above is well enough to understand the codes.
Yet I think you are still "not able to see the result of the ##8255## dial" (plz excuse if I went wrong somewhere in understanding this)
I assume the reason behind this is one of the latest bug fix against USSD code made in Android.
(you may read more about this and check if your device is on the list. its all over the web)
Finally, if you just want to get the android ID straightaway i suggest you to use this app-
https://play.google.com/store/apps/details?id=com.redphx.deviceid&hl=en

Use Apple Push Notification Service through Java

Am trying to implement a Java program which sends an Apple Push Notification to an iPhone client app... Found the following library: Java APNs
Provider code:
Created the following code (from Javapns) to use in my app:
try {
PayLoad payLoad = new PayLoad();
payLoad.addAlert("My alert message");
payLoad.addBadge(45);
payLoad.addSound("default");
PushNotificationManager pushManager = PushNotificationManager.getInstance();
pushManager.addDevice("iPhone", "f4201f5d8278fe39545349d0868a24a3b60ed732");
log.warn("Initializing connectiong with APNS...");
// Connect to APNs
pushManager.initializeConnection(HOST, PORT,
"/etc/Certificates.p12", "password",
SSLConnectionHelper.KEYSTORE_TYPE_PKCS12);
Device client = pushManager.getDevice("Lambo");
// Send Push
log.warn("Sending push notification...");
PushNotificationManager.getInstance().sendNotification(client, payLoad);
}
catch (Exception e) {
throw new ApnsPushNotificationException("Unable to send push " + e);
}
When I run this app (as you can see through the Log4j statements) there's no exceptions which occur:
WARN [MyCode] Initializing connectiong with APNS...
WARN [MyCode] Sending push notification...
But my client app doesn't receive any notifications!
IDPP Registration Process:
Also, did the following on the iPhone Developer Program Portal (IDPP):
Created the APNS based SSL Certificate and Keys
Created and installed the provisioning profile
Installed the SSL Certificate and Key on the server.
Have read over the Apple Push Notification Service Guide several times and noticed a few things:
(1) On page 15, it states that the device token is not the same as the device UDID (which I am currently incorrectly passing in as the second parameter inside the PushNotificationManager.addDevice() method (see above)).
On page 17, it states:
"APNs generates a device token using information contained in the unique device certificate. The device token contains an identifier of the device. It then encrypts the device token with a token key and returns it to the device. The device returns the device token to the requesting application as an NSData object. The application then must deliver the device token to its provider in either binary or hexidecimal format."
iPhone OS Client Implementation
(2) After reading pages 33 - 34, I discovered that I didn't include the Objective-C code to have the app register with APNs.
Am not an Objective-C developer, so is this where I can recover the device code or do I have to get it from the certificate?
Where do I obtain the device token (sorry, someone else wrote the Objective-C client app and I am a Java Developer)?
Question(s):
(1) With the exception of not knowing where to get the device token and the mobile client code registration, is there anything else that I have not looked over or missed?
(2) Am I using the Javapns library the right way?
Thank you for taking the time to read this...
As a shameful self-advertising, I encourage to use java-apns library. Your code will look like:
ApnsService service =
APNS.newService()
.withCert("/etc/Certificates.p12", "password")
.withSandboxDestination() // or .withProductionDestination()
.build();
String payload =
APNS.newPayload()
.alertBody("My alert message")
.badge(45)
.sound("default")
.build();
String deviceToken = "f4201f5d8278fe39545349d0868a24a3b60ed732";
log.warn("Sending push notification...");
service.push(deviceToken, payload);
Just a little tip, in order to convert your received token into a format suitable for registration with javapns, this code will do the trick:
- (NSString *)convertTokenToDeviceID:(NSData *)token {
NSMutableString *deviceID = [NSMutableString string];
// iterate through the bytes and convert to hex
unsigned char *ptr = (unsigned char *)[token bytes];
for (NSInteger i=0; i < 32; ++i) {
[deviceID appendString:[NSString stringWithFormat:#"%02x", ptr[i]]];
}
return deviceID;
}
I tried this and I keep getting hanged when sending the notification, and nothing gets sent.
The issue stems from the following function:
public void sendNotification(Device device, PayLoad payload)
It seems that the bufferedreader has NULL
BufferedReader in =
new BufferedReader(new InputStreamReader(this.socket.getInputStream() ) );
So when this portion of the code gets hit it just hangs there in endless loop
logger.debug( "In: [" + in.readLine() + "]" );
This output is [null]
So then right after then the loops get executed:
while ( ! this.socket.isInputShutdown() ) {
while( in.ready() ) {
logger.debug("ready now");
logger.debug(in.readLine());
System.out.println( this.socket.getInputStream().read() );
}
}
The code enters the first while loop and waits for the BufferedReader in to be ready
and just keeps waiting..... ad that is your hanging
Your Java code looks solid! However, don't forget to close the connection, through PushNotificationManager.closeConnection(). It's important to cleanup after yourself.
As a side comment, I notice that you are adding the device 'iPhone' but querying for 'Lambo' afterwards. This is an indication of a bug.
The device token shown in the code is incorrect. Device tokens, currently, as 32-bit long value, which gets hexed into 64 characters. I assume that the server is failing silently when pushing the notification to invalid token!
The only way to get the device token is from the app itself. As provided by the Push Notification guide suggests, the iPhone app needs to register for notification upon launch. In the application:didRegisterForRemoteNotificationsWithDeviceToken:, the iPhone needs to send the device token to your java provider server. (For debugging purposes, you can just NSLog the device token and use it; it never changes across runs).
I would recommend that you create a server in your java provider server to receive device tokens. Set up a ServerSocket to receive connections from the iPhone and their device token (and any additional info you need) and insert the tokens in the database.
JavaPNS was recently updated to 2.0, and fixed ALL reported issues up to the release date. It does fix the issue you are describing, and using the library is MUCH simpler than it ever was (you can push a notification with a single line of code now).
You seem to be missing the token
pushManager.addDevice("iPhone", "f4201f5d8278fe39545349d0868a24a3b60ed732");
Takes id and token check:
https://github.com/o-sam-o/javapns/blob/master/src/javapns/notification/PushNotificationManager.java#L501
The only way to get a token is from the iphone app. A valid token looks something like this:
1d2d6f34 c5028bca c50df5f9 1992c912 ce7deae8 3bbe7da5 447f6a68 cfecdc0e
Regarding the comment for notnoop here:
If you are landing on this post in 2022, you'll find that the java-apns library doesn't work since 2021. Instead they recommend using pushy library.
I have tried this one just by following their example in the README file and it works really well. They have added examples for both authorisation types: by certificate or by token.

Categories