Fix alarm defect for applaunch based logic.
[platform/framework/native/appfw.git] / src / system / FSys_AlarmManager.cpp
index e7ac796..bf61df0 100644 (file)
@@ -1,5 +1,4 @@
 //
-// Open Service Platform
 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
 //
 // Licensed under the Apache License, Version 2.0 (the License);
  */
 
 #include <unique_ptr.h>
+
 #include <appfw/app.h>
 #include <alarm.h>
 #include <appsvc/appsvc.h>
 
 #include <FBaseSysLog.h>
 #include <FSysSystemTime.h>
+#include <FAppApp.h>
+#include <FBaseColArrayList.h>
 
 #include <FBase_NativeError.h>
-#include <FAppApp.h>
 #include <FBase_StringConverter.h>
 
 #include "inc/FSys_AlarmManager.h"
@@ -43,12 +44,15 @@ namespace Tizen { namespace System
 {
 static const long _SECOND_OF_MINUTE = 60;
 
-_AlarmManager* _AlarmManager::pAlarmManager = null;
+_AlarmManager* _AlarmManager::__pAlarmManager = null;
 
 _AlarmManager::_AlarmManager()
        : __pAlarmHashMap(null)
 {
        result r = E_SUCCESS;
+       int ret = pthread_mutex_init(&__lock, null);
+       SysTryCatch(NID_SYS, ret == 0, r = E_SYSTEM, E_SYSTEM, "It is failed to init mutex.");
+
        __alarmList.Construct();
 
        if (!__pAlarmHashMap)
@@ -69,6 +73,12 @@ CATCH:
 
 _AlarmManager::~_AlarmManager()
 {
+       int ret = pthread_mutex_destroy(&__lock);
+       if(ret != 0)
+       {
+               SysLogException(NID_SYS, E_SYSTEM, "It is failed to destroy mutex.");
+       }
+
        delete __pAlarmHashMap;
        __pAlarmHashMap = null;
 
@@ -76,14 +86,57 @@ _AlarmManager::~_AlarmManager()
        alarm_cancel_all();
 }
 
+int alarm_callback(alarm_id_t alarmId, void *user_param)
+{
+       _AlarmManager* pAlarmManager = _AlarmManager::GetInstance();
+       pAlarmManager->OnAlarmExpired((int)alarmId);
+        return 0;
+}
+
+result
+_AlarmManager::Construct(void)
+{
+       int errorCode;
+       Tizen::App::App* pApp = null;
+       pApp = Tizen::App::App::GetInstance();
+       String appId = pApp->GetAppId();
+       std::unique_ptr<char[]> pAppId(_StringConverter::CopyToCharArrayN(appId));
+
+       errorCode = alarmmgr_init(pAppId.get());
+       SysTryReturnResult(NID_SYS, errorCode == ALARMMGR_RESULT_SUCCESS, E_SYSTEM, "It is failed to init alarmmgr. error [%d]", errorCode);
+       errorCode = alarmmgr_set_cb(alarm_callback, null);
+       SysTryReturnResult(NID_SYS, errorCode == ALARMMGR_RESULT_SUCCESS, E_SYSTEM, "It is failed to set cb to alarmmgr. error [%d]", errorCode);
+       return E_SUCCESS;
+}
+
 _AlarmManager*
 _AlarmManager::GetInstance(void)
 {
-       if(pAlarmManager == null)
+       static pthread_once_t onceBlock = PTHREAD_ONCE_INIT;
+       if(__pAlarmManager == null)
        {
-               pAlarmManager = new (std::nothrow) _AlarmManager();
+               pthread_once(&onceBlock, InitSingleton);
        }
-       return pAlarmManager;
+       return __pAlarmManager;
+}
+
+void
+_AlarmManager::InitSingleton(void)
+{
+       result r = E_SUCCESS;
+       std::unique_ptr<_AlarmManager> pAlarmManager(new (std::nothrow) _AlarmManager());
+       SysTryReturnVoidResult(NID_SYS, pAlarmManager, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.",
+                                                  GetErrorMessage(E_OUT_OF_MEMORY));
+       r = pAlarmManager->Construct();
+       SysTryReturnVoidResult(NID_SYS, r == E_SUCCESS, E_SYSTEM, "It is failed to construct alarm manager.");
+       __pAlarmManager = pAlarmManager.release();
+       std::atexit(DestroySingleton);
+}
+
+void
+_AlarmManager::DestroySingleton(void)
+{
+       delete __pAlarmManager;
 }
 
 int
@@ -98,7 +151,7 @@ _AlarmManager::ReserveAlarm(Tizen::Base::String appId, Tizen::Base::DateTime sta
        SysLog(NID_SYS, "Reserve time is %d/%d/%d %d:%d:%d", startTime.GetYear(), startTime.GetMonth(), startTime.GetDay(), startTime.GetHour(), startTime.GetMinute(), startTime.GetSecond());
 
        bundle* pBundle = null;
-       alarm_entry_t* pAlarmInfo;
+       alarm_entry_t* pAlarmInfo = null;
        alarm_date_t expireTime = {0,};
 
        std::unique_ptr<char[]> pId(_StringConverter::CopyToCharArrayN(appId));
@@ -106,7 +159,7 @@ _AlarmManager::ReserveAlarm(Tizen::Base::String appId, Tizen::Base::DateTime sta
        pBundle = bundle_create();
        SysTryCatch(NID_SYS, pBundle != null, r = E_SYSTEM, r, "It is failed to create bundle");
 
-       ret = appsvc_set_operation(pBundle,"osp.appsvc.operation.ALARM");
+       ret = appsvc_set_operation(pBundle,"osp.operation.ALARM");
        SysTryCatch(NID_SYS, ret == SERVICE_ERROR_NONE, r = E_SYSTEM, r, "It is failed to set operation");
 
        ret = appsvc_set_appid(pBundle, (const char*)(pId.get()));
@@ -127,14 +180,15 @@ _AlarmManager::ReserveAlarm(Tizen::Base::String appId, Tizen::Base::DateTime sta
 
        if(period > 0)
        {
+               SysLog(NID_SYS, "It is repeated alarm and period time is %d minutes", period);
                ret = alarmmgr_set_repeat_mode(pAlarmInfo, ALARM_REPEAT_MODE_REPEAT, period * _SECOND_OF_MINUTE);
                SysTryCatch(NID_SYS, ret == ALARMMGR_RESULT_SUCCESS, r = E_SYSTEM, r, "It is failed to set repeat mode");
        }
 
-       ret = alarmmgr_set_type(pAlarmInfo, 0x04/*ALARM_TYPE_NOLAUNCH*/);
+       ret = alarmmgr_set_type(pAlarmInfo, ALARM_TYPE_NOLAUNCH);
        SysTryCatch(NID_SYS, ret == ALARMMGR_RESULT_SUCCESS, r = E_SYSTEM, r, "It is failed to set repeat mode");
 
-       ret = alarmmgr_add_alarm_appsvc_with_localtime(pAlarmInfo,(void *)pBundle, &reservedAlarmId);
+       ret = alarmmgr_add_alarm_with_localtime(pAlarmInfo, null, &reservedAlarmId);
        SysTryCatch(NID_SYS, ret == ALARMMGR_RESULT_SUCCESS, r = E_SYSTEM, r, "Alarm creation failed!!! Alrmgr error code is %d", ret);
 
 CATCH:
@@ -190,7 +244,7 @@ _AlarmManager::AddAlarmList(int alarmId, int period, String appId, DateTime* end
        {
                DateTime* alarmEndTime = new DateTime(*endTime);
 
-               SysLog(NID_SYS, "Endtime is exist %d:%d:%d", alarmEndTime->GetHour(), alarmEndTime->GetMinute(), alarmEndTime->GetSecond());
+               SysLog(NID_SYS, "Endtime exists %d:%d:%d", alarmEndTime->GetHour(), alarmEndTime->GetMinute(), alarmEndTime->GetSecond());
                r = __pAlarmHashMap->Add(*reservedAlarmId, *alarmEndTime);
                SysTryCatch(NID_SYS, r == E_SUCCESS, r, r, "Fail to add new alarm endtime on the alarm list");
        }
@@ -287,7 +341,7 @@ _AlarmManager::RemoveAlarmList(int alarmId)
                        __pAlarmHashMap->GetCount(*alarmAppId, count);
                        if(count == 0)
                        {
-                               SysLog(NID_SYS, "There is no reserved alarm for AppId:%S", alarmAppId->GetPointer());
+                               SysLog(NID_SYS, "There is no more reserved alarm for AppId:%S", alarmAppId->GetPointer());
                                __pAlarmHashMap->Remove(*alarmAppId, true);
                        }
                }
@@ -343,35 +397,43 @@ _AlarmManager::RegisterAlarm(_AlarmImpl* pAlarmImpl)
        String endTimeStr;
        String appId;
 
+       int reservedAlarmId = 0;
        int period = pAlarmImpl->GetPeriod();
+       int ret = 0;
+       Tizen::App::App* pApp = null;
  
        DateTime currentTime;
        DateTime startTime = pAlarmImpl->GetStartTime();
        const DateTime* pEndTime = pAlarmImpl->GetEndTime();
+       DateTime endTime;
 
        //Argument check
+       startTime.AddMilliseconds(-1 * startTime.GetMillisecond());
        r = SystemTime::GetCurrentTime(WALL_TIME, currentTime);
+       currentTime.AddMilliseconds(-1 * currentTime.GetMillisecond());
+
        SysTryReturnResult(NID_SYS, r == E_SUCCESS, E_SYSTEM, "It is failed to get current time.");
        SysTryReturnResult(NID_SYS, DateTime::Compare(currentTime, startTime) < 0, E_INVALID_ARG, "Designated start time has to be greater than current time.");
-       SysTryReturnResult(NID_SYS, period > -1, E_INVALID_ARG, "Period has to greater then -1");
+       SysTryReturnResult(NID_SYS, period > -1, E_INVALID_ARG, "Period has to greater than -1");
+
+       ret = pthread_mutex_lock(&__lock);
+       SysTryCatch(NID_SYS, ret == 0, r = E_INVALID_ARG, r, "It is failed to lock mutex.");
 
        if(pEndTime != null)
        {
-               SysTryReturnResult(NID_SYS, DateTime::Compare(startTime, *pEndTime) < 0, E_INVALID_ARG, "Designated end time is less then start time.");
+               endTime = *pEndTime;
+               endTime.AddMilliseconds(-1 * endTime.GetMillisecond());
+
+               SysTryCatch(NID_SYS, DateTime::Compare(startTime, endTime) < 0, r = E_INVALID_ARG, r, "Designated end time is less than start time.");
        }
        //End Alarm validation check
 
-       Tizen::App::App* pApp = Tizen::App::App::GetInstance();
-       SysTryReturnResult(NID_SYS, pApp != null, E_SYSTEM, "[%s] A system error has been occurred. App::GetInstance() failed.", GetErrorMessage(E_SYSTEM));
+       pApp = Tizen::App::App::GetInstance();
+       SysTryCatch(NID_SYS, pApp != null, r = E_SYSTEM, r, "[%s] A system error has been occurred. App::GetInstance() failed.", GetErrorMessage(E_SYSTEM));
        appId = pApp->GetAppId();
 
-       String* result = null;
-       int reservedAlarmId = 0;
-
-       SysLog(NID_SYS, "Alarm setting request");
-
        reservedAlarmId = ReserveAlarm(appId, startTime, period);
-       SysTryReturnResult(NID_SYS, reservedAlarmId != -1, E_SYSTEM, "It is failed to register alarm.");
+       SysTryCatch(NID_SYS, reservedAlarmId != -1, r = E_SYSTEM, r, "It is failed to register alarm.");
 
        SysLog(NID_SYS, "Reserved AppId %ls, alarmId: %d", appId.GetPointer(), reservedAlarmId);
 
@@ -381,33 +443,43 @@ _AlarmManager::RegisterAlarm(_AlarmImpl* pAlarmImpl)
        }
        else
        {
-               r = AddAlarmList(reservedAlarmId, period, appId, const_cast<DateTime*>(pEndTime));
+               r = AddAlarmList(reservedAlarmId, period, appId, (DateTime*)(&endTime));
        }
-       SysTryReturnResult(NID_SYS, r == E_SUCCESS, E_SYSTEM, "It is failed to add new alarm on the alarm list.");
+       SysTryCatch(NID_SYS, r == E_SUCCESS, r = E_SYSTEM, r, "It is failed to add new alarm on the alarm list.");
 
        pAlarmImpl->__alarmId.value = reservedAlarmId;
        r = __alarmList.Add(&(pAlarmImpl->__alarmId), pAlarmImpl);
 
+CATCH:
+       ret = pthread_mutex_unlock(&__lock);
+       SysTryReturnResult(NID_SYS, ret == 0, E_INVALID_ARG, "It is failed to unlock mutex.");
        return r;
 }
 
 result
 _AlarmManager::UnregisterAlarm(_AlarmImpl* pAlarmImpl)
 {
+       result r = E_SUCCESS;
+       Integer alarmId;
+       int ret = 0;
        SysLog(NID_SYS, "Alarm Cancel request");
+       SysTryCatch(NID_SYS, pAlarmImpl != null, r = E_INVALID_ARG, r, "There is no alarmImpl.");
 
-       result r = E_SUCCESS;
-       SysTryReturnResult(NID_SYS, pAlarmImpl != null, E_INVALID_ARG, "There is no alarmImpl.");
+       ret = pthread_mutex_lock(&__lock);
+       SysTryCatch(NID_SYS, ret == 0, r = E_SYSTEM, r, "It is failed to lock mutex.");
 
-       Integer alarmId(pAlarmImpl->__alarmId.value);
-       SysTryReturnResult(NID_SYS, __alarmList.ContainsKey(alarmId) == true, E_OBJ_NOT_FOUND, "There is no registered alarm.");
+       alarmId.value = pAlarmImpl->__alarmId.value;
+       SysTryCatch(NID_SYS, __alarmList.ContainsKey(alarmId) == true, r = E_OBJ_NOT_FOUND, r, "There is no registered alarm.");
 
        r = __alarmList.Remove(alarmId);
-       SysTryReturnResult(NID_SYS, r == E_SUCCESS, E_SYSTEM, "It is failed to remove reserved alarmImpl instance.");
+       SysTryCatch(NID_SYS, r == E_SUCCESS, r = E_SYSTEM, r, "It is failed to remove reserved alarmImpl instance.");
 
        r = RemoveAlarmList(alarmId.ToInt());
-       SysTryReturnResult(NID_SYS, r == E_SUCCESS, E_SYSTEM, "It is failed to remove reserved alarm list.");
+       SysTryCatch(NID_SYS, r == E_SUCCESS, r = E_SYSTEM, r, "It is failed to remove reserved alarm list.");
 
+CATCH:
+       ret = pthread_mutex_unlock(&__lock);
+       SysTryReturnResult(NID_SYS, ret == 0, E_SYSTEM, "It is failed to unlock mutex.");
        return r;
 }
 
@@ -415,15 +487,17 @@ result
 _AlarmManager::UpdateAlarm(_AlarmImpl* pAlarmImpl)
 {
        result r = E_SUCCESS;
-       SysTryReturnResult(NID_SYS, pAlarmImpl != null, E_INVALID_ARG, "There is no alarmImpl.");
+       Integer alarmId;
+       SysTryReturnResult(NID_SYS, pAlarmImpl != null, E_SYSTEM, "There is no alarmImpl.");
 
-       Integer alarmId(pAlarmImpl->__alarmId.value);
-       SysTryReturnResult(NID_SYS, __alarmList.ContainsKey(alarmId) == true, E_OBJ_NOT_FOUND, "There is no registered alarm.");
+       alarmId.value = pAlarmImpl->__alarmId.value;
+       SysTryReturnResult(NID_SYS, __alarmList.ContainsKey(alarmId) == true, E_SYSTEM, "There is no registered alarm.");
 
        r = UnregisterAlarm(pAlarmImpl);
        SysTryReturnResult(NID_SYS, r == E_SUCCESS, E_SYSTEM, "It is failed to unregister reserved alarm list.");
 
        r = RegisterAlarm(pAlarmImpl);
+       SysTryReturnResult(NID_SYS, r == E_SUCCESS, E_SYSTEM, "It is failed to register alarm.");
        return r;
 }
 
@@ -431,28 +505,41 @@ void
 _AlarmManager::OnAlarmExpired(int alarmId)
 {
        result r = E_SUCCESS;
+       int ret = 0;
        String* pAppId = null;
        Integer* pPeriod = null;
+       String alarmAppId;
        std::unique_ptr<IEnumerator> pValueEnum(null);
        Integer reservedAlarmId(alarmId);
        DateTime* endTime = null;
+       _AlarmImpl* pAlarmImpl = null;
+
+       SysTryCatch(NID_SYS, __pAlarmHashMap != null, r = E_SYSTEM, r, "Alarm list does not initialized");
+
+       ret = pthread_mutex_lock(&__lock);
+       SysTryReturnVoidResult(NID_SYS, ret == 0, E_SYSTEM, "It is failed to lock mutex.");
 
-       SysTryReturnVoidResult(NID_SYS, __pAlarmHashMap != null, E_SYSTEM, "Alarm list does not initialized");
        pValueEnum.reset(__pAlarmHashMap->GetValuesN(reservedAlarmId));
 
        SysLog(NID_SYS, "Alarm expire event is delivered. alarm id is %d", alarmId);
 
+       pAlarmImpl = (_AlarmImpl*)__alarmList.GetValue(reservedAlarmId);
+       if(pAlarmImpl == null)
+       {
+               SysLog(NID_SYS, "pAlarmImpl of reserved alarm[%d] is not found.", alarmId);
+       }
+
        if(pValueEnum != null)
        {
-               String alarmAppId;
                SysLog(NID_SYS, "Matching Alarm Id is %d \n", alarmId);
+
                r = pValueEnum->MoveNext();
-               SysTryReturnVoidResult(NID_SYS,  r == E_SUCCESS, E_SYSTEM, "Alarm enum value is not valid.");
+               SysTryCatch(NID_SYS,  r == E_SUCCESS, r = E_SYSTEM, r, "Alarm enum value is not valid.");
                pAppId = static_cast< String* >(pValueEnum->GetCurrent());
                alarmAppId.Append(*pAppId);
                r = pValueEnum->MoveNext();
                pPeriod = static_cast< Integer* >(pValueEnum->GetCurrent());
-               SysTryReturnVoidResult(NID_SYS, r == E_SUCCESS, E_SYSTEM, "Alarm enum value is not valid.");
+               SysTryCatch(NID_SYS, r == E_SUCCESS, r = E_SYSTEM, r, "Alarm enum value is not valid.");
 
                if(pValueEnum->MoveNext() == E_SUCCESS)
                {
@@ -466,44 +553,63 @@ _AlarmManager::OnAlarmExpired(int alarmId)
                        if(endTime != null)
                        {
                                DateTime currentTime;
+
                                SystemTime::GetCurrentTime(WALL_TIME, currentTime);
-                               SysLog(NID_SYS, "Current time: %d:%d:%d", currentTime.GetHour(), currentTime.GetMinute(), currentTime.GetSecond());
+                               currentTime.AddMilliseconds(-1 * currentTime.GetMillisecond()); //Remove millisecond
                                currentTime.AddMinutes(pPeriod->ToInt());
-                               SysLog(NID_SYS, "Next time: %d:%d:%d", currentTime.GetHour(), currentTime.GetMinute(), currentTime.GetSecond());
-                               SysLog(NID_SYS, "Endtime is exist %d:%d:%d", endTime->GetHour(), endTime->GetMinute(), endTime->GetSecond());
+                               SysLog(NID_SYS, "Next time[%d min]: %d:%d:%d:%d", pPeriod->ToInt(), currentTime.GetHour(), currentTime.GetMinute(), currentTime.GetSecond(), currentTime.GetMillisecond());
+                               SysLog(NID_SYS, "Endtime exists %d:%d:%d:%d", endTime->GetHour(), endTime->GetMinute(), endTime->GetSecond(), endTime->GetMillisecond());
 
-                               if (currentTime.CompareTo(*endTime) >= 0)
+                               if (currentTime.CompareTo(*endTime) > 0)
                                {
-                                       SysLog(NID_SYS, "Next time is greater then end time.");
+                                       SysLog(NID_SYS, "Next time is greater than end time.");
                                        RemoveAlarmList(alarmId);
                                        pValueEnum->Reset();
+
+                                       if(pAlarmImpl != null)
+                                       {
+                                               pAlarmImpl->__alarmId.value = 0;
+                                       }
                                }
                        }
                }
                else if (pPeriod->ToInt() == 0)
                {
                        RemoveAlarmList(alarmId);
+
+                       if(pAlarmImpl != null)
+                       {
+                               pAlarmImpl->__alarmId.value = 0;
+                       }
                }
                else
                {
                        pValueEnum->Reset();
                }
+
        }
 
-       _AlarmImpl* pAlarmImpl = (_AlarmImpl*)__alarmList.GetValue(reservedAlarmId);
+       ret = pthread_mutex_unlock(&__lock);
+
        if(pAlarmImpl != null)
        {
-               SysLog(NID_SYS, "Reserved Alarm[%d] is found.", alarmId);
                pAlarmImpl->OnAlarmExpired(alarmId);
        }
 
        if(__pAlarmHashMap->ContainsKey(reservedAlarmId) == false)
        {
+               ret = pthread_mutex_lock(&__lock);
+               SysLog(NID_SYS, "Remove an alarm list[%d].", reservedAlarmId.value);
                r = __alarmList.Remove(reservedAlarmId);
+               ret = pthread_mutex_unlock(&__lock);
                SetLastResult(r);
        }
 
        return;
+
+CATCH:
+       ret = pthread_mutex_unlock(&__lock);
+       SysTryReturnVoidResult(NID_SYS, ret == 0, E_SYSTEM, "It is failed to unlock mutex.");
 }
 
 } } // Tizen::System