Detecting if an app runs in a 32-bit or 64-bit iOS Simulator

Posted: October 1st, 2013 | Author: | Filed under: iOS, Programming | Tags: , , , , | No Comments »

With Xcode 5, it is now possible to compile an application for armv7 and/or arm64.
You can compile an application as 32-bit and/or as 64-bit and you can run this application in a 32-bit or 64-bit iOS Simulator:

In fact there are 3 different cases:

  • 32-bit application running in a 32-bit iOS Simulator
  • 32-bit application running in a 64-bit iOS Simulator
  • 64-bit application running in a 64-bit iOS Simulator

It is possible to distinguish these 3 different cases but this is not as easy as I would expected.

The case of a 64-bit application running in a 64-bit iOS Simulator is simple to solve by just using the define __LP64__: A 64-bit application can only run in a 64-bit iOS Simulator.

Distinguishing the 2 other cases is more difficult and a runtime check is needed. Something to note is that the ‘iOS Simulator’ process is running as 64-bit even in the case of a 32-bit iOS Simulator.

I noticed however that a process called ‘SimulatorBridge’ is used:

  • When launching an 64-bit iOS Simulator, the process ‘SimulatorBridge’ runs as 64-bit
  • When launching an 32-bit iOS Simulator, the process ‘SimulatorBridge’ runs as 32-bit

Running a 32-bit iOS Simulator

Below is a function to know if the iOS Simulator is a 32-bit Simulator or a 64-bit Simulator. The function “is64bitSimulator()” returns true if the iOS Simulator is a 64-bit iOS Simulator:

#include <sys/sysctl.h>

#if TARGET_IPHONE_SIMULATOR

