I guess I am not saying it right in the title. What I intend to do is to hook to some system api,like a time interrupt happens every amount of time (which is how every application in the operating system interprets time) and make an application's call to this api return some bigger/smaller result. So from the point view of an applicaiton, time has been speed up or slow down. I have found some application on windows doing this, can anyone gives me some pointers on how to implement this on Mac OS X?
If it is your application, simply route all your time requests through a function you write that has a scalar. To do something similar to arbitrary application, inject some code and patch a trap, so to speak. I think mach-inject is still around and there are other similar tools like ape that put a nice face on it. Even if it is your application, you can use an approach like that in mach-inject to manipulate the result of system time calls.
All cocoa and core foundation wall clock time calls trickle down to gettimeofday. There are other ways that time is tracked, but that is a good start.
I'm not a OS X developer so I can't give you specifics. But I know Windows, and can have a guess at how this might be implemented - you may be able to convert some of the techniques.
For illustration, let's assume most programs that want to follow the abstract passage of time on Windows use GetTickCount. This returns the number of milliseconds since the system was started. (There are other APIs an application could use, but the technique remains the same.)
To change the time as it appears for an application, the values returned from this time function need to be changed. (e.g. multiplied by a factor) so we create a wrapper function to apply the transformation:
DWORD GetTimeWarpTickCount()
{
static double factor = 2.0;
return (DWORD)(GetTickCount()*factor);
// simple implementation - you can be more sophisticated than this
// to preserve accuracy if necessary
}
Once you've coded up the function, use hooking to replace the original Win32 function with your own. Hooking can be done on a per-application basis, so you can localize time changes to specific applications.
So, in short, if there is a way of overriding the basic time functions provided to applications by OS X, then you can apply the same procedure.
Your question has to be split into two parts:
- Which is the source of time values that many applications use?
- How do I intercept this source?
The answer to 1) is (roughly in the order of importance):
- The system clock, read by
gettimeofday
(which, in turn, is used by NSDate, CFAbsoluteTime, ...) - An Audio card's clock. Many multimedia applications synchronize visuals to audio and use the audio as the driving source of time.
- The Video clock (counting vsyncs)
- Processor tick counters, interrupts, etc.
- Just the advancement of the program counter (speed of execution).
Edit:
- The mach timing functions. Thanks, @tc, for pointing that out.
Intercepting gettimeofday
is relatively easy: Just build a dynamic library containing a function with the same name and signature as the original gettimeofday
(see #include <sys/time.h>
). This function should return whatever value you want for the time.
To use this special gettimeofday
function in an application, start it on the Terminal as in:
DYLD_INSERT_LIBRARIES=/path/to/myGetTimeOfDay.dylib /Applications/TextEdit.app/Contents/MacOS/TextEdit
Of course your dylib has to match the applications architecture.
In addition to patching gettimeofday() (or whatever it calls under the hood), you'll also need to patch mach_timebase_info(): It returns the frequency of mach_absolute_time() which is used pretty much everywhere a system API has a timestamp which is "time since boot". You can also patch mach_absolute_time(), of course, but that's probably going to be higher overhead. See QA1398 for some details (note that the line elapsedNano = elapsed * sTimebaseInfo.numer / sTimebaseInfo.denom
is susceptible to overflow).
(The corresponding POSIX function is clock_gettime(CLOCK_MONOTINIC, &result)
. It's unclear why OSX doesn't implement this.)