A backup client application is often referred to as a data owner as it owns the data. This section describes how to write an active backup client which works with the Backup Engine and the Backup Server for data backup and restore.
In an active backup and restore, the Backup Engine calls the active backup client to supply the data for the backup. Writing an active backup client means to:
Create a user
defined class that has a data member pointer to conn::CActiveBackupClient
.
Implement the conn::MActiveBackupDataClient
interface.
Before you start, you must understand:
Backup Engine Concepts introduce the backup and restore types.
Symbian Backup and Restore architecture describes the two ways of data backup and restore.
Active Backup Client Architecture describes the components involved to do active data backup and restore.
KUidBackupRestoreKey
property published
by the backup server.
When a backup server receives a request from a client (a host
PC) for a backup or a restore, it reads backup registration files
for a list of data owners (refer to step 3). It then calls the CSBEClient::SetBURModeL()
function with the registered types
(base or incremental, full or partial). This function signals start
or completion of a backup or restore to all data owners. Data owners
must subscribe the following publish and subscribe property:
KUidBackupRestoreKey
defined in the epoc32\include\connect\sbdefs.h
header file. This key
belongs to the KUidSystemCategoryValue
category.
TBURPartType
or TBackupIncType
.
conn::CActiveBackupClient
object can only be
created once the publish and subscribe flag has transitioned into
a backup or restore mode. The backup client can be deleted once the
backup or restore operation has finished. This releases valuable system
resources.
CActiveBackupClient::ConfirmReadyForBURL()
is called to indicate that the backup client is ready for the data
supply to the Backup Engine.
class CReferenceActiveDataOwner : public CActive { // Methods public: static CReferenceActiveDataOwner* NewL(); ~CReferenceActiveDataOwner(); // From CActive void RunL(); TInt RunError(TInt aError); void DoCancel(); private: CReferenceActiveDataOwner() void ConstructL(); void SubscribeToPSFlag(); void ProcessBackupStateL(TInt aBackupStateValue); // Attributes private: //Active Backup Client CActiveBackupClient* iActiveBackupClient; //The publish and subscribe flag from the Backup Engine RProperty iProperty; //Pointer to the callback implementation CReferenceCallbackImplementation* iCallbackImpl; }; /** Subscribe to the publish and subscribe flag. Call RunL() when the flag changes. */ void CReferenceActiveDataOwner::SubscribeToPSFlag() { iStatus = KRequestPending; iProperty.Subscribe(iStatus); SetActive(); } /** Check the flag in case the data owner has been started for a backup or restore, or in case the publish and subscribe transition is missed. */ void CReferenceActiveDataOwner::ConstructL() { // Set up the property to catch the flag. TInt backupStateValue = 0; iProperty.Attach(KUidSystemCategory, KUidBackupRestoreKey); // Process the mode change accordingly iProperty.Get(backupStateValue); ProcessBackupStateL(backupStateValue); // Add to the active scheduler CActiveScheduler::Add(this); // Subscribe to the flag to catch transitions SubscribeToPSFlag(); } /** Create the CActiveBackupClient and the callback implementation based on the flag. @param aBackupStateValue the new backup state value */ void CReferenceActiveDataOwner::ProcessBackupStateL(TInt aBackupStateValue) { TInt type = aBackupStateValue & KBURPartTypeMask; // Create the the CActiveBackupClient and the callback implementation if // the device is in a backup or a restore mode. if (type == EBURBackupFull || type == EBURRestoreFull || type == EBURBackupPartial || type == EBURRestorePartial) if (iCallbackImpl == NULL) { iCallbackImpl = CReferenceCallbackImplementation::NewL(); } if (iActiveBackupClient == NULL) { iActiveBackupClient = CActiveBackupClient::NewL(iCallbackImpl); } } // Confirm the readiness of the active backup client. if ((type == EBURBackupFull || type == EBURRestoreFull) || ((type == EBURBackupPartial || type == EBURRestorePartial) && iActiveBackupClient->DoesPartialBURAffectMeL())) { .... // Things handled by a device vendor. //Inform the Backup Engine that the client is ready for data supply. iActiveBackupClient->ConfirmReadyForBURL(KErrNone); } else { // CActiveBackupClient and the callback implementation // if it is not an active backup. if (iActiveBackupClient != NULL) { delete iActiveBackupClient; iActiveBackupClient = NULL; } // The callback implementation must be deleted after // the CActiveBackupClient is deleted. if (iCallbackImpl != NULL) { delete iCallbackImpl; iCallbackImpl = NULL; } } } /** When the flag changes, RunL() is called. */ void CReferenceActiveDataOwner::RunL() { TInt backupStateValue = 0; // re-set the flag value // re-subscribe to the flag to monitor future changes SubscribeToPSFlag(); iProperty.Get(backupStateValue); // Process the mode change accordingly ProcessBackupStateL(backupStateValue); } ...
conn::MActiveBackupDataClient
to
write a callback handler.
The callback handler prepares the data to the Backup Engine
for a backup or a restore. For more information about each function,
refer to the conn::MActiveBackupDataClient
API
reference. The callback implementation must fulfill the following
requirements:
InitialiseGetBackupDataL()
is called before GetBackupDataSectionL()
. The Initialise
function gives a chance to a device vendor to prepare the data before
the actual data supply.
MActiveBackupDataClient::AllSnapshotsSuppliedL()
is called, it means that all snapshots have been supplied to the conn::CActiveBackupClient
. If conn::CActiveBackupClient
does not receive a snapshot, it performs a base backup.
aFinished
is passed as an argument.
This indicates to the Backup Engine if all of the data for a backup
is supplied. Setting this to EFalse causes the
Backup Engine to repeatedly call the backup function for more data.
aFinished
is passed
from the Backup Engine to indicate to the data owner if all of the
restore data is supplied. The Backup Engine sets aFinished
to ETrue after the final call of the restore
function.
class CReferenceCallbackImplementation : public CBase, public MActiveBackupDataClient { // Methods public: static CReferenceCallbackImplementation* NewL(); ~CReferenceCallbackImplementation(); // The following functions are from the MActiveBackupDataClient void AllSnapshotsSuppliedL(); void ReceiveSnapshotDataL(TDriveNumber aDrive, TDesC8& aBuffer, TBool aLastSection); TUint GetExpectedDataSize(TDriveNumber aDrive); void GetSnapshotDataL(TDriveNumber aDrive, TPtr8& aBuffer, TBool& aFinished); void InitialiseGetBackupDataL(TDriveNumber aDrive); void GetBackupDataSectionL(TPtr8& aBuffer, TBool& aFinished); void InitialiseRestoreBaseDataL(TDriveNumber aDrive); void RestoreBaseDataSectionL(TDesC8& aBuffer, TBool aFinished); void InitialiseRestoreIncrementDataL(TDriveNumber aDrive); void RestoreIncrementDataSectionL(TDesC8& aBuffer, TBool aFinished); void RestoreComplete(TDriveNumber aDrive); void TerminateMultiStageOperation(); TUint GetDataChecksum(TDriveNumber aDrive); //The following two functions are for the proxy backup client only and // Symbian provides a default implementation for each function. void InitialiseGetProxyBackupDataL(TSecureId aSID, TDriveNumber aDrive); void InitialiseRestoreProxyBaseDataL(TSecureId aSID, TDriveNumber aDrive); private: CReferenceCallbackImplementation() {} CMyABData* iSnapshot; CMyABData* iData; TBool iProxy; TInt iOffset; TInt iSourceSize; TUint iFillChar; TSecureId iID; }; void CReferenceCallbackImplementation::AllSnapshotsSuppliedL() { __LOG1("[0x%08x]: CReferenceCallbackImplementation::AllSnapshotsSuppliedL()", iID.iId); } void CReferenceCallbackImplementation::ReceiveSnapshotDataL( TDriveNumber aDrive, TDesC8& aBuffer, TBool /*aLastSection*/) { __LOG1("[0x%08x]: CReferenceCallbackImplementation::ReceiveSnapshotDataL()", iID.iId); // Create or append a buffer containing the snapshot if (!iSnapshot) { iSnapshot = CMyABData::NewL(aDrive); } iSnapshot->AddDataL(aBuffer); } TUint CReferenceCallbackImplementation::GetExpectedDataSize(TDriveNumber /*aDrive*/) { __LOG1("[0x%08x]: CReferenceCallbackImplementation::GetExpectedDataSize()", iID.iId); return iSourceSize; } void CReferenceCallbackImplementation::GetSnapshotDataL( TDriveNumber /*aDrive*/, TPtr8& aBuffer, TBool& aFinished) { __LOG1("[0x%08x]: CReferenceCallbackImplementation::GetSnapshotDataL()", iID.iId); aBuffer.Append(KABTestSnapshot()); aFinished = ETrue; } void CReferenceCallbackImplementation::InitialiseGetBackupDataL(TDriveNumber /*aDrive*/) { __LOG1("[0x%08x]: CReferenceCallbackImplementation::InitialiseGetBackupData()", iID.iId); iOffset = 0; if (!iSnapshot) { iFillChar = 66; } else { iFillChar = 73; } } void CReferenceCallbackImplementation::GetBackupDataSectionL( TPtr8& aBuffer, TBool& aFinished) { __LOG1("[0x%08x]: CReferenceCallbackImplementation::GetBackupDataSectionL()", iID.iId); FillBuffer(aBuffer, aFinished); } void CReferenceCallbackImplementation::InitialiseRestoreBaseDataL(TDriveNumber aDrive) { __LOG("CReferenceCallbackImplementation::InitialiseRestoreBaseDataL()"); iData = CMyABData::NewL(aDrive); } void CReferenceCallbackImplementation::RestoreBaseDataSectionL( TDesC8& aBuffer, TBool aFinished) { __LOG1("[0x%08x]: CReferenceCallbackImplementation::RestoreBaseDataSectionL()", iID.iId); // append a buffer containing the base data iData->AddDataL(aBuffer); if (aFinished) { ValidateRestoredData(); delete iData; iData = NULL; } } void CReferenceCallbackImplementation::InitialiseRestoreIncrementDataL(TDriveNumber aDrive) { __LOG1("[0x%08x]: CReferenceCallbackImplementation::InitialiseRestoreIncrementDataL()", iID.iId); if (!iSnapshot) { User::Leave(KErrCorrupt); } if (!iData) { iData = CMyABData::NewL(aDrive); } } void CReferenceCallbackImplementation::RestoreIncrementDataSectionL( TDesC8& aBuffer, TBool aFinished) { __LOG1("[0x%08x]: CReferenceCallbackImplementation::RestoreIncrementDataSectionL()", iID.iId); iData->AddDataL(aBuffer); if (aFinished) { ValidateRestoredData(); delete iData; iData = NULL; } } void CReferenceCallbackImplementation::RestoreComplete(TDriveNumber /*aDrive*/) { __LOG1("[0x%08x]: CReferenceCallbackImplementation::RestoreComplete()", iID.iId); } void CReferenceCallbackImplementation::TerminateMultiStageOperation() { __LOG1("[0x%08x]: CReferenceCallbackImplementation::TerminateMultiStageOperation()", iID.iId); // We also don't do anything here until we start testing multipart? } TUint CReferenceCallbackImplementation::GetDataChecksum(TDriveNumber /*aDrive*/) { __LOG1("[0x%08x]: CReferenceCallbackImplementation::GetDataChecksum()", iID.iId); return 0; } void CReferenceCallbackImplementation::InitialiseGetProxyBackupDataL( TSecureId aSID, TDriveNumber /*aDrive*/) { __LOG1("[0x%08x]: CReferenceCallbackImplementation::InitialiseGetProxyBackupDataL()", iID.iId); __LOG2("[0x%08x]: Proxy data about to be requested for SID 0x%08x", iID.iId, aSID.iId); iProxy = ETrue; iOffset = 0; iFillChar = 80; // 'P' } void CReferenceCallbackImplementation::InitialiseRestoreProxyBaseDataL( TSecureId aSID, TDriveNumber aDrive) { __LOG1("[0x%08x]: CReferenceCallbackImplementation::InitialiseRestoreProxyBaseDataL()", iID.iId); __LOG2("[0x%08x]: Proxy data about to be restored for SID 0x%08x", iID.iId, aSID.iId); iProxy = ETrue; iData = CMyABData::NewL(aDrive); } ...
backup_registration.xml
under the private folder of the
data owner application on the Symbian device.
process_name
is the name of the data owner
application.
active_type is set
to activeonly
for an active backup.
supports_incremental
can be set to false
to disable the incremental backup support from the
active backup client.
<!-- backup_registration.xml file for referencetestdataowner.exe --> <?xml version="1.0" standalone="yes"?> <backup_registration version="1.0"> <active_backup process_name = "referencetestdataowner.exe" active_type = "activeonly" requires_delay_to_prepare_data = "yes" <!--deprecated--> supports_incremental = "yes"> </active_backup> <restore requires_reboot = "no"/> <!--Currently only support no--> </backup_registration>
Finally, test the data owner application. The logging
information appends to the securebackup.txt
log
file. To enable the log generation, the C:\logs\connect
directory must be created on the device.