bool is64bitSimulator()
{
	bool is64bitSimulator = false;
	
	/* Setting up the mib (Management Information Base) which is an array of integers where each
	 * integer specifies how the data will be gathered.  Here we are setting the MIB
	 * block to lookup the information on all the BSD processes on the system.  Also note that
	 * every regular application has a recognized BSD process accociated with it.  We pass
	 * CTL_KERN, KERN_PROC, KERN_PROC_ALL to sysctl as the MIB to get back a BSD structure with
	 * all BSD process information for all processes in it (including BSD process names)
	 */
	int mib[6] = {0,0,0,0,0,0};
	mib[0] = CTL_KERN;
    mib[1] = KERN_PROC;
    mib[2] = KERN_PROC_ALL;
	
	long numberOfRunningProcesses = 0;
	struct kinfo_proc* BSDProcessInformationStructure = NULL;
	size_t sizeOfBufferRequired = 0;
	
	/* Here we have a loop set up where we keep calling sysctl until we finally get an unrecoverable error
	 * (and we return) or we finally get a succesful result.  Note with how dynamic the process list can
	 * be you can expect to have a failure here and there since the process list can change between
	 * getting the size of buffer required and the actually filling that buffer.
	 */
	BOOL successfullyGotProcessInformation = NO;
	int error = 0;
	
	while (successfullyGotProcessInformation == NO)
	{
		/* Now that we have the MIB for looking up process information we will pass it to sysctl to get the 
		 * information we want on BSD processes.  However, before we do this we must know the size of the buffer to 
		 * allocate to accomidate the return value.  We can get the size of the data to allocate also using the 
		 * sysctl command.  In this case we call sysctl with the proper arguments but specify no return buffer 
		 * specified (null buffer).  This is a special case which causes sysctl to return the size of buffer required.
		 *
		 * First Argument: The MIB which is really just an array of integers.  Each integer is a constant
		 *     representing what information to gather from the system.  Check out the man page to know what
		 *     constants sysctl will work with.  Here of course we pass our MIB block which was passed to us.
		 * Second Argument: The number of constants in the MIB (array of integers).  In this case there are three.
		 * Third Argument: The output buffer where the return value from sysctl will be stored.  In this case
		 *     we don't want anything return yet since we don't yet know the size of buffer needed.  Thus we will
		 *     pass null for the buffer to begin with.
		 * Forth Argument: The size of the output buffer required.  Since the buffer itself is null we can just
		 *     get the buffer size needed back from this call.
		 * Fifth Argument: The new value we want the system data to have.  Here we don't want to set any system
		 *     information we only want to gather it.  Thus, we pass null as the buffer so sysctl knows that 
		 *     we have no desire to set the value.
		 * Sixth Argument: The length of the buffer containing new information (argument five).  In this case
		 *     argument five was null since we didn't want to set the system value.  Thus, the size of the buffer
		 *     is zero or NULL.
		 * Return Value: a return value indicating success or failure.  Actually, sysctl will either return
		 *     zero on no error and -1 on error.  The errno UNIX variable will be set on error.
		 */ 
		error = sysctl(mib, 3, NULL, &sizeOfBufferRequired, NULL, 0);
		if (error) 
			return NULL;
		
		/* Now we successful obtained the size of the buffer required for the sysctl call.  This is stored in the 
		 * SizeOfBufferRequired variable.  We will malloc a buffer of that size to hold the sysctl result.
		 */
		BSDProcessInformationStructure = (struct kinfo_proc*) malloc(sizeOfBufferRequired);
		if (BSDProcessInformationStructure == NULL)
			return NULL;
		
		/* Now we have the buffer of the correct size to hold the result we can now call sysctl
		 * and get the process information.  
		 *
		 * First Argument: The MIB for gathering information on running BSD processes.  The MIB is really 
		 *     just an array of integers.  Each integer is a constant representing what information to 
		 *     gather from the system.  Check out the man page to know what constants sysctl will work with.  
		 * Second Argument: The number of constants in the MIB (array of integers).  In this case there are three.
		 * Third Argument: The output buffer where the return value from sysctl will be stored.  This is the buffer
		 *     which we allocated specifically for this purpose.  
		 * Forth Argument: The size of the output buffer (argument three).  In this case its the size of the 
		 *     buffer we already allocated.  
		 * Fifth Argument: The buffer containing the value to set the system value to.  In this case we don't
		 *     want to set any system information we only want to gather it.  Thus, we pass null as the buffer
		 *     so sysctl knows that we have no desire to set the value.
		 * Sixth Argument: The length of the buffer containing new information (argument five).  In this case
		 *     argument five was null since we didn't want to set the system value.  Thus, the size of the buffer
		 *     is zero or NULL.
		 * Return Value: a return value indicating success or failure.  Actually, sysctl will either return 
		 *     zero on no error and -1 on error.  The errno UNIX variable will be set on error.
		 */
		error = sysctl(mib, 3, BSDProcessInformationStructure, &sizeOfBufferRequired, NULL, 0);
		if (error == 0)
        {
			//Here we successfully got the process information.  Thus set the variable to end this sysctl calling loop
            successfullyGotProcessInformation = YES;
        }
        else 
        {
			/* failed getting process information we will try again next time around the loop.  Note this is caused
			 * by the fact the process list changed between getting the size of the buffer and actually filling
			 * the buffer (something which will happen from time to time since the process list is dynamic).
			 * Anyways, the attempted sysctl call failed.  We will now begin again by freeing up the allocated 
			 * buffer and starting again at the beginning of the loop.
			 */
            free(BSDProcessInformationStructure); 
        }
	} //end while loop
	
	
	/* Now that we have the BSD structure describing the running processes we will parse it for the desired
     * process name.  First we will the number of running processes.  We can determine
     * the number of processes running because there is a kinfo_proc structure for each process.
     */
	numberOfRunningProcesses = sizeOfBufferRequired / sizeof(struct kinfo_proc);
	for (int i = 0; i < numberOfRunningProcesses; i++)
    {
		//Getting name of process we are examining
        const char *name = BSDProcessInformationStructure[i].kp_proc.p_comm;
		
		if(strcmp(name, "SimulatorBridge") == 0)
		{
			int p_flag = BSDProcessInformationStructure[i].kp_proc.p_flag;
			is64bitSimulator = (p_flag & P_LP64) == P_LP64;
			break;
		}
    }
	
	free(BSDProcessInformationStructure);
	return is64bitSimulator;
}

#endif // TARGET_IPHONE_SIMULATOR



Leave a Reply